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,348 @@
|
|
|
1
|
+
// rnx runtime — manage engine runtimes under ~/.rnx/runtimes/.
|
|
2
|
+
//
|
|
3
|
+
// runtimes are versioned tarballs hosted behind the configured CDN origin
|
|
4
|
+
// (default https://contrast.dev/runtimes/). each install:
|
|
5
|
+
// 1. fetches manifest.json to resolve a version (or confirm the literal)
|
|
6
|
+
// 2. downloads sootsim-runtime-<version>.tar.gz to an operation temp directory
|
|
7
|
+
// 3. verifies sha256
|
|
8
|
+
// 4. extracts to ~/.rnx/runtimes/<version>/
|
|
9
|
+
// 5. (optionally) sets it active + tells the daemon to hot-swap
|
|
10
|
+
//
|
|
11
|
+
// the daemon-side state (active runtime) is mirrored in ~/.rnx/runtimes/active
|
|
12
|
+
// so the CLI can change it even when the daemon isn't running.
|
|
13
|
+
|
|
14
|
+
import fs from 'fs'
|
|
15
|
+
import { compareSemver } from '@contrast/runtime-delivery'
|
|
16
|
+
import { WebSocket } from 'ws'
|
|
17
|
+
import {
|
|
18
|
+
ensureRnxHome,
|
|
19
|
+
readActiveRuntime,
|
|
20
|
+
readLiveRuntimeVersions,
|
|
21
|
+
runtimeDir,
|
|
22
|
+
writeActiveRuntime,
|
|
23
|
+
} from '../../src/home-paths'
|
|
24
|
+
import {
|
|
25
|
+
DEFAULT_RUNTIME_CDN_ORIGIN,
|
|
26
|
+
RNX_CHANGELOG_URL,
|
|
27
|
+
rnxRuntime,
|
|
28
|
+
} from '../../src/runtime-delivery'
|
|
29
|
+
import { resolveRNXAppConfig } from '../app-config'
|
|
30
|
+
import { rnxExit } from '../run-rnx'
|
|
31
|
+
import { fetchRuntimeReleaseNotes, formatRuntimeReleaseNotes } from '../runtime-notes'
|
|
32
|
+
import { resolveDefaultBridgePort } from '../ws-bridge'
|
|
33
|
+
|
|
34
|
+
interface RuntimeOptions {
|
|
35
|
+
channel?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function runRuntime(args: string[], opts: RuntimeOptions = {}) {
|
|
39
|
+
const [sub, ...rest] = args
|
|
40
|
+
if (!sub || sub === '--help' || sub === '-h') {
|
|
41
|
+
printHelp()
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
switch (sub) {
|
|
45
|
+
case 'install':
|
|
46
|
+
return runtimeInstall(rest, opts)
|
|
47
|
+
case 'list':
|
|
48
|
+
return runtimeList(rest)
|
|
49
|
+
case 'use':
|
|
50
|
+
return runtimeUse(rest)
|
|
51
|
+
case 'remove':
|
|
52
|
+
return runtimeRemove(rest)
|
|
53
|
+
case 'which':
|
|
54
|
+
return runtimeWhich()
|
|
55
|
+
case 'notes':
|
|
56
|
+
return runtimeNotes(rest)
|
|
57
|
+
default:
|
|
58
|
+
console.error(` unknown runtime subcommand: ${sub}`)
|
|
59
|
+
printHelp()
|
|
60
|
+
rnxExit(1)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function printHelp() {
|
|
65
|
+
console.log(`
|
|
66
|
+
rnx runtime — manage engine runtimes under ~/.rnx/runtimes/
|
|
67
|
+
|
|
68
|
+
usage:
|
|
69
|
+
rnx runtime install [version] install a version (default: channel latest)
|
|
70
|
+
rnx runtime list show installed + available versions
|
|
71
|
+
rnx runtime use <version> switch active runtime
|
|
72
|
+
rnx runtime remove <version> delete an installed runtime
|
|
73
|
+
rnx runtime which print active runtime version
|
|
74
|
+
rnx runtime notes print repo or default engine release notes
|
|
75
|
+
|
|
76
|
+
flags:
|
|
77
|
+
--channel <name> channel to resolve 'latest' from (default: stable)
|
|
78
|
+
--force reinstall even if the version is already on disk
|
|
79
|
+
--set-active=false do not switch active runtime after install
|
|
80
|
+
|
|
81
|
+
environment:
|
|
82
|
+
RNX_CDN_ORIGIN override the CDN base URL (default: ${DEFAULT_RUNTIME_CDN_ORIGIN})
|
|
83
|
+
|
|
84
|
+
examples:
|
|
85
|
+
rnx runtime install
|
|
86
|
+
rnx runtime install 1.2.3
|
|
87
|
+
rnx runtime install --channel beta
|
|
88
|
+
rnx runtime use 1.2.3
|
|
89
|
+
rnx runtime notes
|
|
90
|
+
`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// --- install --------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
async function runtimeInstall(args: string[], opts: RuntimeOptions) {
|
|
96
|
+
const { version: versionArg, flags } = parseVersionAndFlags(args)
|
|
97
|
+
const channel = flags.channel ?? opts.channel ?? 'stable'
|
|
98
|
+
const force = flags.force === true
|
|
99
|
+
const setActive = flags.setActive !== false
|
|
100
|
+
|
|
101
|
+
ensureRnxHome()
|
|
102
|
+
|
|
103
|
+
console.log(`rnx runtime install`)
|
|
104
|
+
console.log(` cdn: ${rnxRuntime.resolveCdnOrigin()}`)
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const result = await rnxRuntime.install({
|
|
108
|
+
version: versionArg,
|
|
109
|
+
channel,
|
|
110
|
+
force,
|
|
111
|
+
setActive,
|
|
112
|
+
protectVersions: readLiveRuntimeVersions(),
|
|
113
|
+
})
|
|
114
|
+
console.log(` version: ${result.version} (channel: ${result.channel})`)
|
|
115
|
+
if (result.installed) {
|
|
116
|
+
console.log(` installed ${result.version}`)
|
|
117
|
+
} else {
|
|
118
|
+
console.log(` already installed at ${result.runtimeDir}`)
|
|
119
|
+
}
|
|
120
|
+
if (setActive) await activateVersion(result.version)
|
|
121
|
+
return result
|
|
122
|
+
} catch (err) {
|
|
123
|
+
console.error(` ${describeError(err)}`)
|
|
124
|
+
rnxExit(1)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function activateVersion(version: string) {
|
|
129
|
+
writeActiveRuntime(version)
|
|
130
|
+
console.log(` active: ${version}`)
|
|
131
|
+
// if a daemon is running, tell it to hot-swap its http root. the
|
|
132
|
+
// daemon re-reads the active runtime per-request anyway, so this is
|
|
133
|
+
// mostly a nudge — but it also broadcasts runtime:changed so any
|
|
134
|
+
// connected electron webContents can reload. silent failure is fine;
|
|
135
|
+
// the next daemon start picks up the active file from disk.
|
|
136
|
+
const notified = await tellDaemonRuntimeChanged(version)
|
|
137
|
+
if (!notified) {
|
|
138
|
+
console.log(
|
|
139
|
+
` (no daemon running — next rnx/electron launch will pick up ${version})`,
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** notify a running daemon that the active runtime changed so it hot-swaps
|
|
145
|
+
* its http root + pushes a runtime:changed message to every connected
|
|
146
|
+
* browser (electron). uses a raw WebSocket to skip the bridge's
|
|
147
|
+
* primary-browser resolution — this message is daemon-only, not routed
|
|
148
|
+
* to a browser. returns true when the daemon acknowledged; false when
|
|
149
|
+
* no fresh daemon was reachable (caller logs accordingly).
|
|
150
|
+
*
|
|
151
|
+
* skips the ws probe entirely when the lockfile isn't fresh — the
|
|
152
|
+
* default-port fallback in resolveDefaultBridgePort() would otherwise
|
|
153
|
+
* eat a full handshakeTimeout on every `runtime use` when no daemon
|
|
154
|
+
* is running. */
|
|
155
|
+
async function tellDaemonRuntimeChanged(version: string): Promise<boolean> {
|
|
156
|
+
const { isDaemonLockfileFresh, readDaemonLockfile } =
|
|
157
|
+
await import('../../src/home-paths')
|
|
158
|
+
const lock = readDaemonLockfile()
|
|
159
|
+
if (!isDaemonLockfileFresh(lock)) return false
|
|
160
|
+
const port = resolveDefaultBridgePort()
|
|
161
|
+
return new Promise<boolean>((resolve) => {
|
|
162
|
+
let settled = false
|
|
163
|
+
let success = false
|
|
164
|
+
const finish = (ok: boolean) => {
|
|
165
|
+
if (settled) return
|
|
166
|
+
settled = true
|
|
167
|
+
resolve(ok)
|
|
168
|
+
}
|
|
169
|
+
const ws = new WebSocket(`ws://127.0.0.1:${port}`, {
|
|
170
|
+
handshakeTimeout: 800,
|
|
171
|
+
})
|
|
172
|
+
const timer = setTimeout(() => {
|
|
173
|
+
try {
|
|
174
|
+
ws.close()
|
|
175
|
+
} catch {}
|
|
176
|
+
finish(success)
|
|
177
|
+
}, 1500)
|
|
178
|
+
ws.on('open', () => {
|
|
179
|
+
try {
|
|
180
|
+
ws.send(JSON.stringify({ type: 'runtime:use', version, id: 0 }))
|
|
181
|
+
success = true
|
|
182
|
+
} catch {}
|
|
183
|
+
// give the daemon a beat to process, then close
|
|
184
|
+
setTimeout(() => {
|
|
185
|
+
try {
|
|
186
|
+
ws.close()
|
|
187
|
+
} catch {}
|
|
188
|
+
}, 100)
|
|
189
|
+
})
|
|
190
|
+
ws.on('close', () => {
|
|
191
|
+
clearTimeout(timer)
|
|
192
|
+
finish(success)
|
|
193
|
+
})
|
|
194
|
+
ws.on('error', () => {
|
|
195
|
+
clearTimeout(timer)
|
|
196
|
+
finish(false)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// --- list -----------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
async function runtimeList(_args: string[]) {
|
|
204
|
+
ensureRnxHome()
|
|
205
|
+
const installed = rnxRuntime.listInstalled()
|
|
206
|
+
const active = readActiveRuntime()
|
|
207
|
+
console.log(`installed:`)
|
|
208
|
+
if (installed.length === 0) {
|
|
209
|
+
console.log(` (none)`)
|
|
210
|
+
} else {
|
|
211
|
+
for (const v of installed) {
|
|
212
|
+
const marker = v === active ? '*' : ' '
|
|
213
|
+
console.log(` ${marker} ${v}`)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const manifest = await rnxRuntime.fetchManifest()
|
|
218
|
+
console.log(`available (latest per channel):`)
|
|
219
|
+
for (const [name, ch] of Object.entries(manifest.channels)) {
|
|
220
|
+
console.log(` ${name.padEnd(8)} ${ch.latest}`)
|
|
221
|
+
}
|
|
222
|
+
const hosted = Object.keys(manifest.versions).sort(compareSemver).reverse()
|
|
223
|
+
if (hosted.length > 1) {
|
|
224
|
+
console.log(`hosted versions:`)
|
|
225
|
+
for (const v of hosted) console.log(` ${v}`)
|
|
226
|
+
}
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.log(`available: (could not fetch manifest: ${describeError(err)})`)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// --- use ------------------------------------------------------------------
|
|
233
|
+
|
|
234
|
+
async function runtimeUse(args: string[]) {
|
|
235
|
+
const version = args[0]
|
|
236
|
+
if (!version) {
|
|
237
|
+
console.error(` usage: rnx runtime use <version>`)
|
|
238
|
+
rnxExit(1)
|
|
239
|
+
}
|
|
240
|
+
const installed = rnxRuntime.listInstalled()
|
|
241
|
+
if (!installed.includes(version)) {
|
|
242
|
+
console.error(` version ${version} is not installed`)
|
|
243
|
+
console.error(` installed: ${installed.join(', ') || '(none)'}`)
|
|
244
|
+
console.error(` run \`rnx runtime install ${version}\` first`)
|
|
245
|
+
rnxExit(1)
|
|
246
|
+
}
|
|
247
|
+
await activateVersion(version)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --- remove ---------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
async function runtimeRemove(args: string[]) {
|
|
253
|
+
const version = args[0]
|
|
254
|
+
if (!version) {
|
|
255
|
+
console.error(` usage: rnx runtime remove <version>`)
|
|
256
|
+
rnxExit(1)
|
|
257
|
+
}
|
|
258
|
+
const active = readActiveRuntime()
|
|
259
|
+
if (active === version) {
|
|
260
|
+
console.error(` cannot remove active runtime ${version}`)
|
|
261
|
+
console.error(
|
|
262
|
+
` switch with \`rnx runtime use <other>\` first, or install another version`,
|
|
263
|
+
)
|
|
264
|
+
rnxExit(1)
|
|
265
|
+
}
|
|
266
|
+
if (readLiveRuntimeVersions().includes(version)) {
|
|
267
|
+
console.error(` cannot remove runtime ${version} while a project is using it`)
|
|
268
|
+
rnxExit(1)
|
|
269
|
+
}
|
|
270
|
+
const dir = runtimeDir(version)
|
|
271
|
+
if (!fs.existsSync(dir)) {
|
|
272
|
+
console.error(` ${version} is not installed`)
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
fs.rmSync(dir, { recursive: true, force: true })
|
|
276
|
+
console.log(` removed ${version}`)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// --- which ----------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
async function runtimeWhich() {
|
|
282
|
+
const active = readActiveRuntime()
|
|
283
|
+
if (!active) {
|
|
284
|
+
console.log(` no active runtime`)
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
console.log(active)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// --- notes ----------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
async function runtimeNotes(args: string[]) {
|
|
293
|
+
if (args.length > 0) {
|
|
294
|
+
console.error(` usage: rnx runtime notes`)
|
|
295
|
+
rnxExit(1)
|
|
296
|
+
}
|
|
297
|
+
const { config } = await resolveRNXAppConfig()
|
|
298
|
+
const version = config?.runtimeVersion ?? readActiveRuntime()
|
|
299
|
+
if (!version) {
|
|
300
|
+
console.log(` no active runtime`)
|
|
301
|
+
console.log(` release notes: ${RNX_CHANGELOG_URL}`)
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
console.log(formatRuntimeReleaseNotes(version, await fetchRuntimeReleaseNotes(version)))
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// --- helpers --------------------------------------------------------------
|
|
308
|
+
|
|
309
|
+
interface InstallFlags {
|
|
310
|
+
channel?: string
|
|
311
|
+
force?: boolean
|
|
312
|
+
setActive?: boolean
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function parseVersionAndFlags(args: string[]): {
|
|
316
|
+
version: string | null
|
|
317
|
+
flags: InstallFlags
|
|
318
|
+
} {
|
|
319
|
+
const flags: InstallFlags = {}
|
|
320
|
+
const positional: string[] = []
|
|
321
|
+
for (let i = 0; i < args.length; i++) {
|
|
322
|
+
const arg = args[i]
|
|
323
|
+
if (arg === '--channel' && i + 1 < args.length) {
|
|
324
|
+
flags.channel = args[i + 1]
|
|
325
|
+
i++
|
|
326
|
+
continue
|
|
327
|
+
}
|
|
328
|
+
if (arg.startsWith('--channel=')) {
|
|
329
|
+
flags.channel = arg.slice('--channel='.length)
|
|
330
|
+
continue
|
|
331
|
+
}
|
|
332
|
+
if (arg === '--force') {
|
|
333
|
+
flags.force = true
|
|
334
|
+
continue
|
|
335
|
+
}
|
|
336
|
+
if (arg === '--set-active=false' || arg === '--no-set-active') {
|
|
337
|
+
flags.setActive = false
|
|
338
|
+
continue
|
|
339
|
+
}
|
|
340
|
+
positional.push(arg)
|
|
341
|
+
}
|
|
342
|
+
return { version: positional[0] ?? null, flags }
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function describeError(err: unknown): string {
|
|
346
|
+
if (err instanceof Error) return err.message
|
|
347
|
+
return String(err)
|
|
348
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { runScreenshot } from './screenshot'
|
|
2
|
+
import { runScreenshots } from './screenshots'
|
|
3
|
+
import { runSlides } from './slides'
|
|
4
|
+
|
|
5
|
+
interface ScreenshotCommandOptions {
|
|
6
|
+
port?: number
|
|
7
|
+
verbose?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const VALUE_FLAGS = new Set([
|
|
11
|
+
'--sim',
|
|
12
|
+
'--port',
|
|
13
|
+
'-p',
|
|
14
|
+
'--output',
|
|
15
|
+
'-o',
|
|
16
|
+
'--out',
|
|
17
|
+
'--plan',
|
|
18
|
+
'--app',
|
|
19
|
+
'--device',
|
|
20
|
+
'--org',
|
|
21
|
+
'--repo',
|
|
22
|
+
'--api-origin',
|
|
23
|
+
'--branch',
|
|
24
|
+
'--platform',
|
|
25
|
+
'--slides',
|
|
26
|
+
'--shell-origin',
|
|
27
|
+
'--timeout',
|
|
28
|
+
'--ids',
|
|
29
|
+
'--out-dir',
|
|
30
|
+
])
|
|
31
|
+
const SUBCOMMANDS = new Set(['capture', 'slides', 'appstore', 'layers'])
|
|
32
|
+
|
|
33
|
+
function findSubcommand(args: string[]): { name: string; index: number } | null {
|
|
34
|
+
for (let i = 0; i < args.length; i++) {
|
|
35
|
+
const arg = args[i]
|
|
36
|
+
if (arg.startsWith('-')) {
|
|
37
|
+
if (VALUE_FLAGS.has(arg)) i++
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
return SUBCOMMANDS.has(arg) ? { name: arg, index: i } : null
|
|
41
|
+
}
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function removeAt(args: string[], index: number): string[] {
|
|
46
|
+
return [...args.slice(0, index), ...args.slice(index + 1)]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stripSimFlag(args: string[]): string[] {
|
|
50
|
+
const out: string[] = []
|
|
51
|
+
for (let i = 0; i < args.length; i++) {
|
|
52
|
+
if (args[i] === '--sim') {
|
|
53
|
+
i++
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
out.push(args[i])
|
|
57
|
+
}
|
|
58
|
+
return out
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function runScreenshotCommand(
|
|
62
|
+
args: string[],
|
|
63
|
+
opts: ScreenshotCommandOptions,
|
|
64
|
+
): Promise<number | void> {
|
|
65
|
+
const sub = findSubcommand(args)
|
|
66
|
+
if (!sub || sub.name === 'capture') {
|
|
67
|
+
await runScreenshot(sub ? removeAt(args, sub.index) : args, opts)
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (sub.name === 'slides') {
|
|
72
|
+
await runSlides(removeAt(args, sub.index), opts)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (sub.name === 'layers') {
|
|
77
|
+
const { runScreenshotLayers } = await import('./screenshot-layers')
|
|
78
|
+
await runScreenshotLayers(removeAt(args, sub.index), opts)
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const appstoreArgs = removeAt(args, sub.index)
|
|
83
|
+
const nested = findSubcommand(appstoreArgs)
|
|
84
|
+
if (nested?.name === 'capture') {
|
|
85
|
+
// repo-only tooling: screenshots-capture statically imports playwright-core,
|
|
86
|
+
// which the published CLI never ships (it's external in build-cli.ts). a
|
|
87
|
+
// static import here would put that bare import at the top of THIS chunk,
|
|
88
|
+
// so every published `rnx screenshot` printed ERR_MODULE_NOT_FOUND —
|
|
89
|
+
// keep it a runtime dynamic import that only evaluates when capture runs.
|
|
90
|
+
try {
|
|
91
|
+
const { runScreenshotsCapture } = await import('./screenshots-capture')
|
|
92
|
+
return await runScreenshotsCapture(
|
|
93
|
+
stripSimFlag(removeAt(appstoreArgs, nested.index)),
|
|
94
|
+
)
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (err instanceof Error && 'code' in err && err.code === 'ERR_MODULE_NOT_FOUND') {
|
|
97
|
+
console.error(
|
|
98
|
+
'screenshot appstore capture is repo-only tooling — it needs the rnx workspace (playwright is not shipped with the published CLI).',
|
|
99
|
+
)
|
|
100
|
+
return 1
|
|
101
|
+
}
|
|
102
|
+
throw err
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return runScreenshots(appstoreArgs, opts)
|
|
106
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// rnx screenshot layers — engine-rendered layer isolation export.
|
|
2
|
+
//
|
|
3
|
+
// captures one screen as a stack the 3d stage can pull apart: `full.png` is
|
|
4
|
+
// the normal frame, `base.png` re-renders the frame with the target subtrees
|
|
5
|
+
// hidden (content and glass blur behind them are real, not inpainted), and
|
|
6
|
+
// each `layer-<testID>.png` draws exactly that subtree alone on transparency
|
|
7
|
+
// at its on-screen position. `manifest.json` records device metrics and the
|
|
8
|
+
// logical rect of every layer.
|
|
9
|
+
|
|
10
|
+
import { mkdirSync, writeFileSync } from 'fs'
|
|
11
|
+
import { resolve } from 'path'
|
|
12
|
+
import { devices } from 'sootsim-engine/settings'
|
|
13
|
+
import { buildResolveRectEval, type SampleRect } from '../browser-evals'
|
|
14
|
+
import { rnxExit } from '../run-rnx'
|
|
15
|
+
import { callInBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
|
|
16
|
+
import { inspectWaitReady, waitReadyReason } from './inspect/core'
|
|
17
|
+
|
|
18
|
+
interface ScreenshotLayersOptions {
|
|
19
|
+
port?: number
|
|
20
|
+
verbose?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function runScreenshotLayers(
|
|
24
|
+
args: string[],
|
|
25
|
+
opts: ScreenshotLayersOptions,
|
|
26
|
+
): Promise<void> {
|
|
27
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
28
|
+
console.log(`
|
|
29
|
+
rnx screenshot layers — export a screen as engine-isolated layers
|
|
30
|
+
|
|
31
|
+
usage:
|
|
32
|
+
rnx screenshot layers --ids <testID,testID,...> [--out-dir <dir>]
|
|
33
|
+
|
|
34
|
+
options:
|
|
35
|
+
--ids <list> comma-separated testIDs of the subtrees to isolate
|
|
36
|
+
--out-dir <dir> output directory (default: /tmp/rnx-layers)
|
|
37
|
+
|
|
38
|
+
output:
|
|
39
|
+
full.png the normal frame
|
|
40
|
+
base.png the frame re-rendered with every listed subtree hidden
|
|
41
|
+
layer-<id>.png each subtree rendered alone on a transparent frame
|
|
42
|
+
manifest.json device metrics + logical rect per layer
|
|
43
|
+
`)
|
|
44
|
+
rnxExit(0)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const idsArg = args.find((_, i) => args[i - 1] === '--ids')
|
|
48
|
+
if (!idsArg) {
|
|
49
|
+
console.error(' --ids is required (comma-separated testIDs)')
|
|
50
|
+
rnxExit(1)
|
|
51
|
+
}
|
|
52
|
+
const testIds = idsArg
|
|
53
|
+
.split(',')
|
|
54
|
+
.map((entry) => entry.trim())
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
if (testIds.length === 0) {
|
|
57
|
+
console.error(' --ids resolved to an empty list')
|
|
58
|
+
rnxExit(1)
|
|
59
|
+
}
|
|
60
|
+
const outDirArg = args.find((_, i) => args[i - 1] === '--out-dir')
|
|
61
|
+
const outDir = resolve(process.cwd(), outDirArg ?? '/tmp/rnx-layers')
|
|
62
|
+
|
|
63
|
+
const parsed = parseBridgeCliArgs(args, {
|
|
64
|
+
port: opts.port,
|
|
65
|
+
stripValueFlags: ['--ids', '--out-dir'],
|
|
66
|
+
})
|
|
67
|
+
const bridge = createBridgeFromParsed({ ...parsed, commandTimeoutMs: 45000 })
|
|
68
|
+
try {
|
|
69
|
+
const readiness = await inspectWaitReady(bridge, 90_000)
|
|
70
|
+
if (!readiness.ready) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`app not ready to capture after ${Math.round(readiness.elapsedMs / 1000)}s ` +
|
|
73
|
+
`(${waitReadyReason(readiness)})`,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const rects: Record<string, SampleRect> = {}
|
|
78
|
+
for (const testId of testIds) {
|
|
79
|
+
const node = await bridge.send({
|
|
80
|
+
type: 'evaluate',
|
|
81
|
+
code: buildResolveRectEval({ id: testId }),
|
|
82
|
+
})
|
|
83
|
+
if (!node) throw new Error(`no node with testID "${testId}"`)
|
|
84
|
+
rects[testId] = node as SampleRect
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
mkdirSync(outDir, { recursive: true })
|
|
88
|
+
const savePng = (name: string, dataUrl: unknown) => {
|
|
89
|
+
if (typeof dataUrl !== 'string' || !dataUrl.startsWith('data:image/png;base64,')) {
|
|
90
|
+
throw new Error(`capture for ${name} returned no image data`)
|
|
91
|
+
}
|
|
92
|
+
const path = resolve(outDir, name)
|
|
93
|
+
writeFileSync(
|
|
94
|
+
path,
|
|
95
|
+
Buffer.from(dataUrl.slice('data:image/png;base64,'.length), 'base64'),
|
|
96
|
+
)
|
|
97
|
+
console.log(` saved: ${path}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
savePng('full.png', await bridge.send({ type: 'screenshot' }))
|
|
101
|
+
savePng(
|
|
102
|
+
'base.png',
|
|
103
|
+
await bridge.send({
|
|
104
|
+
type: 'screenshot',
|
|
105
|
+
captureFilter: { hideTestIds: testIds },
|
|
106
|
+
}),
|
|
107
|
+
)
|
|
108
|
+
for (const testId of testIds) {
|
|
109
|
+
// every other listed target hides inside this solo, so nested targets
|
|
110
|
+
// (a button inside a lifted card) land in exactly one layer.
|
|
111
|
+
savePng(
|
|
112
|
+
`layer-${testId}.png`,
|
|
113
|
+
await bridge.send({
|
|
114
|
+
type: 'screenshot',
|
|
115
|
+
captureFilter: {
|
|
116
|
+
soloTestId: testId,
|
|
117
|
+
hideTestIds: testIds.filter((other) => other !== testId),
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const settings = (await callInBridge<Record<string, unknown> | null>(
|
|
124
|
+
bridge,
|
|
125
|
+
'SootSim.bridges.settings.get',
|
|
126
|
+
)) ?? { deviceModel: null }
|
|
127
|
+
const model =
|
|
128
|
+
typeof settings.deviceModel === 'string' && settings.deviceModel in devices
|
|
129
|
+
? settings.deviceModel
|
|
130
|
+
: null
|
|
131
|
+
const device = model ? devices[model as keyof typeof devices] : null
|
|
132
|
+
const manifest = {
|
|
133
|
+
device: device
|
|
134
|
+
? { model, width: device.width, height: device.height, scale: device.scale }
|
|
135
|
+
: { model },
|
|
136
|
+
layers: testIds.map((testId) => ({ testId, rect: rects[testId] })),
|
|
137
|
+
}
|
|
138
|
+
const manifestPath = resolve(outDir, 'manifest.json')
|
|
139
|
+
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
140
|
+
console.log(` saved: ${manifestPath}`)
|
|
141
|
+
} finally {
|
|
142
|
+
bridge.close()
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// rnx mode screenshot — toggle the "screenshot mode" chrome overlay
|
|
2
|
+
// in the running rnx sim. orthogonal to `--no-shell` on the
|
|
3
|
+
// `screenshot` command: this hides the DOM browser chrome (rail, menubar,
|
|
4
|
+
// window controls) while still rendering the iOS shell inside the canvas.
|
|
5
|
+
//
|
|
6
|
+
// wraps the existing `toggle-screenshot-mode` shell action so the CLI
|
|
7
|
+
// stays behavior-compatible with the menu item / keyboard shortcut.
|
|
8
|
+
|
|
9
|
+
import { rnxExit } from '../run-rnx'
|
|
10
|
+
import { runShellBooleanMode, type ShellBooleanModeOptions } from './shell-boolean-mode'
|
|
11
|
+
|
|
12
|
+
export async function runScreenshotMode(args: string[], opts: ShellBooleanModeOptions) {
|
|
13
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
14
|
+
console.log(`
|
|
15
|
+
rnx mode screenshot — toggle the screenshot-mode chrome overlay
|
|
16
|
+
|
|
17
|
+
usage:
|
|
18
|
+
rnx mode screenshot [on|off|toggle]
|
|
19
|
+
|
|
20
|
+
arguments:
|
|
21
|
+
on enable screenshot mode (enables showFrame if needed)
|
|
22
|
+
off disable screenshot mode
|
|
23
|
+
toggle flip the current state (default)
|
|
24
|
+
|
|
25
|
+
examples:
|
|
26
|
+
rnx mode screenshot
|
|
27
|
+
rnx mode screenshot on
|
|
28
|
+
rnx mode screenshot off
|
|
29
|
+
`)
|
|
30
|
+
rnxExit(0)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await runShellBooleanMode(args, opts, {
|
|
34
|
+
modeKey: 'screenshotMode',
|
|
35
|
+
displayName: 'screenshot-mode',
|
|
36
|
+
actionId: 'toggle-screenshot-mode',
|
|
37
|
+
})
|
|
38
|
+
}
|