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,751 @@
|
|
|
1
|
+
// rnx debug — drive __sootsimDebug.* from the terminal
|
|
2
|
+
//
|
|
3
|
+
// connects to a running rnx instance via the WebSocket bridge and forwards
|
|
4
|
+
// debug channel management, tree snapshots, and on-demand inspectors without
|
|
5
|
+
// requiring a browser console.
|
|
6
|
+
//
|
|
7
|
+
// usage examples:
|
|
8
|
+
// rnx debug enable sheets,portals,onlayout
|
|
9
|
+
// rnx debug status
|
|
10
|
+
// rnx debug snapshot before
|
|
11
|
+
// # ... tap something in the UI ...
|
|
12
|
+
// rnx debug snapshot after
|
|
13
|
+
// rnx debug diff before after
|
|
14
|
+
// rnx debug find sheets
|
|
15
|
+
// rnx debug find portals
|
|
16
|
+
// rnx debug recent portals
|
|
17
|
+
// rnx debug flags
|
|
18
|
+
//
|
|
19
|
+
// all commands print JSON by default so they pipe cleanly into jq.
|
|
20
|
+
|
|
21
|
+
import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
|
|
22
|
+
import { printBridgeFailureDiagnostics } from '../bridge-diagnostics'
|
|
23
|
+
import { rethrowIfExit, rnxExit } from '../run-rnx'
|
|
24
|
+
import {
|
|
25
|
+
createBridgeFromParsed,
|
|
26
|
+
evalInBridge,
|
|
27
|
+
parseBridgeCliArgs,
|
|
28
|
+
type WsBridge,
|
|
29
|
+
} from '../ws-bridge'
|
|
30
|
+
import {
|
|
31
|
+
callDebugBridge,
|
|
32
|
+
inspectDebugFind,
|
|
33
|
+
inspectDebugFlags,
|
|
34
|
+
inspectDebugRecent,
|
|
35
|
+
inspectDebugStatus,
|
|
36
|
+
setDebugChannels,
|
|
37
|
+
} from './inspect/core'
|
|
38
|
+
import { callTestBridge } from './inspect/shared'
|
|
39
|
+
|
|
40
|
+
interface DebugOptions {
|
|
41
|
+
port?: number
|
|
42
|
+
verbose?: boolean
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const KNOWN_CHANNELS = [
|
|
46
|
+
'portals',
|
|
47
|
+
'sheets',
|
|
48
|
+
'layout',
|
|
49
|
+
'onlayout',
|
|
50
|
+
'animated',
|
|
51
|
+
'render',
|
|
52
|
+
'touch',
|
|
53
|
+
'yoga',
|
|
54
|
+
'all',
|
|
55
|
+
] as const
|
|
56
|
+
|
|
57
|
+
const SHELL_TRACE_STORE_GLOBAL = '__sootsimShellAnimationTrace'
|
|
58
|
+
const SHELL_TRACE_HOOK_GLOBAL = '__sootsimDebugAnimation'
|
|
59
|
+
|
|
60
|
+
function printHelp() {
|
|
61
|
+
console.log(`
|
|
62
|
+
rnx debug — drive __sootsimDebug from the terminal
|
|
63
|
+
|
|
64
|
+
usage:
|
|
65
|
+
rnx debug <subcommand> [args]
|
|
66
|
+
|
|
67
|
+
record, recent, and clear-events target the tenant; --host selects the page buffer.
|
|
68
|
+
enable/disable/toggle also update the tenant unless --host is passed.
|
|
69
|
+
shell event buffers are separate; shell console logs are forwarded to the host.
|
|
70
|
+
|
|
71
|
+
subcommands:
|
|
72
|
+
enable <channels> turn on host, shell/compositor, and tenant channels
|
|
73
|
+
channels: ${KNOWN_CHANNELS.slice(0, -1).join(', ')}
|
|
74
|
+
or 'all' for every channel
|
|
75
|
+
disable <channels> turn off one or more debug channels (or 'all')
|
|
76
|
+
toggle <channel> flip a single channel
|
|
77
|
+
status list host channels forwarded to shell/compositor
|
|
78
|
+
channels list every known channel name
|
|
79
|
+
flags print the host DEBUG flag object
|
|
80
|
+
|
|
81
|
+
state <kind> ... dump raw runtime state (diagnostic — not a getter)
|
|
82
|
+
kinds: shell, worker, keyboard, node <id>,
|
|
83
|
+
scroll <id>, scroll-hit <x> <y>,
|
|
84
|
+
hit <x> <y>, gesture <x> <y>
|
|
85
|
+
|
|
86
|
+
js <code> execute javascript in the running app. rnx
|
|
87
|
+
is the canonical state object — reach into its
|
|
88
|
+
bridges / state / chrome / debug slots directly.
|
|
89
|
+
e.g. SootSim.bridges.test.findByText("Sign in")
|
|
90
|
+
eval <code> alias for js
|
|
91
|
+
perf <sub> shell frame profiling: start, stop, transition
|
|
92
|
+
memory [--watch [s]] per-worker object counts + heaps; --watch samples
|
|
93
|
+
every --interval seconds and reports slopes
|
|
94
|
+
sample-color <...> sample averaged color from canvas (same flags as
|
|
95
|
+
screenshot)
|
|
96
|
+
|
|
97
|
+
snapshot [label] capture a tree snapshot (layout + transform + opacity)
|
|
98
|
+
snapshots list taken snapshot labels
|
|
99
|
+
diff <a> <b> compare two snapshots by label
|
|
100
|
+
clear-snapshots [label] drop a snapshot (or all if no label given)
|
|
101
|
+
|
|
102
|
+
image-audit for every image the compositor actually drew, the
|
|
103
|
+
source pixels it landed on each device pixel. a row
|
|
104
|
+
whose shortfall is well under 1.0 is an image the
|
|
105
|
+
pipeline under-resolved; 0.5 is half resolution.
|
|
106
|
+
flags: --min <ratio> (default 0.98), --all, --json
|
|
107
|
+
exits 1 when any image is under the ratio, and 2 when
|
|
108
|
+
the audit observed no image draws at all
|
|
109
|
+
|
|
110
|
+
find sheets dump Sheet.Frame-shaped nodes currently in the tree
|
|
111
|
+
find portals dump portal-host / portal-view nodes
|
|
112
|
+
find boundaries dump live paint boundaries (+ why scroll rows were
|
|
113
|
+
rejected from the auto-retained raster tier)
|
|
114
|
+
|
|
115
|
+
trace shell [cmd] opt-in shell animation trace
|
|
116
|
+
cmds: on [limit], off, status, clear, [recentLimit]
|
|
117
|
+
trace anim <sub> opt-in per-tick animation value trace
|
|
118
|
+
subs: on <id|all> [limit], off [id|all],
|
|
119
|
+
status, clear, <id> [limit]
|
|
120
|
+
record [on|off] toggle event ring buffer recording
|
|
121
|
+
recent [channel] [n] last N events (default 50), optionally filtered
|
|
122
|
+
clear-events clear the event ring buffer
|
|
123
|
+
|
|
124
|
+
options:
|
|
125
|
+
--port <port> WS bridge port (default: ${DEFAULT_SOOTSIM_BRIDGE_PORT})
|
|
126
|
+
--sim <sim> target a specific connected sim
|
|
127
|
+
--pretty format JSON output for humans (default)
|
|
128
|
+
--json compact JSON output for pipelines
|
|
129
|
+
|
|
130
|
+
examples:
|
|
131
|
+
rnx debug enable sheets,portals
|
|
132
|
+
rnx debug snapshot before
|
|
133
|
+
rnx debug snapshot after
|
|
134
|
+
rnx debug diff before after
|
|
135
|
+
rnx debug image-audit per-image source pixels per device pixel
|
|
136
|
+
rnx debug find sheets | jq '.[] | select(.translateY != null)'
|
|
137
|
+
rnx debug trace shell on 240
|
|
138
|
+
rnx debug trace shell 120
|
|
139
|
+
rnx debug trace anim on 3 240
|
|
140
|
+
rnx debug trace anim 3 60
|
|
141
|
+
`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function parseChannelList(raw: string | undefined): string[] {
|
|
145
|
+
if (!raw) return []
|
|
146
|
+
return raw
|
|
147
|
+
.split(',')
|
|
148
|
+
.map((s) => s.trim())
|
|
149
|
+
.filter(Boolean)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function fmt(value: unknown, pretty: boolean): string {
|
|
153
|
+
if (value === undefined) return ''
|
|
154
|
+
return JSON.stringify(value, null, pretty ? 2 : 0)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function buildShellTraceControlCode(
|
|
158
|
+
action: 'on' | 'off' | 'clear' | 'status',
|
|
159
|
+
limit = 240,
|
|
160
|
+
): string {
|
|
161
|
+
const normalizedLimit =
|
|
162
|
+
Number.isFinite(limit) && limit > 0 ? Math.max(1, Math.round(limit)) : 240
|
|
163
|
+
const storeKey = JSON.stringify(SHELL_TRACE_STORE_GLOBAL)
|
|
164
|
+
const hookKey = JSON.stringify(SHELL_TRACE_HOOK_GLOBAL)
|
|
165
|
+
if (action === 'on') {
|
|
166
|
+
return `(() => {
|
|
167
|
+
const root = window
|
|
168
|
+
const store = root[${storeKey}] || (root[${storeKey}] = {
|
|
169
|
+
enabled: false,
|
|
170
|
+
limit: ${normalizedLimit},
|
|
171
|
+
seq: 0,
|
|
172
|
+
samples: [],
|
|
173
|
+
prevHook: undefined,
|
|
174
|
+
hook: undefined,
|
|
175
|
+
})
|
|
176
|
+
store.limit = ${normalizedLimit}
|
|
177
|
+
store.enabled = true
|
|
178
|
+
const currentHook = root[${hookKey}]
|
|
179
|
+
if (store.hook !== currentHook) {
|
|
180
|
+
store.prevHook = typeof currentHook === 'function' ? currentHook : undefined
|
|
181
|
+
}
|
|
182
|
+
if (typeof store.hook !== 'function') {
|
|
183
|
+
store.hook = (sample) => {
|
|
184
|
+
const target = root[${storeKey}]
|
|
185
|
+
if (!target || target.enabled !== true) return
|
|
186
|
+
const samples = Array.isArray(target.samples) ? target.samples : (target.samples = [])
|
|
187
|
+
target.seq = typeof target.seq === 'number' ? target.seq + 1 : 1
|
|
188
|
+
samples.push({ seq: target.seq, ...sample })
|
|
189
|
+
if (samples.length > target.limit) {
|
|
190
|
+
samples.splice(0, samples.length - target.limit)
|
|
191
|
+
}
|
|
192
|
+
if (typeof target.prevHook === 'function') {
|
|
193
|
+
try {
|
|
194
|
+
target.prevHook(sample)
|
|
195
|
+
} catch {}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
root[${hookKey}] = store.hook
|
|
200
|
+
return {
|
|
201
|
+
enabled: true,
|
|
202
|
+
limit: store.limit,
|
|
203
|
+
count: Array.isArray(store.samples) ? store.samples.length : 0,
|
|
204
|
+
}
|
|
205
|
+
})()`
|
|
206
|
+
}
|
|
207
|
+
if (action === 'off') {
|
|
208
|
+
return `(() => {
|
|
209
|
+
const root = window
|
|
210
|
+
const store = root[${storeKey}]
|
|
211
|
+
if (!store) return { enabled: false, limit: 0, count: 0 }
|
|
212
|
+
store.enabled = false
|
|
213
|
+
if (root[${hookKey}] === store.hook) {
|
|
214
|
+
root[${hookKey}] = typeof store.prevHook === 'function' ? store.prevHook : undefined
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
enabled: false,
|
|
218
|
+
limit: typeof store.limit === 'number' ? store.limit : 0,
|
|
219
|
+
count: Array.isArray(store.samples) ? store.samples.length : 0,
|
|
220
|
+
}
|
|
221
|
+
})()`
|
|
222
|
+
}
|
|
223
|
+
if (action === 'clear') {
|
|
224
|
+
return `(() => {
|
|
225
|
+
const store = window[${storeKey}]
|
|
226
|
+
if (!store) return { cleared: true, count: 0 }
|
|
227
|
+
store.samples = []
|
|
228
|
+
store.seq = 0
|
|
229
|
+
return {
|
|
230
|
+
cleared: true,
|
|
231
|
+
enabled: store.enabled === true,
|
|
232
|
+
limit: typeof store.limit === 'number' ? store.limit : 0,
|
|
233
|
+
count: 0,
|
|
234
|
+
}
|
|
235
|
+
})()`
|
|
236
|
+
}
|
|
237
|
+
return `(() => {
|
|
238
|
+
const store = window[${storeKey}]
|
|
239
|
+
return {
|
|
240
|
+
enabled: !!store?.enabled,
|
|
241
|
+
limit: typeof store?.limit === 'number' ? store.limit : 0,
|
|
242
|
+
count: Array.isArray(store?.samples) ? store.samples.length : 0,
|
|
243
|
+
}
|
|
244
|
+
})()`
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function buildShellTraceRecentCode(limit = 50): string {
|
|
248
|
+
const normalizedLimit =
|
|
249
|
+
Number.isFinite(limit) && limit > 0 ? Math.max(1, Math.round(limit)) : 50
|
|
250
|
+
const storeKey = JSON.stringify(SHELL_TRACE_STORE_GLOBAL)
|
|
251
|
+
return `(() => {
|
|
252
|
+
const store = window[${storeKey}]
|
|
253
|
+
const all = Array.isArray(store?.samples) ? store.samples : []
|
|
254
|
+
const samples = all.slice(-${normalizedLimit})
|
|
255
|
+
const first = samples[0] ?? null
|
|
256
|
+
const last = samples[samples.length - 1] ?? null
|
|
257
|
+
const uniquePhases = [...new Set(samples.map((sample) => sample?.phase).filter(Boolean))]
|
|
258
|
+
const metricRange = (key) => {
|
|
259
|
+
const values = samples
|
|
260
|
+
.map((sample) => (typeof sample?.[key] === 'number' ? sample[key] : null))
|
|
261
|
+
.filter((value) => value != null)
|
|
262
|
+
if (values.length === 0) return null
|
|
263
|
+
return {
|
|
264
|
+
min: Math.min(...values),
|
|
265
|
+
max: Math.max(...values),
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
enabled: !!store?.enabled,
|
|
270
|
+
limit: typeof store?.limit === 'number' ? store.limit : 0,
|
|
271
|
+
count: samples.length,
|
|
272
|
+
total: all.length,
|
|
273
|
+
summary: first && last ? {
|
|
274
|
+
durationMs: last.ts - first.ts,
|
|
275
|
+
phases: uniquePhases,
|
|
276
|
+
start: first,
|
|
277
|
+
end: last,
|
|
278
|
+
zoomLevel: metricRange('zoomLevel'),
|
|
279
|
+
horizontalZoom: metricRange('horizontalZoom'),
|
|
280
|
+
launchProgress: metricRange('launchProgress'),
|
|
281
|
+
dismissOffsetY: metricRange('dismissOffsetY'),
|
|
282
|
+
} : null,
|
|
283
|
+
samples,
|
|
284
|
+
}
|
|
285
|
+
})()`
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async function call<T = unknown>(bridge: WsBridge, code: string): Promise<T> {
|
|
289
|
+
return evalInBridge<T>(bridge, code)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
interface ImageAuditRowView {
|
|
293
|
+
nodeId: number
|
|
294
|
+
type: string
|
|
295
|
+
testID: string | null
|
|
296
|
+
sourceUri: string | null
|
|
297
|
+
resizeMode: string | null
|
|
298
|
+
sampling: string | null
|
|
299
|
+
vector: boolean
|
|
300
|
+
intrinsic: { width: number; height: number } | null
|
|
301
|
+
decoded: { width: number; height: number }
|
|
302
|
+
sampled: { width: number; height: number }
|
|
303
|
+
destination: { x: number; y: number; width: number; height: number }
|
|
304
|
+
decision: { gpuBacked: boolean; hasMipmaps: boolean }
|
|
305
|
+
deviceScale: number
|
|
306
|
+
dpr: number
|
|
307
|
+
needed: { width: number; height: number }
|
|
308
|
+
effective: { width: number; height: number }
|
|
309
|
+
ceiling: { width: number; height: number } | null
|
|
310
|
+
shortfall: number | null
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
interface ImageAuditReportView {
|
|
314
|
+
draws: number
|
|
315
|
+
samplingCounts: { mipmapped: number; cubic: number; repeat: number; none: number }
|
|
316
|
+
rows: ImageAuditRowView[]
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function readNumberFlag(args: string[], flag: string): number | null {
|
|
320
|
+
const index = args.indexOf(flag)
|
|
321
|
+
if (index < 0) return null
|
|
322
|
+
const parsed = Number(args[index + 1])
|
|
323
|
+
return Number.isFinite(parsed) ? parsed : null
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// enable the audit, force one real frame, then read and stop. the screenshot
|
|
327
|
+
// request is what forces the frame: it runs the same publish-and-paint pass
|
|
328
|
+
// `rnx screenshot` does, so the rows describe pixels that were actually
|
|
329
|
+
// produced rather than a tree walk's guess about them.
|
|
330
|
+
async function runImageAudit(bridge: WsBridge): Promise<ImageAuditReportView> {
|
|
331
|
+
await call(
|
|
332
|
+
bridge,
|
|
333
|
+
"window.__sootsimCompositor.getStats(false, false, undefined, 'enable').then(() => 'enabled')",
|
|
334
|
+
)
|
|
335
|
+
await bridge.send({ type: 'screenshot' })
|
|
336
|
+
const stats = await call<{ imageAudit?: ImageAuditReportView | null }>(
|
|
337
|
+
bridge,
|
|
338
|
+
"window.__sootsimCompositor.getStats(false, false, undefined, 'disable').then((s) => ({ imageAudit: s.imageAudit }))",
|
|
339
|
+
)
|
|
340
|
+
const report = stats?.imageAudit
|
|
341
|
+
if (!report) throw new Error('compositor returned no image audit')
|
|
342
|
+
return report
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function ratioText(value: number | null): string {
|
|
346
|
+
return value === null ? ' - ' : value.toFixed(3).padStart(6)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function sourceText(row: ImageAuditRowView): string {
|
|
350
|
+
const uri = row.sourceUri ?? row.testID ?? `node ${row.nodeId}`
|
|
351
|
+
if (uri.length <= 58) return uri
|
|
352
|
+
return `...${uri.slice(-55)}`
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function printImageAudit(
|
|
356
|
+
report: ImageAuditReportView,
|
|
357
|
+
rows: ImageAuditRowView[],
|
|
358
|
+
minimum: number,
|
|
359
|
+
): void {
|
|
360
|
+
const withCeiling = report.rows.filter((row) => row.shortfall !== null)
|
|
361
|
+
const under = withCeiling.filter((row) => row.shortfall! < minimum)
|
|
362
|
+
console.log(
|
|
363
|
+
` ${report.rows.length} images drawn (${report.draws} draws), ` +
|
|
364
|
+
`${under.length} below ${minimum} of what their source could deliver`,
|
|
365
|
+
)
|
|
366
|
+
console.log(
|
|
367
|
+
` sampling: mipmapped ${report.samplingCounts.mipmapped} · cubic ${report.samplingCounts.cubic} · ` +
|
|
368
|
+
`repeat ${report.samplingCounts.repeat} · none ${report.samplingCounts.none}`,
|
|
369
|
+
)
|
|
370
|
+
if (rows.length === 0) {
|
|
371
|
+
console.log(' every image delivered its source resolution')
|
|
372
|
+
return
|
|
373
|
+
}
|
|
374
|
+
console.log('')
|
|
375
|
+
console.log(' short eff decoded source needed(dev) dest(pt) dpr image')
|
|
376
|
+
for (const row of rows) {
|
|
377
|
+
const decoded = `${row.decoded.width}x${row.decoded.height}`.padEnd(11)
|
|
378
|
+
const intrinsic = (
|
|
379
|
+
row.vector
|
|
380
|
+
? 'vector'
|
|
381
|
+
: row.intrinsic
|
|
382
|
+
? `${row.intrinsic.width}x${row.intrinsic.height}`
|
|
383
|
+
: '?'
|
|
384
|
+
).padEnd(11)
|
|
385
|
+
const needed =
|
|
386
|
+
`${Math.round(row.needed.width)}x${Math.round(row.needed.height)}`.padEnd(12)
|
|
387
|
+
const dest =
|
|
388
|
+
`${Math.round(row.destination.width)}x${Math.round(row.destination.height)}`.padEnd(
|
|
389
|
+
9,
|
|
390
|
+
)
|
|
391
|
+
console.log(
|
|
392
|
+
` ${ratioText(row.shortfall)} ${ratioText(row.effective.width)} ` +
|
|
393
|
+
`${decoded} ${intrinsic} ${needed} ${dest} ${row.dpr.toFixed(1)} ${sourceText(row)}`,
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export async function runDebug(args: string[], opts: DebugOptions) {
|
|
399
|
+
const parsed = parseBridgeCliArgs(args, {
|
|
400
|
+
port: opts.port,
|
|
401
|
+
stripBooleanFlags: ['--pretty', '--json', '--help', '-h', '--host'],
|
|
402
|
+
})
|
|
403
|
+
const positional = parsed.positional
|
|
404
|
+
const subcommand = positional[0]
|
|
405
|
+
|
|
406
|
+
if (!subcommand || args.includes('--help') || args.includes('-h')) {
|
|
407
|
+
printHelp()
|
|
408
|
+
rnxExit(0)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const wsPort = parsed.wsPort
|
|
412
|
+
const simId = parsed.simId
|
|
413
|
+
const pretty = !args.includes('--json')
|
|
414
|
+
const simHint = simId ? ` --sim ${simId}` : ''
|
|
415
|
+
|
|
416
|
+
const sub = positional[0]
|
|
417
|
+
const rest = positional.slice(1)
|
|
418
|
+
|
|
419
|
+
// these subcommands are organized under `debug` for the user but their
|
|
420
|
+
// implementation lives in inspect.ts. forward to runInspect with the raw
|
|
421
|
+
// `debug` prefix intact — runInspect strips it. done before we open a
|
|
422
|
+
// debug-side bridge so we don't hold two bridges at once.
|
|
423
|
+
const INSPECT_FORWARDED = new Set(['state', 'js', 'perf', 'memory', 'sample-color'])
|
|
424
|
+
if (INSPECT_FORWARDED.has(sub)) {
|
|
425
|
+
const { runInspect } = await import('./inspect')
|
|
426
|
+
// pass the raw arg list through so every flag (--sim, --json,
|
|
427
|
+
// --verbose, per-subcommand flags, etc.) reaches the inspect parser
|
|
428
|
+
// untouched. the leading 'debug' is recognized as a verb prefix by
|
|
429
|
+
// runInspect and stripped.
|
|
430
|
+
await runInspect(['debug', ...args], {
|
|
431
|
+
port: opts.port,
|
|
432
|
+
verbose: opts.verbose,
|
|
433
|
+
})
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const bridge = createBridgeFromParsed(parsed)
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
switch (sub) {
|
|
441
|
+
case 'enable': {
|
|
442
|
+
const channels = parseChannelList(rest[0])
|
|
443
|
+
if (channels.length === 0) {
|
|
444
|
+
console.error(
|
|
445
|
+
` usage: rnx debug enable <channel[,channel,...]>\n known: ${KNOWN_CHANNELS.join(', ')}`,
|
|
446
|
+
)
|
|
447
|
+
rnxExit(1)
|
|
448
|
+
}
|
|
449
|
+
const active = await setDebugChannels(
|
|
450
|
+
bridge,
|
|
451
|
+
'enable',
|
|
452
|
+
channels,
|
|
453
|
+
args.includes('--host'),
|
|
454
|
+
)
|
|
455
|
+
console.log(fmt({ active }, pretty))
|
|
456
|
+
break
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
case 'disable': {
|
|
460
|
+
const channels = parseChannelList(rest[0])
|
|
461
|
+
const active = await setDebugChannels(
|
|
462
|
+
bridge,
|
|
463
|
+
'disable',
|
|
464
|
+
channels,
|
|
465
|
+
args.includes('--host'),
|
|
466
|
+
)
|
|
467
|
+
console.log(fmt({ active }, pretty))
|
|
468
|
+
break
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
case 'toggle': {
|
|
472
|
+
const channel = rest[0]
|
|
473
|
+
if (!channel) {
|
|
474
|
+
console.error(' usage: rnx debug toggle <channel>')
|
|
475
|
+
rnxExit(1)
|
|
476
|
+
}
|
|
477
|
+
const result = await callDebugBridge(
|
|
478
|
+
bridge,
|
|
479
|
+
`toggle(${JSON.stringify(channel)})`,
|
|
480
|
+
true,
|
|
481
|
+
)
|
|
482
|
+
if (!args.includes('--host')) {
|
|
483
|
+
await callDebugBridge(
|
|
484
|
+
bridge,
|
|
485
|
+
`${result ? 'enable' : 'disable'}(${JSON.stringify(channel)})`,
|
|
486
|
+
)
|
|
487
|
+
}
|
|
488
|
+
console.log(fmt({ [channel]: result }, pretty))
|
|
489
|
+
break
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
case 'status': {
|
|
493
|
+
const result = await inspectDebugStatus(bridge)
|
|
494
|
+
console.log(fmt(result, pretty))
|
|
495
|
+
break
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
case 'channels': {
|
|
499
|
+
const result = await call(bridge, 'window.__sootsimDebug.channels()')
|
|
500
|
+
console.log(fmt(result, pretty))
|
|
501
|
+
break
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
case 'flags': {
|
|
505
|
+
const result = await inspectDebugFlags(bridge)
|
|
506
|
+
console.log(fmt(result, pretty))
|
|
507
|
+
break
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
case 'snapshot': {
|
|
511
|
+
const label = rest[0]
|
|
512
|
+
const code = label
|
|
513
|
+
? `window.__sootsimDebug.snapshot(${JSON.stringify(label)})`
|
|
514
|
+
: 'window.__sootsimDebug.snapshot()'
|
|
515
|
+
// the tree snapshot contains a Map, which doesn't serialize cleanly.
|
|
516
|
+
// project to the same shape the diff command will accept: label +
|
|
517
|
+
// size. to inspect contents, use `find sheets` / `find portals` or
|
|
518
|
+
// take a diff.
|
|
519
|
+
const result = await call<{
|
|
520
|
+
label: string
|
|
521
|
+
at: number
|
|
522
|
+
nodes: unknown
|
|
523
|
+
}>(
|
|
524
|
+
bridge,
|
|
525
|
+
`(() => { const s = ${code}; if (!s) return null; return { label: s.label, at: s.at, size: s.nodes.size }; })()`,
|
|
526
|
+
)
|
|
527
|
+
console.log(fmt(result, pretty))
|
|
528
|
+
break
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
case 'snapshots': {
|
|
532
|
+
const result = await call(bridge, 'window.__sootsimDebug.snapshots()')
|
|
533
|
+
console.log(fmt(result, pretty))
|
|
534
|
+
break
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
case 'diff': {
|
|
538
|
+
const a = rest[0]
|
|
539
|
+
const b = rest[1]
|
|
540
|
+
if (!a || !b) {
|
|
541
|
+
console.error(' usage: rnx debug diff <labelA> <labelB>')
|
|
542
|
+
rnxExit(1)
|
|
543
|
+
}
|
|
544
|
+
// Maps don't serialize — project added/removed/changed arrays only
|
|
545
|
+
const code = `(() => {
|
|
546
|
+
const d = window.__sootsimDebug.diff(${JSON.stringify(a)}, ${JSON.stringify(b)});
|
|
547
|
+
if (!d) return null;
|
|
548
|
+
return {
|
|
549
|
+
a: d.a,
|
|
550
|
+
b: d.b,
|
|
551
|
+
counts: { added: d.added.length, removed: d.removed.length, changed: d.changed.length },
|
|
552
|
+
added: d.added,
|
|
553
|
+
removed: d.removed,
|
|
554
|
+
changed: d.changed,
|
|
555
|
+
};
|
|
556
|
+
})()`
|
|
557
|
+
const result = await call(bridge, code)
|
|
558
|
+
console.log(fmt(result, pretty))
|
|
559
|
+
break
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
case 'clear-snapshots': {
|
|
563
|
+
const label = rest[0]
|
|
564
|
+
const code = label
|
|
565
|
+
? `window.__sootsimDebug.clearSnapshots(${JSON.stringify(label)})`
|
|
566
|
+
: 'window.__sootsimDebug.clearSnapshots()'
|
|
567
|
+
await call(bridge, code)
|
|
568
|
+
console.log(fmt({ cleared: label || 'all' }, pretty))
|
|
569
|
+
break
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
case 'image-audit': {
|
|
573
|
+
const minimum = readNumberFlag(args, '--min') ?? 0.98
|
|
574
|
+
const report = await runImageAudit(bridge)
|
|
575
|
+
if (report.draws === 0) {
|
|
576
|
+
console.error(
|
|
577
|
+
' the audit recorded zero image draws, so an empty result proves nothing.\n' +
|
|
578
|
+
' while it records, paint boundaries rebuild and raster blits are\n' +
|
|
579
|
+
' bypassed, so every image on screen should reach the draw path.\n' +
|
|
580
|
+
' zero draws means either nothing on screen is an image, or the audit\n' +
|
|
581
|
+
' is not attached to the surface that paints.',
|
|
582
|
+
)
|
|
583
|
+
rnxExit(2)
|
|
584
|
+
}
|
|
585
|
+
const under = report.rows.filter(
|
|
586
|
+
(row) => row.shortfall !== null && row.shortfall < minimum,
|
|
587
|
+
)
|
|
588
|
+
if (!pretty) {
|
|
589
|
+
console.log(fmt({ ...report, minimum, under: under.length }, false))
|
|
590
|
+
} else {
|
|
591
|
+
printImageAudit(report, args.includes('--all') ? report.rows : under, minimum)
|
|
592
|
+
}
|
|
593
|
+
if (under.length > 0) rnxExit(1)
|
|
594
|
+
break
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
case 'find': {
|
|
598
|
+
const target = rest[0]
|
|
599
|
+
if (target === 'sheets' || target === 'portals' || target === 'boundaries') {
|
|
600
|
+
const result = await inspectDebugFind(bridge, target)
|
|
601
|
+
console.log(fmt(result, pretty))
|
|
602
|
+
} else {
|
|
603
|
+
console.error(' usage: rnx debug find <sheets|portals|boundaries>')
|
|
604
|
+
rnxExit(1)
|
|
605
|
+
}
|
|
606
|
+
break
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
case 'trace': {
|
|
610
|
+
const traceTarget = rest[0]
|
|
611
|
+
const traceCommand = rest[1]
|
|
612
|
+
if (traceTarget === 'anim') {
|
|
613
|
+
// `debug trace anim on <id|all> [limit]`
|
|
614
|
+
// `debug trace anim off [id|all]`
|
|
615
|
+
// `debug trace anim <id> [limit]` → read samples
|
|
616
|
+
// `debug trace anim status` | `clear`
|
|
617
|
+
const sub = rest[1]
|
|
618
|
+
if (!sub || sub === '--help' || sub === '-h') {
|
|
619
|
+
console.error(
|
|
620
|
+
' usage: rnx debug trace anim <on|off|status|clear|<id>> [id|limit]',
|
|
621
|
+
)
|
|
622
|
+
rnxExit(1)
|
|
623
|
+
}
|
|
624
|
+
if (sub === 'on') {
|
|
625
|
+
const raw = rest[2] ?? 'all'
|
|
626
|
+
const limit = rest[3] ? Number(rest[3]) : undefined
|
|
627
|
+
const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
|
|
628
|
+
if (target !== 'all' && !Number.isFinite(target)) {
|
|
629
|
+
console.error(` invalid target: ${raw}`)
|
|
630
|
+
rnxExit(1)
|
|
631
|
+
}
|
|
632
|
+
await callTestBridge(bridge, 'enableAnimationTrace', target, limit)
|
|
633
|
+
const listed = await callTestBridge(bridge, 'listAnimationTraces')
|
|
634
|
+
console.log(fmt({ enabled: target, traces: listed }, pretty))
|
|
635
|
+
break
|
|
636
|
+
}
|
|
637
|
+
if (sub === 'off') {
|
|
638
|
+
const raw = rest[2] ?? 'all'
|
|
639
|
+
const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
|
|
640
|
+
if (target !== 'all' && !Number.isFinite(target)) {
|
|
641
|
+
console.error(` invalid target: ${raw}`)
|
|
642
|
+
rnxExit(1)
|
|
643
|
+
}
|
|
644
|
+
await callTestBridge(bridge, 'disableAnimationTrace', target)
|
|
645
|
+
console.log(fmt({ disabled: target }, pretty))
|
|
646
|
+
break
|
|
647
|
+
}
|
|
648
|
+
if (sub === 'status' || sub === 'clear') {
|
|
649
|
+
if (sub === 'clear') {
|
|
650
|
+
await callTestBridge(bridge, 'disableAnimationTrace', 'all')
|
|
651
|
+
}
|
|
652
|
+
const listed = await callTestBridge(bridge, 'listAnimationTraces')
|
|
653
|
+
console.log(fmt({ traces: listed }, pretty))
|
|
654
|
+
break
|
|
655
|
+
}
|
|
656
|
+
const id = Number(sub)
|
|
657
|
+
if (!Number.isFinite(id)) {
|
|
658
|
+
console.error(` invalid id: ${sub}`)
|
|
659
|
+
rnxExit(1)
|
|
660
|
+
}
|
|
661
|
+
const limit = rest[2] ? Number(rest[2]) : undefined
|
|
662
|
+
const samples = await callTestBridge(bridge, 'getAnimationTrace', id, limit)
|
|
663
|
+
console.log(fmt({ id, samples }, pretty))
|
|
664
|
+
break
|
|
665
|
+
}
|
|
666
|
+
if (traceTarget !== 'shell') {
|
|
667
|
+
console.error(' usage: rnx debug trace <shell|anim> [args]')
|
|
668
|
+
rnxExit(1)
|
|
669
|
+
}
|
|
670
|
+
if (!traceCommand || /^[0-9]+$/.test(traceCommand)) {
|
|
671
|
+
const recentLimit = traceCommand ? Number(traceCommand) : 50
|
|
672
|
+
const result = await call(bridge, buildShellTraceRecentCode(recentLimit))
|
|
673
|
+
console.log(fmt(result, pretty))
|
|
674
|
+
break
|
|
675
|
+
}
|
|
676
|
+
if (traceCommand === 'on') {
|
|
677
|
+
const limit = rest[2] ? Number(rest[2]) : 240
|
|
678
|
+
const result = await call(bridge, buildShellTraceControlCode('on', limit))
|
|
679
|
+
console.log(fmt(result, pretty))
|
|
680
|
+
break
|
|
681
|
+
}
|
|
682
|
+
if (traceCommand === 'off') {
|
|
683
|
+
const result = await call(bridge, buildShellTraceControlCode('off'))
|
|
684
|
+
console.log(fmt(result, pretty))
|
|
685
|
+
break
|
|
686
|
+
}
|
|
687
|
+
if (traceCommand === 'clear') {
|
|
688
|
+
const result = await call(bridge, buildShellTraceControlCode('clear'))
|
|
689
|
+
console.log(fmt(result, pretty))
|
|
690
|
+
break
|
|
691
|
+
}
|
|
692
|
+
if (traceCommand === 'status') {
|
|
693
|
+
const result = await call(bridge, buildShellTraceControlCode('status'))
|
|
694
|
+
console.log(fmt(result, pretty))
|
|
695
|
+
break
|
|
696
|
+
}
|
|
697
|
+
console.error(
|
|
698
|
+
' usage: rnx debug trace shell [on [limit]|off|status|clear|recentLimit]',
|
|
699
|
+
)
|
|
700
|
+
rnxExit(1)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
case 'record': {
|
|
704
|
+
const target = rest[0]
|
|
705
|
+
const on = target === 'on' ? 'true' : target === 'off' ? 'false' : 'undefined'
|
|
706
|
+
const result = await callDebugBridge(
|
|
707
|
+
bridge,
|
|
708
|
+
`record(${on})`,
|
|
709
|
+
args.includes('--host'),
|
|
710
|
+
)
|
|
711
|
+
console.log(fmt({ recording: result }, pretty))
|
|
712
|
+
break
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
case 'recent': {
|
|
716
|
+
const channel = rest[0]
|
|
717
|
+
const limit = rest[1] ? Number(rest[1]) : 50
|
|
718
|
+
const result = await inspectDebugRecent(
|
|
719
|
+
bridge,
|
|
720
|
+
channel,
|
|
721
|
+
limit,
|
|
722
|
+
args.includes('--host'),
|
|
723
|
+
)
|
|
724
|
+
console.log(fmt(result, pretty))
|
|
725
|
+
break
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
case 'clear-events': {
|
|
729
|
+
await callDebugBridge(bridge, 'clearEvents()', args.includes('--host'))
|
|
730
|
+
console.log(fmt({ cleared: true }, pretty))
|
|
731
|
+
break
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
default:
|
|
735
|
+
console.error(` unknown subcommand: ${sub}`)
|
|
736
|
+
printHelp()
|
|
737
|
+
rnxExit(1)
|
|
738
|
+
}
|
|
739
|
+
} catch (err: any) {
|
|
740
|
+
rethrowIfExit(err)
|
|
741
|
+
console.error(` debug failed: ${err.message}`)
|
|
742
|
+
await printBridgeFailureDiagnostics(bridge, {
|
|
743
|
+
errorsCommand: `rnx get errors 5${simHint}`,
|
|
744
|
+
warningsCommand: `rnx get warnings 5${simHint}`,
|
|
745
|
+
requestsCommand: `rnx get requests 5${simHint}`,
|
|
746
|
+
})
|
|
747
|
+
rnxExit(1)
|
|
748
|
+
} finally {
|
|
749
|
+
bridge.close()
|
|
750
|
+
}
|
|
751
|
+
}
|