rnxsim 0.1.313 → 0.1.314
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 +11 -10
- package/README.md +5 -0
- package/cli/app-config.ts +65 -0
- package/cli/app-fonts.ts +408 -0
- package/cli/app-project.ts +231 -0
- package/cli/app-splash.ts +185 -0
- package/cli/app-state-reset.ts +24 -0
- package/cli/auth.ts +155 -0
- package/cli/bin.ts +594 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2830 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/commands/agent-wrapper.ts +986 -0
- package/cli/commands/agent.ts +423 -0
- package/cli/commands/app-fonts.ts +98 -0
- package/cli/commands/assert.ts +541 -0
- package/cli/commands/auth.ts +59 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +87 -0
- package/cli/commands/config.ts +32 -0
- package/cli/commands/control.ts +2142 -0
- package/cli/commands/cpu-profile.ts +269 -0
- package/cli/commands/daemon-mac-app.ts +169 -0
- package/cli/commands/daemon.ts +874 -0
- package/cli/commands/debug.ts +719 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +197 -0
- package/cli/commands/detox.ts +385 -0
- package/cli/commands/device.ts +133 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/electron.ts +95 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1124 -0
- package/cli/commands/inspect/actions.ts +622 -0
- package/cli/commands/inspect/core.ts +2405 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +192 -0
- package/cli/commands/inspect/env.ts +23 -0
- package/cli/commands/inspect/find.ts +171 -0
- package/cli/commands/inspect/get-layout.ts +39 -0
- package/cli/commands/inspect/keyboard.ts +52 -0
- package/cli/commands/inspect/list.ts +58 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +82 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +22 -0
- package/cli/commands/inspect/settling.ts +158 -0
- package/cli/commands/inspect/shared.ts +353 -0
- package/cli/commands/inspect/sleep.ts +14 -0
- package/cli/commands/inspect/tree.ts +32 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +210 -0
- package/cli/commands/inspect/wait-idle.ts +24 -0
- package/cli/commands/inspect/wait-ready.ts +74 -0
- package/cli/commands/inspect/wait-selector.ts +54 -0
- package/cli/commands/inspect/wait.ts +31 -0
- package/cli/commands/inspect.ts +4519 -0
- package/cli/commands/install-desktop.ts +351 -0
- package/cli/commands/login.ts +331 -0
- package/cli/commands/logout.ts +31 -0
- package/cli/commands/maestro-generate.ts +361 -0
- package/cli/commands/maestro.ts +453 -0
- package/cli/commands/mode.ts +57 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +66 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/profile.ts +108 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1434 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +85 -0
- package/cli/commands/runtime.ts +351 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +143 -0
- package/cli/commands/screenshot-mode.ts +37 -0
- package/cli/commands/screenshot.ts +488 -0
- package/cli/commands/screenshots-capture.ts +607 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +168 -0
- package/cli/commands/setup.ts +545 -0
- package/cli/commands/shell-boolean-mode.ts +81 -0
- package/cli/commands/skills.ts +467 -0
- package/cli/commands/slides.ts +361 -0
- package/cli/commands/state.ts +87 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +54 -0
- package/cli/commands/three-mode.ts +763 -0
- package/cli/commands/timeline.ts +122 -0
- package/cli/commands/upgrade.ts +208 -0
- package/cli/commands/upload.ts +1225 -0
- package/cli/commands/version.ts +54 -0
- package/cli/commands/what-happened.ts +327 -0
- package/cli/current-sim.ts +204 -0
- package/cli/desktop-companion.ts +300 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +180 -0
- package/cli/drivers/playwright.ts +698 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +120 -0
- package/cli/flow-session.ts +187 -0
- package/cli/help.ts +80 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +216 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/maestro-js.ts +334 -0
- package/cli/open-url.ts +8 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +211 -0
- package/cli/prompt.ts +51 -0
- package/cli/recording-access.ts +107 -0
- package/cli/registry.ts +1 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/run-registry.ts +226 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/setup-repository.ts +187 -0
- package/cli/telemetry.ts +187 -0
- package/cli/ws-bridge.ts +798 -0
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-XZ2KTPCU.js → agent-7YBDCYMA.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-JJYYW2WH.js → agent-wrapper-2GHFBHCR.js} +2 -2
- package/dist-cli/chunks/{app-fonts-IXRNQG6B.js → app-fonts-RSNVPQSU.js} +2 -2
- package/dist-cli/chunks/{assert-54T5SK5F.js → assert-XCMX3XJX.js} +2 -2
- package/dist-cli/chunks/{auth-FI5UDI45.js → auth-B442HRAX.js} +2 -2
- package/dist-cli/chunks/{beta-JV6UKADW.js → beta-XJ55JK3M.js} +2 -2
- package/dist-cli/chunks/camera-UGYSSLIK.js +33 -0
- package/dist-cli/chunks/{chunk-3NV2NCNX.js → chunk-277AEQZX.js} +2 -2
- package/dist-cli/chunks/{chunk-2YR5BGA5.js → chunk-2JNSK774.js} +2 -2
- package/dist-cli/chunks/{chunk-RSZWCKNT.js → chunk-32WOTSTR.js} +3 -3
- package/dist-cli/chunks/{chunk-WEXDAC74.js → chunk-3S753SNQ.js} +2 -2
- package/dist-cli/chunks/{chunk-IJO63TDP.js → chunk-46ZOLOYA.js} +2 -2
- package/dist-cli/chunks/{chunk-WUSWBCWA.js → chunk-5L7ELDQL.js} +8 -9
- package/dist-cli/chunks/{chunk-WF3T4SVI.js → chunk-7OOPFSQS.js} +2 -2
- package/dist-cli/chunks/{chunk-TZFFR3SD.js → chunk-7SV3RPRW.js} +2 -2
- package/dist-cli/chunks/{chunk-WWZIXIRD.js → chunk-7ZC35MOU.js} +1 -1
- package/dist-cli/chunks/chunk-AMG5E6CC.js +9 -0
- package/dist-cli/chunks/{chunk-WINYQ44O.js → chunk-APWNH3A4.js} +1 -1
- package/dist-cli/chunks/chunk-B57XUKY3.js +4 -0
- package/dist-cli/chunks/{chunk-YDGQTMQL.js → chunk-C2NL26TD.js} +1 -1
- package/dist-cli/chunks/{chunk-NMF2ZMZQ.js → chunk-D2FNUWAB.js} +4 -4
- package/dist-cli/chunks/{chunk-YIFT42WN.js → chunk-E5T4XSJ3.js} +2 -2
- package/dist-cli/chunks/{chunk-46EUUFJ5.js → chunk-EAC34EQS.js} +1 -1
- package/dist-cli/chunks/{chunk-OVFJFXUD.js → chunk-EG32ML36.js} +2 -2
- package/dist-cli/chunks/{chunk-5YJCOWCH.js → chunk-FXUAC6D5.js} +1 -1
- package/dist-cli/chunks/chunk-GQSL4USA.js +6 -0
- package/dist-cli/chunks/{chunk-VFCMSYZK.js → chunk-HAXW27SS.js} +2 -2
- package/dist-cli/chunks/{chunk-2D2UPBBR.js → chunk-IZAHPAN6.js} +1 -1
- package/dist-cli/chunks/{chunk-7GN3LVWB.js → chunk-J62KM5TB.js} +2 -2
- package/dist-cli/chunks/{chunk-BTWORNNG.js → chunk-JEMCD5E4.js} +1 -1
- package/dist-cli/chunks/{chunk-DCEMHR2Y.js → chunk-JZS3Q37N.js} +2 -2
- package/dist-cli/chunks/{chunk-D4FFVGI5.js → chunk-KR4JON7D.js} +1 -1
- package/dist-cli/chunks/chunk-KWCYKQIQ.js +4 -0
- package/dist-cli/chunks/{chunk-VNQEB4L7.js → chunk-MCWPL644.js} +2 -2
- package/dist-cli/chunks/chunk-MJYK3N2I.js +4 -0
- package/dist-cli/chunks/{chunk-5TEF3ET3.js → chunk-O6TRIZNS.js} +2 -2
- package/dist-cli/chunks/{chunk-QKDWYITG.js → chunk-P7XL2E73.js} +3 -3
- package/dist-cli/chunks/{chunk-BBULZ7CG.js → chunk-PFQTUKQ4.js} +62 -87
- package/dist-cli/chunks/{chunk-GGRX24GF.js → chunk-PG5RZCTN.js} +2 -2
- package/dist-cli/chunks/{chunk-W6K4EFPH.js → chunk-QGRI2Z4M.js} +2 -2
- package/dist-cli/chunks/{chunk-ZMJD5GEC.js → chunk-QLXXE7GE.js} +1 -1
- package/dist-cli/chunks/{chunk-VZXWHRUZ.js → chunk-QOJJJWJE.js} +89 -133
- package/dist-cli/chunks/{chunk-OZSSI4WN.js → chunk-RWZY5427.js} +2 -2
- package/dist-cli/chunks/{chunk-UC6U3MML.js → chunk-RZKU2K3J.js} +2 -2
- package/dist-cli/chunks/{chunk-IJ5CAZZC.js → chunk-SBV4IK4H.js} +1 -1
- package/dist-cli/chunks/{chunk-DZS6WPUI.js → chunk-SGMVFFMK.js} +1 -1
- package/dist-cli/chunks/{chunk-OHAZNXLK.js → chunk-TAX4UT2N.js} +1 -1
- package/dist-cli/chunks/{chunk-5DHC6KHQ.js → chunk-TUOFAWXT.js} +1 -1
- package/dist-cli/chunks/{chunk-GASE6UBA.js → chunk-UHZLOHGP.js} +1 -1
- package/dist-cli/chunks/{chunk-F5ZRSS3C.js → chunk-VC7V76U3.js} +1 -1
- package/dist-cli/chunks/{chunk-RTN5C5RL.js → chunk-VQVMLW4U.js} +1 -1
- package/dist-cli/chunks/{chunk-WMIIKMGK.js → chunk-VUKKYPZN.js} +2 -2
- package/dist-cli/chunks/{chunk-5TPRP5QT.js → chunk-WGGRJDRE.js} +1 -1
- package/dist-cli/chunks/chunk-X6H76EKP.js +15 -0
- package/dist-cli/chunks/chunk-XLZ5FNRT.js +27 -0
- package/dist-cli/chunks/{chunk-HI5TFJWN.js → chunk-XULEACM4.js} +2 -2
- package/dist-cli/chunks/{chunk-MJRLLB4R.js → chunk-YFSDM7AX.js} +4 -4
- package/dist-cli/chunks/chunk-YWI3UEVX.js +5 -0
- package/dist-cli/chunks/{chunk-XEVZYVIW.js → chunk-ZBSJO4NB.js} +10 -9
- package/dist-cli/chunks/{cleanup-P27PA6JI.js → cleanup-EYLGCA6Z.js} +2 -2
- package/dist-cli/chunks/cli-version-LL2UGIHE.js +4 -0
- package/dist-cli/chunks/{compat-ZD65FED3.js → compat-TLJYHB4E.js} +2 -2
- package/dist-cli/chunks/{config-XMJRNM2A.js → config-4JWUOEXK.js} +2 -2
- package/dist-cli/chunks/{control-KMIQT3QP.js → control-HPAOYF4N.js} +2 -2
- package/dist-cli/chunks/daemon-OYLASXLE.js +4 -0
- package/dist-cli/chunks/{debug-PT4HOP7N.js → debug-4BKXF6KI.js} +5 -5
- package/dist-cli/chunks/{desktop-S3FG72AK.js → desktop-ZQ6ZD2S6.js} +3 -3
- package/dist-cli/chunks/{detox-B3D4IFCN.js → detox-WNPASSS3.js} +2 -2
- package/dist-cli/chunks/{device-XBNDSB2R.js → device-BXLXVG3V.js} +2 -2
- package/dist-cli/chunks/{diagnose-HMQXJE5N.js → diagnose-3QX7W5RW.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-BLCZ5BSZ.js → disk-cleanup-KSWKI7WB.js} +2 -2
- package/dist-cli/chunks/drivers-EPIEFF7P.js +4 -0
- package/dist-cli/chunks/{film-BJGTBYZB.js → film-GDMR33VO.js} +3 -3
- package/dist-cli/chunks/flow-NKMPBYCJ.js +4 -0
- package/dist-cli/chunks/help-OGCBHOKA.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-ANOYADHM.js → hidden-runtime-alias-S2GTDX3T.js} +2 -2
- package/dist-cli/chunks/home-paths-QRCDLTTV.js +4 -0
- package/dist-cli/chunks/inspect-FUYMOZPY.js +4 -0
- package/dist-cli/chunks/install-desktop-FR6YKW7Y.js +4 -0
- package/dist-cli/chunks/{login-FJ737MWG.js → login-IJAPUZHI.js} +4 -4
- package/dist-cli/chunks/{logout-ZCNMMHMY.js → logout-QMXDFU2X.js} +2 -2
- package/dist-cli/chunks/{maestro-SZTNKLDF.js → maestro-ZXU3YCVX.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-DCFAIZ4H.js → maestro-generate-PYB5QY7K.js} +3 -3
- package/dist-cli/chunks/{mode-GRMQCRXR.js → mode-WGUCL5FZ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-W36EWFFB.js → optional-demo-registry-WH2O6H36.js} +2 -2
- package/dist-cli/chunks/{perf-QYBAAUZG.js → perf-TOD3UFAH.js} +2 -2
- package/dist-cli/chunks/{permissions-3QCQ6VF4.js → permissions-I5BRJGTB.js} +2 -2
- package/dist-cli/chunks/{record-QPPC2S4E.js → record-ZYL2FYSK.js} +3 -3
- package/dist-cli/chunks/{report-issue-7NMFP4HK.js → report-issue-TAI6DYZO.js} +2 -2
- package/dist-cli/chunks/reset-7YGYKQPQ.js +4 -0
- package/dist-cli/chunks/runtime-B4JO6QRI.js +4 -0
- package/dist-cli/chunks/{screenshot-command-67AECJFB.js → screenshot-command-7ANLODZY.js} +7 -7
- package/dist-cli/chunks/{screenshot-layers-ASWBYPJL.js → screenshot-layers-A7FYXSVU.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-PXA3HFQK.js → screenshots-capture-WT2ZY6CB.js} +2 -2
- package/dist-cli/chunks/serve-TG5WKA4V.js +44 -0
- package/dist-cli/chunks/{setup-7DWPMRSB.js → setup-PCWLD22V.js} +2 -2
- package/dist-cli/chunks/{skills-S3Y22TUA.js → skills-27ZHWCQS.js} +2 -2
- package/dist-cli/chunks/state-ZQVY46ZO.js +14 -0
- package/dist-cli/chunks/{storage-XUIMJWAJ.js → storage-OYC57C4X.js} +6 -6
- package/dist-cli/chunks/store-32HSPZHI.js +4 -0
- package/dist-cli/chunks/telemetry-PBJR7XHR.js +4 -0
- package/dist-cli/chunks/{timeline-TMPLQPSP.js → timeline-RAJJFQT6.js} +2 -2
- package/dist-cli/chunks/{upgrade-7HDSIM7K.js → upgrade-OEFNZRIP.js} +2 -2
- package/dist-cli/chunks/upload-LQJITLKK.js +4 -0
- package/dist-cli/chunks/version-NIXTY6PL.js +6 -0
- package/dist-cli/chunks/{web-DG3WBYD3.js → web-XBUTBVGR.js} +2 -2
- package/dist-cli/chunks/{what-happened-XFVUTZR7.js → what-happened-YNHRFUDX.js} +3 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract.cjs +20 -0
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +67 -28
- package/dist-lib/host/bridge-host.cjs +140 -12
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2815 -40
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +2549 -2061
- package/dist-lib/sdk.mjs +2543 -2061
- package/dist-lib/skills.cjs +480 -280
- package/dist-lib/vite.cjs +1 -1
- package/package.json +8 -2
- package/src/bridge-constants.ts +3 -4
- package/src/bridge-contract.ts +251 -0
- package/src/connect.ts +83 -0
- package/src/disk-cleanup.ts +30 -0
- package/src/home-paths.ts +81 -38
- package/src/host/bridge-host.ts +134 -6
- package/src/index.ts +27 -1
- package/src/sdk.ts +8 -0
- package/src/sim-client.ts +660 -0
- package/dist-cli/chunks/camera-VL73YIKP.js +0 -22
- package/dist-cli/chunks/chunk-4NPPOV2N.js +0 -5
- package/dist-cli/chunks/chunk-FSUYIVJ6.js +0 -9
- package/dist-cli/chunks/chunk-G2WW6L2C.js +0 -23
- package/dist-cli/chunks/chunk-KTHV3RUS.js +0 -26
- package/dist-cli/chunks/chunk-LF2ZVT7O.js +0 -6
- package/dist-cli/chunks/chunk-NFK7T35W.js +0 -4
- package/dist-cli/chunks/chunk-TIVZIMMW.js +0 -4
- package/dist-cli/chunks/cli-version-WWLPBDQ7.js +0 -4
- package/dist-cli/chunks/daemon-G2ME7NLB.js +0 -4
- package/dist-cli/chunks/drivers-LDECZGP2.js +0 -4
- package/dist-cli/chunks/flow-UEQNVTU7.js +0 -4
- package/dist-cli/chunks/help-T5FYSVGB.js +0 -4
- package/dist-cli/chunks/home-paths-GT3LFNOR.js +0 -4
- package/dist-cli/chunks/inspect-ZA6XF5LD.js +0 -4
- package/dist-cli/chunks/install-desktop-TIMUDHPL.js +0 -4
- package/dist-cli/chunks/runtime-XOAXMSTU.js +0 -4
- package/dist-cli/chunks/serve-BI2NBAXG.js +0 -44
- package/dist-cli/chunks/store-JTHEJLAZ.js +0 -4
- package/dist-cli/chunks/telemetry-ZYJGD2DB.js +0 -4
- package/dist-cli/chunks/upload-GMSZPWM6.js +0 -4
- package/dist-cli/chunks/version-HOCHZ37L.js +0 -6
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
// sootsim debug — drive __sootsimDebug.* from the terminal
|
|
2
|
+
//
|
|
3
|
+
// connects to a running sootsim 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
|
+
// sootsim debug enable sheets,portals,onlayout
|
|
9
|
+
// sootsim debug status
|
|
10
|
+
// sootsim debug snapshot before
|
|
11
|
+
// # ... tap something in the UI ...
|
|
12
|
+
// sootsim debug snapshot after
|
|
13
|
+
// sootsim debug diff before after
|
|
14
|
+
// sootsim debug find sheets
|
|
15
|
+
// sootsim debug find portals
|
|
16
|
+
// sootsim debug recent portals
|
|
17
|
+
// sootsim 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 {
|
|
24
|
+
createBridgeFromParsed,
|
|
25
|
+
evalInBridge,
|
|
26
|
+
parseBridgeCliArgs,
|
|
27
|
+
type WsBridge,
|
|
28
|
+
} from '../ws-bridge'
|
|
29
|
+
import {
|
|
30
|
+
inspectDebugFind,
|
|
31
|
+
inspectDebugFlags,
|
|
32
|
+
inspectDebugRecent,
|
|
33
|
+
inspectDebugStatus,
|
|
34
|
+
setDebugChannels,
|
|
35
|
+
} from './inspect/core'
|
|
36
|
+
import { callTestBridge } from './inspect/shared'
|
|
37
|
+
|
|
38
|
+
interface DebugOptions {
|
|
39
|
+
port?: number
|
|
40
|
+
verbose?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const KNOWN_CHANNELS = [
|
|
44
|
+
'portals',
|
|
45
|
+
'sheets',
|
|
46
|
+
'layout',
|
|
47
|
+
'onlayout',
|
|
48
|
+
'animated',
|
|
49
|
+
'render',
|
|
50
|
+
'touch',
|
|
51
|
+
'yoga',
|
|
52
|
+
'all',
|
|
53
|
+
] as const
|
|
54
|
+
|
|
55
|
+
const SHELL_TRACE_STORE_GLOBAL = '__sootsimShellAnimationTrace'
|
|
56
|
+
const SHELL_TRACE_HOOK_GLOBAL = '__sootsimDebugAnimation'
|
|
57
|
+
|
|
58
|
+
function printHelp() {
|
|
59
|
+
console.log(`
|
|
60
|
+
rnxsim debug — drive __sootsimDebug from the terminal
|
|
61
|
+
|
|
62
|
+
usage:
|
|
63
|
+
rnxsim debug <subcommand> [args]
|
|
64
|
+
|
|
65
|
+
subcommands:
|
|
66
|
+
enable <channels> turn on one or more debug channels
|
|
67
|
+
channels: ${KNOWN_CHANNELS.slice(0, -1).join(', ')}
|
|
68
|
+
or 'all' for every channel
|
|
69
|
+
disable <channels> turn off one or more debug channels (or 'all')
|
|
70
|
+
toggle <channel> flip a single channel
|
|
71
|
+
status list currently-enabled channels
|
|
72
|
+
channels list every known channel name
|
|
73
|
+
flags print the full DEBUG flag object
|
|
74
|
+
|
|
75
|
+
state <kind> ... dump raw runtime state (diagnostic — not a getter)
|
|
76
|
+
kinds: shell, worker, keyboard, node <id>,
|
|
77
|
+
scroll <id>, scroll-hit <x> <y>,
|
|
78
|
+
hit <x> <y>, gesture <x> <y>
|
|
79
|
+
|
|
80
|
+
js <code> execute javascript in the running app. SootSim
|
|
81
|
+
is the canonical state object — reach into its
|
|
82
|
+
bridges / state / chrome / debug slots directly.
|
|
83
|
+
e.g. SootSim.bridges.test.findByText("Sign in")
|
|
84
|
+
eval <code> alias for js
|
|
85
|
+
perf <sub> shell frame profiling: start, stop, transition
|
|
86
|
+
memory [--watch [s]] per-worker object counts + heaps; --watch samples
|
|
87
|
+
every --interval seconds and reports slopes
|
|
88
|
+
sample-color <...> sample averaged color from canvas (same flags as
|
|
89
|
+
screenshot)
|
|
90
|
+
|
|
91
|
+
snapshot [label] capture a tree snapshot (layout + transform + opacity)
|
|
92
|
+
snapshots list taken snapshot labels
|
|
93
|
+
diff <a> <b> compare two snapshots by label
|
|
94
|
+
clear-snapshots [label] drop a snapshot (or all if no label given)
|
|
95
|
+
|
|
96
|
+
image-audit for every image the compositor actually drew, the
|
|
97
|
+
source pixels it landed on each device pixel. a row
|
|
98
|
+
whose shortfall is well under 1.0 is an image the
|
|
99
|
+
pipeline under-resolved; 0.5 is half resolution.
|
|
100
|
+
flags: --min <ratio> (default 0.98), --all, --json
|
|
101
|
+
exits 1 when any image is under the ratio, and 2 when
|
|
102
|
+
the audit observed no image draws at all
|
|
103
|
+
|
|
104
|
+
find sheets dump Sheet.Frame-shaped nodes currently in the tree
|
|
105
|
+
find portals dump portal-host / portal-view nodes
|
|
106
|
+
find boundaries dump live paint boundaries (+ why scroll rows were
|
|
107
|
+
rejected from the auto-retained raster tier)
|
|
108
|
+
|
|
109
|
+
trace shell [cmd] opt-in shell animation trace
|
|
110
|
+
cmds: on [limit], off, status, clear, [recentLimit]
|
|
111
|
+
trace anim <sub> opt-in per-tick animation value trace
|
|
112
|
+
subs: on <id|all> [limit], off [id|all],
|
|
113
|
+
status, clear, <id> [limit]
|
|
114
|
+
record [on|off] toggle event ring buffer recording
|
|
115
|
+
recent [channel] [n] last N events (default 50), optionally filtered
|
|
116
|
+
clear-events clear the event ring buffer
|
|
117
|
+
|
|
118
|
+
options:
|
|
119
|
+
--port <port> WS bridge port (default: ${DEFAULT_SOOTSIM_BRIDGE_PORT})
|
|
120
|
+
--sim <sim> target a specific connected sim
|
|
121
|
+
--pretty format JSON output for humans (default)
|
|
122
|
+
--json compact JSON output for pipelines
|
|
123
|
+
|
|
124
|
+
examples:
|
|
125
|
+
rnxsim debug enable sheets,portals
|
|
126
|
+
rnxsim debug snapshot before
|
|
127
|
+
rnxsim debug snapshot after
|
|
128
|
+
rnxsim debug diff before after
|
|
129
|
+
rnxsim debug image-audit per-image source pixels per device pixel
|
|
130
|
+
rnxsim debug find sheets | jq '.[] | select(.translateY != null)'
|
|
131
|
+
rnxsim debug trace shell on 240
|
|
132
|
+
rnxsim debug trace shell 120
|
|
133
|
+
rnxsim debug trace anim on 3 240
|
|
134
|
+
rnxsim debug trace anim 3 60
|
|
135
|
+
`)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parseChannelList(raw: string | undefined): string[] {
|
|
139
|
+
if (!raw) return []
|
|
140
|
+
return raw
|
|
141
|
+
.split(',')
|
|
142
|
+
.map((s) => s.trim())
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function fmt(value: unknown, pretty: boolean): string {
|
|
147
|
+
if (value === undefined) return ''
|
|
148
|
+
return JSON.stringify(value, null, pretty ? 2 : 0)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function buildShellTraceControlCode(
|
|
152
|
+
action: 'on' | 'off' | 'clear' | 'status',
|
|
153
|
+
limit = 240,
|
|
154
|
+
): string {
|
|
155
|
+
const normalizedLimit =
|
|
156
|
+
Number.isFinite(limit) && limit > 0 ? Math.max(1, Math.round(limit)) : 240
|
|
157
|
+
const storeKey = JSON.stringify(SHELL_TRACE_STORE_GLOBAL)
|
|
158
|
+
const hookKey = JSON.stringify(SHELL_TRACE_HOOK_GLOBAL)
|
|
159
|
+
if (action === 'on') {
|
|
160
|
+
return `(() => {
|
|
161
|
+
const root = window
|
|
162
|
+
const store = root[${storeKey}] || (root[${storeKey}] = {
|
|
163
|
+
enabled: false,
|
|
164
|
+
limit: ${normalizedLimit},
|
|
165
|
+
seq: 0,
|
|
166
|
+
samples: [],
|
|
167
|
+
prevHook: undefined,
|
|
168
|
+
hook: undefined,
|
|
169
|
+
})
|
|
170
|
+
store.limit = ${normalizedLimit}
|
|
171
|
+
store.enabled = true
|
|
172
|
+
const currentHook = root[${hookKey}]
|
|
173
|
+
if (store.hook !== currentHook) {
|
|
174
|
+
store.prevHook = typeof currentHook === 'function' ? currentHook : undefined
|
|
175
|
+
}
|
|
176
|
+
if (typeof store.hook !== 'function') {
|
|
177
|
+
store.hook = (sample) => {
|
|
178
|
+
const target = root[${storeKey}]
|
|
179
|
+
if (!target || target.enabled !== true) return
|
|
180
|
+
const samples = Array.isArray(target.samples) ? target.samples : (target.samples = [])
|
|
181
|
+
target.seq = typeof target.seq === 'number' ? target.seq + 1 : 1
|
|
182
|
+
samples.push({ seq: target.seq, ...sample })
|
|
183
|
+
if (samples.length > target.limit) {
|
|
184
|
+
samples.splice(0, samples.length - target.limit)
|
|
185
|
+
}
|
|
186
|
+
if (typeof target.prevHook === 'function') {
|
|
187
|
+
try {
|
|
188
|
+
target.prevHook(sample)
|
|
189
|
+
} catch {}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
root[${hookKey}] = store.hook
|
|
194
|
+
return {
|
|
195
|
+
enabled: true,
|
|
196
|
+
limit: store.limit,
|
|
197
|
+
count: Array.isArray(store.samples) ? store.samples.length : 0,
|
|
198
|
+
}
|
|
199
|
+
})()`
|
|
200
|
+
}
|
|
201
|
+
if (action === 'off') {
|
|
202
|
+
return `(() => {
|
|
203
|
+
const root = window
|
|
204
|
+
const store = root[${storeKey}]
|
|
205
|
+
if (!store) return { enabled: false, limit: 0, count: 0 }
|
|
206
|
+
store.enabled = false
|
|
207
|
+
if (root[${hookKey}] === store.hook) {
|
|
208
|
+
root[${hookKey}] = typeof store.prevHook === 'function' ? store.prevHook : undefined
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
enabled: false,
|
|
212
|
+
limit: typeof store.limit === 'number' ? store.limit : 0,
|
|
213
|
+
count: Array.isArray(store.samples) ? store.samples.length : 0,
|
|
214
|
+
}
|
|
215
|
+
})()`
|
|
216
|
+
}
|
|
217
|
+
if (action === 'clear') {
|
|
218
|
+
return `(() => {
|
|
219
|
+
const store = window[${storeKey}]
|
|
220
|
+
if (!store) return { cleared: true, count: 0 }
|
|
221
|
+
store.samples = []
|
|
222
|
+
store.seq = 0
|
|
223
|
+
return {
|
|
224
|
+
cleared: true,
|
|
225
|
+
enabled: store.enabled === true,
|
|
226
|
+
limit: typeof store.limit === 'number' ? store.limit : 0,
|
|
227
|
+
count: 0,
|
|
228
|
+
}
|
|
229
|
+
})()`
|
|
230
|
+
}
|
|
231
|
+
return `(() => {
|
|
232
|
+
const store = window[${storeKey}]
|
|
233
|
+
return {
|
|
234
|
+
enabled: !!store?.enabled,
|
|
235
|
+
limit: typeof store?.limit === 'number' ? store.limit : 0,
|
|
236
|
+
count: Array.isArray(store?.samples) ? store.samples.length : 0,
|
|
237
|
+
}
|
|
238
|
+
})()`
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function buildShellTraceRecentCode(limit = 50): string {
|
|
242
|
+
const normalizedLimit =
|
|
243
|
+
Number.isFinite(limit) && limit > 0 ? Math.max(1, Math.round(limit)) : 50
|
|
244
|
+
const storeKey = JSON.stringify(SHELL_TRACE_STORE_GLOBAL)
|
|
245
|
+
return `(() => {
|
|
246
|
+
const store = window[${storeKey}]
|
|
247
|
+
const all = Array.isArray(store?.samples) ? store.samples : []
|
|
248
|
+
const samples = all.slice(-${normalizedLimit})
|
|
249
|
+
const first = samples[0] ?? null
|
|
250
|
+
const last = samples[samples.length - 1] ?? null
|
|
251
|
+
const uniquePhases = [...new Set(samples.map((sample) => sample?.phase).filter(Boolean))]
|
|
252
|
+
const metricRange = (key) => {
|
|
253
|
+
const values = samples
|
|
254
|
+
.map((sample) => (typeof sample?.[key] === 'number' ? sample[key] : null))
|
|
255
|
+
.filter((value) => value != null)
|
|
256
|
+
if (values.length === 0) return null
|
|
257
|
+
return {
|
|
258
|
+
min: Math.min(...values),
|
|
259
|
+
max: Math.max(...values),
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
enabled: !!store?.enabled,
|
|
264
|
+
limit: typeof store?.limit === 'number' ? store.limit : 0,
|
|
265
|
+
count: samples.length,
|
|
266
|
+
total: all.length,
|
|
267
|
+
summary: first && last ? {
|
|
268
|
+
durationMs: last.ts - first.ts,
|
|
269
|
+
phases: uniquePhases,
|
|
270
|
+
start: first,
|
|
271
|
+
end: last,
|
|
272
|
+
zoomLevel: metricRange('zoomLevel'),
|
|
273
|
+
horizontalZoom: metricRange('horizontalZoom'),
|
|
274
|
+
launchProgress: metricRange('launchProgress'),
|
|
275
|
+
dismissOffsetY: metricRange('dismissOffsetY'),
|
|
276
|
+
} : null,
|
|
277
|
+
samples,
|
|
278
|
+
}
|
|
279
|
+
})()`
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async function call<T = unknown>(bridge: WsBridge, code: string): Promise<T> {
|
|
283
|
+
return evalInBridge<T>(bridge, code)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface ImageAuditRowView {
|
|
287
|
+
nodeId: number
|
|
288
|
+
type: string
|
|
289
|
+
testID: string | null
|
|
290
|
+
sourceUri: string | null
|
|
291
|
+
resizeMode: string | null
|
|
292
|
+
sampling: string | null
|
|
293
|
+
vector: boolean
|
|
294
|
+
intrinsic: { width: number; height: number } | null
|
|
295
|
+
decoded: { width: number; height: number }
|
|
296
|
+
sampled: { width: number; height: number }
|
|
297
|
+
destination: { width: number; height: number }
|
|
298
|
+
deviceScale: number
|
|
299
|
+
dpr: number
|
|
300
|
+
needed: { width: number; height: number }
|
|
301
|
+
effective: { width: number; height: number }
|
|
302
|
+
ceiling: { width: number; height: number } | null
|
|
303
|
+
shortfall: number | null
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
interface ImageAuditReportView {
|
|
307
|
+
draws: number
|
|
308
|
+
rows: ImageAuditRowView[]
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function readNumberFlag(args: string[], flag: string): number | null {
|
|
312
|
+
const index = args.indexOf(flag)
|
|
313
|
+
if (index < 0) return null
|
|
314
|
+
const parsed = Number(args[index + 1])
|
|
315
|
+
return Number.isFinite(parsed) ? parsed : null
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// enable the audit, force one real frame, then read and stop. the screenshot
|
|
319
|
+
// request is what forces the frame: it runs the same publish-and-paint pass
|
|
320
|
+
// `sootsim screenshot` does, so the rows describe pixels that were actually
|
|
321
|
+
// produced rather than a tree walk's guess about them.
|
|
322
|
+
async function runImageAudit(bridge: WsBridge): Promise<ImageAuditReportView> {
|
|
323
|
+
await call(
|
|
324
|
+
bridge,
|
|
325
|
+
"window.__sootsimCompositor.getStats(false, false, undefined, 'enable').then(() => 'enabled')",
|
|
326
|
+
)
|
|
327
|
+
await bridge.send({ type: 'screenshot' })
|
|
328
|
+
const stats = await call<{ imageAudit?: ImageAuditReportView | null }>(
|
|
329
|
+
bridge,
|
|
330
|
+
"window.__sootsimCompositor.getStats(false, false, undefined, 'disable').then((s) => ({ imageAudit: s.imageAudit }))",
|
|
331
|
+
)
|
|
332
|
+
const report = stats?.imageAudit
|
|
333
|
+
if (!report) throw new Error('compositor returned no image audit')
|
|
334
|
+
return report
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function ratioText(value: number | null): string {
|
|
338
|
+
return value === null ? ' - ' : value.toFixed(3).padStart(6)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function sourceText(row: ImageAuditRowView): string {
|
|
342
|
+
const uri = row.sourceUri ?? row.testID ?? `node ${row.nodeId}`
|
|
343
|
+
if (uri.length <= 58) return uri
|
|
344
|
+
return `...${uri.slice(-55)}`
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function printImageAudit(
|
|
348
|
+
report: ImageAuditReportView,
|
|
349
|
+
rows: ImageAuditRowView[],
|
|
350
|
+
minimum: number,
|
|
351
|
+
): void {
|
|
352
|
+
const withCeiling = report.rows.filter((row) => row.shortfall !== null)
|
|
353
|
+
const under = withCeiling.filter((row) => row.shortfall! < minimum)
|
|
354
|
+
console.log(
|
|
355
|
+
` ${report.rows.length} images drawn (${report.draws} draws), ` +
|
|
356
|
+
`${under.length} below ${minimum} of what their source could deliver`,
|
|
357
|
+
)
|
|
358
|
+
if (rows.length === 0) {
|
|
359
|
+
console.log(' every image delivered its source resolution')
|
|
360
|
+
return
|
|
361
|
+
}
|
|
362
|
+
console.log('')
|
|
363
|
+
console.log(' short eff decoded source needed(dev) dest(pt) dpr image')
|
|
364
|
+
for (const row of rows) {
|
|
365
|
+
const decoded = `${row.decoded.width}x${row.decoded.height}`.padEnd(11)
|
|
366
|
+
const intrinsic = (
|
|
367
|
+
row.vector
|
|
368
|
+
? 'vector'
|
|
369
|
+
: row.intrinsic
|
|
370
|
+
? `${row.intrinsic.width}x${row.intrinsic.height}`
|
|
371
|
+
: '?'
|
|
372
|
+
).padEnd(11)
|
|
373
|
+
const needed =
|
|
374
|
+
`${Math.round(row.needed.width)}x${Math.round(row.needed.height)}`.padEnd(12)
|
|
375
|
+
const dest =
|
|
376
|
+
`${Math.round(row.destination.width)}x${Math.round(row.destination.height)}`.padEnd(
|
|
377
|
+
9,
|
|
378
|
+
)
|
|
379
|
+
console.log(
|
|
380
|
+
` ${ratioText(row.shortfall)} ${ratioText(row.effective.width)} ` +
|
|
381
|
+
`${decoded} ${intrinsic} ${needed} ${dest} ${row.dpr.toFixed(1)} ${sourceText(row)}`,
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export async function runDebug(args: string[], opts: DebugOptions) {
|
|
387
|
+
const parsed = parseBridgeCliArgs(args, {
|
|
388
|
+
port: opts.port,
|
|
389
|
+
stripBooleanFlags: ['--pretty', '--json', '--help', '-h'],
|
|
390
|
+
})
|
|
391
|
+
const positional = parsed.positional
|
|
392
|
+
const subcommand = positional[0]
|
|
393
|
+
|
|
394
|
+
if (!subcommand || args.includes('--help') || args.includes('-h')) {
|
|
395
|
+
printHelp()
|
|
396
|
+
process.exit(0)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const wsPort = parsed.wsPort
|
|
400
|
+
const simId = parsed.simId
|
|
401
|
+
const pretty = !args.includes('--json')
|
|
402
|
+
const simHint = simId ? ` --sim ${simId}` : ''
|
|
403
|
+
|
|
404
|
+
const sub = positional[0]
|
|
405
|
+
const rest = positional.slice(1)
|
|
406
|
+
|
|
407
|
+
// these subcommands are organized under `debug` for the user but their
|
|
408
|
+
// implementation lives in inspect.ts. forward to runInspect with the raw
|
|
409
|
+
// `debug` prefix intact — runInspect strips it. done before we open a
|
|
410
|
+
// debug-side bridge so we don't hold two bridges at once.
|
|
411
|
+
const INSPECT_FORWARDED = new Set([
|
|
412
|
+
'state',
|
|
413
|
+
'js',
|
|
414
|
+
'eval',
|
|
415
|
+
'perf',
|
|
416
|
+
'memory',
|
|
417
|
+
'sample-color',
|
|
418
|
+
])
|
|
419
|
+
if (INSPECT_FORWARDED.has(sub)) {
|
|
420
|
+
const { runInspect } = await import('./inspect')
|
|
421
|
+
// pass the raw arg list through so every flag (--sim, --json,
|
|
422
|
+
// --verbose, per-subcommand flags, etc.) reaches the inspect parser
|
|
423
|
+
// untouched. the leading 'debug' is recognized as a verb prefix by
|
|
424
|
+
// runInspect and stripped.
|
|
425
|
+
await runInspect(['debug', ...args], {
|
|
426
|
+
port: opts.port,
|
|
427
|
+
verbose: opts.verbose,
|
|
428
|
+
})
|
|
429
|
+
return
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const bridge = createBridgeFromParsed(parsed)
|
|
433
|
+
|
|
434
|
+
try {
|
|
435
|
+
switch (sub) {
|
|
436
|
+
case 'enable': {
|
|
437
|
+
const channels = parseChannelList(rest[0])
|
|
438
|
+
if (channels.length === 0) {
|
|
439
|
+
console.error(
|
|
440
|
+
` usage: rnxsim debug enable <channel[,channel,...]>\n known: ${KNOWN_CHANNELS.join(', ')}`,
|
|
441
|
+
)
|
|
442
|
+
process.exit(1)
|
|
443
|
+
}
|
|
444
|
+
const active = await setDebugChannels(bridge, 'enable', channels)
|
|
445
|
+
console.log(fmt({ active }, pretty))
|
|
446
|
+
break
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
case 'disable': {
|
|
450
|
+
const channels = parseChannelList(rest[0])
|
|
451
|
+
const active = await setDebugChannels(bridge, 'disable', channels)
|
|
452
|
+
console.log(fmt({ active }, pretty))
|
|
453
|
+
break
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
case 'toggle': {
|
|
457
|
+
const channel = rest[0]
|
|
458
|
+
if (!channel) {
|
|
459
|
+
console.error(' usage: rnxsim debug toggle <channel>')
|
|
460
|
+
process.exit(1)
|
|
461
|
+
}
|
|
462
|
+
const result = await call(
|
|
463
|
+
bridge,
|
|
464
|
+
`window.__sootsimDebug.toggle(${JSON.stringify(channel)})`,
|
|
465
|
+
)
|
|
466
|
+
console.log(fmt({ [channel]: result }, pretty))
|
|
467
|
+
break
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
case 'status': {
|
|
471
|
+
const result = await inspectDebugStatus(bridge)
|
|
472
|
+
console.log(fmt(result, pretty))
|
|
473
|
+
break
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
case 'channels': {
|
|
477
|
+
const result = await call(bridge, 'window.__sootsimDebug.channels()')
|
|
478
|
+
console.log(fmt(result, pretty))
|
|
479
|
+
break
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
case 'flags': {
|
|
483
|
+
const result = await inspectDebugFlags(bridge)
|
|
484
|
+
console.log(fmt(result, pretty))
|
|
485
|
+
break
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
case 'snapshot': {
|
|
489
|
+
const label = rest[0]
|
|
490
|
+
const code = label
|
|
491
|
+
? `window.__sootsimDebug.snapshot(${JSON.stringify(label)})`
|
|
492
|
+
: 'window.__sootsimDebug.snapshot()'
|
|
493
|
+
// the tree snapshot contains a Map, which doesn't serialize cleanly.
|
|
494
|
+
// project to the same shape the diff command will accept: label +
|
|
495
|
+
// size. to inspect contents, use `find sheets` / `find portals` or
|
|
496
|
+
// take a diff.
|
|
497
|
+
const result = await call<{
|
|
498
|
+
label: string
|
|
499
|
+
at: number
|
|
500
|
+
nodes: unknown
|
|
501
|
+
}>(
|
|
502
|
+
bridge,
|
|
503
|
+
`(() => { const s = ${code}; if (!s) return null; return { label: s.label, at: s.at, size: s.nodes.size }; })()`,
|
|
504
|
+
)
|
|
505
|
+
console.log(fmt(result, pretty))
|
|
506
|
+
break
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
case 'snapshots': {
|
|
510
|
+
const result = await call(bridge, 'window.__sootsimDebug.snapshots()')
|
|
511
|
+
console.log(fmt(result, pretty))
|
|
512
|
+
break
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
case 'diff': {
|
|
516
|
+
const a = rest[0]
|
|
517
|
+
const b = rest[1]
|
|
518
|
+
if (!a || !b) {
|
|
519
|
+
console.error(' usage: rnxsim debug diff <labelA> <labelB>')
|
|
520
|
+
process.exit(1)
|
|
521
|
+
}
|
|
522
|
+
// Maps don't serialize — project added/removed/changed arrays only
|
|
523
|
+
const code = `(() => {
|
|
524
|
+
const d = window.__sootsimDebug.diff(${JSON.stringify(a)}, ${JSON.stringify(b)});
|
|
525
|
+
if (!d) return null;
|
|
526
|
+
return {
|
|
527
|
+
a: d.a,
|
|
528
|
+
b: d.b,
|
|
529
|
+
counts: { added: d.added.length, removed: d.removed.length, changed: d.changed.length },
|
|
530
|
+
added: d.added,
|
|
531
|
+
removed: d.removed,
|
|
532
|
+
changed: d.changed,
|
|
533
|
+
};
|
|
534
|
+
})()`
|
|
535
|
+
const result = await call(bridge, code)
|
|
536
|
+
console.log(fmt(result, pretty))
|
|
537
|
+
break
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
case 'clear-snapshots': {
|
|
541
|
+
const label = rest[0]
|
|
542
|
+
const code = label
|
|
543
|
+
? `window.__sootsimDebug.clearSnapshots(${JSON.stringify(label)})`
|
|
544
|
+
: 'window.__sootsimDebug.clearSnapshots()'
|
|
545
|
+
await call(bridge, code)
|
|
546
|
+
console.log(fmt({ cleared: label || 'all' }, pretty))
|
|
547
|
+
break
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
case 'image-audit': {
|
|
551
|
+
const minimum = readNumberFlag(args, '--min') ?? 0.98
|
|
552
|
+
const report = await runImageAudit(bridge)
|
|
553
|
+
if (report.draws === 0) {
|
|
554
|
+
console.error(
|
|
555
|
+
' the audit recorded zero image draws, so an empty result proves nothing.\n' +
|
|
556
|
+
' while it records, paint boundaries rebuild and raster blits are\n' +
|
|
557
|
+
' bypassed, so every image on screen should reach the draw path.\n' +
|
|
558
|
+
' zero draws means either nothing on screen is an image, or the audit\n' +
|
|
559
|
+
' is not attached to the surface that paints.',
|
|
560
|
+
)
|
|
561
|
+
process.exit(2)
|
|
562
|
+
}
|
|
563
|
+
const under = report.rows.filter(
|
|
564
|
+
(row) => row.shortfall !== null && row.shortfall < minimum,
|
|
565
|
+
)
|
|
566
|
+
if (!pretty) {
|
|
567
|
+
console.log(fmt({ ...report, minimum, under: under.length }, false))
|
|
568
|
+
} else {
|
|
569
|
+
printImageAudit(report, args.includes('--all') ? report.rows : under, minimum)
|
|
570
|
+
}
|
|
571
|
+
if (under.length > 0) process.exit(1)
|
|
572
|
+
break
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
case 'find': {
|
|
576
|
+
const target = rest[0]
|
|
577
|
+
if (target === 'sheets' || target === 'portals' || target === 'boundaries') {
|
|
578
|
+
const result = await inspectDebugFind(bridge, target)
|
|
579
|
+
console.log(fmt(result, pretty))
|
|
580
|
+
} else {
|
|
581
|
+
console.error(' usage: rnxsim debug find <sheets|portals|boundaries>')
|
|
582
|
+
process.exit(1)
|
|
583
|
+
}
|
|
584
|
+
break
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
case 'trace': {
|
|
588
|
+
const traceTarget = rest[0]
|
|
589
|
+
const traceCommand = rest[1]
|
|
590
|
+
if (traceTarget === 'anim') {
|
|
591
|
+
// `debug trace anim on <id|all> [limit]`
|
|
592
|
+
// `debug trace anim off [id|all]`
|
|
593
|
+
// `debug trace anim <id> [limit]` → read samples
|
|
594
|
+
// `debug trace anim status` | `clear`
|
|
595
|
+
const sub = rest[1]
|
|
596
|
+
if (!sub || sub === '--help' || sub === '-h') {
|
|
597
|
+
console.error(
|
|
598
|
+
' usage: rnxsim debug trace anim <on|off|status|clear|<id>> [id|limit]',
|
|
599
|
+
)
|
|
600
|
+
process.exit(1)
|
|
601
|
+
}
|
|
602
|
+
if (sub === 'on') {
|
|
603
|
+
const raw = rest[2] ?? 'all'
|
|
604
|
+
const limit = rest[3] ? Number(rest[3]) : undefined
|
|
605
|
+
const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
|
|
606
|
+
if (target !== 'all' && !Number.isFinite(target)) {
|
|
607
|
+
console.error(` invalid target: ${raw}`)
|
|
608
|
+
process.exit(1)
|
|
609
|
+
}
|
|
610
|
+
await callTestBridge(bridge, 'enableAnimationTrace', target, limit)
|
|
611
|
+
const listed = await callTestBridge(bridge, 'listAnimationTraces')
|
|
612
|
+
console.log(fmt({ enabled: target, traces: listed }, pretty))
|
|
613
|
+
break
|
|
614
|
+
}
|
|
615
|
+
if (sub === 'off') {
|
|
616
|
+
const raw = rest[2] ?? 'all'
|
|
617
|
+
const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
|
|
618
|
+
if (target !== 'all' && !Number.isFinite(target)) {
|
|
619
|
+
console.error(` invalid target: ${raw}`)
|
|
620
|
+
process.exit(1)
|
|
621
|
+
}
|
|
622
|
+
await callTestBridge(bridge, 'disableAnimationTrace', target)
|
|
623
|
+
console.log(fmt({ disabled: target }, pretty))
|
|
624
|
+
break
|
|
625
|
+
}
|
|
626
|
+
if (sub === 'status' || sub === 'clear') {
|
|
627
|
+
if (sub === 'clear') {
|
|
628
|
+
await callTestBridge(bridge, 'disableAnimationTrace', 'all')
|
|
629
|
+
}
|
|
630
|
+
const listed = await callTestBridge(bridge, 'listAnimationTraces')
|
|
631
|
+
console.log(fmt({ traces: listed }, pretty))
|
|
632
|
+
break
|
|
633
|
+
}
|
|
634
|
+
const id = Number(sub)
|
|
635
|
+
if (!Number.isFinite(id)) {
|
|
636
|
+
console.error(` invalid id: ${sub}`)
|
|
637
|
+
process.exit(1)
|
|
638
|
+
}
|
|
639
|
+
const limit = rest[2] ? Number(rest[2]) : undefined
|
|
640
|
+
const samples = await callTestBridge(bridge, 'getAnimationTrace', id, limit)
|
|
641
|
+
console.log(fmt({ id, samples }, pretty))
|
|
642
|
+
break
|
|
643
|
+
}
|
|
644
|
+
if (traceTarget !== 'shell') {
|
|
645
|
+
console.error(' usage: rnxsim debug trace <shell|anim> [args]')
|
|
646
|
+
process.exit(1)
|
|
647
|
+
}
|
|
648
|
+
if (!traceCommand || /^[0-9]+$/.test(traceCommand)) {
|
|
649
|
+
const recentLimit = traceCommand ? Number(traceCommand) : 50
|
|
650
|
+
const result = await call(bridge, buildShellTraceRecentCode(recentLimit))
|
|
651
|
+
console.log(fmt(result, pretty))
|
|
652
|
+
break
|
|
653
|
+
}
|
|
654
|
+
if (traceCommand === 'on') {
|
|
655
|
+
const limit = rest[2] ? Number(rest[2]) : 240
|
|
656
|
+
const result = await call(bridge, buildShellTraceControlCode('on', limit))
|
|
657
|
+
console.log(fmt(result, pretty))
|
|
658
|
+
break
|
|
659
|
+
}
|
|
660
|
+
if (traceCommand === 'off') {
|
|
661
|
+
const result = await call(bridge, buildShellTraceControlCode('off'))
|
|
662
|
+
console.log(fmt(result, pretty))
|
|
663
|
+
break
|
|
664
|
+
}
|
|
665
|
+
if (traceCommand === 'clear') {
|
|
666
|
+
const result = await call(bridge, buildShellTraceControlCode('clear'))
|
|
667
|
+
console.log(fmt(result, pretty))
|
|
668
|
+
break
|
|
669
|
+
}
|
|
670
|
+
if (traceCommand === 'status') {
|
|
671
|
+
const result = await call(bridge, buildShellTraceControlCode('status'))
|
|
672
|
+
console.log(fmt(result, pretty))
|
|
673
|
+
break
|
|
674
|
+
}
|
|
675
|
+
console.error(
|
|
676
|
+
' usage: rnxsim debug trace shell [on [limit]|off|status|clear|recentLimit]',
|
|
677
|
+
)
|
|
678
|
+
process.exit(1)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
case 'record': {
|
|
682
|
+
const target = rest[0]
|
|
683
|
+
const on = target === 'on' ? 'true' : target === 'off' ? 'false' : 'undefined'
|
|
684
|
+
const result = await call(bridge, `window.__sootsimDebug.record(${on})`)
|
|
685
|
+
console.log(fmt({ recording: result }, pretty))
|
|
686
|
+
break
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
case 'recent': {
|
|
690
|
+
const channel = rest[0]
|
|
691
|
+
const limit = rest[1] ? Number(rest[1]) : 50
|
|
692
|
+
const result = await inspectDebugRecent(bridge, channel, limit)
|
|
693
|
+
console.log(fmt(result, pretty))
|
|
694
|
+
break
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
case 'clear-events': {
|
|
698
|
+
await call(bridge, 'window.__sootsimDebug.clearEvents()')
|
|
699
|
+
console.log(fmt({ cleared: true }, pretty))
|
|
700
|
+
break
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
default:
|
|
704
|
+
console.error(` unknown subcommand: ${sub}`)
|
|
705
|
+
printHelp()
|
|
706
|
+
process.exit(1)
|
|
707
|
+
}
|
|
708
|
+
} catch (err: any) {
|
|
709
|
+
console.error(` debug failed: ${err.message}`)
|
|
710
|
+
await printBridgeFailureDiagnostics(bridge, {
|
|
711
|
+
errorsCommand: `rnxsim get errors 5${simHint}`,
|
|
712
|
+
warningsCommand: `rnxsim get warnings 5${simHint}`,
|
|
713
|
+
requestsCommand: `rnxsim get requests 5${simHint}`,
|
|
714
|
+
})
|
|
715
|
+
process.exit(1)
|
|
716
|
+
} finally {
|
|
717
|
+
bridge.close()
|
|
718
|
+
}
|
|
719
|
+
}
|