peachsim 0.1.631 → 0.1.633

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 (75) hide show
  1. package/README.md +9 -1
  2. package/cli/commands/maestro.ts +5 -1
  3. package/cli/commands/test.ts +29 -1
  4. package/cli/drivers/playwright-core-pin.ts +10 -0
  5. package/cli/drivers/playwright-provisioning.ts +36 -1
  6. package/cli/drivers/playwright.ts +26 -19
  7. package/cli/shell-init.ts +6 -1
  8. package/cli/ws-bridge.ts +8 -2
  9. package/dist-lib/agent-daemon-client.cjs +1 -1
  10. package/dist-lib/agent-events.cjs +1 -1
  11. package/dist-lib/agent-identity.cjs +1 -1
  12. package/dist-lib/agent-sessions.cjs +1 -1
  13. package/dist-lib/attached-projects.cjs +1 -1
  14. package/dist-lib/auth/shared-session.cjs +1 -1
  15. package/dist-lib/backend-origin.cjs +1 -1
  16. package/dist-lib/beta.cjs +1 -1
  17. package/dist-lib/beta.mjs +1 -1
  18. package/dist-lib/bridge-constants.cjs +1 -1
  19. package/dist-lib/bridge-contract-input.cjs +1 -1
  20. package/dist-lib/bridge-contract-input.mjs +1 -1
  21. package/dist-lib/bridge-contract.cjs +1 -1
  22. package/dist-lib/bridge-contract.mjs +1 -1
  23. package/dist-lib/capture-contract.cjs +1 -1
  24. package/dist-lib/capture-contract.mjs +1 -1
  25. package/dist-lib/cli-constants.cjs +1 -1
  26. package/dist-lib/cloud-contract.cjs +1 -1
  27. package/dist-lib/cloud-contract.mjs +1 -1
  28. package/dist-lib/cloud-test-args.cjs +17 -5
  29. package/dist-lib/cloud-test-args.mjs +17 -5
  30. package/dist-lib/cloud.cjs +1 -1
  31. package/dist-lib/cloud.mjs +1 -1
  32. package/dist-lib/config.cjs +1 -1
  33. package/dist-lib/detox/index.cjs +1 -1
  34. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  35. package/dist-lib/home-paths.cjs +6 -1
  36. package/dist-lib/host/bridge-host.cjs +48 -47
  37. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  38. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  39. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  40. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  41. package/dist-lib/host/websocket-proxy.cjs +1 -1
  42. package/dist-lib/index.cjs +7 -2
  43. package/dist-lib/jump-to-source-babel.cjs +1 -1
  44. package/dist-lib/jump-to-source-native.cjs +1 -1
  45. package/dist-lib/kotlin-host.cjs +1 -1
  46. package/dist-lib/menu.cjs +1 -1
  47. package/dist-lib/menu.mjs +1 -1
  48. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  49. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  50. package/dist-lib/metro-production-bundle.cjs +1 -1
  51. package/dist-lib/metro-production-bundle.mjs +1 -1
  52. package/dist-lib/metro.cjs +1 -1
  53. package/dist-lib/native-app-identity.cjs +1 -1
  54. package/dist-lib/native-app-identity.mjs +1 -1
  55. package/dist-lib/profiles.cjs +1 -1
  56. package/dist-lib/public-brand.cjs +1 -1
  57. package/dist-lib/react-native-host-modules.cjs +1 -1
  58. package/dist-lib/react-native-host-modules.mjs +1 -1
  59. package/dist-lib/render-mode.cjs +1 -1
  60. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  61. package/dist-lib/sdk.cjs +1 -1
  62. package/dist-lib/sdk.mjs +1 -1
  63. package/dist-lib/skills.cjs +136 -83
  64. package/dist-lib/swift-compile.cjs +1 -1
  65. package/dist-lib/swift-compile.mjs +1 -1
  66. package/dist-lib/swift-package.cjs +1 -1
  67. package/dist-lib/swift-package.mjs +1 -1
  68. package/dist-lib/swift-submit.cjs +1 -1
  69. package/dist-lib/swift-submit.mjs +1 -1
  70. package/dist-lib/swift.cjs +9 -8
  71. package/dist-lib/vite-swift.cjs +1 -1
  72. package/dist-lib/vite.cjs +1 -1
  73. package/package.json +1 -1
  74. package/src/cloud-test-args.ts +18 -6
  75. package/src/home-paths.ts +8 -0
package/README.md CHANGED
@@ -254,7 +254,15 @@ through an unreachable IPv4 address. `peach open` starts a local bridge when no
254
254
  daemon is reachable. The background service is strongly recommended for local
255
255
  agent work because inspect, interaction, and test commands reuse one ready bridge
256
256
  and runtime. Enable it at any time with `peach daemon install`; it is never required
257
- in CI. The packaged Desktop app is optional and available through first-run
257
+ in CI.
258
+
259
+ Sandboxed or agent runners may stop child processes when a command ends,
260
+ including a bridge started by `peach open`. Keep `peach serve` running in a
261
+ persistent terminal or background task outside that command's lifetime, then
262
+ run `peach open` and later commands against it. When using a custom bridge port,
263
+ pass the same `--port <n>` to `peach serve` and the CLI commands.
264
+
265
+ The packaged Desktop app is optional and available through first-run
258
266
  onboarding or `peach desktop install`. A downloaded app starts its own bundled
259
267
  daemon on first launch. An installed runtime can open while the daemon checks
260
268
  for updates; a first install waits for the runtime download to finish. The app
@@ -182,7 +182,11 @@ export function applyEnvFlags(args: string[]): string[] {
182
182
  const out: string[] = []
183
183
  for (let i = 0; i < args.length; i++) {
184
184
  const arg = args[i] as string
185
- const inline = arg.startsWith('--env=') ? arg.slice('--env='.length) : null
185
+ const inline = arg.startsWith('--env=')
186
+ ? arg.slice('--env='.length)
187
+ : arg.startsWith('-e=')
188
+ ? arg.slice('-e='.length)
189
+ : null
186
190
  if (arg === '--env' || arg === '-e' || inline !== null) {
187
191
  const kv = inline ?? args[i + 1]
188
192
  if (!kv || !kv.includes('=')) {
@@ -848,6 +848,21 @@ export async function runCloudTest(
848
848
  ['.maestro', 'maestro'].includes(basename(targetPath))
849
849
  )
850
850
  })()
851
+ if (
852
+ !maestroTarget &&
853
+ (cloudTestArgs ?? []).some(
854
+ (arg) =>
855
+ arg === '--env' ||
856
+ arg === '-e' ||
857
+ arg.startsWith('--env=') ||
858
+ arg.startsWith('-e='),
859
+ )
860
+ ) {
861
+ console.error(
862
+ ' error: --env supplies maestro flow variables and requires a maestro target',
863
+ )
864
+ return 1
865
+ }
851
866
  if (maestroTarget) {
852
867
  // maestro has no test-name or test-path selection; the cloud selector
853
868
  // vocabulary is shared with detox, so a jest selector here is refused
@@ -908,6 +923,19 @@ export async function runCloudTest(
908
923
  return 1
909
924
  }
910
925
  const baseFiles = collectTestFiles(targetPath, localBundlePath)
926
+ // tags have already selected the jobs. only explicit environment overrides
927
+ // remain executor inputs, with duplicates and their order preserved.
928
+ const envArgs: string[] = []
929
+ const executorArgs = cloudTestArgs ?? []
930
+ for (let i = 0; i < executorArgs.length; i++) {
931
+ const arg = executorArgs[i]
932
+ const eq = arg.indexOf('=')
933
+ const head = eq > 0 ? arg.slice(0, eq) : arg
934
+ const value = eq > 0 ? null : executorArgs[++i]
935
+ if (head !== '--env' && head !== '-e') continue
936
+ envArgs.push(arg)
937
+ if (value !== null) envArgs.push(value)
938
+ }
911
939
  for (const flow of flows) {
912
940
  const entryKey = relative(targetPath, flow).split(sep).join('/')
913
941
  let generated: string
@@ -920,7 +948,7 @@ export async function runCloudTest(
920
948
  // the recorder selects the root workspace config. nested config.yaml
921
949
  // files may be runFlow helpers and must keep their original bytes.
922
950
  const testFiles = { ...baseFiles, 'config.yaml': generated }
923
- jobs.push({ label: entryKey, testFiles, testArgs: null })
951
+ jobs.push({ label: entryKey, testFiles, testArgs: envArgs.length ? envArgs : null })
924
952
  }
925
953
  console.log(
926
954
  ` cloud test: ${jobs.length} flow${jobs.length === 1 ? '' : 's'}, one hosted job each`,
@@ -0,0 +1,10 @@
1
+ // the playwright-core this CLI provisions into its own data dir when neither
2
+ // the app nor the CLI's install tree has a playwright package. the standalone
3
+ // binary has no node_modules, so this is how it gets one. it is the exact
4
+ // package and tarball the npm install depends on: build-cli-binary.ts fails
5
+ // unless both fields match package.json and bun.lock.
6
+ export const PINNED_PLAYWRIGHT_CORE = {
7
+ version: '1.61.0',
8
+ integrity:
9
+ 'sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==',
10
+ }
@@ -2,9 +2,12 @@ import { spawnSync } from 'node:child_process'
2
2
  import { existsSync, readFileSync } from 'node:fs'
3
3
  import { createRequire } from 'node:module'
4
4
  import { dirname, join } from 'node:path'
5
+ import { installVerifiedTarball } from '@contrast/runtime-delivery'
6
+ import { playwrightCoreDir } from '../../src/home-paths'
5
7
  import { isRecord } from '../../src/is-record'
6
8
  import { RNX_INTERNAL_CHILDREN, RNX_INTERNAL_COMMAND } from '../internal-child'
7
9
  import { rnxSelfInvocation } from '../self-invocation'
10
+ import { PINNED_PLAYWRIGHT_CORE } from './playwright-core-pin'
8
11
 
9
12
  export interface ResolvedPlaywright {
10
13
  // package name that resolved (for human-facing messaging)
@@ -30,10 +33,12 @@ export type PlaywrightBrowserProvisioningResult =
30
33
 
31
34
  export function resolvePlaywright(): ResolvedPlaywright | null {
32
35
  // resolve from several roots, not just cwd. a user can invoke a global CLI
33
- // from an arbitrary directory while Playwright is installed beside the CLI.
36
+ // from an arbitrary directory while Playwright is installed beside the CLI,
37
+ // and the last root is the pinned package this CLI provisions for itself.
34
38
  const roots = [`${process.cwd()}/`]
35
39
  const self = rnxSelfInvocation()
36
40
  roots.push(self.prefixArgs[0] ?? self.executable)
41
+ roots.push(`${playwrightCoreDir(PINNED_PLAYWRIGHT_CORE.version)}/`)
37
42
  for (const root of roots) {
38
43
  try {
39
44
  const requireFromRoot = createRequire(root)
@@ -69,6 +74,36 @@ export function resolvePlaywright(): ResolvedPlaywright | null {
69
74
  return null
70
75
  }
71
76
 
77
+ /** the playwright package to drive: whichever one resolves, else the pinned
78
+ * playwright-core, downloaded from the npm registry and refused unless its
79
+ * tarball matches the pinned integrity. */
80
+ export async function provisionPlaywright(): Promise<ResolvedPlaywright> {
81
+ const existing = resolvePlaywright()
82
+ if (existing) return existing
83
+ const { version, integrity } = PINNED_PLAYWRIGHT_CORE
84
+ const [algorithm, digest] = integrity.split('-', 2)
85
+ if (algorithm !== 'sha512' || !digest) {
86
+ throw new Error(`pinned playwright-core integrity is not sha512: ${integrity}`)
87
+ }
88
+ process.stderr.write(`peach: installing playwright-core ${version}…\n`)
89
+ await installVerifiedTarball({
90
+ url: `https://registry.npmjs.org/playwright-core/-/playwright-core-${version}.tgz`,
91
+ digest: { algorithm, encoding: 'base64', value: digest },
92
+ destDir: join(playwrightCoreDir(version), 'node_modules', 'playwright-core'),
93
+ installedMarker: 'package.json',
94
+ // npm tarballs hold the package under a leading `package/`
95
+ stripComponents: 1,
96
+ label: `playwright-core ${version}`,
97
+ })
98
+ const installed = resolvePlaywright()
99
+ if (!installed) {
100
+ throw new Error(
101
+ `playwright-core ${version} installed to ${playwrightCoreDir(version)} but does not resolve`,
102
+ )
103
+ }
104
+ return installed
105
+ }
106
+
72
107
  type BrowserProbeResult =
73
108
  | { ok: true; executablePath: string; exists: boolean }
74
109
  | { ok: false; message: string }
@@ -1,8 +1,8 @@
1
1
  // playwright driver — launches Playwright's Google Chrome for Testing via the
2
- // `playwright` package. availability depends on whether the package is
3
- // resolvable from the current working directory OR from the CLI's own
4
- // install tree (repo-local install is typical; the latter covers a global
5
- // CLI invoked from a directory with no node_modules).
2
+ // `playwright` package. the package resolves from the current working
3
+ // directory, then the CLI's own install tree, then the pinned playwright-core
4
+ // the CLI provisions into its data dir on first launch, so the driver is
5
+ // always available.
6
6
  //
7
7
  // the browser runs in a *detached* child process — this CLI re-invoked as
8
8
  // its own `__internal playwright-host` (see cli/internal-child.ts) — rather
@@ -22,7 +22,13 @@ import { ensureProfile, playwrightProfileUserDataDir } from '../../src/profiles'
22
22
  import { RNX_INTERNAL_CHILDREN, RNX_INTERNAL_COMMAND } from '../internal-child'
23
23
  import { getProcessComm } from '../parent-pid'
24
24
  import { rnxSelfInvocation } from '../self-invocation'
25
- import { ensurePlaywrightBrowser, resolvePlaywright } from './playwright-provisioning'
25
+ import { PINNED_PLAYWRIGHT_CORE } from './playwright-core-pin'
26
+ import {
27
+ ensurePlaywrightBrowser,
28
+ provisionPlaywright,
29
+ resolvePlaywright,
30
+ type ResolvedPlaywright,
31
+ } from './playwright-provisioning'
26
32
  import type {
27
33
  Driver,
28
34
  DriverAvailability,
@@ -32,16 +38,12 @@ import type {
32
38
 
33
39
  function probe(): DriverAvailability {
34
40
  const resolved = resolvePlaywright()
35
- if (!resolved) {
36
- return {
37
- available: false,
38
- reason: 'playwright not installed in the current workspace',
39
- }
40
- }
41
41
  return {
42
42
  available: true,
43
43
  reason: null,
44
- detail: `resolved via ${resolved.spec}@${resolved.version}`,
44
+ detail: resolved
45
+ ? `resolved via ${resolved.spec}@${resolved.version}`
46
+ : `installs playwright-core@${PINNED_PLAYWRIGHT_CORE.version} on first launch`,
45
47
  }
46
48
  }
47
49
 
@@ -75,13 +77,6 @@ function resolveUserDataDir(opts: DriverLaunchOptions): string {
75
77
  }
76
78
 
77
79
  async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
78
- const resolved = resolvePlaywright()
79
- if (!resolved) {
80
- return {
81
- launched: false,
82
- message: 'playwright not installed — run `bun add -D playwright` first',
83
- }
84
- }
85
80
  if (!opts.url) {
86
81
  return { launched: false, message: 'playwright driver requires a target url' }
87
82
  }
@@ -93,6 +88,18 @@ async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
93
88
  }
94
89
  }
95
90
 
91
+ let resolved: ResolvedPlaywright
92
+ try {
93
+ resolved = await provisionPlaywright()
94
+ } catch (error) {
95
+ return {
96
+ launched: false,
97
+ message: `playwright provisioning failed: ${
98
+ error instanceof Error ? error.message : String(error)
99
+ }`,
100
+ }
101
+ }
102
+
96
103
  // keep browser discovery, installation, and the detached host on one exact
97
104
  // cache contract even if another caller mutates process.env during launch.
98
105
  const playwrightEnv = { ...process.env }
package/cli/shell-init.ts CHANGED
@@ -27,7 +27,12 @@ export function renderRnxShellInit(shell: string): string {
27
27
  esac
28
28
  done
29
29
  case "$_peach_shell_command" in
30
- claim|close) ;;
30
+ claim|close)
31
+ if [ -z "\${PEACH_CLOUD_SESSION:-}" ]; then
32
+ command peach "\${_peach_shell_args[@]}"
33
+ return $?
34
+ fi
35
+ ;;
31
36
  ios)
32
37
  for _peach_shell_session in "$@"; do
33
38
  if [ "$_peach_shell_session" = '--remote' ]; then
package/cli/ws-bridge.ts CHANGED
@@ -148,7 +148,8 @@ function resolveDefaultDevBridgeLockfile(): DevBridgeLockfile | null {
148
148
  // another checkout's bridge on its own offset belongs to that checkout's
149
149
  // world; only the canonical bridge is shared, and past it the daemon serves.
150
150
  return (
151
- lockfiles.find((lockfile) => lockfile.bridgePort === DEFAULT_SOOTSIM_BRIDGE_PORT) ?? null
151
+ lockfiles.find((lockfile) => lockfile.bridgePort === DEFAULT_SOOTSIM_BRIDGE_PORT) ??
152
+ null
152
153
  )
153
154
  }
154
155
 
@@ -601,7 +602,12 @@ export function createBridge(wsPort: number, opts: WsBridgeOptions = {}): WsBrid
601
602
  // err.message is often empty (ECONNREFUSED surfaces with no message on
602
603
  // some node builds) — don't emit a dangling "...7668: " with no cause.
603
604
  const cause = err.message ? `: ${err.message}` : ''
604
- reject(new Error(`could not connect to ${bridgeWsUrl(wsPort)}${cause}`))
605
+ reject(
606
+ new Error(
607
+ `could not connect to ${bridgeWsUrl(wsPort)}${cause}\n` +
608
+ ` for sandboxed or agent runners, keep \`peach serve --port ${wsPort}\` running in a persistent terminal or background task.`,
609
+ ),
610
+ )
605
611
  })
606
612
  })
607
613
  // a bridge closed before its handshake finished rejects `ready` with nothing
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var REFUSED_PERFORM_STEP_TYPES = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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;
@@ -39,7 +39,9 @@ var CLOUD_TEST_VALUE_FLAGS = [
39
39
  "--testPathPattern",
40
40
  "--include-tags",
41
41
  "--exclude-tags",
42
- "--grep"
42
+ "--grep",
43
+ "--env",
44
+ "-e"
43
45
  ];
44
46
  var CLOUD_TEST_VALUE_FLAG_SET = new Set(CLOUD_TEST_VALUE_FLAGS);
45
47
  function isCloudTestValueFlag(name) {
@@ -64,7 +66,7 @@ function parseCloudTestArgs(value) {
64
66
  return { ok: false, message: "testArgs entries must be non-empty strings" };
65
67
  }
66
68
  if (entry.length > CLOUD_TEST_ARG_MAX_LENGTH || entry.includes("\0")) {
67
- return { ok: false, message: `testArgs entry is too long or carries a NUL byte: ${entry.slice(0, 60)}` };
69
+ return { ok: false, message: "testArgs entry is too long or carries a NUL byte" };
68
70
  }
69
71
  bytes += encoder.encode(entry).length;
70
72
  if (bytes > CLOUD_TEST_ARGS_MAX_BYTES) {
@@ -87,12 +89,19 @@ function parseCloudTestArgs(value) {
87
89
  const eq = entry.indexOf("=");
88
90
  const head = eq > 0 ? entry.slice(0, eq) : entry;
89
91
  if (!isCloudTestValueFlag(head)) {
90
- return { ok: false, message: `testArgs carries an unknown flag: ${head.slice(0, 60)}` };
92
+ return {
93
+ ok: false,
94
+ message: `testArgs carries an unknown flag: ${head.slice(0, 60)}`
95
+ };
91
96
  }
92
97
  if (eq > 0) {
93
- if (!entry.slice(eq + 1)) {
98
+ const value2 = entry.slice(eq + 1);
99
+ if (!value2) {
94
100
  return { ok: false, message: `${head} expects a value` };
95
101
  }
102
+ if ((head === "--env" || head === "-e") && value2.indexOf("=") < 1) {
103
+ return { ok: false, message: `${head} expects KEY=VALUE with a non-empty key` };
104
+ }
96
105
  args.push(entry);
97
106
  continue;
98
107
  }
@@ -100,6 +109,9 @@ function parseCloudTestArgs(value) {
100
109
  if (val === void 0 || val.startsWith("-")) {
101
110
  return { ok: false, message: `${head} expects a value` };
102
111
  }
112
+ if ((head === "--env" || head === "-e") && val.indexOf("=") < 1) {
113
+ return { ok: false, message: `${head} expects KEY=VALUE with a non-empty key` };
114
+ }
103
115
  args.push(entry, val);
104
116
  i += 1;
105
117
  }
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-test-args.ts
4
4
  var CLOUD_TEST_ARGS_MAX_COUNT = 32;
@@ -10,7 +10,9 @@ var CLOUD_TEST_VALUE_FLAGS = [
10
10
  "--testPathPattern",
11
11
  "--include-tags",
12
12
  "--exclude-tags",
13
- "--grep"
13
+ "--grep",
14
+ "--env",
15
+ "-e"
14
16
  ];
15
17
  var CLOUD_TEST_VALUE_FLAG_SET = new Set(CLOUD_TEST_VALUE_FLAGS);
16
18
  function isCloudTestValueFlag(name) {
@@ -35,7 +37,7 @@ function parseCloudTestArgs(value) {
35
37
  return { ok: false, message: "testArgs entries must be non-empty strings" };
36
38
  }
37
39
  if (entry.length > CLOUD_TEST_ARG_MAX_LENGTH || entry.includes("\0")) {
38
- return { ok: false, message: `testArgs entry is too long or carries a NUL byte: ${entry.slice(0, 60)}` };
40
+ return { ok: false, message: "testArgs entry is too long or carries a NUL byte" };
39
41
  }
40
42
  bytes += encoder.encode(entry).length;
41
43
  if (bytes > CLOUD_TEST_ARGS_MAX_BYTES) {
@@ -58,12 +60,19 @@ function parseCloudTestArgs(value) {
58
60
  const eq = entry.indexOf("=");
59
61
  const head = eq > 0 ? entry.slice(0, eq) : entry;
60
62
  if (!isCloudTestValueFlag(head)) {
61
- return { ok: false, message: `testArgs carries an unknown flag: ${head.slice(0, 60)}` };
63
+ return {
64
+ ok: false,
65
+ message: `testArgs carries an unknown flag: ${head.slice(0, 60)}`
66
+ };
62
67
  }
63
68
  if (eq > 0) {
64
- if (!entry.slice(eq + 1)) {
69
+ const value2 = entry.slice(eq + 1);
70
+ if (!value2) {
65
71
  return { ok: false, message: `${head} expects a value` };
66
72
  }
73
+ if ((head === "--env" || head === "-e") && value2.indexOf("=") < 1) {
74
+ return { ok: false, message: `${head} expects KEY=VALUE with a non-empty key` };
75
+ }
67
76
  args.push(entry);
68
77
  continue;
69
78
  }
@@ -71,6 +80,9 @@ function parseCloudTestArgs(value) {
71
80
  if (val === void 0 || val.startsWith("-")) {
72
81
  return { ok: false, message: `${head} expects a value` };
73
82
  }
83
+ if ((head === "--env" || head === "-e") && val.indexOf("=") < 1) {
84
+ return { ok: false, message: `${head} expects KEY=VALUE with a non-empty key` };
85
+ }
74
86
  args.push(entry, val);
75
87
  i += 1;
76
88
  }
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.633 | (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;
@@ -62,6 +62,7 @@ __export(home_paths_exports, {
62
62
  isDevWorkstation: () => isDevWorkstation,
63
63
  isOnboardingComplete: () => isOnboardingComplete,
64
64
  isSootsimDevCheckout: () => isSootsimDevCheckout,
65
+ playwrightCoreDir: () => playwrightCoreDir,
65
66
  profilesDir: () => profilesDir,
66
67
  readActiveRuntime: () => readActiveRuntime,
67
68
  readDaemonLockfile: () => readDaemonLockfile,
@@ -144,6 +145,9 @@ function electronUserDataDir() {
144
145
  function electronVersionDir(version) {
145
146
  return import_node_path.default.join(electronDir(), version);
146
147
  }
148
+ function playwrightCoreDir(version) {
149
+ return import_node_path.default.join(rnxHomeDir(), "playwright-core", version);
150
+ }
147
151
  function profilesDir() {
148
152
  return import_node_path.default.join(rnxHomeDir(), "profiles");
149
153
  }
@@ -613,6 +617,7 @@ function removeDevBridgeLockfile(owner) {
613
617
  isDevWorkstation,
614
618
  isOnboardingComplete,
615
619
  isSootsimDevCheckout,
620
+ playwrightCoreDir,
616
621
  profilesDir,
617
622
  readActiveRuntime,
618
623
  readDaemonLockfile,