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 screenshot — capture the canvas as a PNG
|
|
2
2
|
//
|
|
3
3
|
// prefers the WS bridge when one is reachable so the screenshot comes from
|
|
4
4
|
// the user's current sim (and can be cropped to a logical
|
|
@@ -36,14 +36,14 @@ export async function runScreenshot(rawArgs: string[], opts: ScreenshotOptions)
|
|
|
36
36
|
const args = normalizeAliasFlags(rawArgs)
|
|
37
37
|
if (args.includes('--help') || args.includes('-h')) {
|
|
38
38
|
console.log(`
|
|
39
|
-
|
|
39
|
+
peach screenshot — capture the canvas as a PNG
|
|
40
40
|
|
|
41
41
|
usage:
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
peach screenshot [output] [options]
|
|
43
|
+
peach screenshot [options] --output <path>
|
|
44
44
|
|
|
45
45
|
options:
|
|
46
|
-
--output <path> output file path (default: /tmp/
|
|
46
|
+
--output <path> output file path (default: /tmp/peach-inspect.png)
|
|
47
47
|
first positional arg works too: \`screenshot /tmp/x.png\`
|
|
48
48
|
--with-frame wrap the captured screen in a tight device frame
|
|
49
49
|
--no-frame capture the raw screen bitmap (default)
|
|
@@ -53,16 +53,16 @@ options:
|
|
|
53
53
|
--shell-only capture only the shell chrome, no tenant content
|
|
54
54
|
--allow-loading capture after caller-owned readiness checks even when
|
|
55
55
|
visible app copy matches a generic loading phrase
|
|
56
|
-
--area x,y,w,h crop to a logical
|
|
56
|
+
--area x,y,w,h crop to a logical peach rect
|
|
57
57
|
--id <testID> crop to a node's bounding box
|
|
58
58
|
--text <text> crop to a node found by text content
|
|
59
59
|
|
|
60
60
|
examples:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
peach screenshot
|
|
62
|
+
peach screenshot --no-shell --output app.png
|
|
63
|
+
peach screenshot --with-frame --output framed.png
|
|
64
|
+
peach screenshot --area 0,200,393,400 --output hero.png
|
|
65
|
+
peach screenshot --id loginButton --output button.png
|
|
66
66
|
`)
|
|
67
67
|
rnxExit(0)
|
|
68
68
|
}
|
|
@@ -76,7 +76,7 @@ examples:
|
|
|
76
76
|
: ` unknown flag: ${flag}`,
|
|
77
77
|
)
|
|
78
78
|
}
|
|
79
|
-
console.error(' run `
|
|
79
|
+
console.error(' run `peach screenshot --help` for the list of supported flags')
|
|
80
80
|
rnxExit(1)
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -115,7 +115,7 @@ examples:
|
|
|
115
115
|
if (typeof dataUrl !== 'string' || !dataUrl.startsWith(pngPrefix)) {
|
|
116
116
|
throw new Error('remote simulator screenshot returned invalid image data')
|
|
117
117
|
}
|
|
118
|
-
const outputPath = resolve(process.cwd(), outputArg || '/tmp/
|
|
118
|
+
const outputPath = resolve(process.cwd(), outputArg || '/tmp/peach-inspect.png')
|
|
119
119
|
mkdirSync(dirname(outputPath), { recursive: true })
|
|
120
120
|
const png = Buffer.from(dataUrl.slice(pngPrefix.length), 'base64')
|
|
121
121
|
if (png.length === 0)
|
|
@@ -151,15 +151,15 @@ examples:
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
if (withFrame) {
|
|
154
|
-
console.error(' --with-frame requires a running
|
|
154
|
+
console.error(' --with-frame requires a running peach bridge')
|
|
155
155
|
console.error(' open the app in a live sim first, then rerun the command')
|
|
156
156
|
rnxExit(1)
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
if (rect) {
|
|
160
|
-
console.error(' --area / --id / --text require a running
|
|
160
|
+
console.error(' --area / --id / --text require a running peach bridge')
|
|
161
161
|
console.error(
|
|
162
|
-
' start one with `
|
|
162
|
+
' start one with `peach serve`, `peach desktop`, or your project dev server',
|
|
163
163
|
)
|
|
164
164
|
rnxExit(1)
|
|
165
165
|
}
|
|
@@ -229,12 +229,12 @@ async function captureViaBridge(
|
|
|
229
229
|
process.stderr.write(
|
|
230
230
|
' ⚠ screenshot will capture the LAST PAINTED canvas — likely stale.\n' +
|
|
231
231
|
' navigation/`shell` commands sent before this screenshot may not\n' +
|
|
232
|
-
' have repainted yet. focus the tab manually or `
|
|
232
|
+
' have repainted yet. focus the tab manually or `peach --sim <id>`\n' +
|
|
233
233
|
' to target a visible sim before capturing.\n\n',
|
|
234
234
|
)
|
|
235
235
|
}
|
|
236
236
|
// re-assert readiness on THIS bridge connection right before capturing.
|
|
237
|
-
// the readiness gate (`
|
|
237
|
+
// the readiness gate (`peach wait ready`) and this capture run as
|
|
238
238
|
// separate CLI processes; between them the engine can re-enter its
|
|
239
239
|
// boot/connect overlay — a late reload fires `sootsim:externalAppReloadStart`
|
|
240
240
|
// and clears `__sootsimExternalAppReady` — so a capture taken now can grab
|
|
@@ -298,10 +298,10 @@ async function captureViaBridge(
|
|
|
298
298
|
const dataUrl: string = await bridge.send(request)
|
|
299
299
|
const pngPrefix = 'data:image/png;base64,'
|
|
300
300
|
// never write a 0-byte "saved" file from an empty or malformed payload —
|
|
301
|
-
// the sim may be alive but not painting (check `
|
|
301
|
+
// the sim may be alive but not painting (check `peach get errors`)
|
|
302
302
|
if (typeof dataUrl !== 'string' || dataUrl.length <= pngPrefix.length) {
|
|
303
303
|
throw new Error(
|
|
304
|
-
'screenshot capture returned no image data — the sim is connected but not painting; check `
|
|
304
|
+
'screenshot capture returned no image data — the sim is connected but not painting; check `peach get errors`',
|
|
305
305
|
)
|
|
306
306
|
}
|
|
307
307
|
const base64 = dataUrl.replace(/^data:image\/png;base64,/, '')
|
|
@@ -312,7 +312,7 @@ async function captureViaBridge(
|
|
|
312
312
|
}
|
|
313
313
|
if (layers) console.log(` layers: ${layers}`)
|
|
314
314
|
|
|
315
|
-
const outputPath = resolve(process.cwd(), outputArg || '/tmp/
|
|
315
|
+
const outputPath = resolve(process.cwd(), outputArg || '/tmp/peach-inspect.png')
|
|
316
316
|
mkdirSync(dirname(outputPath), { recursive: true })
|
|
317
317
|
const rawBuffer = Buffer.from(base64, 'base64')
|
|
318
318
|
if (withFrame) {
|
|
@@ -359,7 +359,7 @@ function resolveLayers(args: string[]): 'full' | 'tenant' | 'shell' | undefined
|
|
|
359
359
|
return undefined
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
// known flags for `
|
|
362
|
+
// known flags for `peach screenshot`. booleans take no value, value flags
|
|
363
363
|
// consume the next arg. kept local so this validation can't drift from the
|
|
364
364
|
// flags the command actually reads.
|
|
365
365
|
const SCREENSHOT_BOOLEAN_FLAGS = new Set([
|
|
@@ -445,7 +445,7 @@ function findUnknownFlags(args: string[]): Array<{ flag: string; suggestion?: st
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
// resolve output path: prefer --output <path>, fall back to the first
|
|
448
|
-
// positional arg so `
|
|
448
|
+
// positional arg so `peach screenshot /tmp/foo.png` works the way every
|
|
449
449
|
// other screenshot tool does.
|
|
450
450
|
function resolveOutputPath(args: string[]): string | undefined {
|
|
451
451
|
const explicit = args.find((_, i) => args[i - 1] === '--output')
|
|
@@ -463,7 +463,7 @@ function resolveOutputPath(args: string[]): string | undefined {
|
|
|
463
463
|
|
|
464
464
|
// capture a page in headless chromium when no bridge is running.
|
|
465
465
|
async function runPlaywrightScreenshot(args: string[], opts: ScreenshotOptions) {
|
|
466
|
-
const output = resolveOutputPath(args) || '
|
|
466
|
+
const output = resolveOutputPath(args) || 'peach-screenshot.png'
|
|
467
467
|
const url =
|
|
468
468
|
args.find((_, i) => args[i - 1] === '--url') ||
|
|
469
469
|
`http://localhost:${opts.port || 5173}`
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach screenshot appstore capture — headlessly (re)capture an app's App-Store
|
|
2
2
|
// slides as EDITABLE 3-layer refs (captureRef + cleanRef + screenRef, plus
|
|
3
3
|
// threeScene for 3d) and let the shell's existing auto-upload push them to the
|
|
4
4
|
// signed-in user's org deck. NOT a reimplementation of capture/upload: it
|
|
5
5
|
// launches a GPU headless Chrome, loads the org-mode build shell, seeds the
|
|
6
|
-
// `
|
|
6
|
+
// `peach login` session into the page so the in-browser auto-upload PUTs
|
|
7
7
|
// authenticate as the user, drives the same `SootSim.bridges.screenshotControl`
|
|
8
8
|
// surface the rail UI uses, then waits for the deck/capture PUTs to flush.
|
|
9
9
|
//
|
|
10
|
-
// auth: `
|
|
10
|
+
// auth: `peach login` (resolveCliAuth → session token). the token is seeded
|
|
11
11
|
// into the shell page's localStorage (`sootsim.session.token`) — the exact key
|
|
12
12
|
// `getSession()` reads, which both the deck PUT (projects-persistence) and the
|
|
13
13
|
// per-ref capture PUT (capture-store) attach as `Authorization: Bearer`.
|
|
@@ -28,14 +28,14 @@ import { resolveCliAuth, type CliAuth } from '../auth'
|
|
|
28
28
|
import { rnxExit } from '../run-rnx'
|
|
29
29
|
|
|
30
30
|
const HELP = `
|
|
31
|
-
|
|
31
|
+
peach screenshot appstore capture — headlessly capture + upload App Store slides
|
|
32
32
|
|
|
33
33
|
usage:
|
|
34
|
-
|
|
34
|
+
peach screenshot appstore capture --org <org> --repo <repo> [options]
|
|
35
35
|
|
|
36
36
|
what it does:
|
|
37
37
|
boots the org-mode build shell in headless GPU Chrome (authed via your
|
|
38
|
-
\`
|
|
38
|
+
\`peach login\` session), captures each slide through the live screenshot
|
|
39
39
|
composer so every slide gets editable layers (captureRef + cleanRef +
|
|
40
40
|
screenRef), and lets the shell auto-upload them to your org deck.
|
|
41
41
|
|
|
@@ -54,8 +54,8 @@ options:
|
|
|
54
54
|
--json machine-readable summary
|
|
55
55
|
|
|
56
56
|
examples:
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
peach screenshot appstore capture --org acme --repo my-app --dry-run
|
|
58
|
+
peach screenshot appstore capture --org acme --repo my-app --branch main --force
|
|
59
59
|
`
|
|
60
60
|
|
|
61
61
|
interface CaptureSlide {
|
|
@@ -121,13 +121,13 @@ function parseFlags(args: string[]): Flags {
|
|
|
121
121
|
// the session token + origin power both the page auth seed and the API calls.
|
|
122
122
|
// only a logged-in session works here (the in-browser PUTs read a bearer); an
|
|
123
123
|
// api-key/github CliAuth has no browser session origin, so we direct those to
|
|
124
|
-
// `
|
|
124
|
+
// `peach login` rather than silently failing mid-capture.
|
|
125
125
|
function resolveSessionAuth(): { token: string; origin: string } {
|
|
126
126
|
const auth: CliAuth | null = resolveCliAuth()
|
|
127
127
|
if (auth && auth.kind === 'session') return { token: auth.token, origin: auth.origin }
|
|
128
128
|
process.stderr.write(
|
|
129
|
-
'\n
|
|
130
|
-
' run `
|
|
129
|
+
'\n peach screenshot appstore capture needs a logged-in session.\n' +
|
|
130
|
+
' run `peach login` first (the captured slides upload to that account).\n\n',
|
|
131
131
|
)
|
|
132
132
|
rnxExit(1)
|
|
133
133
|
}
|
|
@@ -142,7 +142,7 @@ function isLoopback(hostname: string): boolean {
|
|
|
142
142
|
)
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// the build shell (/build/...) is served by the
|
|
145
|
+
// the build shell (/build/...) is served by the peach PAGES site, a DIFFERENT
|
|
146
146
|
// origin from the contrast API/auth origin. derive it from the api origin:
|
|
147
147
|
// loopback dev pairs the 3000(+offset) app with the 5173(+offset) shell (the
|
|
148
148
|
// inverse of engine origin.ts's pairedLocalAppOrigin); prod's contrast.dev is
|
|
@@ -417,7 +417,7 @@ export async function runScreenshotsCapture(args: string[]): Promise<number> {
|
|
|
417
417
|
`${shellOrigin}/build/${encodeURIComponent(flags.org)}/${encodeURIComponent(flags.repo)}/` +
|
|
418
418
|
`${encodeURIComponent(flags.branch)}?platform=${encodeURIComponent(flags.platform)}&ssMode=1`
|
|
419
419
|
|
|
420
|
-
const profileDir = mkdtempSync(join(tmpdir(), '
|
|
420
|
+
const profileDir = mkdtempSync(join(tmpdir(), 'peach-capture-'))
|
|
421
421
|
const { browser: ctx, reapNow } = await launchReapedChromeScoped(
|
|
422
422
|
(options) => chromium.launchPersistentContext(profileDir, options),
|
|
423
423
|
{
|
|
@@ -13,10 +13,10 @@ export async function runScreenshots(
|
|
|
13
13
|
): Promise<number> {
|
|
14
14
|
if (args.includes('--help') || args.includes('-h')) {
|
|
15
15
|
console.log(`
|
|
16
|
-
|
|
16
|
+
peach screenshot appstore — capture and compose app-store screenshot sets
|
|
17
17
|
|
|
18
18
|
usage:
|
|
19
|
-
|
|
19
|
+
peach screenshot appstore --plan <plan.yaml> [options]
|
|
20
20
|
|
|
21
21
|
options:
|
|
22
22
|
--plan <path> screenshot plan yaml
|
|
@@ -31,9 +31,9 @@ options:
|
|
|
31
31
|
--compose-only skip flow capture, reuse existing raw screenshots
|
|
32
32
|
|
|
33
33
|
examples:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
peach screenshot appstore --plan app-store.yaml
|
|
35
|
+
peach screenshot appstore --plan app-store.yaml --sim a9
|
|
36
|
+
peach screenshot appstore --plan app-store.yaml --org acme --repo mobile
|
|
37
37
|
`)
|
|
38
38
|
return 0
|
|
39
39
|
}
|
|
@@ -77,7 +77,7 @@ examples:
|
|
|
77
77
|
const auth = resolveCliAuth()
|
|
78
78
|
if (!auth) {
|
|
79
79
|
console.error(
|
|
80
|
-
' error: --org/--repo needs auth — run `
|
|
80
|
+
' error: --org/--repo needs auth — run `peach login` or set PEACH_API_KEY.',
|
|
81
81
|
)
|
|
82
82
|
return 1
|
|
83
83
|
}
|
package/cli/commands/serve.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach serve — foreground bridge host
|
|
2
2
|
//
|
|
3
3
|
// hosts the WS bridge + runtime HTTP server on port 7668 (or --port) so
|
|
4
4
|
// CLI commands and electron windows both work against one bridge. sims
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// them; electron fetches renderer assets over http from the same port.
|
|
7
7
|
//
|
|
8
8
|
// run in the foreground (ctrl-c to stop). the persistent launchd/systemd
|
|
9
|
-
// daemon installation is handled by `
|
|
9
|
+
// daemon installation is handled by `peach daemon install`.
|
|
10
10
|
|
|
11
11
|
import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
|
|
12
12
|
import {
|
|
@@ -25,22 +25,22 @@ interface ServeOptions {
|
|
|
25
25
|
export async function runServe(args: string[], opts: ServeOptions = {}) {
|
|
26
26
|
if (args.includes('--help') || args.includes('-h')) {
|
|
27
27
|
console.log(`
|
|
28
|
-
|
|
28
|
+
peach serve — run the peach bridge in the foreground
|
|
29
29
|
|
|
30
|
-
hosts the WS bridge that CLI commands talk to. once running, any
|
|
30
|
+
hosts the WS bridge that CLI commands talk to. once running, any peach
|
|
31
31
|
renderer (browser, electron, headless playwright) that connects to port 7668
|
|
32
|
-
becomes drivable from '
|
|
32
|
+
becomes drivable from 'peach describe', 'peach do tap', etc.
|
|
33
33
|
|
|
34
34
|
usage:
|
|
35
|
-
|
|
35
|
+
peach serve [options]
|
|
36
36
|
|
|
37
37
|
options:
|
|
38
38
|
--port <n> bridge port (defaults to ${DEFAULT_SOOTSIM_BRIDGE_PORT})
|
|
39
39
|
--quiet suppress per-connection logging
|
|
40
40
|
|
|
41
41
|
examples:
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
peach serve
|
|
43
|
+
peach serve --port 7668 --quiet
|
|
44
44
|
`)
|
|
45
45
|
rnxExit(0)
|
|
46
46
|
}
|
|
@@ -56,15 +56,15 @@ examples:
|
|
|
56
56
|
}
|
|
57
57
|
const quiet = args.includes('--quiet') || args.includes('-q')
|
|
58
58
|
|
|
59
|
-
// only one bridge per
|
|
59
|
+
// only one bridge per peach home. refuse to start a second one
|
|
60
60
|
// regardless of requested port, since both would try to write the same
|
|
61
61
|
// daemon.json and electron/cli clients only read one lockfile.
|
|
62
62
|
const existingLock = readDaemonLockfile()
|
|
63
63
|
if (existingLock && isDaemonLockfileFresh(existingLock)) {
|
|
64
64
|
console.error(
|
|
65
|
-
`
|
|
65
|
+
` a peach bridge is already running (pid ${existingLock.pid}, port ${existingLock.bridgePort})`,
|
|
66
66
|
)
|
|
67
|
-
console.error(` stop it with '
|
|
67
|
+
console.error(` stop it with 'peach daemon stop' first`)
|
|
68
68
|
rnxExit(1)
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -102,7 +102,7 @@ examples:
|
|
|
102
102
|
for (const id of currentIds) lastSimIds.add(id)
|
|
103
103
|
}, 500)
|
|
104
104
|
|
|
105
|
-
log(`
|
|
105
|
+
log(`peach bridge listening on ws://localhost:${boundPort} (runtime http on same port)`)
|
|
106
106
|
if (boundPort !== port) {
|
|
107
107
|
log(` (preferred port ${port} was taken — fell back to ${boundPort})`)
|
|
108
108
|
}
|
package/cli/commands/setup.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach setup owns the optional machine and repository choices. peach itself
|
|
2
2
|
// works without project setup; bare first-run onboarding launches ConnectRN
|
|
3
3
|
// during this flow and leaves the repository choice until the end.
|
|
4
4
|
|
|
@@ -91,7 +91,7 @@ export async function runSetup(
|
|
|
91
91
|
console.log(` ${muted('Would enable')} ${accent('the background service')}`)
|
|
92
92
|
}
|
|
93
93
|
if (!service && !serviceStatus.installed && !options.json) {
|
|
94
|
-
console.log(` ${muted('Enable it later with')} ${accent('
|
|
94
|
+
console.log(` ${muted('Enable it later with')} ${accent('peach daemon install')}`)
|
|
95
95
|
}
|
|
96
96
|
const simulatorDriver = await decideSimulatorDriver(options)
|
|
97
97
|
if (options.dryRun && !options.json) {
|
|
@@ -102,13 +102,13 @@ export async function runSetup(
|
|
|
102
102
|
|
|
103
103
|
const manifest = options.json
|
|
104
104
|
? await rnxRuntime.fetchManifest()
|
|
105
|
-
: await withSpinner('Checking the
|
|
105
|
+
: await withSpinner('Checking the peach runtime', () => rnxRuntime.fetchManifest())
|
|
106
106
|
const runtimeVersion = rnxRuntime.resolveVersion(manifest, {
|
|
107
107
|
channel: 'stable',
|
|
108
108
|
}).version
|
|
109
109
|
const cliVersion = getCliVersion()
|
|
110
110
|
if (cliVersion === '0.0.0') {
|
|
111
|
-
throw new Error('could not resolve the installed
|
|
111
|
+
throw new Error('could not resolve the installed peach CLI version')
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
let runtimeInstalled = false
|
|
@@ -204,7 +204,7 @@ export async function runSetup(
|
|
|
204
204
|
console.log(
|
|
205
205
|
options.dryRun
|
|
206
206
|
? `\n ${success('✓')} Dry run complete.`
|
|
207
|
-
: `\n ${success('✓')} ${launchConnectRN ? 'ConnectRN is open. ' : ''}
|
|
207
|
+
: `\n ${success('✓')} ${launchConnectRN ? 'ConnectRN is open. ' : ''}peach is ready.`,
|
|
208
208
|
)
|
|
209
209
|
}
|
|
210
210
|
|
|
@@ -280,7 +280,7 @@ async function decideService(
|
|
|
280
280
|
if (!options.json) {
|
|
281
281
|
printPromptBlock('Background service', [
|
|
282
282
|
'The persistent service is currently available on macOS and Linux.',
|
|
283
|
-
'
|
|
283
|
+
'peach will start the bridge when needed on this platform.',
|
|
284
284
|
])
|
|
285
285
|
}
|
|
286
286
|
return false
|
|
@@ -309,22 +309,22 @@ async function decideSimulatorDriver(
|
|
|
309
309
|
requireInteractive(options, '--desktop or --browser')
|
|
310
310
|
const desktopDescription =
|
|
311
311
|
process.platform === 'darwin'
|
|
312
|
-
? 'Desktop downloads a DMG and installs
|
|
312
|
+
? 'Desktop downloads a DMG and installs peach.app.'
|
|
313
313
|
: process.platform === 'win32'
|
|
314
|
-
? 'Desktop downloads and runs the
|
|
315
|
-
: 'Desktop downloads the matching
|
|
314
|
+
? 'Desktop downloads and runs the peach installer.'
|
|
315
|
+
: 'Desktop downloads the matching peach AppImage.'
|
|
316
316
|
const desktopChoice =
|
|
317
317
|
process.platform === 'darwin'
|
|
318
|
-
? 'Desktop app Installs
|
|
318
|
+
? 'Desktop app Installs peach.app from a DMG'
|
|
319
319
|
: process.platform === 'win32'
|
|
320
|
-
? 'Desktop app Runs the
|
|
320
|
+
? 'Desktop app Runs the peach installer'
|
|
321
321
|
: 'Desktop app Installs the matching AppImage'
|
|
322
322
|
printPromptBlock('Simulator window', [
|
|
323
323
|
'Browser opens immediately in an isolated Chrome window.',
|
|
324
324
|
desktopDescription,
|
|
325
325
|
'The Desktop app opens in a dedicated native window.',
|
|
326
326
|
])
|
|
327
|
-
const choice = await select('Where should
|
|
327
|
+
const choice = await select('Where should peach open??', [
|
|
328
328
|
'Browser (recommended) No additional download',
|
|
329
329
|
desktopChoice,
|
|
330
330
|
])
|
|
@@ -343,7 +343,7 @@ async function decidePrivacy(
|
|
|
343
343
|
'Reports can contain package compatibility or an error class.',
|
|
344
344
|
'They never contain your code or app data.',
|
|
345
345
|
])
|
|
346
|
-
return confirm('Share bounded diagnostics to improve
|
|
346
|
+
return confirm('Share bounded diagnostics to improve peach??', false)
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
async function decideRepository(
|
|
@@ -359,11 +359,11 @@ async function decideRepository(
|
|
|
359
359
|
if (plan.operations.length === 0) return true
|
|
360
360
|
if (options.repository !== undefined) return options.repository
|
|
361
361
|
if (options.yes || options.ci || !process.stdin.isTTY) return false
|
|
362
|
-
printPromptBlock('Share
|
|
363
|
-
'
|
|
364
|
-
'This only adds an exact peachsim dev dependency and
|
|
362
|
+
printPromptBlock('Share peach with your team', [
|
|
363
|
+
'peach already works here with no project setup.',
|
|
364
|
+
'This only adds an exact peachsim dev dependency and a peach script for teammates.',
|
|
365
365
|
])
|
|
366
|
-
return confirm(`Add
|
|
366
|
+
return confirm(`Add peach to ${path.basename(plan.appDir)}?`, false)
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
function requireInteractive(options: SetupOptions, flags: string): void {
|
|
@@ -376,7 +376,7 @@ function runtimeCacheMetadata(runtimeVersion: string) {
|
|
|
376
376
|
const arch = os.arch()
|
|
377
377
|
return {
|
|
378
378
|
path: runtimeDir(runtimeVersion),
|
|
379
|
-
key: `
|
|
379
|
+
key: `peach-runtime-${platform}-${arch}-${runtimeVersion}`,
|
|
380
380
|
inputs: { platform, arch, runtimeVersion },
|
|
381
381
|
}
|
|
382
382
|
}
|
|
@@ -388,17 +388,17 @@ function printIntro(options: SetupOptions): void {
|
|
|
388
388
|
|
|
389
389
|
function printHelp(): void {
|
|
390
390
|
console.log(`
|
|
391
|
-
|
|
391
|
+
peach setup - configure optional local conveniences
|
|
392
392
|
|
|
393
|
-
|
|
393
|
+
peach works without project setup. This command can enable the faster background
|
|
394
394
|
service, choose Browser or Desktop, configure private diagnostics, and optionally
|
|
395
|
-
add an exact peachsim dependency plus
|
|
395
|
+
add an exact peachsim dependency plus a peach script for teammates.
|
|
396
396
|
|
|
397
397
|
usage:
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
398
|
+
peach setup
|
|
399
|
+
peach setup --yes
|
|
400
|
+
peach setup --ci --yes --json
|
|
401
|
+
peach setup --dry-run
|
|
402
402
|
|
|
403
403
|
choices:
|
|
404
404
|
--service | --no-service
|
package/cli/commands/skills.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
//
|
|
1
|
+
// peach skill - install and inspect agent skill files
|
|
2
2
|
//
|
|
3
3
|
// usage:
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// peach skill install install all skills to supported agents
|
|
5
|
+
// peach skill install codex debug install specific skills to Codex only
|
|
6
|
+
// peach skill show [name] list skills or print one skill
|
|
7
7
|
|
|
8
8
|
import * as fs from 'fs'
|
|
9
9
|
import * as os from 'os'
|
|
@@ -38,14 +38,14 @@ interface InstallTarget {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function printSkillHelp() {
|
|
41
|
-
console.log(`
|
|
41
|
+
console.log(`peach skill
|
|
42
42
|
|
|
43
|
-
install and inspect bundled
|
|
43
|
+
install and inspect bundled peach agent skills.
|
|
44
44
|
|
|
45
45
|
usage:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
peach skill install [all|codex|claude] [skill-name...]
|
|
47
|
+
peach skill install --target <dir> [skill-name...]
|
|
48
|
+
peach skill show [skill-name]
|
|
49
49
|
|
|
50
50
|
commands:
|
|
51
51
|
install install skills; no target means all supported local agents
|
|
@@ -59,25 +59,25 @@ targets:
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function printInstallHelp() {
|
|
62
|
-
console.log(`
|
|
62
|
+
console.log(`peach skill install
|
|
63
63
|
|
|
64
|
-
install bundled
|
|
64
|
+
install bundled peach skills in the agent skill layout: <skill>/SKILL.md.
|
|
65
65
|
each skill directory is symlinked back to its source, so edits stay live
|
|
66
66
|
without a re-install. an existing install from an older CLI is upgraded in
|
|
67
67
|
place; an unrelated skill directory is left alone unless --force is passed.
|
|
68
68
|
|
|
69
69
|
usage:
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
peach skill install [all|codex|claude] [skill-name...]
|
|
71
|
+
peach skill install --target <dir> [skill-name...]
|
|
72
72
|
|
|
73
73
|
options:
|
|
74
74
|
--force, -f replace a conflicting existing skill with the symlink
|
|
75
75
|
|
|
76
76
|
examples:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
peach skill install
|
|
78
|
+
peach skill install codex
|
|
79
|
+
peach skill install codex peach-debug
|
|
80
|
+
peach skill install --force peach-debug
|
|
81
81
|
`)
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -174,9 +174,11 @@ function matchSkills(skills: SkillInfo[], filters: string[]): SkillInfo[] {
|
|
|
174
174
|
if (filters.length === 0) return skills
|
|
175
175
|
const matched = skills.filter((skill) =>
|
|
176
176
|
filters.some((filter) => {
|
|
177
|
-
|
|
177
|
+
// accept the pre-rename rnx- prefix on filter input so installed docs
|
|
178
|
+
// and muscle memory keep resolving; installed names are peach- only.
|
|
179
|
+
const needle = filter.replace(/^(peach|rnx)-/, '')
|
|
178
180
|
return (
|
|
179
|
-
skill.name.includes(filter) || skill.name.replace(/^
|
|
181
|
+
skill.name.includes(filter) || skill.name.replace(/^peach-/, '').includes(needle)
|
|
180
182
|
)
|
|
181
183
|
}),
|
|
182
184
|
)
|
|
@@ -216,7 +218,7 @@ function symlinkPointsTo(dest: string, src: string): boolean {
|
|
|
216
218
|
}
|
|
217
219
|
|
|
218
220
|
// a store entry left by an older CLI is safe to upgrade: either a real dir
|
|
219
|
-
// whose only content is a SKILL.md symlink into
|
|
221
|
+
// whose only content is a SKILL.md symlink into a peach skills source (the
|
|
220
222
|
// pre-dir-layout install — possibly broken after the source moved), or a dir
|
|
221
223
|
// holding a byte-identical copy of the skill. only our installer creates
|
|
222
224
|
// those shapes, so replacing them can't lose user work.
|
|
@@ -305,6 +307,11 @@ const LEGACY_BUNDLED_SKILL_DIRS = [
|
|
|
305
307
|
'sootsim-perf',
|
|
306
308
|
'sootsim-test',
|
|
307
309
|
'sootsim-visual',
|
|
310
|
+
'rnx-setup',
|
|
311
|
+
'rnx-debug',
|
|
312
|
+
'rnx-perf',
|
|
313
|
+
'rnx-test',
|
|
314
|
+
'rnx-visual',
|
|
308
315
|
]
|
|
309
316
|
|
|
310
317
|
function removeLegacyBundledSkills(targetDir: string) {
|
|
@@ -331,8 +338,8 @@ function printSkillList(skills: SkillInfo[]) {
|
|
|
331
338
|
console.log(` ${skill.name}`)
|
|
332
339
|
console.log(` ${skill.description}\n`)
|
|
333
340
|
}
|
|
334
|
-
console.log(' usage:
|
|
335
|
-
console.log(' usage:
|
|
341
|
+
console.log(' usage: peach skill install [all|codex|claude] [skill-name...]')
|
|
342
|
+
console.log(' usage: peach skill show [skill-name]\n')
|
|
336
343
|
}
|
|
337
344
|
|
|
338
345
|
function parseInstallArgs(args: string[]): {
|
|
@@ -386,7 +393,7 @@ function parseInstallArgs(args: string[]): {
|
|
|
386
393
|
async function runInstall(args: string[]) {
|
|
387
394
|
const skills = listSkills()
|
|
388
395
|
if (skills.length === 0) {
|
|
389
|
-
console.error(' no skills found in
|
|
396
|
+
console.error(' no skills found in peach package')
|
|
390
397
|
rnxExit(1)
|
|
391
398
|
}
|
|
392
399
|
|