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
|
-
// installs the standalone
|
|
1
|
+
// installs the standalone peach executable into the user's command path.
|
|
2
2
|
//
|
|
3
3
|
// the public shell installer owns download and checksum verification. this
|
|
4
4
|
// command mirrors its local mutation after those bytes are trusted, while the
|
|
@@ -32,13 +32,13 @@ type CliInstallOptions = {
|
|
|
32
32
|
export async function runCliInstall(args: string[]): Promise<void> {
|
|
33
33
|
const options = parseCliInstallOptions(args)
|
|
34
34
|
if (!IS_STANDALONE) {
|
|
35
|
-
throw new Error('
|
|
35
|
+
throw new Error('peach cli install requires the standalone peach executable')
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const target = installedCliPath()
|
|
39
39
|
if (!options.alreadyInstalled) installCurrentExecutable(target)
|
|
40
40
|
else if (!existsSync(target)) {
|
|
41
|
-
throw new Error(`
|
|
41
|
+
throw new Error(`peach cli install expected ${target} to exist`)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const profile = installCommandPath(target)
|
|
@@ -57,20 +57,20 @@ export async function runCliInstall(args: string[]): Promise<void> {
|
|
|
57
57
|
function parseCliInstallOptions(args: string[]): CliInstallOptions {
|
|
58
58
|
const [subcommand] = args
|
|
59
59
|
if (subcommand === '--help' || subcommand === '-h') {
|
|
60
|
-
console.log(`\
|
|
60
|
+
console.log(`\npeach cli install - install the peach command in your PATH
|
|
61
61
|
|
|
62
62
|
usage:
|
|
63
|
-
|
|
63
|
+
peach cli install
|
|
64
64
|
|
|
65
65
|
internal options:
|
|
66
|
-
--installed update shell startup after an installer copied
|
|
66
|
+
--installed update shell startup after an installer copied peach
|
|
67
67
|
--handoff-pid <pid> replace this desktop-owned daemon with the service
|
|
68
68
|
--port <port> daemon bridge port to preserve during handoff
|
|
69
69
|
`)
|
|
70
70
|
process.exit(0)
|
|
71
71
|
}
|
|
72
72
|
if (subcommand !== 'install') {
|
|
73
|
-
throw new Error('usage:
|
|
73
|
+
throw new Error('usage: peach cli install')
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
const handoffPid = readHandoffPid(args)
|
|
@@ -109,14 +109,14 @@ function readPort(args: string[]): number | null {
|
|
|
109
109
|
|
|
110
110
|
function installedCliPath(): string {
|
|
111
111
|
const home = process.env.HOME || homedir()
|
|
112
|
-
const prefix = process.env.
|
|
113
|
-
return join(prefix, 'bin', process.platform === 'win32' ? '
|
|
112
|
+
const prefix = process.env.PEACH_CLI_PREFIX || join(home, '.local')
|
|
113
|
+
return join(prefix, 'bin', process.platform === 'win32' ? 'peach.exe' : 'peach')
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
function installCurrentExecutable(target: string): void {
|
|
117
117
|
if (process.execPath === target) return
|
|
118
118
|
mkdirSync(dirname(target), { recursive: true })
|
|
119
|
-
const temporary = join(dirname(target), `.
|
|
119
|
+
const temporary = join(dirname(target), `.peach-install-${process.pid}`)
|
|
120
120
|
try {
|
|
121
121
|
copyFileSync(process.execPath, temporary)
|
|
122
122
|
chmodSync(temporary, 0o755)
|
|
@@ -152,7 +152,7 @@ function installCommandPath(target: string): string | null {
|
|
|
152
152
|
{ encoding: 'utf8' },
|
|
153
153
|
)
|
|
154
154
|
if (result.status !== 0) {
|
|
155
|
-
throw new Error(`could not add
|
|
155
|
+
throw new Error(`could not add peach to the user PATH: ${result.stderr.trim()}`)
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
return 'the user PATH'
|
|
@@ -167,14 +167,14 @@ function installCommandPath(target: string): string | null {
|
|
|
167
167
|
)
|
|
168
168
|
const bin = dirname(target)
|
|
169
169
|
const pathLine = `export PATH="${bin}:$PATH"`
|
|
170
|
-
const integration = shellName ? `eval "$(command
|
|
170
|
+
const integration = shellName ? `eval "$(command peach __shell-init ${shellName})"` : ''
|
|
171
171
|
const current = existsSync(profile) ? readFileSync(profile, 'utf8') : ''
|
|
172
172
|
if (current.includes(pathLine) && (!integration || current.includes(integration)))
|
|
173
173
|
return null
|
|
174
174
|
|
|
175
175
|
const additions = [
|
|
176
176
|
'',
|
|
177
|
-
'# added by the
|
|
177
|
+
'# added by the peach installer; delete this block to remove peach from your shell',
|
|
178
178
|
...(current.includes(pathLine) ? [] : [pathLine]),
|
|
179
179
|
...(integration && !current.includes(integration) ? [integration] : []),
|
|
180
180
|
]
|
|
@@ -223,7 +223,7 @@ async function handOffDaemon({
|
|
|
223
223
|
)
|
|
224
224
|
if (result.status !== 0) {
|
|
225
225
|
throw new Error(
|
|
226
|
-
`could not register the
|
|
226
|
+
`could not register the peach daemon: ${(result.stderr || result.stdout || 'unknown error').trim()}`,
|
|
227
227
|
)
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -232,10 +232,10 @@ async function handOffDaemon({
|
|
|
232
232
|
const lock = readDaemonLockfile()
|
|
233
233
|
return isDaemonLockfileFresh(lock) && lock.pid !== pid && lock.bridgePort === port
|
|
234
234
|
},
|
|
235
|
-
'the installed
|
|
235
|
+
'the installed peach daemon to start',
|
|
236
236
|
deadline,
|
|
237
237
|
)
|
|
238
|
-
console.log(' desktop daemon: handed off to the installed
|
|
238
|
+
console.log(' desktop daemon: handed off to the installed peach command')
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
async function waitFor(
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach desktop install — download and install the optional desktop GUI
|
|
2
2
|
//
|
|
3
|
-
// the CLI + daemon are the canonical
|
|
3
|
+
// the CLI + daemon are the canonical peach surface; this command is only
|
|
4
4
|
// for users who want the Electron-based GUI companion on top of that.
|
|
5
5
|
//
|
|
6
6
|
// fetches the right platform artifact from https://contrast.dev/api/electron-release/
|
|
7
7
|
// and installs it into the OS-native location that findDesktopCompanion() looks for:
|
|
8
|
-
// macos: ~/Applications/
|
|
9
|
-
// linux: ~/Applications/
|
|
8
|
+
// macos: ~/Applications/peach.app (or /Applications if writable)
|
|
9
|
+
// linux: ~/Applications/peach.AppImage
|
|
10
10
|
// win: spawns the NSIS installer
|
|
11
11
|
//
|
|
12
12
|
// post-install the electron-updater feed (same URL) handles upgrades inside the
|
|
@@ -45,7 +45,7 @@ function detectTarget(): Target | null {
|
|
|
45
45
|
const arch = process.arch
|
|
46
46
|
if (process.platform === 'darwin') {
|
|
47
47
|
const platform: TargetPlatform = arch === 'arm64' ? 'mac-arm64' : 'mac-x64'
|
|
48
|
-
const filename = `
|
|
48
|
+
const filename = `peach-latest-${platform}.dmg`
|
|
49
49
|
return {
|
|
50
50
|
platform,
|
|
51
51
|
filename,
|
|
@@ -60,7 +60,7 @@ function detectTarget(): Target | null {
|
|
|
60
60
|
// /lib64/ld-linux-x86-64.so.2". detect the running arch and pick the
|
|
61
61
|
// matching artifact.
|
|
62
62
|
const platform: TargetPlatform = arch === 'arm64' ? 'linux-arm64' : 'linux-x64'
|
|
63
|
-
const filename = `
|
|
63
|
+
const filename = `peach-latest-${platform}.AppImage`
|
|
64
64
|
return {
|
|
65
65
|
platform,
|
|
66
66
|
filename,
|
|
@@ -69,7 +69,7 @@ function detectTarget(): Target | null {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
if (process.platform === 'win32') {
|
|
72
|
-
const filename = `
|
|
72
|
+
const filename = `peach-latest-win-x64.exe`
|
|
73
73
|
return {
|
|
74
74
|
platform: 'win-x64',
|
|
75
75
|
filename,
|
|
@@ -148,10 +148,10 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
148
148
|
throw new Error(`could not determine dmg mount point (output: ${mountOutput.stdout})`)
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
const appSource = join(mountPoint, '
|
|
151
|
+
const appSource = join(mountPoint, 'peach.app')
|
|
152
152
|
if (!existsSync(appSource)) {
|
|
153
153
|
spawnSync('hdiutil', ['detach', '-force', mountPoint])
|
|
154
|
-
throw new Error(`
|
|
154
|
+
throw new Error(`peach.app not found inside ${mountPoint}`)
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
// prefer /Applications if writable, otherwise ~/Applications (same paths
|
|
@@ -160,7 +160,7 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
160
160
|
const userApps = resolve(process.env.HOME || '', 'Applications')
|
|
161
161
|
let destRoot = systemApps
|
|
162
162
|
try {
|
|
163
|
-
const probe = join(systemApps, `.
|
|
163
|
+
const probe = join(systemApps, `.peach-write-probe-${process.pid}`)
|
|
164
164
|
spawnSync('touch', [probe])
|
|
165
165
|
if (existsSync(probe)) rmSync(probe, { force: true })
|
|
166
166
|
else destRoot = userApps
|
|
@@ -171,13 +171,13 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
171
171
|
mkdirSync(destRoot, { recursive: true })
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
const appDest = join(destRoot, '
|
|
174
|
+
const appDest = join(destRoot, 'peach.app')
|
|
175
175
|
|
|
176
176
|
// copy alongside the destination and swap, rather than deleting the installed
|
|
177
177
|
// app first. removing it up front means a failed copy leaves the user with no
|
|
178
178
|
// app at all, having destroyed a working install to do it. the staging path is
|
|
179
179
|
// in the same directory so the swap is a rename on one volume.
|
|
180
|
-
const staging = join(destRoot, `.
|
|
180
|
+
const staging = join(destRoot, `.peach-incoming-${process.pid}.app`)
|
|
181
181
|
rmSync(staging, { recursive: true, force: true })
|
|
182
182
|
|
|
183
183
|
const copy = spawnSync('cp', ['-R', appSource, staging])
|
|
@@ -188,7 +188,7 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
188
188
|
}
|
|
189
189
|
const detach = spawnSync('hdiutil', ['detach', '-force', mountPoint])
|
|
190
190
|
|
|
191
|
-
const previous = join(destRoot, `.
|
|
191
|
+
const previous = join(destRoot, `.peach-previous-${process.pid}.app`)
|
|
192
192
|
if (existsSync(appDest)) {
|
|
193
193
|
const park = spawnSync('mv', [appDest, previous])
|
|
194
194
|
if (park.status !== 0) {
|
|
@@ -225,7 +225,7 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
225
225
|
async function installLinuxAppImage(appImagePath: string): Promise<string> {
|
|
226
226
|
const destDir = resolve(process.env.HOME || '', 'Applications')
|
|
227
227
|
mkdirSync(destDir, { recursive: true })
|
|
228
|
-
const dest = join(destDir, '
|
|
228
|
+
const dest = join(destDir, 'peach.AppImage')
|
|
229
229
|
if (existsSync(dest)) rmSync(dest, { force: true })
|
|
230
230
|
// copyFile + unlink instead of rename: /tmp and ~/Applications are
|
|
231
231
|
// routinely on separate mounts in containers / VMs, where renameSync
|
|
@@ -251,7 +251,7 @@ async function installWindowsExe(exePath: string): Promise<string> {
|
|
|
251
251
|
})
|
|
252
252
|
const installed = findDesktopCompanion()
|
|
253
253
|
if (!installed) {
|
|
254
|
-
throw new Error('the installer finished but the
|
|
254
|
+
throw new Error('the installer finished but the peach application was not registered')
|
|
255
255
|
}
|
|
256
256
|
return installed.path
|
|
257
257
|
}
|
|
@@ -259,21 +259,21 @@ async function installWindowsExe(exePath: string): Promise<string> {
|
|
|
259
259
|
export async function runInstallDesktop(args: string[]) {
|
|
260
260
|
if (args.includes('--help') || args.includes('-h')) {
|
|
261
261
|
console.log(`
|
|
262
|
-
|
|
262
|
+
peach desktop install
|
|
263
263
|
|
|
264
|
-
Download and install the optional
|
|
264
|
+
Download and install the optional peach Desktop app.
|
|
265
265
|
The CLI works without it. Choose Desktop when you want a dedicated native window.
|
|
266
266
|
|
|
267
267
|
usage:
|
|
268
|
-
|
|
268
|
+
peach desktop install [options]
|
|
269
269
|
|
|
270
270
|
options:
|
|
271
271
|
-y, --yes skip confirmation and install immediately
|
|
272
272
|
--force reinstall even if the companion is already present
|
|
273
273
|
|
|
274
274
|
examples:
|
|
275
|
-
|
|
276
|
-
|
|
275
|
+
peach desktop install
|
|
276
|
+
peach desktop install --yes
|
|
277
277
|
`)
|
|
278
278
|
rnxExit(0)
|
|
279
279
|
}
|
|
@@ -281,7 +281,7 @@ examples:
|
|
|
281
281
|
const skipConfirm =
|
|
282
282
|
args.includes('--yes') ||
|
|
283
283
|
args.includes('-y') ||
|
|
284
|
-
process.env.
|
|
284
|
+
process.env.PEACH_NO_PROMPT === '1' ||
|
|
285
285
|
process.env.CI === '1' ||
|
|
286
286
|
!process.stdin.isTTY
|
|
287
287
|
const force = args.includes('--force')
|
|
@@ -318,7 +318,7 @@ examples:
|
|
|
318
318
|
console.log()
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
const workDir = join(tmpdir(), `
|
|
321
|
+
const workDir = join(tmpdir(), `peach-install-${Date.now()}`)
|
|
322
322
|
const downloadPath = join(workDir, target.filename)
|
|
323
323
|
|
|
324
324
|
let lastDraw = 0
|
|
@@ -347,7 +347,7 @@ examples:
|
|
|
347
347
|
console.error(
|
|
348
348
|
' network blocked the request. Check your connection and try again later.',
|
|
349
349
|
)
|
|
350
|
-
console.error(' The CLI and daemon work without the desktop app. Run `
|
|
350
|
+
console.error(' The CLI and daemon work without the desktop app. Run `peach --help`.')
|
|
351
351
|
rnxExit(1)
|
|
352
352
|
}
|
|
353
353
|
|
|
@@ -371,7 +371,7 @@ examples:
|
|
|
371
371
|
// drag rather than leaving them at a dead end. keep workDir for that.
|
|
372
372
|
if (process.platform === 'darwin') {
|
|
373
373
|
spawnSync('open', [downloadPath])
|
|
374
|
-
console.error(` Opened ${target.filename} — drag
|
|
374
|
+
console.error(` Opened ${target.filename} — drag peach to Applications to finish.`)
|
|
375
375
|
} else {
|
|
376
376
|
console.error(` Keeping the download at ${downloadPath} for manual installation.`)
|
|
377
377
|
}
|
|
@@ -380,6 +380,6 @@ examples:
|
|
|
380
380
|
|
|
381
381
|
console.log()
|
|
382
382
|
console.log(` ${bold('Ready')}`)
|
|
383
|
-
console.log('
|
|
384
|
-
console.log('
|
|
383
|
+
console.log(' peach desktop Launch the desktop app')
|
|
384
|
+
console.log(' peach open <target> Open a demo or bundle in it')
|
|
385
385
|
}
|
package/cli/commands/login.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
12
12
|
import { rnxExit } from '../run-rnx'
|
|
13
13
|
|
|
14
|
-
const REMOTE_DEFAULT_ORIGIN = process.env.
|
|
14
|
+
const REMOTE_DEFAULT_ORIGIN = process.env.PEACH_AUTH_ORIGIN || 'https://contrast.dev'
|
|
15
15
|
|
|
16
16
|
type LoginResult =
|
|
17
17
|
| { ok: true; token: string; userId?: string; email?: string }
|
|
@@ -19,21 +19,21 @@ type LoginResult =
|
|
|
19
19
|
|
|
20
20
|
function resolveDefaultAuthOrigin(explicitOrigin?: string) {
|
|
21
21
|
if (explicitOrigin) return explicitOrigin
|
|
22
|
-
if (process.env.
|
|
23
|
-
if (process.env.
|
|
22
|
+
if (process.env.PEACH_AUTH_ORIGIN) return process.env.PEACH_AUTH_ORIGIN
|
|
23
|
+
if (process.env.PEACH_UPLOAD_ORIGIN) return process.env.PEACH_UPLOAD_ORIGIN
|
|
24
24
|
return REMOTE_DEFAULT_ORIGIN
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function printHelp() {
|
|
28
28
|
console.log(`
|
|
29
|
-
|
|
29
|
+
peach login — sign in so uploads can attach to your account
|
|
30
30
|
|
|
31
31
|
usage:
|
|
32
|
-
|
|
32
|
+
peach login [--origin <url>] [--account <name-or-id>]
|
|
33
33
|
|
|
34
34
|
options:
|
|
35
35
|
--origin <url> auth host (default: ${REMOTE_DEFAULT_ORIGIN})
|
|
36
|
-
override with
|
|
36
|
+
override with PEACH_AUTH_ORIGIN env var
|
|
37
37
|
--account <name-or-id> the account remote simulators and boxes bill to.
|
|
38
38
|
one account is chosen for you; several ask.
|
|
39
39
|
-h, --help
|
|
@@ -182,7 +182,7 @@ function isLocalOrigin(origin: string): boolean {
|
|
|
182
182
|
if (hostname.endsWith('.local')) return true
|
|
183
183
|
if (hostname.endsWith('.localhost')) return true
|
|
184
184
|
// VM↔host bridge aliases — orb, docker, lima, multipass all forward the
|
|
185
|
-
// host on a well-known name (IPv4 or IPv6) so a VM-internal `
|
|
185
|
+
// host on a well-known name (IPv4 or IPv6) so a VM-internal `peach login`
|
|
186
186
|
// can still take the dev-login fast path against the host's Contrast dev
|
|
187
187
|
// server. without this the CLI falls through to a browser callback that
|
|
188
188
|
// is unreachable from a headless VM.
|
|
@@ -288,7 +288,7 @@ export async function runLogin(args: string[]) {
|
|
|
288
288
|
|
|
289
289
|
if (!token) {
|
|
290
290
|
res.end(
|
|
291
|
-
renderCallbackPage('missing token. close this tab and retry `
|
|
291
|
+
renderCallbackPage('missing token. close this tab and retry `peach login`.'),
|
|
292
292
|
)
|
|
293
293
|
finish({ ok: false, error: 'missing token' })
|
|
294
294
|
return
|
|
@@ -298,7 +298,7 @@ export async function runLogin(args: string[]) {
|
|
|
298
298
|
finish({ ok: true, token, email, userId })
|
|
299
299
|
} catch (err) {
|
|
300
300
|
res.statusCode = 500
|
|
301
|
-
res.end(renderCallbackPage('sign-in callback failed. retry `
|
|
301
|
+
res.end(renderCallbackPage('sign-in callback failed. retry `peach login`.'))
|
|
302
302
|
finish({
|
|
303
303
|
ok: false,
|
|
304
304
|
error: err instanceof Error ? err.message : 'callback failed',
|
|
@@ -310,7 +310,7 @@ export async function runLogin(args: string[]) {
|
|
|
310
310
|
finish({
|
|
311
311
|
ok: false,
|
|
312
312
|
error:
|
|
313
|
-
'timed out waiting for the browser sign-in (5 minutes). rerun `
|
|
313
|
+
'timed out waiting for the browser sign-in (5 minutes). rerun `peach login` and complete the github authorize screen if it appears.',
|
|
314
314
|
})
|
|
315
315
|
}, LOGIN_TIMEOUT_MS)
|
|
316
316
|
|
|
@@ -326,7 +326,7 @@ export async function runLogin(args: string[]) {
|
|
|
326
326
|
url.searchParams.set('port', String(address.port))
|
|
327
327
|
url.searchParams.set('contrast', origin)
|
|
328
328
|
|
|
329
|
-
console.log(' opening browser for
|
|
329
|
+
console.log(' opening browser for peach login...')
|
|
330
330
|
console.log(
|
|
331
331
|
' first time here? github will show an authorize screen. approve it to continue.',
|
|
332
332
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// plain-language Maestro authoring for `
|
|
1
|
+
// plain-language Maestro authoring for `peach maestro generate`.
|
|
2
2
|
|
|
3
3
|
import { mkdtempSync, writeFileSync } from 'fs'
|
|
4
4
|
import { tmpdir } from 'os'
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { inspectDescribe } from './inspect/core'
|
|
20
20
|
import { resolveDefaultUploadOrigin } from './upload'
|
|
21
21
|
|
|
22
|
-
const DEFAULT_TEST_MODEL = process.env.
|
|
22
|
+
const DEFAULT_TEST_MODEL = process.env.PEACH_TEST_MODEL || 'deepseek-v4-flash'
|
|
23
23
|
const DESCRIBE_CONTEXT_LIMIT = 18_000
|
|
24
24
|
const LLM_TIMEOUT_MS = 180_000
|
|
25
25
|
|
|
@@ -96,7 +96,7 @@ async function describeCurrentSim(args: string[], promptIndex: number): Promise<
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
const RNX_TEST_SYSTEM_PROMPT = `
|
|
99
|
-
You write Maestro-compatible
|
|
99
|
+
You write Maestro-compatible peach YAML flows from a user's plain-language test goal.
|
|
100
100
|
Return only JSON, no markdown, with this exact shape:
|
|
101
101
|
{"summary":"short human-readable result goal","steps":[{"waitFor":{"text":"...","timeout":10000}}]}
|
|
102
102
|
|
|
@@ -122,7 +122,7 @@ function buildPromptRequest(prompt: string, describe: string): string {
|
|
|
122
122
|
User goal:
|
|
123
123
|
${prompt}
|
|
124
124
|
|
|
125
|
-
Current
|
|
125
|
+
Current peach visible tree:
|
|
126
126
|
${describe || '[no tree available]'}
|
|
127
127
|
|
|
128
128
|
Generate the shortest replayable flow that verifies the goal from this current state.
|
|
@@ -224,7 +224,7 @@ function parseGeneratedFlow(text: string): {
|
|
|
224
224
|
const summary =
|
|
225
225
|
typeof parsed.summary === 'string' && parsed.summary.trim()
|
|
226
226
|
? parsed.summary.trim().slice(0, 500)
|
|
227
|
-
: '
|
|
227
|
+
: 'peach generated test'
|
|
228
228
|
const rawSteps = parsed.steps
|
|
229
229
|
if (!Array.isArray(rawSteps) || rawSteps.length === 0) {
|
|
230
230
|
throw new Error('llm returned no flow steps')
|
|
@@ -291,7 +291,7 @@ export function findUnexpectedGenerateArgs(
|
|
|
291
291
|
// generate writes --billing-kind onto the flow argv itself and getFlag
|
|
292
292
|
// takes the first occurrence, so a caller's value loses to it in silence.
|
|
293
293
|
if (arg === '--billing-kind') {
|
|
294
|
-
problems.push({ arg, message: `${arg} is set by
|
|
294
|
+
problems.push({ arg, message: `${arg} is set by peach maestro generate` })
|
|
295
295
|
i += 1
|
|
296
296
|
continue
|
|
297
297
|
}
|
|
@@ -311,7 +311,7 @@ export function findUnexpectedGenerateArgs(
|
|
|
311
311
|
export async function runMaestroGenerate(args: string[]): Promise<number> {
|
|
312
312
|
const promptArg = findPrompt(args)
|
|
313
313
|
if (!promptArg) {
|
|
314
|
-
console.error(' usage:
|
|
314
|
+
console.error(' usage: peach maestro generate "test goal"')
|
|
315
315
|
return 1
|
|
316
316
|
}
|
|
317
317
|
const { prompt, index: promptIndex } = promptArg
|
|
@@ -320,12 +320,12 @@ export async function runMaestroGenerate(args: string[]): Promise<number> {
|
|
|
320
320
|
for (const problem of unexpected) {
|
|
321
321
|
console.error(` error: ${problem.message}`)
|
|
322
322
|
}
|
|
323
|
-
console.error('\n run `
|
|
323
|
+
console.error('\n run `peach maestro --help` for the flags this command accepts')
|
|
324
324
|
return 1
|
|
325
325
|
}
|
|
326
326
|
const cliAuth = resolveCliAuth()
|
|
327
327
|
if (!cliAuth || cliAuth.kind === 'github') {
|
|
328
|
-
console.error('
|
|
328
|
+
console.error(' peach maestro generate "<goal>" needs a login or PEACH_API_KEY.')
|
|
329
329
|
console.error(' API keys must include preview_upload and llm scopes.')
|
|
330
330
|
return 1
|
|
331
331
|
}
|
|
@@ -338,7 +338,7 @@ export async function runMaestroGenerate(args: string[]): Promise<number> {
|
|
|
338
338
|
console.log(' generating Maestro flow…')
|
|
339
339
|
const generated = await generateFlowJson({ prompt, describe, origin, authHeader })
|
|
340
340
|
const flow = parseGeneratedFlow(generated)
|
|
341
|
-
const tempDir = mkdtempSync(join(tmpdir(), '
|
|
341
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'peach-maestro-generate-'))
|
|
342
342
|
const flowPath = join(tempDir, 'flow.yaml')
|
|
343
343
|
writeFileSync(flowPath, flow.yamlText)
|
|
344
344
|
console.log(` flow: ${flowPath}`)
|