peachsim 0.1.570 → 0.1.572
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 +108 -108
- 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 +28 -20
- 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 +3 -2
- package/cli/cloud-session.ts +12 -12
- package/cli/cloud-test-result-files.ts +97 -0
- 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 +173 -71
- 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 +176 -18
- 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 +4 -2
- package/cli/main.ts +14 -14
- package/cli/outbound-endpoints.ts +32 -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 +3 -2
- 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/jest-preset.cjs +2 -2
- 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 +116 -0
- package/dist-lib/cloud-test-args.mjs +86 -0
- 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/detox/jest-preset.cjs +2 -2
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +12 -12
- package/dist-lib/host/bridge-host.cjs +87 -77
- 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 +63 -73
- 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 +534 -520
- 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 +1 -1
- package/dist-lib/vite.cjs +479 -161
- package/package.json +22 -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 +47 -47
- 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-test-args.ts +100 -0
- 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 +11 -10
- 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/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 +8 -8
- package/src/vite-plugin-swift.ts +106 -110
- 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
|
|
|
@@ -10,6 +10,7 @@ import * as fs from 'fs'
|
|
|
10
10
|
import * as path from 'path'
|
|
11
11
|
import yaml from 'yaml'
|
|
12
12
|
import { resolveCliAuth } from '../auth'
|
|
13
|
+
import { cloudTestResultFileNames } from '../cloud-test-result-files'
|
|
13
14
|
import { parseFlowFile, type FlowFrontmatter } from '../flow-file'
|
|
14
15
|
import {
|
|
15
16
|
buildFlowCommandsJson,
|
|
@@ -42,36 +43,45 @@ const MAESTRO_DIRS = ['.maestro', 'maestro']
|
|
|
42
43
|
|
|
43
44
|
function printHelp() {
|
|
44
45
|
console.log(`
|
|
45
|
-
|
|
46
|
+
peach maestro — author and run Maestro YAML flows against peach
|
|
46
47
|
|
|
47
48
|
usage:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
57
58
|
|
|
58
59
|
options:
|
|
59
60
|
--dry-run, --no-run load flow into runner idle without auto-running
|
|
60
61
|
--env KEY=VALUE set env vars for \${KEY} interpolation (repeatable)
|
|
61
|
-
--continuous accepted for maestro cli compat;
|
|
62
|
+
--continuous accepted for maestro cli compat; peach runs the flow once
|
|
62
63
|
--include-tags <a,b> run only flows carrying one of these tags (comma-
|
|
63
64
|
separated; CLI wins over config.yaml includeTags)
|
|
64
65
|
--exclude-tags <a,b> skip flows carrying any of these tags
|
|
65
66
|
--config <path> read the workspace config (flows/tags) from this file
|
|
66
67
|
instead of <dir>/config.yaml
|
|
67
68
|
--format junit write a junit xml report (default ./report.xml)
|
|
69
|
+
JUNIT, NOOP also accepted (case-insensitive)
|
|
68
70
|
--output <file> junit report path (needs --format junit)
|
|
69
71
|
--test-output-dir <dir>
|
|
70
72
|
per-flow screenshots, commands.json, and logs/maestro.log
|
|
71
73
|
(config key testOutputDir:; CLI wins over config)
|
|
72
74
|
--debug-output <dir> write a session maestro.log there
|
|
73
|
-
--
|
|
74
|
-
--
|
|
75
|
+
--flatten-debug-output accepted; peach output is already flat
|
|
76
|
+
--test-suite-name <n> junit testsuite name (default "Test Suite")
|
|
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
|
+
--shard-all, --shard-split <spec>
|
|
83
|
+
warned; peach runs the full selection on one sim
|
|
84
|
+
-c warned; --continuous runs once under peach
|
|
75
85
|
--device <model> override the flow frontmatter device for this run
|
|
76
86
|
--new force a fresh browser window for this run
|
|
77
87
|
--headed force a fresh, VISIBLE window (implies --new,
|
|
@@ -85,19 +95,19 @@ options:
|
|
|
85
95
|
--slow <ms> delay between steps for natural pacing
|
|
86
96
|
|
|
87
97
|
examples:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
95
105
|
`)
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
function printCompatMatrix() {
|
|
99
109
|
console.log(`
|
|
100
|
-
|
|
110
|
+
peach maestro — compatibility matrix
|
|
101
111
|
|
|
102
112
|
supported verbs:
|
|
103
113
|
launchApp (including arguments), stopApp, clearState, clearKeychain (warn-only),
|
|
@@ -125,7 +135,7 @@ cli flags (maestro test parity):
|
|
|
125
135
|
CLI wins over config.yaml), --config <path>, --format junit with
|
|
126
136
|
--output (default report.xml; flow name:/properties: shape the
|
|
127
137
|
testcase), --test-output-dir (config key testOutputDir:, CLI wins),
|
|
128
|
-
--debug-output, --platform ios (others refused), --no-ansi (
|
|
138
|
+
--debug-output, --platform ios (others refused), --no-ansi (peach
|
|
129
139
|
output is already plain), -d for --device, -e for --env.
|
|
130
140
|
--continuous warns and runs once; --format html warns and runs
|
|
131
141
|
without a report.
|
|
@@ -137,14 +147,14 @@ launch behavior:
|
|
|
137
147
|
openLink: replaces the guest, then delivers the URL to the new tenant.
|
|
138
148
|
|
|
139
149
|
partial:
|
|
140
|
-
clearKeychain — warn-only,
|
|
141
|
-
when.platform —
|
|
150
|
+
clearKeychain — warn-only, peach has no keychain surface.
|
|
151
|
+
when.platform — peach reports iOS for this runner.
|
|
142
152
|
openLink: app routing works; no OS-level Safari fallback.
|
|
143
|
-
launchApp.resetRuntime —
|
|
153
|
+
launchApp.resetRuntime — peach-only extension for recorded benchmarks:
|
|
144
154
|
keep tenant storage/auth, but soft-reload the guest app inside launchApp.
|
|
145
|
-
takeScreenshot — maestro string form works unchanged;
|
|
155
|
+
takeScreenshot — maestro string form works unchanged; peach also accepts
|
|
146
156
|
{ path, withFrame } for framed export.
|
|
147
|
-
env —
|
|
157
|
+
env — peach seeds the JS env from the full shell environment, not just
|
|
148
158
|
MAESTRO_* (so \${SOOTSIM_*} credentials resolve); a bare \${NAME} that is
|
|
149
159
|
undefined fails the step loudly instead of typing "undefined".
|
|
150
160
|
|
|
@@ -162,11 +172,13 @@ function looksLikeFlag(s: string): boolean {
|
|
|
162
172
|
// extract --env KEY=VALUE pairs from argv and apply to process.env for the
|
|
163
173
|
// duration of the run. returns argv with the consumed flags removed so the
|
|
164
174
|
// rest can be forwarded to runFlowPlayback verbatim.
|
|
165
|
-
function applyEnvFlags(args: string[]): string[] {
|
|
175
|
+
export function applyEnvFlags(args: string[]): string[] {
|
|
166
176
|
const out: string[] = []
|
|
167
177
|
for (let i = 0; i < args.length; i++) {
|
|
168
|
-
|
|
169
|
-
|
|
178
|
+
const arg = args[i] as string
|
|
179
|
+
const inline = arg.startsWith('--env=') ? arg.slice('--env='.length) : null
|
|
180
|
+
if (arg === '--env' || arg === '-e' || inline !== null) {
|
|
181
|
+
const kv = inline ?? args[i + 1]
|
|
170
182
|
if (!kv || !kv.includes('=')) {
|
|
171
183
|
throw new Error(`--env expects KEY=VALUE (got ${JSON.stringify(kv ?? '')})`)
|
|
172
184
|
}
|
|
@@ -174,16 +186,16 @@ function applyEnvFlags(args: string[]): string[] {
|
|
|
174
186
|
const key = kv.slice(0, eq)
|
|
175
187
|
const value = kv.slice(eq + 1)
|
|
176
188
|
process.env[key] = value
|
|
177
|
-
i += 1
|
|
189
|
+
if (inline === null) i += 1
|
|
178
190
|
continue
|
|
179
191
|
}
|
|
180
|
-
out.push(
|
|
192
|
+
out.push(arg)
|
|
181
193
|
}
|
|
182
194
|
return out
|
|
183
195
|
}
|
|
184
196
|
|
|
185
197
|
// maestro-cli flags this command consumes itself, accepted so an existing
|
|
186
|
-
// script can swap `maestro test` for `
|
|
198
|
+
// script can swap `maestro test` for `peach maestro test` unedited. each one
|
|
187
199
|
// either takes effect below or says out loud that it does not: an option
|
|
188
200
|
// that is quietly dropped is how a run reports success while doing something
|
|
189
201
|
// other than what was asked. `--origin` is consumed here because only this
|
|
@@ -204,6 +216,7 @@ export interface MaestroCompatOptions {
|
|
|
204
216
|
testOutputDir: string | null
|
|
205
217
|
debugOutput: string | null
|
|
206
218
|
platform: string | null
|
|
219
|
+
testSuiteName: string | null
|
|
207
220
|
}
|
|
208
221
|
|
|
209
222
|
const MAESTRO_COMPAT_VALUE_FLAGS = new Set([
|
|
@@ -215,6 +228,14 @@ const MAESTRO_COMPAT_VALUE_FLAGS = new Set([
|
|
|
215
228
|
'--test-output-dir',
|
|
216
229
|
'--debug-output',
|
|
217
230
|
'--platform',
|
|
231
|
+
'--udid',
|
|
232
|
+
'--test-suite-name',
|
|
233
|
+
'--shards',
|
|
234
|
+
'--shard-all',
|
|
235
|
+
'--shard-split',
|
|
236
|
+
'--api-key',
|
|
237
|
+
'--api-url',
|
|
238
|
+
'--screen-size',
|
|
218
239
|
])
|
|
219
240
|
|
|
220
241
|
function splitTagList(value: string): string[] {
|
|
@@ -237,6 +258,7 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
237
258
|
testOutputDir: null,
|
|
238
259
|
debugOutput: null,
|
|
239
260
|
platform: null,
|
|
261
|
+
testSuiteName: null,
|
|
240
262
|
}
|
|
241
263
|
const rest: string[] = []
|
|
242
264
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -267,7 +289,8 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
267
289
|
compat.configPath = value
|
|
268
290
|
break
|
|
269
291
|
case '--format':
|
|
270
|
-
|
|
292
|
+
// maestro spells it JUNIT; normalize so either case works.
|
|
293
|
+
compat.format = value.toLowerCase()
|
|
271
294
|
break
|
|
272
295
|
case '--output':
|
|
273
296
|
compat.output = value
|
|
@@ -280,10 +303,32 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
280
303
|
break
|
|
281
304
|
case '--platform':
|
|
282
305
|
if (value.toLowerCase() !== 'ios') {
|
|
283
|
-
throw new Error(`
|
|
306
|
+
throw new Error(`peach emulates iOS only; --platform ${value} is not supported`)
|
|
284
307
|
}
|
|
285
308
|
compat.platform = value
|
|
286
309
|
break
|
|
310
|
+
case '--udid':
|
|
311
|
+
console.warn(
|
|
312
|
+
' warn: --udid selects a Maestro simulator; peach manages its own sim — pin one with --sim instead',
|
|
313
|
+
)
|
|
314
|
+
break
|
|
315
|
+
case '--test-suite-name':
|
|
316
|
+
compat.testSuiteName = value
|
|
317
|
+
break
|
|
318
|
+
case '--shards':
|
|
319
|
+
case '--shard-all':
|
|
320
|
+
case '--shard-split':
|
|
321
|
+
console.warn(
|
|
322
|
+
` warn: ${head} shards across Maestro devices; peach runs the full selection on one sim`,
|
|
323
|
+
)
|
|
324
|
+
break
|
|
325
|
+
case '--api-key':
|
|
326
|
+
case '--api-url':
|
|
327
|
+
console.warn(` warn: ${head} is Maestro beta AI analysis; peach ignores it`)
|
|
328
|
+
break
|
|
329
|
+
case '--screen-size':
|
|
330
|
+
console.warn(' warn: --screen-size is web-only; peach ignores it')
|
|
331
|
+
break
|
|
287
332
|
}
|
|
288
333
|
continue
|
|
289
334
|
}
|
|
@@ -294,26 +339,66 @@ export function extractMaestroCompatFlags(args: string[]): {
|
|
|
294
339
|
continue
|
|
295
340
|
}
|
|
296
341
|
if (a === '-d') {
|
|
297
|
-
// maestro's short form for --device.
|
|
342
|
+
// maestro's short form for --device. peach's device flag names a device
|
|
298
343
|
// model, and the flow runner reads it under the long spelling only.
|
|
299
344
|
rest.push('--device')
|
|
300
345
|
continue
|
|
301
346
|
}
|
|
302
|
-
if (a === '--no-ansi') {
|
|
303
|
-
// trivially satisfied:
|
|
347
|
+
if (a === '--no-ansi' || a === '--no-color') {
|
|
348
|
+
// trivially satisfied: peach prints no ANSI escapes anywhere on this path.
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
if (a === '--ansi' || a === '--color') {
|
|
352
|
+
console.warn(' warn: peach prints no ANSI escapes; colored output is unavailable')
|
|
353
|
+
continue
|
|
354
|
+
}
|
|
355
|
+
if (a === '--continuous' || a === '-c') {
|
|
356
|
+
console.warn(' warn: --continuous is not implemented in peach — running once')
|
|
357
|
+
continue
|
|
358
|
+
}
|
|
359
|
+
if (a === '--flatten-debug-output') {
|
|
360
|
+
// peach writes one <dir>/maestro.log with no per-run subfolders or
|
|
361
|
+
// timestamps, so the maestro layout flag is already satisfied.
|
|
362
|
+
continue
|
|
363
|
+
}
|
|
364
|
+
if (a === '--analyze') {
|
|
365
|
+
console.warn(' warn: --analyze is Maestro beta AI analysis; peach ignores it')
|
|
366
|
+
continue
|
|
367
|
+
}
|
|
368
|
+
if (a === '-s') {
|
|
369
|
+
const count = args[i + 1]
|
|
370
|
+
if (!count || count.startsWith('-')) throw new Error('-s expects a value')
|
|
371
|
+
i += 1
|
|
372
|
+
console.warn(
|
|
373
|
+
' warn: -s shards across Maestro devices; peach runs the full selection on one sim',
|
|
374
|
+
)
|
|
304
375
|
continue
|
|
305
376
|
}
|
|
306
|
-
if (
|
|
307
|
-
|
|
377
|
+
if (head === '-p') {
|
|
378
|
+
// -p is the peach bridge-port short, not maestro's --platform short. a
|
|
379
|
+
// non-numeric value is a pasted maestro command line; fail loud with
|
|
380
|
+
// the mapping instead of pinning the bridge to a NaN port.
|
|
381
|
+
const value = eq > 0 ? a.slice(eq + 1) : args[i + 1]
|
|
382
|
+
if (value !== undefined && !value.startsWith('-') && !/^\d+$/.test(value)) {
|
|
383
|
+
throw new Error(
|
|
384
|
+
`-p is the peach bridge-port short; use --platform for the Maestro platform (got ${JSON.stringify(value)})`,
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
rest.push(a)
|
|
308
388
|
continue
|
|
309
389
|
}
|
|
310
390
|
rest.push(a)
|
|
311
391
|
}
|
|
312
392
|
if (
|
|
313
393
|
compat.format !== null &&
|
|
314
|
-
!['junit', 'html', 'html-detailed'].includes(compat.format)
|
|
394
|
+
!['junit', 'html', 'html-detailed', 'noop'].includes(compat.format)
|
|
315
395
|
) {
|
|
316
|
-
throw new Error(`unsupported --format: ${compat.format} (
|
|
396
|
+
throw new Error(`unsupported --format: ${compat.format} (peach writes junit reports)`)
|
|
397
|
+
}
|
|
398
|
+
if (compat.format === 'html' || compat.format === 'html-detailed') {
|
|
399
|
+
console.warn(
|
|
400
|
+
' warn: --format html is not implemented in peach — running without a report',
|
|
401
|
+
)
|
|
317
402
|
}
|
|
318
403
|
return { rest, compat }
|
|
319
404
|
}
|
|
@@ -475,8 +560,8 @@ async function runInit(cwd: string): Promise<number> {
|
|
|
475
560
|
console.error(` error: ${outPath} already exists`)
|
|
476
561
|
return 1
|
|
477
562
|
}
|
|
478
|
-
const starter = `#
|
|
479
|
-
# run:
|
|
563
|
+
const starter = `# peach maestro starter flow — drop-in compatible with the maestro cli.
|
|
564
|
+
# run: peach maestro test .maestro/login.yaml
|
|
480
565
|
appId: com.example.app
|
|
481
566
|
---
|
|
482
567
|
- launchApp
|
|
@@ -491,7 +576,7 @@ appId: com.example.app
|
|
|
491
576
|
`
|
|
492
577
|
fs.writeFileSync(outPath, starter, 'utf8')
|
|
493
578
|
console.log(` + wrote ${outPath}`)
|
|
494
|
-
console.log(` next:
|
|
579
|
+
console.log(` next: peach maestro test .maestro/login.yaml`)
|
|
495
580
|
return 0
|
|
496
581
|
}
|
|
497
582
|
|
|
@@ -566,7 +651,7 @@ export async function runMaestro(
|
|
|
566
651
|
}
|
|
567
652
|
if (compat.format === 'html' || compat.format === 'html-detailed') {
|
|
568
653
|
console.warn(
|
|
569
|
-
` 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`,
|
|
570
655
|
)
|
|
571
656
|
}
|
|
572
657
|
if (compat.output && compat.format !== 'junit') {
|
|
@@ -578,7 +663,7 @@ export async function runMaestro(
|
|
|
578
663
|
let forwardArgs: string[]
|
|
579
664
|
|
|
580
665
|
if (sub === 'test') {
|
|
581
|
-
// `
|
|
666
|
+
// `peach maestro test <flow-or-dir> [flags...]`. the flow path is the first
|
|
582
667
|
// token that is neither a flag nor the value of one — without the second
|
|
583
668
|
// half, `test --sim a2 login.yaml` takes `a2` as the flow file. remove it
|
|
584
669
|
// by index, since a path can equal a flag value elsewhere in the argv.
|
|
@@ -592,7 +677,7 @@ export async function runMaestro(
|
|
|
592
677
|
forwardArgs = rest.filter((_, i) => i !== positionalIndex)
|
|
593
678
|
} else if (compat.configPath) {
|
|
594
679
|
// no positional with an explicit workspace config: run the directory
|
|
595
|
-
// the config lives in, like `
|
|
680
|
+
// the config lives in, like `peach test --config` does.
|
|
596
681
|
target = path.resolve(cwd, path.dirname(compat.configPath))
|
|
597
682
|
forwardArgs = rest
|
|
598
683
|
} else {
|
|
@@ -600,7 +685,7 @@ export async function runMaestro(
|
|
|
600
685
|
forwardArgs = rest
|
|
601
686
|
}
|
|
602
687
|
} else if (sub && !looksLikeFlag(sub)) {
|
|
603
|
-
// `
|
|
688
|
+
// `peach maestro <flow-or-dir>` — tolerate the shorthand.
|
|
604
689
|
target = path.resolve(cwd, sub)
|
|
605
690
|
forwardArgs = remaining.slice(1)
|
|
606
691
|
} else {
|
|
@@ -618,7 +703,7 @@ export async function runMaestro(
|
|
|
618
703
|
for (const problem of unexpected) {
|
|
619
704
|
console.error(` error: ${problem.message}`)
|
|
620
705
|
}
|
|
621
|
-
console.error('\n run `
|
|
706
|
+
console.error('\n run `peach maestro --help` for the flags this command accepts')
|
|
622
707
|
return 1
|
|
623
708
|
}
|
|
624
709
|
|
|
@@ -626,8 +711,8 @@ export async function runMaestro(
|
|
|
626
711
|
console.error(`
|
|
627
712
|
error: no maestro flows found.
|
|
628
713
|
expected one of: ${MAESTRO_DIRS.map((d) => `./${d}/`).join(', ')}
|
|
629
|
-
or pass a flow explicitly:
|
|
630
|
-
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
|
|
631
716
|
`)
|
|
632
717
|
return 1
|
|
633
718
|
}
|
|
@@ -666,7 +751,7 @@ export async function runMaestro(
|
|
|
666
751
|
}
|
|
667
752
|
|
|
668
753
|
// maestro's priority rule: CLI flag, then config.yaml, then the default
|
|
669
|
-
// (which for
|
|
754
|
+
// (which for peach is no test-output routing at all). a config-relative dir
|
|
670
755
|
// resolves against the config file, a CLI dir against the invocation cwd.
|
|
671
756
|
const testOutputRoot = compat.testOutputDir
|
|
672
757
|
? path.resolve(cwd, compat.testOutputDir)
|
|
@@ -675,7 +760,7 @@ export async function runMaestro(
|
|
|
675
760
|
: null
|
|
676
761
|
|
|
677
762
|
console.log(`
|
|
678
|
-
|
|
763
|
+
peach maestro — ${files.length} flow${files.length === 1 ? '' : 's'}
|
|
679
764
|
root: ${path.relative(cwd, target) || '.'}
|
|
680
765
|
`)
|
|
681
766
|
|
|
@@ -705,7 +790,7 @@ export async function runMaestro(
|
|
|
705
790
|
steps: ReturnType<typeof getLastFlowTraceSteps>
|
|
706
791
|
frontmatter: FlowFrontmatter
|
|
707
792
|
}> = []
|
|
708
|
-
for (const file of files) {
|
|
793
|
+
for (const [flowIndex, file] of files.entries()) {
|
|
709
794
|
console.log(`\n ▶ ${path.relative(cwd, file)}`)
|
|
710
795
|
const playbackArgs = [file, ...forwardArgs]
|
|
711
796
|
let flowTestDir: string | null = null
|
|
@@ -730,7 +815,7 @@ export async function runMaestro(
|
|
|
730
815
|
// one. sending it on as `--url` made it an app target instead, which left
|
|
731
816
|
// the playback bridge on whichever world resolveBridgeWorld picks by
|
|
732
817
|
// default (a live Vite dev shell selected from the development registry).
|
|
733
|
-
// so `
|
|
818
|
+
// so `peach --port <installed daemon> maestro …` silently ran the flow
|
|
734
819
|
// against the dev engine, then failed trying to resolve a bundle at the
|
|
735
820
|
// bridge port. an explicit command-level `--port` still wins, since
|
|
736
821
|
// parseBridgeCliArgs takes the last occurrence.
|
|
@@ -789,17 +874,20 @@ export async function runMaestro(
|
|
|
789
874
|
}
|
|
790
875
|
|
|
791
876
|
const upload = getLastFlowPreviewUploadResult()
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
877
|
+
// the receipt files are the per-flow manifest: always written, with
|
|
878
|
+
// null ids when the upload failed, so the flow never disappears from
|
|
879
|
+
// the collected entries.
|
|
880
|
+
const previewPayload = {
|
|
881
|
+
flow: path.relative(cwd, file) || file,
|
|
882
|
+
previewId: upload?.shareId ?? null,
|
|
883
|
+
previewUrl: upload?.previewUrl ?? null,
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
for (const name of cloudTestResultFileNames('preview', flowIndex, files.length)) {
|
|
887
|
+
fs.writeFileSync(path.join(cwd, name), JSON.stringify(previewPayload))
|
|
888
|
+
}
|
|
889
|
+
} catch {}
|
|
890
|
+
if (!upload?.shareId && !upload?.previewUrl && args.includes('--preview')) {
|
|
803
891
|
console.error(' error: required hosted recording upload failed')
|
|
804
892
|
if (exit === 0) exit = 1
|
|
805
893
|
if (worstExit === 0) worstExit = 1
|
|
@@ -832,11 +920,24 @@ export async function runMaestro(
|
|
|
832
920
|
}),
|
|
833
921
|
)
|
|
834
922
|
} catch {}
|
|
835
|
-
} else if (process.env.
|
|
923
|
+
} else if (process.env.PEACH_REQUIRE_REGISTRATION === 'true') {
|
|
836
924
|
console.error(' error: required hosted run registration failed')
|
|
837
925
|
if (exit === 0) exit = 1
|
|
838
926
|
if (worstExit === 0) worstExit = 1
|
|
839
927
|
}
|
|
928
|
+
// like the preview receipt above: always written, null ids when the
|
|
929
|
+
// registration failed, so the flow keeps its collected entry.
|
|
930
|
+
const testPayload = {
|
|
931
|
+
flow: path.relative(cwd, file) || file,
|
|
932
|
+
runId: run?.id ?? null,
|
|
933
|
+
previewUrl: run?.previewUrl ?? null,
|
|
934
|
+
traceUrl: run?.traceUrl ?? null,
|
|
935
|
+
}
|
|
936
|
+
try {
|
|
937
|
+
for (const name of cloudTestResultFileNames('test', flowIndex, files.length)) {
|
|
938
|
+
fs.writeFileSync(path.join(cwd, name), JSON.stringify(testPayload))
|
|
939
|
+
}
|
|
940
|
+
} catch {}
|
|
840
941
|
}
|
|
841
942
|
// artifact, upload, and registration failures above flip the local exit
|
|
842
943
|
// after the result was pushed; the report below must see the final one.
|
|
@@ -865,6 +966,7 @@ export async function runMaestro(
|
|
|
865
966
|
buildJUnitXml({
|
|
866
967
|
device: deviceLabel,
|
|
867
968
|
cases: results.map((r) => junitCaseForResult(cwd, r)),
|
|
969
|
+
...(compat.testSuiteName ? { name: compat.testSuiteName } : {}),
|
|
868
970
|
}),
|
|
869
971
|
)
|
|
870
972
|
console.log(` junit: ${path.relative(cwd, junitPath) || junitPath}`)
|
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
|
|