peachsim 0.1.571 → 0.1.573

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 (235) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +106 -106
  3. package/cli/app-config.ts +1 -1
  4. package/cli/app-fonts.ts +4 -4
  5. package/cli/auth.ts +11 -11
  6. package/cli/bin.ts +4 -4
  7. package/cli/bridge-flow-runner.ts +13 -13
  8. package/cli/browser-evals.ts +2 -2
  9. package/cli/cli-update.ts +6 -6
  10. package/cli/cloud-client.ts +16 -16
  11. package/cli/cloud-dispatch.ts +2 -2
  12. package/cli/cloud-session.ts +12 -12
  13. package/cli/cloud-test-tunnel.ts +4 -4
  14. package/cli/command-registry.ts +7 -7
  15. package/cli/commands/agent-wrapper.ts +7 -7
  16. package/cli/commands/agent.ts +16 -16
  17. package/cli/commands/app-fonts.ts +3 -3
  18. package/cli/commands/assert.ts +10 -10
  19. package/cli/commands/auth.ts +5 -5
  20. package/cli/commands/box/checkout-plane.ts +1 -1
  21. package/cli/commands/box/plane-share.ts +2 -2
  22. package/cli/commands/box/rnx-command.ts +5 -5
  23. package/cli/commands/box.ts +38 -38
  24. package/cli/commands/camera.ts +13 -13
  25. package/cli/commands/cleanup.ts +13 -13
  26. package/cli/commands/compat.ts +7 -7
  27. package/cli/commands/config.ts +5 -5
  28. package/cli/commands/control.ts +63 -63
  29. package/cli/commands/cpu-profile.ts +11 -11
  30. package/cli/commands/daemon-mac-app.ts +10 -10
  31. package/cli/commands/daemon.ts +29 -27
  32. package/cli/commands/debug.ts +35 -35
  33. package/cli/commands/desktop.ts +3 -3
  34. package/cli/commands/detox.ts +33 -33
  35. package/cli/commands/device.ts +9 -9
  36. package/cli/commands/diagnose.ts +17 -17
  37. package/cli/commands/do-chain.ts +4 -4
  38. package/cli/commands/electron.ts +9 -9
  39. package/cli/commands/film.ts +9 -9
  40. package/cli/commands/flow.ts +49 -49
  41. package/cli/commands/inspect/core.ts +12 -12
  42. package/cli/commands/inspect/count.ts +1 -1
  43. package/cli/commands/inspect/describe.ts +1 -1
  44. package/cli/commands/inspect/env.ts +2 -2
  45. package/cli/commands/inspect/find.ts +2 -2
  46. package/cli/commands/inspect/get-layout.ts +2 -2
  47. package/cli/commands/inspect/keyboard.ts +1 -1
  48. package/cli/commands/inspect/list.ts +4 -4
  49. package/cli/commands/inspect/memory.ts +1 -1
  50. package/cli/commands/inspect/resolve-target.ts +1 -1
  51. package/cli/commands/inspect/screens.ts +1 -1
  52. package/cli/commands/inspect/shared.ts +1 -1
  53. package/cli/commands/inspect/tree.ts +1 -1
  54. package/cli/commands/inspect/url.ts +1 -1
  55. package/cli/commands/inspect/wait-event.ts +5 -5
  56. package/cli/commands/inspect.ts +82 -82
  57. package/cli/commands/install-cli.ts +16 -16
  58. package/cli/commands/install-desktop.ts +26 -26
  59. package/cli/commands/login.ts +11 -11
  60. package/cli/commands/maestro-generate.ts +10 -10
  61. package/cli/commands/maestro.ts +77 -67
  62. package/cli/commands/mode.ts +4 -4
  63. package/cli/commands/no-bridge-hint.ts +12 -12
  64. package/cli/commands/perf.ts +11 -11
  65. package/cli/commands/permissions.ts +5 -5
  66. package/cli/commands/platform.ts +21 -21
  67. package/cli/commands/preview.ts +5 -5
  68. package/cli/commands/profile.ts +12 -12
  69. package/cli/commands/react.ts +15 -15
  70. package/cli/commands/record.ts +31 -31
  71. package/cli/commands/report-issue.ts +4 -4
  72. package/cli/commands/reset.ts +2 -2
  73. package/cli/commands/runtime.ts +23 -23
  74. package/cli/commands/screenshot-command.ts +2 -2
  75. package/cli/commands/screenshot-layers.ts +5 -5
  76. package/cli/commands/screenshot-mode.ts +7 -7
  77. package/cli/commands/screenshot.ts +24 -24
  78. package/cli/commands/screenshots-capture.ts +13 -13
  79. package/cli/commands/screenshots.ts +6 -6
  80. package/cli/commands/serve.ts +12 -12
  81. package/cli/commands/setup.ts +25 -25
  82. package/cli/commands/skills.ts +30 -23
  83. package/cli/commands/slides.ts +20 -20
  84. package/cli/commands/state.ts +2 -2
  85. package/cli/commands/storage.ts +3 -3
  86. package/cli/commands/telemetry.ts +2 -2
  87. package/cli/commands/test.ts +15 -15
  88. package/cli/commands/three-mode.ts +17 -17
  89. package/cli/commands/timeline.ts +12 -12
  90. package/cli/commands/upgrade.ts +11 -11
  91. package/cli/commands/upload.ts +26 -26
  92. package/cli/commands/version.ts +7 -7
  93. package/cli/commands/what-happened.ts +20 -20
  94. package/cli/current-sim.ts +3 -3
  95. package/cli/desktop-companion.ts +16 -16
  96. package/cli/drivers/electron.ts +4 -4
  97. package/cli/drivers/playwright-sim-host.ts +7 -7
  98. package/cli/drivers/playwright.ts +4 -4
  99. package/cli/drivers/registry.ts +1 -1
  100. package/cli/drivers/types.ts +5 -5
  101. package/cli/flow-export.ts +1 -1
  102. package/cli/flow-file.ts +5 -5
  103. package/cli/flow-session.ts +1 -1
  104. package/cli/help-core.ts +13 -13
  105. package/cli/hints.ts +14 -14
  106. package/cli/inspect-notice-state.ts +1 -1
  107. package/cli/internal-child.ts +2 -2
  108. package/cli/maestro-js.ts +4 -4
  109. package/cli/maestro-report.ts +1 -1
  110. package/cli/main.ts +14 -14
  111. package/cli/outbound-endpoints.ts +30 -30
  112. package/cli/parse-args.ts +7 -7
  113. package/cli/privacy.ts +1 -1
  114. package/cli/recording-access.ts +10 -10
  115. package/cli/resolve-assets.ts +2 -2
  116. package/cli/rnx-in-process.ts +5 -5
  117. package/cli/run-registry.ts +1 -1
  118. package/cli/run-rnx-core.ts +3 -3
  119. package/cli/run-rnx.ts +1 -1
  120. package/cli/runtime-notes.ts +1 -1
  121. package/cli/self-invocation.ts +1 -1
  122. package/cli/send-to-box.ts +1 -1
  123. package/cli/shell-init.ts +40 -40
  124. package/cli/ui.ts +1 -1
  125. package/cli/ws-bridge.ts +22 -22
  126. package/detox/config-loader.ts +1 -1
  127. package/detox/index.ts +28 -28
  128. package/detox/navigation.ts +2 -2
  129. package/dist-lib/agent-daemon-client.cjs +12 -12
  130. package/dist-lib/agent-events.cjs +1 -1
  131. package/dist-lib/agent-identity.cjs +2 -2
  132. package/dist-lib/agent-sessions.cjs +12 -12
  133. package/dist-lib/attached-projects.cjs +4 -4
  134. package/dist-lib/auth/shared-session.cjs +4 -4
  135. package/dist-lib/backend-origin.cjs +1 -1
  136. package/dist-lib/beta.cjs +1 -1
  137. package/dist-lib/beta.mjs +1 -1
  138. package/dist-lib/bridge-constants.cjs +4 -4
  139. package/dist-lib/bridge-contract-input.cjs +1 -1
  140. package/dist-lib/bridge-contract-input.mjs +1 -1
  141. package/dist-lib/bridge-contract.cjs +2 -2
  142. package/dist-lib/bridge-contract.mjs +2 -2
  143. package/dist-lib/capture-contract.cjs +1 -1
  144. package/dist-lib/capture-contract.mjs +1 -1
  145. package/dist-lib/cli-constants.cjs +1 -1
  146. package/dist-lib/cloud-contract.cjs +1 -1
  147. package/dist-lib/cloud-contract.mjs +1 -1
  148. package/dist-lib/cloud-test-args.cjs +1 -1
  149. package/dist-lib/cloud-test-args.mjs +1 -1
  150. package/dist-lib/cloud.cjs +42 -42
  151. package/dist-lib/cloud.mjs +42 -42
  152. package/dist-lib/config.cjs +2 -2
  153. package/dist-lib/detox/index.cjs +29 -29
  154. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  155. package/dist-lib/home-paths.cjs +12 -12
  156. package/dist-lib/host/bridge-host.cjs +72 -71
  157. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  158. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  159. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  160. package/dist-lib/host/replacement-module-handler.cjs +6 -6
  161. package/dist-lib/host/websocket-proxy.cjs +1 -1
  162. package/dist-lib/index.cjs +48 -48
  163. package/dist-lib/jump-to-source-babel.cjs +1 -1
  164. package/dist-lib/jump-to-source-native.cjs +1 -1
  165. package/dist-lib/menu.cjs +5 -5
  166. package/dist-lib/menu.mjs +5 -5
  167. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  168. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  169. package/dist-lib/metro-production-bundle.cjs +1 -1
  170. package/dist-lib/metro-production-bundle.mjs +1 -1
  171. package/dist-lib/metro.cjs +15 -15
  172. package/dist-lib/profiles.cjs +4 -4
  173. package/dist-lib/public-brand.cjs +3 -3
  174. package/dist-lib/react-native-host-modules.cjs +1 -1
  175. package/dist-lib/react-native-host-modules.mjs +1 -1
  176. package/dist-lib/render-mode.cjs +1 -1
  177. package/dist-lib/scripts/dev-server-scanner.cjs +2 -1
  178. package/dist-lib/sdk.cjs +9 -9
  179. package/dist-lib/sdk.mjs +9 -9
  180. package/dist-lib/skills.cjs +416 -415
  181. package/dist-lib/swift-compile.cjs +1 -1
  182. package/dist-lib/swift-compile.mjs +1 -1
  183. package/dist-lib/swift-package.cjs +1 -1
  184. package/dist-lib/swift-package.mjs +1 -1
  185. package/dist-lib/swift-submit.cjs +1 -1
  186. package/dist-lib/swift-submit.mjs +1 -1
  187. package/dist-lib/swift.cjs +1 -1
  188. package/dist-lib/vite.cjs +24 -24
  189. package/package.json +1 -1
  190. package/scripts/dev-server-scanner.ts +4 -3
  191. package/skills/contrast/SKILL.md +75 -75
  192. package/skills/{rnx-debug → peach-debug}/SKILL.md +90 -90
  193. package/skills/{rnx-perf → peach-perf}/SKILL.md +13 -13
  194. package/skills/{rnx-setup → peach-setup}/SKILL.md +60 -60
  195. package/skills/{rnx-test → peach-test}/SKILL.md +44 -44
  196. package/skills/{rnx-visual → peach-visual}/SKILL.md +26 -26
  197. package/src/agent-daemon-client.ts +5 -5
  198. package/src/agent-events.ts +1 -1
  199. package/src/agent-identity.ts +1 -1
  200. package/src/agent-sessions.ts +13 -13
  201. package/src/attached-projects.ts +1 -1
  202. package/src/auth/shared-session.ts +1 -1
  203. package/src/bridge-constants.ts +3 -3
  204. package/src/bridge-contract-input.ts +1 -1
  205. package/src/bridge-contract.ts +3 -3
  206. package/src/cli-version.ts +6 -6
  207. package/src/cloud.ts +40 -40
  208. package/src/config.ts +1 -1
  209. package/src/connect.ts +6 -6
  210. package/src/dev-server-open.ts +8 -8
  211. package/src/disk-cleanup.ts +3 -3
  212. package/src/home-paths.ts +26 -26
  213. package/src/host/agent-host.ts +3 -3
  214. package/src/host/bridge-host.ts +33 -33
  215. package/src/host/fetch-proxy-handler.ts +1 -1
  216. package/src/host/plane-host.ts +2 -2
  217. package/src/host/replacement-module-handler.ts +2 -2
  218. package/src/menu.ts +2 -2
  219. package/src/metro-plugin.ts +7 -7
  220. package/src/metro-production-bundle.ts +2 -2
  221. package/src/native-dev-bundle-url.ts +2 -2
  222. package/src/playwright-host-log.ts +1 -1
  223. package/src/public-brand.ts +2 -2
  224. package/src/react-native-host-modules.ts +1 -1
  225. package/src/rolldown-plugin-swift.ts +3 -3
  226. package/src/runtime-assets.ts +11 -11
  227. package/src/runtime-delivery.ts +6 -6
  228. package/src/screenshots/orchestrate.ts +1 -1
  229. package/src/screenshots/org-deck.ts +1 -1
  230. package/src/screenshots/schema.ts +2 -2
  231. package/src/sim-client.ts +1 -1
  232. package/src/skills/builtin/compat-check.ts +2 -2
  233. package/src/vite-plugin-one.ts +8 -8
  234. package/src/vite-plugin-swift.ts +3 -3
  235. package/src/vite-plugin.ts +6 -19
package/cli/bin.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // rnx CLI entry point. the full command and verb surface lives in the
3
+ // peach CLI entry point. the full command and verb surface lives in the
4
4
  // registry at `packages/peach-skills/src/cli/meta.ts` — help output,
5
5
  // website docs, and agent skills all read from there. do not duplicate
6
- // command listings in this file; run `rnx --help` for the canonical
6
+ // command listings in this file; run `peach --help` for the canonical
7
7
  // surface.
8
8
  //
9
9
  // this file only routes. the hidden entry points below each take over the
@@ -30,14 +30,14 @@ if (process.argv[2] === '__cloud-confirm') {
30
30
  import('./cloud-session'),
31
31
  ])
32
32
  const session = readCloudSession()
33
- if (!session) throw new Error('RNX cloud confirmation has no shell session')
33
+ if (!session) throw new Error('Peach Cloud confirmation has no shell session')
34
34
  // a box has no claim to keep alive: its simulator is held by the Box page
35
35
  // for as long as the box runs, so a shell on a box confirms nothing.
36
36
  if (session.service === 'sim') await confirmCloudSimulator(session)
37
37
  process.exit(0)
38
38
  } catch (error) {
39
39
  process.stderr.write(
40
- `RNX cloud confirmation failed: ${
40
+ `Peach Cloud confirmation failed: ${
41
41
  error instanceof Error ? error.message : String(error)
42
42
  }\n`,
43
43
  )
@@ -161,7 +161,7 @@ export interface MaestroStep {
161
161
  launchApp?: any
162
162
  // maestro canonical form: object with `file` XOR inline `commands`, plus
163
163
  // optional `when` gate and `env` vars scoped to the sub-flow. legacy
164
- // rnx also accepts a bare path string.
164
+ // peach also accepts a bare path string.
165
165
  runFlow?:
166
166
  | string
167
167
  | {
@@ -426,7 +426,7 @@ export class SootSimBridgeFlowRunner {
426
426
  screenshotPathMode?: FlowScreenshotPathMode
427
427
  // flow-wide default for screenshot layers — applied to every
428
428
  // takeScreenshot step unless that step has its own `layers:`. set by
429
- // `rnx maestro test --no-shell` to produce clean tenant-only captures
429
+ // `peach maestro test --no-shell` to produce clean tenant-only captures
430
430
  // (useful when a stuck shell overlay would otherwise pollute the
431
431
  // demo asset set).
432
432
  screenshotLayers?: 'full' | 'tenant' | 'shell'
@@ -530,8 +530,8 @@ export class SootSimBridgeFlowRunner {
530
530
  if (status.bridgeError) {
531
531
  throw new Error(
532
532
  `target sim is not responding to the bridge (${status.bridgeError}). ` +
533
- `it is likely a stale orphan; run \`rnx list\`, then close it ` +
534
- `with \`rnx close <id>\` or start a fresh one with \`rnx open --new <port>\`.`,
533
+ `it is likely a stale orphan; run \`peach list\`, then close it ` +
534
+ `with \`peach close <id>\` or start a fresh one with \`peach open --new <port>\`.`,
535
535
  )
536
536
  }
537
537
  throw new Error(`app not ready after ${timeout}ms: ${waitReadyReason(status)}`)
@@ -714,7 +714,7 @@ export class SootSimBridgeFlowRunner {
714
714
  const extension = videoMime.includes('mp4') ? 'mp4' : 'webm'
715
715
  const outputPath = path.join(
716
716
  this.opts.recordingOutputDir,
717
- `rnx-${Date.now()}.${extension}`,
717
+ `peach-${Date.now()}.${extension}`,
718
718
  )
719
719
  fs.writeFileSync(outputPath, Buffer.concat(chunks))
720
720
  return outputPath
@@ -1089,7 +1089,7 @@ export class SootSimBridgeFlowRunner {
1089
1089
  // single tap can land on a transitioning node and never grant focus —
1090
1090
  // the keys then go nowhere and the field stays empty, silently breaking
1091
1091
  // submit (the bluesky login-submit RCA, 2026-06-11). re-resolve + re-tap
1092
- // until the input reports focused, the same gate rnx's `type-into`
1092
+ // until the input reports focused, the same gate peach's `type-into`
1093
1093
  // command uses. non-text-input taps keep the single-tap path.
1094
1094
  const tapInputAttempts = element.isTextInput ? 4 : 1
1095
1095
  for (let attempt = 0; attempt < tapInputAttempts; attempt++) {
@@ -1231,14 +1231,14 @@ export class SootSimBridgeFlowRunner {
1231
1231
 
1232
1232
  async inputText(text: string) {
1233
1233
  // real maestro types into the currently-focused field, and its driver's
1234
- // tap synchronously focuses it. in rnx, focus propagates async across
1234
+ // tap synchronously focuses it. in peach, focus propagates async across
1235
1235
  // the tenant→shell worker boundary (tap → focusTextInput → keyboard show),
1236
1236
  // so a preceding `tapOn` on a text input may not have landed focus by the
1237
1237
  // time we dispatch keystrokes — especially right after a re-render storm
1238
1238
  // (e.g. bluesky dismissing the custom-server dialog before tapping the
1239
1239
  // username field). without a focused input the keys go nowhere and the
1240
1240
  // field stays empty, silently breaking submit. wait for a focused text
1241
- // input first — the same focus gate rnx's own `type-into` uses (see
1241
+ // input first — the same focus gate peach's own `type-into` uses (see
1242
1242
  // the 2026-04-17 bluesky tap-routing regression in commands/inspect.ts).
1243
1243
  if (!(await this.waitForFocusedTextInput())) {
1244
1244
  throw new Error(
@@ -1610,8 +1610,8 @@ export class SootSimBridgeFlowRunner {
1610
1610
  )
1611
1611
  if (typeof tree === 'string') write('tree.txt', tree)
1612
1612
 
1613
- // 6. console buffer + failed requests (captured by rnx's native-globals
1614
- // hook / request recorder; same shape as `rnx get errors` etc.).
1613
+ // 6. console buffer + failed requests (captured by peach's native-globals
1614
+ // hook / request recorder; same shape as `peach get errors` etc.).
1615
1615
  const consoleBuf = await safeEval<{
1616
1616
  errors: unknown[]
1617
1617
  warnings: unknown[]
@@ -2171,11 +2171,11 @@ export class SootSimBridgeFlowRunner {
2171
2171
  await this.rearmCaptureAfterRuntimeReload()
2172
2172
  }
2173
2173
 
2174
- // maestro clearKeychain: there is no real keychain in rnx's browser
2174
+ // maestro clearKeychain: there is no real keychain in peach's browser
2175
2175
  // sandbox. log loudly so the author notices, then continue — matching the
2176
2176
  // "loud warning, not silent skip" policy in the plan.
2177
2177
  clearKeychain() {
2178
- console.warn('[flow] clearKeychain: rnx has no keychain surface — no-op (warning)')
2178
+ console.warn('[flow] clearKeychain: peach has no keychain surface — no-op (warning)')
2179
2179
  }
2180
2180
 
2181
2181
  // maestro copyTextFrom: find an element and capture its text for use in
@@ -2263,7 +2263,7 @@ export class SootSimBridgeFlowRunner {
2263
2263
  return !(await this.isElementVisible(opts))
2264
2264
  }
2265
2265
  if (when.platform !== undefined) {
2266
- // rnx emulates iOS — match against the context's platform the way
2266
+ // peach emulates iOS — match against the context's platform the way
2267
2267
  // upstream compares against cachedDeviceInfo.platform. keeps
2268
2268
  // cross-platform maestro flows running without stripping guards.
2269
2269
  return when.platform.toLowerCase() === this.js.maestro.platform.toLowerCase()
@@ -1,7 +1,7 @@
1
1
  // browser-side evaluator snippets for CLI inspect commands.
2
2
  //
3
- // the rnx CLI ships some commands that need to observe the live
4
- // rnx tree or its rendered pixels. we send these strings over the rnx host's
3
+ // the peach CLI ships some commands that need to observe the live
4
+ // peach tree or its rendered pixels. we send these strings over the peach host's
5
5
  // `evaluate` handler.
6
6
  //
7
7
  // cropping happens once, in the capture module (`bridges.screenshot`),
package/cli/cli-update.ts CHANGED
@@ -130,7 +130,7 @@ function envFlagIsOn(value: string | undefined): boolean {
130
130
  export function automaticCliUpdateChecksEnabled(
131
131
  env: Readonly<Record<string, string | undefined>> = process.env,
132
132
  ): boolean {
133
- return !envFlagIsOff(env.RNX_UPDATE_CHECK)
133
+ return !envFlagIsOff(env.PEACH_UPDATE_CHECK)
134
134
  }
135
135
 
136
136
  export function shouldUseAutomaticCliUpdateCheck(
@@ -146,7 +146,7 @@ export function shouldUseAutomaticCliUpdateCheck(
146
146
  !automaticCliUpdateChecksEnabled(env) ||
147
147
  envFlagIsOn(env.CI) ||
148
148
  envFlagIsOn(env.GITHUB_ACTIONS) ||
149
- envFlagIsOn(env.RNX_NO_PROMPT) ||
149
+ envFlagIsOn(env.PEACH_NO_PROMPT) ||
150
150
  isAgentEnv(env) ||
151
151
  invocation.commandArgs.includes('--json') ||
152
152
  invocation.commandArgs.includes('--ci') ||
@@ -212,14 +212,14 @@ export async function fetchCliReleaseFile(
212
212
  })
213
213
  } catch (error) {
214
214
  throw new Error(
215
- `could not reach the rnx update service: ${
215
+ `could not reach the peach update service: ${
216
216
  error instanceof Error ? error.message : String(error)
217
217
  }`,
218
218
  )
219
219
  }
220
220
  if (!response.ok) {
221
221
  throw new Error(
222
- `rnx update download failed: ${response.status} ${response.statusText}`,
222
+ `peach update download failed: ${response.status} ${response.statusText}`,
223
223
  )
224
224
  }
225
225
  return Buffer.from(await response.arrayBuffer())
@@ -242,7 +242,7 @@ export async function refreshCliUpdateCache(
242
242
  .trim()
243
243
  if (!CLI_VERSION_PATTERN.test(latestVersion)) {
244
244
  throw new Error(
245
- `rnx update service returned an invalid version: ${latestVersion || '(empty)'}`,
245
+ `peach update service returned an invalid version: ${latestVersion || '(empty)'}`,
246
246
  )
247
247
  }
248
248
 
@@ -256,6 +256,6 @@ export async function refreshCliUpdateCache(
256
256
  }
257
257
  writeState(next)
258
258
  const update = availability(next)
259
- if (!update) throw new Error('rnx update cache did not retain the latest version')
259
+ if (!update) throw new Error('peach update cache did not retain the latest version')
260
260
  return update
261
261
  }
@@ -67,8 +67,8 @@ export const DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin
67
67
  export const MAX_RNX_CLOUD_BUNDLE_BYTES = RNX_CLOUD_MAX_ARTIFACT_BYTES
68
68
 
69
69
  // every message this module writes names the command through this constant.
70
- const REMOTE_COMMAND = 'rnx remote'
71
- const PREVIEW_COMMAND = 'rnx preview'
70
+ const REMOTE_COMMAND = 'peach remote'
71
+ const PREVIEW_COMMAND = 'peach preview'
72
72
 
73
73
  export class UnsupportedRemoteHostError extends Error {
74
74
  readonly code = 'unsupported_host' as const
@@ -78,7 +78,7 @@ export class UnsupportedRemoteHostError extends Error {
78
78
  constructor(platform: string, host: string, message?: string) {
79
79
  super(
80
80
  message ??
81
- `rnx remote ${platform} does not support --${host}: peachsim/cloud only creates iOS simulators`,
81
+ `peach remote ${platform} does not support --${host}: peachsim/cloud only creates iOS simulators`,
82
82
  )
83
83
  this.name = 'UnsupportedRemoteHostError'
84
84
  this.platform = platform
@@ -147,7 +147,7 @@ function failureSentence(text: string): string | null {
147
147
  }
148
148
 
149
149
  // the account service says what it needs in its own words; the CLI says what
150
- // the person can do about it, which is choose the account at `rnx login`.
150
+ // the person can do about it, which is choose the account at `peach login`.
151
151
  const ACCOUNT_CHOICE_REFUSALS = new Set([
152
152
  'accountId is required',
153
153
  'you do not have access to this account',
@@ -165,7 +165,7 @@ function responseError(status: number, text: string): Error {
165
165
  }
166
166
 
167
167
  function resolveCloudOrigin(value?: string): string {
168
- const configured = value?.trim() || process.env.RNX_CLOUD_ORIGIN?.trim()
168
+ const configured = value?.trim() || process.env.PEACH_CLOUD_ORIGIN?.trim()
169
169
  const source = configured || DEFAULT_RNX_CLOUD_ORIGIN
170
170
  return normalizeCloudOrigin(source)
171
171
  }
@@ -715,18 +715,18 @@ export async function produceCloudBoxArtifact(
715
715
  ): Promise<CloudBoxArtifactProduction> {
716
716
  const prepared = await embedBundleAssets(
717
717
  bundlePath,
718
- 'rnx box create',
718
+ 'peach box create',
719
719
  'allow-placeholders',
720
720
  )
721
721
  const warnings: string[] = []
722
722
  if (prepared.search.unconfirmed && prepared.dest) {
723
723
  warnings.push(
724
- `rnx box create read this bundle's assets from ${prepared.dest.directory} on layout alone: every asset declares a scale that directory does not hold, so not one of Metro's hashes could be reproduced. Confirm these are the images this bundle was built against.`,
724
+ `peach box create read this bundle's assets from ${prepared.dest.directory} on layout alone: every asset declares a scale that directory does not hold, so not one of Metro's hashes could be reproduced. Confirm these are the images this bundle was built against.`,
725
725
  )
726
726
  }
727
727
  if (prepared.substituted.length > 0) {
728
728
  warnings.push(
729
- `rnx box create embedded a placeholder image for ${prepared.substituted.length} asset(s) no scale of which is in ${prepared.search.searched.join(', ') || 'any asset dest directory'}: ${prepared.substituted.join(', ')}. Rebuild with \`react-native bundle --assets-dest\` to ship the real images.`,
729
+ `peach box create embedded a placeholder image for ${prepared.substituted.length} asset(s) no scale of which is in ${prepared.search.searched.join(', ') || 'any asset dest directory'}: ${prepared.substituted.join(', ')}. Rebuild with \`react-native bundle --assets-dest\` to ship the real images.`,
730
730
  )
731
731
  }
732
732
  return {
@@ -1020,7 +1020,7 @@ export async function createCloudBox(options: CreateCloudBoxOptions): Promise<{
1020
1020
  }
1021
1021
  }
1022
1022
 
1023
- // one customer plane: the sim-service instance API. every `rnx remote`
1023
+ // one customer plane: the sim-service instance API. every `peach remote`
1024
1024
  // simulator is created, listed, read, and deleted here; the box stays the
1025
1025
  // host behind it and is never the addressed object.
1026
1026
 
@@ -1083,7 +1083,7 @@ function readSimCreateResponse(
1083
1083
  }
1084
1084
  }
1085
1085
 
1086
- // `rnx remote ios|android <bundle>` creates one simulator through the
1086
+ // `peach remote ios|android <bundle>` creates one simulator through the
1087
1087
  // instance API and waits for its app to answer ready. both platforms run
1088
1088
  // this same typed path: an android create is refused by the service with a
1089
1089
  // typed 400, never by a cli-side branch.
@@ -1098,7 +1098,7 @@ export async function createRemoteSim(options: CreateRemoteSimOptions): Promise<
1098
1098
  const apiOrigin = resolveCloudOrigin(options.apiOrigin)
1099
1099
  const artifact = await produceCloudArtifact(options.bundlePath)
1100
1100
  const query = new URLSearchParams({
1101
- labels: `rnx.remote=1,rnx.platform=${options.platform},rnx.bundle=${artifact.sha256.slice(0, 12)}`,
1101
+ labels: `peach.remote=1,peach.platform=${options.platform},peach.bundle=${artifact.sha256.slice(0, 12)}`,
1102
1102
  wait: 'true',
1103
1103
  })
1104
1104
  if (options.reuse) query.set('reuseIfExists', 'true')
@@ -1210,14 +1210,14 @@ function readSimView(value: unknown): RnxCloudSimView {
1210
1210
  }
1211
1211
  }
1212
1212
 
1213
- // `rnx remote list`: the simulators this account runs that `rnx remote` made.
1213
+ // `peach remote list`: the simulators this account runs that `peach remote` made.
1214
1214
  export async function listRemoteSims(options: {
1215
1215
  apiOrigin?: string
1216
1216
  authorization: string
1217
1217
  accountId?: string | null
1218
1218
  }): Promise<RnxCloudSimView[]> {
1219
1219
  const apiOrigin = resolveCloudOrigin(options.apiOrigin)
1220
- const selector = new URLSearchParams({ labelSelector: 'rnx.remote=1' })
1220
+ const selector = new URLSearchParams({ labelSelector: 'peach.remote=1' })
1221
1221
  const headers: Record<string, string> = { authorization: options.authorization }
1222
1222
  if (options.accountId) headers['x-rnx-account-id'] = options.accountId
1223
1223
  let response: Response
@@ -1289,7 +1289,7 @@ export async function getRemoteSim(options: {
1289
1289
  }
1290
1290
  }
1291
1291
 
1292
- // `rnx remote stop <id>`: delete one simulator by id. missing is null so the
1292
+ // `peach remote stop <id>`: delete one simulator by id. missing is null so the
1293
1293
  // caller can name what was not there; anything else refused throws.
1294
1294
  export async function deleteRemoteSim(options: {
1295
1295
  apiOrigin?: string
@@ -1536,7 +1536,7 @@ class CloudBoxBridge implements WsBridge {
1536
1536
  }
1537
1537
 
1538
1538
  closeSim(): Promise<never> {
1539
- return Promise.reject(new Error('close a box simulator with rnx box stop'))
1539
+ return Promise.reject(new Error('close a box simulator with peach box stop'))
1540
1540
  }
1541
1541
 
1542
1542
  claim(): Promise<BridgeClaimResult> {
@@ -1612,7 +1612,7 @@ export interface BoxDisplayGrant {
1612
1612
  expectedPeer: unknown
1613
1613
  }
1614
1614
 
1615
- // how long `rnx remote` waits for a fresh box's page to attach its simulator
1615
+ // how long `peach remote` waits for a fresh box's page to attach its simulator
1616
1616
  // before giving up on the watch url. the page boots the bundle after the
1617
1617
  // browser is up, and a large bundle takes a while to parse.
1618
1618
  const BOX_DISPLAY_GRANT_WAIT_MS = 180_000
@@ -119,7 +119,7 @@ function refuseCloudInvocation(
119
119
  ): CloudBoundaryResult {
120
120
  const verb = firstVerb(positional)
121
121
  const name = verb ? `${command} ${verb}` : command
122
- console.error(` rnx ${name} is not available for a remote simulator`)
122
+ console.error(` peach is not available for a remote simulator`)
123
123
  return { handled: true, code: 1 }
124
124
  }
125
125
 
@@ -183,7 +183,7 @@ export async function dispatchCloudBoundary({
183
183
  if (session.service === 'box') {
184
184
  if (command === 'claim') {
185
185
  console.error(
186
- ` rnx ${command} is not available for a box; its simulator is held by the Box page. use rnx box stop to end the box.`,
186
+ ` peach is not available for a box; its simulator is held by the Box page. use peach box stop to end the box.`,
187
187
  )
188
188
  return { handled: true, code: 1 }
189
189
  }
@@ -2,15 +2,15 @@ import { fstatSync, writeSync } from 'node:fs'
2
2
  import { isLoopbackHost } from '../src/backend-origin.ts'
3
3
 
4
4
  const CLOUD_SESSION_VERSION = 3 as const
5
- const SHELL_UPDATE_FD_ENV = 'RNX_SHELL_UPDATE_FD'
5
+ const SHELL_UPDATE_FD_ENV = 'PEACH_SHELL_UPDATE_FD'
6
6
  const MAX_ENCODED_SESSION_BYTES = 32 * 1024
7
7
 
8
- export const RNX_CLOUD_SESSION_ENV = 'RNX_CLOUD_SESSION'
8
+ export const PEACH_CLOUD_SESSION_ENV = 'PEACH_CLOUD_SESSION'
9
9
  export const RNX_SHELL_UPDATE_PREFIX = '__RNX_SHELL_UPDATE_V1__'
10
10
  export const RNX_SHELL_UPDATE_SET_PREFIX = `${RNX_SHELL_UPDATE_PREFIX}set:`
11
11
  export const RNX_SHELL_UPDATE_UNSET = `${RNX_SHELL_UPDATE_PREFIX}unset`
12
12
 
13
- // the shell's remote target. two services answer rnx commands and they are
13
+ // the shell's remote target. two services answer peach commands and they are
14
14
  // addressed differently, so the session names which one it is rather than
15
15
  // leaving a reader to infer it from which fields happen to be filled in.
16
16
  export type CloudSession = CloudSimSession | CloudBoxSession
@@ -163,7 +163,7 @@ export function parseCloudSession(encoded: string): CloudSession {
163
163
  value.length > MAX_ENCODED_SESSION_BYTES ||
164
164
  !/^[A-Za-z0-9_-]+$/.test(value)
165
165
  ) {
166
- throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`)
166
+ throw new Error(`${PEACH_CLOUD_SESSION_ENV} is invalid`)
167
167
  }
168
168
  let parsed: unknown
169
169
  try {
@@ -173,14 +173,14 @@ export function parseCloudSession(encoded: string): CloudSession {
173
173
  }
174
174
  parsed = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes))
175
175
  } catch {
176
- throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`)
176
+ throw new Error(`${PEACH_CLOUD_SESSION_ENV} is invalid`)
177
177
  }
178
178
  if (!isRecord(parsed) || parsed.version !== CLOUD_SESSION_VERSION) {
179
- throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`)
179
+ throw new Error(`${PEACH_CLOUD_SESSION_ENV} is invalid`)
180
180
  }
181
181
  const apiOrigin = parsed.apiOrigin
182
182
  if (typeof apiOrigin !== 'string') {
183
- throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`)
183
+ throw new Error(`${PEACH_CLOUD_SESSION_ENV} is invalid`)
184
184
  }
185
185
  const platform =
186
186
  parsed.platform === 'ios' || parsed.platform === 'android'
@@ -234,14 +234,14 @@ export function parseCloudSession(encoded: string): CloudSession {
234
234
  boxToken,
235
235
  })
236
236
  } catch {
237
- throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`)
237
+ throw new Error(`${PEACH_CLOUD_SESSION_ENV} is invalid`)
238
238
  }
239
239
  }
240
240
 
241
241
  export function readCloudSession(
242
242
  environment: Readonly<Record<string, string | undefined>> = process.env,
243
243
  ): CloudSession | null {
244
- const encoded = environment[RNX_CLOUD_SESSION_ENV]
244
+ const encoded = environment[PEACH_CLOUD_SESSION_ENV]
245
245
  return encoded?.trim() ? parseCloudSession(encoded) : null
246
246
  }
247
247
 
@@ -252,12 +252,12 @@ function shellUpdateFd(
252
252
  if (!source) return null
253
253
  const descriptor = Number(source)
254
254
  if (!Number.isSafeInteger(descriptor) || descriptor < 3) {
255
- throw new Error('RNX shell integration provided an invalid update channel')
255
+ throw new Error('Peach shell integration provided an invalid update channel')
256
256
  }
257
257
  try {
258
258
  fstatSync(descriptor)
259
259
  } catch {
260
- throw new Error('RNX shell integration update channel is unavailable')
260
+ throw new Error('Peach shell integration update channel is unavailable')
261
261
  }
262
262
  return descriptor
263
263
  }
@@ -266,7 +266,7 @@ export function requireCloudSessionShellUpdate(): number {
266
266
  const descriptor = shellUpdateFd()
267
267
  if (descriptor === null) {
268
268
  throw new Error(
269
- 'RNX shell integration is required so this remote simulator stays connected to the current shell; restart the shell after installing RNX',
269
+ 'Peach shell integration is required so this remote simulator stays connected to the current shell; restart the shell after installing peach',
270
270
  )
271
271
  }
272
272
  return descriptor
@@ -1,4 +1,4 @@
1
- // rnx test --cloud live-dev-stack publisher (tunnel CLI half).
1
+ // peach test --cloud live-dev-stack publisher (tunnel CLI half).
2
2
  //
3
3
  // when --app names a live packager (http loopback) instead of a prebuilt
4
4
  // bundle, the submitter publishes that stack through a token-gated
@@ -188,7 +188,7 @@ async function ensureCloudflared(): Promise<boolean> {
188
188
  const osMap: Record<string, string> = { linux: 'linux', darwin: 'darwin' }
189
189
  const os = osMap[process.platform]
190
190
  if (!arch || !os) return false
191
- const dest = join(tmpdir(), 'rnx-cloudflared')
191
+ const dest = join(tmpdir(), 'peach-cloudflared')
192
192
  const binary = join(dest, 'cloudflared')
193
193
  if (existsSync(binary)) {
194
194
  process.env.PATH = `${dest}:${process.env.PATH ?? ''}`
@@ -317,10 +317,10 @@ export async function publishLiveDevStack(args: {
317
317
  if (!(await ensureCloudflared())) {
318
318
  closeProxy()
319
319
  throw new Error(
320
- 'cloudflared is required for live dev stacks (rnx test --cloud with http://localhost:<port>). install it or check your network.',
320
+ 'cloudflared is required for live dev stacks (peach test --cloud with http://localhost:<port>). install it or check your network.',
321
321
  )
322
322
  }
323
- const logFile = join(tmpdir(), `rnx-test-tunnel-${Date.now()}-${proxyPort}.log`)
323
+ const logFile = join(tmpdir(), `peach-test-tunnel-${Date.now()}-${proxyPort}.log`)
324
324
  const tunnel = await launchQuickTunnel(
325
325
  `http://127.0.0.1:${proxyPort}`,
326
326
  hostHeader,
@@ -169,14 +169,14 @@ export function getRnxCommandAvailability(
169
169
  : {
170
170
  available: false,
171
171
  reason:
172
- 'rnx web is available in the browser backend, where it selects the existing web preview.',
172
+ 'peach web is available in the browser backend, where it selects the existing web preview.',
173
173
  }
174
174
  }
175
175
 
176
176
  if (!registration.browserFamily) {
177
177
  return {
178
178
  available: false,
179
- reason: `rnx ${command} is unavailable in the browser backend; it requires the node backend.`,
179
+ reason: `peach ${command} is unavailable in the browser backend; it requires the node backend.`,
180
180
  }
181
181
  }
182
182
 
@@ -184,7 +184,7 @@ export function getRnxCommandAvailability(
184
184
  if (command === 'shell' && subcommand && subcommand !== 'appearance') {
185
185
  return {
186
186
  available: false,
187
- reason: `rnx shell ${subcommand} is unavailable in the browser backend; Factory exposes no semantic operation for it.`,
187
+ reason: `peach shell ${subcommand} is unavailable in the browser backend; Factory exposes no semantic operation for it.`,
188
188
  }
189
189
  }
190
190
  if (
@@ -196,14 +196,14 @@ export function getRnxCommandAvailability(
196
196
  ) {
197
197
  return {
198
198
  available: false,
199
- reason: 'rnx shell appearance supports light or dark in the browser backend.',
199
+ reason: 'peach shell appearance supports light or dark in the browser backend.',
200
200
  }
201
201
  }
202
202
  if (command === 'storage' && subcommand === 'profile') {
203
203
  return {
204
204
  available: false,
205
205
  reason:
206
- 'rnx storage profile is unavailable in the browser backend; use rnx storage clear for the selected preview.',
206
+ 'peach storage profile is unavailable in the browser backend; use peach storage clear for the selected preview.',
207
207
  }
208
208
  }
209
209
  const screenshotSubcommand = command === 'screenshot' ? subcommand : null
@@ -213,14 +213,14 @@ export function getRnxCommandAvailability(
213
213
  ) {
214
214
  return {
215
215
  available: false,
216
- reason: `rnx screenshot ${screenshotSubcommand} is unavailable in the browser backend; it requires the node backend.`,
216
+ reason: `peach screenshot ${screenshotSubcommand} is unavailable in the browser backend; it requires the node backend.`,
217
217
  }
218
218
  }
219
219
  if (command === 'timeline' && subcommand === 'dump') {
220
220
  return {
221
221
  available: false,
222
222
  reason:
223
- 'rnx timeline dump is unavailable in the browser backend because it writes to the host filesystem.',
223
+ 'peach timeline dump is unavailable in the browser backend because it writes to the host filesystem.',
224
224
  }
225
225
  }
226
226
 
@@ -1,10 +1,10 @@
1
- // agent-wrapper — long-running bridge process between rnx desktop and a
1
+ // agent-wrapper — long-running bridge process between peach desktop and a
2
2
  // local coding agent (codex / claude).
3
3
  //
4
- // shipped as an internal rnx CLI subcommand so it survives `bun build
4
+ // shipped as an internal peach CLI subcommand so it survives `bun build
5
5
  // --compile` bundling. callers spawn it as:
6
6
  //
7
- // rnx agent-wrapper \
7
+ // peach agent-wrapper \
8
8
  // --session-id <id> --project-id <id> --provider codex \
9
9
  // --cwd <path> --prompt-in <fifo> --events-out <fifo> \
10
10
  // [--transcript <file>]
@@ -148,7 +148,7 @@ export async function runAgentWrapper(argv: string[]): Promise<number> {
148
148
  !args.eventsOut
149
149
  ) {
150
150
  process.stderr.write(
151
- 'usage: rnx agent-wrapper --session-id <id> --project-id <id>\n' +
151
+ 'usage: peach agent-wrapper --session-id <id> --project-id <id>\n' +
152
152
  ' --provider codex|claude --cwd <path>\n' +
153
153
  ' --prompt-in <fifo> --events-out <fifo>\n' +
154
154
  ' [--transcript <file>]\n' +
@@ -246,7 +246,7 @@ export async function runAgentWrapper(argv: string[]): Promise<number> {
246
246
  bin: resolvedAgentBin,
247
247
  cwd,
248
248
  env: {
249
- RNX_CLI_IDENTITY: sessionId,
249
+ PEACH_CLI_IDENTITY: sessionId,
250
250
  SOOTSIM_PROJECT_ID: projectId,
251
251
  },
252
252
  })
@@ -419,7 +419,7 @@ export async function runAgentWrapper(argv: string[]): Promise<number> {
419
419
  }
420
420
 
421
421
  // open prompt.in with O_RDWR so our own write end keeps the FIFO alive
422
- // across external writer open/close cycles. `rnx agent prompt` opens,
422
+ // across external writer open/close cycles. `peach agent prompt` opens,
423
423
  // writes one line, closes — without a self-writer the reader would EOF
424
424
  // after the first prompt and subsequent prompts would be lost.
425
425
  const promptFd = openSync(promptIn, fsConstants.O_RDWR)
@@ -889,7 +889,7 @@ function buildClaudeTurnRunner(deps: ClaudeTurnDeps): TurnRunner {
889
889
  stdio: ['ignore', 'pipe', 'pipe'],
890
890
  env: {
891
891
  ...claudeEnv,
892
- RNX_CLI_IDENTITY: sessionId,
892
+ PEACH_CLI_IDENTITY: sessionId,
893
893
  SOOTSIM_PROJECT_ID: projectId,
894
894
  },
895
895
  },