peachsim 0.1.571 → 0.1.573
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 +1 -1
- package/README.md +106 -106
- package/cli/app-config.ts +1 -1
- package/cli/app-fonts.ts +4 -4
- package/cli/auth.ts +11 -11
- package/cli/bin.ts +4 -4
- package/cli/bridge-flow-runner.ts +13 -13
- package/cli/browser-evals.ts +2 -2
- package/cli/cli-update.ts +6 -6
- package/cli/cloud-client.ts +16 -16
- package/cli/cloud-dispatch.ts +2 -2
- package/cli/cloud-session.ts +12 -12
- package/cli/cloud-test-tunnel.ts +4 -4
- package/cli/command-registry.ts +7 -7
- package/cli/commands/agent-wrapper.ts +7 -7
- package/cli/commands/agent.ts +16 -16
- package/cli/commands/app-fonts.ts +3 -3
- package/cli/commands/assert.ts +10 -10
- package/cli/commands/auth.ts +5 -5
- package/cli/commands/box/checkout-plane.ts +1 -1
- package/cli/commands/box/plane-share.ts +2 -2
- package/cli/commands/box/rnx-command.ts +5 -5
- package/cli/commands/box.ts +38 -38
- package/cli/commands/camera.ts +13 -13
- package/cli/commands/cleanup.ts +13 -13
- package/cli/commands/compat.ts +7 -7
- package/cli/commands/config.ts +5 -5
- package/cli/commands/control.ts +63 -63
- package/cli/commands/cpu-profile.ts +11 -11
- package/cli/commands/daemon-mac-app.ts +10 -10
- package/cli/commands/daemon.ts +29 -27
- package/cli/commands/debug.ts +35 -35
- package/cli/commands/desktop.ts +3 -3
- package/cli/commands/detox.ts +33 -33
- package/cli/commands/device.ts +9 -9
- package/cli/commands/diagnose.ts +17 -17
- package/cli/commands/do-chain.ts +4 -4
- package/cli/commands/electron.ts +9 -9
- package/cli/commands/film.ts +9 -9
- package/cli/commands/flow.ts +49 -49
- package/cli/commands/inspect/core.ts +12 -12
- package/cli/commands/inspect/count.ts +1 -1
- package/cli/commands/inspect/describe.ts +1 -1
- package/cli/commands/inspect/env.ts +2 -2
- package/cli/commands/inspect/find.ts +2 -2
- package/cli/commands/inspect/get-layout.ts +2 -2
- package/cli/commands/inspect/keyboard.ts +1 -1
- package/cli/commands/inspect/list.ts +4 -4
- package/cli/commands/inspect/memory.ts +1 -1
- package/cli/commands/inspect/resolve-target.ts +1 -1
- package/cli/commands/inspect/screens.ts +1 -1
- package/cli/commands/inspect/shared.ts +1 -1
- package/cli/commands/inspect/tree.ts +1 -1
- package/cli/commands/inspect/url.ts +1 -1
- package/cli/commands/inspect/wait-event.ts +5 -5
- package/cli/commands/inspect.ts +82 -82
- package/cli/commands/install-cli.ts +16 -16
- package/cli/commands/install-desktop.ts +26 -26
- package/cli/commands/login.ts +11 -11
- package/cli/commands/maestro-generate.ts +10 -10
- package/cli/commands/maestro.ts +77 -67
- package/cli/commands/mode.ts +4 -4
- package/cli/commands/no-bridge-hint.ts +12 -12
- package/cli/commands/perf.ts +11 -11
- package/cli/commands/permissions.ts +5 -5
- package/cli/commands/platform.ts +21 -21
- package/cli/commands/preview.ts +5 -5
- package/cli/commands/profile.ts +12 -12
- package/cli/commands/react.ts +15 -15
- package/cli/commands/record.ts +31 -31
- package/cli/commands/report-issue.ts +4 -4
- package/cli/commands/reset.ts +2 -2
- package/cli/commands/runtime.ts +23 -23
- package/cli/commands/screenshot-command.ts +2 -2
- package/cli/commands/screenshot-layers.ts +5 -5
- package/cli/commands/screenshot-mode.ts +7 -7
- package/cli/commands/screenshot.ts +24 -24
- package/cli/commands/screenshots-capture.ts +13 -13
- package/cli/commands/screenshots.ts +6 -6
- package/cli/commands/serve.ts +12 -12
- package/cli/commands/setup.ts +25 -25
- package/cli/commands/skills.ts +30 -23
- package/cli/commands/slides.ts +20 -20
- package/cli/commands/state.ts +2 -2
- package/cli/commands/storage.ts +3 -3
- package/cli/commands/telemetry.ts +2 -2
- package/cli/commands/test.ts +15 -15
- package/cli/commands/three-mode.ts +17 -17
- package/cli/commands/timeline.ts +12 -12
- package/cli/commands/upgrade.ts +11 -11
- package/cli/commands/upload.ts +26 -26
- package/cli/commands/version.ts +7 -7
- package/cli/commands/what-happened.ts +20 -20
- package/cli/current-sim.ts +3 -3
- package/cli/desktop-companion.ts +16 -16
- package/cli/drivers/electron.ts +4 -4
- package/cli/drivers/playwright-sim-host.ts +7 -7
- package/cli/drivers/playwright.ts +4 -4
- package/cli/drivers/registry.ts +1 -1
- package/cli/drivers/types.ts +5 -5
- package/cli/flow-export.ts +1 -1
- package/cli/flow-file.ts +5 -5
- package/cli/flow-session.ts +1 -1
- package/cli/help-core.ts +13 -13
- package/cli/hints.ts +14 -14
- package/cli/inspect-notice-state.ts +1 -1
- package/cli/internal-child.ts +2 -2
- package/cli/maestro-js.ts +4 -4
- package/cli/maestro-report.ts +1 -1
- package/cli/main.ts +14 -14
- package/cli/outbound-endpoints.ts +30 -30
- package/cli/parse-args.ts +7 -7
- package/cli/privacy.ts +1 -1
- package/cli/recording-access.ts +10 -10
- package/cli/resolve-assets.ts +2 -2
- package/cli/rnx-in-process.ts +5 -5
- package/cli/run-registry.ts +1 -1
- package/cli/run-rnx-core.ts +3 -3
- package/cli/run-rnx.ts +1 -1
- package/cli/runtime-notes.ts +1 -1
- package/cli/self-invocation.ts +1 -1
- package/cli/send-to-box.ts +1 -1
- package/cli/shell-init.ts +40 -40
- package/cli/ui.ts +1 -1
- package/cli/ws-bridge.ts +22 -22
- package/detox/config-loader.ts +1 -1
- package/detox/index.ts +28 -28
- package/detox/navigation.ts +2 -2
- package/dist-lib/agent-daemon-client.cjs +12 -12
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +2 -2
- package/dist-lib/agent-sessions.cjs +12 -12
- package/dist-lib/attached-projects.cjs +4 -4
- package/dist-lib/auth/shared-session.cjs +4 -4
- 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 +4 -4
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +2 -2
- package/dist-lib/bridge-contract.mjs +2 -2
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- 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 +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +42 -42
- package/dist-lib/cloud.mjs +42 -42
- package/dist-lib/config.cjs +2 -2
- package/dist-lib/detox/index.cjs +29 -29
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +12 -12
- package/dist-lib/host/bridge-host.cjs +72 -71
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +6 -6
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +48 -48
- 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 +5 -5
- package/dist-lib/menu.mjs +5 -5
- 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 +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +15 -15
- package/dist-lib/profiles.cjs +4 -4
- package/dist-lib/public-brand.cjs +3 -3
- 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 +2 -1
- package/dist-lib/sdk.cjs +9 -9
- package/dist-lib/sdk.mjs +9 -9
- package/dist-lib/skills.cjs +416 -415
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite.cjs +24 -24
- package/package.json +1 -1
- package/scripts/dev-server-scanner.ts +4 -3
- package/skills/contrast/SKILL.md +75 -75
- package/skills/{rnx-debug → peach-debug}/SKILL.md +90 -90
- package/skills/{rnx-perf → peach-perf}/SKILL.md +13 -13
- package/skills/{rnx-setup → peach-setup}/SKILL.md +60 -60
- package/skills/{rnx-test → peach-test}/SKILL.md +44 -44
- package/skills/{rnx-visual → peach-visual}/SKILL.md +26 -26
- package/src/agent-daemon-client.ts +5 -5
- package/src/agent-events.ts +1 -1
- package/src/agent-identity.ts +1 -1
- package/src/agent-sessions.ts +13 -13
- package/src/attached-projects.ts +1 -1
- package/src/auth/shared-session.ts +1 -1
- package/src/bridge-constants.ts +3 -3
- package/src/bridge-contract-input.ts +1 -1
- package/src/bridge-contract.ts +3 -3
- package/src/cli-version.ts +6 -6
- package/src/cloud.ts +40 -40
- package/src/config.ts +1 -1
- package/src/connect.ts +6 -6
- package/src/dev-server-open.ts +8 -8
- package/src/disk-cleanup.ts +3 -3
- package/src/home-paths.ts +26 -26
- package/src/host/agent-host.ts +3 -3
- package/src/host/bridge-host.ts +33 -33
- package/src/host/fetch-proxy-handler.ts +1 -1
- package/src/host/plane-host.ts +2 -2
- package/src/host/replacement-module-handler.ts +2 -2
- package/src/menu.ts +2 -2
- package/src/metro-plugin.ts +7 -7
- package/src/metro-production-bundle.ts +2 -2
- package/src/native-dev-bundle-url.ts +2 -2
- package/src/playwright-host-log.ts +1 -1
- package/src/public-brand.ts +2 -2
- package/src/react-native-host-modules.ts +1 -1
- package/src/rolldown-plugin-swift.ts +3 -3
- package/src/runtime-assets.ts +11 -11
- package/src/runtime-delivery.ts +6 -6
- package/src/screenshots/orchestrate.ts +1 -1
- package/src/screenshots/org-deck.ts +1 -1
- package/src/screenshots/schema.ts +2 -2
- package/src/sim-client.ts +1 -1
- package/src/skills/builtin/compat-check.ts +2 -2
- package/src/vite-plugin-one.ts +8 -8
- package/src/vite-plugin-swift.ts +3 -3
- package/src/vite-plugin.ts +6 -19
package/cli/commands/maestro.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach maestro — drop-in replacement for the real `maestro` cli.
|
|
2
2
|
//
|
|
3
3
|
// users with an existing `.maestro/` directory can swap `maestro test`
|
|
4
|
-
// for `
|
|
5
|
-
//
|
|
4
|
+
// for `peach maestro test` and have their flows execute against
|
|
5
|
+
// peach's in-browser engine. the heavy lifting lives in `flow.ts` +
|
|
6
6
|
// `bridge-flow-runner.ts`; this file just re-maps the maestro argv shape
|
|
7
7
|
// onto the existing flow runner and handles directory iteration + init.
|
|
8
8
|
|
|
@@ -43,23 +43,23 @@ const MAESTRO_DIRS = ['.maestro', 'maestro']
|
|
|
43
43
|
|
|
44
44
|
function printHelp() {
|
|
45
45
|
console.log(`
|
|
46
|
-
|
|
46
|
+
peach maestro — author and run Maestro YAML flows against peach
|
|
47
47
|
|
|
48
48
|
usage:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
peach maestro # discover .maestro/ or maestro/ in cwd, run all
|
|
50
|
+
peach maestro test <flow-or-dir> # mirrors "maestro test"
|
|
51
|
+
peach maestro load <flow> # load flow into runner without running (--dry-run)
|
|
52
|
+
peach maestro test .maestro/ # every *.yaml / *.yml in a directory
|
|
53
|
+
peach maestro generate "<goal>" # generate, run, and upload a Maestro flow
|
|
54
|
+
peach maestro start|keep|end # author a flow from live CLI actions
|
|
55
|
+
peach maestro validate <flow> # validate a Maestro YAML file
|
|
56
|
+
peach maestro init # scaffold .maestro/login.yaml
|
|
57
|
+
peach maestro --list-compat # print supported/unsupported verbs
|
|
58
58
|
|
|
59
59
|
options:
|
|
60
60
|
--dry-run, --no-run load flow into runner idle without auto-running
|
|
61
61
|
--env KEY=VALUE set env vars for \${KEY} interpolation (repeatable)
|
|
62
|
-
--continuous accepted for maestro cli compat;
|
|
62
|
+
--continuous accepted for maestro cli compat; peach runs the flow once
|
|
63
63
|
--include-tags <a,b> run only flows carrying one of these tags (comma-
|
|
64
64
|
separated; CLI wins over config.yaml includeTags)
|
|
65
65
|
--exclude-tags <a,b> skip flows carrying any of these tags
|
|
@@ -72,16 +72,16 @@ options:
|
|
|
72
72
|
per-flow screenshots, commands.json, and logs/maestro.log
|
|
73
73
|
(config key testOutputDir:; CLI wins over config)
|
|
74
74
|
--debug-output <dir> write a session maestro.log there
|
|
75
|
-
--flatten-debug-output accepted;
|
|
75
|
+
--flatten-debug-output accepted; peach output is already flat
|
|
76
76
|
--test-suite-name <n> junit testsuite name (default "Test Suite")
|
|
77
|
-
--platform ios accepted; any other platform is refused (
|
|
78
|
-
(-p stays the
|
|
79
|
-
--no-ansi accepted;
|
|
80
|
-
--udid <id> warned;
|
|
81
|
-
-s, --shards <n> warned;
|
|
77
|
+
--platform ios accepted; any other platform is refused (peach is iOS-only)
|
|
78
|
+
(-p stays the peach bridge-port short)
|
|
79
|
+
--no-ansi accepted; peach output is already plain text
|
|
80
|
+
--udid <id> warned; peach manages its own sim (pin one with --sim)
|
|
81
|
+
-s, --shards <n> warned; peach runs the full selection on one sim
|
|
82
82
|
--shard-all, --shard-split <spec>
|
|
83
|
-
warned;
|
|
84
|
-
-c warned; --continuous runs once under
|
|
83
|
+
warned; peach runs the full selection on one sim
|
|
84
|
+
-c warned; --continuous runs once under peach
|
|
85
85
|
--device <model> override the flow frontmatter device for this run
|
|
86
86
|
--new force a fresh browser window for this run
|
|
87
87
|
--headed force a fresh, VISIBLE window (implies --new,
|
|
@@ -95,19 +95,19 @@ options:
|
|
|
95
95
|
--slow <ms> delay between steps for natural pacing
|
|
96
96
|
|
|
97
97
|
examples:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
peach maestro test .maestro/login.yaml
|
|
99
|
+
peach maestro test .maestro/
|
|
100
|
+
peach maestro generate "log in and verify the welcome screen"
|
|
101
|
+
peach maestro start
|
|
102
|
+
peach maestro end --output .maestro/login.yaml --validate
|
|
103
|
+
peach maestro --env USERNAME=alice test .maestro/login.yaml
|
|
104
|
+
peach maestro init
|
|
105
105
|
`)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function printCompatMatrix() {
|
|
109
109
|
console.log(`
|
|
110
|
-
|
|
110
|
+
peach maestro — compatibility matrix
|
|
111
111
|
|
|
112
112
|
supported verbs:
|
|
113
113
|
launchApp (including arguments), stopApp, clearState, clearKeychain (warn-only),
|
|
@@ -135,7 +135,7 @@ cli flags (maestro test parity):
|
|
|
135
135
|
CLI wins over config.yaml), --config <path>, --format junit with
|
|
136
136
|
--output (default report.xml; flow name:/properties: shape the
|
|
137
137
|
testcase), --test-output-dir (config key testOutputDir:, CLI wins),
|
|
138
|
-
--debug-output, --platform ios (others refused), --no-ansi (
|
|
138
|
+
--debug-output, --platform ios (others refused), --no-ansi (peach
|
|
139
139
|
output is already plain), -d for --device, -e for --env.
|
|
140
140
|
--continuous warns and runs once; --format html warns and runs
|
|
141
141
|
without a report.
|
|
@@ -147,14 +147,14 @@ launch behavior:
|
|
|
147
147
|
openLink: replaces the guest, then delivers the URL to the new tenant.
|
|
148
148
|
|
|
149
149
|
partial:
|
|
150
|
-
clearKeychain — warn-only,
|
|
151
|
-
when.platform —
|
|
150
|
+
clearKeychain — warn-only, peach has no keychain surface.
|
|
151
|
+
when.platform — peach reports iOS for this runner.
|
|
152
152
|
openLink: app routing works; no OS-level Safari fallback.
|
|
153
|
-
launchApp.resetRuntime —
|
|
153
|
+
launchApp.resetRuntime — peach-only extension for recorded benchmarks:
|
|
154
154
|
keep tenant storage/auth, but soft-reload the guest app inside launchApp.
|
|
155
|
-
takeScreenshot — maestro string form works unchanged;
|
|
155
|
+
takeScreenshot — maestro string form works unchanged; peach also accepts
|
|
156
156
|
{ path, withFrame } for framed export.
|
|
157
|
-
env —
|
|
157
|
+
env — peach seeds the JS env from the full shell environment, not just
|
|
158
158
|
MAESTRO_* (so \${SOOTSIM_*} credentials resolve); a bare \${NAME} that is
|
|
159
159
|
undefined fails the step loudly instead of typing "undefined".
|
|
160
160
|
|
|
@@ -195,7 +195,7 @@ export function applyEnvFlags(args: string[]): string[] {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
// maestro-cli flags this command consumes itself, accepted so an existing
|
|
198
|
-
// script can swap `maestro test` for `
|
|
198
|
+
// script can swap `maestro test` for `peach maestro test` unedited. each one
|
|
199
199
|
// either takes effect below or says out loud that it does not: an option
|
|
200
200
|
// that is quietly dropped is how a run reports success while doing something
|
|
201
201
|
// other than what was asked. `--origin` is consumed here because only this
|
|
@@ -303,13 +303,13 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
303
303
|
break
|
|
304
304
|
case '--platform':
|
|
305
305
|
if (value.toLowerCase() !== 'ios') {
|
|
306
|
-
throw new Error(`
|
|
306
|
+
throw new Error(`peach emulates iOS only; --platform ${value} is not supported`)
|
|
307
307
|
}
|
|
308
308
|
compat.platform = value
|
|
309
309
|
break
|
|
310
310
|
case '--udid':
|
|
311
311
|
console.warn(
|
|
312
|
-
' warn: --udid selects a Maestro simulator;
|
|
312
|
+
' warn: --udid selects a Maestro simulator; peach manages its own sim — pin one with --sim instead',
|
|
313
313
|
)
|
|
314
314
|
break
|
|
315
315
|
case '--test-suite-name':
|
|
@@ -319,15 +319,15 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
319
319
|
case '--shard-all':
|
|
320
320
|
case '--shard-split':
|
|
321
321
|
console.warn(
|
|
322
|
-
` warn: ${head} shards across Maestro devices;
|
|
322
|
+
` warn: ${head} shards across Maestro devices; peach runs the full selection on one sim`,
|
|
323
323
|
)
|
|
324
324
|
break
|
|
325
325
|
case '--api-key':
|
|
326
326
|
case '--api-url':
|
|
327
|
-
console.warn(` warn: ${head} is Maestro beta AI analysis;
|
|
327
|
+
console.warn(` warn: ${head} is Maestro beta AI analysis; peach ignores it`)
|
|
328
328
|
break
|
|
329
329
|
case '--screen-size':
|
|
330
|
-
console.warn(' warn: --screen-size is web-only;
|
|
330
|
+
console.warn(' warn: --screen-size is web-only; peach ignores it')
|
|
331
331
|
break
|
|
332
332
|
}
|
|
333
333
|
continue
|
|
@@ -339,30 +339,30 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
339
339
|
continue
|
|
340
340
|
}
|
|
341
341
|
if (a === '-d') {
|
|
342
|
-
// maestro's short form for --device.
|
|
342
|
+
// maestro's short form for --device. peach's device flag names a device
|
|
343
343
|
// model, and the flow runner reads it under the long spelling only.
|
|
344
344
|
rest.push('--device')
|
|
345
345
|
continue
|
|
346
346
|
}
|
|
347
347
|
if (a === '--no-ansi' || a === '--no-color') {
|
|
348
|
-
// trivially satisfied:
|
|
348
|
+
// trivially satisfied: peach prints no ANSI escapes anywhere on this path.
|
|
349
349
|
continue
|
|
350
350
|
}
|
|
351
351
|
if (a === '--ansi' || a === '--color') {
|
|
352
|
-
console.warn(' warn:
|
|
352
|
+
console.warn(' warn: peach prints no ANSI escapes; colored output is unavailable')
|
|
353
353
|
continue
|
|
354
354
|
}
|
|
355
355
|
if (a === '--continuous' || a === '-c') {
|
|
356
|
-
console.warn(' warn: --continuous is not implemented in
|
|
356
|
+
console.warn(' warn: --continuous is not implemented in peach — running once')
|
|
357
357
|
continue
|
|
358
358
|
}
|
|
359
359
|
if (a === '--flatten-debug-output') {
|
|
360
|
-
//
|
|
360
|
+
// peach writes one <dir>/maestro.log with no per-run subfolders or
|
|
361
361
|
// timestamps, so the maestro layout flag is already satisfied.
|
|
362
362
|
continue
|
|
363
363
|
}
|
|
364
364
|
if (a === '--analyze') {
|
|
365
|
-
console.warn(' warn: --analyze is Maestro beta AI analysis;
|
|
365
|
+
console.warn(' warn: --analyze is Maestro beta AI analysis; peach ignores it')
|
|
366
366
|
continue
|
|
367
367
|
}
|
|
368
368
|
if (a === '-s') {
|
|
@@ -370,18 +370,18 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
370
370
|
if (!count || count.startsWith('-')) throw new Error('-s expects a value')
|
|
371
371
|
i += 1
|
|
372
372
|
console.warn(
|
|
373
|
-
' warn: -s shards across Maestro devices;
|
|
373
|
+
' warn: -s shards across Maestro devices; peach runs the full selection on one sim',
|
|
374
374
|
)
|
|
375
375
|
continue
|
|
376
376
|
}
|
|
377
377
|
if (head === '-p') {
|
|
378
|
-
// -p is the
|
|
378
|
+
// -p is the peach bridge-port short, not maestro's --platform short. a
|
|
379
379
|
// non-numeric value is a pasted maestro command line; fail loud with
|
|
380
380
|
// the mapping instead of pinning the bridge to a NaN port.
|
|
381
381
|
const value = eq > 0 ? a.slice(eq + 1) : args[i + 1]
|
|
382
382
|
if (value !== undefined && !value.startsWith('-') && !/^\d+$/.test(value)) {
|
|
383
383
|
throw new Error(
|
|
384
|
-
`-p is the
|
|
384
|
+
`-p is the peach bridge-port short; use --platform for the Maestro platform (got ${JSON.stringify(value)})`,
|
|
385
385
|
)
|
|
386
386
|
}
|
|
387
387
|
rest.push(a)
|
|
@@ -393,11 +393,11 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
393
393
|
compat.format !== null &&
|
|
394
394
|
!['junit', 'html', 'html-detailed', 'noop'].includes(compat.format)
|
|
395
395
|
) {
|
|
396
|
-
throw new Error(`unsupported --format: ${compat.format} (
|
|
396
|
+
throw new Error(`unsupported --format: ${compat.format} (peach writes junit reports)`)
|
|
397
397
|
}
|
|
398
398
|
if (compat.format === 'html' || compat.format === 'html-detailed') {
|
|
399
399
|
console.warn(
|
|
400
|
-
' warn: --format html is not implemented in
|
|
400
|
+
' warn: --format html is not implemented in peach — running without a report',
|
|
401
401
|
)
|
|
402
402
|
}
|
|
403
403
|
return { rest, compat }
|
|
@@ -560,8 +560,8 @@ async function runInit(cwd: string): Promise<number> {
|
|
|
560
560
|
console.error(` error: ${outPath} already exists`)
|
|
561
561
|
return 1
|
|
562
562
|
}
|
|
563
|
-
const starter = `#
|
|
564
|
-
# run:
|
|
563
|
+
const starter = `# peach maestro starter flow — drop-in compatible with the maestro cli.
|
|
564
|
+
# run: peach maestro test .maestro/login.yaml
|
|
565
565
|
appId: com.example.app
|
|
566
566
|
---
|
|
567
567
|
- launchApp
|
|
@@ -576,7 +576,7 @@ appId: com.example.app
|
|
|
576
576
|
`
|
|
577
577
|
fs.writeFileSync(outPath, starter, 'utf8')
|
|
578
578
|
console.log(` + wrote ${outPath}`)
|
|
579
|
-
console.log(` next:
|
|
579
|
+
console.log(` next: peach maestro test .maestro/login.yaml`)
|
|
580
580
|
return 0
|
|
581
581
|
}
|
|
582
582
|
|
|
@@ -651,7 +651,7 @@ export async function runMaestro(
|
|
|
651
651
|
}
|
|
652
652
|
if (compat.format === 'html' || compat.format === 'html-detailed') {
|
|
653
653
|
console.warn(
|
|
654
|
-
` warn: --format ${compat.format} reports are not implemented in
|
|
654
|
+
` warn: --format ${compat.format} reports are not implemented in peach — running without writing a report`,
|
|
655
655
|
)
|
|
656
656
|
}
|
|
657
657
|
if (compat.output && compat.format !== 'junit') {
|
|
@@ -663,7 +663,7 @@ export async function runMaestro(
|
|
|
663
663
|
let forwardArgs: string[]
|
|
664
664
|
|
|
665
665
|
if (sub === 'test') {
|
|
666
|
-
// `
|
|
666
|
+
// `peach maestro test <flow-or-dir> [flags...]`. the flow path is the first
|
|
667
667
|
// token that is neither a flag nor the value of one — without the second
|
|
668
668
|
// half, `test --sim a2 login.yaml` takes `a2` as the flow file. remove it
|
|
669
669
|
// by index, since a path can equal a flag value elsewhere in the argv.
|
|
@@ -677,7 +677,7 @@ export async function runMaestro(
|
|
|
677
677
|
forwardArgs = rest.filter((_, i) => i !== positionalIndex)
|
|
678
678
|
} else if (compat.configPath) {
|
|
679
679
|
// no positional with an explicit workspace config: run the directory
|
|
680
|
-
// the config lives in, like `
|
|
680
|
+
// the config lives in, like `peach test --config` does.
|
|
681
681
|
target = path.resolve(cwd, path.dirname(compat.configPath))
|
|
682
682
|
forwardArgs = rest
|
|
683
683
|
} else {
|
|
@@ -685,7 +685,7 @@ export async function runMaestro(
|
|
|
685
685
|
forwardArgs = rest
|
|
686
686
|
}
|
|
687
687
|
} else if (sub && !looksLikeFlag(sub)) {
|
|
688
|
-
// `
|
|
688
|
+
// `peach maestro <flow-or-dir>` — tolerate the shorthand.
|
|
689
689
|
target = path.resolve(cwd, sub)
|
|
690
690
|
forwardArgs = remaining.slice(1)
|
|
691
691
|
} else {
|
|
@@ -703,7 +703,7 @@ export async function runMaestro(
|
|
|
703
703
|
for (const problem of unexpected) {
|
|
704
704
|
console.error(` error: ${problem.message}`)
|
|
705
705
|
}
|
|
706
|
-
console.error('\n run `
|
|
706
|
+
console.error('\n run `peach maestro --help` for the flags this command accepts')
|
|
707
707
|
return 1
|
|
708
708
|
}
|
|
709
709
|
|
|
@@ -711,8 +711,8 @@ export async function runMaestro(
|
|
|
711
711
|
console.error(`
|
|
712
712
|
error: no maestro flows found.
|
|
713
713
|
expected one of: ${MAESTRO_DIRS.map((d) => `./${d}/`).join(', ')}
|
|
714
|
-
or pass a flow explicitly:
|
|
715
|
-
or scaffold a starter flow:
|
|
714
|
+
or pass a flow explicitly: peach maestro test path/to/flow.yaml
|
|
715
|
+
or scaffold a starter flow: peach maestro init
|
|
716
716
|
`)
|
|
717
717
|
return 1
|
|
718
718
|
}
|
|
@@ -751,7 +751,7 @@ export async function runMaestro(
|
|
|
751
751
|
}
|
|
752
752
|
|
|
753
753
|
// maestro's priority rule: CLI flag, then config.yaml, then the default
|
|
754
|
-
// (which for
|
|
754
|
+
// (which for peach is no test-output routing at all). a config-relative dir
|
|
755
755
|
// resolves against the config file, a CLI dir against the invocation cwd.
|
|
756
756
|
const testOutputRoot = compat.testOutputDir
|
|
757
757
|
? path.resolve(cwd, compat.testOutputDir)
|
|
@@ -760,7 +760,7 @@ export async function runMaestro(
|
|
|
760
760
|
: null
|
|
761
761
|
|
|
762
762
|
console.log(`
|
|
763
|
-
|
|
763
|
+
peach maestro — ${files.length} flow${files.length === 1 ? '' : 's'}
|
|
764
764
|
root: ${path.relative(cwd, target) || '.'}
|
|
765
765
|
`)
|
|
766
766
|
|
|
@@ -815,7 +815,7 @@ export async function runMaestro(
|
|
|
815
815
|
// one. sending it on as `--url` made it an app target instead, which left
|
|
816
816
|
// the playback bridge on whichever world resolveBridgeWorld picks by
|
|
817
817
|
// default (a live Vite dev shell selected from the development registry).
|
|
818
|
-
// so `
|
|
818
|
+
// so `peach --port <installed daemon> maestro …` silently ran the flow
|
|
819
819
|
// against the dev engine, then failed trying to resolve a bundle at the
|
|
820
820
|
// bridge port. an explicit command-level `--port` still wins, since
|
|
821
821
|
// parseBridgeCliArgs takes the last occurrence.
|
|
@@ -910,7 +910,17 @@ export async function runMaestro(
|
|
|
910
910
|
})
|
|
911
911
|
if (run) {
|
|
912
912
|
console.log(` run: ${run.id}${run.traceUrl ? ` · replay: ${run.traceUrl}` : ''}`)
|
|
913
|
-
|
|
913
|
+
try {
|
|
914
|
+
fs.writeFileSync(
|
|
915
|
+
path.join(cwd, 'test-result.json'),
|
|
916
|
+
JSON.stringify({
|
|
917
|
+
runId: run.id,
|
|
918
|
+
previewUrl: run.previewUrl,
|
|
919
|
+
traceUrl: run.traceUrl,
|
|
920
|
+
}),
|
|
921
|
+
)
|
|
922
|
+
} catch {}
|
|
923
|
+
} else if (process.env.PEACH_REQUIRE_REGISTRATION === 'true') {
|
|
914
924
|
console.error(' error: required hosted run registration failed')
|
|
915
925
|
if (exit === 0) exit = 1
|
|
916
926
|
if (worstExit === 0) worstExit = 1
|
package/cli/commands/mode.ts
CHANGED
|
@@ -28,12 +28,12 @@ function withoutSubcommand(args: string[], index: number): string[] {
|
|
|
28
28
|
|
|
29
29
|
function printHelp(): void {
|
|
30
30
|
console.log(`
|
|
31
|
-
|
|
31
|
+
peach mode — toggle live display modes
|
|
32
32
|
|
|
33
33
|
usage:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
peach mode screenshot [on|off|toggle]
|
|
35
|
+
peach mode three [on|off|toggle]
|
|
36
|
+
peach mode three configure [options]
|
|
37
37
|
`)
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -4,39 +4,39 @@ import { findDesktopCompanion } from '../desktop-companion'
|
|
|
4
4
|
import type { BridgeSimInfo } from '../ws-bridge'
|
|
5
5
|
|
|
6
6
|
export function printMissingCompanionHint() {
|
|
7
|
-
console.error(' no
|
|
7
|
+
console.error(' no peach desktop companion found.')
|
|
8
8
|
console.error('')
|
|
9
9
|
console.error(' install the desktop app:')
|
|
10
|
-
console.error('
|
|
10
|
+
console.error(' peach desktop install')
|
|
11
11
|
console.error('')
|
|
12
12
|
console.error(' or install the recommended background service:')
|
|
13
|
-
console.error('
|
|
13
|
+
console.error(' peach daemon install')
|
|
14
14
|
console.error('')
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function printMissingBridgeHint(port: number) {
|
|
18
18
|
const companion = findDesktopCompanion()
|
|
19
|
-
console.log(` note: no
|
|
19
|
+
console.log(` note: no peach bridge detected on port ${port}`)
|
|
20
20
|
if (companion) {
|
|
21
21
|
console.log(` launch the installed companion with:`)
|
|
22
|
-
console.log(`
|
|
22
|
+
console.log(` peach desktop`)
|
|
23
23
|
return
|
|
24
24
|
}
|
|
25
25
|
console.log('')
|
|
26
|
-
console.log(' run `
|
|
27
|
-
console.log(' or run `
|
|
26
|
+
console.log(' run `peach daemon install` to enable the faster background service,')
|
|
27
|
+
console.log(' or run `peach serve` in another shell for a foreground bridge.')
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function printMissingSimHint(port: number) {
|
|
31
31
|
console.error('')
|
|
32
|
-
console.error(` no sim is connected to the
|
|
32
|
+
console.error(` no sim is connected to the peach bridge on port ${port}.`)
|
|
33
33
|
console.error('')
|
|
34
|
-
console.error(' start your app dev server, then open it in
|
|
34
|
+
console.error(' start your app dev server, then open it in peach:')
|
|
35
35
|
console.error(' npx expo start --localhost --port 8081')
|
|
36
|
-
console.error('
|
|
36
|
+
console.error(' peach open 8081')
|
|
37
37
|
console.error('')
|
|
38
38
|
console.error(' then inspect the live app:')
|
|
39
|
-
console.error('
|
|
39
|
+
console.error(' peach describe')
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// printed when a command targeted a specific `--sim <id>` that the bridge
|
|
@@ -76,5 +76,5 @@ export async function printUnknownSimHint(
|
|
|
76
76
|
console.error(` ${sim.id} (${flags})`)
|
|
77
77
|
}
|
|
78
78
|
console.error('')
|
|
79
|
-
console.error(' pass a valid --sim id, or run `
|
|
79
|
+
console.error(' pass a valid --sim id, or run `peach list` to see all sessions.')
|
|
80
80
|
}
|
package/cli/commands/perf.ts
CHANGED
|
@@ -28,22 +28,22 @@ function withoutSubcommand(args: string[], index: number): string[] {
|
|
|
28
28
|
|
|
29
29
|
function printHelp(): void {
|
|
30
30
|
console.log(`
|
|
31
|
-
|
|
31
|
+
peach perf — performance profiling tools
|
|
32
32
|
|
|
33
33
|
usage:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
peach perf cpu [options]
|
|
35
|
+
peach perf react <subcommand> [options]
|
|
36
|
+
peach perf shell <start|stop|transition> [options]
|
|
37
|
+
peach perf scroll <start|stop> [options]
|
|
38
38
|
|
|
39
39
|
examples:
|
|
40
|
-
|
|
40
|
+
peach perf cpu --duration 5 --output /tmp/trace.cpuprofile
|
|
41
41
|
# writes page + every worker profile and a role-labelled manifest
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
peach perf react summary --limit 10
|
|
43
|
+
peach perf shell start
|
|
44
|
+
peach perf shell stop --json
|
|
45
|
+
peach perf scroll start
|
|
46
|
+
peach perf scroll stop --json
|
|
47
47
|
`)
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -51,13 +51,13 @@ const KINDS: readonly SystemPermissionKind[] = [
|
|
|
51
51
|
|
|
52
52
|
function printHelp(): void {
|
|
53
53
|
console.log(`
|
|
54
|
-
|
|
54
|
+
peach permissions — inspect and change simulated operating-system permissions
|
|
55
55
|
|
|
56
56
|
usage:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
peach permissions list [--json]
|
|
58
|
+
peach permissions get <app-id> [--json]
|
|
59
|
+
peach permissions set <app-id> <kind> <status> [--once] [--accuracy full|reduced] [--json]
|
|
60
|
+
peach permissions reset <app-id> [kind] [--json]
|
|
61
61
|
`)
|
|
62
62
|
}
|
|
63
63
|
|
package/cli/commands/platform.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// `
|
|
1
|
+
// `peach ios` and `peach android` — start a simulator on that platform.
|
|
2
2
|
//
|
|
3
3
|
// the platform picks the device; the command context picks where the sim runs
|
|
4
|
-
// (this machine, a local box, or the `
|
|
4
|
+
// (this machine, a local box, or the `peach remote` namespace). this file resolves
|
|
5
5
|
// the device and hands the rest to the normal open path.
|
|
6
6
|
|
|
7
7
|
import { createHash } from 'node:crypto'
|
|
@@ -49,7 +49,7 @@ function remoteInputFromArgs(
|
|
|
49
49
|
}
|
|
50
50
|
if (REMOTE_VALUE_FLAGS.has(arg)) {
|
|
51
51
|
const value = args[++index] ?? null
|
|
52
|
-
if (!value) throw new Error(`
|
|
52
|
+
if (!value) throw new Error(`peach remote ${platform} ${arg} requires a value`)
|
|
53
53
|
if (arg === '--name') name = value
|
|
54
54
|
continue
|
|
55
55
|
}
|
|
@@ -57,7 +57,7 @@ function remoteInputFromArgs(
|
|
|
57
57
|
if (assigned && REMOTE_VALUE_FLAGS.has(assigned[1] ?? '')) {
|
|
58
58
|
const value = assigned[2] ?? ''
|
|
59
59
|
if (!value)
|
|
60
|
-
throw new Error(`
|
|
60
|
+
throw new Error(`peach remote ${platform} ${assigned[1]} requires a value`)
|
|
61
61
|
if (assigned[1] === '--name') name = value
|
|
62
62
|
continue
|
|
63
63
|
}
|
|
@@ -70,23 +70,23 @@ function remoteInputFromArgs(
|
|
|
70
70
|
arg.startsWith('--tab=')
|
|
71
71
|
) {
|
|
72
72
|
throw new Error(
|
|
73
|
-
`
|
|
73
|
+
`peach remote ${platform} creates a new simulator and cannot target --sim`,
|
|
74
74
|
)
|
|
75
75
|
}
|
|
76
76
|
if (arg.startsWith('-')) {
|
|
77
|
-
throw new Error(`
|
|
77
|
+
throw new Error(`peach remote ${platform} does not support ${arg}`)
|
|
78
78
|
}
|
|
79
79
|
positional.push(arg)
|
|
80
80
|
}
|
|
81
81
|
if (positional.length !== 1 || !positional[0]) {
|
|
82
82
|
throw new Error(
|
|
83
|
-
`usage:
|
|
83
|
+
`usage: peach remote ${platform} <local bundle.js|https://bundle-url> [--device <model>] [--reuse|--new]`,
|
|
84
84
|
)
|
|
85
85
|
}
|
|
86
86
|
const reuse = args.includes('--reuse')
|
|
87
87
|
const fresh = args.includes('--new')
|
|
88
88
|
if (reuse && fresh) {
|
|
89
|
-
throw new Error(`
|
|
89
|
+
throw new Error(`peach remote ${platform} cannot combine --reuse and --new`)
|
|
90
90
|
}
|
|
91
91
|
return { bundlePath: positional[0], name, reuse, fresh }
|
|
92
92
|
}
|
|
@@ -105,7 +105,7 @@ function boxNameForBundle(bundlePath: string): string {
|
|
|
105
105
|
.toLowerCase()
|
|
106
106
|
.replace(/[^a-z0-9]+/g, '-')
|
|
107
107
|
.replace(/^-+|-+$/g, '')
|
|
108
|
-
if (!name) throw new Error(`
|
|
108
|
+
if (!name) throw new Error(`peach remote could not name a box after ${bundlePath}`)
|
|
109
109
|
return name
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -143,7 +143,7 @@ export async function runPlatformCommand(
|
|
|
143
143
|
selectedDevice = explicitDevice
|
|
144
144
|
} else {
|
|
145
145
|
// keep the user's own device when it already belongs to the platform they
|
|
146
|
-
// asked for, so `
|
|
146
|
+
// asked for, so `peach ios` after `peach device set iphone-16` does not
|
|
147
147
|
// silently snap back to the default model.
|
|
148
148
|
const current = settingsStore.get('deviceModel')
|
|
149
149
|
if (getRuntimePlatform(current) !== platform) {
|
|
@@ -231,7 +231,7 @@ const REMOTE_COMMANDS_HELP =
|
|
|
231
231
|
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot'
|
|
232
232
|
|
|
233
233
|
/**
|
|
234
|
-
* `
|
|
234
|
+
* `peach remote ios|android <bundle>` on the one customer plane: one typed
|
|
235
235
|
* create through the instance API for both platforms, and a reattach to the
|
|
236
236
|
* shell's own simulator when it already runs this bundle. the box stays the
|
|
237
237
|
* host behind the API and is never created or addressed here.
|
|
@@ -352,9 +352,9 @@ async function runRemoteCreate(
|
|
|
352
352
|
}
|
|
353
353
|
|
|
354
354
|
/**
|
|
355
|
-
* `
|
|
355
|
+
* `peach ios --remote` and `peach android --remote` — the app runs in a micro box.
|
|
356
356
|
*
|
|
357
|
-
* the bundle is prepared by the box plane's own producer, the one `
|
|
357
|
+
* the bundle is prepared by the box plane's own producer, the one `peach box
|
|
358
358
|
* create --bundle` uses: assets embedded, nothing minified and no module
|
|
359
359
|
* identity rewritten. the nano producer's artifact is built for the nano
|
|
360
360
|
* runner, which imports it as a module; a box page evaluates the bytes with
|
|
@@ -384,7 +384,7 @@ async function runRemoteBox(
|
|
|
384
384
|
publishCloudSessionToShell,
|
|
385
385
|
readCloudSession,
|
|
386
386
|
serializeCloudSession,
|
|
387
|
-
|
|
387
|
+
PEACH_CLOUD_SESSION_ENV,
|
|
388
388
|
},
|
|
389
389
|
] = await Promise.all([
|
|
390
390
|
import('../cloud-client'),
|
|
@@ -447,7 +447,7 @@ async function runRemoteBox(
|
|
|
447
447
|
try {
|
|
448
448
|
publishCloudSessionToShell(null)
|
|
449
449
|
} catch {
|
|
450
|
-
// no shell update channel is required outside an interactive
|
|
450
|
+
// no shell update channel is required outside an interactive peach shell
|
|
451
451
|
}
|
|
452
452
|
} else if (existingSession) {
|
|
453
453
|
await closeCloudSession(existingSession)
|
|
@@ -482,7 +482,7 @@ async function runRemoteBox(
|
|
|
482
482
|
} catch {
|
|
483
483
|
// shell update fd not configured
|
|
484
484
|
}
|
|
485
|
-
process.env[
|
|
485
|
+
process.env[PEACH_CLOUD_SESSION_ENV] = serializeCloudSession(session)
|
|
486
486
|
|
|
487
487
|
console.log(` box: ${created.id} (${artifact.bytes.length} bytes)`)
|
|
488
488
|
console.log(` platform: ${platform}`)
|
|
@@ -504,7 +504,7 @@ async function runRemoteBox(
|
|
|
504
504
|
return openInBrowser(watchUrl)
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
-
/** `
|
|
507
|
+
/** `peach remote list`: the simulators this account runs that `peach remote` made. */
|
|
508
508
|
export async function runRemoteList(args: string[]): Promise<number> {
|
|
509
509
|
try {
|
|
510
510
|
let json = false
|
|
@@ -513,7 +513,7 @@ export async function runRemoteList(args: string[]): Promise<number> {
|
|
|
513
513
|
json = true
|
|
514
514
|
continue
|
|
515
515
|
}
|
|
516
|
-
throw new Error(`usage:
|
|
516
|
+
throw new Error(`usage: peach remote list [--json]`)
|
|
517
517
|
}
|
|
518
518
|
const [{ authHeaderOrExit, cloudAccountIdOrExit }, { listRemoteSims }] =
|
|
519
519
|
await Promise.all([import('../auth'), import('../cloud-client')])
|
|
@@ -529,7 +529,7 @@ export async function runRemoteList(args: string[]): Promise<number> {
|
|
|
529
529
|
return 0
|
|
530
530
|
}
|
|
531
531
|
for (const sim of sims) {
|
|
532
|
-
const platformLabel = sim.labels['
|
|
532
|
+
const platformLabel = sim.labels['peach.platform'] ?? 'unknown'
|
|
533
533
|
console.log(
|
|
534
534
|
` ${sim.simId} ${sim.status} ${platformLabel} sha256:${sim.artifact.sha256.slice(0, 12)}`,
|
|
535
535
|
)
|
|
@@ -546,7 +546,7 @@ export async function runRemoteList(args: string[]): Promise<number> {
|
|
|
546
546
|
}
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
-
/** `
|
|
549
|
+
/** `peach remote stop <id>`: delete one remote simulator by id. */
|
|
550
550
|
export async function runRemoteStop(args: string[]): Promise<number> {
|
|
551
551
|
try {
|
|
552
552
|
const positional = args.filter((arg) => !arg.startsWith('-'))
|
|
@@ -555,7 +555,7 @@ export async function runRemoteStop(args: string[]): Promise<number> {
|
|
|
555
555
|
positional.length !== 1 ||
|
|
556
556
|
!positional[0]
|
|
557
557
|
) {
|
|
558
|
-
throw new Error(`usage:
|
|
558
|
+
throw new Error(`usage: peach remote stop <sim-id>`)
|
|
559
559
|
}
|
|
560
560
|
const simId = positional[0]
|
|
561
561
|
const [
|