peachsim 0.1.527
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/LICENSE +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { runCpuProfile } from './cpu-profile'
|
|
2
|
+
import { runInspect } from './inspect'
|
|
3
|
+
import { runReact } from './react'
|
|
4
|
+
|
|
5
|
+
interface PerfOptions {
|
|
6
|
+
port?: number
|
|
7
|
+
verbose?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const VALUE_FLAGS = new Set(['--sim', '--port', '-p'])
|
|
11
|
+
const SUBCOMMANDS = new Set(['cpu', 'react', 'shell', 'scroll'])
|
|
12
|
+
|
|
13
|
+
function findSubcommand(args: string[]): { name: string; index: number } | null {
|
|
14
|
+
for (let i = 0; i < args.length; i++) {
|
|
15
|
+
const arg = args[i]
|
|
16
|
+
if (arg.startsWith('-')) {
|
|
17
|
+
if (VALUE_FLAGS.has(arg)) i++
|
|
18
|
+
continue
|
|
19
|
+
}
|
|
20
|
+
return SUBCOMMANDS.has(arg) ? { name: arg, index: i } : null
|
|
21
|
+
}
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function withoutSubcommand(args: string[], index: number): string[] {
|
|
26
|
+
return [...args.slice(0, index), ...args.slice(index + 1)]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function printHelp(): void {
|
|
30
|
+
console.log(`
|
|
31
|
+
rnx perf — performance profiling tools
|
|
32
|
+
|
|
33
|
+
usage:
|
|
34
|
+
rnx perf cpu [options]
|
|
35
|
+
rnx perf react <subcommand> [options]
|
|
36
|
+
rnx perf shell <start|stop|transition> [options]
|
|
37
|
+
rnx perf scroll <start|stop> [options]
|
|
38
|
+
|
|
39
|
+
examples:
|
|
40
|
+
rnx perf cpu --duration 5 --output /tmp/trace.cpuprofile
|
|
41
|
+
# writes page + every worker profile and a role-labelled manifest
|
|
42
|
+
rnx perf react summary --limit 10
|
|
43
|
+
rnx perf shell start
|
|
44
|
+
rnx perf shell stop --json
|
|
45
|
+
rnx perf scroll start
|
|
46
|
+
rnx perf scroll stop --json
|
|
47
|
+
`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function runPerf(args: string[], opts: PerfOptions): Promise<number> {
|
|
51
|
+
const sub = findSubcommand(args)
|
|
52
|
+
if (!sub) {
|
|
53
|
+
printHelp()
|
|
54
|
+
return args.includes('--help') || args.includes('-h') ? 0 : 1
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const rest = withoutSubcommand(args, sub.index)
|
|
58
|
+
if (sub.name === 'cpu') return runCpuProfile(rest, opts)
|
|
59
|
+
if (sub.name === 'react') return runReact(rest, opts)
|
|
60
|
+
|
|
61
|
+
const inspectArgs = rest.includes('--help') || rest.includes('-h') ? [] : rest
|
|
62
|
+
await runInspect(['debug', 'perf', ...inspectArgs], {
|
|
63
|
+
...opts,
|
|
64
|
+
internalPerfCommand: sub.name === 'scroll' ? 'scroll' : 'shell',
|
|
65
|
+
})
|
|
66
|
+
return typeof process.exitCode === 'number' ? process.exitCode : 0
|
|
67
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
callInBridge,
|
|
3
|
+
callInBridgeWrite,
|
|
4
|
+
createBridgeFromParsed,
|
|
5
|
+
parseBridgeCliArgs,
|
|
6
|
+
} from '../ws-bridge'
|
|
7
|
+
import type {
|
|
8
|
+
AppSettingsSnapshot,
|
|
9
|
+
SystemPermissionApp,
|
|
10
|
+
SystemPermissionKind,
|
|
11
|
+
SystemPermissionMutation,
|
|
12
|
+
SystemPermissionStatus,
|
|
13
|
+
} from '@rnx/globals'
|
|
14
|
+
|
|
15
|
+
interface PermissionsOptions {
|
|
16
|
+
port?: number
|
|
17
|
+
verbose?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const STATUSES: readonly SystemPermissionStatus[] = [
|
|
21
|
+
'not-determined',
|
|
22
|
+
'restricted',
|
|
23
|
+
'denied',
|
|
24
|
+
'authorized',
|
|
25
|
+
'limited',
|
|
26
|
+
'provisional',
|
|
27
|
+
'ephemeral',
|
|
28
|
+
'unavailable',
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
const KINDS: readonly SystemPermissionKind[] = [
|
|
32
|
+
'app-tracking-transparency',
|
|
33
|
+
'bluetooth',
|
|
34
|
+
'calendars',
|
|
35
|
+
'camera',
|
|
36
|
+
'contacts',
|
|
37
|
+
'face-id',
|
|
38
|
+
'local-network',
|
|
39
|
+
'location-always',
|
|
40
|
+
'location-when-in-use',
|
|
41
|
+
'media-library',
|
|
42
|
+
'microphone',
|
|
43
|
+
'motion',
|
|
44
|
+
'notifications',
|
|
45
|
+
'photo-library',
|
|
46
|
+
'photo-library-add-only',
|
|
47
|
+
'reminders',
|
|
48
|
+
'siri',
|
|
49
|
+
'speech-recognition',
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
function printHelp(): void {
|
|
53
|
+
console.log(`
|
|
54
|
+
rnx permissions — inspect and change simulated operating-system permissions
|
|
55
|
+
|
|
56
|
+
usage:
|
|
57
|
+
rnx permissions list [--json]
|
|
58
|
+
rnx permissions get <app-id> [--json]
|
|
59
|
+
rnx permissions set <app-id> <kind> <status> [--once] [--accuracy full|reduced] [--json]
|
|
60
|
+
rnx permissions reset <app-id> [kind] [--json]
|
|
61
|
+
`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function print(value: unknown, json: boolean): void {
|
|
65
|
+
console.log(json ? JSON.stringify(value, null, 2) : value)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function flagValue(args: string[], flag: string): string | undefined {
|
|
69
|
+
const index = args.indexOf(flag)
|
|
70
|
+
return index >= 0 ? args[index + 1] : undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function permissionKind(value: string): SystemPermissionKind | null {
|
|
74
|
+
return KINDS.find((candidate) => candidate === value) ?? null
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function permissionStatus(value: string): SystemPermissionStatus | null {
|
|
78
|
+
return STATUSES.find((candidate) => candidate === value) ?? null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function mutationFor(
|
|
82
|
+
status: SystemPermissionStatus,
|
|
83
|
+
once: boolean,
|
|
84
|
+
accuracy: 'full' | 'reduced' | undefined,
|
|
85
|
+
): SystemPermissionMutation {
|
|
86
|
+
switch (status) {
|
|
87
|
+
case 'authorized':
|
|
88
|
+
return {
|
|
89
|
+
status,
|
|
90
|
+
...(once ? { authorizationScope: 'once' } : null),
|
|
91
|
+
...(accuracy ? { locationAccuracy: accuracy } : null),
|
|
92
|
+
}
|
|
93
|
+
case 'not-determined':
|
|
94
|
+
case 'restricted':
|
|
95
|
+
case 'denied':
|
|
96
|
+
case 'limited':
|
|
97
|
+
case 'provisional':
|
|
98
|
+
case 'ephemeral':
|
|
99
|
+
case 'unavailable':
|
|
100
|
+
return { status }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function runPermissions(
|
|
105
|
+
args: string[],
|
|
106
|
+
opts: PermissionsOptions,
|
|
107
|
+
): Promise<number> {
|
|
108
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
109
|
+
printHelp()
|
|
110
|
+
return 0
|
|
111
|
+
}
|
|
112
|
+
const parsed = parseBridgeCliArgs(args, {
|
|
113
|
+
port: opts.port,
|
|
114
|
+
stripBooleanFlags: ['--json', '--once'],
|
|
115
|
+
stripValueFlags: ['--accuracy'],
|
|
116
|
+
})
|
|
117
|
+
const [command, appId, kindValue, statusValue] = parsed.positional
|
|
118
|
+
if (!command) {
|
|
119
|
+
printHelp()
|
|
120
|
+
return 1
|
|
121
|
+
}
|
|
122
|
+
const json = args.includes('--json')
|
|
123
|
+
const bridge = createBridgeFromParsed(parsed)
|
|
124
|
+
try {
|
|
125
|
+
if (command === 'list') {
|
|
126
|
+
const apps = await callInBridge<readonly SystemPermissionApp[]>(
|
|
127
|
+
bridge,
|
|
128
|
+
'SootSim.bridges.test.permissionListApps',
|
|
129
|
+
)
|
|
130
|
+
print(
|
|
131
|
+
json ? apps : apps.map((app) => `${app.appId}\t${app.displayName}`).join('\n'),
|
|
132
|
+
json,
|
|
133
|
+
)
|
|
134
|
+
return 0
|
|
135
|
+
}
|
|
136
|
+
if (!appId) throw new Error(`${command} requires an app id`)
|
|
137
|
+
if (command === 'get') {
|
|
138
|
+
const snapshot = await callInBridge<AppSettingsSnapshot>(
|
|
139
|
+
bridge,
|
|
140
|
+
'SootSim.bridges.test.permissionGetAppSettings',
|
|
141
|
+
appId,
|
|
142
|
+
)
|
|
143
|
+
print(snapshot, json)
|
|
144
|
+
return 0
|
|
145
|
+
}
|
|
146
|
+
if (command === 'reset') {
|
|
147
|
+
if (kindValue) {
|
|
148
|
+
const kind = permissionKind(kindValue)
|
|
149
|
+
if (!kind) throw new Error(`unknown permission kind: ${kindValue}`)
|
|
150
|
+
await callInBridgeWrite<AppSettingsSnapshot>(
|
|
151
|
+
bridge,
|
|
152
|
+
'SootSim.bridges.test.permissionSetAppPermission',
|
|
153
|
+
appId,
|
|
154
|
+
kind,
|
|
155
|
+
{ status: 'not-determined' },
|
|
156
|
+
)
|
|
157
|
+
} else {
|
|
158
|
+
await callInBridgeWrite<void>(
|
|
159
|
+
bridge,
|
|
160
|
+
'SootSim.bridges.test.permissionResetApp',
|
|
161
|
+
appId,
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
const snapshot = await callInBridge<AppSettingsSnapshot>(
|
|
165
|
+
bridge,
|
|
166
|
+
'SootSim.bridges.test.permissionGetAppSettings',
|
|
167
|
+
appId,
|
|
168
|
+
)
|
|
169
|
+
print(snapshot, json)
|
|
170
|
+
return 0
|
|
171
|
+
}
|
|
172
|
+
if (command !== 'set') throw new Error(`unknown permissions command: ${command}`)
|
|
173
|
+
if (!kindValue || !statusValue) {
|
|
174
|
+
throw new Error('set requires an app id, permission kind, and status')
|
|
175
|
+
}
|
|
176
|
+
const kind = permissionKind(kindValue)
|
|
177
|
+
if (!kind) throw new Error(`unknown permission kind: ${kindValue}`)
|
|
178
|
+
const status = permissionStatus(statusValue)
|
|
179
|
+
if (!status) throw new Error(`unknown permission status: ${statusValue}`)
|
|
180
|
+
const accuracyValue = flagValue(args, '--accuracy')
|
|
181
|
+
const accuracy =
|
|
182
|
+
accuracyValue === 'full' || accuracyValue === 'reduced' ? accuracyValue : undefined
|
|
183
|
+
if (accuracyValue && !accuracy) {
|
|
184
|
+
throw new Error(`unknown location accuracy: ${accuracyValue}`)
|
|
185
|
+
}
|
|
186
|
+
const snapshot = await callInBridgeWrite<AppSettingsSnapshot>(
|
|
187
|
+
bridge,
|
|
188
|
+
'SootSim.bridges.test.permissionSetAppPermission',
|
|
189
|
+
appId,
|
|
190
|
+
kind,
|
|
191
|
+
mutationFor(status, args.includes('--once'), accuracy),
|
|
192
|
+
)
|
|
193
|
+
print(snapshot, json)
|
|
194
|
+
return 0
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error(
|
|
197
|
+
` permissions failed: ${error instanceof Error ? error.message : error}`,
|
|
198
|
+
)
|
|
199
|
+
return 1
|
|
200
|
+
} finally {
|
|
201
|
+
bridge.close()
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
// `rnx ios` and `rnx android` — start a simulator on that platform.
|
|
2
|
+
//
|
|
3
|
+
// the platform picks the device; the command context picks where the sim runs
|
|
4
|
+
// (this machine, a local box, or the `rnx remote` namespace). this file resolves
|
|
5
|
+
// the device and hands the rest to the normal open path.
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_DEVICE_BY_PLATFORM,
|
|
9
|
+
devices,
|
|
10
|
+
getRuntimePlatform,
|
|
11
|
+
listSelectableDeviceModels,
|
|
12
|
+
type DeviceModel,
|
|
13
|
+
type RuntimePlatform,
|
|
14
|
+
} from 'sootsim-engine/settings'
|
|
15
|
+
import { settingsStore } from 'sootsim-engine/settings/store'
|
|
16
|
+
import { rnxPublicBrand } from '../../src/public-brand'
|
|
17
|
+
import { rethrowIfExit } from '../run-rnx'
|
|
18
|
+
import type { CloudSession } from '../cloud-session'
|
|
19
|
+
|
|
20
|
+
const PLATFORM_LABEL: Record<RuntimePlatform, string> = {
|
|
21
|
+
ios: 'iOS',
|
|
22
|
+
android: 'Android',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isDeviceModel(value: string): value is DeviceModel {
|
|
26
|
+
return value in devices
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// flags this command reads for itself rather than treating as the bundle.
|
|
30
|
+
const REMOTE_VALUE_FLAGS = new Set(['--device'])
|
|
31
|
+
|
|
32
|
+
function remoteInputFromArgs(
|
|
33
|
+
args: string[],
|
|
34
|
+
platform: RuntimePlatform,
|
|
35
|
+
): {
|
|
36
|
+
bundlePath: string
|
|
37
|
+
reuse: boolean
|
|
38
|
+
fresh: boolean
|
|
39
|
+
} {
|
|
40
|
+
const positional: string[] = []
|
|
41
|
+
for (let index = 0; index < args.length; index++) {
|
|
42
|
+
const arg = args[index]
|
|
43
|
+
if (arg === '--remote' || arg === '--reuse' || arg === '--new') continue
|
|
44
|
+
if (REMOTE_VALUE_FLAGS.has(arg)) {
|
|
45
|
+
const value = args[++index] ?? null
|
|
46
|
+
if (!value) throw new Error(`rnx remote ${platform} ${arg} requires a value`)
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
const assigned = arg.match(/^(--[a-z-]+)=(.*)$/)
|
|
50
|
+
if (assigned && REMOTE_VALUE_FLAGS.has(assigned[1] ?? '')) {
|
|
51
|
+
const value = assigned[2] ?? ''
|
|
52
|
+
if (!value)
|
|
53
|
+
throw new Error(`rnx remote ${platform} ${assigned[1]} requires a value`)
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
if (
|
|
57
|
+
arg === '--sim' ||
|
|
58
|
+
arg === '--session' ||
|
|
59
|
+
arg === '--tab' ||
|
|
60
|
+
arg.startsWith('--sim=') ||
|
|
61
|
+
arg.startsWith('--session=') ||
|
|
62
|
+
arg.startsWith('--tab=')
|
|
63
|
+
) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`rnx remote ${platform} creates a new simulator and cannot target --sim`,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
if (arg.startsWith('-')) {
|
|
69
|
+
throw new Error(`rnx remote ${platform} does not support ${arg}`)
|
|
70
|
+
}
|
|
71
|
+
positional.push(arg)
|
|
72
|
+
}
|
|
73
|
+
if (positional.length !== 1 || !positional[0]) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`usage: rnx remote ${platform} <local bundle.js|https://bundle-url> [--device <model>] [--reuse|--new]`,
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
const reuse = args.includes('--reuse')
|
|
79
|
+
const fresh = args.includes('--new')
|
|
80
|
+
if (reuse && fresh) {
|
|
81
|
+
throw new Error(`rnx remote ${platform} cannot combine --reuse and --new`)
|
|
82
|
+
}
|
|
83
|
+
return { bundlePath: positional[0], reuse, fresh }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function runPlatformCommand(
|
|
87
|
+
platform: RuntimePlatform,
|
|
88
|
+
args: string[],
|
|
89
|
+
opts: { port?: number } = {},
|
|
90
|
+
): Promise<number | undefined> {
|
|
91
|
+
// `--device` is applied to the settings store before dispatch, so a
|
|
92
|
+
// contradiction shows up here as a platform mismatch. refuse it by name
|
|
93
|
+
// rather than silently overriding whichever one the user meant.
|
|
94
|
+
const assignedDevice = args.find((arg) => arg.startsWith('--device='))
|
|
95
|
+
const explicitDevice =
|
|
96
|
+
args.find((_, i) => args[i - 1] === '--device') ?? assignedDevice?.slice(9)
|
|
97
|
+
let selectedDevice: DeviceModel
|
|
98
|
+
if (explicitDevice !== undefined) {
|
|
99
|
+
if (!isDeviceModel(explicitDevice)) {
|
|
100
|
+
console.error(
|
|
101
|
+
` ${rnxPublicBrand.commandName} ${platform}: unknown device "${explicitDevice}"\n` +
|
|
102
|
+
` run \`${rnxPublicBrand.commandName} device list\` to see valid models`,
|
|
103
|
+
)
|
|
104
|
+
return 1
|
|
105
|
+
}
|
|
106
|
+
const devicePlatform = getRuntimePlatform(explicitDevice)
|
|
107
|
+
if (devicePlatform !== platform) {
|
|
108
|
+
console.error(
|
|
109
|
+
` ${rnxPublicBrand.commandName} ${platform}: --device ${explicitDevice} is ` +
|
|
110
|
+
`${PLATFORM_LABEL[devicePlatform]}, not ${PLATFORM_LABEL[platform]}.\n` +
|
|
111
|
+
` pick one of: ${listSelectableDeviceModels()
|
|
112
|
+
.filter((model) => getRuntimePlatform(model) === platform)
|
|
113
|
+
.join(', ')}`,
|
|
114
|
+
)
|
|
115
|
+
return 1
|
|
116
|
+
}
|
|
117
|
+
selectedDevice = explicitDevice
|
|
118
|
+
} else {
|
|
119
|
+
// keep the user's own device when it already belongs to the platform they
|
|
120
|
+
// asked for, so `rnx ios` after `rnx device set iphone-16` does not
|
|
121
|
+
// silently snap back to the default model.
|
|
122
|
+
const current = settingsStore.get('deviceModel')
|
|
123
|
+
if (getRuntimePlatform(current) !== platform) {
|
|
124
|
+
settingsStore.apply({ deviceModel: DEFAULT_DEVICE_BY_PLATFORM[platform] })
|
|
125
|
+
selectedDevice = DEFAULT_DEVICE_BY_PLATFORM[platform]
|
|
126
|
+
} else {
|
|
127
|
+
selectedDevice = current
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (args.includes('--remote')) {
|
|
132
|
+
try {
|
|
133
|
+
return await runRemoteCreate(platform, args, selectedDevice)
|
|
134
|
+
} catch (error) {
|
|
135
|
+
rethrowIfExit(error)
|
|
136
|
+
console.error(
|
|
137
|
+
` ${rnxPublicBrand.commandName} ${platform} --remote failed: ${
|
|
138
|
+
error instanceof Error ? error.message : String(error)
|
|
139
|
+
}`,
|
|
140
|
+
)
|
|
141
|
+
return 1
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// leftover `--*` tokens are not bundle targets. parse the same flags `open`
|
|
146
|
+
// consumes, then refuse anything still starting with `-`.
|
|
147
|
+
const { parseBridgeCliArgs } = await import('../ws-bridge')
|
|
148
|
+
const leftover = parseBridgeCliArgs(args, {
|
|
149
|
+
port: opts.port,
|
|
150
|
+
stripBooleanFlags: [
|
|
151
|
+
'--new',
|
|
152
|
+
'--headless',
|
|
153
|
+
'--headed',
|
|
154
|
+
'--ephemeral',
|
|
155
|
+
'--hot',
|
|
156
|
+
'--no-hmr',
|
|
157
|
+
'--no-describe',
|
|
158
|
+
'--quiet',
|
|
159
|
+
'--remote',
|
|
160
|
+
],
|
|
161
|
+
stripValueFlags: [
|
|
162
|
+
'--base-url',
|
|
163
|
+
'--replace',
|
|
164
|
+
'--driver',
|
|
165
|
+
'--profile',
|
|
166
|
+
'--cdp-port',
|
|
167
|
+
'--device',
|
|
168
|
+
'--viewport',
|
|
169
|
+
'--remap',
|
|
170
|
+
],
|
|
171
|
+
}).positional.find((value) => value.startsWith('-'))
|
|
172
|
+
if (leftover) {
|
|
173
|
+
console.error(` unknown flag: ${leftover}`)
|
|
174
|
+
return 1
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const { runOpenCommand } = await import('./control')
|
|
178
|
+
await runOpenCommand(args, { port: opts.port })
|
|
179
|
+
return 0
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Runs the existing remote session path without changing the local platform commands. */
|
|
183
|
+
export function runRemotePlatformCommand(
|
|
184
|
+
platform: RuntimePlatform,
|
|
185
|
+
args: string[],
|
|
186
|
+
opts: { port?: number } = {},
|
|
187
|
+
): Promise<number | undefined> {
|
|
188
|
+
return runPlatformCommand(platform, ['--remote', ...args], opts)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const REMOTE_COMMANDS_HELP =
|
|
192
|
+
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot'
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* `rnx remote ios|android <bundle>` on the one customer plane: one typed
|
|
196
|
+
* create through the instance API for both platforms, and a reattach to the
|
|
197
|
+
* shell's own simulator when it already runs this bundle. the box stays the
|
|
198
|
+
* host behind the API and is never created or addressed here.
|
|
199
|
+
*/
|
|
200
|
+
async function runRemoteCreate(
|
|
201
|
+
platform: RuntimePlatform,
|
|
202
|
+
args: string[],
|
|
203
|
+
selectedDevice: string,
|
|
204
|
+
): Promise<number> {
|
|
205
|
+
const input = remoteInputFromArgs(args, platform)
|
|
206
|
+
const [
|
|
207
|
+
{ authHeaderOrExit, cloudAccountIdOrExit },
|
|
208
|
+
{
|
|
209
|
+
claimCloudSimulator,
|
|
210
|
+
closeCloudSession,
|
|
211
|
+
createRemoteSim,
|
|
212
|
+
getRemoteSim,
|
|
213
|
+
produceCloudArtifact,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
createCloudSession,
|
|
217
|
+
publishCloudSessionToShell,
|
|
218
|
+
readCloudSession,
|
|
219
|
+
requireCloudSessionShellUpdate,
|
|
220
|
+
},
|
|
221
|
+
{ openInBrowser },
|
|
222
|
+
] = await Promise.all([
|
|
223
|
+
import('../auth'),
|
|
224
|
+
import('../cloud-client'),
|
|
225
|
+
import('../cloud-session'),
|
|
226
|
+
import('./box'),
|
|
227
|
+
])
|
|
228
|
+
const artifact = await produceCloudArtifact(input.bundlePath)
|
|
229
|
+
const descriptor = requireCloudSessionShellUpdate()
|
|
230
|
+
const { auth, header } = authHeaderOrExit(`${platform} --remote`)
|
|
231
|
+
const accountId = cloudAccountIdOrExit(auth)
|
|
232
|
+
|
|
233
|
+
const existingSession = readCloudSession()
|
|
234
|
+
if (
|
|
235
|
+
existingSession &&
|
|
236
|
+
!input.fresh &&
|
|
237
|
+
existingSession.platform === platform &&
|
|
238
|
+
existingSession.artifact?.sha256 === artifact.sha256
|
|
239
|
+
) {
|
|
240
|
+
// an api key reads the simulator back through the account, which mints a
|
|
241
|
+
// fresh watch url with the read. any other credential rereads with the
|
|
242
|
+
// simulator's own token and keeps the stored watch url.
|
|
243
|
+
const live = await getRemoteSim({
|
|
244
|
+
apiOrigin: existingSession.apiOrigin,
|
|
245
|
+
simId: existingSession.simId,
|
|
246
|
+
authorization: auth.kind === 'api-key' ? header : `Bearer ${existingSession.token}`,
|
|
247
|
+
})
|
|
248
|
+
if (live && (live.status === 'open' || live.status === 'hibernated')) {
|
|
249
|
+
const claimed = await claimCloudSimulator(existingSession)
|
|
250
|
+
const streamUrl = live.streamUrl ?? existingSession.streamUrl ?? null
|
|
251
|
+
const session = createCloudSession({
|
|
252
|
+
...existingSession,
|
|
253
|
+
claimId: claimed.claim.id,
|
|
254
|
+
...(streamUrl ? { streamUrl } : {}),
|
|
255
|
+
})
|
|
256
|
+
publishCloudSessionToShell(session, descriptor)
|
|
257
|
+
console.log(
|
|
258
|
+
` reconnected to remote simulator: ${existingSession.simId} (${platform})`,
|
|
259
|
+
)
|
|
260
|
+
console.log(` claim expires: ${claimed.claim.expiresAt}`)
|
|
261
|
+
console.log(REMOTE_COMMANDS_HELP)
|
|
262
|
+
return 0
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// the new session supersedes the old one, so the shell update channel
|
|
267
|
+
// carries exactly one update: the shell accepts nothing else.
|
|
268
|
+
if (existingSession) await closeCloudSession(existingSession)
|
|
269
|
+
const created = await createRemoteSim({
|
|
270
|
+
bundlePath: input.bundlePath,
|
|
271
|
+
device: selectedDevice,
|
|
272
|
+
authorization: header,
|
|
273
|
+
accountId,
|
|
274
|
+
platform,
|
|
275
|
+
reuse: input.reuse,
|
|
276
|
+
})
|
|
277
|
+
try {
|
|
278
|
+
publishCloudSessionToShell(created.session, descriptor)
|
|
279
|
+
} catch (error) {
|
|
280
|
+
await closeCloudSession(created.session)
|
|
281
|
+
throw error
|
|
282
|
+
}
|
|
283
|
+
const receipt = created.receipt
|
|
284
|
+
const produced = created.artifact
|
|
285
|
+
console.log(` remote simulator: ${receipt.simId}${created.reused ? ' (reused)' : ''}`)
|
|
286
|
+
console.log(` platform: ${platform}`)
|
|
287
|
+
console.log(` device: ${selectedDevice}`)
|
|
288
|
+
console.log(` artifact: ${receipt.artifact.id} (${receipt.artifact.bytes} bytes)`)
|
|
289
|
+
console.log(
|
|
290
|
+
` source bundle: sha256:${produced.source.sha256} (${produced.source.bytes} bytes)`,
|
|
291
|
+
)
|
|
292
|
+
console.log(
|
|
293
|
+
` normalized modules: ${produced.modules}; javascript ${produced.javascript.sourceBytes} -> ${produced.javascript.minifiedBytes} bytes`,
|
|
294
|
+
)
|
|
295
|
+
console.log(
|
|
296
|
+
` embedded assets: ${produced.assets.descriptors} descriptors, ${produced.assets.variants} scales, ${produced.assets.bytes} bytes (${produced.assets.encodedBytes} encoded)`,
|
|
297
|
+
)
|
|
298
|
+
// the dest directory was chosen by resolving this bundle's descriptors
|
|
299
|
+
// against it, so say which one won rather than leaving it invisible.
|
|
300
|
+
if (created.assetsDirectory) {
|
|
301
|
+
console.log(` asset dest: ${created.assetsDirectory}`)
|
|
302
|
+
}
|
|
303
|
+
console.log(` claim expires: ${receipt.claim.expiresAt}`)
|
|
304
|
+
console.log(REMOTE_COMMANDS_HELP)
|
|
305
|
+
for (const warning of created.warnings) console.warn(` warning: ${warning}`)
|
|
306
|
+
if (!created.session.streamUrl) {
|
|
307
|
+
console.log(' the service minted no watch url for this simulator')
|
|
308
|
+
return 0
|
|
309
|
+
}
|
|
310
|
+
return openInBrowser(created.session.streamUrl)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/** `rnx remote list`: the simulators this account runs that `rnx remote` made. */
|
|
314
|
+
export async function runRemoteList(args: string[]): Promise<number> {
|
|
315
|
+
try {
|
|
316
|
+
let json = false
|
|
317
|
+
for (const arg of args) {
|
|
318
|
+
if (arg === '--json') {
|
|
319
|
+
json = true
|
|
320
|
+
continue
|
|
321
|
+
}
|
|
322
|
+
throw new Error(`usage: rnx remote list [--json]`)
|
|
323
|
+
}
|
|
324
|
+
const [{ authHeaderOrExit, cloudAccountIdOrExit }, { listRemoteSims }] =
|
|
325
|
+
await Promise.all([import('../auth'), import('../cloud-client')])
|
|
326
|
+
const { auth, header } = authHeaderOrExit('remote list')
|
|
327
|
+
const accountId = cloudAccountIdOrExit(auth)
|
|
328
|
+
const sims = await listRemoteSims({ authorization: header, accountId })
|
|
329
|
+
if (json) {
|
|
330
|
+
console.log(JSON.stringify({ sims }))
|
|
331
|
+
return 0
|
|
332
|
+
}
|
|
333
|
+
if (sims.length === 0) {
|
|
334
|
+
console.log(' no remote simulators are running')
|
|
335
|
+
return 0
|
|
336
|
+
}
|
|
337
|
+
for (const sim of sims) {
|
|
338
|
+
const platformLabel = sim.labels['rnx.platform'] ?? 'unknown'
|
|
339
|
+
console.log(
|
|
340
|
+
` ${sim.simId} ${sim.status} ${platformLabel} sha256:${sim.artifact.sha256.slice(0, 12)}`,
|
|
341
|
+
)
|
|
342
|
+
}
|
|
343
|
+
return 0
|
|
344
|
+
} catch (error) {
|
|
345
|
+
rethrowIfExit(error)
|
|
346
|
+
console.error(
|
|
347
|
+
` ${rnxPublicBrand.commandName} remote list failed: ${
|
|
348
|
+
error instanceof Error ? error.message : String(error)
|
|
349
|
+
}`,
|
|
350
|
+
)
|
|
351
|
+
return 1
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** `rnx remote stop <id>`: delete one remote simulator by id. */
|
|
356
|
+
export async function runRemoteStop(args: string[]): Promise<number> {
|
|
357
|
+
try {
|
|
358
|
+
const positional = args.filter((arg) => !arg.startsWith('-'))
|
|
359
|
+
if (
|
|
360
|
+
args.some((arg) => arg.startsWith('-')) ||
|
|
361
|
+
positional.length !== 1 ||
|
|
362
|
+
!positional[0]
|
|
363
|
+
) {
|
|
364
|
+
throw new Error(`usage: rnx remote stop <sim-id>`)
|
|
365
|
+
}
|
|
366
|
+
const simId = positional[0]
|
|
367
|
+
const [
|
|
368
|
+
{ authHeaderOrExit, cloudAccountIdOrExit },
|
|
369
|
+
{ deleteRemoteSim },
|
|
370
|
+
{ publishCloudSessionToShell, readCloudSession, requireCloudSessionShellUpdate },
|
|
371
|
+
] = await Promise.all([
|
|
372
|
+
import('../auth'),
|
|
373
|
+
import('../cloud-client'),
|
|
374
|
+
import('../cloud-session'),
|
|
375
|
+
])
|
|
376
|
+
let current: CloudSession | null = null
|
|
377
|
+
try {
|
|
378
|
+
current = readCloudSession()
|
|
379
|
+
} catch {
|
|
380
|
+
current = null
|
|
381
|
+
}
|
|
382
|
+
// stopping the shell's own simulator clears the shell with it, so the
|
|
383
|
+
// update channel is required before anything is deleted.
|
|
384
|
+
const descriptor = current?.simId === simId ? requireCloudSessionShellUpdate() : null
|
|
385
|
+
const { auth, header } = authHeaderOrExit('remote stop')
|
|
386
|
+
const accountId = cloudAccountIdOrExit(auth)
|
|
387
|
+
const deleted = await deleteRemoteSim({
|
|
388
|
+
simId,
|
|
389
|
+
authorization: header,
|
|
390
|
+
accountId,
|
|
391
|
+
})
|
|
392
|
+
if (!deleted) {
|
|
393
|
+
console.error(
|
|
394
|
+
` ${rnxPublicBrand.commandName} remote stop: ${simId} does not exist`,
|
|
395
|
+
)
|
|
396
|
+
return 1
|
|
397
|
+
}
|
|
398
|
+
if (descriptor !== null) publishCloudSessionToShell(null, descriptor)
|
|
399
|
+
console.log(` stopped remote simulator: ${deleted.simId}`)
|
|
400
|
+
return 0
|
|
401
|
+
} catch (error) {
|
|
402
|
+
rethrowIfExit(error)
|
|
403
|
+
console.error(
|
|
404
|
+
` ${rnxPublicBrand.commandName} remote stop failed: ${
|
|
405
|
+
error instanceof Error ? error.message : String(error)
|
|
406
|
+
}`,
|
|
407
|
+
)
|
|
408
|
+
return 1
|
|
409
|
+
}
|
|
410
|
+
}
|