peachsim 0.1.570 → 0.1.572

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 (242) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +108 -108
  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 +28 -20
  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 +3 -2
  12. package/cli/cloud-session.ts +12 -12
  13. package/cli/cloud-test-result-files.ts +97 -0
  14. package/cli/cloud-test-tunnel.ts +4 -4
  15. package/cli/command-registry.ts +7 -7
  16. package/cli/commands/agent-wrapper.ts +7 -7
  17. package/cli/commands/agent.ts +16 -16
  18. package/cli/commands/app-fonts.ts +3 -3
  19. package/cli/commands/assert.ts +10 -10
  20. package/cli/commands/auth.ts +5 -5
  21. package/cli/commands/box/checkout-plane.ts +1 -1
  22. package/cli/commands/box/plane-share.ts +2 -2
  23. package/cli/commands/box/rnx-command.ts +5 -5
  24. package/cli/commands/box.ts +38 -38
  25. package/cli/commands/camera.ts +13 -13
  26. package/cli/commands/cleanup.ts +13 -13
  27. package/cli/commands/compat.ts +7 -7
  28. package/cli/commands/config.ts +5 -5
  29. package/cli/commands/control.ts +63 -63
  30. package/cli/commands/cpu-profile.ts +11 -11
  31. package/cli/commands/daemon-mac-app.ts +10 -10
  32. package/cli/commands/daemon.ts +29 -27
  33. package/cli/commands/debug.ts +35 -35
  34. package/cli/commands/desktop.ts +3 -3
  35. package/cli/commands/detox.ts +33 -33
  36. package/cli/commands/device.ts +9 -9
  37. package/cli/commands/diagnose.ts +17 -17
  38. package/cli/commands/do-chain.ts +4 -4
  39. package/cli/commands/electron.ts +9 -9
  40. package/cli/commands/film.ts +9 -9
  41. package/cli/commands/flow.ts +49 -49
  42. package/cli/commands/inspect/core.ts +12 -12
  43. package/cli/commands/inspect/count.ts +1 -1
  44. package/cli/commands/inspect/describe.ts +1 -1
  45. package/cli/commands/inspect/env.ts +2 -2
  46. package/cli/commands/inspect/find.ts +2 -2
  47. package/cli/commands/inspect/get-layout.ts +2 -2
  48. package/cli/commands/inspect/keyboard.ts +1 -1
  49. package/cli/commands/inspect/list.ts +4 -4
  50. package/cli/commands/inspect/memory.ts +1 -1
  51. package/cli/commands/inspect/resolve-target.ts +1 -1
  52. package/cli/commands/inspect/screens.ts +1 -1
  53. package/cli/commands/inspect/shared.ts +1 -1
  54. package/cli/commands/inspect/tree.ts +1 -1
  55. package/cli/commands/inspect/url.ts +1 -1
  56. package/cli/commands/inspect/wait-event.ts +5 -5
  57. package/cli/commands/inspect.ts +82 -82
  58. package/cli/commands/install-cli.ts +16 -16
  59. package/cli/commands/install-desktop.ts +26 -26
  60. package/cli/commands/login.ts +11 -11
  61. package/cli/commands/maestro-generate.ts +10 -10
  62. package/cli/commands/maestro.ts +173 -71
  63. package/cli/commands/mode.ts +4 -4
  64. package/cli/commands/no-bridge-hint.ts +12 -12
  65. package/cli/commands/perf.ts +11 -11
  66. package/cli/commands/permissions.ts +5 -5
  67. package/cli/commands/platform.ts +21 -21
  68. package/cli/commands/preview.ts +5 -5
  69. package/cli/commands/profile.ts +12 -12
  70. package/cli/commands/react.ts +15 -15
  71. package/cli/commands/record.ts +31 -31
  72. package/cli/commands/report-issue.ts +4 -4
  73. package/cli/commands/reset.ts +2 -2
  74. package/cli/commands/runtime.ts +23 -23
  75. package/cli/commands/screenshot-command.ts +2 -2
  76. package/cli/commands/screenshot-layers.ts +5 -5
  77. package/cli/commands/screenshot-mode.ts +7 -7
  78. package/cli/commands/screenshot.ts +24 -24
  79. package/cli/commands/screenshots-capture.ts +13 -13
  80. package/cli/commands/screenshots.ts +6 -6
  81. package/cli/commands/serve.ts +12 -12
  82. package/cli/commands/setup.ts +25 -25
  83. package/cli/commands/skills.ts +30 -23
  84. package/cli/commands/slides.ts +20 -20
  85. package/cli/commands/state.ts +2 -2
  86. package/cli/commands/storage.ts +3 -3
  87. package/cli/commands/telemetry.ts +2 -2
  88. package/cli/commands/test.ts +176 -18
  89. package/cli/commands/three-mode.ts +17 -17
  90. package/cli/commands/timeline.ts +12 -12
  91. package/cli/commands/upgrade.ts +11 -11
  92. package/cli/commands/upload.ts +26 -26
  93. package/cli/commands/version.ts +7 -7
  94. package/cli/commands/what-happened.ts +20 -20
  95. package/cli/current-sim.ts +3 -3
  96. package/cli/desktop-companion.ts +16 -16
  97. package/cli/drivers/electron.ts +4 -4
  98. package/cli/drivers/playwright-sim-host.ts +7 -7
  99. package/cli/drivers/playwright.ts +4 -4
  100. package/cli/drivers/registry.ts +1 -1
  101. package/cli/drivers/types.ts +5 -5
  102. package/cli/flow-export.ts +1 -1
  103. package/cli/flow-file.ts +5 -5
  104. package/cli/flow-session.ts +1 -1
  105. package/cli/help-core.ts +13 -13
  106. package/cli/hints.ts +14 -14
  107. package/cli/inspect-notice-state.ts +1 -1
  108. package/cli/internal-child.ts +2 -2
  109. package/cli/maestro-js.ts +4 -4
  110. package/cli/maestro-report.ts +4 -2
  111. package/cli/main.ts +14 -14
  112. package/cli/outbound-endpoints.ts +32 -30
  113. package/cli/parse-args.ts +7 -7
  114. package/cli/privacy.ts +1 -1
  115. package/cli/recording-access.ts +10 -10
  116. package/cli/resolve-assets.ts +2 -2
  117. package/cli/rnx-in-process.ts +5 -5
  118. package/cli/run-registry.ts +3 -2
  119. package/cli/run-rnx-core.ts +3 -3
  120. package/cli/run-rnx.ts +1 -1
  121. package/cli/runtime-notes.ts +1 -1
  122. package/cli/self-invocation.ts +1 -1
  123. package/cli/send-to-box.ts +1 -1
  124. package/cli/shell-init.ts +40 -40
  125. package/cli/ui.ts +1 -1
  126. package/cli/ws-bridge.ts +22 -22
  127. package/detox/config-loader.ts +1 -1
  128. package/detox/index.ts +28 -28
  129. package/detox/jest-preset.cjs +2 -2
  130. package/detox/navigation.ts +2 -2
  131. package/dist-lib/agent-daemon-client.cjs +12 -12
  132. package/dist-lib/agent-events.cjs +1 -1
  133. package/dist-lib/agent-identity.cjs +2 -2
  134. package/dist-lib/agent-sessions.cjs +12 -12
  135. package/dist-lib/attached-projects.cjs +4 -4
  136. package/dist-lib/auth/shared-session.cjs +4 -4
  137. package/dist-lib/backend-origin.cjs +1 -1
  138. package/dist-lib/beta.cjs +1 -1
  139. package/dist-lib/beta.mjs +1 -1
  140. package/dist-lib/bridge-constants.cjs +4 -4
  141. package/dist-lib/bridge-contract-input.cjs +1 -1
  142. package/dist-lib/bridge-contract-input.mjs +1 -1
  143. package/dist-lib/bridge-contract.cjs +2 -2
  144. package/dist-lib/bridge-contract.mjs +2 -2
  145. package/dist-lib/capture-contract.cjs +1 -1
  146. package/dist-lib/capture-contract.mjs +1 -1
  147. package/dist-lib/cli-constants.cjs +1 -1
  148. package/dist-lib/cloud-contract.cjs +1 -1
  149. package/dist-lib/cloud-contract.mjs +1 -1
  150. package/dist-lib/cloud-test-args.cjs +116 -0
  151. package/dist-lib/cloud-test-args.mjs +86 -0
  152. package/dist-lib/cloud.cjs +42 -42
  153. package/dist-lib/cloud.mjs +42 -42
  154. package/dist-lib/config.cjs +2 -2
  155. package/dist-lib/detox/index.cjs +29 -29
  156. package/dist-lib/detox/jest-preset.cjs +2 -2
  157. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  158. package/dist-lib/home-paths.cjs +12 -12
  159. package/dist-lib/host/bridge-host.cjs +87 -77
  160. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  161. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  162. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  163. package/dist-lib/host/replacement-module-handler.cjs +6 -6
  164. package/dist-lib/host/websocket-proxy.cjs +1 -1
  165. package/dist-lib/index.cjs +63 -73
  166. package/dist-lib/jump-to-source-babel.cjs +1 -1
  167. package/dist-lib/jump-to-source-native.cjs +1 -1
  168. package/dist-lib/menu.cjs +5 -5
  169. package/dist-lib/menu.mjs +5 -5
  170. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  171. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  172. package/dist-lib/metro-production-bundle.cjs +1 -1
  173. package/dist-lib/metro-production-bundle.mjs +1 -1
  174. package/dist-lib/metro.cjs +15 -15
  175. package/dist-lib/profiles.cjs +4 -4
  176. package/dist-lib/public-brand.cjs +3 -3
  177. package/dist-lib/react-native-host-modules.cjs +1 -1
  178. package/dist-lib/react-native-host-modules.mjs +1 -1
  179. package/dist-lib/render-mode.cjs +1 -1
  180. package/dist-lib/scripts/dev-server-scanner.cjs +2 -1
  181. package/dist-lib/sdk.cjs +9 -9
  182. package/dist-lib/sdk.mjs +9 -9
  183. package/dist-lib/skills.cjs +534 -520
  184. package/dist-lib/swift-compile.cjs +372 -0
  185. package/dist-lib/swift-compile.mjs +339 -0
  186. package/dist-lib/swift-package.cjs +78 -0
  187. package/dist-lib/swift-package.mjs +52 -0
  188. package/dist-lib/swift-submit.cjs +1 -1
  189. package/dist-lib/swift-submit.mjs +1 -1
  190. package/dist-lib/swift.cjs +1 -1
  191. package/dist-lib/vite.cjs +479 -161
  192. package/package.json +22 -1
  193. package/scripts/dev-server-scanner.ts +4 -3
  194. package/skills/contrast/SKILL.md +75 -75
  195. package/skills/{rnx-debug → peach-debug}/SKILL.md +90 -90
  196. package/skills/{rnx-perf → peach-perf}/SKILL.md +13 -13
  197. package/skills/{rnx-setup → peach-setup}/SKILL.md +60 -60
  198. package/skills/{rnx-test → peach-test}/SKILL.md +47 -47
  199. package/skills/{rnx-visual → peach-visual}/SKILL.md +26 -26
  200. package/src/agent-daemon-client.ts +5 -5
  201. package/src/agent-events.ts +1 -1
  202. package/src/agent-identity.ts +1 -1
  203. package/src/agent-sessions.ts +13 -13
  204. package/src/attached-projects.ts +1 -1
  205. package/src/auth/shared-session.ts +1 -1
  206. package/src/bridge-constants.ts +3 -3
  207. package/src/bridge-contract-input.ts +1 -1
  208. package/src/bridge-contract.ts +3 -3
  209. package/src/cli-version.ts +6 -6
  210. package/src/cloud-test-args.ts +100 -0
  211. package/src/cloud.ts +40 -40
  212. package/src/config.ts +1 -1
  213. package/src/connect.ts +6 -6
  214. package/src/dev-server-open.ts +8 -8
  215. package/src/disk-cleanup.ts +3 -3
  216. package/src/home-paths.ts +26 -26
  217. package/src/host/agent-host.ts +3 -3
  218. package/src/host/bridge-host.ts +33 -33
  219. package/src/host/fetch-proxy-handler.ts +1 -1
  220. package/src/host/plane-host.ts +2 -2
  221. package/src/host/replacement-module-handler.ts +2 -2
  222. package/src/menu.ts +2 -2
  223. package/src/metro-plugin.ts +7 -7
  224. package/src/metro-production-bundle.ts +2 -2
  225. package/src/native-dev-bundle-url.ts +2 -2
  226. package/src/playwright-host-log.ts +1 -1
  227. package/src/public-brand.ts +2 -2
  228. package/src/react-native-host-modules.ts +1 -1
  229. package/src/rolldown-plugin-swift.ts +11 -10
  230. package/src/runtime-assets.ts +11 -11
  231. package/src/runtime-delivery.ts +6 -6
  232. package/src/screenshots/orchestrate.ts +1 -1
  233. package/src/screenshots/org-deck.ts +1 -1
  234. package/src/screenshots/schema.ts +2 -2
  235. package/src/sim-client.ts +1 -1
  236. package/src/skills/builtin/compat-check.ts +2 -2
  237. package/src/swift-compile.ts +359 -0
  238. package/src/swift-package.ts +69 -0
  239. package/src/swift-submit.ts +3 -2
  240. package/src/vite-plugin-one.ts +8 -8
  241. package/src/vite-plugin-swift.ts +106 -110
  242. package/src/vite-plugin.ts +6 -19
package/cli/help-core.ts CHANGED
@@ -38,10 +38,10 @@ function backendLabel(command: string, args: readonly string[]): string {
38
38
  }
39
39
 
40
40
  function renderPreviewHelp(command: 'web' | 'ios' | 'android'): string {
41
- return `rnx ${command} — select or ensure the current branch's existing ${command} preview
41
+ return `peach ${command} — select or ensure the current branch's existing ${command} preview
42
42
 
43
43
  usage:
44
- rnx ${command}
44
+ peach ${command}
45
45
 
46
46
  The browser backend selects the Factory-owned ${command} iframe. It never launches a
47
47
  host process or Cloudflare runtime.`
@@ -51,19 +51,19 @@ function renderFactoryBrowserLeaves(command: string): string | null {
51
51
  switch (command) {
52
52
  case 'do':
53
53
  return `Factory browser leaves:
54
- rnx do navigate /route`
54
+ peach do navigate /route`
55
55
  case 'shell':
56
56
  return `Factory browser leaves:
57
- rnx shell appearance light|dark`
57
+ peach shell appearance light|dark`
58
58
  case 'assert':
59
59
  return `Factory browser leaves:
60
- rnx assert find (--testid <id>|--text <text>|--role <role>) [--exists|--empty] [--contains <text>]`
60
+ peach assert find (--testid <id>|--text <text>|--role <role>) [--exists|--empty] [--contains <text>]`
61
61
  case 'screenshot':
62
62
  return `Factory browser leaves:
63
- rnx screenshot
64
- rnx screenshot ask <question>
65
- rnx screenshot appearance light|dark /route --by <query-kind> --value <target>
66
- rnx screenshot motion <task-id> /route --trigger-by <kind> --trigger-value <target> --result-by <kind> --result-value <target> [--duration-ms <100..2000>]`
63
+ peach screenshot
64
+ peach screenshot ask <question>
65
+ peach screenshot appearance light|dark /route --by <query-kind> --value <target>
66
+ peach screenshot motion <task-id> /route --trigger-by <kind> --trigger-value <target> --result-by <kind> --result-value <target> [--duration-ms <100..2000>]`
67
67
  default:
68
68
  return null
69
69
  }
@@ -90,7 +90,7 @@ function renderRootAvailability(backend: RnxBackendKind): string {
90
90
  available: ${available.join(', ')}
91
91
  unavailable: ${unavailable.join(', ')}
92
92
 
93
- Run \`rnx <command> --help\` for leaf availability and usage.`
93
+ Run \`peach <command> --help\` for leaf availability and usage.`
94
94
  }
95
95
 
96
96
  export function renderRnxHelp(options: RnxHelpOptions): string {
@@ -100,9 +100,9 @@ export function renderRnxHelp(options: RnxHelpOptions): string {
100
100
  return `${renderCliIndexHelp(HELP_CONTEXT, formatFlagHelp()).trimEnd()}
101
101
 
102
102
  browser preview selectors:
103
- rnx web select the existing Factory web preview
104
- rnx ios select the existing Factory iOS preview
105
- rnx android select the existing Factory Android preview
103
+ peach web select the existing Factory web preview
104
+ peach ios select the existing Factory iOS preview
105
+ peach android select the existing Factory Android preview
106
106
 
107
107
  ${renderRootAvailability(options.backend)}`
108
108
  }
package/cli/hints.ts CHANGED
@@ -1,4 +1,4 @@
1
- // configurable, identity-scoped hint registry for the rnx CLI.
1
+ // configurable, identity-scoped hint registry for the peach CLI.
2
2
  //
3
3
  // two problems this solves:
4
4
  // 1. the CLI scatters "hint: ..." console.logs across many command files,
@@ -46,11 +46,11 @@ interface HintStateFile {
46
46
  const STATE_VERSION = 1 as const
47
47
 
48
48
  function identityStatePath(): string {
49
- return join(tmpdir(), `rnx-cli-hints-${getCliIdentityKey()}.json`)
49
+ return join(tmpdir(), `peach-cli-hints-${getCliIdentityKey()}.json`)
50
50
  }
51
51
 
52
52
  function globalStatePath(): string {
53
- return join(tmpdir(), `rnx-cli-hints-global.json`)
53
+ return join(tmpdir(), `peach-cli-hints-global.json`)
54
54
  }
55
55
 
56
56
  function readState(path: string): HintStateFile {
@@ -76,7 +76,7 @@ function writeState(path: string, state: HintStateFile) {
76
76
  }
77
77
 
78
78
  function modeFromEnv(): 'normal' | 'always' | 'off' {
79
- const v = (process.env.RNX_HINTS || '').toLowerCase()
79
+ const v = (process.env.PEACH_HINTS || '').toLowerCase()
80
80
  if (v === 'off' || v === '0' || v === 'false') return 'off'
81
81
  if (v === 'always' || v === 'verbose') return 'always'
82
82
  return 'normal'
@@ -119,7 +119,7 @@ function shouldShow(id: string, frequency: HintFrequency): boolean {
119
119
  export function maybeHint(id: string, ...args: unknown[]): boolean {
120
120
  const spec = registry.get(id)
121
121
  if (!spec) {
122
- if (process.env.RNX_HINTS_DEBUG) {
122
+ if (process.env.PEACH_HINTS_DEBUG) {
123
123
  console.error(` [hints] no hint registered for id "${id}"`)
124
124
  }
125
125
  return false
@@ -158,13 +158,13 @@ defineHint<[number]>('app-still-loading', {
158
158
  // bundle boots — telling the user about it again is useful, not noisy.
159
159
  frequency: { cooldownMs: 60_000 },
160
160
  render: (nodeCount) =>
161
- `app may still be loading (${nodeCount} nodes). run \`rnx wait ready\` first.`,
161
+ `app may still be loading (${nodeCount} nodes). run \`peach wait ready\` first.`,
162
162
  })
163
163
 
164
164
  defineHint<[string]>('wait-selector-for-missing-testid', {
165
165
  // advice is stable; once per CLI identity is enough.
166
166
  frequency: 'once-per-identity',
167
- render: (testId) => `rnx wait selector ${testId}`,
167
+ render: (testId) => `peach wait selector ${testId}`,
168
168
  })
169
169
 
170
170
  defineHint<[string[]]>('prefer-cli-over-eval', {
@@ -181,9 +181,9 @@ defineHint<[]>('describe-use-filters', {
181
181
  frequency: 'once-per-identity',
182
182
  render: () => [
183
183
  `describe output is long. narrow it with:`,
184
- ` rnx describe --only '*Bottom Sheet*'`,
185
- ` rnx describe --testid-like 'swap-*'`,
186
- ` rnx describe --subtree <testID>`,
184
+ ` peach describe --only '*Bottom Sheet*'`,
185
+ ` peach describe --testid-like 'swap-*'`,
186
+ ` peach describe --subtree <testID>`,
187
187
  ],
188
188
  })
189
189
 
@@ -194,21 +194,21 @@ defineHint<[]>('describe-filter-context', {
194
194
  frequency: 'once-per-identity',
195
195
  render: () => [
196
196
  `filtered describe is search output, not current-route proof.`,
197
- `run \`rnx describe\` without filters after navigation; clipped nodes are marked \`(clipped:...)\`.`,
197
+ `run \`peach describe\` without filters after navigation; clipped nodes are marked \`(clipped:...)\`.`,
198
198
  ],
199
199
  })
200
200
 
201
201
  defineHint<[string]>('subtree-root-not-found', {
202
202
  frequency: 'always',
203
203
  render: (id) =>
204
- `no node with testID/id "${id}" — try \`rnx find --testid ${id}\` to discover available ids.`,
204
+ `no node with testID/id "${id}" — try \`peach find --testid ${id}\` to discover available ids.`,
205
205
  })
206
206
 
207
207
  defineHint<[]>('clean-uninstall', {
208
- // shown once on the first `rnx --help` run so users learn the teardown path.
208
+ // shown once on the first `peach --help` run so users learn the teardown path.
209
209
  frequency: 'once-ever',
210
210
  render: () => [
211
- `to remove the background daemon, run \`rnx daemon uninstall\`. it keeps your runtimes and device profiles; add \`--purge\` to delete ~/.rnx too.`,
211
+ `to remove the background daemon, run \`peach daemon uninstall\`. it keeps your runtimes and device profiles; add \`--purge\` to delete ~/.peach too.`,
212
212
  `the optional desktop app and its macOS preference plist are separate from the daemon.`,
213
213
  ],
214
214
  })
@@ -23,7 +23,7 @@ interface InspectNoticeState {
23
23
  export function getInspectNoticeStatePath() {
24
24
  return resolve(
25
25
  process.env[INSPECT_NOTICE_PATH_ENV] ||
26
- join(tmpdir(), 'rnx-inspect-notice-state.json'),
26
+ join(tmpdir(), 'peach-inspect-notice-state.json'),
27
27
  )
28
28
  }
29
29
 
@@ -1,10 +1,10 @@
1
1
  // hidden child-process entry points.
2
2
  //
3
3
  // the CLI needs separate JS processes for a few jobs: a detached browser host
4
- // that outlives `rnx open`, playwright's own installer, and a blocking fetch
4
+ // that outlives `peach open`, playwright's own installer, and a blocking fetch
5
5
  // worker for maestro's synchronous `http` API. each used to run as
6
6
  // `process.execPath -e '<source>'`, which cannot work once the CLI ships as a
7
- // compiled binary: there process.execPath is rnx, and rnx has no -e. a
7
+ // compiled binary: there process.execPath is peach, and peach has no -e. a
8
8
  // shell-installed user has no node and no bun either, so there is nothing else
9
9
  // to reach for. the binary is the JS runtime, and it runs these itself.
10
10
  //
package/cli/maestro-js.ts CHANGED
@@ -14,10 +14,10 @@
14
14
  // time (maestro-orchestra-models util/Env.kt): regex (?<!\\)\$\{([^$]*)},
15
15
  // result stringified, `\${...}` escapes to a literal, blank exprs become ''.
16
16
  //
17
- // divergences (deliberate, rnx-side ergonomics — keep this list short):
17
+ // divergences (deliberate, peach-side ergonomics — keep this list short):
18
18
  // 1. envBinding is seeded from the full process.env, not just MAESTRO_*.
19
- // rnx flows historically resolve `${SOOTSIM_*}` credentials from the
20
- // shell environment and `rnx maestro --env K=V` writes process.env.
19
+ // peach flows historically resolve `${SOOTSIM_*}` credentials from the
20
+ // shell environment and `peach maestro --env K=V` writes process.env.
21
21
  // 2. a *bare identifier* template (`${NAME}`) that evaluates to undefined
22
22
  // throws a loud "missing variable" error instead of interpolating the
23
23
  // literal text "undefined" into a tap target or login form. complex
@@ -45,7 +45,7 @@ function executeSyncHttp(
45
45
  params?: HttpParams,
46
46
  ): { ok: boolean; status: number; body: string; headers: Record<string, string> } {
47
47
  if (params?.multipartForm) {
48
- throw new Error('http: multipartForm is not supported by rnx yet')
48
+ throw new Error('http: multipartForm is not supported by peach yet')
49
49
  }
50
50
  // maestro's `http` API is synchronous (flows do `var res = http.post(...)`)
51
51
  // and there is no synchronous fetch, so each request round-trips through a
@@ -34,6 +34,8 @@ export interface JUnitCaseInput {
34
34
  export interface JUnitSuiteInput {
35
35
  device: string
36
36
  cases: JUnitCaseInput[]
37
+ // --test-suite-name; absent keeps the existing "Test Suite" name.
38
+ name?: string
37
39
  }
38
40
 
39
41
  function formatJUnitTime(seconds: number): string {
@@ -49,7 +51,7 @@ export function buildJUnitXml(suite: JUnitSuiteInput): string {
49
51
  const lines = [
50
52
  '<?xml version="1.0" encoding="UTF-8"?>',
51
53
  '<testsuites>',
52
- ` <testsuite name="Test Suite" device="${escapeXml(suite.device)}" tests="${suite.cases.length}" failures="${failures}" time="${formatJUnitTime(totalTime)}">`,
54
+ ` <testsuite name="${escapeXml(suite.name ?? 'Test Suite')}" device="${escapeXml(suite.device)}" tests="${suite.cases.length}" failures="${failures}" time="${formatJUnitTime(totalTime)}">`,
53
55
  ]
54
56
  for (const c of suite.cases) {
55
57
  lines.push(
@@ -164,7 +166,7 @@ export function buildSessionLog(input: {
164
166
  }): string {
165
167
  const passed = input.flows.filter((flow) => flow.passed).length
166
168
  const lines = [
167
- '# rnx maestro session log',
169
+ '# peach maestro session log',
168
170
  `# started: ${input.startedAtIso}`,
169
171
  `# root: ${input.root}`,
170
172
  `# device: ${input.device}`,
package/cli/main.ts CHANGED
@@ -1,4 +1,4 @@
1
- // the rnx CLI proper: argv parsing, the one-time privacy choice, and the
1
+ // the peach CLI proper: argv parsing, the one-time privacy choice, and the
2
2
  // single lazy-imported command a run dispatches to. `./bin` imports this only
3
3
  // when none of its hidden entry points claimed the process.
4
4
 
@@ -22,7 +22,7 @@ import { IS_STANDALONE } from './standalone'
22
22
  // don't paper over real bugs.
23
23
  function handleTopLevelError(err: unknown): never {
24
24
  const msg = err instanceof Error ? err.message : String(err)
25
- // rnx's known top-level errors are all single-line, narrow strings.
25
+ // peach's known top-level errors are all single-line, narrow strings.
26
26
  // everything else gets the full stack so unexpected crashes still surface.
27
27
  const isKnownCliFailure =
28
28
  /^command timed out after \d+s$/.test(msg) ||
@@ -32,12 +32,12 @@ function handleTopLevelError(err: unknown): never {
32
32
  msg.startsWith('saved sim ') ||
33
33
  msg.startsWith('no sim connected with id ') ||
34
34
  msg.startsWith('could not connect to ws://') ||
35
- msg.startsWith('rnx bridge daemon is not running') ||
36
- msg.startsWith('rnx bridge lockfile is fresh') ||
37
- msg.startsWith('rnx bridge exited before becoming ready') ||
35
+ msg.startsWith('peach bridge daemon is not running') ||
36
+ msg.startsWith('peach bridge lockfile is fresh') ||
37
+ msg.startsWith('peach bridge exited before becoming ready') ||
38
38
  msg.startsWith(`${rnxPublicBrand.commandName} open: requested bridge port`) ||
39
39
  msg.startsWith('background daemon setup is unavailable') ||
40
- msg.startsWith('rnx bridge did not start within')
40
+ msg.startsWith('peach bridge did not start within')
41
41
  if (isKnownCliFailure && !process.env.SOOTSIM_VERBOSE) {
42
42
  process.stderr.write(` ${msg}\n`)
43
43
  process.exit(1)
@@ -191,7 +191,7 @@ async function scheduleAutomaticCliUpdate(exitCode: number): Promise<void> {
191
191
  const update = takeCliUpdateNotification()
192
192
  if (update) {
193
193
  process.stderr.write(
194
- ` update: rnx v${update.currentVersion} → v${update.latestVersion} · run \`rnx upgrade\`\n`,
194
+ ` update: peach v${update.currentVersion} → v${update.latestVersion} · run \`peach upgrade\`\n`,
195
195
  )
196
196
  }
197
197
  if (!claimAutomaticCliUpdateCheck()) return
@@ -223,7 +223,7 @@ if (parsed.version) {
223
223
  console.log(`${rnxPublicBrand.commandName} v${getCliVersion()}${suffix}`)
224
224
  // runtime version on its own line — keeps the first line parseable while
225
225
  // surfacing the (independently-versioned) engine runtime users actually
226
- // render with. see `rnx upgrade`.
226
+ // render with. see `peach upgrade`.
227
227
  const { readActiveRuntime } = await import('../src/home-paths')
228
228
  const runtime = readActiveRuntime()
229
229
  console.log(runtime ? `runtime v${runtime}` : 'runtime not installed')
@@ -270,7 +270,7 @@ if (!parsed.command && parsed.commandArgs.length === 0) {
270
270
  }
271
271
 
272
272
  // route to command. an empty command at this point only happens if the
273
- // caller passed bare positional args without a verb (e.g. `rnx -- foo`),
273
+ // caller passed bare positional args without a verb (e.g. `peach -- foo`),
274
274
  // which used to fall through to the bundler-wrap behavior in `dev`. now that
275
275
  // `dev` is gone, treat it as "show help".
276
276
  const command = parsed.command ?? ''
@@ -313,8 +313,8 @@ if (
313
313
  await exitWithFlush(await runReset(commandArgsWithSim, { port }))
314
314
  }
315
315
  // for grouping verbs, try to resolve per-verb help from the first
316
- // positional arg. e.g. `rnx do tap --help` shows tap's help page,
317
- // not the generic `do` grouping page. bare `rnx do --help` falls
316
+ // positional arg. e.g. `peach do tap --help` shows tap's help page,
317
+ // not the generic `do` grouping page. bare `peach do --help` falls
318
318
  // through to runInspect which has the full verb group listing.
319
319
  const isGroupingVerb =
320
320
  command === 'do' ||
@@ -328,7 +328,7 @@ if (
328
328
  // shell and perf subcommands are documented by their runtime dispatchers.
329
329
  // don't try to route through generated per-verb docs.
330
330
  } else if (isGroupingVerb && !subVerb) {
331
- // bare `rnx <group> --help` — render from the registry.
331
+ // bare `peach <group> --help` — render from the registry.
332
332
  const { printGroupHelp } = await import('./help')
333
333
  if (printGroupHelp(command)) await exitWithFlush(0)
334
334
  // fall through — runInspect shows the full help for anything the
@@ -390,7 +390,7 @@ try {
390
390
  const { runMaestro } = await import('./commands/maestro')
391
391
  // Maestro forwards playback argv to the shared runner, so it must
392
392
  // receive the global `--sim`. passing the bare
393
- // parsed.commandArgs dropped an explicit `rnx --sim <id> maestro
393
+ // parsed.commandArgs dropped an explicit `peach --sim <id> maestro
394
394
  // …`, silently falling back to the current/saved sim (QA F21-4).
395
395
  const code = await runMaestro(commandArgsWithSim, { port, verbose })
396
396
  // bridge + dynamic imports leave handles open that keep node alive.
@@ -539,7 +539,7 @@ try {
539
539
  case 'web': {
540
540
  const { getRnxCommandAvailability } = await import('./command-registry')
541
541
  const availability = getRnxCommandAvailability('web', parsed.commandArgs, 'node')
542
- console.error(` ${availability.reason ?? 'rnx web is unavailable'}`)
542
+ console.error(` ${availability.reason ?? 'peach web is unavailable'}`)
543
543
  await exitWithFlush(1)
544
544
  }
545
545
 
@@ -82,7 +82,7 @@ export const OUTBOUND_ENDPOINTS: Record<string, OutboundEndpointDeclaration> = {
82
82
  },
83
83
  same_origin_runtime: {
84
84
  category: 'same-origin-runtime',
85
- destination: 'the origin already serving the rnx runtime',
85
+ destination: 'the origin already serving the peach runtime',
86
86
  preConsent: true,
87
87
  payload: 'runtime assets and shared local settings',
88
88
  },
@@ -90,7 +90,7 @@ export const OUTBOUND_ENDPOINTS: Record<string, OutboundEndpointDeclaration> = {
90
90
  category: 'guest-app-network',
91
91
  destination: 'URLs requested by the user app or supplied explicitly by the user',
92
92
  preConsent: true,
93
- payload: 'the app request itself; rnx does not add telemetry fields',
93
+ payload: 'the app request itself; peach does not add telemetry fields',
94
94
  },
95
95
  remote_display_server: {
96
96
  category: 'explicit-user-action',
@@ -109,10 +109,10 @@ export const OUTBOUND_ENDPOINTS: Record<string, OutboundEndpointDeclaration> = {
109
109
  // the only egress that sends the CONTENTS of the user's project somewhere,
110
110
  // and to an operator-chosen host rather than a Contrast one, so it must not
111
111
  // be readable as "the usual Contrast call".
112
- rnx_cloud_box: {
112
+ peach_cloud_box: {
113
113
  category: 'explicit-user-action',
114
114
  destination:
115
- 'the RNX cloud box service named by --endpoint or RNX_BOX_ENDPOINT; no default, so this call cannot happen unless the user names a host',
115
+ 'the Peach Cloud box service named by --endpoint or PEACH_BOX_ENDPOINT; no default, so this call cannot happen unless the user names a host',
116
116
  preConsent: false,
117
117
  payload:
118
118
  'every file git reports for the current checkout, then shell commands and file reads and writes for as long as the box shell is open',
@@ -125,20 +125,20 @@ export const OUTBOUND_ENDPOINTS: Record<string, OutboundEndpointDeclaration> = {
125
125
  payload:
126
126
  'the project .swift sources, packed bundle resources and images, plus the signed preview token or ccdn_ api key that authorizes the compile',
127
127
  },
128
- rnx_cloud_sim: {
128
+ peach_cloud_sim: {
129
129
  category: 'explicit-user-action',
130
130
  destination:
131
- 'https://rnxsim.com by default, or the test or disposable origin named by RNX_CLOUD_ORIGIN',
131
+ 'https://rnxsim.com by default, or the test or disposable origin named by PEACH_CLOUD_ORIGIN',
132
132
  preConsent: false,
133
133
  payload:
134
- 'the Metro JavaScript bundle selected by rnx ios --remote, then structured simulator commands and lifecycle requests',
134
+ 'the Metro JavaScript bundle selected by peach ios --remote, then structured simulator commands and lifecycle requests',
135
135
  },
136
136
  tunnel_tool_download: {
137
137
  category: 'explicit-user-action',
138
138
  destination: 'https://github.com/cloudflare/cloudflared/releases/latest/download/',
139
139
  preConsent: false,
140
140
  payload:
141
- 'platform and architecture only, carried in the release asset name; fires only for rnx test --cloud with a live dev stack when no cloudflared binary is installed',
141
+ 'platform and architecture only, carried in the release asset name; fires only for peach test --cloud with a live dev stack when no cloudflared binary is installed',
142
142
  },
143
143
  }
144
144
 
@@ -152,50 +152,50 @@ export interface OutboundCallDeclaration {
152
152
  // fails the package test until its destination and consent behavior are declared.
153
153
  export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> = {
154
154
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${apiOrigin}/v1/boxes`': {
155
- category: 'rnx_cloud_sim',
155
+ category: 'peach_cloud_sim',
156
156
  count: 1,
157
157
  },
158
158
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${session.apiOrigin}/v1/sims/${encodeURIComponent()}/claim`':
159
- { category: 'rnx_cloud_sim', count: 1 },
159
+ { category: 'peach_cloud_sim', count: 1 },
160
160
  // two call sites delete a box by id: closing a nano-box simulator, and
161
161
  // closing a box from a session that is not itself the box. one destination,
162
162
  // so one declaration.
163
163
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${session.apiOrigin}/v1/boxes/${encodeURIComponent()}`':
164
- { category: 'rnx_cloud_sim', count: 2 },
164
+ { category: 'peach_cloud_sim', count: 2 },
165
165
  // closing an instance simulator deletes it by its own id with its own token.
166
166
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${session.apiOrigin}/v1/sims/${encodeURIComponent()}`':
167
- { category: 'rnx_cloud_sim', count: 1 },
167
+ { category: 'peach_cloud_sim', count: 1 },
168
168
  // the box api mirrors the sim api for a micro box: the same destination and
169
169
  // the same box token, reached through the session rather than a loose id.
170
170
  // driving a box sends each command to its own box.
171
171
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${this.session.apiOrigin}/v1/boxes/${encodeURIComponent()}/commands`':
172
- { category: 'rnx_cloud_sim', count: 1 },
172
+ { category: 'peach_cloud_sim', count: 1 },
173
173
  // stopping a box leaves it allocated, unlike the delete above.
174
174
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${session.apiOrigin}/v1/boxes/${encodeURIComponent()}/stop`':
175
- { category: 'rnx_cloud_sim', count: 1 },
175
+ { category: 'peach_cloud_sim', count: 1 },
176
176
  // the display grant is polled until the box hands one back; the body is
177
177
  // empty, so the request carries no project or app data.
178
178
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${options.apiOrigin}/v1/boxes/${encodeURIComponent()}/display-grant`':
179
- { category: 'rnx_cloud_sim', count: 1 },
180
- // `rnx remote` creates through the instance api and lists what it made.
179
+ { category: 'peach_cloud_sim', count: 1 },
180
+ // `peach remote` creates through the instance api and lists what it made.
181
181
  // the create carries labels and wait=true in the query; the list filters
182
182
  // by the remote label.
183
183
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${apiOrigin}/v1/sims?${query}`': {
184
- category: 'rnx_cloud_sim',
184
+ category: 'peach_cloud_sim',
185
185
  count: 1,
186
186
  },
187
187
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${apiOrigin}/v1/sims?${selector}`':
188
188
  {
189
- category: 'rnx_cloud_sim',
189
+ category: 'peach_cloud_sim',
190
190
  count: 1,
191
191
  },
192
192
  // rereading one simulator and deleting one by id share the route: the
193
- // reattach probe reads with either credential and `rnx remote stop`
193
+ // reattach probe reads with either credential and `peach remote stop`
194
194
  // deletes with the account credential.
195
195
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${apiOrigin}/v1/sims/${encodeURIComponent()}`':
196
- { category: 'rnx_cloud_sim', count: 2 },
196
+ { category: 'peach_cloud_sim', count: 2 },
197
197
  'packages/peachsim/cli/cloud-client.ts :: fetch :: `${this.session.apiOrigin}/v1/sims/${encodeURIComponent()}/commands`':
198
- { category: 'rnx_cloud_sim', count: 1 },
198
+ { category: 'peach_cloud_sim', count: 1 },
199
199
  'packages/peachsim/cli/cloud-client.ts :: fetch :: bundleUrl': {
200
200
  category: 'guest_app_network',
201
201
  count: 1,
@@ -225,7 +225,7 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
225
225
  count: 1,
226
226
  },
227
227
  'packages/peachsim/src/cloud.ts :: fetch :: url': {
228
- category: 'rnx_cloud_sim',
228
+ category: 'peach_cloud_sim',
229
229
  count: 1,
230
230
  },
231
231
  // maestro's flow `http` API. the url is whatever the flow author wrote, and
@@ -234,15 +234,15 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
234
234
  category: 'guest_app_network',
235
235
  count: 1,
236
236
  },
237
- // `rnx box create` uploads the checkout to the box service and then talks to
237
+ // `peach box create` uploads the checkout to the box service and then talks to
238
238
  // it. the destination is whatever the user named; there is no default.
239
239
  'packages/peach-cloud-box/src/client.ts :: fetch :: endpointOf(base, name, verb, search)':
240
240
  {
241
- category: 'rnx_cloud_box',
241
+ category: 'peach_cloud_box',
242
242
  count: 1,
243
243
  },
244
244
  'packages/peach-cloud-box/src/client.ts :: websocket :: url': {
245
- category: 'rnx_cloud_box',
245
+ category: 'peach_cloud_box',
246
246
  count: 1,
247
247
  },
248
248
  // a micro box's own Browser Run session, over the worker's BROWSER binding.
@@ -250,13 +250,13 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
250
250
  // is a placeholder that exists only so URL can parse the search parameters.
251
251
  // nothing leaves Cloudflare and no project content is sent.
252
252
  'packages/peach-cloud-box/src/browser-run.ts :: fetch :: sessionEndpoint(undefined, { keepAliveMs, includeTargets: true })':
253
- { category: 'rnx_cloud_box', count: 1 },
253
+ { category: 'peach_cloud_box', count: 1 },
254
254
  'packages/peach-cloud-box/src/browser-run.ts :: fetch :: `https://browser.invalid/v1/devtools/browser/${sessionId}/json/list`':
255
- { category: 'rnx_cloud_box', count: 1 },
255
+ { category: 'peach_cloud_box', count: 1 },
256
256
  // twice: closing the session, and the CDP websocket upgrade that navigates a
257
257
  // target. both address the same session over the same binding.
258
258
  'packages/peach-cloud-box/src/browser-run.ts :: fetch :: `https://browser.invalid/v1/devtools/browser/${sessionId}`':
259
- { category: 'rnx_cloud_box', count: 2 },
259
+ { category: 'peach_cloud_box', count: 2 },
260
260
  // the account's own session meter: starting, listing and heartbeating the
261
261
  // session a cloud box is billed against. no project content.
262
262
  "packages/peach-cloud-box/src/client.ts :: fetch :: `${options.apiOrigin.replace(/\\/+$/, '')}/api/v1/rnx/sessions${ options.accountId ? `?accountId=${encodeURIComponent()}` : '' }`":
@@ -265,7 +265,7 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
265
265
  category: 'contrast_user_action',
266
266
  count: 1,
267
267
  },
268
- // `rnx box connect` asks the account service which box that ID or name is
268
+ // `peach box connect` asks the account service which box that ID or name is
269
269
  // and for the box's own token. the account is the only thing that knows, so
270
270
  // this is the one call that turns a name into an authorized Box reference.
271
271
  'packages/peach-cloud-box/src/client.ts :: fetch :: connectUrl': {
@@ -325,6 +325,8 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
325
325
  { category: 'contrast_user_action', count: 1 },
326
326
  'packages/peach-engine/src/auth/shared-session.ts :: fetch :: `${CONTRAST_ORIGIN}/api/auth/me`':
327
327
  { category: 'contrast_user_action', count: 1 },
328
+ 'packages/peach-engine/src/auth/shared-session.ts :: fetch :: `${CONTRAST_ORIGIN}/api/preview/pair-token`':
329
+ { category: 'contrast_user_action', count: 1 },
328
330
  'packages/peach-engine/src/auth/shared-session.ts :: fetch :: `${CONTRAST_ORIGIN}/api/auth/sign-out`':
329
331
  { category: 'contrast_user_action', count: 1 },
330
332
  "packages/peach-engine/src/billing/client.ts :: fetch :: apiUrl('/api/sootsim/billing/checkout')":
@@ -404,7 +406,7 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
404
406
  count: 2,
405
407
  },
406
408
  // the path is a parameter so one uploader serves both callers: recordings use
407
- // /api/preview/upload/{init,finalize} (the default) and `rnx preview` passes
409
+ // /api/preview/upload/{init,finalize} (the default) and `peach preview` passes
408
410
  // /api/v1/previews{,/finalize}. both are first-party contrast endpoints.
409
411
  'packages/peach-engine/src/preview/presigned-upload.ts :: fetch :: `${origin}${endpoints.finalize}`':
410
412
  { category: 'contrast_user_action', count: 1 },
package/cli/parse-args.ts CHANGED
@@ -35,7 +35,7 @@ const GLOBAL_FLAGS: Record<
35
35
  // whether it takes a value. a command that rejects unknown flags uses this to
36
36
  // tell a genuinely unknown flag apart from a global one typed after the
37
37
  // command, where nothing reads it, and to show how to pass that one: telling
38
- // someone to write `rnx --verbose <value>` earns them a second error.
38
+ // someone to write `peach --verbose <value>` earns them a second error.
39
39
  export const GLOBAL_FLAG_TAKES_VALUE: ReadonlyMap<string, boolean> = new Map(
40
40
  Object.entries(GLOBAL_FLAGS).flatMap(([name, def]): [string, boolean][] => {
41
41
  const takesValue = def.type !== 'boolean'
@@ -50,9 +50,9 @@ export const GLOBAL_FLAG_TAKES_VALUE: ReadonlyMap<string, boolean> = new Map(
50
50
 
51
51
  // top-level verbs that route into runInspect. the surface is intentionally
52
52
  // tiny — everything else lives under one of the grouping verbs:
53
- // - `rnx get <noun>` reads
54
- // - `rnx do <action>` writes
55
- // - `rnx debug <tool>` instrumentation (handled by runDebug)
53
+ // - `peach get <noun>` reads
54
+ // - `peach do <action>` writes
55
+ // - `peach debug <tool>` instrumentation (handled by runDebug)
56
56
  // `describe` and `find` stay at root as the most common entrypoints.
57
57
  // `list` stays at root because it's a sim-management read.
58
58
  export const TOP_LEVEL_RUNTIME_COMMANDS = new Set([
@@ -67,9 +67,9 @@ export const TOP_LEVEL_RUNTIME_COMMANDS = new Set([
67
67
  'shell',
68
68
  ])
69
69
 
70
- // grouping verbs that take a sub-verb (`rnx wait ready`,
71
- // `rnx do tap-id`). agents and humans very often type the hyphenated
72
- // form (`rnx wait-ready`, `rnx do-tap-id`) — it reads as one
70
+ // grouping verbs that take a sub-verb (`peach wait ready`,
71
+ // `peach do tap-id`). agents and humans very often type the hyphenated
72
+ // form (`peach wait-ready`, `peach do-tap-id`) — it reads as one
73
73
  // command and matches the typed-tool names (rnx_wait_ready). bin.ts
74
74
  // normalizes `<verb>-<rest>` → `<verb> <rest>` for these so the intuitive
75
75
  // spelling just works instead of failing as "unknown command".
package/cli/privacy.ts CHANGED
@@ -42,7 +42,7 @@ export async function ensurePrivacyChoice(options: {
42
42
  }
43
43
 
44
44
  const allowed = await confirm(
45
- 'Share anonymous package incompatibilities and error classes to improve rnx?',
45
+ 'Share anonymous package incompatibilities and error classes to improve peach?',
46
46
  false,
47
47
  )
48
48
  // the engine's historical analytics and crash transports carry broader
@@ -24,7 +24,7 @@ async function billingOriginFor(auth: CliAuth, originOverride?: string): Promise
24
24
  if (shared?.origin) {
25
25
  return shared.origin.replace(/\/$/, '')
26
26
  }
27
- // api-key auth (RNX_API_KEY) carries no origin.
27
+ // api-key auth (PEACH_API_KEY) carries no origin.
28
28
  // resolve it the same way the upload itself does — probe a local Contrast
29
29
  // stack on :3000, else fall back to prod. this keeps the entitlement
30
30
  // check pointed at the *same* origin the recording will upload to (the
@@ -42,7 +42,7 @@ export interface RecordingEntitlementOptions {
42
42
  * origin stored in the shared desktop session. */
43
43
  originOverride?: string
44
44
  /** allow GitHub installation/action auth to record for pr preview uploads.
45
- * this is intentionally opt-in so local `rnx record` stays tied to
45
+ * this is intentionally opt-in so local `peach record` stays tied to
46
46
  * the user's paid/trial desktop entitlement. */
47
47
  allowGitHubAuth?: boolean
48
48
  }
@@ -54,10 +54,10 @@ export async function ensureCliRecordingEntitlement(
54
54
  const auth = resolveCliAuth()
55
55
  if (!auth) {
56
56
  process.stderr.write(
57
- `\n rnx ${commandLabel} needs auth before it can check recording access.\n\n` +
57
+ `\n peach needs auth before it can check recording access.\n\n` +
58
58
  ` pick one:\n` +
59
- ` • run \`rnx login\`\n` +
60
- ` • set RNX_API_KEY=sk_rnx_... (recommended for CI)\n\n`,
59
+ ` • run \`peach login\`\n` +
60
+ ` • set PEACH_API_KEY=sk_rnx_... (recommended for CI)\n\n`,
61
61
  )
62
62
  rnxExit(1)
63
63
  }
@@ -72,7 +72,7 @@ export async function ensureCliRecordingEntitlement(
72
72
  })
73
73
  } catch (error) {
74
74
  process.stderr.write(
75
- `\n rnx ${commandLabel} couldn't verify recording access.\n` +
75
+ `\n peach couldn't verify recording access.\n` +
76
76
  ` ${error instanceof Error ? error.message : String(error)}\n\n`,
77
77
  )
78
78
  rnxExit(1)
@@ -80,8 +80,8 @@ export async function ensureCliRecordingEntitlement(
80
80
 
81
81
  if (res.status === 401) {
82
82
  process.stderr.write(
83
- `\n rnx ${commandLabel} couldn't verify recording access with the current auth against ${billingOrigin}.\n` +
84
- ` sign in again for that origin, or provide a valid RNX_API_KEY.\n\n`,
83
+ `\n peach couldn't verify recording access with the current auth against ${billingOrigin}.\n` +
84
+ ` sign in again for that origin, or provide a valid PEACH_API_KEY.\n\n`,
85
85
  )
86
86
  rnxExit(1)
87
87
  }
@@ -89,7 +89,7 @@ export async function ensureCliRecordingEntitlement(
89
89
  if (!res.ok) {
90
90
  const text = await res.text().catch(() => '')
91
91
  process.stderr.write(
92
- `\n rnx ${commandLabel} couldn't verify recording access (${res.status}).\n` +
92
+ `\n peach couldn't verify recording access (${res.status}).\n` +
93
93
  ` ${text || 'unexpected billing response'}\n\n`,
94
94
  )
95
95
  rnxExit(1)
@@ -100,7 +100,7 @@ export async function ensureCliRecordingEntitlement(
100
100
 
101
101
  const plan = data.plan ?? 'free'
102
102
  process.stderr.write(
103
- `\n rnx ${commandLabel} recording requires Personal, Team, or an active trial.\n` +
103
+ `\n peach recording requires Personal, Team, or an active trial.\n` +
104
104
  ` current plan: ${plan}.\n` +
105
105
  ` free keeps basic 3d mode; the trial unlocks the full Personal surface.\n\n`,
106
106
  )
@@ -1,4 +1,4 @@
1
- // resolve rnx's bundled assets (fonts, icons, sounds)
1
+ // resolve peach's bundled assets (fonts, icons, sounds)
2
2
  // regardless of how the package was installed (source checkout, npm install, bunx).
3
3
  //
4
4
  // uses import.meta.url to derive the package root, then checks both
@@ -48,7 +48,7 @@ export function resolveAssets(): SootSimAssets {
48
48
  const soundsDir = resolve(publicDir, 'sounds')
49
49
 
50
50
  if (!existsSync(fontsDir)) {
51
- console.warn(`[rnx] warning: fonts directory not found at ${fontsDir}`)
51
+ console.warn(`[peach] warning: fonts directory not found at ${fontsDir}`)
52
52
  }
53
53
 
54
54
  return {