peachsim 0.1.1481 → 0.1.1619
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.
- package/README.md +56 -13
- package/cli/app-catalog.ts +7 -5
- package/cli/app-config.ts +47 -8
- package/cli/app-fonts.ts +84 -49
- package/cli/app-stubs.ts +433 -0
- package/cli/bin.ts +15 -2
- package/cli/bridge-flow-runner.ts +383 -123
- package/cli/cloud-client.ts +26 -25
- package/cli/cloud-test-tunnel.ts +2 -0
- package/cli/command-registry.ts +2 -1
- package/cli/commands/agent-indicator-mode.ts +39 -0
- package/cli/commands/box/bundle-plane.ts +4 -0
- package/cli/commands/box.ts +16 -23
- package/cli/commands/control.ts +221 -126
- package/cli/commands/daemon.ts +99 -24
- package/cli/commands/debug.ts +31 -3
- package/cli/commands/detect.ts +1 -1
- package/cli/commands/device.ts +6 -8
- package/cli/commands/diagnose.ts +2 -0
- package/cli/commands/do-chain.ts +2 -2
- package/cli/commands/doctor.ts +1030 -0
- package/cli/commands/flow.ts +447 -406
- package/cli/commands/inspect/actions.ts +2 -0
- package/cli/commands/inspect/core.ts +138 -46
- package/cli/commands/inspect/env.ts +10 -0
- package/cli/commands/inspect/list.ts +25 -8
- package/cli/commands/inspect/memory.ts +9 -0
- package/cli/commands/inspect/settling.ts +219 -66
- package/cli/commands/inspect/shared.ts +53 -12
- package/cli/commands/inspect/wait-event.ts +0 -1
- package/cli/commands/inspect/wait.ts +2 -2
- package/cli/commands/inspect.ts +51 -16
- package/cli/commands/install-desktop.ts +3 -2
- package/cli/commands/kotlin.ts +81 -22
- package/cli/commands/login.ts +1 -1
- package/cli/commands/maestro-compare.ts +41 -5
- package/cli/commands/maestro-generate.ts +11 -7
- package/cli/commands/maestro.ts +43 -15
- package/cli/commands/mode.ts +13 -1
- package/cli/commands/no-bridge-hint.ts +26 -3
- package/cli/commands/perf-record.ts +296 -0
- package/cli/commands/perf.ts +6 -1
- package/cli/commands/platform.ts +15 -4
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/record.ts +37 -6
- package/cli/commands/report-issue.ts +2 -1
- package/cli/commands/runtime.ts +9 -11
- package/cli/commands/screenshots.ts +4 -3
- package/cli/commands/serve.ts +30 -2
- package/cli/commands/setup.ts +32 -7
- package/cli/commands/skills.ts +16 -43
- package/cli/commands/swift.ts +22 -3
- package/cli/commands/upgrade.ts +7 -6
- package/cli/commands/upload.ts +118 -69
- package/cli/commands/window.ts +449 -0
- package/cli/current-sim.ts +1 -2
- package/cli/desktop-companion.ts +84 -10
- package/cli/device-option.ts +8 -0
- package/cli/drivers/desktop.ts +3 -1
- package/cli/drivers/playwright-sim-host.ts +30 -11
- package/cli/drivers/playwright.ts +1 -4
- package/cli/flow-export.ts +2 -2
- package/cli/flow-file.ts +19 -18
- package/cli/internal-child.ts +7 -6
- package/cli/maestro-compare.ts +28 -6
- package/cli/maestro-js.ts +2 -1
- package/cli/main.ts +25 -4
- package/cli/material-symbol-fonts.ts +171 -0
- package/cli/outbound-endpoints.ts +132 -54
- package/cli/parse-args.ts +7 -0
- package/cli/preview-capture.ts +12 -0
- package/cli/privacy.ts +1 -1
- package/cli/run-registry.ts +5 -2
- package/cli/runtime-compat.ts +16 -0
- package/cli/telemetry.ts +6 -3
- package/cli/ui.ts +5 -0
- package/cli/ws-bridge.ts +121 -62
- package/detox/attempt-events.cjs +762 -0
- package/detox/attempt-events.d.cts +106 -0
- package/detox/gestures.ts +115 -2
- package/detox/index.ts +762 -426
- package/detox/jest-environment.cjs +86 -0
- package/detox/jest-preset.cjs +3 -1
- package/detox/jest-setup-after-env.cjs +1 -0
- package/detox/matchers.ts +3 -6
- package/detox/motion-change.cjs +259 -0
- package/detox/motion-change.d.cts +73 -0
- package/detox/proof-frame.cjs +83 -9
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +15 -5
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +3 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/bundle-channel.cjs +5950 -1775
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +6 -1
- package/dist-lib/cloud-contract.mjs +5 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +34 -3
- package/dist-lib/config.mjs +33 -3
- package/dist-lib/detox/index.cjs +3443 -564
- package/dist-lib/detox/jest-environment.cjs +86 -0
- package/dist-lib/detox/jest-preset.cjs +3 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +5518 -1446
- package/dist-lib/expo-swift-metadata.cjs +21 -13
- package/dist-lib/expo-swift-metadata.mjs +21 -13
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +21728 -16808
- package/dist-lib/host/fetch-proxy-handler.cjs +177 -102
- package/dist-lib/host/fetch-proxy-overrides.cjs +84 -4
- package/dist-lib/host/fetch-proxy-overrides.mjs +74 -3
- package/dist-lib/host/replacement-module-handler.cjs +16 -15
- package/dist-lib/host/websocket-proxy.cjs +243 -6
- package/dist-lib/index.cjs +6063 -4113
- package/dist-lib/jump-to-source-babel.cjs +73 -35
- package/dist-lib/jump-to-source-native.cjs +118 -10
- package/dist-lib/kotlin-host.cjs +264 -121
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +147 -99
- package/dist-lib/metro-production-bundle.mjs +142 -99
- package/dist-lib/metro.cjs +4249 -360
- package/dist-lib/native-app-identity-project.cjs +318 -131
- package/dist-lib/native-app-identity-project.mjs +317 -131
- package/dist-lib/native-app-identity.cjs +322 -33
- package/dist-lib/native-app-identity.mjs +319 -32
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +11 -1
- package/dist-lib/react-native-host-modules.mjs +11 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +127 -42
- package/dist-lib/sdk.cjs +311 -103
- package/dist-lib/sdk.mjs +311 -103
- package/dist-lib/skills.cjs +18344 -11121
- package/dist-lib/swift-compile.cjs +3291 -544
- package/dist-lib/swift-compile.mjs +3227 -478
- package/dist-lib/swift-package.cjs +25 -3
- package/dist-lib/swift-package.mjs +22 -2
- package/dist-lib/swift-submit.cjs +2 -2
- package/dist-lib/swift-submit.mjs +2 -2
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +5523 -1428
- package/dist-lib/vite.cjs +251 -60
- package/dist-lib/worklet-executable.cjs +18 -4
- package/dist-lib/worklet-executable.mjs +18 -4
- package/install.sh +8 -3
- package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +2 -0
- package/kotlin/AndroidViewSources/android/graphics/Paint.kt +18 -0
- package/kotlin/AndroidViewSources/dev/peach/app/JavaFormat.kt +16 -8
- package/kotlin/AppSources/android/view/Window.kt +4 -1
- package/kotlin/AppSources/android/window/BackEvent.kt +24 -0
- package/kotlin/AppSources/android/window/OnBackAnimationCallback.kt +7 -0
- package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +37 -1
- package/kotlin/AppSources/androidx/activity/BackEventCompat.kt +5 -0
- package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +8 -1
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +14 -0
- package/kotlin/CompilerSources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar +1 -0
- package/kotlin/CompilerSources/PeachJniIncoming.kt +243 -0
- package/kotlin/CompilerSources/PeachJniPlugin.kt +116 -0
- package/kotlin/ComposeSources/PeachComposeHost.kt +58 -32
- package/kotlin/ComposeSources/PeachMagnifier.kt +185 -0
- package/kotlin/ExpoComposeSources/PeachAndroidView.kt +16 -0
- package/kotlin/JniPlatformSources/androidx/annotation/CallSuper.kt +5 -0
- package/kotlin/JniPlatformSources/com/facebook/proguard/annotations/DoNotStrip.kt +5 -0
- package/kotlin/JniPlatformSources/dalvik/annotation/optimization/FastNative.kt +5 -0
- package/kotlin/JniPlatformSources/kotlin/Synchronized.kt +6 -0
- package/kotlin/JniPlatformSources/kotlin/jvm/JvmField.kt +5 -0
- package/kotlin/JniPlatformSources/kotlin/jvm/JvmStatic.kt +5 -0
- package/kotlin/JniSources/com/facebook/jni/HybridData.kt +68 -0
- package/kotlin/JniSources/dev/peach/jni/IncomingBindings.kt +157 -0
- package/kotlin/JniSources/dev/peach/jni/NativeBindings.kt +79 -0
- package/kotlin/JniTransportSources/dev/peach/jni/integration/JniTransport.kt +91 -0
- package/kotlin/README.md +18 -0
- package/kotlin/Sources/java/util/IllegalFormatCodePointException.kt +10 -0
- package/kotlin/Sources/java/util/IllegalFormatException.kt +5 -0
- package/kotlin/fixtures/counter/CounterApp.native.tsx +30 -3
- package/kotlin/fixtures/counter/CounterScreen.d.kt.ts +1 -0
- package/kotlin/fixtures/counter/CounterScreen.kt +2 -1
- package/kotlin/fixtures/counter/package.json +15 -2
- package/kotlin/fixtures/counter/vite.config.ts +11 -1
- package/kotlin/fork/NOTICE +1 -0
- package/kotlin/fork/README.md +5 -4
- package/kotlin/fork/compose-worker-globals.patch +629 -0
- package/kotlin/fork/fork.json +1 -1
- package/kotlin/toolchain.json +3 -3
- package/package.json +1 -1
- package/scripts/dev-server-scanner.ts +166 -81
- package/skills/contrast/SKILL.md +4 -4
- package/skills/peach-debug/SKILL.md +1 -1
- package/skills/peach-perf/SKILL.md +25 -0
- package/skills/peach-setup/SKILL.md +47 -13
- package/skills/peach-test/SKILL.md +2 -3
- package/src/agent-identity.ts +18 -0
- package/src/assetCatalogContract.ts +31 -3
- package/src/auth/shared-session.ts +3 -2
- package/src/bridge-constants.ts +1 -1
- package/src/bridge-contract.ts +5 -0
- package/src/bundle-channel.mjs +38 -7
- package/src/bundleGlobalFooter.ts +70 -20
- package/src/cloud-contract.ts +11 -0
- package/src/config.ts +47 -1
- package/src/configured-bundle-producer.ts +4 -1
- package/src/desktop-host-delivery.ts +4 -3
- package/src/expo-kotlin-host.ts +7 -2
- package/src/guest-bundle.ts +15 -8
- package/src/host/agent-host.ts +2 -4
- package/src/host/bridge-host.ts +260 -119
- package/src/host/fetch-proxy-handler.ts +237 -146
- package/src/host/fetch-proxy-overrides.ts +118 -0
- package/src/host/fetch-proxy-transport.ts +77 -63
- package/src/host/lease-owner.test.ts +18 -1
- package/src/host/lease-owner.ts +4 -5
- package/src/host/loopback-ports.ts +34 -0
- package/src/host/replacement-module-handler.ts +24 -15
- package/src/host/server-scan-handler.ts +87 -0
- package/src/host/staged-host-files.ts +92 -0
- package/src/host/websocket-proxy.ts +271 -5
- package/src/installed-package-versions.ts +66 -0
- package/src/jump-to-source-babel.ts +97 -89
- package/src/jump-to-source-native.ts +109 -11
- package/src/kotlin-host.ts +144 -27
- package/src/kotlin-module.ts +52 -0
- package/src/kotlinDiscoveryContract.ts +27 -0
- package/src/metro-layout-parser.ts +78 -0
- package/src/metro-plugin.ts +129 -39
- package/src/metro-production-bundle.ts +140 -139
- package/src/native-app-identity-project.ts +103 -5
- package/src/native-app-identity.ts +173 -11
- package/src/native-firebase-config.ts +83 -80
- package/src/native-seam-manifest.ts +0 -44
- package/src/nativeAppIconContract.ts +137 -0
- package/src/nativeViewSourceContract.ts +49 -0
- package/src/nativeViewWebContract.ts +41 -0
- package/src/nitro-bundle.ts +43 -0
- package/src/nitro-compile.ts +107 -0
- package/src/nitro-source.ts +310 -0
- package/src/nitroContract.ts +51 -0
- package/src/one-widget-metadata.ts +23 -3
- package/src/oneWidgetContract.ts +36 -3
- package/src/packageVersionsContract.ts +52 -0
- package/src/process-group.ts +306 -0
- package/src/process-liveness.ts +24 -0
- package/src/process-output.ts +21 -2
- package/src/react-devtools-frontend-react.ts +45 -0
- package/src/react-native-host-modules.ts +10 -0
- package/src/serverDiscoveryContract.ts +41 -0
- package/src/skills/builtin/maestro-test.ts +2 -4
- package/src/swift-compile.ts +3195 -650
- package/src/swift-design-time.ts +552 -0
- package/src/swift-distribution-contract.ts +11 -0
- package/src/swift-distribution.lock.json +46 -11
- package/src/swift-host.ts +144 -30
- package/src/swift-icu.ts +10 -2
- package/src/swift-objc-sdk.ts +726 -0
- package/src/swift-objc-standin.ts +441 -0
- package/src/swift-package.ts +25 -0
- package/src/swift-packages.ts +25 -10
- package/src/swift-standin-config.ts +94 -0
- package/src/swift-standin-emit.ts +5 -3
- package/src/swift-standins.ts +225 -81
- package/src/swift-submit.ts +2 -1
- package/src/swiftContract.ts +4 -0
- package/src/target-matcher.ts +67 -0
- package/src/visit-parsed-program.ts +21 -0
- package/src/vite-plugin-one.ts +65 -17
- package/src/vite-plugin-swift.ts +1 -0
- package/src/vite-plugin.ts +168 -70
- package/src/worker-system-chunks.ts +89 -10
- package/src/worklet-executable.ts +21 -3
- package/src/worklets-babel.ts +85 -13
- package/src/xcode-project.ts +81 -134
- package/src/xcode-target-members.ts +107 -0
- package/cli/commands/compat.ts +0 -395
package/cli/cloud-client.ts
CHANGED
|
@@ -70,7 +70,6 @@ import type {
|
|
|
70
70
|
export const DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin
|
|
71
71
|
export const MAX_RNX_CLOUD_BUNDLE_BYTES = RNX_CLOUD_MAX_ARTIFACT_BYTES
|
|
72
72
|
|
|
73
|
-
// every message this module writes names the command through this constant.
|
|
74
73
|
const REMOTE_COMMAND = 'peach remote'
|
|
75
74
|
const PREVIEW_COMMAND = 'peach preview'
|
|
76
75
|
|
|
@@ -170,19 +169,19 @@ function resolveCloudOrigin(value?: string): string {
|
|
|
170
169
|
return normalizeCloudOrigin(source)
|
|
171
170
|
}
|
|
172
171
|
|
|
173
|
-
function readImmutableBundleSource(bundlePath: string): string {
|
|
172
|
+
function readImmutableBundleSource(bundlePath: string, command: string): string {
|
|
174
173
|
const filepath = resolve(bundlePath)
|
|
175
174
|
if (extname(filepath) !== '.js') {
|
|
176
|
-
throw new Error(`${
|
|
175
|
+
throw new Error(`${command} requires one local Metro .js bundle`)
|
|
177
176
|
}
|
|
178
177
|
const descriptor = openSync(filepath, 'r')
|
|
179
178
|
try {
|
|
180
179
|
const before = fstatSync(descriptor, { bigint: true })
|
|
181
180
|
if (!before.isFile()) {
|
|
182
|
-
throw new Error(`${
|
|
181
|
+
throw new Error(`${command} bundle must be a regular local file`)
|
|
183
182
|
}
|
|
184
183
|
if (before.size <= 0n) {
|
|
185
|
-
throw new Error(`${
|
|
184
|
+
throw new Error(`${command} bundle is empty`)
|
|
186
185
|
}
|
|
187
186
|
const bytes = readFileSync(descriptor)
|
|
188
187
|
const after = fstatSync(descriptor, { bigint: true })
|
|
@@ -193,16 +192,16 @@ function readImmutableBundleSource(bundlePath: string): string {
|
|
|
193
192
|
before.mtimeNs !== after.mtimeNs ||
|
|
194
193
|
bytes.length !== Number(before.size)
|
|
195
194
|
) {
|
|
196
|
-
throw new Error(`${
|
|
195
|
+
throw new Error(`${command} bundle changed while it was being read`)
|
|
197
196
|
}
|
|
198
197
|
let source: string
|
|
199
198
|
try {
|
|
200
199
|
source = new TextDecoder('utf-8', { fatal: true }).decode(bytes)
|
|
201
200
|
} catch {
|
|
202
|
-
throw new Error(`${
|
|
201
|
+
throw new Error(`${command} bundle must be valid UTF-8 JavaScript`)
|
|
203
202
|
}
|
|
204
203
|
if (source.includes('\0') || !source.includes('__d(') || !source.includes('__r(')) {
|
|
205
|
-
throw new Error(`${
|
|
204
|
+
throw new Error(`${command} requires a Metro JavaScript bundle`)
|
|
206
205
|
}
|
|
207
206
|
return source
|
|
208
207
|
} finally {
|
|
@@ -210,30 +209,30 @@ function readImmutableBundleSource(bundlePath: string): string {
|
|
|
210
209
|
}
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
async function fetchBundleSource(bundleUrl: string): Promise<string> {
|
|
212
|
+
async function fetchBundleSource(bundleUrl: string, command: string): Promise<string> {
|
|
214
213
|
let response: Response
|
|
215
214
|
try {
|
|
216
215
|
response = await fetch(bundleUrl)
|
|
217
216
|
} catch (error) {
|
|
218
217
|
throw new Error(
|
|
219
|
-
`${
|
|
218
|
+
`${command} could not fetch bundle from ${bundleUrl}: ${
|
|
220
219
|
error instanceof Error ? error.message : String(error)
|
|
221
220
|
}`,
|
|
222
221
|
)
|
|
223
222
|
}
|
|
224
223
|
if (!response.ok) {
|
|
225
224
|
throw new Error(
|
|
226
|
-
`${
|
|
225
|
+
`${command} could not fetch bundle from ${bundleUrl}: HTTP ${response.status}${
|
|
227
226
|
response.statusText ? ` ${response.statusText}` : ''
|
|
228
227
|
}`,
|
|
229
228
|
)
|
|
230
229
|
}
|
|
231
230
|
const text = await response.text()
|
|
232
231
|
if (text.length === 0) {
|
|
233
|
-
throw new Error(`${
|
|
232
|
+
throw new Error(`${command} bundle is empty`)
|
|
234
233
|
}
|
|
235
234
|
if (text.includes('\0') || !text.includes('__d(') || !text.includes('__r(')) {
|
|
236
|
-
throw new Error(`${
|
|
235
|
+
throw new Error(`${command} requires a Metro JavaScript bundle`)
|
|
237
236
|
}
|
|
238
237
|
return text
|
|
239
238
|
}
|
|
@@ -254,20 +253,20 @@ function isRemoteBundleInput(bundleInput: string): boolean {
|
|
|
254
253
|
return bundleInput.startsWith('https://') || bundleInput.startsWith('http://')
|
|
255
254
|
}
|
|
256
255
|
|
|
257
|
-
async function loadBundleSource(bundleInput: string): Promise<string> {
|
|
256
|
+
async function loadBundleSource(bundleInput: string, command: string): Promise<string> {
|
|
258
257
|
if (bundleInput.startsWith('http://') && !isLoopbackBundleUrl(bundleInput)) {
|
|
259
|
-
throw new Error(`${
|
|
258
|
+
throw new Error(`${command} bundle URL must use HTTPS`)
|
|
260
259
|
}
|
|
261
260
|
const source = isRemoteBundleInput(bundleInput)
|
|
262
|
-
? await fetchBundleSource(bundleInput)
|
|
263
|
-
: readImmutableBundleSource(bundleInput)
|
|
261
|
+
? await fetchBundleSource(bundleInput, command)
|
|
262
|
+
: readImmutableBundleSource(bundleInput, command)
|
|
264
263
|
// validate the actual runtime script form without executing guest code or
|
|
265
264
|
// allocating a host.
|
|
266
265
|
try {
|
|
267
266
|
new Script(rewriteGuestImportMeta(source), { filename: bundleInput })
|
|
268
267
|
} catch (error) {
|
|
269
268
|
throw new Error(
|
|
270
|
-
`${
|
|
269
|
+
`${command} bundle contains invalid JavaScript: ${
|
|
271
270
|
error instanceof Error ? error.message : String(error)
|
|
272
271
|
}`,
|
|
273
272
|
)
|
|
@@ -549,6 +548,7 @@ function unverifiedContentKey(
|
|
|
549
548
|
function searchMetroAssetDest(
|
|
550
549
|
bundlePath: string,
|
|
551
550
|
descriptors: readonly MetroAssetDescriptor[],
|
|
551
|
+
command: string,
|
|
552
552
|
assetsDirectory?: string,
|
|
553
553
|
): MetroAssetSearch {
|
|
554
554
|
const bundleDirectory = dirname(resolve(bundlePath))
|
|
@@ -616,7 +616,7 @@ function searchMetroAssetDest(
|
|
|
616
616
|
// the wrong repair for a dest that only needs rebuilding.
|
|
617
617
|
if (stale.length > 0) {
|
|
618
618
|
throw new Error(
|
|
619
|
-
`${
|
|
619
|
+
`${command} found this bundle's assets in ${stale.join(', ')}, but their bytes are not the ones it was built against. Rebuild with \`react-native bundle --assets-dest ${stale[0]}\` so the bundle and the images match.`,
|
|
620
620
|
)
|
|
621
621
|
}
|
|
622
622
|
return { dest: null, searched, truncated, unconfirmed: false }
|
|
@@ -633,7 +633,7 @@ function searchMetroAssetDest(
|
|
|
633
633
|
if (!winner) return { dest: null, searched, truncated, unconfirmed: false }
|
|
634
634
|
if (distinct.size > 1) {
|
|
635
635
|
throw new Error(
|
|
636
|
-
`${
|
|
636
|
+
`${command} found this bundle's assets in more than one directory and cannot tell which build wrote them: ${rivals
|
|
637
637
|
.map((rival) => rival.dest.directory)
|
|
638
638
|
.join(
|
|
639
639
|
', ',
|
|
@@ -649,13 +649,14 @@ function searchMetroAssetDest(
|
|
|
649
649
|
|
|
650
650
|
async function inferCloudModuleIdentity(
|
|
651
651
|
source: string,
|
|
652
|
+
command: string,
|
|
652
653
|
): Promise<RNXMetroModuleIdentityMetadata> {
|
|
653
654
|
let receipt
|
|
654
655
|
try {
|
|
655
656
|
receipt = await loadMetroFingerprintRegistry()
|
|
656
657
|
} catch (error) {
|
|
657
658
|
throw new Error(
|
|
658
|
-
`${
|
|
659
|
+
`${command} could not load the Metro fingerprint registry needed to identify this bundle: ${
|
|
659
660
|
error instanceof Error ? error.message : String(error)
|
|
660
661
|
}. Build it through the published Metro plugin: withPeach(config).`,
|
|
661
662
|
)
|
|
@@ -674,7 +675,7 @@ async function inferCloudModuleIdentity(
|
|
|
674
675
|
}
|
|
675
676
|
} catch (error) {
|
|
676
677
|
throw new Error(
|
|
677
|
-
`${
|
|
678
|
+
`${command} could not infer module identity for this Metro bundle: ${
|
|
678
679
|
error instanceof Error ? error.message : String(error)
|
|
679
680
|
}. Build it through the published Metro plugin: withPeach(config).`,
|
|
680
681
|
)
|
|
@@ -775,7 +776,7 @@ async function embedBundleAssets(
|
|
|
775
776
|
dest: MetroAssetDest | null
|
|
776
777
|
substituted: string[]
|
|
777
778
|
}> {
|
|
778
|
-
const source = await loadBundleSource(bundlePath)
|
|
779
|
+
const source = await loadBundleSource(bundlePath, command)
|
|
779
780
|
const descriptors = extractAssetDescriptors(source).filter(
|
|
780
781
|
(descriptor) => !isEmbeddedAssetDescriptor(descriptor),
|
|
781
782
|
)
|
|
@@ -791,7 +792,7 @@ async function embedBundleAssets(
|
|
|
791
792
|
// an https bundle uses only an explicit local asset destination.
|
|
792
793
|
const search: MetroAssetSearch =
|
|
793
794
|
assetsDirectory || !isRemoteBundleInput(bundlePath)
|
|
794
|
-
? searchMetroAssetDest(bundlePath, descriptors, assetsDirectory)
|
|
795
|
+
? searchMetroAssetDest(bundlePath, descriptors, command, assetsDirectory)
|
|
795
796
|
: { dest: null, searched: [], truncated: false, unconfirmed: false }
|
|
796
797
|
const dest = search.dest
|
|
797
798
|
// `embedMetroAssetFiles` re-parses the bundle, so its descriptors are equal
|
|
@@ -877,7 +878,7 @@ async function produceArtifact(
|
|
|
877
878
|
assetsDirectory,
|
|
878
879
|
)
|
|
879
880
|
const artifact = await buildRnxCloudArtifact(prepared.code, {
|
|
880
|
-
inferModuleIdentity: inferCloudModuleIdentity,
|
|
881
|
+
inferModuleIdentity: (source) => inferCloudModuleIdentity(source, command),
|
|
881
882
|
})
|
|
882
883
|
const bytes = Buffer.from(artifact.code, 'utf8')
|
|
883
884
|
const assets = artifact.receipt.assets
|
package/cli/cloud-test-tunnel.ts
CHANGED
|
@@ -137,6 +137,8 @@ export function startCloudTestTokenProxy(
|
|
|
137
137
|
return
|
|
138
138
|
}
|
|
139
139
|
if (selectedPort !== upstreamPort) headers.host = `127.0.0.1:${selectedPort}`
|
|
140
|
+
// the recorder's browser origin belongs to its host, not this dev server.
|
|
141
|
+
if (headers.origin) headers.origin = `http://127.0.0.1:${selectedPort}`
|
|
140
142
|
for (const key of Object.keys(headers)) {
|
|
141
143
|
const lower = key.toLowerCase()
|
|
142
144
|
if (lower.startsWith('x-forwarded-') || lower.startsWith('cf-')) {
|
package/cli/command-registry.ts
CHANGED
|
@@ -50,7 +50,7 @@ const NODE_COMMAND_NAMES = [
|
|
|
50
50
|
'use',
|
|
51
51
|
'claim',
|
|
52
52
|
'close',
|
|
53
|
-
'
|
|
53
|
+
'doctor',
|
|
54
54
|
'project-report',
|
|
55
55
|
'support',
|
|
56
56
|
'desktop',
|
|
@@ -129,6 +129,7 @@ const VALUE_FLAGS = new Set([
|
|
|
129
129
|
'--device',
|
|
130
130
|
'--posture',
|
|
131
131
|
'--os-version',
|
|
132
|
+
'--ios-target',
|
|
132
133
|
'--output',
|
|
133
134
|
'-o',
|
|
134
135
|
'--out',
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// peach mode agent-indicator — show or hide the connected agent indicator and
|
|
2
|
+
// its resting agent cursor over the device in the running peach sim, so
|
|
3
|
+
// scripted recordings can film clean devices while the CLI drives them.
|
|
4
|
+
|
|
5
|
+
import { peachExit } from '../run-rnx'
|
|
6
|
+
import { runShellBooleanMode, type ShellBooleanModeOptions } from './shell-boolean-mode'
|
|
7
|
+
|
|
8
|
+
export async function runAgentIndicatorMode(
|
|
9
|
+
args: string[],
|
|
10
|
+
opts: ShellBooleanModeOptions,
|
|
11
|
+
) {
|
|
12
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
13
|
+
console.log(`
|
|
14
|
+
peach mode agent-indicator — toggle the connected agent indicator
|
|
15
|
+
|
|
16
|
+
usage:
|
|
17
|
+
peach mode agent-indicator [on|off|toggle]
|
|
18
|
+
|
|
19
|
+
arguments:
|
|
20
|
+
on show the indicator while a CLI or agent drives the sim (default)
|
|
21
|
+
off hide it and the agent cursor that rests under it, for clean recordings
|
|
22
|
+
of scripted sims
|
|
23
|
+
toggle flip the current state (default action)
|
|
24
|
+
|
|
25
|
+
the setting persists. a shell url can also seed it with agentIndicator=0.
|
|
26
|
+
|
|
27
|
+
examples:
|
|
28
|
+
peach mode agent-indicator off
|
|
29
|
+
peach --sim a1 mode agent-indicator on
|
|
30
|
+
`)
|
|
31
|
+
peachExit(0)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
await runShellBooleanMode(args, opts, {
|
|
35
|
+
modeKey: 'agentIndicator',
|
|
36
|
+
displayName: 'agent-indicator',
|
|
37
|
+
actionId: 'toggle-agent-indicator',
|
|
38
|
+
})
|
|
39
|
+
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
PREBUILT_BUNDLE_DEVICE_PATH,
|
|
13
|
+
PREBUILT_BUNDLE_INITIAL_URL_PATH,
|
|
13
14
|
PREBUILT_BUNDLE_NATIVE_RENDERER_PATH,
|
|
14
15
|
prebuiltAppFontsPartPath,
|
|
15
16
|
PREBUILT_BUNDLE_PART_BYTES,
|
|
@@ -25,6 +26,7 @@ export class BundleFilePlane implements ProjectFilePlane {
|
|
|
25
26
|
constructor(
|
|
26
27
|
bundle: Uint8Array,
|
|
27
28
|
device: string | null,
|
|
29
|
+
initialUrl: string | null,
|
|
28
30
|
appFonts = '',
|
|
29
31
|
nativeRenderer?: NativeRenderer,
|
|
30
32
|
) {
|
|
@@ -32,6 +34,8 @@ export class BundleFilePlane implements ProjectFilePlane {
|
|
|
32
34
|
if (appFonts)
|
|
33
35
|
this.recordParts(new TextEncoder().encode(appFonts), prebuiltAppFontsPartPath)
|
|
34
36
|
if (device) this.record(PREBUILT_BUNDLE_DEVICE_PATH, new TextEncoder().encode(device))
|
|
37
|
+
if (initialUrl)
|
|
38
|
+
this.record(PREBUILT_BUNDLE_INITIAL_URL_PATH, new TextEncoder().encode(initialUrl))
|
|
35
39
|
if (nativeRenderer !== undefined)
|
|
36
40
|
this.record(
|
|
37
41
|
PREBUILT_BUNDLE_NATIVE_RENDERER_PATH,
|
package/cli/commands/box.ts
CHANGED
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
cloudBoxConnectUrl,
|
|
28
28
|
createCloudBoxProvider,
|
|
29
29
|
ensureCloudBoxBrowser,
|
|
30
|
-
heartbeatSession,
|
|
31
30
|
resolveCloudBoxReference,
|
|
32
31
|
} from 'peach-cloud-box/client'
|
|
33
32
|
import { getRuntimePlatform, isDeviceModel } from 'peach-engine/settings/devices'
|
|
@@ -125,7 +124,7 @@ function apiOrigin(args: string[], auth: CliAuth): string {
|
|
|
125
124
|
return (
|
|
126
125
|
flag(args, 'api-origin') ??
|
|
127
126
|
process.env[API_ORIGIN_ENV]?.trim() ??
|
|
128
|
-
(auth.kind === 'session' ? auth.origin :
|
|
127
|
+
(auth.kind === 'session' ? auth.origin : rnxPublicBrand.origin)
|
|
129
128
|
).replace(/\/+$/, '')
|
|
130
129
|
}
|
|
131
130
|
|
|
@@ -187,6 +186,7 @@ async function runCloudBoxUse(args: string[]): Promise<number> {
|
|
|
187
186
|
apiOrigin: apiOrigin(args, auth),
|
|
188
187
|
apiKey,
|
|
189
188
|
boxId: named,
|
|
189
|
+
accountId: cloudAccountIdOrExit(auth),
|
|
190
190
|
})
|
|
191
191
|
// attach for the Box's own name: the caller may have typed either an id or
|
|
192
192
|
// a name, and the default has to be able to print the one a person reads.
|
|
@@ -361,9 +361,13 @@ async function runCloudBoxConnect(args: string[]): Promise<number> {
|
|
|
361
361
|
const origin = apiOrigin(args, auth)
|
|
362
362
|
|
|
363
363
|
let session: BoxShellSession | null = null
|
|
364
|
-
let heartbeat: { stop: () => void } | null = null
|
|
365
364
|
try {
|
|
366
|
-
const reference = await resolveCloudBoxReference({
|
|
365
|
+
const reference = await resolveCloudBoxReference({
|
|
366
|
+
apiOrigin: origin,
|
|
367
|
+
apiKey,
|
|
368
|
+
boxId,
|
|
369
|
+
accountId: cloudAccountIdOrExit(auth),
|
|
370
|
+
})
|
|
367
371
|
const box = await createBoxClient(
|
|
368
372
|
createCloudBoxProvider({
|
|
369
373
|
endpoint: reference.endpoint,
|
|
@@ -388,11 +392,6 @@ async function runCloudBoxConnect(args: string[]): Promise<number> {
|
|
|
388
392
|
}
|
|
389
393
|
console.log(` ...accessing shell\n`)
|
|
390
394
|
session = await box.connect()
|
|
391
|
-
// the same reason `create` heartbeats: the box holds no account credential,
|
|
392
|
-
// so the client using it is what keeps its session alive.
|
|
393
|
-
const sessionId = box.description.sessionId
|
|
394
|
-
if (!sessionId) throw new BoxClientError('the box service returned no session id')
|
|
395
|
-
heartbeat = heartbeatSession({ apiOrigin: origin, apiKey, sessionId })
|
|
396
395
|
return await repl(session, '')
|
|
397
396
|
} catch (error) {
|
|
398
397
|
if (error instanceof BoxClientError) {
|
|
@@ -401,7 +400,6 @@ async function runCloudBoxConnect(args: string[]): Promise<number> {
|
|
|
401
400
|
}
|
|
402
401
|
throw error
|
|
403
402
|
} finally {
|
|
404
|
-
heartbeat?.stop()
|
|
405
403
|
session?.close()
|
|
406
404
|
}
|
|
407
405
|
}
|
|
@@ -414,7 +412,7 @@ async function runCloudBoxConnect(args: string[]): Promise<number> {
|
|
|
414
412
|
* person sees is what the agent is working on, and two people opening the same
|
|
415
413
|
* box see the same screen.
|
|
416
414
|
*
|
|
417
|
-
* the url carries no credential: it is the box's page on
|
|
415
|
+
* the url carries no credential: it is the box's page on its account origin,
|
|
418
416
|
* and opening it signed in resolves the box through the account service. that
|
|
419
417
|
* makes it a link somebody can keep, paste, or reload.
|
|
420
418
|
*/
|
|
@@ -436,6 +434,7 @@ async function runCloudBoxOpen(args: string[]): Promise<number> {
|
|
|
436
434
|
apiOrigin: apiOrigin(args, auth),
|
|
437
435
|
apiKey,
|
|
438
436
|
boxId,
|
|
437
|
+
accountId: cloudAccountIdOrExit(auth),
|
|
439
438
|
})
|
|
440
439
|
const connectUrl = cloudBoxConnectUrl(reference.endpoint, reference.boxId)
|
|
441
440
|
// ensure first: it is what navigates the generation's tab to the Box page,
|
|
@@ -499,6 +498,7 @@ export async function openInBrowser(url: string): Promise<number> {
|
|
|
499
498
|
|
|
500
499
|
function cloudBoxClient(options: {
|
|
501
500
|
endpoint: string
|
|
501
|
+
fresh?: boolean
|
|
502
502
|
apiOrigin: string
|
|
503
503
|
apiKey: string
|
|
504
504
|
accountId: string | null
|
|
@@ -506,6 +506,7 @@ function cloudBoxClient(options: {
|
|
|
506
506
|
return createBoxClient(
|
|
507
507
|
createCloudBoxProvider({
|
|
508
508
|
endpoint: options.endpoint,
|
|
509
|
+
fresh: options.fresh,
|
|
509
510
|
authority: {
|
|
510
511
|
kind: 'account',
|
|
511
512
|
apiOrigin: options.apiOrigin,
|
|
@@ -525,10 +526,13 @@ function cloudBoxClient(options: {
|
|
|
525
526
|
* that bundle instead of building anything.
|
|
526
527
|
*/
|
|
527
528
|
export async function createPrebuiltBundleBox(options: {
|
|
529
|
+
fresh?: boolean
|
|
528
530
|
bundle: Uint8Array
|
|
529
531
|
nativeProjectDir?: string
|
|
530
532
|
// the simulator's device model, or null for the Box page's default
|
|
531
533
|
device: string | null
|
|
534
|
+
// the link the app launches with, as Linking.getInitialURL reports it
|
|
535
|
+
initialUrl?: string | null
|
|
532
536
|
name: string
|
|
533
537
|
endpoint: string
|
|
534
538
|
apiOrigin: string
|
|
@@ -550,6 +554,7 @@ export async function createPrebuiltBundleBox(options: {
|
|
|
550
554
|
source: new BundleFilePlane(
|
|
551
555
|
options.bundle,
|
|
552
556
|
options.device,
|
|
557
|
+
options.initialUrl ?? null,
|
|
553
558
|
options.nativeProjectDir
|
|
554
559
|
? readNativeLinkedAppFontsWire({
|
|
555
560
|
projectDir: options.nativeProjectDir,
|
|
@@ -711,7 +716,6 @@ async function runCloudBoxCreate(
|
|
|
711
716
|
accountId,
|
|
712
717
|
}
|
|
713
718
|
let session: BoxShellSession | null = null
|
|
714
|
-
let heartbeat: { stop: () => void } | null = null
|
|
715
719
|
try {
|
|
716
720
|
const box =
|
|
717
721
|
'bundle' in source
|
|
@@ -760,16 +764,6 @@ async function runCloudBoxCreate(
|
|
|
760
764
|
}
|
|
761
765
|
console.log(` ...accessing shell\n`)
|
|
762
766
|
session = await box.connect()
|
|
763
|
-
// bank the wall clock while the shell is open. the box holds no account
|
|
764
|
-
// credential, so the client that is using it is what keeps the session
|
|
765
|
-
// alive; when this process dies the sweep closes it at the last heartbeat.
|
|
766
|
-
const sessionId = box.description.sessionId
|
|
767
|
-
if (!sessionId) throw new BoxClientError('the box service returned no session id')
|
|
768
|
-
heartbeat = heartbeatSession({
|
|
769
|
-
apiOrigin: apiOrigin(args, auth),
|
|
770
|
-
apiKey,
|
|
771
|
-
sessionId,
|
|
772
|
-
})
|
|
773
767
|
return await repl(session, '')
|
|
774
768
|
} catch (error) {
|
|
775
769
|
if (error instanceof BoxClientError) {
|
|
@@ -778,7 +772,6 @@ async function runCloudBoxCreate(
|
|
|
778
772
|
}
|
|
779
773
|
throw error
|
|
780
774
|
} finally {
|
|
781
|
-
heartbeat?.stop()
|
|
782
775
|
session?.close()
|
|
783
776
|
}
|
|
784
777
|
}
|