peachsim 0.1.527 → 0.1.571
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 +28 -28
- package/cli/app-fonts.ts +1 -1
- package/cli/app-splash.ts +1 -1
- package/cli/bin.ts +1 -1
- package/cli/bridge-diagnostics.ts +1 -1
- package/cli/bridge-flow-runner.ts +72 -12
- package/cli/cloud-client.ts +273 -6
- package/cli/cloud-dispatch.ts +23 -2
- package/cli/cloud-session.ts +60 -4
- package/cli/cloud-test-result-files.ts +97 -0
- package/cli/cloud-test-tunnel.ts +354 -0
- package/cli/commands/box/bundle-plane.ts +2 -2
- package/cli/commands/box/checkout-plane.ts +1 -1
- package/cli/commands/box/rnx-command.ts +2 -2
- package/cli/commands/box/search-command.ts +2 -2
- package/cli/commands/box.ts +8 -8
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/control.ts +22 -3
- package/cli/commands/detox.ts +1 -1
- package/cli/commands/device.ts +1 -1
- package/cli/commands/diagnose.ts +1 -1
- package/cli/commands/film.ts +1 -1
- package/cli/commands/flow.ts +60 -3
- package/cli/commands/inspect/actions.ts +1 -1
- package/cli/commands/inspect/core.ts +6 -7
- package/cli/commands/inspect/find.ts +2 -1
- package/cli/commands/inspect/resolve-target.ts +5 -3
- package/cli/commands/inspect/shared.ts +1 -1
- package/cli/commands/inspect/wait-event.ts +1 -1
- package/cli/commands/inspect/wait-selector.ts +15 -4
- package/cli/commands/inspect.ts +19 -14
- package/cli/commands/maestro.ts +582 -69
- package/cli/commands/permissions.ts +1 -1
- package/cli/commands/platform.ts +205 -8
- package/cli/commands/preview.ts +2 -2
- package/cli/commands/record.ts +2 -2
- package/cli/commands/report-issue.ts +2 -2
- package/cli/commands/screenshot-layers.ts +1 -1
- package/cli/commands/screenshot.ts +1 -1
- package/cli/commands/setup.ts +2 -2
- package/cli/commands/test.ts +600 -117
- package/cli/commands/three-mode.ts +1 -1
- package/cli/commands/upload.ts +5 -5
- package/cli/commands/what-happened.ts +1 -1
- package/cli/desktop-companion.ts +3 -3
- package/cli/drivers/playwright-sim-host.ts +2 -2
- package/cli/flow-file.ts +7 -0
- package/cli/flow-live-status.ts +65 -8
- package/cli/help-core.ts +3 -3
- package/cli/hidden-runtime-alias.ts +1 -1
- package/cli/maestro-report.ts +180 -0
- package/cli/main.ts +1 -1
- package/cli/outbound-endpoints.ts +187 -136
- package/cli/parse-args.ts +1 -1
- package/cli/registry.ts +1 -1
- package/cli/resolve-assets.ts +1 -1
- package/cli/run-registry.ts +10 -1
- package/cli/send-to-box.ts +4 -4
- package/cli/ws-bridge.ts +3 -5
- package/detox/expectations.ts +1 -1
- package/detox/gestures.ts +2 -2
- package/detox/index.ts +71 -29
- package/detox/jest-preset.cjs +5 -5
- package/detox/jest-setup-after-env.cjs +1 -1
- package/dist-lib/agent-daemon-client.cjs +2 -2
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +2 -2
- package/dist-lib/attached-projects.cjs +2 -2
- package/dist-lib/auth/shared-session.cjs +1 -1
- 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/capture-contract.cjs +94 -3
- package/dist-lib/capture-contract.mjs +93 -3
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +116 -0
- package/dist-lib/cloud-test-args.mjs +86 -0
- package/dist-lib/cloud.cjs +2 -2
- package/dist-lib/cloud.mjs +2 -2
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +106 -25
- package/dist-lib/detox/jest-preset.cjs +5 -5
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +150 -65
- package/dist-lib/host/fetch-proxy-handler.cjs +28 -2
- package/dist-lib/host/fetch-proxy-overrides.cjs +33 -3
- package/dist-lib/host/fetch-proxy-overrides.mjs +30 -2
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +224 -41
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/menu.cjs +2 -2
- package/dist-lib/menu.mjs +2 -2
- 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 +3 -3
- package/dist-lib/metro-production-bundle.mjs +3 -3
- package/dist-lib/metro.cjs +8 -8
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +2 -2
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +31 -15
- package/dist-lib/sdk.cjs +3 -2
- package/dist-lib/sdk.mjs +3 -2
- package/dist-lib/skills.cjs +478 -266
- package/dist-lib/swift-compile.cjs +372 -0
- package/dist-lib/swift-compile.mjs +339 -0
- package/dist-lib/swift-package.cjs +78 -0
- package/dist-lib/swift-package.mjs +52 -0
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +583 -16
- package/dist-lib/vite.cjs +483 -150
- package/package.json +30 -9
- package/scripts/dev-server-scanner.ts +41 -14
- package/scripts/optional-demo-registry.ts +3 -3
- package/skills/contrast/SKILL.md +9 -9
- package/skills/rnx-debug/SKILL.md +14 -4
- package/skills/rnx-perf/SKILL.md +5 -5
- package/skills/rnx-setup/SKILL.md +11 -11
- package/skills/rnx-test/SKILL.md +14 -14
- package/skills/rnx-visual/SKILL.md +6 -6
- package/src/agent-sessions.ts +3 -3
- package/src/attached-projects.ts +1 -1
- package/src/bridge-contract-input.ts +1 -1
- package/src/bridge-contract.ts +23 -5
- package/src/capture-contract.ts +145 -3
- package/src/cloud-test-args.ts +100 -0
- package/src/config.ts +2 -2
- package/src/connect.ts +2 -2
- package/src/home-paths.ts +3 -3
- package/src/host/bridge-host.ts +2 -2
- package/src/host/fetch-proxy-handler.ts +4 -3
- package/src/host/fetch-proxy-overrides.ts +41 -0
- package/src/host/plane-host.ts +2 -2
- package/src/index.ts +3 -0
- package/src/metro-plugin.ts +4 -4
- package/src/metro-production-bundle.ts +2 -2
- package/src/native-seam-manifest.ts +6 -6
- package/src/public-brand.ts +1 -1
- package/src/rolldown-plugin-swift.ts +16 -12
- package/src/runtime-assets.ts +8 -6
- package/src/screenshots/frame-compose.ts +24 -56
- package/src/screenshots/org-deck.ts +1 -1
- package/src/screenshots/registry.ts +4 -4
- package/src/screenshots/schema.ts +1 -1
- package/src/sdk.ts +2 -2
- package/src/settings-bundle.ts +1 -1
- package/src/sim-client.ts +2 -4
- package/src/skills/builtin/compat-check.ts +1 -1
- package/src/swift-compile.ts +359 -0
- package/src/swift-package.ts +69 -0
- package/src/swift-submit.ts +3 -2
- package/src/vite-plugin-one.ts +1 -1
- package/src/vite-plugin-swift.ts +114 -113
- package/src/vite-plugin.ts +30 -17
- package/src/worklets-babel.ts +2 -2
package/cli/commands/platform.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// (this machine, a local box, or the `rnx remote` namespace). this file resolves
|
|
5
5
|
// the device and hands the rest to the normal open path.
|
|
6
6
|
|
|
7
|
+
import { createHash } from 'node:crypto'
|
|
7
8
|
import {
|
|
8
9
|
DEFAULT_DEVICE_BY_PLATFORM,
|
|
9
10
|
devices,
|
|
@@ -11,9 +12,10 @@ import {
|
|
|
11
12
|
listSelectableDeviceModels,
|
|
12
13
|
type DeviceModel,
|
|
13
14
|
type RuntimePlatform,
|
|
14
|
-
} from '
|
|
15
|
-
import { settingsStore } from '
|
|
15
|
+
} from 'peach-engine/settings'
|
|
16
|
+
import { settingsStore } from 'peach-engine/settings/store'
|
|
16
17
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
18
|
+
import { UnsupportedRemoteHostError } from '../cloud-client'
|
|
17
19
|
import { rethrowIfExit } from '../run-rnx'
|
|
18
20
|
import type { CloudSession } from '../cloud-session'
|
|
19
21
|
|
|
@@ -27,23 +29,28 @@ function isDeviceModel(value: string): value is DeviceModel {
|
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
// flags this command reads for itself rather than treating as the bundle.
|
|
30
|
-
const REMOTE_VALUE_FLAGS = new Set(['--device'])
|
|
32
|
+
const REMOTE_VALUE_FLAGS = new Set(['--device', '--name', '--endpoint'])
|
|
31
33
|
|
|
32
34
|
function remoteInputFromArgs(
|
|
33
35
|
args: string[],
|
|
34
36
|
platform: RuntimePlatform,
|
|
35
37
|
): {
|
|
36
38
|
bundlePath: string
|
|
39
|
+
name: string | null
|
|
37
40
|
reuse: boolean
|
|
38
41
|
fresh: boolean
|
|
39
42
|
} {
|
|
40
43
|
const positional: string[] = []
|
|
44
|
+
let name: string | null = null
|
|
41
45
|
for (let index = 0; index < args.length; index++) {
|
|
42
46
|
const arg = args[index]
|
|
43
|
-
if (arg === '--remote' || arg === '--reuse' || arg === '--new')
|
|
47
|
+
if (arg === '--remote' || arg === '--nano' || arg === '--reuse' || arg === '--new') {
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
44
50
|
if (REMOTE_VALUE_FLAGS.has(arg)) {
|
|
45
51
|
const value = args[++index] ?? null
|
|
46
52
|
if (!value) throw new Error(`rnx remote ${platform} ${arg} requires a value`)
|
|
53
|
+
if (arg === '--name') name = value
|
|
47
54
|
continue
|
|
48
55
|
}
|
|
49
56
|
const assigned = arg.match(/^(--[a-z-]+)=(.*)$/)
|
|
@@ -51,6 +58,7 @@ function remoteInputFromArgs(
|
|
|
51
58
|
const value = assigned[2] ?? ''
|
|
52
59
|
if (!value)
|
|
53
60
|
throw new Error(`rnx remote ${platform} ${assigned[1]} requires a value`)
|
|
61
|
+
if (assigned[1] === '--name') name = value
|
|
54
62
|
continue
|
|
55
63
|
}
|
|
56
64
|
if (
|
|
@@ -80,7 +88,25 @@ function remoteInputFromArgs(
|
|
|
80
88
|
if (reuse && fresh) {
|
|
81
89
|
throw new Error(`rnx remote ${platform} cannot combine --reuse and --new`)
|
|
82
90
|
}
|
|
83
|
-
return { bundlePath: positional[0], reuse, fresh }
|
|
91
|
+
return { bundlePath: positional[0], name, reuse, fresh }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* the box's name, taken from what was built.
|
|
96
|
+
*
|
|
97
|
+
* a bundle arrives as a file or a URL and neither carries a name, so the last
|
|
98
|
+
* path segment without its extension is the one thing both have. box names are
|
|
99
|
+
* lowercase words joined by dashes, so anything else in it becomes a dash.
|
|
100
|
+
*/
|
|
101
|
+
function boxNameForBundle(bundlePath: string): string {
|
|
102
|
+
const segment = bundlePath.split(/[?#]/)[0]?.split('/').filter(Boolean).at(-1) ?? ''
|
|
103
|
+
const stem = segment.replace(/\.[^.]+$/, '')
|
|
104
|
+
const name = stem
|
|
105
|
+
.toLowerCase()
|
|
106
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
107
|
+
.replace(/^-+|-+$/g, '')
|
|
108
|
+
if (!name) throw new Error(`rnx remote could not name a box after ${bundlePath}`)
|
|
109
|
+
return name
|
|
84
110
|
}
|
|
85
111
|
|
|
86
112
|
export async function runPlatformCommand(
|
|
@@ -129,7 +155,15 @@ export async function runPlatformCommand(
|
|
|
129
155
|
}
|
|
130
156
|
|
|
131
157
|
if (args.includes('--remote')) {
|
|
158
|
+
if (platform === 'android' && args.includes('--nano')) {
|
|
159
|
+
const error = new UnsupportedRemoteHostError('android', 'nano')
|
|
160
|
+
console.error(` ${error.message}`)
|
|
161
|
+
return 1
|
|
162
|
+
}
|
|
132
163
|
try {
|
|
164
|
+
if (!args.includes('--nano')) {
|
|
165
|
+
return await runRemoteBox(platform, args, selectedDevice)
|
|
166
|
+
}
|
|
133
167
|
return await runRemoteCreate(platform, args, selectedDevice)
|
|
134
168
|
} catch (error) {
|
|
135
169
|
rethrowIfExit(error)
|
|
@@ -185,6 +219,11 @@ export function runRemotePlatformCommand(
|
|
|
185
219
|
args: string[],
|
|
186
220
|
opts: { port?: number } = {},
|
|
187
221
|
): Promise<number | undefined> {
|
|
222
|
+
if (platform === 'android' && args.includes('--nano')) {
|
|
223
|
+
const error = new UnsupportedRemoteHostError('android', 'nano')
|
|
224
|
+
console.error(` ${error.message}`)
|
|
225
|
+
return Promise.resolve(1)
|
|
226
|
+
}
|
|
188
227
|
return runPlatformCommand(platform, ['--remote', ...args], opts)
|
|
189
228
|
}
|
|
190
229
|
|
|
@@ -207,6 +246,7 @@ async function runRemoteCreate(
|
|
|
207
246
|
{ authHeaderOrExit, cloudAccountIdOrExit },
|
|
208
247
|
{
|
|
209
248
|
claimCloudSimulator,
|
|
249
|
+
closeCloudBox,
|
|
210
250
|
closeCloudSession,
|
|
211
251
|
createRemoteSim,
|
|
212
252
|
getRemoteSim,
|
|
@@ -232,7 +272,7 @@ async function runRemoteCreate(
|
|
|
232
272
|
|
|
233
273
|
const existingSession = readCloudSession()
|
|
234
274
|
if (
|
|
235
|
-
existingSession &&
|
|
275
|
+
existingSession?.service === 'sim' &&
|
|
236
276
|
!input.fresh &&
|
|
237
277
|
existingSession.platform === platform &&
|
|
238
278
|
existingSession.artifact?.sha256 === artifact.sha256
|
|
@@ -265,7 +305,8 @@ async function runRemoteCreate(
|
|
|
265
305
|
|
|
266
306
|
// the new session supersedes the old one, so the shell update channel
|
|
267
307
|
// carries exactly one update: the shell accepts nothing else.
|
|
268
|
-
if (existingSession) await
|
|
308
|
+
if (existingSession?.service === 'box') await closeCloudBox(existingSession)
|
|
309
|
+
else if (existingSession) await closeCloudSession(existingSession)
|
|
269
310
|
const created = await createRemoteSim({
|
|
270
311
|
bundlePath: input.bundlePath,
|
|
271
312
|
device: selectedDevice,
|
|
@@ -310,6 +351,159 @@ async function runRemoteCreate(
|
|
|
310
351
|
return openInBrowser(created.session.streamUrl)
|
|
311
352
|
}
|
|
312
353
|
|
|
354
|
+
/**
|
|
355
|
+
* `rnx ios --remote` and `rnx android --remote` — the app runs in a micro box.
|
|
356
|
+
*
|
|
357
|
+
* the bundle is prepared by the box plane's own producer, the one `rnx box
|
|
358
|
+
* create --bundle` uses: assets embedded, nothing minified and no module
|
|
359
|
+
* identity rewritten. the nano producer's artifact is built for the nano
|
|
360
|
+
* runner, which imports it as a module; a box page evaluates the bytes with
|
|
361
|
+
* `(0, eval)` as Script in global scope, and a minified artifact reaches it
|
|
362
|
+
* with no react instance for the reconciler to bind to. there is no size cap
|
|
363
|
+
* either way: the box holds the bundle in parts, so the single-message ceiling
|
|
364
|
+
* a nano upload answers to does not apply.
|
|
365
|
+
*
|
|
366
|
+
* a box created from the already-built app boots it in its own page, and this
|
|
367
|
+
* opens the bare shell watch url minted from the box's display grant — the same
|
|
368
|
+
* /sootsim/#remoteEngine fragment the nano service mints, pointed at the box.
|
|
369
|
+
*/
|
|
370
|
+
async function runRemoteBox(
|
|
371
|
+
platform: RuntimePlatform,
|
|
372
|
+
args: string[],
|
|
373
|
+
selectedDevice: string,
|
|
374
|
+
): Promise<number> {
|
|
375
|
+
const command = `${platform} --remote`
|
|
376
|
+
const input = remoteInputFromArgs(args, platform)
|
|
377
|
+
const [
|
|
378
|
+
{ closeCloudBox, closeCloudSession, produceCloudBoxArtifact, requestBoxWatchUrl },
|
|
379
|
+
box,
|
|
380
|
+
{ cloudBoxConnectUrl, ensureCloudBoxBrowser, readCloudBoxSession },
|
|
381
|
+
{ authHeaderOrExit, cloudAccountIdOrExit },
|
|
382
|
+
{
|
|
383
|
+
createCloudBoxSession,
|
|
384
|
+
publishCloudSessionToShell,
|
|
385
|
+
readCloudSession,
|
|
386
|
+
serializeCloudSession,
|
|
387
|
+
RNX_CLOUD_SESSION_ENV,
|
|
388
|
+
},
|
|
389
|
+
] = await Promise.all([
|
|
390
|
+
import('../cloud-client'),
|
|
391
|
+
import('./box'),
|
|
392
|
+
import('peach-cloud-box/client'),
|
|
393
|
+
import('../auth'),
|
|
394
|
+
import('../cloud-session'),
|
|
395
|
+
])
|
|
396
|
+
const { openInBrowser } = box
|
|
397
|
+
const artifact = await produceCloudBoxArtifact(input.bundlePath)
|
|
398
|
+
// the session records which bundle a box already holds, so reattaching can
|
|
399
|
+
// tell the same app from a rebuilt one. the box producer returns no digest
|
|
400
|
+
// of its own, so take it here over the bytes that actually crossed.
|
|
401
|
+
const artifactSha256 = createHash('sha256').update(artifact.bytes).digest('hex')
|
|
402
|
+
const endpoint = box.cloudBoxEndpoint(args, command)
|
|
403
|
+
if (!endpoint) return 1
|
|
404
|
+
|
|
405
|
+
const existingSession = readCloudSession()
|
|
406
|
+
if (
|
|
407
|
+
existingSession?.service === 'box' &&
|
|
408
|
+
!input.fresh &&
|
|
409
|
+
existingSession.apiOrigin === endpoint &&
|
|
410
|
+
existingSession.platform === platform &&
|
|
411
|
+
existingSession.device === selectedDevice &&
|
|
412
|
+
existingSession.artifact?.sha256 === artifactSha256
|
|
413
|
+
) {
|
|
414
|
+
const live = await readCloudBoxSession({
|
|
415
|
+
endpoint: existingSession.apiOrigin,
|
|
416
|
+
boxId: existingSession.boxId,
|
|
417
|
+
accessToken: existingSession.boxToken,
|
|
418
|
+
})
|
|
419
|
+
if (live.sessionId) {
|
|
420
|
+
// the simulator lives in the box's Browser Run tab, which lapses on its
|
|
421
|
+
// own, so a reconnect restores it before promising commands will answer.
|
|
422
|
+
await ensureCloudBoxBrowser({
|
|
423
|
+
connectUrl: cloudBoxConnectUrl(existingSession.apiOrigin, existingSession.boxId),
|
|
424
|
+
accessToken: existingSession.boxToken,
|
|
425
|
+
})
|
|
426
|
+
// grants are short-lived, so a reconnect mints a fresh one rather than
|
|
427
|
+
// reopening whatever url the create printed.
|
|
428
|
+
const watchUrl = await requestBoxWatchUrl({
|
|
429
|
+
apiOrigin: existingSession.apiOrigin,
|
|
430
|
+
boxId: existingSession.boxId,
|
|
431
|
+
boxToken: existingSession.boxToken,
|
|
432
|
+
})
|
|
433
|
+
console.log(
|
|
434
|
+
` reconnected to remote simulator: ${existingSession.boxId} (${platform})`,
|
|
435
|
+
)
|
|
436
|
+
console.log(` open ${watchUrl}`)
|
|
437
|
+
console.log(REMOTE_COMMANDS_HELP)
|
|
438
|
+
return openInBrowser(watchUrl)
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const { auth, header } = authHeaderOrExit(command)
|
|
443
|
+
const accountId = cloudAccountIdOrExit(auth)
|
|
444
|
+
|
|
445
|
+
if (existingSession?.service === 'box') {
|
|
446
|
+
await closeCloudBox(existingSession)
|
|
447
|
+
try {
|
|
448
|
+
publishCloudSessionToShell(null)
|
|
449
|
+
} catch {
|
|
450
|
+
// no shell update channel is required outside an interactive rnx shell
|
|
451
|
+
}
|
|
452
|
+
} else if (existingSession) {
|
|
453
|
+
await closeCloudSession(existingSession)
|
|
454
|
+
}
|
|
455
|
+
const created = await box.createPrebuiltBundleBox({
|
|
456
|
+
bundle: new Uint8Array(artifact.bytes),
|
|
457
|
+
name: input.name ?? boxNameForBundle(input.bundlePath),
|
|
458
|
+
endpoint,
|
|
459
|
+
apiOrigin: box.cloudBoxApiOrigin(args, auth),
|
|
460
|
+
apiKey: header.replace(/^Bearer /, ''),
|
|
461
|
+
accountId,
|
|
462
|
+
})
|
|
463
|
+
// creating a box starts no browser, and only its Browser Run tab hosts the
|
|
464
|
+
// simulator, so without this the viewer opens onto a box nobody is running.
|
|
465
|
+
await ensureCloudBoxBrowser({
|
|
466
|
+
connectUrl: cloudBoxConnectUrl(endpoint, created.id),
|
|
467
|
+
accessToken: created.accessToken ?? '',
|
|
468
|
+
})
|
|
469
|
+
const session = createCloudBoxSession({
|
|
470
|
+
boxId: created.id,
|
|
471
|
+
boxToken: created.accessToken ?? '',
|
|
472
|
+
apiOrigin: endpoint,
|
|
473
|
+
platform,
|
|
474
|
+
device: selectedDevice,
|
|
475
|
+
artifact: {
|
|
476
|
+
sha256: artifactSha256,
|
|
477
|
+
bytes: artifact.bytes.length,
|
|
478
|
+
},
|
|
479
|
+
})
|
|
480
|
+
try {
|
|
481
|
+
publishCloudSessionToShell(session)
|
|
482
|
+
} catch {
|
|
483
|
+
// shell update fd not configured
|
|
484
|
+
}
|
|
485
|
+
process.env[RNX_CLOUD_SESSION_ENV] = serializeCloudSession(session)
|
|
486
|
+
|
|
487
|
+
console.log(` box: ${created.id} (${artifact.bytes.length} bytes)`)
|
|
488
|
+
console.log(` platform: ${platform}`)
|
|
489
|
+
if (selectedDevice) console.log(` device: ${selectedDevice}`)
|
|
490
|
+
console.log(` artifact: sha256:${artifactSha256}`)
|
|
491
|
+
// the dest directory was chosen by resolving this bundle's descriptors
|
|
492
|
+
// against it, so say which one won rather than leaving it invisible.
|
|
493
|
+
if (artifact.assetsDirectory) console.log(` asset dest: ${artifact.assetsDirectory}`)
|
|
494
|
+
for (const warning of artifact.warnings) console.warn(` warning: ${warning}`)
|
|
495
|
+
console.log(REMOTE_COMMANDS_HELP)
|
|
496
|
+
// the session is published before the grant is minted, so a grant that never
|
|
497
|
+
// arrives still leaves the box addressable: re-running this command mints it.
|
|
498
|
+
const watchUrl = await requestBoxWatchUrl({
|
|
499
|
+
apiOrigin: endpoint,
|
|
500
|
+
boxId: created.id,
|
|
501
|
+
boxToken: created.accessToken ?? '',
|
|
502
|
+
})
|
|
503
|
+
console.log(` open ${watchUrl}`)
|
|
504
|
+
return openInBrowser(watchUrl)
|
|
505
|
+
}
|
|
506
|
+
|
|
313
507
|
/** `rnx remote list`: the simulators this account runs that `rnx remote` made. */
|
|
314
508
|
export async function runRemoteList(args: string[]): Promise<number> {
|
|
315
509
|
try {
|
|
@@ -381,7 +575,10 @@ export async function runRemoteStop(args: string[]): Promise<number> {
|
|
|
381
575
|
}
|
|
382
576
|
// stopping the shell's own simulator clears the shell with it, so the
|
|
383
577
|
// update channel is required before anything is deleted.
|
|
384
|
-
const descriptor =
|
|
578
|
+
const descriptor =
|
|
579
|
+
current?.service === 'sim' && current.simId === simId
|
|
580
|
+
? requireCloudSessionShellUpdate()
|
|
581
|
+
: null
|
|
385
582
|
const { auth, header } = authHeaderOrExit('remote stop')
|
|
386
583
|
const accountId = cloudAccountIdOrExit(auth)
|
|
387
584
|
const deleted = await deleteRemoteSim({
|
package/cli/commands/preview.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto'
|
|
2
|
-
import { brotliBundle } from '
|
|
2
|
+
import { brotliBundle } from 'peach-engine/preview/compress-node'
|
|
3
3
|
import {
|
|
4
4
|
runPresignedUpload,
|
|
5
5
|
type InitRequestBody,
|
|
6
|
-
} from '
|
|
6
|
+
} from 'peach-engine/preview/presigned-upload'
|
|
7
7
|
import { authHeaderValue, cloudAccountIdOrExit, resolveCliAuth } from '../auth'
|
|
8
8
|
import { producePreviewArtifact } from '../cloud-client'
|
|
9
9
|
import { openUrl } from '../open-url'
|
package/cli/commands/record.ts
CHANGED
|
@@ -37,7 +37,7 @@ type OutputFormat = 'webm' | 'mp4' | 'gif' | 'png'
|
|
|
37
37
|
// recorder bridge (current CLI default). 'live' and 'combined' route
|
|
38
38
|
// through the recording store so they capture pointer events (and, for
|
|
39
39
|
// combined, video) and upload to /preview/<id>. mirrors RecordingMode in
|
|
40
|
-
// packages/
|
|
40
|
+
// packages/peach-engine/src/recording/recordingStore.ts.
|
|
41
41
|
type RecordMode = 'video' | 'live' | 'combined'
|
|
42
42
|
|
|
43
43
|
// how long to wait for the live/combined upload to settle after stop. dev
|
|
@@ -180,7 +180,7 @@ function readRepoScope(args: string[]): RepoScope {
|
|
|
180
180
|
|
|
181
181
|
export async function runRecord(args: string[], opts: RecordOptions) {
|
|
182
182
|
// note: `--help` / `-h` never reach here — bin.ts intercepts them and
|
|
183
|
-
// renders the registry-driven help page (packages/
|
|
183
|
+
// renders the registry-driven help page (packages/peach-skills meta.ts).
|
|
184
184
|
|
|
185
185
|
const sub = findRecordSubcommand(args)
|
|
186
186
|
if (sub) {
|
|
@@ -6,7 +6,7 @@ import { getCliVersion } from '../../src/cli-version'
|
|
|
6
6
|
import { readActiveRuntime } from '../../src/home-paths'
|
|
7
7
|
import { authHeaderValue, resolveCliAuth } from '../auth'
|
|
8
8
|
import { confirm } from '../prompt'
|
|
9
|
-
import type { ScanResult } from '@
|
|
9
|
+
import type { ScanResult } from '@peach/compat/web'
|
|
10
10
|
|
|
11
11
|
const DEFAULT_REPORT_ORIGIN = 'https://contrast.dev'
|
|
12
12
|
const MAX_DESCRIPTION_LENGTH = 8_000
|
|
@@ -154,7 +154,7 @@ export async function createReportIssuePayload(
|
|
|
154
154
|
): Promise<ReportIssuePayload> {
|
|
155
155
|
const manifest = readManifest(options.appDir)
|
|
156
156
|
const compatibility = manifest
|
|
157
|
-
? (await import('@
|
|
157
|
+
? (await import('@peach/compat/web')).scanDeps(manifest)
|
|
158
158
|
: null
|
|
159
159
|
const cliVersion = getCliVersion()
|
|
160
160
|
const runtimeVersion = readActiveRuntime()
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { mkdirSync, writeFileSync } from 'fs'
|
|
11
11
|
import { resolve } from 'path'
|
|
12
|
-
import { devices } from '
|
|
12
|
+
import { devices } from 'peach-engine/settings'
|
|
13
13
|
import { buildResolveRectEval, type SampleRect } from '../browser-evals'
|
|
14
14
|
import { rnxExit } from '../run-rnx'
|
|
15
15
|
import { callInBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { mkdirSync, writeFileSync } from 'fs'
|
|
10
10
|
import { dirname, resolve } from 'path'
|
|
11
|
-
import { devices, type DeviceModel } from '
|
|
11
|
+
import { devices, type DeviceModel } from 'peach-engine/settings'
|
|
12
12
|
import { launchReapedChrome } from '../../../../scripts/lib/reap-browser'
|
|
13
13
|
import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
|
|
14
14
|
import { composeFramedScreenshot } from '../../src/screenshots/frame-compose'
|
package/cli/commands/setup.ts
CHANGED
|
@@ -361,7 +361,7 @@ async function decideRepository(
|
|
|
361
361
|
if (options.yes || options.ci || !process.stdin.isTTY) return false
|
|
362
362
|
printPromptBlock('Share rnx with your team', [
|
|
363
363
|
'rnx already works here with no project setup.',
|
|
364
|
-
'This only adds an exact
|
|
364
|
+
'This only adds an exact peachsim dev dependency and an rnx script for teammates.',
|
|
365
365
|
])
|
|
366
366
|
return confirm(`Add rnx to ${path.basename(plan.appDir)}?`, false)
|
|
367
367
|
}
|
|
@@ -392,7 +392,7 @@ rnx setup - configure optional local conveniences
|
|
|
392
392
|
|
|
393
393
|
rnx works without project setup. This command can enable the faster background
|
|
394
394
|
service, choose Browser or Desktop, configure private diagnostics, and optionally
|
|
395
|
-
add an exact
|
|
395
|
+
add an exact peachsim dependency plus an rnx script for teammates.
|
|
396
396
|
|
|
397
397
|
usage:
|
|
398
398
|
rnx setup
|