peachsim 0.1.527
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 +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// rnx screenshot slides — drive the live screenshot-mode composition from the
|
|
2
|
+
// terminal. same pipeline as the in-shell UI (rail/strip): every mutation
|
|
3
|
+
// goes through the shell's screenshotControl bridge so the browser UI
|
|
4
|
+
// reflects each step live, captures auto-upload, and exports are the
|
|
5
|
+
// composed App-Store canvases (bg + copy + posed device at export size).
|
|
6
|
+
|
|
7
|
+
import { mkdirSync, writeFileSync } from 'node:fs'
|
|
8
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
9
|
+
import {
|
|
10
|
+
callInBridge,
|
|
11
|
+
callInBridgeWrite,
|
|
12
|
+
createBridgeFromParsed,
|
|
13
|
+
evalInBridge,
|
|
14
|
+
parseBridgeCliArgs,
|
|
15
|
+
type WsBridge,
|
|
16
|
+
} from '../ws-bridge'
|
|
17
|
+
|
|
18
|
+
const HELP = `
|
|
19
|
+
rnx screenshot slides — compose App Store screenshots in the live sim
|
|
20
|
+
|
|
21
|
+
usage:
|
|
22
|
+
rnx screenshot slides list slides (alias: slides list)
|
|
23
|
+
rnx screenshot slides set <n> [fields] patch a slide's copy/colors
|
|
24
|
+
rnx screenshot slides add append a blank slide (focuses it)
|
|
25
|
+
rnx screenshot slides remove <n> delete a slide
|
|
26
|
+
rnx screenshot slides move <n> <position> reorder a slide
|
|
27
|
+
rnx screenshot slides focus <n> open a slide (device flips into it)
|
|
28
|
+
rnx screenshot slides overview back to the gallery
|
|
29
|
+
rnx screenshot slides capture [<n>] capture the live frame into a slide
|
|
30
|
+
rnx screenshot slides export [<n>] [--out <dir>]
|
|
31
|
+
write composed App-Store PNG(s)
|
|
32
|
+
|
|
33
|
+
set fields:
|
|
34
|
+
--title <text> headline
|
|
35
|
+
--subtitle <text> subheadline
|
|
36
|
+
--bg-top <color> gradient top (white gray slate black cyan blue
|
|
37
|
+
--bg-bottom <color> gradient bottom teal green lime gold orange coral
|
|
38
|
+
--title-color <color> copy color override, or "auto" red berry magenta
|
|
39
|
+
--title-size <s> sm | md | lg | none gray-light
|
|
40
|
+
--underlay <s> black | white | none gray-dark …)
|
|
41
|
+
--shadow <s> light | medium | strong | none
|
|
42
|
+
|
|
43
|
+
notes:
|
|
44
|
+
slides are addressed by 1-based index. screenshot mode is auto-enabled.
|
|
45
|
+
capture shoots whatever the sim currently shows — navigate the app first
|
|
46
|
+
(rnx do tap-id …), then capture.
|
|
47
|
+
|
|
48
|
+
examples:
|
|
49
|
+
rnx screenshot slides set 1 --title "The ultimate MMA community." --bg-top cyan --bg-bottom black
|
|
50
|
+
rnx screenshot slides capture 1
|
|
51
|
+
rnx screenshot slides export --out ./exports
|
|
52
|
+
`
|
|
53
|
+
|
|
54
|
+
interface SlideRow {
|
|
55
|
+
index: number
|
|
56
|
+
id: string
|
|
57
|
+
title: string
|
|
58
|
+
subtitle: string
|
|
59
|
+
bgTop: string
|
|
60
|
+
bgBottom: string
|
|
61
|
+
titleColor: string | null
|
|
62
|
+
titleSize: string | null
|
|
63
|
+
titleUnderlay: string | null
|
|
64
|
+
titleShadow: string | null
|
|
65
|
+
captured: boolean
|
|
66
|
+
captureMode: string | null
|
|
67
|
+
focused: boolean
|
|
68
|
+
active: boolean
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface ControlState {
|
|
72
|
+
projectName: string
|
|
73
|
+
canvas: string
|
|
74
|
+
exportSize: { width: number; height: number }
|
|
75
|
+
deviceModel: string
|
|
76
|
+
slides: SlideRow[]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// my value flags, extracted before bridge-arg parsing.
|
|
80
|
+
const VALUE_FLAGS: Record<string, string> = {
|
|
81
|
+
'--title': 'title',
|
|
82
|
+
'--subtitle': 'subtitle',
|
|
83
|
+
'--bg-top': 'bgTop',
|
|
84
|
+
'--bg-bottom': 'bgBottom',
|
|
85
|
+
'--title-color': 'titleColor',
|
|
86
|
+
'--title-size': 'titleSize',
|
|
87
|
+
'--underlay': 'titleUnderlay',
|
|
88
|
+
'--shadow': 'titleShadow',
|
|
89
|
+
'--out': 'out',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function extractFlags(args: string[]): {
|
|
93
|
+
rest: string[]
|
|
94
|
+
values: Record<string, string>
|
|
95
|
+
json: boolean
|
|
96
|
+
} {
|
|
97
|
+
const rest: string[] = []
|
|
98
|
+
const values: Record<string, string> = {}
|
|
99
|
+
let json = false
|
|
100
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
101
|
+
const arg = args[i]
|
|
102
|
+
if (arg === '--json') {
|
|
103
|
+
json = true
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
const eq = arg.indexOf('=')
|
|
107
|
+
const flagName = eq > 0 ? arg.slice(0, eq) : arg
|
|
108
|
+
const key = VALUE_FLAGS[flagName]
|
|
109
|
+
if (key) {
|
|
110
|
+
if (eq > 0) {
|
|
111
|
+
values[key] = arg.slice(eq + 1)
|
|
112
|
+
} else {
|
|
113
|
+
values[key] = args[i + 1] ?? ''
|
|
114
|
+
i += 1
|
|
115
|
+
}
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
rest.push(arg)
|
|
119
|
+
}
|
|
120
|
+
return { rest, values, json }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function parseSlideRef(raw: string | undefined): number | string | undefined {
|
|
124
|
+
if (!raw) return undefined
|
|
125
|
+
const n = Number(raw)
|
|
126
|
+
return Number.isInteger(n) && n > 0 ? n : raw
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function ensureScreenshotMode(bridge: WsBridge): Promise<void> {
|
|
130
|
+
const on = await evalInBridge<boolean>(
|
|
131
|
+
bridge,
|
|
132
|
+
`(async () => {
|
|
133
|
+
if (window.SootSim?.bridges?.settings?.get?.()?.screenshotMode) return true
|
|
134
|
+
window.dispatchEvent(new CustomEvent('sootsim:shell-command', {
|
|
135
|
+
detail: { type: 'fire-action', id: 'toggle-screenshot-mode' },
|
|
136
|
+
}))
|
|
137
|
+
const deadline = Date.now() + 2000
|
|
138
|
+
while (Date.now() < deadline) {
|
|
139
|
+
if (window.SootSim?.bridges?.settings?.get?.()?.screenshotMode) return true
|
|
140
|
+
await new Promise((r) => setTimeout(r, 40))
|
|
141
|
+
}
|
|
142
|
+
return false
|
|
143
|
+
})()`,
|
|
144
|
+
{ acquireLock: true },
|
|
145
|
+
)
|
|
146
|
+
if (!on) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
'could not enable screenshot mode — is this a browser sim with the screenshot plugin? (electron has no screenshot mode)',
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function printState(state: ControlState) {
|
|
154
|
+
console.log(
|
|
155
|
+
` ${state.projectName} — canvas ${state.canvas} (${state.exportSize.width}×${state.exportSize.height}), device ${state.deviceModel}`,
|
|
156
|
+
)
|
|
157
|
+
for (const s of state.slides) {
|
|
158
|
+
const marks = [
|
|
159
|
+
s.focused ? 'focused' : s.active ? 'active' : null,
|
|
160
|
+
s.captured ? `captured${s.captureMode === '3d' ? ' 3d' : ''}` : 'no capture',
|
|
161
|
+
]
|
|
162
|
+
.filter(Boolean)
|
|
163
|
+
.join(', ')
|
|
164
|
+
const copy = s.title ? `"${s.title}"` : '(no title)'
|
|
165
|
+
const style = [
|
|
166
|
+
`bg ${s.bgTop}→${s.bgBottom}`,
|
|
167
|
+
s.titleColor ? `color ${s.titleColor}` : null,
|
|
168
|
+
s.titleSize ? `size ${s.titleSize}` : null,
|
|
169
|
+
s.titleUnderlay ? `underlay ${s.titleUnderlay}` : null,
|
|
170
|
+
s.titleShadow ? `shadow ${s.titleShadow}` : null,
|
|
171
|
+
]
|
|
172
|
+
.filter(Boolean)
|
|
173
|
+
.join(', ')
|
|
174
|
+
console.log(` ${s.index}. ${copy} — ${style} [${marks}]`)
|
|
175
|
+
if (s.subtitle) console.log(` ${s.subtitle}`)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function dataUrlToBytes(dataUrl: string): Buffer {
|
|
180
|
+
const m = dataUrl.match(/^data:[^;]+;base64,(.+)$/)
|
|
181
|
+
if (!m) throw new Error('export returned an unexpected payload')
|
|
182
|
+
return Buffer.from(m[1], 'base64')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export async function runSlides(
|
|
186
|
+
args: string[],
|
|
187
|
+
opts: { port?: number; verbose?: boolean },
|
|
188
|
+
): Promise<void> {
|
|
189
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
190
|
+
console.log(HELP)
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
const { rest, values, json } = extractFlags(args)
|
|
194
|
+
const parsed = parseBridgeCliArgs(rest, {
|
|
195
|
+
port: opts.port,
|
|
196
|
+
// capture waits on focus animation + frame bake; export composes at
|
|
197
|
+
// full App-Store resolution — both can exceed the default 15s.
|
|
198
|
+
commandTimeoutMs: 45_000,
|
|
199
|
+
})
|
|
200
|
+
const sub = parsed.positional[0] ?? 'list'
|
|
201
|
+
const refArg = parseSlideRef(parsed.positional[1])
|
|
202
|
+
const positionArg = Number(parsed.positional[2])
|
|
203
|
+
const bridge = createBridgeFromParsed(parsed)
|
|
204
|
+
const emit = (state: ControlState) => {
|
|
205
|
+
if (json) console.log(JSON.stringify(state, null, 2))
|
|
206
|
+
else printState(state)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
await ensureScreenshotMode(bridge)
|
|
211
|
+
switch (sub) {
|
|
212
|
+
case 'list': {
|
|
213
|
+
emit(
|
|
214
|
+
await callInBridge<ControlState>(
|
|
215
|
+
bridge,
|
|
216
|
+
'SootSim.bridges.screenshotControl.getState',
|
|
217
|
+
),
|
|
218
|
+
)
|
|
219
|
+
break
|
|
220
|
+
}
|
|
221
|
+
case 'set': {
|
|
222
|
+
if (refArg == null)
|
|
223
|
+
throw new Error('usage: rnx screenshot slides set <n> --title … (see --help)')
|
|
224
|
+
const patch: Record<string, string> = {}
|
|
225
|
+
for (const key of [
|
|
226
|
+
'title',
|
|
227
|
+
'subtitle',
|
|
228
|
+
'bgTop',
|
|
229
|
+
'bgBottom',
|
|
230
|
+
'titleColor',
|
|
231
|
+
'titleSize',
|
|
232
|
+
'titleUnderlay',
|
|
233
|
+
'titleShadow',
|
|
234
|
+
]) {
|
|
235
|
+
if (values[key] != null) patch[key] = values[key]
|
|
236
|
+
}
|
|
237
|
+
if (Object.keys(patch).length === 0) {
|
|
238
|
+
throw new Error('nothing to set — pass at least one field (see --help)')
|
|
239
|
+
}
|
|
240
|
+
emit(
|
|
241
|
+
await callInBridgeWrite<ControlState>(
|
|
242
|
+
bridge,
|
|
243
|
+
'SootSim.bridges.screenshotControl.setSlide',
|
|
244
|
+
refArg,
|
|
245
|
+
patch,
|
|
246
|
+
),
|
|
247
|
+
)
|
|
248
|
+
break
|
|
249
|
+
}
|
|
250
|
+
case 'add': {
|
|
251
|
+
emit(
|
|
252
|
+
await callInBridgeWrite<ControlState>(
|
|
253
|
+
bridge,
|
|
254
|
+
'SootSim.bridges.screenshotControl.addSlide',
|
|
255
|
+
),
|
|
256
|
+
)
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
case 'remove': {
|
|
260
|
+
if (refArg == null) throw new Error('usage: rnx screenshot slides remove <n>')
|
|
261
|
+
emit(
|
|
262
|
+
await callInBridgeWrite<ControlState>(
|
|
263
|
+
bridge,
|
|
264
|
+
'SootSim.bridges.screenshotControl.removeSlide',
|
|
265
|
+
refArg,
|
|
266
|
+
),
|
|
267
|
+
)
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
case 'move': {
|
|
271
|
+
if (refArg == null || !Number.isInteger(positionArg) || positionArg < 1) {
|
|
272
|
+
throw new Error('usage: rnx screenshot slides move <n> <position>')
|
|
273
|
+
}
|
|
274
|
+
emit(
|
|
275
|
+
await callInBridgeWrite<ControlState>(
|
|
276
|
+
bridge,
|
|
277
|
+
'SootSim.bridges.screenshotControl.moveSlide',
|
|
278
|
+
refArg,
|
|
279
|
+
positionArg,
|
|
280
|
+
),
|
|
281
|
+
)
|
|
282
|
+
break
|
|
283
|
+
}
|
|
284
|
+
case 'focus': {
|
|
285
|
+
if (refArg == null) throw new Error('usage: rnx screenshot slides focus <n>')
|
|
286
|
+
emit(
|
|
287
|
+
await callInBridgeWrite<ControlState>(
|
|
288
|
+
bridge,
|
|
289
|
+
'SootSim.bridges.screenshotControl.focusSlide',
|
|
290
|
+
refArg,
|
|
291
|
+
),
|
|
292
|
+
)
|
|
293
|
+
break
|
|
294
|
+
}
|
|
295
|
+
case 'overview': {
|
|
296
|
+
emit(
|
|
297
|
+
await callInBridgeWrite<ControlState>(
|
|
298
|
+
bridge,
|
|
299
|
+
'SootSim.bridges.screenshotControl.overview',
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
break
|
|
303
|
+
}
|
|
304
|
+
case 'capture': {
|
|
305
|
+
const state = await callInBridgeWrite<ControlState>(
|
|
306
|
+
bridge,
|
|
307
|
+
'SootSim.bridges.screenshotControl.capture',
|
|
308
|
+
...(refArg != null ? [refArg] : []),
|
|
309
|
+
)
|
|
310
|
+
emit(state)
|
|
311
|
+
break
|
|
312
|
+
}
|
|
313
|
+
case 'export': {
|
|
314
|
+
const outDir = values.out
|
|
315
|
+
? isAbsolute(values.out)
|
|
316
|
+
? values.out
|
|
317
|
+
: resolve(process.cwd(), values.out)
|
|
318
|
+
: join(process.cwd(), 'screenshots')
|
|
319
|
+
const state = await callInBridge<ControlState>(
|
|
320
|
+
bridge,
|
|
321
|
+
'SootSim.bridges.screenshotControl.getState',
|
|
322
|
+
)
|
|
323
|
+
const targets =
|
|
324
|
+
refArg != null
|
|
325
|
+
? state.slides.filter((s) => s.index === refArg || s.id === refArg)
|
|
326
|
+
: state.slides.filter((s) => s.captured)
|
|
327
|
+
if (targets.length === 0) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
refArg != null
|
|
330
|
+
? `no slide ${refArg}`
|
|
331
|
+
: 'no captured slides to export — capture first',
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
const written: string[] = []
|
|
335
|
+
for (const slide of targets) {
|
|
336
|
+
const result = await callInBridge<{
|
|
337
|
+
name: string
|
|
338
|
+
width: number
|
|
339
|
+
height: number
|
|
340
|
+
dataUrl: string
|
|
341
|
+
}>(bridge, 'SootSim.bridges.screenshotControl.exportSlide', slide.index)
|
|
342
|
+
const path = join(outDir, result.name)
|
|
343
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
344
|
+
writeFileSync(path, dataUrlToBytes(result.dataUrl))
|
|
345
|
+
written.push(path)
|
|
346
|
+
console.log(` saved: ${path} (${result.width}×${result.height})`)
|
|
347
|
+
}
|
|
348
|
+
if (json) console.log(JSON.stringify({ written }, null, 2))
|
|
349
|
+
break
|
|
350
|
+
}
|
|
351
|
+
default:
|
|
352
|
+
throw new Error(`unknown subcommand "${sub}" — see rnx screenshot slides --help`)
|
|
353
|
+
}
|
|
354
|
+
} finally {
|
|
355
|
+
bridge.close()
|
|
356
|
+
}
|
|
357
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { printBridgeFailureDiagnostics } from '../bridge-diagnostics'
|
|
2
|
+
import {
|
|
3
|
+
type BridgeTransportOption,
|
|
4
|
+
createBridgeFromParsed,
|
|
5
|
+
parseBridgeCliArgs,
|
|
6
|
+
} from '../ws-bridge'
|
|
7
|
+
import { formatSemanticTree, isSimSemanticTree } from './inspect/core'
|
|
8
|
+
import type { SimStateResult } from '../../src/bridge-contract'
|
|
9
|
+
|
|
10
|
+
function isSimStateResult(value: unknown): value is SimStateResult {
|
|
11
|
+
return (
|
|
12
|
+
!!value &&
|
|
13
|
+
typeof value === 'object' &&
|
|
14
|
+
typeof Reflect.get(value, 'capturedAt') === 'number' &&
|
|
15
|
+
(Reflect.get(value, 'tree') === undefined ||
|
|
16
|
+
isSimSemanticTree(Reflect.get(value, 'tree')))
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function printHelp(): void {
|
|
21
|
+
console.log(`
|
|
22
|
+
rnx state - capture the current app state in one call
|
|
23
|
+
|
|
24
|
+
usage:
|
|
25
|
+
rnx state [--json] [--sim <id>]
|
|
26
|
+
|
|
27
|
+
options:
|
|
28
|
+
--json print the complete structured result, including the screenshot
|
|
29
|
+
--sim <id> target a specific sim
|
|
30
|
+
--port <p> WS bridge port
|
|
31
|
+
`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function runState(
|
|
35
|
+
args: string[],
|
|
36
|
+
opts: { port?: number } & BridgeTransportOption = {},
|
|
37
|
+
): Promise<number> {
|
|
38
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
39
|
+
printHelp()
|
|
40
|
+
return 0
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const parsed = parseBridgeCliArgs(args, {
|
|
44
|
+
port: opts.port,
|
|
45
|
+
stripBooleanFlags: ['--json'],
|
|
46
|
+
})
|
|
47
|
+
if (parsed.positional.length > 0) {
|
|
48
|
+
console.error(` unexpected state argument: ${parsed.positional[0]}`)
|
|
49
|
+
return 1
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const bridge = (opts.createBridge ?? createBridgeFromParsed)(parsed)
|
|
53
|
+
try {
|
|
54
|
+
const value: unknown = await bridge.send({ type: 'state' })
|
|
55
|
+
if (!isSimStateResult(value)) {
|
|
56
|
+
throw new Error('state bridge returned an invalid result')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (args.includes('--json')) {
|
|
60
|
+
console.log(JSON.stringify(value))
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const route = value.route
|
|
65
|
+
console.log(` route: ${route?.screen ?? route?.url ?? '(unknown)'}`)
|
|
66
|
+
if (route?.stack?.length) console.log(` stack: ${route.stack.join(' > ')}`)
|
|
67
|
+
console.log(` keyboard: ${value.keyboard?.visible ? 'visible' : 'hidden'}`)
|
|
68
|
+
console.log('')
|
|
69
|
+
console.log(value.tree ? formatSemanticTree(value.tree) : '')
|
|
70
|
+
console.log('')
|
|
71
|
+
if (value.recentErrors?.length) {
|
|
72
|
+
console.log(` recent errors (${value.recentErrors.length}):`)
|
|
73
|
+
for (const error of value.recentErrors) {
|
|
74
|
+
console.log(` [${error.level}] ${error.text}`)
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
console.log(' recent errors: none')
|
|
78
|
+
}
|
|
79
|
+
const screenshotLength =
|
|
80
|
+
typeof value.screenshot === 'string' ? value.screenshot.length : 0
|
|
81
|
+
console.log(
|
|
82
|
+
screenshotLength > 0
|
|
83
|
+
? ` screenshot: captured (${screenshotLength} characters; use --json to read it)`
|
|
84
|
+
: ' screenshot: unavailable',
|
|
85
|
+
)
|
|
86
|
+
return 0
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(` state failed: ${error instanceof Error ? error.message : error}`)
|
|
89
|
+
await printBridgeFailureDiagnostics(bridge)
|
|
90
|
+
return 1
|
|
91
|
+
} finally {
|
|
92
|
+
bridge.close()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { runProfile } from './profile'
|
|
2
|
+
import { runReset } from './reset'
|
|
3
|
+
|
|
4
|
+
interface StorageOptions {
|
|
5
|
+
port?: number
|
|
6
|
+
verbose?: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const VALUE_FLAGS = new Set(['--sim', '--port', '-p'])
|
|
10
|
+
const SUBCOMMANDS = new Set(['profile', 'clear'])
|
|
11
|
+
|
|
12
|
+
function findSubcommand(args: string[]): { name: string; index: number } | null {
|
|
13
|
+
for (let i = 0; i < args.length; i++) {
|
|
14
|
+
const arg = args[i]
|
|
15
|
+
if (arg.startsWith('-')) {
|
|
16
|
+
if (VALUE_FLAGS.has(arg)) i++
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
return SUBCOMMANDS.has(arg) ? { name: arg, index: i } : null
|
|
20
|
+
}
|
|
21
|
+
return null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function printHelp(): void {
|
|
25
|
+
console.log(`
|
|
26
|
+
rnx storage — manage sim and app storage
|
|
27
|
+
|
|
28
|
+
usage:
|
|
29
|
+
rnx storage profile <subcommand>
|
|
30
|
+
rnx storage clear [--full] [--sim <id>] [--json]
|
|
31
|
+
|
|
32
|
+
subcommands:
|
|
33
|
+
profile list
|
|
34
|
+
profile create <id>
|
|
35
|
+
profile clear <id>
|
|
36
|
+
profile delete <id>
|
|
37
|
+
clear clear the current guest app data and relaunch it
|
|
38
|
+
`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function runStorage(args: string[], opts: StorageOptions): Promise<number> {
|
|
42
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
43
|
+
printHelp()
|
|
44
|
+
return 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const sub = findSubcommand(args)
|
|
48
|
+
if (sub?.name === 'profile') {
|
|
49
|
+
return runProfile([...args.slice(0, sub.index), ...args.slice(sub.index + 1)], opts)
|
|
50
|
+
}
|
|
51
|
+
if (sub?.name === 'clear') {
|
|
52
|
+
return runReset([...args.slice(0, sub.index), ...args.slice(sub.index + 1)], opts)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.error(` unknown storage command: ${sub?.name ?? '(missing)'}`)
|
|
56
|
+
printHelp()
|
|
57
|
+
return 1
|
|
58
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// `rnx config telemetry on|off` — retained as the command spelling for the
|
|
2
|
+
// product analytics preference shown by guided setup and Settings.
|
|
3
|
+
//
|
|
4
|
+
// this is the process-wide preference; `DO_NOT_TRACK=1` still forces opt-out
|
|
5
|
+
// for a single run regardless of what's stored (honored by isOptedOut in
|
|
6
|
+
// telemetry.ts, the same cross-tool signal npm/turbo/supabase use).
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
configFilePath,
|
|
10
|
+
readPrivacyPreferences,
|
|
11
|
+
writePrivacyPreferences,
|
|
12
|
+
} from '../../src/home-paths'
|
|
13
|
+
import { rnxExit } from '../run-rnx'
|
|
14
|
+
|
|
15
|
+
function printStatus(): void {
|
|
16
|
+
const preferences = readPrivacyPreferences()
|
|
17
|
+
const enabled = preferences.configured && preferences.productAnalytics
|
|
18
|
+
console.log(` bounded diagnostics are ${enabled ? 'ON' : 'OFF'}`)
|
|
19
|
+
console.log(' permitted fields: package name/version/unsupported API or error class')
|
|
20
|
+
console.log(` config: ${configFilePath()}`)
|
|
21
|
+
const doNotTrack = process.env.DO_NOT_TRACK
|
|
22
|
+
if (doNotTrack === '1' || doNotTrack === 'true') {
|
|
23
|
+
console.log(
|
|
24
|
+
` note: DO_NOT_TRACK=${doNotTrack} is set — telemetry is off for this run`,
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runTelemetry(args: string[]): Promise<void> {
|
|
30
|
+
const sub = args.find((a) => !a.startsWith('-'))?.toLowerCase()
|
|
31
|
+
|
|
32
|
+
switch (sub) {
|
|
33
|
+
case undefined:
|
|
34
|
+
case 'status':
|
|
35
|
+
printStatus()
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
case 'on':
|
|
39
|
+
writePrivacyPreferences({ productAnalytics: true, crashReports: false })
|
|
40
|
+
console.log(' bounded diagnostics ON')
|
|
41
|
+
console.log(` config: ${configFilePath()}`)
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
case 'off':
|
|
45
|
+
writePrivacyPreferences({ productAnalytics: false, crashReports: false })
|
|
46
|
+
console.log(' bounded diagnostics OFF')
|
|
47
|
+
console.log(` config: ${configFilePath()}`)
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
default:
|
|
51
|
+
console.error(` unknown telemetry action: ${sub}`)
|
|
52
|
+
console.error(' usage: rnx config telemetry [on|off|status]')
|
|
53
|
+
rnxExit(1)
|
|
54
|
+
}
|
|
55
|
+
}
|