peachsim 0.1.854 → 0.1.872

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 (94) hide show
  1. package/cli/commands/control.ts +37 -7
  2. package/cli/commands/do-chain.ts +1 -1
  3. package/cli/commands/inspect/settling.ts +2 -0
  4. package/cli/commands/inspect.ts +2 -2
  5. package/cli/commands/preview.ts +0 -11
  6. package/cli/current-sim.ts +11 -4
  7. package/cli/drivers/playwright-sim-host.ts +21 -13
  8. package/cli/drivers/playwright.ts +2 -47
  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/bundle-channel.cjs +21 -20
  24. package/dist-lib/capture-contract.cjs +1 -1
  25. package/dist-lib/capture-contract.mjs +1 -1
  26. package/dist-lib/cli-constants.cjs +1 -1
  27. package/dist-lib/cloud-contract.cjs +1 -1
  28. package/dist-lib/cloud-contract.mjs +1 -1
  29. package/dist-lib/cloud-test-args.cjs +1 -1
  30. package/dist-lib/cloud-test-args.mjs +1 -1
  31. package/dist-lib/cloud.cjs +1 -1
  32. package/dist-lib/cloud.mjs +1 -1
  33. package/dist-lib/config.cjs +1 -1
  34. package/dist-lib/detox/index.cjs +5 -3
  35. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  36. package/dist-lib/expo-swift-bundle.cjs +21 -20
  37. package/dist-lib/expo-swift-metadata.cjs +1 -1
  38. package/dist-lib/expo-swift-metadata.mjs +1 -1
  39. package/dist-lib/home-paths.cjs +1 -1
  40. package/dist-lib/host/bridge-host.cjs +21 -20
  41. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  42. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  43. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  44. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  45. package/dist-lib/host/websocket-proxy.cjs +1 -1
  46. package/dist-lib/index.cjs +7 -3
  47. package/dist-lib/jump-to-source-babel.cjs +1 -1
  48. package/dist-lib/jump-to-source-native.cjs +1 -1
  49. package/dist-lib/kotlin-host.cjs +1 -1
  50. package/dist-lib/menu.cjs +1 -1
  51. package/dist-lib/menu.mjs +1 -1
  52. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  53. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  54. package/dist-lib/metro-production-bundle.cjs +1 -1
  55. package/dist-lib/metro-production-bundle.mjs +1 -1
  56. package/dist-lib/metro.cjs +1 -1
  57. package/dist-lib/native-app-identity.cjs +1 -1
  58. package/dist-lib/native-app-identity.mjs +1 -1
  59. package/dist-lib/native-firebase-metadata.cjs +1 -1
  60. package/dist-lib/native-firebase-metadata.mjs +1 -1
  61. package/dist-lib/plist.cjs +1 -1
  62. package/dist-lib/plist.mjs +1 -1
  63. package/dist-lib/profiles.cjs +1 -1
  64. package/dist-lib/public-brand.cjs +1 -1
  65. package/dist-lib/react-native-host-modules.cjs +1 -1
  66. package/dist-lib/react-native-host-modules.mjs +1 -1
  67. package/dist-lib/render-mode.cjs +1 -1
  68. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  69. package/dist-lib/sdk.cjs +3 -1
  70. package/dist-lib/sdk.mjs +3 -1
  71. package/dist-lib/skills.cjs +61 -56
  72. package/dist-lib/swift-compile.cjs +1 -1
  73. package/dist-lib/swift-compile.mjs +1 -1
  74. package/dist-lib/swift-package.cjs +1 -1
  75. package/dist-lib/swift-package.mjs +1 -1
  76. package/dist-lib/swift-submit.cjs +1 -1
  77. package/dist-lib/swift-submit.mjs +1 -1
  78. package/dist-lib/swift-toolchain.cjs +1 -1
  79. package/dist-lib/swift.cjs +1 -1
  80. package/dist-lib/vite-swift.cjs +22 -21
  81. package/dist-lib/vite.cjs +1 -1
  82. package/dist-lib/worklet-executable.cjs +1 -1
  83. package/dist-lib/worklet-executable.mjs +1 -1
  84. package/kotlin/fork/NOTICE +4 -2
  85. package/kotlin/fork/README.md +12 -6
  86. package/kotlin/fork/build.sh +9 -2
  87. package/kotlin/fork/fork.json +1 -1
  88. package/kotlin/fork/skia-android-shaping.patch +124 -1
  89. package/kotlin/toolchain.json +3 -3
  90. package/package.json +1 -1
  91. package/skills/contrast/SKILL.md +2 -2
  92. package/skills/peach-debug/SKILL.md +2 -2
  93. package/src/swift-distribution.lock.json +8 -8
  94. package/src/swift-host.ts +14 -15
@@ -1084,7 +1084,15 @@ async function waitForSimReady(
1084
1084
  await sleep(intervalMs)
1085
1085
  }
1086
1086
 
1087
- return { bridge: null, attempts, intervalMs, minNodeCount, lastCount, lastError }
1087
+ const observed = lastError
1088
+ ? `last bridge error: ${lastError}`
1089
+ : lastCount === null
1090
+ ? 'guest never installed window.__sootsimTest'
1091
+ : `last node count: ${String(lastCount)} (needs > ${minNodeCount})`
1092
+ return {
1093
+ bridge: null,
1094
+ failure: `after ${attempts} polls over ${Math.round((attempts * intervalMs) / 1000)}s; ${observed}`,
1095
+ }
1088
1096
  }
1089
1097
 
1090
1098
  export async function waitForSimMatch(
@@ -2023,13 +2031,8 @@ export async function runOpenCommand(
2023
2031
  targetSim.id,
2024
2032
  )
2025
2033
  if (!ready.bridge) {
2026
- const observed = ready.lastError
2027
- ? `last bridge error: ${ready.lastError}`
2028
- : ready.lastCount === null
2029
- ? 'guest never installed window.__sootsimTest'
2030
- : `last node count: ${String(ready.lastCount)} (needs > ${ready.minNodeCount})`
2031
2034
  console.error(
2032
- ` timed out waiting for current sim to load target after ${ready.attempts} polls over ${Math.round((ready.attempts * ready.intervalMs) / 1000)}s; ${observed}`,
2035
+ ` timed out waiting for current sim to load target ${ready.failure}`,
2033
2036
  )
2034
2037
  await printBridgeFailureDiagnostics(bridge, {
2035
2038
  errorsCommand: `peach get errors 5${simHint}`,
@@ -2139,6 +2142,33 @@ export async function runOpenCommand(
2139
2142
  if (opts.resources) opts.resources.simId = match.id
2140
2143
  saveCurrentSimId(match.id)
2141
2144
  signalDriverLaunchConnected(result)
2145
+ // a sim registers with the bridge as its page boots, before its app has a
2146
+ // tree; open returns a sim the next command can drive, as a reused one does.
2147
+ // a first dev-server bundle can take as long as the launch itself, so the
2148
+ // launch's own connect budget bounds it.
2149
+ const ready = await waitForSimReady(parsed.wsPort, parsed.commandTimeoutMs, match.id, {
2150
+ intervalMs: connectWait.intervalMs,
2151
+ attempts: connectWait.attempts,
2152
+ })
2153
+ if (!ready.bridge) {
2154
+ console.error(
2155
+ ` timed out waiting for opened sim ${match.id} to load ${ready.failure}`,
2156
+ )
2157
+ const hint = ` --sim ${match.id}`
2158
+ const bridge = createBridge(parsed.wsPort, {
2159
+ commandTimeoutMs: parsed.commandTimeoutMs,
2160
+ simId: match.id,
2161
+ simIdSource: 'flag',
2162
+ })
2163
+ await printBridgeFailureDiagnostics(bridge, {
2164
+ errorsCommand: `peach get errors 5${hint}`,
2165
+ warningsCommand: `peach get warnings 5${hint}`,
2166
+ requestsCommand: `peach get requests 5${hint}`,
2167
+ })
2168
+ bridge.close()
2169
+ rnxExit(1)
2170
+ }
2171
+ ready.bridge.close()
2142
2172
  printOpenedSim(openUrl, match, `${driver.name} driver`, quiet)
2143
2173
  await maybeDescribeAfterOpen(parsed.wsPort, match.id, args)
2144
2174
  printAgentHints(quiet)
@@ -433,7 +433,7 @@ export async function runDoChain(
433
433
  const settled = await sim.settle({ maxMs: budgetMs })
434
434
  if (!settled.settled) {
435
435
  process.stderr.write(
436
- ` ⚠ auto-wait timed out after ${settled.elapsed ?? budgetMs}ms. next command may see mid-animation state. use \`peach do settle\` for a longer wait.\n`,
436
+ ` ⚠ auto-wait timed out after ${settled.elapsed ?? budgetMs}ms (${settled.blockedBy}). next command may see mid-animation state. use \`peach do settle\` for a longer wait.\n`,
437
437
  )
438
438
  }
439
439
  } catch {}
@@ -242,6 +242,8 @@ export async function waitForSootsimIdle({
242
242
  if (paintStill && !last.screenPixels) blockers.push('screen pixels unavailable')
243
243
  else if (paintStill && !screenUnchanged(last.screenPixels)) blockers.push('screen pixels still changing')
244
244
  if (last.requestInFlight > 0) blockers.push(last.requestInFlight + ' requests in flight')
245
+ else if (last.requestTotal !== lastRequestTotal) blockers.push('new requests issued')
246
+ if (polls < 2) blockers.push('sim too busy to poll twice')
245
247
  return {
246
248
  settled: false,
247
249
  elapsed: Date.now() - start,
@@ -1344,7 +1344,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1344
1344
  // transitions should use an explicit `do settle` or `wait idle`.
1345
1345
  const budgetMs = isAgentEnv() ? 400 : 200
1346
1346
  try {
1347
- const { settled, elapsed } = await waitForSootsimIdle({
1347
+ const { settled, elapsed, blockedBy } = await waitForSootsimIdle({
1348
1348
  bridge: b,
1349
1349
  maxMs: budgetMs,
1350
1350
  pollMs: 32,
@@ -1352,7 +1352,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1352
1352
  })
1353
1353
  if (!settled) {
1354
1354
  process.stderr.write(
1355
- ` ⚠ auto-wait timed out after ${elapsed ?? budgetMs}ms — next command may see mid-animation state. use \`peach do settle\` for a longer wait.\n`,
1355
+ ` ⚠ auto-wait timed out after ${elapsed ?? budgetMs}ms (${blockedBy}) — next command may see mid-animation state. use \`peach do settle\` for a longer wait.\n`,
1356
1356
  )
1357
1357
  }
1358
1358
  } catch {
@@ -34,17 +34,6 @@ function takeValue(args: string[], flag: string): string | null {
34
34
  }
35
35
 
36
36
  export async function runPreview(args: string[]): Promise<number> {
37
- if (args.includes('--help') || args.includes('-h')) {
38
- console.log(`
39
- peach preview: publish a React Native project or bundle as a standalone share
40
-
41
- usage:
42
- peach preview <project-or-bundle> [--platform ios|android] [--open] [--json]
43
-
44
- The share contains the immutable build and its automatically discovered Metro assets. It is not a recorded replay.
45
- `)
46
- return 0
47
- }
48
37
  try {
49
38
  const input = [...args]
50
39
  const origin = await resolveDefaultUploadOrigin(
@@ -79,6 +79,11 @@ export interface CliIdentity {
79
79
  // tab's /usr/bin/login instead (real incident 2026-08-06: six chrome hosts
80
80
  // survived their agents, 17GB rss, load 19 with the GPU saturated).
81
81
  const IMMORTAL_HOST_COMM_RE = /^(?:tmux|screen)|^tm$/i
82
+ // pid 1 is normally an init system, which outlives every session. a container
83
+ // started without one runs its job as pid 1 (`docker run image sh -c 'peach
84
+ // open ...'`), and that job is the session: it ends when the container does.
85
+ const INIT_COMM_RE =
86
+ /^(?:init|systemd|launchd|tini|docker-init|dumb-init|catatonit|s6-svscan|runsvdir)$/i
82
87
 
83
88
  function findTopAncestor(start: number, maxDepth = 20): number | null {
84
89
  // check each CANDIDATE's own comm and return the child below a multiplexer
@@ -94,10 +99,12 @@ function findTopAncestor(start: number, maxDepth = 20): number | null {
94
99
  // a readable ordinary process directly below init is itself the stable
95
100
  // session root. this is the shape produced by detached job launchers, and
96
101
  // returning null here used to disable the browser owner's lifetime watch.
97
- // an unreadable or known-immortal process has no defensible child bound at
98
- // this point, so leave it unresolved and make the launcher fail loudly.
102
+ // so is a container job running as pid 1. an unreadable or known-immortal
103
+ // process has no defensible child bound at this point, so leave it
104
+ // unresolved and make the launcher fail loudly.
99
105
  const comm = getProcessComm(start)
100
- return start > 1 && comm && !IMMORTAL_HOST_COMM_RE.test(comm) ? start : null
106
+ if (!comm || start < 1 || IMMORTAL_HOST_COMM_RE.test(comm)) return null
107
+ return start > 1 || !INIT_COMM_RE.test(comm) ? start : null
101
108
  }
102
109
  for (let i = 0; i < maxDepth; i++) {
103
110
  const comm = getProcessComm(pid)
@@ -124,7 +131,7 @@ export function getCliIdentity(): CliIdentity {
124
131
  }
125
132
  }
126
133
  const topPid = findTopAncestor(process.ppid)
127
- if (topPid && topPid > 1) {
134
+ if (topPid) {
128
135
  return { key: `gppid-${topPid}`, source: 'grand-ppid', stable: true }
129
136
  }
130
137
  return { key: `pid-${process.ppid}`, source: 'ppid', stable: false }
@@ -146,17 +146,13 @@ const diskCacheDir = mkdtempSync(join(tmpdir(), 'peach-playwright-cache-'));
146
146
  const chromePidsByProfile = () => {
147
147
  if (!reapEnabled) return [];
148
148
  try {
149
- // escape special regex chars in profileDir to ensure we match only
150
- // the exact --user-data-dir parameter. without proper escaping, multiple
151
- // browsers with overlapping paths (e.g. /tmp/a and /tmp/ab) would match
152
- // incorrectly. use a trailing space or end-of-line to avoid substring matches.
153
- let escapedPath = profileDir;
154
- for (const char of ['.', '+', '*', '?', '^', '$', '{', '}', '(', ')', '|', '[', ']', '\\\\']) {
155
- escapedPath = escapedPath.split(char).join('\\\\' + char);
156
- }
157
- const pattern = '--user-data-dir=' + escapedPath + '(?:\\\\s|$)';
158
- return execSync('pgrep -f ' + pattern + ' || true', { stdio: ['ignore', 'pipe', 'ignore'] })
159
- .toString().split('\\n').filter(Boolean).map((p) => Number(p))
149
+ // match the whole --user-data-dir argument: a pattern search also found
150
+ // browsers whose profile path merely starts with this one.
151
+ const flag = ' --user-data-dir=' + profileDir + ' ';
152
+ return execSync('ps -axo pid=,command=', { stdio: ['ignore', 'pipe', 'ignore'] })
153
+ .toString().split('\\n').map((line) => line.trim().match(/^(\\d+)\\s+(.*)$/))
154
+ .filter((row) => row && (' ' + row[2] + ' ').includes(flag))
155
+ .map((row) => Number(row[1]))
160
156
  .filter((p) => p && p !== process.pid);
161
157
  } catch { return []; }
162
158
  };
@@ -378,7 +374,7 @@ const cleanupProfile = () => {
378
374
  // down when it's gone. ESRCH (kill throws) = owner exited; EPERM = alive but
379
375
  // not signalable by us, which still counts as alive.
380
376
  const startOwnerWatch = () => {
381
- if (!Number.isInteger(ownerPid) || ownerPid <= 1) {
377
+ if (!Number.isInteger(ownerPid) || ownerPid < 1) {
382
378
  throw new Error('[playwright-driver] missing valid owning process; refusing unsupervised browser host');
383
379
  }
384
380
  const intervalMs = Number.isFinite(ownerPollMs) && ownerPollMs > 0 ? ownerPollMs : 5000;
@@ -685,7 +681,19 @@ const cleanupProfile = () => {
685
681
  context.on('close', () => { void shutdown(0); });
686
682
  page.on('close', () => { void shutdown(0); });
687
683
  })().catch((err) => {
688
- process.stderr.write(String((err && err.stack) || err) + '\\n');
684
+ const detail = String((err && err.stack) || err);
685
+ process.stderr.write(detail + '\\n');
686
+ // chrome's own error ("Missing X server") says what is wrong on a linux
687
+ // box with no display, not what to do about it.
688
+ if (
689
+ process.platform === 'linux' &&
690
+ !headless &&
691
+ !process.env.DISPLAY &&
692
+ !process.env.WAYLAND_DISPLAY &&
693
+ /missing x server|cannot open display|x server|x11/i.test(detail)
694
+ ) {
695
+ process.stderr.write('hint: linux without DISPLAY/WAYLAND_DISPLAY — rerun without --headed (or add --headless) to run playwright headless.\\n');
696
+ }
689
697
  process.exit(1);
690
698
  });
691
699
  `
@@ -13,7 +13,7 @@
13
13
  // until the sim's page closes (e.g. via `peach close`).
14
14
 
15
15
  import { spawn } from 'child_process'
16
- import { closeSync, mkdtempSync, openSync, readFileSync } from 'fs'
16
+ import { closeSync, mkdtempSync, openSync } from 'fs'
17
17
  import { createServer } from 'net'
18
18
  import { tmpdir } from 'os'
19
19
  import { join } from 'path'
@@ -49,22 +49,6 @@ function probe(): DriverAvailability {
49
49
  }
50
50
  }
51
51
 
52
- // when a headed launch fails on a Linux box with no display, chrome's own
53
- // error ("Missing X server", "cannot open display") tells the user *what*
54
- // is wrong but not *what to do*. surface the actionable flag.
55
- function headlessHintForLinuxFailure(
56
- opts: DriverLaunchOptions,
57
- detail: string,
58
- ): string | null {
59
- if (process.platform !== 'linux') return null
60
- if (opts.headless) return null
61
- if (process.env.DISPLAY || process.env.WAYLAND_DISPLAY) return null
62
- if (!/missing x server|cannot open display|x server|x11/i.test(detail)) {
63
- return null
64
- }
65
- return ' hint: linux without DISPLAY/WAYLAND_DISPLAY — rerun without --headed (or add --headless) to run playwright headless.'
66
- }
67
-
68
52
  // resolve the Chrome user-data dir for a profiled launch. a non-empty
69
53
  // return means the host should use a persistent context; '' means a plain
70
54
  // (in-memory) browser launch.
@@ -98,7 +82,7 @@ async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
98
82
  return { launched: false, message: 'playwright driver requires a target url' }
99
83
  }
100
84
  const ownerPid = opts.ownerPid
101
- if (ownerPid === undefined || !Number.isInteger(ownerPid) || ownerPid <= 1) {
85
+ if (ownerPid === undefined || !Number.isInteger(ownerPid) || ownerPid < 1) {
102
86
  return {
103
87
  launched: false,
104
88
  message: 'playwright driver requires a valid owning session process',
@@ -211,35 +195,6 @@ async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
211
195
  )
212
196
  child.unref()
213
197
 
214
- // give the host a short window to fail fast (resolve errors, browser
215
- // binary missing). if it is still alive after that, the sim is on its
216
- // way and the caller's own `waitForSimMatch` takes over.
217
- const earlyExit = await new Promise<number | null>((resolve) => {
218
- const timer = setTimeout(() => resolve(null), 4000)
219
- child.once('exit', (code) => {
220
- clearTimeout(timer)
221
- resolve(code ?? 0)
222
- })
223
- })
224
- if (earlyExit !== null) {
225
- // ANY exit inside the 4s startup window is a failure: a healthy host
226
- // stays alive until the sim disconnects (much longer than 4s). a code-0
227
- // early exit can happen when the inline script's top-level catch fires
228
- // before the launch even reaches a thrown error path, or when chromium
229
- // is killed externally — both still mean "no sim is coming". emit the
230
- // host's FULL stderr — its first line is the error message, and the
231
- // prior `slice(-3)` kept only trailing stack frames, dropping the
232
- // message and making CI failures undiagnosable. leave errLog on disk
233
- // (path included) so it can be inspected after the fact.
234
- const detail = readFileSync(errLog, 'utf8').trim()
235
- const hint = headlessHintForLinuxFailure(opts, detail)
236
- return {
237
- launched: false,
238
- message: `playwright host exited early (code ${earlyExit}) — host log ${errLog}${
239
- detail ? `:\n${detail}` : ''
240
- }${hint ? `\n${hint}` : ''}`,
241
- }
242
- }
243
198
  // name both lifetime bounds: the bridge closes an automation sim neither a
244
199
  // cli nor a person has touched for the idle window, and the host watchdog closes chrome ~5s
245
200
  // after the owning session pid exits, which surprises one-shot/detached
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } 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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } 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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -2369,24 +2369,24 @@ var swift_distribution_lock_default;
2369
2369
  var init_swift_distribution_lock = __esm({
2370
2370
  "src/swift-distribution.lock.json"() {
2371
2371
  swift_distribution_lock_default = {
2372
- id: "8a53b074b33eb8b5",
2372
+ id: "cf49b84963eae4ec",
2373
2373
  release: "swift-6.3-RELEASE",
2374
2374
  wasmSdkId: "swift-6.3-RELEASE_wasm-peach-41921598-peach-edd95e37",
2375
2375
  wasmSdkUrl: "https://r2.rnxsim.com/swift-wasm-sdk/swift-6.3-RELEASE_wasm-peach-41921598-peach-edd95e37.artifactbundle.tar.gz",
2376
2376
  wasmSdkChecksum: "e8b76a6b78c21e9e16a6943a691ea001aeb0a18518d775a26130520303eb5c6d",
2377
- source: "882ff4ff4b262e108926af9d13985fba69132c1a",
2377
+ source: "7b29f31b65a02aea2d28fd0518e0118f2337f2b7",
2378
2378
  hosts: {
2379
2379
  "darwin-arm64": {
2380
- sha256: "6199b51b4d4f963db72bff2fc7174d7944bbf7c6f0379b58fc9fe1db81081dd7",
2381
- size: 39773614
2380
+ sha256: "c120569e34e16edb81fe0fabe92a9d7c4c5f64b06363726b466f996cdb05588b",
2381
+ size: 43318901
2382
2382
  },
2383
2383
  "linux-x64": {
2384
- sha256: "dd414d2c73175b5ea4e142f414615e2648102f827a998b8a80edf3c0a8acbb0f",
2385
- size: 39779064
2384
+ sha256: "d8a65a3f77d7302ed3547f525c4274a6c7aa2bdccdf9a41f4864ad305d0ae643",
2385
+ size: 43324299
2386
2386
  },
2387
2387
  "linux-arm64": {
2388
- sha256: "67396e3baa888a4463ecfdeb9f14996e8f5ee397c181e64cf0e82868b27d3463",
2389
- size: 39778119
2388
+ sha256: "d47964d033ac59af2417939703335148993ea2d3e931a7db048a8080780c5de6",
2389
+ size: 43323284
2390
2390
  }
2391
2391
  }
2392
2392
  };
@@ -8177,11 +8177,13 @@ function packageSources(packagePath) {
8177
8177
  }
8178
8178
  return files2;
8179
8179
  }
8180
- function packageSnapshot(project) {
8180
+ function packageSnapshot(project, entry) {
8181
8181
  const files2 = packageSources(project.packagePath);
8182
+ const layout = xcodeLayout(project.packagePath);
8182
8183
  const native = nativeSourceDescriptor(project.packagePath);
8183
8184
  return {
8184
8185
  files: files2,
8186
+ entry: layout ? xcodeInputKey(layout, import_node_path15.default.resolve(project.packagePath, entry), entry) : entry,
8185
8187
  resourcePaths: swiftImplicitResourcePaths(
8186
8188
  resourceCandidateFiles(project.packagePath).map(
8187
8189
  (file) => import_node_path15.default.relative(project.packagePath, file).split(import_node_path15.default.sep).join(import_node_path15.default.posix.sep)
@@ -8199,18 +8201,18 @@ function packageSnapshot(project) {
8199
8201
  } : {}
8200
8202
  };
8201
8203
  }
8202
- function snapshotCompileInput(snapshot, entry) {
8204
+ function snapshotCompileInput(snapshot) {
8203
8205
  const input = {
8204
8206
  files: snapshot.files,
8205
8207
  resourcePaths: snapshot.resourcePaths,
8206
8208
  resources: snapshot.bundleFiles.files,
8207
8209
  images: snapshot.resources.images,
8208
- entry,
8210
+ entry: snapshot.entry,
8209
8211
  oneModule: true
8210
8212
  };
8211
8213
  return snapshot.glue ? withNativeSourceGlue(input, snapshot.glue) : input;
8212
8214
  }
8213
- async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, snapshot) {
8215
+ async function compile(packagePath, stamp, moduleRootOverride, hosted, snapshot) {
8214
8216
  const resources = {
8215
8217
  table: snapshot.resources.table,
8216
8218
  colors: snapshot.resources.colors,
@@ -8224,7 +8226,7 @@ async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, sn
8224
8226
  };
8225
8227
  if (hosted)
8226
8228
  return {
8227
- ...await compileRemote(packagePath, entry, snapshot, hosted),
8229
+ ...await compileRemote(packagePath, snapshot, hosted),
8228
8230
  stamp,
8229
8231
  package: content
8230
8232
  };
@@ -8233,12 +8235,12 @@ async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, sn
8233
8235
  ) ?? await swiftDistributionRoot();
8234
8236
  if (!moduleRoot)
8235
8237
  return {
8236
- ...await compileRemote(packagePath, entry, snapshot),
8238
+ ...await compileRemote(packagePath, snapshot),
8237
8239
  stamp,
8238
8240
  package: content
8239
8241
  };
8240
8242
  const toolchain = swiftModuleToolchain(moduleRoot);
8241
- const input = snapshotCompileInput(snapshot, entry);
8243
+ const input = snapshotCompileInput(snapshot);
8242
8244
  const targets = compileTargets(input).map((target) => target.name);
8243
8245
  const missing = missingSwiftModules(
8244
8246
  input.files,
@@ -8356,7 +8358,7 @@ async function missingModulesMessage(packagePath, missing) {
8356
8358
  })
8357
8359
  ].join("\n");
8358
8360
  }
8359
- async function compileRemote(packagePath, entry, snapshot, hosted) {
8361
+ async function compileRemote(packagePath, snapshot, hosted) {
8360
8362
  const auth = hosted ? null : resolveCliAuth();
8361
8363
  if (!hosted && (!auth || auth.kind === "github")) {
8362
8364
  throw new Error(
@@ -8390,7 +8392,7 @@ async function compileRemote(packagePath, entry, snapshot, hosted) {
8390
8392
  resourcePaths: snapshot.resourcePaths,
8391
8393
  resources: snapshot.bundleFiles.files,
8392
8394
  images: snapshot.resources.images,
8393
- entry,
8395
+ entry: snapshot.entry,
8394
8396
  packageId: descriptor?.packageId ?? swiftPackageId(packagePath)
8395
8397
  },
8396
8398
  origin,
@@ -8438,13 +8440,12 @@ function artifactFor(project, entry, moduleRoot) {
8438
8440
  const again = () => artifactFor(project, entry, moduleRoot);
8439
8441
  return running.promise.then(again, again);
8440
8442
  }
8441
- const snapshot = packageSnapshot(project);
8443
+ const snapshot = packageSnapshot(project, entry);
8442
8444
  if (sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted)) !== stamp) {
8443
8445
  return artifactFor(project, entry, moduleRoot);
8444
8446
  }
8445
8447
  const promise = compile(
8446
8448
  project.packagePath,
8447
- entry,
8448
8449
  stamp,
8449
8450
  moduleRoot,
8450
8451
  project.hosted,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (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.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.854 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.872 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -6525,12 +6525,14 @@ var IDENTITY_ENV_VARS = [
6525
6525
  // vscode integrated terminal
6526
6526
  ];
6527
6527
  var IMMORTAL_HOST_COMM_RE = /^(?:tmux|screen)|^tm$/i;
6528
+ var INIT_COMM_RE = /^(?:init|systemd|launchd|tini|docker-init|dumb-init|catatonit|s6-svscan|runsvdir)$/i;
6528
6529
  function findTopAncestor(start, maxDepth = 20) {
6529
6530
  let prev = start;
6530
6531
  let pid = getParentPid(start);
6531
6532
  if (!pid || pid <= 1) {
6532
6533
  const comm = getProcessComm(start);
6533
- return start > 1 && comm && !IMMORTAL_HOST_COMM_RE.test(comm) ? start : null;
6534
+ if (!comm || start < 1 || IMMORTAL_HOST_COMM_RE.test(comm)) return null;
6535
+ return start > 1 || !INIT_COMM_RE.test(comm) ? start : null;
6534
6536
  }
6535
6537
  for (let i = 0; i < maxDepth; i++) {
6536
6538
  const comm = getProcessComm(pid);
@@ -6552,7 +6554,7 @@ function getCliIdentity() {
6552
6554
  }
6553
6555
  }
6554
6556
  const topPid = findTopAncestor(process.ppid);
6555
- if (topPid && topPid > 1) {
6557
+ if (topPid) {
6556
6558
  return { key: `gppid-${topPid}`, source: "grand-ppid", stable: true };
6557
6559
  }
6558
6560
  return { key: `pid-${process.ppid}`, source: "ppid", stable: false };