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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach what-happened — show recent events from the semantic timeline
|
|
2
2
|
//
|
|
3
3
|
// the agent-facing read verb for the SootSim.bridges.timeline API. by default
|
|
4
4
|
// shows everything since the previous CLI call from the same agent
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
// the events it displayed so the next call shows only new events.
|
|
7
7
|
//
|
|
8
8
|
// usage:
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
9
|
+
// peach what-happened # since last call
|
|
10
|
+
// peach what-happened --summary # one-line counts
|
|
11
|
+
// peach what-happened --all # full ring (no cursor)
|
|
12
|
+
// peach what-happened --since 5s # absolute window
|
|
13
|
+
// peach what-happened --kinds toast,fetch # filter
|
|
14
|
+
// peach what-happened --json # structured
|
|
15
|
+
// peach what-happened --limit 50 # cap (default 200)
|
|
16
16
|
|
|
17
17
|
import { getCliIdentityKey } from '../current-sim'
|
|
18
18
|
import { rnxExit } from '../run-rnx'
|
|
@@ -157,7 +157,7 @@ export async function runWhatHappened(args: string[], opts: WhatHappenedOptions)
|
|
|
157
157
|
'--flow',
|
|
158
158
|
// by default we hide high-frequency render/layout/scroll noise so
|
|
159
159
|
// a single tap doesn't get buried under 1000+ rows. enable
|
|
160
|
-
// `react-commit` with `
|
|
160
|
+
// `react-commit` with `peach timeline start react-commit`, then pass
|
|
161
161
|
// `--noisy` (or an explicit `--kinds react-commit,…` filter) when you
|
|
162
162
|
// actually want to see them.
|
|
163
163
|
'--noisy',
|
|
@@ -167,21 +167,21 @@ export async function runWhatHappened(args: string[], opts: WhatHappenedOptions)
|
|
|
167
167
|
|
|
168
168
|
if (args.includes('--help') || args.includes('-h')) {
|
|
169
169
|
console.log(`
|
|
170
|
-
|
|
170
|
+
peach what-happened — show recent events from the semantic timeline
|
|
171
171
|
|
|
172
172
|
usage:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
173
|
+
peach what-happened # since last CLI call
|
|
174
|
+
peach what-happened --summary # one-line counts
|
|
175
|
+
peach what-happened --all # full ring (ignore cursor)
|
|
176
|
+
peach what-happened --since 5s # absolute window
|
|
177
|
+
peach what-happened --kinds toast,fetch
|
|
178
|
+
peach what-happened --noisy # include react-commit/layout/scroll
|
|
179
|
+
peach what-happened --limit 50
|
|
180
|
+
peach what-happened --json
|
|
181
|
+
peach what-happened --no-advance # don't advance cursor after read
|
|
182
182
|
|
|
183
183
|
note: react-commit, layout, and scroll are opt-in/noisy events. enable them
|
|
184
|
-
with "
|
|
184
|
+
with "peach timeline start <kind>", then pass --noisy or include them in
|
|
185
185
|
--kinds to see them.
|
|
186
186
|
`)
|
|
187
187
|
rnxExit(0)
|
package/cli/current-sim.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface LocalCurrentTarget {
|
|
|
18
18
|
// checked in order — the first one present wins. anything further down is a
|
|
19
19
|
// progressively weaker signal of "same caller across invocations".
|
|
20
20
|
const IDENTITY_ENV_VARS = [
|
|
21
|
-
'
|
|
21
|
+
'PEACH_CLI_IDENTITY', // explicit override — fastest path, skips all pid lookups
|
|
22
22
|
'TM_SESSION', // Team Machine session id; routes prompt-bar followups back to this agent
|
|
23
23
|
'CLAUDE_CODE_SESSION_ID', // claude code, if ever set
|
|
24
24
|
'CODEX_THREAD_ID', // codex / openai agent thread, stable across tool invocations
|
|
@@ -56,7 +56,7 @@ export interface CliIdentity {
|
|
|
56
56
|
// pids drift across invocations:
|
|
57
57
|
// - claude code's bash tool spawns a fresh shell per call, so the
|
|
58
58
|
// immediate gppid (the shell's parent) can change
|
|
59
|
-
// - shell pipelines (`
|
|
59
|
+
// - shell pipelines (`peach list | grep`) wrap the command in a
|
|
60
60
|
// subshell, adding an extra ppid layer that shifts gppid down by one
|
|
61
61
|
// the topmost user process (just below init/launchd) is stable across
|
|
62
62
|
// all of these — same agent / login shell / terminal across calls.
|
|
@@ -147,7 +147,7 @@ export function getCurrentSimPath() {
|
|
|
147
147
|
return resolve(process.env[CURRENT_SIM_PATH_ENV])
|
|
148
148
|
}
|
|
149
149
|
const key = getCliIdentityKey()
|
|
150
|
-
return join(tmpdir(), `
|
|
150
|
+
return join(tmpdir(), `peach-current-sim-${key}.json`)
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
function legacyCloudCredentialDirectory(filepath: string): string {
|
package/cli/desktop-companion.ts
CHANGED
|
@@ -19,7 +19,7 @@ function getSootsimRoot(): string | null {
|
|
|
19
19
|
}
|
|
20
20
|
return _sootsimRoot
|
|
21
21
|
}
|
|
22
|
-
const
|
|
22
|
+
const PEACH_BUNDLE_ID = 'dev.peachsim.simulator'
|
|
23
23
|
|
|
24
24
|
export interface DesktopCompanionInstall {
|
|
25
25
|
path: string
|
|
@@ -38,7 +38,7 @@ export interface DesktopCompanionLaunchResult {
|
|
|
38
38
|
|
|
39
39
|
// dev-electron: when running from inside the Contrast checkout with sootsim-engine
|
|
40
40
|
// built and the electron dev dep present, prefer launching the local unpacked
|
|
41
|
-
// electron instead of the stale packaged /Applications/
|
|
41
|
+
// electron instead of the stale packaged /Applications/peach.app.
|
|
42
42
|
//
|
|
43
43
|
// rationale: in dev we want electron to hit http://localhost:5173
|
|
44
44
|
// (src-electron/main.ts does this when !app.isPackaged).
|
|
@@ -92,9 +92,9 @@ function findElectronBin(startDir: string): string | null {
|
|
|
92
92
|
function findMacApp(): DesktopCompanionInstall | null {
|
|
93
93
|
const root = getSootsimRoot()
|
|
94
94
|
const candidates = [
|
|
95
|
-
'/Applications/
|
|
96
|
-
resolve(process.env.HOME || '', 'Applications/
|
|
97
|
-
...(root ? [resolve(root, 'app/
|
|
95
|
+
'/Applications/peach.app',
|
|
96
|
+
resolve(process.env.HOME || '', 'Applications/peach.app'),
|
|
97
|
+
...(root ? [resolve(root, 'app/peach.app')] : []),
|
|
98
98
|
]
|
|
99
99
|
|
|
100
100
|
const found = candidates.find((candidate) => existsSync(candidate))
|
|
@@ -109,7 +109,7 @@ function findMacApp(): DesktopCompanionInstall | null {
|
|
|
109
109
|
try {
|
|
110
110
|
const result = execFileSync(
|
|
111
111
|
'mdfind',
|
|
112
|
-
[`kMDItemCFBundleIdentifier == "${
|
|
112
|
+
[`kMDItemCFBundleIdentifier == "${PEACH_BUNDLE_ID}"`],
|
|
113
113
|
{ encoding: 'utf8', timeout: 3000 },
|
|
114
114
|
).trim()
|
|
115
115
|
if (result) {
|
|
@@ -127,7 +127,7 @@ function findMacApp(): DesktopCompanionInstall | null {
|
|
|
127
127
|
function findFirstAppImage(dir: string): string | null {
|
|
128
128
|
if (!existsSync(dir)) return null
|
|
129
129
|
const match = readdirSync(dir)
|
|
130
|
-
.filter((entry) => entry.startsWith('
|
|
130
|
+
.filter((entry) => entry.startsWith('peach') && entry.endsWith('.AppImage'))
|
|
131
131
|
.sort()
|
|
132
132
|
.reverse()[0]
|
|
133
133
|
return match ? join(dir, match) : null
|
|
@@ -136,12 +136,12 @@ function findFirstAppImage(dir: string): string | null {
|
|
|
136
136
|
function findLinuxInstall(): DesktopCompanionInstall | null {
|
|
137
137
|
const root = getSootsimRoot()
|
|
138
138
|
const directCandidates = [
|
|
139
|
-
resolve(process.env.HOME || '', 'Applications/
|
|
140
|
-
resolve(process.env.HOME || '', '.local/bin/
|
|
141
|
-
'/opt/
|
|
142
|
-
'/opt/
|
|
139
|
+
resolve(process.env.HOME || '', 'Applications/peach.AppImage'),
|
|
140
|
+
resolve(process.env.HOME || '', '.local/bin/peach.AppImage'),
|
|
141
|
+
'/opt/peach/peach.AppImage',
|
|
142
|
+
'/opt/peach/peach',
|
|
143
143
|
...(root
|
|
144
|
-
? [resolve(root, 'app/
|
|
144
|
+
? [resolve(root, 'app/peach.AppImage'), resolve(root, 'release/linux-unpacked/peach')]
|
|
145
145
|
: []),
|
|
146
146
|
]
|
|
147
147
|
|
|
@@ -173,7 +173,7 @@ function findWindowsInstall(): DesktopCompanionInstall | null {
|
|
|
173
173
|
try {
|
|
174
174
|
const output = execFileSync(
|
|
175
175
|
'reg',
|
|
176
|
-
['query', `${hive}\\Software\\Classes\\
|
|
176
|
+
['query', `${hive}\\Software\\Classes\\peach\\shell\\open\\command`, '/ve'],
|
|
177
177
|
{ encoding: 'utf8', timeout: 3000 },
|
|
178
178
|
)
|
|
179
179
|
const executable = /"([^"\r\n]+\.exe)"/i.exec(output)?.[1]
|
|
@@ -240,8 +240,8 @@ export interface LaunchCompanionOptions {
|
|
|
240
240
|
device?: string
|
|
241
241
|
profileId?: string
|
|
242
242
|
ephemeralProfile?: boolean
|
|
243
|
-
// set by `
|
|
244
|
-
// session. `
|
|
243
|
+
// set by `peach open`, whose native window belongs to the launching
|
|
244
|
+
// session. `peach desktop` omits it and remains a persistent desktop app.
|
|
245
245
|
ownerPid?: number
|
|
246
246
|
}
|
|
247
247
|
|
|
@@ -304,7 +304,7 @@ export async function launchDesktopCompanion(
|
|
|
304
304
|
|
|
305
305
|
function buildMacLaunchUrl(url: string, opts: LaunchCompanionOptions): string {
|
|
306
306
|
if (!opts.profileId && !opts.ephemeralProfile && !opts.ownerPid) return url
|
|
307
|
-
const deepLink = new URL('
|
|
307
|
+
const deepLink = new URL('peach://dev')
|
|
308
308
|
deepLink.searchParams.set('url', url)
|
|
309
309
|
if (opts.profileId) deepLink.searchParams.set('profile', opts.profileId)
|
|
310
310
|
if (opts.ephemeralProfile) deepLink.searchParams.set('ephemeral', '1')
|
package/cli/drivers/electron.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// electron driver — wraps the existing desktop-companion helper. availability
|
|
2
|
-
// is "is the
|
|
2
|
+
// is "is the peach desktop app installed on this machine". launch delegates
|
|
3
3
|
// to launchDesktopCompanion, which already handles mac `open -a`, linux
|
|
4
4
|
// AppImage, and the --device seed.
|
|
5
5
|
|
|
@@ -16,7 +16,7 @@ function probe(): DriverAvailability {
|
|
|
16
16
|
if (!install) {
|
|
17
17
|
return {
|
|
18
18
|
available: false,
|
|
19
|
-
reason: '
|
|
19
|
+
reason: 'peach desktop app not installed (run `peach desktop install`)',
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
return {
|
|
@@ -31,7 +31,7 @@ async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
|
|
|
31
31
|
if (!install) {
|
|
32
32
|
return {
|
|
33
33
|
launched: false,
|
|
34
|
-
message: '
|
|
34
|
+
message: 'peach desktop app not installed',
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
try {
|
|
@@ -63,7 +63,7 @@ async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
|
|
|
63
63
|
export const electronDriver: Driver = {
|
|
64
64
|
id: 'electron',
|
|
65
65
|
name: 'electron',
|
|
66
|
-
description: '
|
|
66
|
+
description: 'peach desktop companion app (native window, menu bar)',
|
|
67
67
|
kind: 'native',
|
|
68
68
|
availability: probe,
|
|
69
69
|
launch,
|
|
@@ -34,7 +34,7 @@ const callerUserDataDir = process.env.SOOTSIM_PW_USERDATADIR || '';
|
|
|
34
34
|
const ownerPid = Number(process.env.SOOTSIM_PW_OWNER_PID || 0);
|
|
35
35
|
const ownerPollMs = Number(process.env.SOOTSIM_PW_OWNER_POLL_MS || 5000);
|
|
36
36
|
// optional CDP port — exposes Chrome's remote-debugging endpoint so a
|
|
37
|
-
// bridge-driven sim can also be cpu-profiled (
|
|
37
|
+
// bridge-driven sim can also be cpu-profiled (peach perf cpu --cdp-port).
|
|
38
38
|
// playwright keeps its own pipe connection; the port is an additional endpoint.
|
|
39
39
|
const cdpPort = process.env.SOOTSIM_PW_CDP_PORT || '';
|
|
40
40
|
// extra chromium launch args, space-separated. a linux GPU runner injects
|
|
@@ -81,7 +81,7 @@ const resolveBrowserCompositeCdpClip = ${resolveBrowserCompositeCdpClip.toString
|
|
|
81
81
|
//
|
|
82
82
|
// the prior approach was \`pgrep -f ms-playwright/[c]hromium\`. it never matched
|
|
83
83
|
// system Chrome, so the reaper was a no-op in the common case and every
|
|
84
|
-
// aborted/closed \`
|
|
84
|
+
// aborted/closed \`peach open\` leaked a renderer + gpu helper burning 100%+
|
|
85
85
|
// CPU until manually killed (multiple incidents 2026-06).
|
|
86
86
|
//
|
|
87
87
|
// fix: identify our chrome tree by its UNIQUE user-data-dir. every helper a
|
|
@@ -94,13 +94,13 @@ const reapEnabled = process.platform !== 'win32';
|
|
|
94
94
|
let profileDir = callerUserDataDir;
|
|
95
95
|
let ephemeralProfile = false;
|
|
96
96
|
if (!profileDir) {
|
|
97
|
-
profileDir = mkdtempSync(join(tmpdir(), '
|
|
97
|
+
profileDir = mkdtempSync(join(tmpdir(), 'peach-playwright-host-'));
|
|
98
98
|
ephemeralProfile = true;
|
|
99
99
|
}
|
|
100
100
|
// browser HTTP caches are acceleration data, not profile identity. give each
|
|
101
101
|
// host a bounded temporary cache so persistent named profiles retain cookies
|
|
102
102
|
// and storage without multiplying a private cache for every profile.
|
|
103
|
-
const diskCacheDir = mkdtempSync(join(tmpdir(), '
|
|
103
|
+
const diskCacheDir = mkdtempSync(join(tmpdir(), 'peach-playwright-cache-'));
|
|
104
104
|
const chromePidsByProfile = () => {
|
|
105
105
|
if (!reapEnabled) return [];
|
|
106
106
|
try {
|
|
@@ -271,10 +271,10 @@ const cleanupProfile = () => {
|
|
|
271
271
|
// through shutdown(); the exit hook (sync sweep) still reaps the tree.
|
|
272
272
|
process.on('exit', () => { reapChrome(); cleanupProfile(); });
|
|
273
273
|
// owner-liveness watchdog — the load-bearing fix for leaked Chrome hosts.
|
|
274
|
-
// we are spawned detached + unref'd so \`
|
|
274
|
+
// we are spawned detached + unref'd so \`peach open\` returns immediately,
|
|
275
275
|
// which means nothing in the OS process tree ties Chrome's lifetime to the
|
|
276
276
|
// session that asked for it. once the sim connects, the connect-timeout
|
|
277
|
-
// safety net is cleared, so absent an explicit \`
|
|
277
|
+
// safety net is cleared, so absent an explicit \`peach close\` (or the
|
|
278
278
|
// daemon's idle reaper closing the sim socket) the host would hold Chrome
|
|
279
279
|
// open forever after its owner exits. poll the owning session's pid and tear
|
|
280
280
|
// down when it's gone. ESRCH (kill throws) = owner exited; EPERM = alive but
|
|
@@ -300,7 +300,7 @@ const cleanupProfile = () => {
|
|
|
300
300
|
// com.google.chrome.for.testing identity cannot intercept open/quit events for
|
|
301
301
|
// the user's com.google.Chrome browser. CI may use chromium_headless_shell;
|
|
302
302
|
// local rendering fails closed because that shell has no GPU and silently
|
|
303
|
-
// chooses SwiftShader. NOTE: this is NOT enough to make \`
|
|
303
|
+
// chooses SwiftShader. NOTE: this is NOT enough to make \`peach perf cpu\`
|
|
304
304
|
// work — that profiles the tenant *worker*, and the JS Self-Profiler API
|
|
305
305
|
// cannot be constructed in a dedicated worker (see
|
|
306
306
|
// worker-handlers/cpu-profile.ts). cpu-profile needs a CDP-based profiler
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
//
|
|
7
7
|
// the browser runs in a *detached* child process — this CLI re-invoked as
|
|
8
8
|
// its own `__internal playwright-host` (see cli/internal-child.ts) — rather
|
|
9
|
-
// than in this CLI process. that is load-bearing: `
|
|
9
|
+
// than in this CLI process. that is load-bearing: `peach open` returns the
|
|
10
10
|
// moment the sim connects, and playwright tears its browser down when the
|
|
11
11
|
// launching process exits. an in-process launch would mean the sim vanished
|
|
12
12
|
// the instant `open` finished. the detached host keeps the test browser alive
|
|
13
|
-
// until the sim's page closes (e.g. via `
|
|
13
|
+
// until the sim's page closes (e.g. via `peach close`).
|
|
14
14
|
|
|
15
15
|
import { spawn } from 'child_process'
|
|
16
16
|
import { closeSync, mkdtempSync, openSync, readFileSync } from 'fs'
|
|
@@ -68,7 +68,7 @@ function resolveUserDataDir(opts: DriverLaunchOptions): string {
|
|
|
68
68
|
return playwrightProfileUserDataDir(ensureProfile(opts.profileId).id)
|
|
69
69
|
}
|
|
70
70
|
if (opts.ephemeralProfile) {
|
|
71
|
-
return mkdtempSync(join(tmpdir(), '
|
|
71
|
+
return mkdtempSync(join(tmpdir(), 'peach-playwright-profile-'))
|
|
72
72
|
}
|
|
73
73
|
return ''
|
|
74
74
|
}
|
|
@@ -107,7 +107,7 @@ async function launch(opts: DriverLaunchOptions): Promise<DriverLaunchResult> {
|
|
|
107
107
|
const connectAckFile = `${errLog}.connected`
|
|
108
108
|
const errFd = openSync(errLog, 'a')
|
|
109
109
|
try {
|
|
110
|
-
// spawn the browser host detached so Chrome outlives `
|
|
110
|
+
// spawn the browser host detached so Chrome outlives `peach
|
|
111
111
|
// open`. stdout is dropped; stderr is captured to errLog so an early
|
|
112
112
|
// crash (bad profile dir, missing browser binary) produces a real
|
|
113
113
|
// message instead of a silent "timed out waiting for sim".
|
package/cli/drivers/registry.ts
CHANGED
|
@@ -37,7 +37,7 @@ export function resolveDriver(
|
|
|
37
37
|
return null
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// utility for the `
|
|
40
|
+
// utility for the `peach list --drivers` view. returns a rich row per
|
|
41
41
|
// driver with availability + kind + description, suitable for a table.
|
|
42
42
|
export interface DriverListRow {
|
|
43
43
|
id: DriverId
|
package/cli/drivers/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// driver / runner abstraction for
|
|
1
|
+
// driver / runner abstraction for peach. browser sims run in an isolated
|
|
2
2
|
// playwright-owned profile. electron remains the native desktop surface.
|
|
3
3
|
|
|
4
4
|
export type DriverId = 'electron' | 'playwright'
|
|
@@ -29,7 +29,7 @@ export interface DriverLaunchOptions {
|
|
|
29
29
|
url?: string
|
|
30
30
|
// run in headless mode where the driver supports it. ignored by electron.
|
|
31
31
|
headless?: boolean
|
|
32
|
-
// initial device model seed forwarded to the
|
|
32
|
+
// initial device model seed forwarded to the peach shell. the electron
|
|
33
33
|
// driver forwards it via argv (--device=<model>); browser drivers receive
|
|
34
34
|
// it already stamped on the URL (?device=<model>) by runOpenCommand.
|
|
35
35
|
device?: string
|
|
@@ -51,7 +51,7 @@ export interface DriverLaunchOptions {
|
|
|
51
51
|
// stable pid for the session that owns a CLI-opened host. electron closes
|
|
52
52
|
// only that session's windows when the owner exits; playwright requires it
|
|
53
53
|
// so a detached browser can never outlive its session. omitted only for the
|
|
54
|
-
// persistent `
|
|
54
|
+
// persistent `peach desktop` app lifecycle.
|
|
55
55
|
ownerPid?: number
|
|
56
56
|
// expose Chrome's remote-debugging endpoint on this port so a
|
|
57
57
|
// bridge-driven sim can also be cpu-profiled. only the playwright driver
|
|
@@ -60,7 +60,7 @@ export interface DriverLaunchOptions {
|
|
|
60
60
|
// maximum time the detached host should wait for the launched sim to
|
|
61
61
|
// register with the bridge before it tears itself down.
|
|
62
62
|
connectTimeoutMs?: number
|
|
63
|
-
// the
|
|
63
|
+
// the peach WS bridge port the launched sim page should register with,
|
|
64
64
|
// injected as window.__sootsimBridgePort. load-bearing when the dev bridge
|
|
65
65
|
// drifted off the shell-port-implied default (e.g. :7668 taken at the shell's
|
|
66
66
|
// boot -> bridge on :7669 while the shell kept :5173): the page's own
|
|
@@ -85,7 +85,7 @@ export interface DriverLaunchResult {
|
|
|
85
85
|
|
|
86
86
|
export interface Driver {
|
|
87
87
|
id: DriverId
|
|
88
|
-
// short human name shown in `
|
|
88
|
+
// short human name shown in `peach list --drivers`.
|
|
89
89
|
name: string
|
|
90
90
|
// one-line description. keep under 80 chars so the list command reads
|
|
91
91
|
// nicely at default terminal width.
|
package/cli/flow-export.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// store has to load wherever the CLI's runtime commands load, including inside
|
|
6
6
|
// a box shell running in workerd, where the `yaml` package does not load at
|
|
7
7
|
// all. YAML formatting and writing the file are the export step, and only
|
|
8
|
-
// `
|
|
8
|
+
// `peach flow` and `peach maestro` ever reach it.
|
|
9
9
|
|
|
10
10
|
import { mkdirSync, writeFileSync } from 'node:fs'
|
|
11
11
|
import { dirname, resolve } from 'node:path'
|
package/cli/flow-file.ts
CHANGED
|
@@ -2,14 +2,14 @@ import * as fs from 'fs'
|
|
|
2
2
|
import yaml from 'yaml'
|
|
3
3
|
|
|
4
4
|
export interface FlowFrontmatter {
|
|
5
|
-
// raw `
|
|
5
|
+
// raw `peach open` target: port, dev-server URL, bundle URL, or shell URL
|
|
6
6
|
app?: string | number
|
|
7
7
|
device?: string
|
|
8
8
|
// pin the sim color scheme for this flow run (screenshot baselines are
|
|
9
9
|
// theme-sensitive; a dark capture can never match a light baseline)
|
|
10
10
|
theme?: 'light' | 'dark'
|
|
11
11
|
electron?: boolean
|
|
12
|
-
// maestro-compatible: appId is accepted but not used by
|
|
12
|
+
// maestro-compatible: appId is accepted but not used by peach (ios bundle id)
|
|
13
13
|
appId?: string
|
|
14
14
|
// maestro-compatible: flow-level env vars, defined into the flow's JS
|
|
15
15
|
// context before the first step runs
|
|
@@ -27,10 +27,10 @@ export interface FlowFrontmatter {
|
|
|
27
27
|
|
|
28
28
|
// parse flow file. accepts three shapes:
|
|
29
29
|
// 1. plain yaml array of steps (no frontmatter)
|
|
30
|
-
// 2.
|
|
30
|
+
// 2. peach style: ---\n<fm>\n---\n<steps>
|
|
31
31
|
// 3. maestro style: <fm>\n---\n<steps> (multi-doc yaml, fm first)
|
|
32
32
|
// maestro compat matters because real users have real .maestro/*.yaml files
|
|
33
|
-
// and shouldn't have to rewrite them to drive
|
|
33
|
+
// and shouldn't have to rewrite them to drive peach.
|
|
34
34
|
//
|
|
35
35
|
// `${...}` templates are NOT resolved here — interpolation happens per-step
|
|
36
36
|
// at execution time in the flow runner's JS context (matching maestro), so
|
|
@@ -123,7 +123,7 @@ export function validateFlowSteps(steps: any[]): string[] {
|
|
|
123
123
|
// structural-only validator used by CI runners before uploading the flow
|
|
124
124
|
// artifact. we only check: file exists, parseable yaml, has at least one
|
|
125
125
|
// real interaction step. playback validation is a separate concern handled
|
|
126
|
-
// by `
|
|
126
|
+
// by `peach maestro end --validate` during the authoring session.
|
|
127
127
|
export function validateFlowFile(flowPath: string): string[] {
|
|
128
128
|
if (!fs.existsSync(flowPath)) {
|
|
129
129
|
return [`file not found: ${flowPath}`]
|
package/cli/flow-session.ts
CHANGED
|
@@ -23,7 +23,7 @@ const FLOW_SESSION_VERSION = 1 as const
|
|
|
23
23
|
|
|
24
24
|
export function getFlowSessionPath() {
|
|
25
25
|
return resolve(
|
|
26
|
-
process.env.
|
|
26
|
+
process.env.PEACH_FLOW_SESSION_PATH || join(tmpdir(), 'peach-flow-session.json'),
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
|
package/cli/help-core.ts
CHANGED
|
@@ -38,10 +38,10 @@ function backendLabel(command: string, args: readonly string[]): string {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function renderPreviewHelp(command: 'web' | 'ios' | 'android'): string {
|
|
41
|
-
return `
|
|
41
|
+
return `peach ${command} — select or ensure the current branch's existing ${command} preview
|
|
42
42
|
|
|
43
43
|
usage:
|
|
44
|
-
|
|
44
|
+
peach ${command}
|
|
45
45
|
|
|
46
46
|
The browser backend selects the Factory-owned ${command} iframe. It never launches a
|
|
47
47
|
host process or Cloudflare runtime.`
|
|
@@ -51,19 +51,19 @@ function renderFactoryBrowserLeaves(command: string): string | null {
|
|
|
51
51
|
switch (command) {
|
|
52
52
|
case 'do':
|
|
53
53
|
return `Factory browser leaves:
|
|
54
|
-
|
|
54
|
+
peach do navigate /route`
|
|
55
55
|
case 'shell':
|
|
56
56
|
return `Factory browser leaves:
|
|
57
|
-
|
|
57
|
+
peach shell appearance light|dark`
|
|
58
58
|
case 'assert':
|
|
59
59
|
return `Factory browser leaves:
|
|
60
|
-
|
|
60
|
+
peach assert find (--testid <id>|--text <text>|--role <role>) [--exists|--empty] [--contains <text>]`
|
|
61
61
|
case 'screenshot':
|
|
62
62
|
return `Factory browser leaves:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
peach screenshot
|
|
64
|
+
peach screenshot ask <question>
|
|
65
|
+
peach screenshot appearance light|dark /route --by <query-kind> --value <target>
|
|
66
|
+
peach screenshot motion <task-id> /route --trigger-by <kind> --trigger-value <target> --result-by <kind> --result-value <target> [--duration-ms <100..2000>]`
|
|
67
67
|
default:
|
|
68
68
|
return null
|
|
69
69
|
}
|
|
@@ -90,7 +90,7 @@ function renderRootAvailability(backend: RnxBackendKind): string {
|
|
|
90
90
|
available: ${available.join(', ')}
|
|
91
91
|
unavailable: ${unavailable.join(', ')}
|
|
92
92
|
|
|
93
|
-
Run \`
|
|
93
|
+
Run \`peach <command> --help\` for leaf availability and usage.`
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
export function renderRnxHelp(options: RnxHelpOptions): string {
|
|
@@ -100,9 +100,9 @@ export function renderRnxHelp(options: RnxHelpOptions): string {
|
|
|
100
100
|
return `${renderCliIndexHelp(HELP_CONTEXT, formatFlagHelp()).trimEnd()}
|
|
101
101
|
|
|
102
102
|
browser preview selectors:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
peach web select the existing Factory web preview
|
|
104
|
+
peach ios select the existing Factory iOS preview
|
|
105
|
+
peach android select the existing Factory Android preview
|
|
106
106
|
|
|
107
107
|
${renderRootAvailability(options.backend)}`
|
|
108
108
|
}
|
package/cli/hints.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// configurable, identity-scoped hint registry for the
|
|
1
|
+
// configurable, identity-scoped hint registry for the peach CLI.
|
|
2
2
|
//
|
|
3
3
|
// two problems this solves:
|
|
4
4
|
// 1. the CLI scatters "hint: ..." console.logs across many command files,
|
|
@@ -46,11 +46,11 @@ interface HintStateFile {
|
|
|
46
46
|
const STATE_VERSION = 1 as const
|
|
47
47
|
|
|
48
48
|
function identityStatePath(): string {
|
|
49
|
-
return join(tmpdir(), `
|
|
49
|
+
return join(tmpdir(), `peach-cli-hints-${getCliIdentityKey()}.json`)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function globalStatePath(): string {
|
|
53
|
-
return join(tmpdir(), `
|
|
53
|
+
return join(tmpdir(), `peach-cli-hints-global.json`)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
function readState(path: string): HintStateFile {
|
|
@@ -76,7 +76,7 @@ function writeState(path: string, state: HintStateFile) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function modeFromEnv(): 'normal' | 'always' | 'off' {
|
|
79
|
-
const v = (process.env.
|
|
79
|
+
const v = (process.env.PEACH_HINTS || '').toLowerCase()
|
|
80
80
|
if (v === 'off' || v === '0' || v === 'false') return 'off'
|
|
81
81
|
if (v === 'always' || v === 'verbose') return 'always'
|
|
82
82
|
return 'normal'
|
|
@@ -119,7 +119,7 @@ function shouldShow(id: string, frequency: HintFrequency): boolean {
|
|
|
119
119
|
export function maybeHint(id: string, ...args: unknown[]): boolean {
|
|
120
120
|
const spec = registry.get(id)
|
|
121
121
|
if (!spec) {
|
|
122
|
-
if (process.env.
|
|
122
|
+
if (process.env.PEACH_HINTS_DEBUG) {
|
|
123
123
|
console.error(` [hints] no hint registered for id "${id}"`)
|
|
124
124
|
}
|
|
125
125
|
return false
|
|
@@ -158,13 +158,13 @@ defineHint<[number]>('app-still-loading', {
|
|
|
158
158
|
// bundle boots — telling the user about it again is useful, not noisy.
|
|
159
159
|
frequency: { cooldownMs: 60_000 },
|
|
160
160
|
render: (nodeCount) =>
|
|
161
|
-
`app may still be loading (${nodeCount} nodes). run \`
|
|
161
|
+
`app may still be loading (${nodeCount} nodes). run \`peach wait ready\` first.`,
|
|
162
162
|
})
|
|
163
163
|
|
|
164
164
|
defineHint<[string]>('wait-selector-for-missing-testid', {
|
|
165
165
|
// advice is stable; once per CLI identity is enough.
|
|
166
166
|
frequency: 'once-per-identity',
|
|
167
|
-
render: (testId) => `
|
|
167
|
+
render: (testId) => `peach wait selector ${testId}`,
|
|
168
168
|
})
|
|
169
169
|
|
|
170
170
|
defineHint<[string[]]>('prefer-cli-over-eval', {
|
|
@@ -181,9 +181,9 @@ defineHint<[]>('describe-use-filters', {
|
|
|
181
181
|
frequency: 'once-per-identity',
|
|
182
182
|
render: () => [
|
|
183
183
|
`describe output is long. narrow it with:`,
|
|
184
|
-
`
|
|
185
|
-
`
|
|
186
|
-
`
|
|
184
|
+
` peach describe --only '*Bottom Sheet*'`,
|
|
185
|
+
` peach describe --testid-like 'swap-*'`,
|
|
186
|
+
` peach describe --subtree <testID>`,
|
|
187
187
|
],
|
|
188
188
|
})
|
|
189
189
|
|
|
@@ -194,21 +194,21 @@ defineHint<[]>('describe-filter-context', {
|
|
|
194
194
|
frequency: 'once-per-identity',
|
|
195
195
|
render: () => [
|
|
196
196
|
`filtered describe is search output, not current-route proof.`,
|
|
197
|
-
`run \`
|
|
197
|
+
`run \`peach describe\` without filters after navigation; clipped nodes are marked \`(clipped:...)\`.`,
|
|
198
198
|
],
|
|
199
199
|
})
|
|
200
200
|
|
|
201
201
|
defineHint<[string]>('subtree-root-not-found', {
|
|
202
202
|
frequency: 'always',
|
|
203
203
|
render: (id) =>
|
|
204
|
-
`no node with testID/id "${id}" — try \`
|
|
204
|
+
`no node with testID/id "${id}" — try \`peach find --testid ${id}\` to discover available ids.`,
|
|
205
205
|
})
|
|
206
206
|
|
|
207
207
|
defineHint<[]>('clean-uninstall', {
|
|
208
|
-
// shown once on the first `
|
|
208
|
+
// shown once on the first `peach --help` run so users learn the teardown path.
|
|
209
209
|
frequency: 'once-ever',
|
|
210
210
|
render: () => [
|
|
211
|
-
`to remove the background daemon, run \`
|
|
211
|
+
`to remove the background daemon, run \`peach daemon uninstall\`. it keeps your runtimes and device profiles; add \`--purge\` to delete ~/.peach too.`,
|
|
212
212
|
`the optional desktop app and its macOS preference plist are separate from the daemon.`,
|
|
213
213
|
],
|
|
214
214
|
})
|
|
@@ -23,7 +23,7 @@ interface InspectNoticeState {
|
|
|
23
23
|
export function getInspectNoticeStatePath() {
|
|
24
24
|
return resolve(
|
|
25
25
|
process.env[INSPECT_NOTICE_PATH_ENV] ||
|
|
26
|
-
join(tmpdir(), '
|
|
26
|
+
join(tmpdir(), 'peach-inspect-notice-state.json'),
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
|
package/cli/internal-child.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// hidden child-process entry points.
|
|
2
2
|
//
|
|
3
3
|
// the CLI needs separate JS processes for a few jobs: a detached browser host
|
|
4
|
-
// that outlives `
|
|
4
|
+
// that outlives `peach open`, playwright's own installer, and a blocking fetch
|
|
5
5
|
// worker for maestro's synchronous `http` API. each used to run as
|
|
6
6
|
// `process.execPath -e '<source>'`, which cannot work once the CLI ships as a
|
|
7
|
-
// compiled binary: there process.execPath is
|
|
7
|
+
// compiled binary: there process.execPath is peach, and peach has no -e. a
|
|
8
8
|
// shell-installed user has no node and no bun either, so there is nothing else
|
|
9
9
|
// to reach for. the binary is the JS runtime, and it runs these itself.
|
|
10
10
|
//
|
package/cli/maestro-js.ts
CHANGED
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
// time (maestro-orchestra-models util/Env.kt): regex (?<!\\)\$\{([^$]*)},
|
|
15
15
|
// result stringified, `\${...}` escapes to a literal, blank exprs become ''.
|
|
16
16
|
//
|
|
17
|
-
// divergences (deliberate,
|
|
17
|
+
// divergences (deliberate, peach-side ergonomics — keep this list short):
|
|
18
18
|
// 1. envBinding is seeded from the full process.env, not just MAESTRO_*.
|
|
19
|
-
//
|
|
20
|
-
// shell environment and `
|
|
19
|
+
// peach flows historically resolve `${SOOTSIM_*}` credentials from the
|
|
20
|
+
// shell environment and `peach maestro --env K=V` writes process.env.
|
|
21
21
|
// 2. a *bare identifier* template (`${NAME}`) that evaluates to undefined
|
|
22
22
|
// throws a loud "missing variable" error instead of interpolating the
|
|
23
23
|
// literal text "undefined" into a tap target or login form. complex
|
|
@@ -45,7 +45,7 @@ function executeSyncHttp(
|
|
|
45
45
|
params?: HttpParams,
|
|
46
46
|
): { ok: boolean; status: number; body: string; headers: Record<string, string> } {
|
|
47
47
|
if (params?.multipartForm) {
|
|
48
|
-
throw new Error('http: multipartForm is not supported by
|
|
48
|
+
throw new Error('http: multipartForm is not supported by peach yet')
|
|
49
49
|
}
|
|
50
50
|
// maestro's `http` API is synchronous (flows do `var res = http.post(...)`)
|
|
51
51
|
// and there is no synchronous fetch, so each request round-trips through a
|
package/cli/maestro-report.ts
CHANGED
|
@@ -166,7 +166,7 @@ export function buildSessionLog(input: {
|
|
|
166
166
|
}): string {
|
|
167
167
|
const passed = input.flows.filter((flow) => flow.passed).length
|
|
168
168
|
const lines = [
|
|
169
|
-
'#
|
|
169
|
+
'# peach maestro session log',
|
|
170
170
|
`# started: ${input.startedAtIso}`,
|
|
171
171
|
`# root: ${input.root}`,
|
|
172
172
|
`# device: ${input.device}`,
|