peachsim 0.1.1594 → 0.1.1620
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 +34 -11
- package/cli/app-catalog.ts +7 -5
- package/cli/app-config.ts +6 -2
- package/cli/app-fonts.ts +74 -35
- package/cli/app-stubs.ts +173 -42
- package/cli/bin.ts +9 -0
- package/cli/bridge-flow-runner.ts +226 -145
- package/cli/cloud-client.ts +52 -29
- package/cli/commands/agent-indicator-mode.ts +39 -0
- package/cli/commands/box.ts +13 -3
- package/cli/commands/control.ts +132 -108
- package/cli/commands/daemon.ts +99 -24
- package/cli/commands/debug.ts +29 -1
- package/cli/commands/detect.ts +1 -1
- package/cli/commands/device.ts +6 -8
- package/cli/commands/diagnose.ts +2 -0
- package/cli/commands/doctor.ts +97 -34
- package/cli/commands/flow.ts +22 -12
- package/cli/commands/inspect/actions.ts +2 -0
- package/cli/commands/inspect/core.ts +106 -40
- package/cli/commands/inspect/list.ts +9 -3
- package/cli/commands/inspect/memory.ts +9 -0
- package/cli/commands/inspect/settling.ts +167 -49
- 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 +19 -4
- package/cli/commands/kotlin.ts +5 -7
- package/cli/commands/maestro-compare.ts +25 -2
- package/cli/commands/mode.ts +13 -1
- package/cli/commands/perf-record.ts +296 -0
- package/cli/commands/perf.ts +6 -1
- package/cli/commands/platform.ts +34 -11
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/record.ts +48 -20
- package/cli/commands/runtime.ts +9 -11
- package/cli/commands/screenshots.ts +4 -3
- package/cli/commands/setup.ts +17 -5
- package/cli/commands/skills.ts +16 -43
- package/cli/commands/swift.ts +18 -3
- package/cli/commands/upgrade.ts +7 -6
- package/cli/commands/upload.ts +27 -51
- package/cli/commands/window.ts +449 -0
- package/cli/desktop-companion.ts +84 -10
- package/cli/drivers/desktop.ts +2 -0
- package/cli/drivers/playwright-sim-host.ts +12 -1
- package/cli/flow-file.ts +1 -0
- package/cli/maestro-compare.ts +19 -3
- package/cli/main.ts +22 -1
- package/cli/material-symbol-fonts.ts +171 -0
- package/cli/outbound-endpoints.ts +32 -16
- package/cli/preview-capture.ts +2 -2
- package/cli/run-registry.ts +5 -2
- package/cli/telemetry.ts +6 -3
- package/cli/ws-bridge.ts +15 -19
- package/detox/attempt-events.cjs +63 -7
- package/detox/attempt-events.d.cts +7 -0
- package/detox/gestures.ts +115 -2
- package/detox/index.ts +313 -411
- 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 +9 -1
- 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 +1 -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 +4005 -1362
- 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 +2 -2
- package/dist-lib/cloud.mjs +2 -2
- package/dist-lib/config.cjs +26 -7
- package/dist-lib/config.mjs +26 -7
- package/dist-lib/detox/index.cjs +1908 -539
- 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 +3617 -1016
- package/dist-lib/expo-swift-metadata.cjs +1 -1
- package/dist-lib/expo-swift-metadata.mjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +4760 -1825
- package/dist-lib/host/fetch-proxy-handler.cjs +59 -9
- package/dist-lib/host/fetch-proxy-overrides.cjs +62 -2
- package/dist-lib/host/fetch-proxy-overrides.mjs +56 -2
- package/dist-lib/host/replacement-module-handler.cjs +8 -8
- package/dist-lib/host/websocket-proxy.cjs +22 -6
- package/dist-lib/index.cjs +610 -184
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +33 -4
- package/dist-lib/kotlin-host.cjs +262 -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 +101 -7
- package/dist-lib/metro-production-bundle.mjs +106 -7
- package/dist-lib/metro.cjs +315 -87
- package/dist-lib/native-app-identity-project.cjs +101 -26
- package/dist-lib/native-app-identity-project.mjs +101 -26
- package/dist-lib/native-app-identity.cjs +33 -7
- package/dist-lib/native-app-identity.mjs +33 -7
- 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 +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +30 -9
- package/dist-lib/sdk.cjs +236 -78
- package/dist-lib/sdk.mjs +236 -78
- package/dist-lib/skills.cjs +6788 -2636
- package/dist-lib/swift-compile.cjs +1637 -299
- package/dist-lib/swift-compile.mjs +1558 -219
- package/dist-lib/swift-package.cjs +25 -3
- package/dist-lib/swift-package.mjs +22 -2
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +3675 -1051
- package/dist-lib/vite.cjs +142 -20
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/install.sh +1 -1
- 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 +27 -20
- 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/package.json +1 -1
- package/scripts/dev-server-scanner.ts +30 -40
- package/skills/contrast/SKILL.md +1 -1
- package/skills/peach-perf/SKILL.md +25 -0
- package/skills/peach-setup/SKILL.md +25 -1
- package/src/assetCatalogContract.ts +31 -3
- package/src/auth/shared-session.ts +3 -2
- package/src/bridge-contract.ts +5 -0
- package/src/bundle-channel.mjs +1 -1
- package/src/cloud-contract.ts +11 -0
- package/src/cloud.ts +2 -2
- package/src/config.ts +16 -8
- 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 +52 -54
- package/src/host/fetch-proxy-handler.ts +94 -31
- package/src/host/fetch-proxy-overrides.ts +91 -0
- package/src/host/replacement-module-handler.ts +11 -10
- package/src/host/server-scan-handler.ts +1 -1
- package/src/host/staged-host-files.ts +92 -0
- package/src/host/websocket-proxy.ts +27 -6
- package/src/installed-package-versions.ts +1 -0
- package/src/jump-to-source-native.ts +3 -3
- package/src/kotlin-host.ts +143 -26
- package/src/kotlin-module.ts +52 -0
- package/src/metro-layout-parser.ts +78 -0
- package/src/metro-production-bundle.ts +59 -10
- package/src/native-app-identity-project.ts +67 -3
- package/src/native-app-identity.ts +48 -0
- package/src/native-firebase-config.ts +3 -2
- package/src/native-seam-manifest.ts +0 -44
- package/src/nativeAppIconContract.ts +11 -6
- package/src/nativeViewSourceContract.ts +49 -0
- package/src/nativeViewWebContract.ts +41 -0
- package/src/nitro-source.ts +3 -7
- package/src/one-widget-metadata.ts +23 -3
- package/src/oneWidgetContract.ts +22 -0
- package/src/process-group.ts +306 -0
- package/src/process-liveness.ts +24 -0
- package/src/process-output.ts +21 -2
- package/src/serverDiscoveryContract.ts +41 -0
- package/src/swift-compile.ts +1063 -265
- package/src/swift-design-time.ts +552 -0
- package/src/swift-distribution.lock.json +12 -11
- package/src/swift-host.ts +133 -25
- 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/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 +58 -16
- package/src/vite-plugin-swift.ts +1 -0
- package/src/vite-plugin.ts +105 -41
- package/src/worker-system-chunks.ts +86 -9
- package/src/worklets-babel.ts +85 -13
- package/src/xcode-project.ts +40 -15
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
|
|
@@ -1602,9 +1603,11 @@ export function createCloudBridgeForParsed(
|
|
|
1602
1603
|
: new CloudBridge(session)
|
|
1603
1604
|
}
|
|
1604
1605
|
|
|
1605
|
-
//
|
|
1606
|
-
//
|
|
1607
|
-
//
|
|
1606
|
+
// deletes the box, which ends the simulator it holds. a cloud session box is
|
|
1607
|
+
// the prebuilt bundle `peach ios --remote` created, so it holds nothing but that
|
|
1608
|
+
// bundle: stopping it would only keep its name taken and its storage held. an
|
|
1609
|
+
// account api key deletes with its own authority; a session login deletes with
|
|
1610
|
+
// the login, falling back to the box token the session already holds.
|
|
1608
1611
|
export async function closeCloudBox(session: CloudSession): Promise<void> {
|
|
1609
1612
|
if (session.service !== 'box') {
|
|
1610
1613
|
if (!session.boxId || !session.boxToken) return
|
|
@@ -1631,7 +1634,7 @@ export async function closeCloudBox(session: CloudSession): Promise<void> {
|
|
|
1631
1634
|
let response: Response
|
|
1632
1635
|
try {
|
|
1633
1636
|
response = await fetch(
|
|
1634
|
-
`${session.apiOrigin}/v1/boxes/${encodeURIComponent(session.boxId)}/
|
|
1637
|
+
`${session.apiOrigin}/v1/boxes/${encodeURIComponent(session.boxId)}/delete`,
|
|
1635
1638
|
{
|
|
1636
1639
|
method: 'POST',
|
|
1637
1640
|
headers: { authorization: authHeader },
|
|
@@ -1650,6 +1653,15 @@ export async function closeCloudBox(session: CloudSession): Promise<void> {
|
|
|
1650
1653
|
}
|
|
1651
1654
|
}
|
|
1652
1655
|
|
|
1656
|
+
// the box's page reported that the app threw while booting, so no simulator is
|
|
1657
|
+
// coming and the box should end rather than bill.
|
|
1658
|
+
export class BoxBootFailedError extends Error {
|
|
1659
|
+
constructor(boxId: string, detail: string) {
|
|
1660
|
+
super(`box ${boxId} could not boot the app: ${detail}`)
|
|
1661
|
+
this.name = 'BoxBootFailedError'
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1653
1665
|
export interface BoxDisplayGrant {
|
|
1654
1666
|
url: string
|
|
1655
1667
|
authToken: string
|
|
@@ -1710,6 +1722,17 @@ export async function requestBoxWatchUrl(options: {
|
|
|
1710
1722
|
}`,
|
|
1711
1723
|
)
|
|
1712
1724
|
}
|
|
1725
|
+
if (response.status === 422) {
|
|
1726
|
+
const text = await response.text()
|
|
1727
|
+
let failure: unknown = null
|
|
1728
|
+
try {
|
|
1729
|
+
failure = JSON.parse(text)
|
|
1730
|
+
} catch {}
|
|
1731
|
+
if (isRecord(failure) && failure.code === 'boot-failed') {
|
|
1732
|
+
throw new BoxBootFailedError(options.boxId, String(failure.error))
|
|
1733
|
+
}
|
|
1734
|
+
throw responseError(response.status, text)
|
|
1735
|
+
}
|
|
1713
1736
|
if (response.status === 409) {
|
|
1714
1737
|
// the page has not attached its simulator yet. this is the normal state
|
|
1715
1738
|
// right after a create, so wait rather than refusing.
|
|
@@ -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
|
+
}
|
package/cli/commands/box.ts
CHANGED
|
@@ -124,7 +124,7 @@ function apiOrigin(args: string[], auth: CliAuth): string {
|
|
|
124
124
|
return (
|
|
125
125
|
flag(args, 'api-origin') ??
|
|
126
126
|
process.env[API_ORIGIN_ENV]?.trim() ??
|
|
127
|
-
(auth.kind === 'session' ? auth.origin :
|
|
127
|
+
(auth.kind === 'session' ? auth.origin : rnxPublicBrand.origin)
|
|
128
128
|
).replace(/\/+$/, '')
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -186,6 +186,7 @@ async function runCloudBoxUse(args: string[]): Promise<number> {
|
|
|
186
186
|
apiOrigin: apiOrigin(args, auth),
|
|
187
187
|
apiKey,
|
|
188
188
|
boxId: named,
|
|
189
|
+
accountId: cloudAccountIdOrExit(auth),
|
|
189
190
|
})
|
|
190
191
|
// attach for the Box's own name: the caller may have typed either an id or
|
|
191
192
|
// a name, and the default has to be able to print the one a person reads.
|
|
@@ -361,7 +362,12 @@ async function runCloudBoxConnect(args: string[]): Promise<number> {
|
|
|
361
362
|
|
|
362
363
|
let session: BoxShellSession | null = null
|
|
363
364
|
try {
|
|
364
|
-
const reference = await resolveCloudBoxReference({
|
|
365
|
+
const reference = await resolveCloudBoxReference({
|
|
366
|
+
apiOrigin: origin,
|
|
367
|
+
apiKey,
|
|
368
|
+
boxId,
|
|
369
|
+
accountId: cloudAccountIdOrExit(auth),
|
|
370
|
+
})
|
|
365
371
|
const box = await createBoxClient(
|
|
366
372
|
createCloudBoxProvider({
|
|
367
373
|
endpoint: reference.endpoint,
|
|
@@ -406,7 +412,7 @@ async function runCloudBoxConnect(args: string[]): Promise<number> {
|
|
|
406
412
|
* person sees is what the agent is working on, and two people opening the same
|
|
407
413
|
* box see the same screen.
|
|
408
414
|
*
|
|
409
|
-
* 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,
|
|
410
416
|
* and opening it signed in resolves the box through the account service. that
|
|
411
417
|
* makes it a link somebody can keep, paste, or reload.
|
|
412
418
|
*/
|
|
@@ -428,6 +434,7 @@ async function runCloudBoxOpen(args: string[]): Promise<number> {
|
|
|
428
434
|
apiOrigin: apiOrigin(args, auth),
|
|
429
435
|
apiKey,
|
|
430
436
|
boxId,
|
|
437
|
+
accountId: cloudAccountIdOrExit(auth),
|
|
431
438
|
})
|
|
432
439
|
const connectUrl = cloudBoxConnectUrl(reference.endpoint, reference.boxId)
|
|
433
440
|
// ensure first: it is what navigates the generation's tab to the Box page,
|
|
@@ -491,6 +498,7 @@ export async function openInBrowser(url: string): Promise<number> {
|
|
|
491
498
|
|
|
492
499
|
function cloudBoxClient(options: {
|
|
493
500
|
endpoint: string
|
|
501
|
+
fresh?: boolean
|
|
494
502
|
apiOrigin: string
|
|
495
503
|
apiKey: string
|
|
496
504
|
accountId: string | null
|
|
@@ -498,6 +506,7 @@ function cloudBoxClient(options: {
|
|
|
498
506
|
return createBoxClient(
|
|
499
507
|
createCloudBoxProvider({
|
|
500
508
|
endpoint: options.endpoint,
|
|
509
|
+
fresh: options.fresh,
|
|
501
510
|
authority: {
|
|
502
511
|
kind: 'account',
|
|
503
512
|
apiOrigin: options.apiOrigin,
|
|
@@ -517,6 +526,7 @@ function cloudBoxClient(options: {
|
|
|
517
526
|
* that bundle instead of building anything.
|
|
518
527
|
*/
|
|
519
528
|
export async function createPrebuiltBundleBox(options: {
|
|
529
|
+
fresh?: boolean
|
|
520
530
|
bundle: Uint8Array
|
|
521
531
|
nativeProjectDir?: string
|
|
522
532
|
// the simulator's device model, or null for the Box page's default
|