sootsim 0.1.191 → 0.1.192
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/dist-cli/bin.js +3 -3
- package/dist-cli/chunks/{agent-YS7SPS6Z.js → agent-PHL7BCDF.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-MHH4YKJE.js → agent-wrapper-Q7YYGB47.js} +2 -2
- package/dist-cli/chunks/{app-fonts-PZNPXQAI.js → app-fonts-JHXDCDMV.js} +2 -2
- package/dist-cli/chunks/{assert-XVKXT3KE.js → assert-QZGQRITN.js} +2 -2
- package/dist-cli/chunks/{auth-DUCWOBV3.js → auth-WUJUCT45.js} +2 -2
- package/dist-cli/chunks/beta-SVHMZB4M.js +2 -0
- package/dist-cli/chunks/{camera-XVZUX6Q2.js → camera-MXS4S7SH.js} +2 -2
- package/dist-cli/chunks/{chunk-UZDH32UA.js → chunk-267P7YH5.js} +1 -1
- package/dist-cli/chunks/{chunk-5XMJFP54.js → chunk-45KEJM4F.js} +1 -1
- package/dist-cli/chunks/{chunk-5N2BFB4I.js → chunk-5GCJBPRA.js} +1 -1
- package/dist-cli/chunks/{chunk-A46MWTJB.js → chunk-5J623CXF.js} +2 -2
- package/dist-cli/chunks/{chunk-O2X7YSAD.js → chunk-5L46K7LQ.js} +12 -12
- package/dist-cli/chunks/{chunk-JYRWIES4.js → chunk-5QCTFBI7.js} +3 -3
- package/dist-cli/chunks/{chunk-2QAG5IPN.js → chunk-62WAWGK7.js} +1 -1
- package/dist-cli/chunks/{chunk-7NN725AT.js → chunk-6Q7UG6C3.js} +2 -2
- package/dist-cli/chunks/{chunk-O7QYV2FI.js → chunk-AATVF4IX.js} +1 -1
- package/dist-cli/chunks/{chunk-EXC6INU6.js → chunk-ADT62BUW.js} +3 -3
- package/dist-cli/chunks/{chunk-BORW7JE4.js → chunk-ALOU4MLU.js} +1 -1
- package/dist-cli/chunks/{chunk-KITHQVX5.js → chunk-AZLLXQK3.js} +2 -2
- package/dist-cli/chunks/{chunk-WXN3JD2J.js → chunk-BXYUWFLE.js} +2 -2
- package/dist-cli/chunks/{chunk-S23R7GAE.js → chunk-CDLN4Q7X.js} +2 -2
- package/dist-cli/chunks/{chunk-R7AEJR2M.js → chunk-D73E5VNF.js} +2 -2
- package/dist-cli/chunks/{chunk-RINOK2FV.js → chunk-DNGOW6HY.js} +2 -2
- package/dist-cli/chunks/{chunk-6PJLFYJT.js → chunk-DVR4VXGW.js} +1 -1
- package/dist-cli/chunks/{chunk-6YV6WW5Q.js → chunk-FBCO2HQG.js} +1 -1
- package/dist-cli/chunks/{chunk-BYZ5SCMD.js → chunk-GC63ON27.js} +1 -1
- package/dist-cli/chunks/chunk-H2UPWMBO.js +1 -0
- package/dist-cli/chunks/chunk-H3P7HIBN.js +1 -0
- package/dist-cli/chunks/{chunk-UYNPUHMD.js → chunk-ICUPPGF3.js} +1 -1
- package/dist-cli/chunks/{chunk-NX2QM2BE.js → chunk-IKTVEAYW.js} +2 -2
- package/dist-cli/chunks/{chunk-JCXQE5XP.js → chunk-IRM7PFIN.js} +2 -2
- package/dist-cli/chunks/{chunk-2ZZIXID6.js → chunk-K2GDJUD7.js} +2 -2
- package/dist-cli/chunks/{chunk-64GTYKIF.js → chunk-LBQLZO2B.js} +2 -2
- package/dist-cli/chunks/{chunk-UKKQXZFZ.js → chunk-M5EP44JR.js} +2 -2
- package/dist-cli/chunks/{chunk-FWZQSSEJ.js → chunk-NKAAWXM5.js} +2 -2
- package/dist-cli/chunks/{chunk-WUV6QJJU.js → chunk-SC2KZOH5.js} +2 -2
- package/dist-cli/chunks/{chunk-SQ2MTGDQ.js → chunk-T4V7I7WJ.js} +2 -2
- package/dist-cli/chunks/{chunk-WXMGGTWH.js → chunk-UQEHUIRP.js} +2 -2
- package/dist-cli/chunks/{chunk-JALTULVB.js → chunk-VGZK7VNM.js} +1 -1
- package/dist-cli/chunks/{chunk-S6L32ZQF.js → chunk-WNJWTMX4.js} +1 -1
- package/dist-cli/chunks/{chunk-QLZSJLM4.js → chunk-WZWDWY2L.js} +2 -2
- package/dist-cli/chunks/{chunk-M6GIXT25.js → chunk-XBGRSZHS.js} +1 -1
- package/dist-cli/chunks/{chunk-XJHF3OFF.js → chunk-XIBAP4UZ.js} +3 -3
- package/dist-cli/chunks/{chunk-TE4UPZY2.js → chunk-XMP5FJG7.js} +1 -1
- package/dist-cli/chunks/{chunk-R6YZNTVX.js → chunk-Y7ZXRH2W.js} +1 -1
- package/dist-cli/chunks/{chunk-6XAGMAP7.js → chunk-YCOBUNXO.js} +3 -3
- package/dist-cli/chunks/{chunk-WSF2QLMD.js → chunk-YDZHGHVA.js} +2 -2
- package/dist-cli/chunks/{chunk-LJ4CQHHZ.js → chunk-ZK6HGLGX.js} +2 -2
- package/dist-cli/chunks/cli-version-IDX6FF7E.js +2 -0
- package/dist-cli/chunks/{compat-ZKG2T55R.js → compat-MWU75WMC.js} +3 -3
- package/dist-cli/chunks/{config-RWZGJPQB.js → config-DUJOWFFM.js} +2 -2
- package/dist-cli/chunks/{control-6PTTSYCT.js → control-YBCFFZLP.js} +2 -2
- package/dist-cli/chunks/daemon-XCYS3XQD.js +2 -0
- package/dist-cli/chunks/{debug-WMJUSORS.js → debug-BCUJW7ZY.js} +3 -3
- package/dist-cli/chunks/{desktop-B4IZ3JSC.js → desktop-J6P2F5YA.js} +3 -3
- package/dist-cli/chunks/{detox-GL2W7X6M.js → detox-OLQMVDYX.js} +2 -2
- package/dist-cli/chunks/{device-ID3KADOW.js → device-62OJ5XLI.js} +2 -2
- package/dist-cli/chunks/{diagnose-SNSGBFUR.js → diagnose-NMT4W24M.js} +2 -2
- package/dist-cli/chunks/drivers-TYEZPNJP.js +2 -0
- package/dist-cli/chunks/flow-LJQPTY47.js +2 -0
- package/dist-cli/chunks/help-YWHSQJCE.js +2 -0
- package/dist-cli/chunks/{home-paths-QGNZG3YG.js → home-paths-HFFORXSK.js} +2 -2
- package/dist-cli/chunks/inspect-IUI6ZUYC.js +2 -0
- package/dist-cli/chunks/install-desktop-WSKIMDMC.js +2 -0
- package/dist-cli/chunks/{login-GDTYJBVI.js → login-7JXCRVQ5.js} +4 -4
- package/dist-cli/chunks/{logout-VE4INQI4.js → logout-VUPESZNG.js} +2 -2
- package/dist-cli/chunks/{maestro-XBBDWQQU.js → maestro-5K5BDL6P.js} +2 -2
- package/dist-cli/chunks/{mode-P34QE7AA.js → mode-6BSG3QCZ.js} +2 -2
- package/dist-cli/chunks/optional-demo-registry-VSPJ2XGJ.js +2 -0
- package/dist-cli/chunks/{perf-ROSEJBSJ.js → perf-MCLK5HK6.js} +2 -2
- package/dist-cli/chunks/{record-UT47RU34.js → record-F3MUROPJ.js} +3 -3
- package/dist-cli/chunks/runtime-6OEHJM2Q.js +2 -0
- package/dist-cli/chunks/{screenshot-command-LXG5T54F.js → screenshot-command-AVMZUXHN.js} +2 -2
- package/dist-cli/chunks/{serve-UHVABXXQ.js → serve-DAIFEBTB.js} +2 -2
- package/dist-cli/chunks/{setup-RP4ZZNHU.js → setup-KRLG5W3C.js} +3 -3
- package/dist-cli/chunks/{skills-IGB4LGQE.js → skills-XRLZ2Y4R.js} +2 -2
- package/dist-cli/chunks/{storage-WIZD4QJO.js → storage-T37FFEEA.js} +2 -2
- package/dist-cli/chunks/store-46JZKZH5.js +2 -0
- package/dist-cli/chunks/telemetry-3KQWDHF2.js +2 -0
- package/dist-cli/chunks/{test-6O3VSW7H.js → test-CU5C7WLG.js} +5 -5
- package/dist-cli/chunks/{timeline-J6JK2K5P.js → timeline-DPA4PNDR.js} +2 -2
- package/dist-cli/chunks/{upgrade-UCL5HS5J.js → upgrade-TAFBZLLU.js} +2 -2
- package/dist-cli/chunks/upload-VYWQLOYM.js +2 -0
- package/dist-cli/chunks/{version-YHJ4K5CY.js → version-3FRRKSVE.js} +2 -2
- package/dist-cli/chunks/{web-5UEVEPW2.js → web-FRS3JVLH.js} +2 -2
- package/dist-cli/chunks/{what-happened-3UE3QORD.js → what-happened-IZ4FTX5W.js} +2 -2
- 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/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 +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- 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 +1 -1
- 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/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +4 -1
- package/dist-lib/sdk.mjs +4 -1
- package/dist-lib/skills.cjs +1 -1
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/dist-cli/chunks/beta-4JXGELJG.js +0 -2
- package/dist-cli/chunks/chunk-A4J3ZFTP.js +0 -1
- package/dist-cli/chunks/chunk-D3FMK5KM.js +0 -1
- package/dist-cli/chunks/cli-version-UOHSVKG2.js +0 -2
- package/dist-cli/chunks/daemon-NZA4D5HD.js +0 -2
- package/dist-cli/chunks/drivers-SCKKGVU5.js +0 -2
- package/dist-cli/chunks/flow-2DURO62S.js +0 -2
- package/dist-cli/chunks/help-NVVELOB7.js +0 -2
- package/dist-cli/chunks/inspect-5FWMOJ7P.js +0 -2
- package/dist-cli/chunks/install-desktop-5Z3S4JTX.js +0 -2
- package/dist-cli/chunks/optional-demo-registry-E7K3MGYI.js +0 -2
- package/dist-cli/chunks/runtime-HXK427JM.js +0 -2
- package/dist-cli/chunks/store-MS3GXV6K.js +0 -2
- package/dist-cli/chunks/telemetry-2RQQYIGP.js +0 -2
- package/dist-cli/chunks/upload-H53ZS5FN.js +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
2
|
-
import{b as B}from"./chunk-S6L32ZQF.js";var v={bridgePort:7668,defaultShellUrl:"http://localhost:5173/"};function t(o,s){return{flag:o,description:s}}function e(o,s){return{command:o,description:s}}var D=[{id:"test",slug:"test",navTitle:"test",title:"sootsim test",description:"run tests against sootsim",summary:"Run package-local smoke and debugging tests, YAML flows, or the shared Detox-style conformance suites against a running sootsim target.",order:30,usage:["sootsim test [options]"],options:[t("--flows","run YAML flows through the sootsim flow runner"),t("--detox","run the shared Detox-style conformance suites against sootsim"),t("--parallel","run discovered flows in parallel where supported"),t("--watch","re-run interactively when files change"),t("--reporter <type>","select console, json, or junit reporting"),t("--grep <pattern>","filter the test set by name")],examples:[e("sootsim test","run package-local Playwright smoke/debug tests"),e("sootsim test --flows"),e("sootsim test --detox","run the shared conformance suite against sootsim"),e("sootsim test --detox --watch")],related:["flow","inspect","record"]},{id:"flow",slug:"flow",navTitle:"flow",title:"sootsim flow",description:"run flows through the current sim or manage a draft from live inspect actions",summary:"Use flow files when you already have them, or start a draft so inspect-driven actions can be kept one by one and exported into YAML once the path is proven. Flow playback, recording, and profiling now stay on the shared bridge runner.",order:40,usage:["sootsim flow <flow.yaml> [options]","sootsim flow start","sootsim flow keep (alias: sootsim flow good)","sootsim flow end [--output <path>] [--validate] [--video]"],options:[t("--record","record a video while the flow runs"),t("--profile","capture perf stats while the flow runs"),t("--out <dir>","output bundle directory \u2014 recordings land here, and `--screenshots` also defaults to this directory (so one flag controls the whole demo-run bundle instead of needing both)"),t("--screenshots <dir>","override screenshot output directory (defaults to --out, or /tmp/sootsim-flow if neither is set)"),t("--screenshot-paths <mode>","screenshot path mode: `dir` (default \u2014 flat directory of files) or `flow` (per-flow subdirectory tree)"),t("--replace <module>=<file>","replace a Metro module with a local file for this run \u2014 useful for swapping in a fixture component (e.g. a deterministic SeedPhraseInputScreen for demo recordings). repeatable"),t("--slow <ms>","delay between steps for easier debugging"),t("--tail-wait <ms>","hold recording open after the last step so the final UI state is captured (default: smart idle up to 6000ms for --preview, fixed 2000ms for --record, 0 otherwise)"),t("--url <url>","load this target before running the flow"),t("--no-shell","capture every screenshot tenant-only (no status bar, keyboard, notification center, or other shell overlays). per-step `layers:` still wins over this default"),t("--shell-only","inverse \u2014 capture only the shell chrome overlays"),t("--new","open a fresh sim before running the flow"),t("--driver <id>","when paired with --new, launch through a specific driver from the registry (e.g. playwright); see `sootsim list --drivers`"),t("--headless","pass headless=true to the launch driver (useful with --driver playwright)"),t("--headed","force a fresh, VISIBLE window for this run (implies --new, overrides --headless) \u2014 watch the flow run live even if the current sim is headless or stale"),t("--sim <sim>","target a specific current sim"),t("--electron","prefer the desktop companion for this flow run"),t("--output <path>","write the drafted flow when using `flow end`"),t("--validate","replay the drafted flow before clearing it"),t("--video","replay and record the drafted flow before clearing it"),t("--preview","record + upload the run as a shareable /preview/<id> link (implies --record)"),t("--preview-origin <url>","override the upload target for --preview (defaults to auto)"),t("--preview-public-origin <url>","override the public link origin for --preview (defaults to sootsim.com for prod uploads)"),t("--preview-open","open the resulting /preview/<id> url after upload")],examples:[e("sootsim flow flows/login.yaml"),e("sootsim flow flows/login.yaml --profile"),e("sootsim flow flows/demo.yaml --record --slow 500"),e("sootsim flow flows/demo.yaml --preview","record + upload a shareable link in one step"),e("sootsim flow start"),e("sootsim flow keep"),e("sootsim flow end --output ./flows/draft.yaml"),e("sootsim flow end --output ./flows/draft.yaml --validate"),e("sootsim flow end --output ./flows/draft.yaml --video")],related:["inspect","record","desktop","test"]},{id:"record",slug:"record",navTitle:"record",title:"sootsim record",description:"capture the live sim as webm/mp4/gif, or sample N png frames (--frames)",summary:"Drives the engine's built-in canvas recorder over the WS bridge \u2014 no second browser, no ffmpeg. Encoding happens in the running page (MediaRecorder for webm, WebCodecs for mp4, gifenc for gif). Two modes: atomic (duration-bounded) or stateful (start \u2192 interact \u2192 stop). Stateful mode is webm/mp4 only; for gif/png use atomic mode. Use --frames to sample N evenly-spaced png snapshots instead of a video. NOTE on `live`/`combined`: the `/preview/<id>` id is derived from the app's bundle identity, not the recording \u2014 so re-recording the same app reuses the same URL and overwrites the previous preview. This is intentional (re-record replaces in place); keep a recording you want to preserve by copying its `/preview/<id>` page elsewhere before recording the same app again.",order:60,usage:["sootsim record [options]","sootsim record start [options]","sootsim record prelude-start [--origin <url>]","sootsim record stop [--output <path>]","sootsim record status # reports the record-start session; also probes the engine","sootsim record cancel # cancels a record-start session","sootsim record upload (--events <path> | --video <path>) [--open]"],options:[t("--format <type>","webm | mp4 | gif | png (inferred from --output extension; stateful mode is webm/mp4 only)"),t("--mode <kind>","video | live | combined (default: video). live captures the event stream; combined captures both and uploads automatically. NOTE: live/combined upload to /preview/<id> whose id is bundle-derived, so re-recording the same app overwrites the previous preview"),t("--duration <seconds>","recording duration (default: 10, atomic mode only)"),t("--fps <number>","target frame rate for video/gif (default: 30)"),t("--output <path>","output file, or directory when --frames is set"),t("--frames <n>","sample N evenly-spaced png frames instead of a video"),t("--max-width <px>","downscale gif frames to this width"),t("--no-shell","exclude the simulated iOS chrome (status bar, keyboard, toasts) \u2014 record the tenant surfaces only"),t("--shell-only","record only the shell chrome"),t("--open","open the uploaded preview URL in the browser after stop (live/combined)"),t("--sim <sim>","target a specific sim"),t("--origin <url>","billing/upload origin for live/combined (default: auto \u2014 probes a local :3000 stack, else https://sootbean.com; also honors SOOTSIM_UPLOAD_ORIGIN)"),t("--owner <org>","associate live/combined preview uploads with a linked org repo; pass with --repo"),t("--repo <repo>","repo name for --owner; the signed-in user must belong to the owning org team"),t("--events <path>","for upload: gzipped events .jsonl.gz file to attach"),t("--video <path>","for upload: webm/mp4/gif recording to attach"),t("--assets-only","for upload: keep assets only; replay API calls live")],examples:[e("sootsim record --duration 5"),e("sootsim record --format mp4 --output demo.mp4 --duration 8"),e("sootsim record --output demo.gif --duration 3"),e("sootsim record --frames 10 --output ./frames/"),e("sootsim record --mode combined --duration 8 --open --owner my-org --repo my-app","capture video + events and upload a repo-associated preview link"),e("sootsim record start --format mp4","begin; interact freely across any number of CLI calls"),e("sootsim record start --mode combined","start a stateful preview-share recording"),e("sootsim record prelude-start","capture hidden setup events before starting the visible proof segment"),e("sootsim record stop --output flow.mp4","finalize + save"),e("sootsim record cancel","discard a record-start session (atomic --duration runs own their own lifecycle)"),e("sootsim record upload --events ./my-run.jsonl.gz --open"),e("sootsim record upload --video /tmp/soot-flow.webm")],related:["screenshot","flow"]},{id:"storage",slug:"storage",navTitle:"storage",title:"sootsim storage",description:"manage guest app storage and launch profiles",summary:"Clear the current guest app's local storage through the live reload bridge, or manage persistent storage profiles for Electron and Playwright launches. Profiles isolate cookies, localStorage, IndexedDB, cache, permissions, and service workers; browser-tab launches cannot honor them.",order:65,usage:["sootsim storage clear [--sim <id>] [--json]","sootsim storage profile ls","sootsim storage profile create <id>","sootsim storage profile clear <id>","sootsim storage profile delete <id>"],options:[t("--sim <id>","target a specific connected sim for `storage clear`"),t("--json","emit { cleared, ready, reload } for `storage clear`"),t("<id>","profile id: letters, numbers, dot, dash, or underscore")],examples:[e("sootsim storage clear"),e("sootsim storage clear --sim a9 --json"),e("sootsim storage profile ls"),e("sootsim storage profile create qa"),e("sootsim open 8081 --profile qa --driver playwright"),e("sootsim storage profile clear qa")],related:["open","desktop"]},{id:"perf",slug:"perf",navTitle:"perf",title:"sootsim perf",description:"CPU, React render, and shell frame profiling",summary:"One profiling group for the three performance surfaces: sampled JS CPU profiles via Chrome DevTools Protocol, React render-cost tables from the tenant worker, and shell-worker frame profiling for the renderer that paints app pixels.",order:66,usage:["sootsim perf cpu [options]","sootsim perf react <profile|summary|slow|rerenders|tree|why> [options]","sootsim perf shell <start|stop|transition> [options]"],options:[t("--cdp-port <port>","for `perf cpu`: Chrome DevTools port (default: $SOOTSIM_CDP_PORT or 9222)"),t("--duration <seconds>","for `perf cpu`: recording duration (default: 5)"),t("--match <substring>","for `perf cpu`: pick the page target by URL substring"),t("--output <path>","for `perf cpu`: output .cpuprofile path"),t("--include-props","for `perf react profile start`: record shallow prop previews"),t("--limit <n>","for `perf react`: rows to print"),t("--json","structured output where supported"),t("--sim <sim>","target a specific connected sim")],examples:[e("sootsim open 8089 --new --driver playwright --cdp-port 9222"),e("sootsim perf cpu --cdp-port 9222 --duration 5"),e("sootsim perf react profile start"),e("sootsim perf react summary --limit 10"),e("sootsim perf shell start"),e("sootsim perf shell stop --json")],related:["open","record","flow","debug"]},{id:"screenshot",slug:"screenshot",navTitle:"screenshot",title:"sootsim screenshot",description:"capture PNGs and manage App Store screenshot assets",summary:"One screenshot surface: capture the current canvas as a PNG, drive the live App Store slide composer, or run the plan/headless App Store capture pipeline. Bare `sootsim screenshot` is the same as `sootsim screenshot capture`.",order:70,usage:["sootsim screenshot [capture] [output] [options]","sootsim screenshot slides <list|set|add|remove|focus|overview|capture|export> [args]","sootsim screenshot appstore --plan <plan.yaml> [options]","sootsim screenshot appstore capture --org <org> --repo <repo> [options]"],options:[t("--output <path>","for capture: output PNG path (default: /tmp/sootsim-inspect.png). aliases: -o, --out, --file, --path"),t("--area <x,y,w,h>","for capture: crop to a logical sootsim rect. aliases: --rect, --crop"),t("--id <testID>","for capture: crop to the bounding box of a node by testID. alias: --testid"),t("--text <text>","for capture: crop to the bounding box of a node by text content"),t("--no-shell","for capture/flows: exclude simulated iOS chrome"),t("--shell-only","for capture/flows: capture only shell chrome"),t("--plan <path>","for appstore: screenshot plan yaml"),t("--org <org>","for appstore capture: github org slug"),t("--repo <repo>","for appstore capture: repo name"),t("--compose-only","for appstore: skip flow capture and reuse existing raws"),t("--capture-only","for appstore: stop after raw/framed intermediates")],examples:[e("sootsim screenshot","capture the current sim to a PNG"),e("sootsim screenshot --output app.png"),e("sootsim screenshot capture --no-shell --output tenant-only.png"),e("sootsim screenshot --area 0,200,393,400"),e("sootsim screenshot slides","list the current live deck"),e("sootsim screenshot slides capture 1"),e("sootsim screenshot slides export --out ./exports"),e("sootsim screenshot appstore --plan .sootsim/app-store.yaml"),e("sootsim screenshot appstore --plan .sootsim/app-store.yaml --compose-only","rerender marketing canvases from existing raw PNGs"),e("sootsim screenshot appstore capture --org acme --repo my-app --dry-run","headlessly capture editable org-deck slides without uploading")],related:["mode","record","inspect","flow"]},{id:"mode",slug:"mode",navTitle:"mode",title:"sootsim mode",description:"toggle screenshot and 3D display modes",summary:"Toggle live shell display modes using the same plugin-owned action paths as the rail and menus. `mode screenshot` hides browser chrome for clean captures; `mode three` toggles and configures the live 3D device stage.",order:73,usage:["sootsim mode screenshot [on|off|toggle]","sootsim mode three [on|off|toggle]","sootsim mode three configure [flags]"],options:[t("screenshot on|off|toggle","toggle screenshot-mode chrome overlay"),t("three on|off|toggle","toggle the live 3D device stage"),t("--background <id>","set the 3d background"),t("--gradient <stops>","custom gradient bg: comma-separated css hex stops (overrides --background)"),t("--gradient-angle <deg>","custom gradient angle (default 180 = top\u2192bottom)"),t("--colorway <id>","set the phone colorway"),t("--script <id>","apply a camera preset pose"),t("--progress <0..1>","script progress to sample (default: 1)"),t("--animate","run the script instead of sampling one frame"),t("--slow","run the script slowly when --animate is set"),t("--environment <on|off>","enable or disable environment objects"),t("--env-shape <id>","orb | pill | diamond | pane"),t("--env-spread <id>","tight | medium | wide"),t("--env-size <id>","small | medium | large"),t("--env-color <id>","peach | gold | mint | sky | violet"),t("--env-glow <on|off>","enable or disable environment glow"),t("--env-plastic <on|off>","enable or disable environment plastic material"),t("--room <on|off>","enable or disable the room effect"),t("--bokeh <on|off>","enable or disable bokeh"),t("--reset-pose","return to the default hero pose before other changes")],examples:[e("sootsim mode screenshot on","hide browser chrome around the canvas"),e("sootsim mode screenshot off"),e("sootsim mode three on","force 3d mode on"),e("sootsim mode three configure --colorway sky --background gradient-sunset","set the phone and background to specific options"),e('sootsim mode three configure --room on --gradient "#0a1822,#0d2233,#06101a"',"room effect + a custom brand-color gradient background"),e("sootsim mode three configure --script hero-pan --animate --slow","play a camera script slowly"),e("sootsim mode three configure --reset-pose","return to the default pose")],related:["screenshot"]},{id:"describe",slug:"describe",navTitle:"describe",title:"sootsim describe",description:"curated human-readable UI summary (default inspection tool)",summary:"The default way to see what is on screen. Lists visible UI elements with type, text, position, size, and style \u2014 buttons show [button], tappable views show [tap], inputs show [input]. Structural noise (icon wrappers, layout containers, duplicate text inside buttons) is pruned by default; use --all for the unfiltered tree, --verbose for ids/labels/style, and --json to script against it. Reach for describe before screenshots or DOM poking.",order:68,usage:["sootsim describe [filter] [--verbose] [--watch] [--all] [--json] [--no-clipped] [--compact] [--no-xy] [--only <glob>] [--subtree <id>] [--testid-like <pat>]"],options:[t("--verbose","include ids, labels, and extra style info"),t("--all","do not prune structural view nodes"),t("--watch","redraw as the UI changes (ctrl-c to stop)"),t("--json","emit structured JSON"),t("--no-clipped","strip rows annotated (clipped:left|right|top|bottom) so the on-screen state is not buried"),t("--compact","render the tree in a tighter format"),t("--no-xy","hide x,y coordinates from each row"),t("--only <glob>","glob filter across text/role/testID"),t("--subtree <id>","limit the dump to a subtree rooted at the given testID"),t("--testid-like <pattern>","fuzzy-match nodes whose testID contains the pattern")],examples:[e("sootsim describe"),e("sootsim describe button"),e("sootsim describe --verbose"),e("sootsim describe --json"),e("sootsim describe --watch"),e("sootsim describe --subtree feedListRoot","limit to one subtree"),e('sootsim describe --only "*Header*"',"glob-match across text/role/testID")],related:["find","get","do","inspect"]},{id:"find",slug:"find",navTitle:"find",title:"sootsim find",description:"locate nodes by text / testID / role / type / predicate",summary:"The unified finder. A bare argument matches node text (findByText); flag forms match by testID, role, component type, or predicate. --pressable and --visible list every tappable or visible node, and --interactive-targets (alias --actions) ranks visible+pressable nodes and prints a ready-to-run `sootsim do tap-...` command per row, so the next tap is one copy away. Use --verbose for full node JSON and --json to script.",order:68.5,usage:["sootsim find <text>","sootsim find --testid <id>","sootsim find --role <role>","sootsim find --type <component-type>","sootsim find --pressable","sootsim find --visible","sootsim find --interactive-targets"],options:[t("--text <text>","match node text content (same as bare positional)"),t("--testid <id>","match node testID or id exactly"),t("--role <role>","match accessibilityRole"),t("--type <type>","match React component type"),t("--pressable","list all tappable nodes"),t("--visible","list all visible (non-zero) nodes"),t("--interactive-targets, --actions","ranked tappable nodes, each with a ready-to-run tap command"),t("--verbose, --dump","emit full node JSON for each result"),t("--json","emit structured JSON")],examples:[e('sootsim find "Sign in"'),e("sootsim find --testid loginButton"),e("sootsim find --role button"),e("sootsim find --pressable"),e("sootsim find --visible --json"),e("sootsim find --interactive-targets","ranked visible+pressable nodes with copy-paste tap commands")],related:["describe","get","do","inspect"]},{id:"assert",slug:"assert",navTitle:"assert",title:"sootsim assert",description:"run any read verb and convert its output into an exit code",summary:"Thin wrapper that spawns a read verb (describe, find, get errors, \u2026) with --json forced on, parses stdout, and evaluates assertion flags over the payload. Exit codes are bisect-friendly: 0 pass, 1 fail, 125 skip (app not loaded / verb crashed), 2 misuse. Flag-level composition (--count / --contains / --jq / --has-path / --within) means the same predicate surface works across every read verb.",order:69,usage:["sootsim assert <verb> <verb-args...> <assertion-flags...>"],options:[t("--count <n>","result array has exactly n items"),t("--count-at-least <n>","length >= n"),t("--count-at-most <n>","length <= n"),t("--exists","non-null, non-empty (default when no flag given)"),t("--empty","null or zero length"),t("--contains <str>","stringified result contains str (repeatable)"),t("--not-contains <str>","stringified result does not contain str"),t("--matches <regex>","stringified result matches regex"),t("--not-matches <regex>","stringified result does not match regex"),t("--equals <literal>","scalar equality"),t("--has-path <dotted.path>","nested path exists"),t("--path-equals <path> <value>","nested path equals value"),t("--jq <expr>","jq expression is truthy (requires jq on PATH)"),t("--within <ms>","retry verb + predicates until pass or deadline"),t("--allow-timeout","treat verb auto-wait timeout as fail, not skip"),t("--negate, !","flip pass/fail (does not flip skip)"),t("--quiet","suppress the one-line pass/fail summary")],examples:[e("sootsim assert find --testid set-max-input --count 4","exactly four matching nodes"),e("sootsim assert describe --contains swap-form-header","substring anywhere in the tree dump"),e("sootsim assert get errors --count 0","fail the commit if any console error"),e("sootsim assert find --testid submit --exists --within 3000","poll for 3s before failing"),e(`sootsim assert describe --jq '.shell.state == "app"'`,"jq predicate over the payload"),e("git bisect run sootsim assert find --testid set-max-input --count 4","git-bisect integration")],related:["find","describe","get","list"]},{id:"get",slug:"get",navTitle:"get",title:"sootsim get",description:"read runtime state (tree, a11y, url, count, errors, \u2026)",summary:"Grouping verb for pure reads. `sootsim get <noun>` covers the read side of the bridge \u2014 tree, a11y, url, count, console errors/warnings/requests, layout, globals, and single-node lookups.",order:70,usage:["sootsim get <noun> [args]"],examples:[e("sootsim get tree"),e("sootsim get a11y 3"),e("sootsim get url"),e("sootsim get count"),e("sootsim get errors 5"),e("sootsim get requests 5"),e("sootsim get node loginButton"),e("sootsim get layout loginButton"),e("sootsim get globals")],related:["do","find","describe","inspect"]},{id:"do",slug:"do",navTitle:"do",title:"sootsim do",description:"drive the app (tap, type, scroll, swipe, key, reload, \u2026)",summary:"Grouping verb for user-interaction actions. `sootsim do <action>` covers the write side of the bridge \u2014 taps, typing, key presses, touch/scroll/drag/swipe/pinch gestures, reload, and local timing helpers.",order:71,usage:["sootsim do <action> [args]"],examples:[e("sootsim do tap 196 727"),e("sootsim do double-tap 196 400"),e('sootsim do tap-text "Sign in"'),e("sootsim do tap-id loginNextButton"),e('sootsim do type "natew.bsky.social"'),e('sootsim do type-into email "me@example.com"'),e("sootsim do key return"),e("sootsim do key-sequence shift h i"),e("sootsim do dismiss"),e("sootsim do scroll feed 0 400"),e("sootsim do drag 200 720 200 160"),e("sootsim do swipe 200 720 200 160"),e("sootsim do gesture swipe-from-bottom-edge"),e("sootsim do reload")],related:["shell","get","find","describe","inspect","wait"]},{id:"wait",slug:"wait",navTitle:"wait",title:"sootsim wait",description:"block until the runtime reaches a known state",summary:"Grouping verb for explicit synchronization. Use instead of guessing with `sleep`. Every subverb has a bounded timeout and exits non-zero when it times out, so automations fail loudly rather than silently racing animations or missing nodes.",order:72,usage:["sootsim wait <kind> [args]"],examples:[e("sootsim wait ready","block until the app bundle is loaded and painted"),e("sootsim wait idle","block until animations + rAF queue are settled"),e("sootsim wait selector loginButton","block until a node with this testID is present"),e("sootsim wait selector feedList --max-ms 3000","cap how long to wait for a node")],related:["do","find","describe","get"]},{id:"shell",slug:"shell",navTitle:"shell",title:"sootsim shell",description:"drive shell state and simulator chrome",summary:"Top-level shell controls for app launch, home/switcher transitions, and simulator-owned chrome such as appearance and lock state.",order:72,usage:["sootsim shell launch <appId> [waitMs] [--clear-state]","sootsim shell home [waitMs]","sootsim shell switcher [waitMs]","sootsim shell open-card <appId> [waitMs]","sootsim shell appearance <light|dark|auto|toggle>","sootsim shell lock","sootsim shell shake"],examples:[e("sootsim shell launch photos"),e("sootsim shell home"),e("sootsim shell switcher 800"),e("sootsim shell appearance dark"),e("sootsim shell lock")],related:["do","inspect","debug"]},{id:"inspect",slug:"inspect",navTitle:"inspect",title:"sootsim inspect",description:"query, describe, and drive the running sootsim instance",summary:"Use the bridge-backed inspection surface for full access to the real node tree. `sootsim inspect <sub>` works for every subcommand in the surface; day-to-day, prefer the grouped verbs (`describe`, `find`, `get`, `do`, `shell`, `debug`) \u2014 run `sootsim --help` to see the full set.",order:80,usage:["sootsim inspect <subcommand> [args]"],options:[t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--timeout <ms>","command timeout for bridge requests"),t("--base-url <url>","base shell URL used by open when wrapping bundle targets")],examples:[e("sootsim describe"),e("sootsim get errors 5"),e("sootsim get requests 5"),e('sootsim do tap-text "Sign in"'),e("sootsim list"),e("sootsim debug state shell --sim a2")],related:["debug","get","do","shell","find","list","open","use"]},{id:"network",slug:"network",navTitle:"network",title:"sootsim network",description:"inspect live network traffic from the running sootsim worker",summary:"Read the shared observability store (fetch + XHR captured in the render worker) from the terminal. List recent requests, tail in real time, filter by URL or status, inspect one entry in detail, or clear the buffer. Shares its data source with the in-shell devtools dock so both views stay in lock-step.",order:85,usage:["sootsim network [limit]","sootsim network --failed","sootsim network --slow [--threshold <ms>]","sootsim network --filter <substring>","sootsim network --tail","sootsim network get <id>","sootsim network clear"],options:[t("--failed","only show errored or non-2xx responses"),t("--slow","only show requests slower than --threshold (default 1000ms), sorted by duration desc"),t("--threshold <ms>","slow threshold in milliseconds for --slow (default 1000)"),t("--filter <substring>","URL substring filter (case-insensitive)"),t("--limit <n>","max entries to print (default 20)"),t("--tail, -f","follow mode: stream new entries as they land"),t("--json","emit structured JSON instead of formatted rows"),t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim network","list the last 20 requests"),e("sootsim network 100","list the last 100"),e("sootsim network --failed","only errors and 4xx/5xx"),e("sootsim network --slow","requests slower than 1000ms, sorted by duration desc"),e("sootsim network --slow --threshold 200","tighten the slow threshold to 200ms"),e("sootsim network --filter api.example.com"),e("sootsim network --tail","live follow mode, ctrl-c to stop"),e("sootsim network --tail --failed"),e("sootsim network get req-42-l7k9"),e("sootsim network clear")],related:["inspect","debug","get","logs"]},{id:"logs",slug:"logs",navTitle:"logs",title:"sootsim logs",description:"inspect live console output from the running sootsim worker",summary:"Read the shared observability log store (console.log/info/warn/error/debug plus uncaught errors and unhandled rejections, captured in the render worker) from the terminal. List recent logs, tail in real time, filter by level or substring, or clear the buffer. Shares its data source with the devtools dock so both views stay in lock-step.",order:86,usage:["sootsim logs [limit]","sootsim logs --level <csv>","sootsim logs --filter <substring>","sootsim logs --tail","sootsim logs clear"],options:[t("--level <csv>","comma-separated level filter (log,info,warn,error,debug)"),t("--filter <substring>","message substring filter (case-insensitive)"),t("--limit <n>","max entries to print (default 50)"),t("--tail, -f","follow mode: stream new log entries as they land"),t("--json","emit structured JSON instead of formatted rows"),t("--internal, --all","include engine-internal [sootsim] logs (bundle-loader, HMR traps, etc.) \u2014 hidden by default so guest-app output stays readable"),t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim logs","last 50 log entries"),e("sootsim logs 200","last 200"),e("sootsim logs --level error,warn"),e('sootsim logs --filter "hydrate"'),e("sootsim logs --tail","live follow mode, ctrl-c to stop"),e("sootsim logs --tail --level error"),e("sootsim logs --internal","include engine-internal logs"),e("sootsim logs clear")],related:["network","inspect","get"]},{id:"debug",slug:"debug",navTitle:"debug",title:"sootsim debug",description:"drive __sootsimDebug: channels, snapshots, and inspectors",summary:"Toggle engine debug channels, capture snapshots, and diff internal state from the terminal while targeting any connected sim.",order:90,usage:["sootsim debug <subcommand> [args]"],options:[t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--json","emit compact JSON for machine consumption"),t("--pretty","emit formatted JSON for human inspection")],examples:[e("sootsim debug enable sheets,portals"),e("sootsim debug snapshot before"),e("sootsim debug diff before after"),e("sootsim debug recent portals 20")],related:["inspect","open","what-happened"]},{id:"what-happened",slug:"what-happened",navTitle:"what-happened",title:"sootsim what-happened",description:"show recent semantic events: toasts, keyboards, screens, alerts, fetches, errors",summary:"Read the unified semantic timeline across host, shell worker, and tenant worker. Defaults to events since the previous CLI call (per-agent cursor), so 'what-happened' reliably shows what's new instead of replaying state you already saw. Catches ephemeral UI like toasts that disappear before describe/find can find them.",order:91,usage:["sootsim what-happened","sootsim what-happened --summary","sootsim what-happened --since 5s --kinds toast,fetch"],options:[t("--summary","one-line counts by kind, no event list"),t("--flow","section the event stream by screen/route boundaries (demo-friendly recap)"),t("--all","full ring (ignore the per-identity cursor)"),t("--since <duration>","absolute window; accepts e.g. 5s, 500ms, 2m"),t("--kinds <csv>","filter to specific kinds: toast, keyboard, screen, alert, fetch, console, ..."),t("--limit <n>","cap returned events (default 200)"),t("--json","emit structured JSON"),t("--no-advance","do not advance the read cursor after rendering"),t("--noisy","include react-commit, layout, and scroll events (suppressed by default so taps/fetches/screen transitions are not buried)"),t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim what-happened","since the previous CLI call"),e("sootsim what-happened --summary","5 errors \xB7 2 warnings \xB7 1 toast"),e("sootsim what-happened --kinds toast,fetch --since 10s","trace a toast back to its trigger"),e("sootsim what-happened --flow --since 5m","section the last 5 minutes by screen/route \u2014 demo-friendly recap"),e("sootsim what-happened --all --json","dump full ring as JSON")],related:["timeline","debug","logs","network"]},{id:"timeline",slug:"timeline",navTitle:"timeline",title:"sootsim timeline",description:"control the semantic event timeline (enable opt-in kinds, clear, dump)",summary:"Distinct from `sootsim record` (video) and `sootsim debug record` (engine channels): manages the semantic agent-facing event stream that backs `sootsim what-happened`. Cheap kinds record at all times; opt-in kinds (scroll, gesture, text-input, reanimated, animation) need to be enabled.",order:92,usage:["sootsim timeline <subcommand> [args]"],options:[t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--json","emit compact JSON for machine consumption")],examples:[e("sootsim timeline status"),e("sootsim timeline start scroll,gesture","enable opt-in kinds"),e("sootsim timeline stop all","silence everything"),e("sootsim timeline dump /tmp/events.json")],related:["what-happened","debug","record"]},{id:"open",slug:"open",navTitle:"open",title:"sootsim open",description:"load a target into the current sim or open a new one",summary:"Resolve a port, dev-server URL, bundle URL, full shell URL, or app deep link. Ports and bundle targets load into a sim; custom-scheme URLs and leading-slash routes dispatch through the current app\u2019s React Native Linking pipeline. Fresh sims open in a separate window. Named profiles force a fresh Electron or Playwright sim because storage isolation is fixed at window/context construction time. A SootSim preview/build link (e.g. https://sootsim.com/preview/<id>) is a full player page, not a driveable sim \u2014 `open` recognizes it and launches it in your browser for viewing instead of mis-loading the HTML as a bundle.",order:100,usage:["sootsim open <port|target|bundle-url|sootsim-url|deeplink> [--new]"],options:[t("--new","open a fresh sim instead of reusing the current sim"),t("--profile <id>","open with an isolated persistent storage profile"),t("--ephemeral","open with a temporary isolated storage profile"),t("--driver <id>","launch through a specific driver (electron and playwright support profiles)"),t("--headless","pass headless=true to the launch driver (useful with `--driver playwright` for CI runs)"),t("--cdp-port <number>","expose Chrome remote debugging on this port so the sim can be cpu-profiled while still driveable over the bridge (playwright driver only)"),t("--browser <engine>","playwright engine: chromium (default), webkit, or firefox. webkit is the iOS Safari proxy \u2014 headless webkit renders on the real Apple GPU while headless chromium software-rasterizes canvas/WebGL"),t("--device <model>","device profile for the opened sim (e.g. iphone-16, iphone-16-pro-max, pixel-8). stamped on the engine URL so every open path honors it; playwright sims also size their viewport to the device instead of a desktop-shaped default"),t("--base-url <url>","base shell URL to wrap around bundle targets"),t("--replace <module>=<file>","replace a Metro module with a local file for this run \u2014 useful for swapping in a deterministic fixture component during demos. repeatable"),t("--remap <host:port>=<host:port>","rewrite guest-app fetch/websocket traffic from one host:port to another for this run (e.g. a third-party e2e suite that hardcodes a port already taken on the host). repeatable"),t("--no-describe","skip the automatic `describe` snapshot that prints right after open finishes (useful when scripting and you only want open's own output)"),t("--hot","force metro HMR on (sets `hot=true` on the bundle URL). default for interactive opens \u2014 edits hot-apply through sootsim's HmrClient"),t("--no-hmr","force metro HMR off (sets `hot=false` on the bundle URL). default under `--driver playwright` so agent/CI runs stay deterministic with no in-bundle refresh wiring"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim open 8081"),e("sootsim open --new 8085"),e("sootsim open 8081 --profile qa"),e("sootsim open 8081 --profile qa --driver playwright"),e("sootsim open http://localhost:8082"),e("sootsim open /settings","dispatch a route deep link to the current app"),e("sootsim open myapp://settings/profile"),e("sootsim open 8081 --driver playwright --headless","headless CI / scripted runs"),e("sootsim open 8081 --new --driver playwright --browser webkit --device iphone-16","iOS Safari proxy on a pinned device profile (cross-browser comparisons need the same device)"),e("sootsim open 8089 --new --driver playwright --cdp-port 9222","open a sim that is both driveable and cpu-profilable (then `sootsim perf cpu --cdp-port 9222`)"),e("sootsim open 8081 --no-describe","silent open for scripts"),e("sootsim open 8081 --no-hmr","open with metro HMR off (e.g. when reproducing a non-HMR boot path)"),e("sootsim open 8081 --driver playwright --hot","driver playwright but keep HMR on (e.g. recording an edit-driven demo)"),e("sootsim open https://sootsim.com/preview/<id>","opens a preview/build link in the browser for viewing (not a driveable sim)")],related:["list","use","close","desktop"]},{id:"list",slug:"list",navTitle:"list",title:"sootsim list",description:"list connected sims or available launch drivers",summary:"Show every connected sim, or \u2014 with `--drivers` \u2014 enumerate the launch drivers (chromium, electron, playwright, system) along with their availability on the current machine. By default hides idle host shells (open tabs with no app bundle loaded) so the output stays focused on the demos that actually have an app running; pass `--all` to see everything.",order:110,usage:["sootsim list [--all] [--bundle <substr>] [--app-port <port>] [--primary] [--sim <sim>] [--json]","sootsim list --drivers"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","highlight a specific sim in the output"),t("--all","show every connected sim, including idle host shells with no app loaded"),t("--bundle <substring>","only sims whose loaded url contains this substring"),t("--app-port <port>","shorthand for `--bundle '/rn/<port>'` \u2014 filter to sims for the app on a specific metro/vite port. NOT `--port` (that's reserved for the bridge port)"),t("--primary","only the primary sim"),t("--drivers, -D","list available launch drivers instead of connected sims"),t("--json","emit array of sim objects for scripts")],examples:[e("sootsim list"),e("sootsim list --all","include idle host shells"),e("sootsim list --app-port 8082","only sims running the app on port 8082"),e("sootsim list --bundle bluesky","sims whose bundle url mentions bluesky"),e("sootsim list --primary"),e("sootsim list --sim a6"),e("sootsim list --drivers","show every installable launch driver"),e('sootsim list --json | jq ".[] | select(.active)"')],related:["open","use","close","inspect"]},{id:"use",slug:"use",navTitle:"use",title:"sootsim use",description:"select a connected sim",summary:"Make one connected sim current by focusing it and saving it as the default target for later bridge-backed commands.",order:120,usage:["sootsim use [sim]"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","target a specific connected sim")],examples:[e("sootsim use"),e("sootsim use a6")],related:["list","open","close"]},{id:"claim",slug:"claim",navTitle:"claim",title:"sootsim claim",description:"take an exclusive lease on a sim",summary:"Reserve a connected sim so other agents cannot send commands to it. Leases auto-expire after 60s of inactivity and refresh on every command from the owner. Prefer `sootsim open --new` over `claim --force` when another agent is active \u2014 the latter steals the lease mid-flight and breaks the other agent's in-progress flow.",order:125,usage:["sootsim claim [sim] [--force]"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","target a specific connected sim"),t("--force","steal the lease from whoever currently holds it. only safe when you know the other holder is dead or abandoned \u2014 prefer `sootsim open --new` to get a fresh sim instead")],examples:[e("sootsim claim"),e("sootsim claim a6"),e("sootsim claim a6 --force","last-resort lease steal \u2014 see `sootsim open --new` for the safer alternative")],related:["list","use","open","close"]},{id:"close",slug:"close",navTitle:"close",title:"sootsim close",description:"close a connected sim",summary:"Request that a sim close itself over the bridge and wait for it to disappear from the sim registry.",order:130,usage:["sootsim close [sim]","sootsim close --all","sootsim close --others"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","target a specific connected sim"),t("--all","close every connected sim"),t("--others","close every connected sim except the current/target one")],examples:[e("sootsim close"),e("sootsim close a6"),e("sootsim close --all"),e("sootsim close --others")],related:["list","use"]},{id:"setup",slug:"setup",navTitle:"setup",title:"sootsim setup",description:"bootstrap SootSim, then install the global CLI",summary:"Run the guided machine setup. It asks which package manager you use for app commands, explains repo-pinned Node versions, recommends installing `sootsim` globally, and offers the background daemon so every CLI command can reuse the same bridge instead of spinning up a server. No per-app SootSim install or iOS native build is required; run Metro/Expo/One normally, then open it with `sootsim open`.",order:140,usage:["sootsim setup [options]"],options:[t("--app <dir>","project directory to inspect (default: current directory)"),t("-y, --yes","accept the recommended setup steps without prompting"),t("--dry-run","show what setup would offer without changing files")],examples:[e("sootsim setup"),e("sootsim setup --app ./apps/mobile"),e("sootsim setup --dry-run"),e("sootsim setup --yes")],related:["open","daemon","serve","compat"]},{id:"compat",slug:"compat",navTitle:"compat",title:"sootsim compat",description:"check package compatibility",summary:"Scan a project or specific dependency against the compat registry and summarize where native packages are fully supported, partially shimmed, or still risky.",order:150,usage:["sootsim compat [package-name]"],options:[t("--json","emit machine-readable JSON"),t("--brief","print a compact one-line summary"),t("--app <dir>","scan a target app directory instead of cwd")],examples:[e("sootsim compat"),e("sootsim compat react-native-reanimated"),e("sootsim compat --brief")],related:["setup"]},{id:"desktop",slug:"desktop",navTitle:"desktop",title:"sootsim desktop",description:"launch or install the desktop companion",summary:"Launch the optional desktop companion from the global CLI, or install it when missing. Profiles map to Electron partitions, so cookies and app storage stay isolated per profile.",order:160,usage:["sootsim desktop [--port <number>] [--profile <id>] [--driver <id>]","sootsim desktop install [options]"],options:[t("--port <number>","open a local app server through the sootsim shell, for example Metro on 8081"),t("--profile <id>","launch with an isolated persistent storage profile"),t("--ephemeral","launch with a temporary isolated storage profile"),t("--driver <id>","override the launch driver (electron|chromium|playwright|system)"),t("-y, --yes","for install: skip confirmation and install immediately"),t("--force","for install: reinstall even if the companion is present")],examples:[e("sootsim desktop"),e("sootsim desktop --port 8081"),e("sootsim desktop --profile qa"),e("sootsim desktop --driver system","fall back to the OS default browser"),e("sootsim desktop install --yes")],related:["open","list","debug"]},{id:"daemon",slug:"daemon",navTitle:"daemon",title:"sootsim daemon",description:"manage the sootsim bridge as a login agent",summary:"`sootsim setup` installs the background daemon. This command inspects, restarts, starts, stops, tails logs for, or uninstalls that existing login agent. `sootsim daemon uninstall` is the clean-teardown path \u2014 it stops + removes the launchd/systemd agent AND deletes the ~/.sootsim cache (runtimes, profiles, lockfile).",order:173,usage:["sootsim daemon uninstall","sootsim daemon status","sootsim daemon restart","sootsim daemon start","sootsim daemon stop","sootsim daemon logs [-n <lines>] [-f]"],options:[t("-n, --lines <n>","number of log lines to show (default 200)"),t("-f, --follow","stream new log lines as they arrive")],examples:[e("sootsim daemon status","is the bridge daemon registered + alive?"),e("sootsim daemon restart","kick the daemon (after a CLI upgrade, etc.)"),e("sootsim daemon logs -n 100","tail the last 100 daemon log lines"),e("sootsim daemon uninstall","clean teardown \u2014 remove the launchd/systemd agent + ~/.sootsim cache")],related:["setup","serve","open"]},{id:"serve",slug:"serve",navTitle:"serve",title:"sootsim serve",description:"run the sootsim bridge in the foreground",summary:"Host the WS bridge in the foreground. This is mainly for development or diagnosis; the recommended path is `sootsim open`, which starts a local bridge when needed, and `sootsim setup`, which installs the faster background daemon.",order:175,usage:["sootsim serve [options]"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("-q, --quiet","suppress per-connection logging")],examples:[e("sootsim serve"),e("sootsim serve --quiet"),e("sootsim serve --port 7668")],related:["setup","daemon","open"]},{id:"runtime",slug:"runtime",navTitle:"runtime",title:"sootsim runtime",description:"manage engine runtimes under ~/.sootsim/runtimes/",summary:"Install, list, switch, and remove versioned sootsim engine runtimes. The CLI downloads a tarball from the configured CDN (default sootbean.com \u2014 override with `SOOTSIM_CDN_ORIGIN`), verifies its sha256, and extracts it. The daemon serves the active runtime to Electron and the browser shell. `sootsim runtime notes` prints the hosted changelog URL.",order:176,usage:["sootsim runtime install [version]","sootsim runtime list","sootsim runtime use <version>","sootsim runtime remove <version>","sootsim runtime which","sootsim runtime notes"],options:[t("--channel <name>","channel for 'latest' (default: stable)"),t("--force","reinstall even if already on disk"),t("--no-set-active","don't switch active runtime after install (also accepts --set-active=false)")],examples:[e("sootsim runtime install"),e("sootsim runtime install 1.2.3"),e("sootsim runtime install --channel beta","install the latest from a non-stable channel"),e("sootsim runtime use 1.2.3"),e("sootsim runtime list","show installed + available versions"),e("sootsim runtime which","print the currently active runtime version"),e("sootsim runtime notes","print the hosted release notes URL"),e("sootsim runtime remove 1.2.2")],related:["setup","serve","daemon","version"]},{id:"upgrade",slug:"upgrade",navTitle:"upgrade",title:"sootsim upgrade",description:"update the sootsim CLI and engine runtime to the latest",summary:'One command to get current. Checks the npm registry for a newer `sootsim` CLI and, when the CLI half is behind, tells you to run `sootsim@latest`. It then checks the runtime channel and installs + activates the latest engine runtime. Safe to run anytime \u2014 each half is skipped when already up to date. The CLI and engine runtime are versioned independently, which is a frequent source of "I ran upgrade but the version did not change" confusion \u2014 this command checks both.',order:174,usage:["sootsim upgrade [--channel <name>]"],options:[t("--channel <name>","runtime channel for 'latest' (default: stable)")],examples:[e("sootsim upgrade"),e("sootsim upgrade --channel beta","install the latest engine runtime from the beta channel")],related:["runtime","setup","version"]},{id:"version",slug:"version",navTitle:"version",title:"sootsim version",description:"show the CLI + engine runtime versions you are running",summary:'A one-look overview of both independently-versioned halves: the `sootsim` CLI (npm package) and the engine runtime (the versioned tarball rendered in the browser/electron shell). Adds the active channel, a "newer runtime available" hint, and a what\'s-new pointer to `sootsim runtime notes`. The terse `sootsim --version` flag prints the two version lines for scripts; this command adds the surrounding context.',order:173,usage:["sootsim version"],options:[],examples:[e("sootsim version"),e("sootsim --version","terse, script-parseable")],related:["upgrade","runtime"]},{id:"maestro",slug:"maestro",navTitle:"maestro",title:"sootsim maestro",description:"run existing Maestro YAML flows against sootsim",summary:"Drop-in replacement for the Maestro CLI. Runs real `.maestro/*.yaml` flows against a sim \u2014 supports all three Maestro shapes (plain array, frontmatter, multi-doc). Flag surface mirrors the Maestro CLI for easy migration.",order:41,usage:["sootsim maestro [test] <flow-or-dir> [options]","sootsim maestro # auto-discovers ./.maestro/","sootsim maestro init # scaffold a starter flow","sootsim maestro --list-compat"],options:[t("--env KEY=VALUE","set env vars for ${KEY} interpolation (repeatable)"),t("--continuous","re-run the flow on file changes (alias for --watch)"),t("--format <fmt>","accepted for maestro cli compat (not used)"),t("--new","force a fresh sim for this run"),t("--headed","force a fresh, VISIBLE window (implies --new, overrides --headless) \u2014 watch the flow run live"),t("--record","record a webm while the flow runs"),t("--preview","record events+video, upload, and print /preview/<id>"),t("--preview-open","open the uploaded preview link after a successful run"),t("--preview-origin <url>","upload target for --preview"),t("--preview-public-origin <url>","public link origin for --preview"),t("--slow <ms>","delay between steps for natural pacing"),t("--list-compat","print supported and unsupported Maestro verbs")],examples:[e("sootsim maestro test .maestro/login.yaml"),e("sootsim maestro --env USERNAME=alice test .maestro/login.yaml"),e("sootsim maestro test .maestro/flow.yaml --record"),e("sootsim maestro --list-compat")],related:["flow","detox","test","record"]},{id:"detox",slug:"detox",navTitle:"detox",title:"sootsim detox",description:"run existing Detox suites against sootsim on headless Chromium",summary:"Drop-in Detox runner. Existing `import from 'detox'` suites run unchanged via a Jest `moduleNameMapper` rewrite \u2014 no code edits, no config churn. Auto-launches a sootsim shell if none is running.",order:42,usage:["sootsim detox [options] [-- <jest args>]"],options:[t("--config <path>","use a specific jest config instead of the default"),t("--watch","jest watch mode"),t("--headed","keep the sootsim shell window visible"),t("-t <pattern>","pass a Jest --testNamePattern"),t("--no-launch","skip auto-launching a sootsim shell (manage it yourself)")],examples:[e("sootsim detox"),e("sootsim detox --watch"),e('sootsim detox -t "login flow"'),e("sootsim detox --headed","keep the shell visible while iterating on a failing suite")],related:["maestro","flow","test"]},{id:"device",slug:"device",navTitle:"device",title:"sootsim device",description:"inspect or change the live device preset for a sim",summary:"Read the current device preset, switch it on the fly, or list the available models. Switching a preset reshapes the running sim \u2014 screen size, density, and chrome \u2014 without restarting the bundle.",order:78,usage:["sootsim device","sootsim device get","sootsim device set <model> [--sim <id>]","sootsim device list"],options:[t("--sim <sim>","target a specific connected sim when setting"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim device","show the active device preset"),e("sootsim device list","list every available model id"),e("sootsim device set iphone-14"),e("sootsim device set iphone-16-pro-max --sim a7")],related:["mode","screenshot","open","list"]},{id:"skill",slug:"skill",navTitle:"skill",title:"sootsim skill",description:"install and inspect bundled SootSim agent skills",summary:"Install bundled SootSim agent skills into agent-compatible skill directories, or print the bundled skill markdown. `install` defaults to all supported local agent homes; pass `codex` or `claude` to target one.",order:122,usage:["sootsim skill install [all|codex|claude] [skill-name...]","sootsim skill install --target <dir> [skill-name...]","sootsim skill show [skill-name]"],options:[t("install","install skills; no target means all supported local agents"),t("show","list bundled skills, or print one skill markdown"),t("--target <dir>","install into an explicit skill directory")],examples:[e("sootsim skill install"),e("sootsim skill install codex"),e("sootsim skill install codex sootsim-debug"),e("sootsim skill show"),e("sootsim skill show sootsim-debug")],related:["inspect","debug"]},{id:"agent",slug:"agent",navTitle:"agent",title:"sootsim agent",description:"attached projects + local agent sessions (codex/claude)",summary:"Manage attached project directories and the agent sessions running inside them. Session-lifecycle commands (start, prompt, watch, end) route through the bridge daemon, which owns the single FIFO reader per session so concurrent cli watches + electron UI subscribers no longer steal bytes from each other. Disk-only inspection commands (projects, sessions, paths, transcript) read attached-project state directly \u2014 no daemon needed.",order:125,usage:["sootsim agent attach <dir> [--name <label>] [--provider codex|claude]","sootsim agent projects","sootsim agent project show <id>","sootsim agent project remove <id>","sootsim agent sessions [--project <id>] [--all]","sootsim agent start <projectId> [--provider codex|claude]",'sootsim agent prompt <sessionId> "<text>"',"sootsim agent watch <sessionId>","sootsim agent transcript <sessionId>","sootsim agent end <sessionId>","sootsim agent paths"],options:[t("--name <label>","human-readable label when attaching a project"),t("--provider <id>","agent backend: codex (default) or claude \u2014 used by attach + start"),t("--project <id>","filter sessions to a specific attached project"),t("--all","include ended sessions (sessions defaults to active only)")],examples:[e("sootsim agent attach ~/projects/three-punch --name 3pc"),e("sootsim agent projects","list every attached project"),e("sootsim agent project show 3pc"),e("sootsim agent start 3pc --provider claude","spawn a wrapper session (detached) inside the attached project"),e('sootsim agent prompt <sessionId> "fix the failing scroll test"',"enqueue a prompt \u2014 the daemon delivers it to the wrapper"),e("sootsim agent watch <sessionId>","tail events.out pretty-printed"),e("sootsim agent sessions --all","include ended sessions in the list"),e("sootsim agent transcript <sessionId>"),e("sootsim agent end <sessionId>"),e("sootsim agent paths","print userData + state file locations")],related:["skill","auth","login"]},{id:"auth",slug:"auth",navTitle:"auth",title:"sootsim auth",description:"inspect active CLI auth",summary:"Print the auth source the CLI will use. API keys are not managed by the CLI; pass them via SOOTSIM_API_KEY when CI or a headless script needs one. Use `sootsim login` and `sootsim logout` for the browser-backed desktop session.",order:190,usage:["sootsim auth"],options:[t("SOOTSIM_API_KEY","env var for API-key auth; no local key file is read")],examples:[e("sootsim auth","show the active auth source")],related:["login","logout","record","flow"]},{id:"login",slug:"login",navTitle:"login",title:"sootsim login",description:"sign in for preview uploads",summary:"Sign in with the browser-backed desktop session so uploads and App Store screenshot capture can attach to your account. Local development origins use the dev-login fast path; CI should pass SOOTSIM_API_KEY instead.",order:191,usage:["sootsim login [--origin <url>]"],options:[t("--origin <url>","auth host (default: auto; prefers localhost:3000 when available)")],examples:[e("sootsim login"),e("sootsim login --origin http://localhost:3000")],related:["auth","logout","record","flow"]},{id:"logout",slug:"logout",navTitle:"logout",title:"sootsim logout",description:"clear the local desktop auth session",summary:"Clear the browser-backed desktop session written by `sootsim login`. SOOTSIM_API_KEY and GitHub runner auth are environment-provided and are not affected.",order:192,usage:["sootsim logout"],examples:[e("sootsim logout")],related:["auth","login"]},{id:"config",slug:"config",navTitle:"config",title:"sootsim config",description:"manage local CLI preferences",summary:"Manage local preferences that affect the CLI and desktop companion. Telemetry is persisted in ~/.sootsim/config.json. CLI hints are intentionally not a command surface; set SOOTSIM_HINTS=off to suppress them.",order:195,usage:["sootsim config telemetry [on|off|status]"],examples:[e("sootsim config telemetry","show the current opt-out state and config path"),e("sootsim config telemetry off","disable CLI + desktop analytics on this machine"),e("SOOTSIM_HINTS=off sootsim describe","suppress hints for a single run")],related:["auth"]}],ae=new Map(D.map(o=>[o.id,o])),L=new Map;for(let o of D){L.set(o.id,o);for(let s of o.aliases||[])L.set(s,o)}function j(o){return L.get(o)}function i(o,s,a,l,r,n){return{verb:o,description:s,usage:a,examples:l,notes:r,...n}}var R=[i("describe","show visible UI elements with type, text, position, size, and style. filters structural noise by default \u2014 use --all to include everything.",["sootsim describe [filter] [--verbose] [--watch] [--all] [--json] [--no-clipped] [--compact] [--no-xy] [--only <glob>] [--subtree <id>] [--testid-like <pat>]"],[e("sootsim describe"),e("sootsim describe button"),e("sootsim describe --verbose"),e("sootsim describe --all"),e("sootsim describe --json"),e("sootsim describe --watch"),e("sootsim describe --no-clipped","hide rows annotated (clipped:left|right|top|bottom) \u2014 useful on screens dominated by edge-pulled chrome or off-screen list items"),e("sootsim describe --compact --no-xy","tighter tree without coords"),e("sootsim describe --subtree feedListRoot","limit the dump to a subtree rooted at testID feedListRoot"),e('sootsim describe --only "*Header*"',"glob-match across text/role/testID"),e("sootsim describe --testid-like login",'fuzzy-match nodes whose testID contains "login"')],"buttons show [button], tappable views show [tap], inputs show [input]. structural noise (icon wrappers, layout containers, duplicate text inside buttons) is pruned by default. use --all for the unfiltered view.",{shortDescription:"curated human-readable UI summary (default inspection tool)",options:[t("--verbose","include ids, labels, and extra style info"),t("--all","do not prune structural view nodes"),t("--watch","redraw as the UI changes (ctrl-c to stop)"),t("--json","emit structured JSON"),t("--no-clipped","strip rows annotated (clipped:left|right|top|bottom) \u2014 keeps the on-screen state from being buried"),t("--compact","render the tree in a tighter format"),t("--no-xy","hide x,y coordinates from each row"),t("--only <glob>","glob filter across text/role/testID \u2014 preferred when the bare positional would be ambiguous"),t("--subtree <id>","limit the dump to a subtree rooted at the given testID"),t("--testid-like <pattern>","fuzzy-match nodes whose testID contains the pattern (substring + case-insensitive)")],seeAlso:["tree","a11y","find"]}),i("find","unified finder (text, testid, role, type, pressable, visible, interactive-targets)",["sootsim find <text>","sootsim find --text <text>","sootsim find --testid <id>","sootsim find --role <role>","sootsim find --type <component-type>","sootsim find --pressable","sootsim find --visible","sootsim find --interactive-targets"],[e('sootsim find "Sign in"'),e("sootsim find --testid loginButton"),e("sootsim find --role button"),e("sootsim find --pressable"),e("sootsim find --visible --json"),e("sootsim find --testid loginButton --verbose"),e("sootsim find --interactive-targets","ranked list of visible+pressable nodes with copy-paste tap commands"),e("sootsim find --actions","alias for --interactive-targets")],"bare text matches findByText. flag-based forms replace the old `find-id` and `query <predicate>` subcommands. use --verbose to dump the full node JSON for each result instead of the one-liner summary. `--interactive-targets` (alias `--actions`) ranks visible+pressable nodes and emits a `sootsim do tap-...` command per row so the agent's next tap is one copy away.",{shortDescription:"locate nodes by text / testID / role / type / predicate",options:[t("--text <text>","match node text content (same as bare positional)"),t("--testid <id>","match node testID or id exactly"),t("--role <role>","match accessibilityRole"),t("--type <type>","match React component type"),t("--pressable","list all tappable nodes"),t("--visible","list all visible (non-zero) nodes"),t("--interactive-targets, --actions",'ranked tappable nodes with per-row tap command (best demo "next tap" picker)'),t("--verbose, --dump","emit full node JSON for each result, not a one-liner"),t("--json","emit structured JSON")],seeAlso:["describe","node","selector"]}),i("count","show total node count",["sootsim get count [--json]"],[e("sootsim get count"),e("sootsim get count --json")],void 0,{group:"get",subgroup:"tree",shortDescription:"total node count",options:[t("--json","emit { nodes: n } for scripts")]}),i("layout","measure layout \u2014 bare for every visible element on the screen (box + radius/padding/fontSize), or with an id for one node",["sootsim get layout [id] [--json]"],[e("sootsim get layout","every visible element: on-screen box (x/y/w/h) + borderRadius, per-side padding, fontSize"),e("sootsim get layout --json","machine-readable { count, elements }"),e("sootsim get layout loginButton","single node {x, y, width, height} by id/testID")],"bare `get layout` is the screen-wide measurement designers reach for to check spacing/sizing/radius/type-scale parity \u2014 more detailed than describe, which gives the element tree but not these numbers. it runs the same shared extractor as the agent app_get_layout tool, so CLI and agent output match. pass an id for the single-node layout lookup.",{group:"get",subgroup:"tree",shortDescription:"screen-wide box + radius/padding/fontSize (or one node by id)",options:[t("--json","emit { count, elements } for scripts")],seeAlso:["describe","find","node"]}),i("tree","dump the node tree",["sootsim get tree [depth] [--json]"],[e("sootsim get tree"),e("sootsim get tree 3"),e("sootsim get tree --json")],"raw, depth-limited tree dump. good for machine consumption and debugging when describe has filtered something out. for day-to-day inspection prefer describe.",{group:"get",subgroup:"tree",shortDescription:"raw node tree dump (default depth 5)",options:[t("--json","emit { depth, tree } for scripts")],seeAlso:["describe","a11y","node"]}),i("a11y","dump the accessibility tree with roles and labels",["sootsim get a11y [depth]"],[e("sootsim get a11y")],"only accessibility-relevant fields (role, label, hint). for general inspection use describe; for raw tree use get tree.",{group:"get",subgroup:"tree",shortDescription:"accessibility tree (roles, labels, hints)",seeAlso:["describe","tree"]}),i("node","resolve testID/id/text to a full node JSON",["sootsim get node <matcher>"],[e("sootsim get node loginButton"),e('sootsim get node "Sign in"')],void 0,{group:"get",subgroup:"tree",shortDescription:"resolve testID \u2192 id \u2192 text, full node JSON",seeAlso:["find","layout"]}),i("tap","tap at absolute coordinates, or resolve --testid / --text to a node center",["sootsim do tap <x> <y>","sootsim do tap --testid <id>","sootsim do tap --text <text>"],[e("sootsim do tap 196 400"),e("sootsim do tap --testid loginButton"),e('sootsim do tap --text "Sign in"')],"uses the internal interaction bridge (fireTap), not real PointerEvent dispatch. for gesture-handler debugging, use drag/swipe which dispatch real pointer events. --testid and --text also work on double-tap and long-press.",{group:"do",subgroup:"targeting",shortDescription:"tap absolute coords, or a node by --testid / --text",seeAlso:["tap-id","tap-text","double-tap","long-press"],order:10}),i("double-tap","tap the same spot twice with a short gap",["sootsim do double-tap <x> <y> [gapMs]","sootsim do double-tap --testid <id> [gapMs]"],[e("sootsim do double-tap 196 400"),e("sootsim do double-tap --testid myButton 80")],"uses the shared interact bridge so text selection and other double-tap gestures run through the same path as live taps.",{group:"do",subgroup:"targeting",shortDescription:"tap the same coordinates twice quickly",seeAlso:["tap"],order:20}),i("tap-text","find a node by text content and tap its center",["sootsim do tap-text <text> [--nth <n>] [--within <testID>]"," [--min-y <px>] [--max-y <px>] [--min-x <px>] [--max-x <px>]"," [--near <x> <y>] [--exact] [--role <role>] [--first]"],[e('sootsim do tap-text "Sign in"'),e("sootsim do tap-text Swap --within sheet-container"),e("sootsim do tap-text Swap --min-y 700"),e("sootsim do tap-text Cancel --nth 2"),e("sootsim do tap-text OK --near 283 784")],"errors with a ranked candidate list (testID + abs position + ancestor chain) when more than one visible match remains after filters, instead of silently picking one. pass --first to keep the old behavior.",{group:"do",subgroup:"targeting",shortDescription:"findByText then tap (rich disambiguation flags)",options:[t("--nth <n>","pick the nth visible match (supports -1)"),t("--within <testID>","descendants of a testID ancestor only"),t("--min-y <px>","absolute y-position floor"),t("--max-y <px>","absolute y-position ceiling"),t("--min-x <px>","absolute x-position floor"),t("--max-x <px>","absolute x-position ceiling"),t("--near <x> <y>","pick the closest match to a coordinate"),t("--exact","exact text match (default: substring)"),t("--role <role>","narrow to accessibilityRole"),t("--first","keep legacy pick-first-silently behavior")],seeAlso:["tap","tap-id","find"],order:30}),i("tap-id","find a node by testID and tap its center",["sootsim do tap-id <id>"],[e("sootsim do tap-id loginButton")],void 0,{group:"do",subgroup:"targeting",shortDescription:"findByTestId then tap center",seeAlso:["tap","tap-text","tap-best"],order:40}),i("tap-best","tap by query: try testID first, then visible text \u2014 one command, two strategies",["sootsim do tap-best <query>"],[e('sootsim do tap-best "Create expense"',`agent doesn't need to know whether "Create expense" is a testID or text`),e("sootsim do tap-best floating-action-button")],"designed for agent ergonomics: when you have a label and don't know whether it's the testID or the visible text, tap-best tries findByTestId first (strongest signal), then findByText. prints which strategy matched. for ambiguity (multiple text matches) use tap-text with --nth / --within instead \u2014 tap-best fails fast and points you there.",{group:"do",subgroup:"targeting",shortDescription:"testID-first, text-fallback robust tap",seeAlso:["tap-id","tap-text","find"],order:41}),i("scan","inject a synthetic barcode scan into the active expo-camera scan session",["sootsim do scan <text> [--format <web-format>]"],[e('sootsim do scan "https://example.com/pair/abc123"'),e('sootsim do scan "myapp://connect?token=abc" --format qr_code',"drive a connect-by-QR flow")],"fails when no guest CameraView is actively scanning. the event flows through the same host \u2192 worker \u2192 native seam path as a real BarcodeDetector hit.",{group:"do",subgroup:"native device",shortDescription:"inject a barcode scan into active camera scanning",options:[t("--format <f>","BarcodeDetector format string (default: qr_code)")],seeAlso:["tap","wait"],order:10}),i("type","type text through the iOS keyboard (requires a focused input)",["sootsim do type <text>"],[e('sootsim do type "hello world"')],"a text input must be focused first via tap-id or tap-text. if no input is focused, this silently does nothing.",{group:"do",subgroup:"text input",shortDescription:"type through the iOS visual keyboard",seeAlso:["type-into","key","dismiss"],order:10}),i("type-into","find an input by testID, tap to focus, then type text",["sootsim do type-into <id> <text>"],[e('sootsim do type-into kav-input "hello world"')],"combines tap-id + type in one command. warns if the target is not a text input or if the keyboard did not open.",{group:"do",subgroup:"text input",shortDescription:"focus input by testID then type",seeAlso:["type","tap-id"],order:20}),i("key","press a special keyboard key",["sootsim do key <name>"],[e("sootsim do key return"),e("sootsim do key delete")],"valid keys: return, delete, space, shift, 123, ABC, #+=, num-back",{group:"do",subgroup:"text input",shortDescription:"special key (return, delete, space, shift, ...)",seeAlso:["key-sequence","keycode"],order:30}),i("key-sequence","press multiple visual keyboard keys in order",["sootsim do key-sequence <key> [<key> ...]"],[e("sootsim do key-sequence shift h i")],void 0,{group:"do",subgroup:"text input",shortDescription:"press multiple visual keyboard keys",seeAlso:["key","keycode"],order:40}),i("keycode","press DOM-style key codes through the visual keyboard",["sootsim do keycode <code> [<code> ...]"],[e("sootsim do keycode ShiftLeft KeyH KeyI")],void 0,{group:"do",subgroup:"text input",shortDescription:"press DOM-style key codes via visual keyboard",seeAlso:["key","key-sequence"],order:50}),i("dismiss","dismiss the keyboard",["sootsim do dismiss"],void 0,void 0,{group:"do",subgroup:"text input",shortDescription:"dismiss the iOS keyboard",order:60}),i("scroll","scroll a scrollview by testID or inspect node id",["sootsim do scroll <id> <x> <y>","sootsim do scroll --testid <id> <x> <y>","sootsim do scroll --node-id <nodeId> <x> <y>"],[e("sootsim do scroll feed-list 0 500"),e("sootsim do scroll --testid feed-list 0 500"),e("sootsim do scroll --node-id 3027 0 1200")],void 0,{group:"do",subgroup:"gestures",shortDescription:"scroll a ScrollView by testID or inspect node id",seeAlso:["gesture","swipe"],order:10}),i("drag","drag from one point to another using real PointerEvent dispatch",["sootsim do drag <x1> <y1> <x2> <y2> [steps] [stepMs]"],[e("sootsim do drag 200 400 200 200 20 16")],"dispatches real PointerEvents to the canvas, unlike tap which uses the internal bridge. use this for gesture-handler and responder chain debugging.",{group:"do",subgroup:"gestures",shortDescription:"drag via real PointerEvents",seeAlso:["swipe","touch","pinch"],order:20}),i("swipe","swipe gesture (drag with fewer steps)",["sootsim do swipe <x1> <y1> <x2> <y2> [steps] [stepMs]"],[e("sootsim do swipe 350 400 50 400 10 16")],void 0,{group:"do",subgroup:"gestures",shortDescription:"drag with faster defaults",seeAlso:["drag","gesture"],order:30}),i("long-press","hold a press at coordinates",["sootsim do long-press <x> <y> [durationMs]","sootsim do long-press --testid <id> [durationMs]"],[e("sootsim do long-press 196 400 600"),e("sootsim do long-press --testid myButton 600")],void 0,{group:"do",subgroup:"gestures",shortDescription:"hold a press at coordinates",seeAlso:["tap","gesture"],order:40}),i("touch","low-level touch primitives",["sootsim do touch <down|move|up|cancel> <x> <y> [pointerId]"],[e("sootsim do touch down 200 720 1"),e("sootsim do touch up 200 720 1")],void 0,{group:"do",subgroup:"gestures",shortDescription:"low-level touch primitives",seeAlso:["drag","pinch"],order:50}),i("gesture","preset gestures such as scrolls and edge swipes",["sootsim do gesture <preset> [durationMs]"],[e("sootsim do gesture swipe-from-bottom-edge"),e("sootsim do gesture scroll-up 250")],void 0,{group:"do",subgroup:"gestures",shortDescription:"preset gestures (scroll / edge swipes)",seeAlso:["swipe","scroll"],order:60}),i("pinch","two-pointer pinch helper",["sootsim do pinch <x1> <y1> <x2> <y2> <x1'> <y1'> <x2'> <y2'> [steps] [stepMs]"],[e("sootsim do pinch 120 320 280 320 90 320 310 320")],void 0,{group:"do",subgroup:"gestures",shortDescription:"two-pointer pinch helper",seeAlso:["touch","gesture"],order:70}),i("state","dump raw runtime state (shell, worker, keyboard, node, scroll, hit, gesture, ownership)",["sootsim debug state <kind> [args]","sootsim debug state shell","sootsim debug state keyboard","sootsim debug state node <id>","sootsim debug state hit <x> <y>","sootsim debug state gesture <x> <y>","sootsim debug state ownership"],[e("sootsim debug state shell"),e("sootsim debug state keyboard"),e("sootsim debug state node photos"),e("sootsim debug state hit 200 720"),e("sootsim debug state ownership",'authoritative surface-ownership + pointer-delivery snapshot \u2014 diagnose "which surface owns this region"')],void 0,{group:"debug",subgroup:"state",shortDescription:"runtime dumps (shell, worker, keyboard, hit, gesture, ownership, ...)",seeAlso:["js"]}),i("js","evaluate javascript in the browser context",["sootsim debug js <expression>"],[e("sootsim debug js SootSim.bridges.test.getNodeCount()"),e("sootsim debug js SootSim.bridges.keyboard.isVisible()"),e("sootsim debug js SootSim.state.root.children.length")],"reach into the SootSim global: bridges (test, debug, interact, keyboard, a11y, perf, ...), state (root, simId, ...), chrome (shell, headless, engineBase, ...).",{group:"debug",subgroup:"eval",shortDescription:"evaluate JS in the engine realm (reach into SootSim.*)",seeAlso:["eval","state"]}),i("eval","evaluate javascript (same as js)",["sootsim debug eval <expression>"],[e('sootsim debug eval "document.title"')],void 0,{group:"debug",subgroup:"eval",shortDescription:"alias for js",seeAlso:["js"]}),i("errors","show recent console errors",["sootsim get errors [n|clear] [--json]"],[e("sootsim get errors 5"),e("sootsim get errors clear"),e("sootsim get errors --json | jq length")],void 0,{group:"get",subgroup:"diagnostics",shortDescription:"console errors (default 20)",options:[t("--json","emit array of { timestamp, args, stack } for scripts")],seeAlso:["warnings","requests","logs"]}),i("warnings","show recent console warnings",["sootsim get warnings [n] [--json]"],[e("sootsim get warnings 5"),e("sootsim get warnings --json")],void 0,{group:"get",subgroup:"diagnostics",shortDescription:"console warnings (default 20)",options:[t("--json","emit array of { timestamp, args } for scripts")],seeAlso:["errors","logs"]}),i("requests","show recent failed network requests",["sootsim get requests [n|all n|clear] [--json]"],[e("sootsim get requests 5"),e("sootsim get requests all 10"),e("sootsim get requests --json")],void 0,{group:"get",subgroup:"diagnostics",shortDescription:"failed / all / clear request buffer",options:[t("--json","emit array of request entries for scripts")],seeAlso:["errors","network"]}),i("diagnosis",'composed "what just went wrong?" report',["sootsim get diagnosis [--since <duration>] [--include <csv>] [--json]"],[e("sootsim get diagnosis","last 90s, all dimensions"),e("sootsim get diagnosis --since 30s --include network,react"),e("sootsim get diagnosis --json > /tmp/diagnosis.json","structured snapshot for agent / CI consumption")],"runs timeline + network (failed/slow) + react summary + console errors in parallel against the same sim and returns a grouped report.",{group:"get",subgroup:"diagnostics",shortDescription:"timeline + network + react + console summary",options:[t("--since <duration>","absolute window, e.g. 90s or 2m (default 90s)"),t("--include <csv>","timeline, network, react, console, screen"),t("--slow-threshold <n>","network slow-request threshold in ms"),t("--limit <n>","rows to print per react table"),t("--json","emit one structured JSON document")],seeAlso:["errors","warnings","requests","network"]}),i("animations","list every active animation with id, kind, progress, and current value",["sootsim get animations","sootsim get animations --json"],[e("sootsim get animations","one line per running animation"),e("sootsim get animations --json | jq","structured for scripts")],'answers "what is moving right now?" without resorting to screenshots or debug eval. pair with `sootsim get animation <id>` for full spec, `sootsim do stop-animation <id>` to halt one, or `sootsim debug trace anim on <id>` for per-tick values.',{group:"get",subgroup:"animations",shortDescription:"list active animations",seeAlso:["animation","stop-animation","state"]}),i("animation","full detail for a single active animation by id",["sootsim get animation <id>"],[e("sootsim get animation 3","JSON spec + current value + progress")],"ids come from `sootsim get animations`. poll this to watch a single animation settle without enabling a trace.",{group:"get",subgroup:"animations",shortDescription:"single animation detail",seeAlso:["animations","stop-animation"]}),i("state","runtime dashboard: url, active animation counts, diagnostics, shell scene",["sootsim get state"],[e("sootsim get state","what is this sim doing right now")],'one-shot JSON snapshot answering "what is happening in this sim right now" \u2014 intended as the first call of a debugging pass. separate from `sootsim debug state <kind>`, which dumps raw runtime state for one subsystem.',{group:"get",subgroup:"diagnostics",shortDescription:"runtime dashboard snapshot",seeAlso:["animations","errors","keyboard"]}),i("memory","per-worker live object counts (nodes, paragraphs, yoga nodes, pictures, raster images) + image cache + JS heaps; --watch samples over time and reports per-counter slopes",["sootsim get memory","sootsim debug memory --watch [seconds] [--interval seconds]"],[e("sootsim get memory","one-shot tenant + shell + host snapshot"),e("sootsim debug memory --watch 120","sample every 5s for 2 min, then print which counters are climbing"),e("sootsim debug memory --watch 60 --interval 2 --json | jq .perSecond","machine-readable slopes for scripting")],"the memory-leak RCA instrument. counters are maintained at engine create/delete sites, so resources retained by discarded (unmounted) subtrees still show up \u2014 a climbing nodesRegistered/paragraphs while the on-screen tree is stable means unmounted nodes are being retained. tenant and shell workers report independently (the shell paints the app:* mirror trees). heaps are chrome-only (webkit omits performance.memory).",{group:"debug",subgroup:"profiling",shortDescription:"live object counts + heap sampler",options:[t("--watch [seconds]","sample repeatedly for N seconds (default 60)"),t("--interval <seconds>","seconds between samples (default 5)"),t("--json","one-shot report, or { samples, perSecond } under --watch")],seeAlso:["state","perf"]}),i("stop-animation","stop a running animation by id, or stop all active animations",["sootsim do stop-animation <id|all>"],[e("sootsim do stop-animation 3"),e("sootsim do stop-animation all","freeze everything for inspection")],"the id comes from `sootsim get animations`. stopping fires the animation's finished callback with finished=false, matching react-native Animated.stop() semantics.",{group:"do",subgroup:"animations",shortDescription:"stop a running animation",seeAlso:["animations","animation"]}),i("trace","opt-in trace recorders: shell animation frames or per-tick animation values",["sootsim debug trace shell [on [limit]|off|status|clear|<recentLimit>]","sootsim debug trace anim <on <id|all> [limit]|off [id|all]|status|clear|<id> [limit]>"],[e("sootsim debug trace shell on 240","arm the shell frame recorder"),e("sootsim debug trace shell 120","dump the last 120 shell samples"),e("sootsim debug trace anim on 3 240","record up to 240 ticks for anim #3"),e("sootsim debug trace anim 3 60","read last 60 ticks for anim #3"),e("sootsim debug trace anim on all","record every active animation")],"for a focused perf trace: `get animations` to find the id, `trace anim on <id>` to arm, reproduce the issue, then `trace anim <id>` to pull per-tick value + velocity samples. `trace anim off` disables when done.",{group:"debug",subgroup:"profiling",shortDescription:"per-tick animation + shell frame trace",seeAlso:["animations","animation","stop-animation"]}),i("snapshot","capture a tree snapshot (layout + transform + opacity) for later diffing",["sootsim debug snapshot [label]"],[e("sootsim debug snapshot before","capture state before an interaction"),e("sootsim debug snapshot after","capture state after an interaction"),e("sootsim debug snapshot","unlabeled \u2014 auto-named based on current time")],"snapshots live in-memory in the engine for the life of the page. use `snapshots` to list labels and `diff <a> <b>` to compare two. clear with `clear-snapshots [label]`.",{group:"debug",subgroup:"snapshot",shortDescription:"capture tree snapshot for later diff",seeAlso:["snapshots","diff","state"]}),i("snapshots","list the labels of every captured tree snapshot",["sootsim debug snapshots"],[e("sootsim debug snapshots","list every label, with capture time")],void 0,{group:"debug",subgroup:"snapshot",shortDescription:"list captured snapshot labels",seeAlso:["snapshot","diff"]}),i("diff","compare two captured snapshots \u2014 added / removed / changed nodes",["sootsim debug diff <labelA> <labelB>"],[e("sootsim debug diff before after","diff a paired snapshot \u2014 added/removed/changed counts + per-node detail")],"project both snapshots with `snapshot <label>` first, then diff. emits counts plus added / removed / changed arrays; pipe through jq for filtering.",{group:"debug",subgroup:"snapshot",shortDescription:"compare two snapshots",seeAlso:["snapshot","snapshots","clear-snapshots"]}),i("clear-snapshots","drop a labeled snapshot (or all snapshots if no label is given)",["sootsim debug clear-snapshots [label]"],[e("sootsim debug clear-snapshots before","drop just the `before` snapshot"),e("sootsim debug clear-snapshots","drop every captured snapshot")],void 0,{group:"debug",subgroup:"snapshot",shortDescription:"discard captured snapshots",seeAlso:["snapshot","snapshots","diff"]}),i("find","dump engine-internal nodes by category (e.g. all Sheet.Frame portals)",["sootsim debug find sheets","sootsim debug find portals"],[e("sootsim debug find sheets","every Sheet.Frame-shaped node in the tree"),e("sootsim debug find portals","every portal-host / portal-view pair the engine is currently mounting"),e("sootsim debug find sheets | jq '.[] | select(.translateY != null)'","narrow to sheets mid-animation")],"category-specific inspectors for runtime structures that `describe` collapses. emits a JSON array of node-shaped records \u2014 pipe through jq for filtering.",{group:"debug",subgroup:"inspectors",shortDescription:"list engine-internal nodes by category",seeAlso:["state","describe"]}),i("record","toggle the debug event ring buffer (off / on)",["sootsim debug record [on|off]"],[e("sootsim debug record on","arm the ring buffer"),e("sootsim debug record off","stop recording"),e("sootsim debug record","query current state without flipping it")],"the ring buffer feeds `debug recent <channel> [n]`. enable a channel via `debug enable <channel>` first so the corresponding events actually fire.",{group:"debug",subgroup:"events",shortDescription:"toggle the debug event ring buffer",seeAlso:["recent","clear-events"]}),i("recent","tail the last N events from the debug ring buffer (optionally filtered by channel)",["sootsim debug recent","sootsim debug recent <channel>","sootsim debug recent <channel> <n>"],[e("sootsim debug recent","last 50 events across every channel"),e("sootsim debug recent portals 20","last 20 portal events"),e("sootsim debug recent layout 200","larger window for layout debugging")],"requires `debug record on` to have armed the buffer at some prior point. default limit is 50.",{group:"debug",subgroup:"events",shortDescription:"last N debug events",seeAlso:["record","clear-events"]}),i("clear-events","drop everything currently in the debug event ring buffer",["sootsim debug clear-events"],[e("sootsim debug clear-events","reset the buffer before a clean repro")],void 0,{group:"debug",subgroup:"events",shortDescription:"reset the debug event ring buffer",seeAlso:["record","recent"]}),i("sample-color","average the canvas color over a pixel or rect; returns hex + rgba",["sootsim debug sample-color <x> <y> [w] [h]","sootsim debug sample-color --area x,y,w,h","sootsim debug sample-color --id <testID>","sootsim debug sample-color --text <text>"],[e("sootsim debug sample-color 196 400"),e("sootsim debug sample-color 100 200 50 80"),e("sootsim debug sample-color --id loginButton"),e('sootsim debug sample-color --text "Sign in" --json')],"coords are logical sootsim units. pixels are averaged across the rect. --json emits { r, g, b, a, hex, samples, rect } for scripts.",{group:"debug",subgroup:"profiling",shortDescription:"average canvas color over a rect",options:[t("--area x,y,w,h","rect to sample (coords are logical sootsim units)"),t("--id <testID>","sample over a node's layout rect"),t("--text <text>","sample over the node matching text"),t("--json","emit { r, g, b, a, hex, samples, rect }")],seeAlso:["screenshot"]}),i("screenshot","capture the canvas (full or a cropped area) as PNG",["sootsim screenshot [--output <path>]","sootsim screenshot --area x,y,w,h [--output <path>]","sootsim screenshot --id <testID> [--output <path>]","sootsim screenshot --text <text> [--output <path>]"],[e("sootsim screenshot"),e("sootsim screenshot --output /tmp/app.png"),e("sootsim screenshot --area 0,200,393,400"),e("sootsim screenshot --id loginButton --output button.png")],"area args use logical sootsim coords; default output is /tmp/sootsim-inspect.png.",{options:[t("--output <path>","write PNG here (default /tmp/sootsim-inspect.png)"),t("--area x,y,w,h","crop to rect (logical sootsim coords)"),t("--id <testID>","crop to a node's layout rect"),t("--text <text>","crop to the node matching text")],seeAlso:["sample-color","record"]}),i("url","show the current page URL",["sootsim get url [--json]"],[e("sootsim get url"),e("sootsim get url --json")],void 0,{group:"get",subgroup:"info",shortDescription:"current page URL",options:[t("--json","emit { url } for scripts")]}),i("reload","reload the page and wait for reconnection",["sootsim do reload"],void 0,void 0,{group:"do",subgroup:"lifecycle",shortDescription:"reload the page + wait for reconnect",seeAlso:["wait","ready"],order:10}),i("globals","list all __sootsim* globals available in the browser",["sootsim get globals"],void 0,void 0,{group:"get",subgroup:"info",shortDescription:"list available __sootsim* globals"}),i("sleep","simple local pause between commands",["sootsim do sleep [seconds]"],[e("sootsim do sleep 0.5")],void 0,{group:"do",subgroup:"lifecycle",shortDescription:"local pause between commands",seeAlso:["settle","idle"],order:40}),i("wait","wait for the current sim to reconnect",["sootsim do wait [seconds]"],[e("sootsim do wait 30")],void 0,{group:"do",subgroup:"lifecycle",shortDescription:"wait for sim reconnect",seeAlso:["ready","idle","settle"],order:20}),i("settle","wait until the visible layout is stable (default max 3s)",["sootsim do settle [seconds] [--strict]"],[e("sootsim do settle 3"),e("sootsim do settle 2 --strict")],"default requires layout hash to be stable for 3 consecutive polls \u2014 this is the right signal for slide transitions, spring-driven position changes, and scroll momentum. --strict additionally requires the worker animation flags (hasActiveAnims, hasActiveNativeAnimations, hasPendingAnimationFrames) to all be false. use --strict only when the target app has no perpetual background animation, otherwise it will time out.",{group:"do",subgroup:"lifecycle",shortDescription:"wait for animations to settle",options:[t("--strict","also require all worker animation flags to be false (use only when no perpetual bg animation)")],seeAlso:["idle","ready","selector"],order:30}),i("ready","block until the guest app bundle is loaded and painted (20s default)",["sootsim wait ready [--max-ms <ms>]"],[e("sootsim wait ready"),e("sootsim wait ready --max-ms 30000","cold uniswap/expensify reload"),e("sootsim wait ready --max-ms 5000")],"authoritative signal: the persistent __sootsimExternalAppReady flag (set by the sootsim:externalAppReady event handler, cleared on reload). polls CLI-side so --max-ms can exceed the bridge per-command timeout. prefer this over `do wait`, which is a node-count heuristic that false-positives on ConnectRN skeletons. idempotent: calling it after the app is already ready returns in ~200ms. exits non-zero on timeout.",{group:"wait",shortDescription:"block until the guest app bundle is loaded and painted",options:[t("--max-ms <ms>","override the 20s default deadline")],seeAlso:["idle","selector","settle"],order:10}),i("idle","block until animations, rAF queue, and layout are all settled",["sootsim wait idle [--max-ms <ms>] [--strict]"],[e("sootsim wait idle"),e("sootsim wait idle --max-ms 2000 --strict")],"same signal as `do settle` but under the discoverable `wait` verb. exits non-zero on timeout.",{group:"wait",shortDescription:"block until animations + rAF + layout are settled",options:[t("--max-ms <ms>","override the idle deadline"),t("--strict","also require worker animation flags to all be false")],seeAlso:["ready","selector","settle"],order:20}),i("selector","block until a node with <testid> is present with non-zero layout (or absent with --gone)",["sootsim wait selector <testid> [--max-ms <ms>] [--gone]"],[e("sootsim wait selector loginButton"),e("sootsim wait selector feedList --max-ms 3000"),e("sootsim wait selector loginButton --gone --max-ms 90000","after a gate action, wait for the gate to leave instead of re-tapping")],'playwright-style. when `find --testid <id>` returns no result, the CLI now prints this command as a hint. `--gone` inverts the wait \u2014 it resolves when the node is confirmed absent (the positive "gate/screen left" signal), and never resolves on an indeterminate bridge. exits non-zero on timeout.',{group:"wait",shortDescription:"block until a testID appears (or, with --gone, disappears)",options:[t("--max-ms <ms>","override the deadline"),t("--gone","resolve when the node is absent instead of present")],seeAlso:["ready","idle","find"],order:30}),i("event","block until a semantic timeline event of <kind> appears",["sootsim wait event <kind> [--max-ms <ms>]","sootsim wait event <kind> --filter <substring>","sootsim wait event <kind> --equals <exact>"],[e("sootsim wait event fetch --filter BeginSignIn","wait for the next BeginSignIn fetch after a tap"),e("sootsim wait event screen --equals Inbox","wait until a screen named Inbox appears"),e("sootsim wait event alert","wait for the next iOS alert/sheet"),e("sootsim wait event react-commit --max-ms 2000","block until the next React commit fires (or 2s)")],"timeline-backed companion to wait selector / wait idle. polls SootSim.bridges.timeline.recent() at 200ms; matches against url, message, name, path, title, and phase fields. defaults: --max-ms 5000, --since now (only counts events that arrive after this command starts; pass --since cursor to include prior events). exits non-zero on timeout.",{group:"wait",shortDescription:"block until the next timeline event of a given kind",options:[t("--max-ms <ms>","wait deadline in milliseconds (default 5000)"),t("--filter <substring>","substring match against url/message/name/path/title (case-insensitive)"),t("--equals <exact>","exact match against any of the same fields"),t("--since <mode>",'"now" (default \u2014 only events after this command starts) or "cursor"'),t("--json","emit { found, elapsedMs, event } JSON")],seeAlso:["ready","idle","selector"],order:40}),i("dispatch","dispatch a raw keyboard key (bypasses visual shift state)",["sootsim do dispatch <char>"],[e("sootsim do dispatch A")],void 0,{group:"do",subgroup:"text input",shortDescription:"raw key (bypasses visual shift state)",seeAlso:["key","type"],order:70}),i("keyboard","on-screen keyboard state (type, returnKey, autoCap, mode, shift, accessory)",["sootsim get keyboard [--json]"],[e("sootsim get keyboard"),e("sootsim get keyboard --json")],void 0,{group:"get",subgroup:"info",shortDescription:"on-screen keyboard state",options:[t("--json","emit structured JSON")],seeAlso:["type","dismiss","state"]}),i("screens","list the current navigation stack: active app, route stack, modal stack, keyboard",["sootsim get screens [--json]"],[e("sootsim get screens"),e("sootsim get screens --json")],'pulls from the shell (active app, switcher phase), the navigation bridge (route stack for react-navigation / one-router if present), and the top presented modal. use this when a screen id or nav-state is the fastest orientation signal \u2014 e.g. "am I on the onboarding landing, or did the login sheet open over it?". Exits quietly when no navigation bridge is available.',{group:"get",subgroup:"info",shortDescription:"current screen + modal + route stack",options:[t("--json","emit structured JSON")],seeAlso:["describe","state","keyboard"]})];function _(o,s){return`${o??""}:${s}`}var C=new Map,V=new Map;for(let o of R){let s=C.get(o.verb);s?s.push(o):C.set(o.verb,[o]),V.set(_(o.group,o.verb),o)}var le=new Map(Array.from(C,([o,s])=>[o,s.find(a=>!a.group)??s[0]]));function W(o,s){return V.get(_(o,s))}function w(o,s){if(s!==void 0)return W(s,o);let a=C.get(o);return a?.find(l=>!l.group)??a?.[0]}function h(o,s=v){return o.replaceAll("{{bridgePort}}",String(s.bridgePort)).replaceAll("{{defaultShellUrl}}",s.defaultShellUrl)}function Y(){return D.slice().sort((o,s)=>o.order-s.order)}function k(o,s){let a=Math.max(...s.map(r=>r.name.length),0)+2,l=s.map(r=>` ${r.name.padEnd(a)}${r.desc}`);return` ${o}
|
|
1
|
+
/*! sootsim v0.1.192 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{b as B}from"./chunk-WNJWTMX4.js";var v={bridgePort:7668,defaultShellUrl:"http://localhost:5173/"};function t(o,s){return{flag:o,description:s}}function e(o,s){return{command:o,description:s}}var D=[{id:"test",slug:"test",navTitle:"test",title:"sootsim test",description:"run tests against sootsim",summary:"Run package-local smoke and debugging tests, YAML flows, or the shared Detox-style conformance suites against a running sootsim target.",order:30,usage:["sootsim test [options]"],options:[t("--flows","run YAML flows through the sootsim flow runner"),t("--detox","run the shared Detox-style conformance suites against sootsim"),t("--parallel","run discovered flows in parallel where supported"),t("--watch","re-run interactively when files change"),t("--reporter <type>","select console, json, or junit reporting"),t("--grep <pattern>","filter the test set by name")],examples:[e("sootsim test","run package-local Playwright smoke/debug tests"),e("sootsim test --flows"),e("sootsim test --detox","run the shared conformance suite against sootsim"),e("sootsim test --detox --watch")],related:["flow","inspect","record"]},{id:"flow",slug:"flow",navTitle:"flow",title:"sootsim flow",description:"run flows through the current sim or manage a draft from live inspect actions",summary:"Use flow files when you already have them, or start a draft so inspect-driven actions can be kept one by one and exported into YAML once the path is proven. Flow playback, recording, and profiling now stay on the shared bridge runner.",order:40,usage:["sootsim flow <flow.yaml> [options]","sootsim flow start","sootsim flow keep (alias: sootsim flow good)","sootsim flow end [--output <path>] [--validate] [--video]"],options:[t("--record","record a video while the flow runs"),t("--profile","capture perf stats while the flow runs"),t("--out <dir>","output bundle directory \u2014 recordings land here, and `--screenshots` also defaults to this directory (so one flag controls the whole demo-run bundle instead of needing both)"),t("--screenshots <dir>","override screenshot output directory (defaults to --out, or /tmp/sootsim-flow if neither is set)"),t("--screenshot-paths <mode>","screenshot path mode: `dir` (default \u2014 flat directory of files) or `flow` (per-flow subdirectory tree)"),t("--replace <module>=<file>","replace a Metro module with a local file for this run \u2014 useful for swapping in a fixture component (e.g. a deterministic SeedPhraseInputScreen for demo recordings). repeatable"),t("--slow <ms>","delay between steps for easier debugging"),t("--tail-wait <ms>","hold recording open after the last step so the final UI state is captured (default: smart idle up to 6000ms for --preview, fixed 2000ms for --record, 0 otherwise)"),t("--url <url>","load this target before running the flow"),t("--no-shell","capture every screenshot tenant-only (no status bar, keyboard, notification center, or other shell overlays). per-step `layers:` still wins over this default"),t("--shell-only","inverse \u2014 capture only the shell chrome overlays"),t("--new","open a fresh sim before running the flow"),t("--driver <id>","when paired with --new, launch through a specific driver from the registry (e.g. playwright); see `sootsim list --drivers`"),t("--headless","pass headless=true to the launch driver (useful with --driver playwright)"),t("--headed","force a fresh, VISIBLE window for this run (implies --new, overrides --headless) \u2014 watch the flow run live even if the current sim is headless or stale"),t("--sim <sim>","target a specific current sim"),t("--electron","prefer the desktop companion for this flow run"),t("--output <path>","write the drafted flow when using `flow end`"),t("--validate","replay the drafted flow before clearing it"),t("--video","replay and record the drafted flow before clearing it"),t("--preview","record + upload the run as a shareable /preview/<id> link (implies --record)"),t("--preview-origin <url>","override the upload target for --preview (defaults to auto)"),t("--preview-public-origin <url>","override the public link origin for --preview (defaults to sootsim.com for prod uploads)"),t("--preview-open","open the resulting /preview/<id> url after upload")],examples:[e("sootsim flow flows/login.yaml"),e("sootsim flow flows/login.yaml --profile"),e("sootsim flow flows/demo.yaml --record --slow 500"),e("sootsim flow flows/demo.yaml --preview","record + upload a shareable link in one step"),e("sootsim flow start"),e("sootsim flow keep"),e("sootsim flow end --output ./flows/draft.yaml"),e("sootsim flow end --output ./flows/draft.yaml --validate"),e("sootsim flow end --output ./flows/draft.yaml --video")],related:["inspect","record","desktop","test"]},{id:"record",slug:"record",navTitle:"record",title:"sootsim record",description:"capture the live sim as webm/mp4/gif, or sample N png frames (--frames)",summary:"Drives the engine's built-in canvas recorder over the WS bridge \u2014 no second browser, no ffmpeg. Encoding happens in the running page (MediaRecorder for webm, WebCodecs for mp4, gifenc for gif). Two modes: atomic (duration-bounded) or stateful (start \u2192 interact \u2192 stop). Stateful mode is webm/mp4 only; for gif/png use atomic mode. Use --frames to sample N evenly-spaced png snapshots instead of a video. NOTE on `live`/`combined`: the `/preview/<id>` id is derived from the app's bundle identity, not the recording \u2014 so re-recording the same app reuses the same URL and overwrites the previous preview. This is intentional (re-record replaces in place); keep a recording you want to preserve by copying its `/preview/<id>` page elsewhere before recording the same app again.",order:60,usage:["sootsim record [options]","sootsim record start [options]","sootsim record prelude-start [--origin <url>]","sootsim record stop [--output <path>]","sootsim record status # reports the record-start session; also probes the engine","sootsim record cancel # cancels a record-start session","sootsim record upload (--events <path> | --video <path>) [--open]"],options:[t("--format <type>","webm | mp4 | gif | png (inferred from --output extension; stateful mode is webm/mp4 only)"),t("--mode <kind>","video | live | combined (default: video). live captures the event stream; combined captures both and uploads automatically. NOTE: live/combined upload to /preview/<id> whose id is bundle-derived, so re-recording the same app overwrites the previous preview"),t("--duration <seconds>","recording duration (default: 10, atomic mode only)"),t("--fps <number>","target frame rate for video/gif (default: 30)"),t("--output <path>","output file, or directory when --frames is set"),t("--frames <n>","sample N evenly-spaced png frames instead of a video"),t("--max-width <px>","downscale gif frames to this width"),t("--no-shell","exclude the simulated iOS chrome (status bar, keyboard, toasts) \u2014 record the tenant surfaces only"),t("--shell-only","record only the shell chrome"),t("--open","open the uploaded preview URL in the browser after stop (live/combined)"),t("--sim <sim>","target a specific sim"),t("--origin <url>","billing/upload origin for live/combined (default: auto \u2014 probes a local :3000 stack, else https://sootbean.com; also honors SOOTSIM_UPLOAD_ORIGIN)"),t("--owner <org>","associate live/combined preview uploads with a linked org repo; pass with --repo"),t("--repo <repo>","repo name for --owner; the signed-in user must belong to the owning org team"),t("--events <path>","for upload: gzipped events .jsonl.gz file to attach"),t("--video <path>","for upload: webm/mp4/gif recording to attach"),t("--assets-only","for upload: keep assets only; replay API calls live")],examples:[e("sootsim record --duration 5"),e("sootsim record --format mp4 --output demo.mp4 --duration 8"),e("sootsim record --output demo.gif --duration 3"),e("sootsim record --frames 10 --output ./frames/"),e("sootsim record --mode combined --duration 8 --open --owner my-org --repo my-app","capture video + events and upload a repo-associated preview link"),e("sootsim record start --format mp4","begin; interact freely across any number of CLI calls"),e("sootsim record start --mode combined","start a stateful preview-share recording"),e("sootsim record prelude-start","capture hidden setup events before starting the visible proof segment"),e("sootsim record stop --output flow.mp4","finalize + save"),e("sootsim record cancel","discard a record-start session (atomic --duration runs own their own lifecycle)"),e("sootsim record upload --events ./my-run.jsonl.gz --open"),e("sootsim record upload --video /tmp/soot-flow.webm")],related:["screenshot","flow"]},{id:"storage",slug:"storage",navTitle:"storage",title:"sootsim storage",description:"manage guest app storage and launch profiles",summary:"Clear the current guest app's local storage through the live reload bridge, or manage persistent storage profiles for Electron and Playwright launches. Profiles isolate cookies, localStorage, IndexedDB, cache, permissions, and service workers; browser-tab launches cannot honor them.",order:65,usage:["sootsim storage clear [--sim <id>] [--json]","sootsim storage profile ls","sootsim storage profile create <id>","sootsim storage profile clear <id>","sootsim storage profile delete <id>"],options:[t("--sim <id>","target a specific connected sim for `storage clear`"),t("--json","emit { cleared, ready, reload } for `storage clear`"),t("<id>","profile id: letters, numbers, dot, dash, or underscore")],examples:[e("sootsim storage clear"),e("sootsim storage clear --sim a9 --json"),e("sootsim storage profile ls"),e("sootsim storage profile create qa"),e("sootsim open 8081 --profile qa --driver playwright"),e("sootsim storage profile clear qa")],related:["open","desktop"]},{id:"perf",slug:"perf",navTitle:"perf",title:"sootsim perf",description:"CPU, React render, and shell frame profiling",summary:"One profiling group for the three performance surfaces: sampled JS CPU profiles via Chrome DevTools Protocol, React render-cost tables from the tenant worker, and shell-worker frame profiling for the renderer that paints app pixels.",order:66,usage:["sootsim perf cpu [options]","sootsim perf react <profile|summary|slow|rerenders|tree|why> [options]","sootsim perf shell <start|stop|transition> [options]"],options:[t("--cdp-port <port>","for `perf cpu`: Chrome DevTools port (default: $SOOTSIM_CDP_PORT or 9222)"),t("--duration <seconds>","for `perf cpu`: recording duration (default: 5)"),t("--match <substring>","for `perf cpu`: pick the page target by URL substring"),t("--output <path>","for `perf cpu`: output .cpuprofile path"),t("--include-props","for `perf react profile start`: record shallow prop previews"),t("--limit <n>","for `perf react`: rows to print"),t("--json","structured output where supported"),t("--sim <sim>","target a specific connected sim")],examples:[e("sootsim open 8089 --new --driver playwright --cdp-port 9222"),e("sootsim perf cpu --cdp-port 9222 --duration 5"),e("sootsim perf react profile start"),e("sootsim perf react summary --limit 10"),e("sootsim perf shell start"),e("sootsim perf shell stop --json")],related:["open","record","flow","debug"]},{id:"screenshot",slug:"screenshot",navTitle:"screenshot",title:"sootsim screenshot",description:"capture PNGs and manage App Store screenshot assets",summary:"One screenshot surface: capture the current canvas as a PNG, drive the live App Store slide composer, or run the plan/headless App Store capture pipeline. Bare `sootsim screenshot` is the same as `sootsim screenshot capture`.",order:70,usage:["sootsim screenshot [capture] [output] [options]","sootsim screenshot slides <list|set|add|remove|focus|overview|capture|export> [args]","sootsim screenshot appstore --plan <plan.yaml> [options]","sootsim screenshot appstore capture --org <org> --repo <repo> [options]"],options:[t("--output <path>","for capture: output PNG path (default: /tmp/sootsim-inspect.png). aliases: -o, --out, --file, --path"),t("--area <x,y,w,h>","for capture: crop to a logical sootsim rect. aliases: --rect, --crop"),t("--id <testID>","for capture: crop to the bounding box of a node by testID. alias: --testid"),t("--text <text>","for capture: crop to the bounding box of a node by text content"),t("--no-shell","for capture/flows: exclude simulated iOS chrome"),t("--shell-only","for capture/flows: capture only shell chrome"),t("--plan <path>","for appstore: screenshot plan yaml"),t("--org <org>","for appstore capture: github org slug"),t("--repo <repo>","for appstore capture: repo name"),t("--compose-only","for appstore: skip flow capture and reuse existing raws"),t("--capture-only","for appstore: stop after raw/framed intermediates")],examples:[e("sootsim screenshot","capture the current sim to a PNG"),e("sootsim screenshot --output app.png"),e("sootsim screenshot capture --no-shell --output tenant-only.png"),e("sootsim screenshot --area 0,200,393,400"),e("sootsim screenshot slides","list the current live deck"),e("sootsim screenshot slides capture 1"),e("sootsim screenshot slides export --out ./exports"),e("sootsim screenshot appstore --plan .sootsim/app-store.yaml"),e("sootsim screenshot appstore --plan .sootsim/app-store.yaml --compose-only","rerender marketing canvases from existing raw PNGs"),e("sootsim screenshot appstore capture --org acme --repo my-app --dry-run","headlessly capture editable org-deck slides without uploading")],related:["mode","record","inspect","flow"]},{id:"mode",slug:"mode",navTitle:"mode",title:"sootsim mode",description:"toggle screenshot and 3D display modes",summary:"Toggle live shell display modes using the same plugin-owned action paths as the rail and menus. `mode screenshot` hides browser chrome for clean captures; `mode three` toggles and configures the live 3D device stage.",order:73,usage:["sootsim mode screenshot [on|off|toggle]","sootsim mode three [on|off|toggle]","sootsim mode three configure [flags]"],options:[t("screenshot on|off|toggle","toggle screenshot-mode chrome overlay"),t("three on|off|toggle","toggle the live 3D device stage"),t("--background <id>","set the 3d background"),t("--gradient <stops>","custom gradient bg: comma-separated css hex stops (overrides --background)"),t("--gradient-angle <deg>","custom gradient angle (default 180 = top\u2192bottom)"),t("--colorway <id>","set the phone colorway"),t("--script <id>","apply a camera preset pose"),t("--progress <0..1>","script progress to sample (default: 1)"),t("--animate","run the script instead of sampling one frame"),t("--slow","run the script slowly when --animate is set"),t("--environment <on|off>","enable or disable environment objects"),t("--env-shape <id>","orb | pill | diamond | pane"),t("--env-spread <id>","tight | medium | wide"),t("--env-size <id>","small | medium | large"),t("--env-color <id>","peach | gold | mint | sky | violet"),t("--env-glow <on|off>","enable or disable environment glow"),t("--env-plastic <on|off>","enable or disable environment plastic material"),t("--room <on|off>","enable or disable the room effect"),t("--bokeh <on|off>","enable or disable bokeh"),t("--reset-pose","return to the default hero pose before other changes")],examples:[e("sootsim mode screenshot on","hide browser chrome around the canvas"),e("sootsim mode screenshot off"),e("sootsim mode three on","force 3d mode on"),e("sootsim mode three configure --colorway sky --background gradient-sunset","set the phone and background to specific options"),e('sootsim mode three configure --room on --gradient "#0a1822,#0d2233,#06101a"',"room effect + a custom brand-color gradient background"),e("sootsim mode three configure --script hero-pan --animate --slow","play a camera script slowly"),e("sootsim mode three configure --reset-pose","return to the default pose")],related:["screenshot"]},{id:"describe",slug:"describe",navTitle:"describe",title:"sootsim describe",description:"curated human-readable UI summary (default inspection tool)",summary:"The default way to see what is on screen. Lists visible UI elements with type, text, position, size, and style \u2014 buttons show [button], tappable views show [tap], inputs show [input]. Structural noise (icon wrappers, layout containers, duplicate text inside buttons) is pruned by default; use --all for the unfiltered tree, --verbose for ids/labels/style, and --json to script against it. Reach for describe before screenshots or DOM poking.",order:68,usage:["sootsim describe [filter] [--verbose] [--watch] [--all] [--json] [--no-clipped] [--compact] [--no-xy] [--only <glob>] [--subtree <id>] [--testid-like <pat>]"],options:[t("--verbose","include ids, labels, and extra style info"),t("--all","do not prune structural view nodes"),t("--watch","redraw as the UI changes (ctrl-c to stop)"),t("--json","emit structured JSON"),t("--no-clipped","strip rows annotated (clipped:left|right|top|bottom) so the on-screen state is not buried"),t("--compact","render the tree in a tighter format"),t("--no-xy","hide x,y coordinates from each row"),t("--only <glob>","glob filter across text/role/testID"),t("--subtree <id>","limit the dump to a subtree rooted at the given testID"),t("--testid-like <pattern>","fuzzy-match nodes whose testID contains the pattern")],examples:[e("sootsim describe"),e("sootsim describe button"),e("sootsim describe --verbose"),e("sootsim describe --json"),e("sootsim describe --watch"),e("sootsim describe --subtree feedListRoot","limit to one subtree"),e('sootsim describe --only "*Header*"',"glob-match across text/role/testID")],related:["find","get","do","inspect"]},{id:"find",slug:"find",navTitle:"find",title:"sootsim find",description:"locate nodes by text / testID / role / type / predicate",summary:"The unified finder. A bare argument matches node text (findByText); flag forms match by testID, role, component type, or predicate. --pressable and --visible list every tappable or visible node, and --interactive-targets (alias --actions) ranks visible+pressable nodes and prints a ready-to-run `sootsim do tap-...` command per row, so the next tap is one copy away. Use --verbose for full node JSON and --json to script.",order:68.5,usage:["sootsim find <text>","sootsim find --testid <id>","sootsim find --role <role>","sootsim find --type <component-type>","sootsim find --pressable","sootsim find --visible","sootsim find --interactive-targets"],options:[t("--text <text>","match node text content (same as bare positional)"),t("--testid <id>","match node testID or id exactly"),t("--role <role>","match accessibilityRole"),t("--type <type>","match React component type"),t("--pressable","list all tappable nodes"),t("--visible","list all visible (non-zero) nodes"),t("--interactive-targets, --actions","ranked tappable nodes, each with a ready-to-run tap command"),t("--verbose, --dump","emit full node JSON for each result"),t("--json","emit structured JSON")],examples:[e('sootsim find "Sign in"'),e("sootsim find --testid loginButton"),e("sootsim find --role button"),e("sootsim find --pressable"),e("sootsim find --visible --json"),e("sootsim find --interactive-targets","ranked visible+pressable nodes with copy-paste tap commands")],related:["describe","get","do","inspect"]},{id:"assert",slug:"assert",navTitle:"assert",title:"sootsim assert",description:"run any read verb and convert its output into an exit code",summary:"Thin wrapper that spawns a read verb (describe, find, get errors, \u2026) with --json forced on, parses stdout, and evaluates assertion flags over the payload. Exit codes are bisect-friendly: 0 pass, 1 fail, 125 skip (app not loaded / verb crashed), 2 misuse. Flag-level composition (--count / --contains / --jq / --has-path / --within) means the same predicate surface works across every read verb.",order:69,usage:["sootsim assert <verb> <verb-args...> <assertion-flags...>"],options:[t("--count <n>","result array has exactly n items"),t("--count-at-least <n>","length >= n"),t("--count-at-most <n>","length <= n"),t("--exists","non-null, non-empty (default when no flag given)"),t("--empty","null or zero length"),t("--contains <str>","stringified result contains str (repeatable)"),t("--not-contains <str>","stringified result does not contain str"),t("--matches <regex>","stringified result matches regex"),t("--not-matches <regex>","stringified result does not match regex"),t("--equals <literal>","scalar equality"),t("--has-path <dotted.path>","nested path exists"),t("--path-equals <path> <value>","nested path equals value"),t("--jq <expr>","jq expression is truthy (requires jq on PATH)"),t("--within <ms>","retry verb + predicates until pass or deadline"),t("--allow-timeout","treat verb auto-wait timeout as fail, not skip"),t("--negate, !","flip pass/fail (does not flip skip)"),t("--quiet","suppress the one-line pass/fail summary")],examples:[e("sootsim assert find --testid set-max-input --count 4","exactly four matching nodes"),e("sootsim assert describe --contains swap-form-header","substring anywhere in the tree dump"),e("sootsim assert get errors --count 0","fail the commit if any console error"),e("sootsim assert find --testid submit --exists --within 3000","poll for 3s before failing"),e(`sootsim assert describe --jq '.shell.state == "app"'`,"jq predicate over the payload"),e("git bisect run sootsim assert find --testid set-max-input --count 4","git-bisect integration")],related:["find","describe","get","list"]},{id:"get",slug:"get",navTitle:"get",title:"sootsim get",description:"read runtime state (tree, a11y, url, count, errors, \u2026)",summary:"Grouping verb for pure reads. `sootsim get <noun>` covers the read side of the bridge \u2014 tree, a11y, url, count, console errors/warnings/requests, layout, globals, and single-node lookups.",order:70,usage:["sootsim get <noun> [args]"],examples:[e("sootsim get tree"),e("sootsim get a11y 3"),e("sootsim get url"),e("sootsim get count"),e("sootsim get errors 5"),e("sootsim get requests 5"),e("sootsim get node loginButton"),e("sootsim get layout loginButton"),e("sootsim get globals")],related:["do","find","describe","inspect"]},{id:"do",slug:"do",navTitle:"do",title:"sootsim do",description:"drive the app (tap, type, scroll, swipe, key, reload, \u2026)",summary:"Grouping verb for user-interaction actions. `sootsim do <action>` covers the write side of the bridge \u2014 taps, typing, key presses, touch/scroll/drag/swipe/pinch gestures, reload, and local timing helpers.",order:71,usage:["sootsim do <action> [args]"],examples:[e("sootsim do tap 196 727"),e("sootsim do double-tap 196 400"),e('sootsim do tap-text "Sign in"'),e("sootsim do tap-id loginNextButton"),e('sootsim do type "natew.bsky.social"'),e('sootsim do type-into email "me@example.com"'),e("sootsim do key return"),e("sootsim do key-sequence shift h i"),e("sootsim do dismiss"),e("sootsim do scroll feed 0 400"),e("sootsim do drag 200 720 200 160"),e("sootsim do swipe 200 720 200 160"),e("sootsim do gesture swipe-from-bottom-edge"),e("sootsim do reload")],related:["shell","get","find","describe","inspect","wait"]},{id:"wait",slug:"wait",navTitle:"wait",title:"sootsim wait",description:"block until the runtime reaches a known state",summary:"Grouping verb for explicit synchronization. Use instead of guessing with `sleep`. Every subverb has a bounded timeout and exits non-zero when it times out, so automations fail loudly rather than silently racing animations or missing nodes.",order:72,usage:["sootsim wait <kind> [args]"],examples:[e("sootsim wait ready","block until the app bundle is loaded and painted"),e("sootsim wait idle","block until animations + rAF queue are settled"),e("sootsim wait selector loginButton","block until a node with this testID is present"),e("sootsim wait selector feedList --max-ms 3000","cap how long to wait for a node")],related:["do","find","describe","get"]},{id:"shell",slug:"shell",navTitle:"shell",title:"sootsim shell",description:"drive shell state and simulator chrome",summary:"Top-level shell controls for app launch, home/switcher transitions, and simulator-owned chrome such as appearance and lock state.",order:72,usage:["sootsim shell launch <appId> [waitMs] [--clear-state]","sootsim shell home [waitMs]","sootsim shell switcher [waitMs]","sootsim shell open-card <appId> [waitMs]","sootsim shell appearance <light|dark|auto|toggle>","sootsim shell lock","sootsim shell shake"],examples:[e("sootsim shell launch photos"),e("sootsim shell home"),e("sootsim shell switcher 800"),e("sootsim shell appearance dark"),e("sootsim shell lock")],related:["do","inspect","debug"]},{id:"inspect",slug:"inspect",navTitle:"inspect",title:"sootsim inspect",description:"query, describe, and drive the running sootsim instance",summary:"Use the bridge-backed inspection surface for full access to the real node tree. `sootsim inspect <sub>` works for every subcommand in the surface; day-to-day, prefer the grouped verbs (`describe`, `find`, `get`, `do`, `shell`, `debug`) \u2014 run `sootsim --help` to see the full set.",order:80,usage:["sootsim inspect <subcommand> [args]"],options:[t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--timeout <ms>","command timeout for bridge requests"),t("--base-url <url>","base shell URL used by open when wrapping bundle targets")],examples:[e("sootsim describe"),e("sootsim get errors 5"),e("sootsim get requests 5"),e('sootsim do tap-text "Sign in"'),e("sootsim list"),e("sootsim debug state shell --sim a2")],related:["debug","get","do","shell","find","list","open","use"]},{id:"network",slug:"network",navTitle:"network",title:"sootsim network",description:"inspect live network traffic from the running sootsim worker",summary:"Read the shared observability store (fetch + XHR captured in the render worker) from the terminal. List recent requests, tail in real time, filter by URL or status, inspect one entry in detail, or clear the buffer. Shares its data source with the in-shell devtools dock so both views stay in lock-step.",order:85,usage:["sootsim network [limit]","sootsim network --failed","sootsim network --slow [--threshold <ms>]","sootsim network --filter <substring>","sootsim network --tail","sootsim network get <id>","sootsim network clear"],options:[t("--failed","only show errored or non-2xx responses"),t("--slow","only show requests slower than --threshold (default 1000ms), sorted by duration desc"),t("--threshold <ms>","slow threshold in milliseconds for --slow (default 1000)"),t("--filter <substring>","URL substring filter (case-insensitive)"),t("--limit <n>","max entries to print (default 20)"),t("--tail, -f","follow mode: stream new entries as they land"),t("--json","emit structured JSON instead of formatted rows"),t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim network","list the last 20 requests"),e("sootsim network 100","list the last 100"),e("sootsim network --failed","only errors and 4xx/5xx"),e("sootsim network --slow","requests slower than 1000ms, sorted by duration desc"),e("sootsim network --slow --threshold 200","tighten the slow threshold to 200ms"),e("sootsim network --filter api.example.com"),e("sootsim network --tail","live follow mode, ctrl-c to stop"),e("sootsim network --tail --failed"),e("sootsim network get req-42-l7k9"),e("sootsim network clear")],related:["inspect","debug","get","logs"]},{id:"logs",slug:"logs",navTitle:"logs",title:"sootsim logs",description:"inspect live console output from the running sootsim worker",summary:"Read the shared observability log store (console.log/info/warn/error/debug plus uncaught errors and unhandled rejections, captured in the render worker) from the terminal. List recent logs, tail in real time, filter by level or substring, or clear the buffer. Shares its data source with the devtools dock so both views stay in lock-step.",order:86,usage:["sootsim logs [limit]","sootsim logs --level <csv>","sootsim logs --filter <substring>","sootsim logs --tail","sootsim logs clear"],options:[t("--level <csv>","comma-separated level filter (log,info,warn,error,debug)"),t("--filter <substring>","message substring filter (case-insensitive)"),t("--limit <n>","max entries to print (default 50)"),t("--tail, -f","follow mode: stream new log entries as they land"),t("--json","emit structured JSON instead of formatted rows"),t("--internal, --all","include engine-internal [sootsim] logs (bundle-loader, HMR traps, etc.) \u2014 hidden by default so guest-app output stays readable"),t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim logs","last 50 log entries"),e("sootsim logs 200","last 200"),e("sootsim logs --level error,warn"),e('sootsim logs --filter "hydrate"'),e("sootsim logs --tail","live follow mode, ctrl-c to stop"),e("sootsim logs --tail --level error"),e("sootsim logs --internal","include engine-internal logs"),e("sootsim logs clear")],related:["network","inspect","get"]},{id:"debug",slug:"debug",navTitle:"debug",title:"sootsim debug",description:"drive __sootsimDebug: channels, snapshots, and inspectors",summary:"Toggle engine debug channels, capture snapshots, and diff internal state from the terminal while targeting any connected sim.",order:90,usage:["sootsim debug <subcommand> [args]"],options:[t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--json","emit compact JSON for machine consumption"),t("--pretty","emit formatted JSON for human inspection")],examples:[e("sootsim debug enable sheets,portals"),e("sootsim debug snapshot before"),e("sootsim debug diff before after"),e("sootsim debug recent portals 20")],related:["inspect","open","what-happened"]},{id:"what-happened",slug:"what-happened",navTitle:"what-happened",title:"sootsim what-happened",description:"show recent semantic events: toasts, keyboards, screens, alerts, fetches, errors",summary:"Read the unified semantic timeline across host, shell worker, and tenant worker. Defaults to events since the previous CLI call (per-agent cursor), so 'what-happened' reliably shows what's new instead of replaying state you already saw. Catches ephemeral UI like toasts that disappear before describe/find can find them.",order:91,usage:["sootsim what-happened","sootsim what-happened --summary","sootsim what-happened --since 5s --kinds toast,fetch"],options:[t("--summary","one-line counts by kind, no event list"),t("--flow","section the event stream by screen/route boundaries (demo-friendly recap)"),t("--all","full ring (ignore the per-identity cursor)"),t("--since <duration>","absolute window; accepts e.g. 5s, 500ms, 2m"),t("--kinds <csv>","filter to specific kinds: toast, keyboard, screen, alert, fetch, console, ..."),t("--limit <n>","cap returned events (default 200)"),t("--json","emit structured JSON"),t("--no-advance","do not advance the read cursor after rendering"),t("--noisy","include react-commit, layout, and scroll events (suppressed by default so taps/fetches/screen transitions are not buried)"),t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim what-happened","since the previous CLI call"),e("sootsim what-happened --summary","5 errors \xB7 2 warnings \xB7 1 toast"),e("sootsim what-happened --kinds toast,fetch --since 10s","trace a toast back to its trigger"),e("sootsim what-happened --flow --since 5m","section the last 5 minutes by screen/route \u2014 demo-friendly recap"),e("sootsim what-happened --all --json","dump full ring as JSON")],related:["timeline","debug","logs","network"]},{id:"timeline",slug:"timeline",navTitle:"timeline",title:"sootsim timeline",description:"control the semantic event timeline (enable opt-in kinds, clear, dump)",summary:"Distinct from `sootsim record` (video) and `sootsim debug record` (engine channels): manages the semantic agent-facing event stream that backs `sootsim what-happened`. Cheap kinds record at all times; opt-in kinds (scroll, gesture, text-input, reanimated, animation) need to be enabled.",order:92,usage:["sootsim timeline <subcommand> [args]"],options:[t("--sim <sim>","target a specific connected sim"),t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--json","emit compact JSON for machine consumption")],examples:[e("sootsim timeline status"),e("sootsim timeline start scroll,gesture","enable opt-in kinds"),e("sootsim timeline stop all","silence everything"),e("sootsim timeline dump /tmp/events.json")],related:["what-happened","debug","record"]},{id:"open",slug:"open",navTitle:"open",title:"sootsim open",description:"load a target into the current sim or open a new one",summary:"Resolve a port, dev-server URL, bundle URL, full shell URL, or app deep link. Ports and bundle targets load into a sim; custom-scheme URLs and leading-slash routes dispatch through the current app\u2019s React Native Linking pipeline. Fresh sims open in a separate window. Named profiles force a fresh Electron or Playwright sim because storage isolation is fixed at window/context construction time. A SootSim preview/build link (e.g. https://sootsim.com/preview/<id>) is a full player page, not a driveable sim \u2014 `open` recognizes it and launches it in your browser for viewing instead of mis-loading the HTML as a bundle.",order:100,usage:["sootsim open <port|target|bundle-url|sootsim-url|deeplink> [--new]"],options:[t("--new","open a fresh sim instead of reusing the current sim"),t("--profile <id>","open with an isolated persistent storage profile"),t("--ephemeral","open with a temporary isolated storage profile"),t("--driver <id>","launch through a specific driver (electron and playwright support profiles)"),t("--headless","pass headless=true to the launch driver (useful with `--driver playwright` for CI runs)"),t("--cdp-port <number>","expose Chrome remote debugging on this port so the sim can be cpu-profiled while still driveable over the bridge (playwright driver only)"),t("--browser <engine>","playwright engine: chromium (default), webkit, or firefox. webkit is the iOS Safari proxy \u2014 headless webkit renders on the real Apple GPU while headless chromium software-rasterizes canvas/WebGL"),t("--device <model>","device profile for the opened sim (e.g. iphone-16, iphone-16-pro-max, pixel-8). stamped on the engine URL so every open path honors it; playwright sims also size their viewport to the device instead of a desktop-shaped default"),t("--base-url <url>","base shell URL to wrap around bundle targets"),t("--replace <module>=<file>","replace a Metro module with a local file for this run \u2014 useful for swapping in a deterministic fixture component during demos. repeatable"),t("--remap <host:port>=<host:port>","rewrite guest-app fetch/websocket traffic from one host:port to another for this run (e.g. a third-party e2e suite that hardcodes a port already taken on the host). repeatable"),t("--no-describe","skip the automatic `describe` snapshot that prints right after open finishes (useful when scripting and you only want open's own output)"),t("--hot","force metro HMR on (sets `hot=true` on the bundle URL). default for interactive opens \u2014 edits hot-apply through sootsim's HmrClient"),t("--no-hmr","force metro HMR off (sets `hot=false` on the bundle URL). default under `--driver playwright` so agent/CI runs stay deterministic with no in-bundle refresh wiring"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim open 8081"),e("sootsim open --new 8085"),e("sootsim open 8081 --profile qa"),e("sootsim open 8081 --profile qa --driver playwright"),e("sootsim open http://localhost:8082"),e("sootsim open /settings","dispatch a route deep link to the current app"),e("sootsim open myapp://settings/profile"),e("sootsim open 8081 --driver playwright --headless","headless CI / scripted runs"),e("sootsim open 8081 --new --driver playwright --browser webkit --device iphone-16","iOS Safari proxy on a pinned device profile (cross-browser comparisons need the same device)"),e("sootsim open 8089 --new --driver playwright --cdp-port 9222","open a sim that is both driveable and cpu-profilable (then `sootsim perf cpu --cdp-port 9222`)"),e("sootsim open 8081 --no-describe","silent open for scripts"),e("sootsim open 8081 --no-hmr","open with metro HMR off (e.g. when reproducing a non-HMR boot path)"),e("sootsim open 8081 --driver playwright --hot","driver playwright but keep HMR on (e.g. recording an edit-driven demo)"),e("sootsim open https://sootsim.com/preview/<id>","opens a preview/build link in the browser for viewing (not a driveable sim)")],related:["list","use","close","desktop"]},{id:"list",slug:"list",navTitle:"list",title:"sootsim list",description:"list connected sims or available launch drivers",summary:"Show every connected sim, or \u2014 with `--drivers` \u2014 enumerate the launch drivers (chromium, electron, playwright, system) along with their availability on the current machine. By default hides idle host shells (open tabs with no app bundle loaded) so the output stays focused on the demos that actually have an app running; pass `--all` to see everything.",order:110,usage:["sootsim list [--all] [--bundle <substr>] [--app-port <port>] [--primary] [--sim <sim>] [--json]","sootsim list --drivers"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","highlight a specific sim in the output"),t("--all","show every connected sim, including idle host shells with no app loaded"),t("--bundle <substring>","only sims whose loaded url contains this substring"),t("--app-port <port>","shorthand for `--bundle '/rn/<port>'` \u2014 filter to sims for the app on a specific metro/vite port. NOT `--port` (that's reserved for the bridge port)"),t("--primary","only the primary sim"),t("--drivers, -D","list available launch drivers instead of connected sims"),t("--json","emit array of sim objects for scripts")],examples:[e("sootsim list"),e("sootsim list --all","include idle host shells"),e("sootsim list --app-port 8082","only sims running the app on port 8082"),e("sootsim list --bundle bluesky","sims whose bundle url mentions bluesky"),e("sootsim list --primary"),e("sootsim list --sim a6"),e("sootsim list --drivers","show every installable launch driver"),e('sootsim list --json | jq ".[] | select(.active)"')],related:["open","use","close","inspect"]},{id:"use",slug:"use",navTitle:"use",title:"sootsim use",description:"select a connected sim",summary:"Make one connected sim current by focusing it and saving it as the default target for later bridge-backed commands.",order:120,usage:["sootsim use [sim]"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","target a specific connected sim")],examples:[e("sootsim use"),e("sootsim use a6")],related:["list","open","close"]},{id:"claim",slug:"claim",navTitle:"claim",title:"sootsim claim",description:"take an exclusive lease on a sim",summary:"Reserve a connected sim so other agents cannot send commands to it. Leases auto-expire after 60s of inactivity and refresh on every command from the owner. Prefer `sootsim open --new` over `claim --force` when another agent is active \u2014 the latter steals the lease mid-flight and breaks the other agent's in-progress flow.",order:125,usage:["sootsim claim [sim] [--force]"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","target a specific connected sim"),t("--force","steal the lease from whoever currently holds it. only safe when you know the other holder is dead or abandoned \u2014 prefer `sootsim open --new` to get a fresh sim instead")],examples:[e("sootsim claim"),e("sootsim claim a6"),e("sootsim claim a6 --force","last-resort lease steal \u2014 see `sootsim open --new` for the safer alternative")],related:["list","use","open","close"]},{id:"close",slug:"close",navTitle:"close",title:"sootsim close",description:"close a connected sim",summary:"Request that a sim close itself over the bridge and wait for it to disappear from the sim registry.",order:130,usage:["sootsim close [sim]","sootsim close --all","sootsim close --others"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("--sim <sim>","target a specific connected sim"),t("--all","close every connected sim"),t("--others","close every connected sim except the current/target one")],examples:[e("sootsim close"),e("sootsim close a6"),e("sootsim close --all"),e("sootsim close --others")],related:["list","use"]},{id:"setup",slug:"setup",navTitle:"setup",title:"sootsim setup",description:"bootstrap SootSim, then install the global CLI",summary:"Run the guided machine setup. It asks which package manager you use for app commands, explains repo-pinned Node versions, recommends installing `sootsim` globally, and offers the background daemon so every CLI command can reuse the same bridge instead of spinning up a server. No per-app SootSim install or iOS native build is required; run Metro/Expo/One normally, then open it with `sootsim open`.",order:140,usage:["sootsim setup [options]"],options:[t("--app <dir>","project directory to inspect (default: current directory)"),t("-y, --yes","accept the recommended setup steps without prompting"),t("--dry-run","show what setup would offer without changing files")],examples:[e("sootsim setup"),e("sootsim setup --app ./apps/mobile"),e("sootsim setup --dry-run"),e("sootsim setup --yes")],related:["open","daemon","serve","compat"]},{id:"compat",slug:"compat",navTitle:"compat",title:"sootsim compat",description:"check package compatibility",summary:"Scan a project or specific dependency against the compat registry and summarize where native packages are fully supported, partially shimmed, or still risky.",order:150,usage:["sootsim compat [package-name]"],options:[t("--json","emit machine-readable JSON"),t("--brief","print a compact one-line summary"),t("--app <dir>","scan a target app directory instead of cwd")],examples:[e("sootsim compat"),e("sootsim compat react-native-reanimated"),e("sootsim compat --brief")],related:["setup"]},{id:"desktop",slug:"desktop",navTitle:"desktop",title:"sootsim desktop",description:"launch or install the desktop companion",summary:"Launch the optional desktop companion from the global CLI, or install it when missing. Profiles map to Electron partitions, so cookies and app storage stay isolated per profile.",order:160,usage:["sootsim desktop [--port <number>] [--profile <id>] [--driver <id>]","sootsim desktop install [options]"],options:[t("--port <number>","open a local app server through the sootsim shell, for example Metro on 8081"),t("--profile <id>","launch with an isolated persistent storage profile"),t("--ephemeral","launch with a temporary isolated storage profile"),t("--driver <id>","override the launch driver (electron|chromium|playwright|system)"),t("-y, --yes","for install: skip confirmation and install immediately"),t("--force","for install: reinstall even if the companion is present")],examples:[e("sootsim desktop"),e("sootsim desktop --port 8081"),e("sootsim desktop --profile qa"),e("sootsim desktop --driver system","fall back to the OS default browser"),e("sootsim desktop install --yes")],related:["open","list","debug"]},{id:"daemon",slug:"daemon",navTitle:"daemon",title:"sootsim daemon",description:"manage the sootsim bridge as a login agent",summary:"`sootsim setup` installs the background daemon. This command inspects, restarts, starts, stops, tails logs for, or uninstalls that existing login agent. `sootsim daemon uninstall` is the clean-teardown path \u2014 it stops + removes the launchd/systemd agent AND deletes the ~/.sootsim cache (runtimes, profiles, lockfile).",order:173,usage:["sootsim daemon uninstall","sootsim daemon status","sootsim daemon restart","sootsim daemon start","sootsim daemon stop","sootsim daemon logs [-n <lines>] [-f]"],options:[t("-n, --lines <n>","number of log lines to show (default 200)"),t("-f, --follow","stream new log lines as they arrive")],examples:[e("sootsim daemon status","is the bridge daemon registered + alive?"),e("sootsim daemon restart","kick the daemon (after a CLI upgrade, etc.)"),e("sootsim daemon logs -n 100","tail the last 100 daemon log lines"),e("sootsim daemon uninstall","clean teardown \u2014 remove the launchd/systemd agent + ~/.sootsim cache")],related:["setup","serve","open"]},{id:"serve",slug:"serve",navTitle:"serve",title:"sootsim serve",description:"run the sootsim bridge in the foreground",summary:"Host the WS bridge in the foreground. This is mainly for development or diagnosis; the recommended path is `sootsim open`, which starts a local bridge when needed, and `sootsim setup`, which installs the faster background daemon.",order:175,usage:["sootsim serve [options]"],options:[t("--port <number>","bridge port (defaults to {{bridgePort}})"),t("-q, --quiet","suppress per-connection logging")],examples:[e("sootsim serve"),e("sootsim serve --quiet"),e("sootsim serve --port 7668")],related:["setup","daemon","open"]},{id:"runtime",slug:"runtime",navTitle:"runtime",title:"sootsim runtime",description:"manage engine runtimes under ~/.sootsim/runtimes/",summary:"Install, list, switch, and remove versioned sootsim engine runtimes. The CLI downloads a tarball from the configured CDN (default sootbean.com \u2014 override with `SOOTSIM_CDN_ORIGIN`), verifies its sha256, and extracts it. The daemon serves the active runtime to Electron and the browser shell. `sootsim runtime notes` prints the hosted changelog URL.",order:176,usage:["sootsim runtime install [version]","sootsim runtime list","sootsim runtime use <version>","sootsim runtime remove <version>","sootsim runtime which","sootsim runtime notes"],options:[t("--channel <name>","channel for 'latest' (default: stable)"),t("--force","reinstall even if already on disk"),t("--no-set-active","don't switch active runtime after install (also accepts --set-active=false)")],examples:[e("sootsim runtime install"),e("sootsim runtime install 1.2.3"),e("sootsim runtime install --channel beta","install the latest from a non-stable channel"),e("sootsim runtime use 1.2.3"),e("sootsim runtime list","show installed + available versions"),e("sootsim runtime which","print the currently active runtime version"),e("sootsim runtime notes","print the hosted release notes URL"),e("sootsim runtime remove 1.2.2")],related:["setup","serve","daemon","version"]},{id:"upgrade",slug:"upgrade",navTitle:"upgrade",title:"sootsim upgrade",description:"update the sootsim CLI and engine runtime to the latest",summary:'One command to get current. Checks the npm registry for a newer `sootsim` CLI and, when the CLI half is behind, tells you to run `sootsim@latest`. It then checks the runtime channel and installs + activates the latest engine runtime. Safe to run anytime \u2014 each half is skipped when already up to date. The CLI and engine runtime are versioned independently, which is a frequent source of "I ran upgrade but the version did not change" confusion \u2014 this command checks both.',order:174,usage:["sootsim upgrade [--channel <name>]"],options:[t("--channel <name>","runtime channel for 'latest' (default: stable)")],examples:[e("sootsim upgrade"),e("sootsim upgrade --channel beta","install the latest engine runtime from the beta channel")],related:["runtime","setup","version"]},{id:"version",slug:"version",navTitle:"version",title:"sootsim version",description:"show the CLI + engine runtime versions you are running",summary:'A one-look overview of both independently-versioned halves: the `sootsim` CLI (npm package) and the engine runtime (the versioned tarball rendered in the browser/electron shell). Adds the active channel, a "newer runtime available" hint, and a what\'s-new pointer to `sootsim runtime notes`. The terse `sootsim --version` flag prints the two version lines for scripts; this command adds the surrounding context.',order:173,usage:["sootsim version"],options:[],examples:[e("sootsim version"),e("sootsim --version","terse, script-parseable")],related:["upgrade","runtime"]},{id:"maestro",slug:"maestro",navTitle:"maestro",title:"sootsim maestro",description:"run existing Maestro YAML flows against sootsim",summary:"Drop-in replacement for the Maestro CLI. Runs real `.maestro/*.yaml` flows against a sim \u2014 supports all three Maestro shapes (plain array, frontmatter, multi-doc). Flag surface mirrors the Maestro CLI for easy migration.",order:41,usage:["sootsim maestro [test] <flow-or-dir> [options]","sootsim maestro # auto-discovers ./.maestro/","sootsim maestro init # scaffold a starter flow","sootsim maestro --list-compat"],options:[t("--env KEY=VALUE","set env vars for ${KEY} interpolation (repeatable)"),t("--continuous","re-run the flow on file changes (alias for --watch)"),t("--format <fmt>","accepted for maestro cli compat (not used)"),t("--new","force a fresh sim for this run"),t("--headed","force a fresh, VISIBLE window (implies --new, overrides --headless) \u2014 watch the flow run live"),t("--record","record a webm while the flow runs"),t("--preview","record events+video, upload, and print /preview/<id>"),t("--preview-open","open the uploaded preview link after a successful run"),t("--preview-origin <url>","upload target for --preview"),t("--preview-public-origin <url>","public link origin for --preview"),t("--slow <ms>","delay between steps for natural pacing"),t("--list-compat","print supported and unsupported Maestro verbs")],examples:[e("sootsim maestro test .maestro/login.yaml"),e("sootsim maestro --env USERNAME=alice test .maestro/login.yaml"),e("sootsim maestro test .maestro/flow.yaml --record"),e("sootsim maestro --list-compat")],related:["flow","detox","test","record"]},{id:"detox",slug:"detox",navTitle:"detox",title:"sootsim detox",description:"run existing Detox suites against sootsim on headless Chromium",summary:"Drop-in Detox runner. Existing `import from 'detox'` suites run unchanged via a Jest `moduleNameMapper` rewrite \u2014 no code edits, no config churn. Auto-launches a sootsim shell if none is running.",order:42,usage:["sootsim detox [options] [-- <jest args>]"],options:[t("--config <path>","use a specific jest config instead of the default"),t("--watch","jest watch mode"),t("--headed","keep the sootsim shell window visible"),t("-t <pattern>","pass a Jest --testNamePattern"),t("--no-launch","skip auto-launching a sootsim shell (manage it yourself)")],examples:[e("sootsim detox"),e("sootsim detox --watch"),e('sootsim detox -t "login flow"'),e("sootsim detox --headed","keep the shell visible while iterating on a failing suite")],related:["maestro","flow","test"]},{id:"device",slug:"device",navTitle:"device",title:"sootsim device",description:"inspect or change the live device preset for a sim",summary:"Read the current device preset, switch it on the fly, or list the available models. Switching a preset reshapes the running sim \u2014 screen size, density, and chrome \u2014 without restarting the bundle.",order:78,usage:["sootsim device","sootsim device get","sootsim device set <model> [--sim <id>]","sootsim device list"],options:[t("--sim <sim>","target a specific connected sim when setting"),t("--port <number>","bridge port (defaults to {{bridgePort}})")],examples:[e("sootsim device","show the active device preset"),e("sootsim device list","list every available model id"),e("sootsim device set iphone-14"),e("sootsim device set iphone-16-pro-max --sim a7")],related:["mode","screenshot","open","list"]},{id:"skill",slug:"skill",navTitle:"skill",title:"sootsim skill",description:"install and inspect bundled SootSim agent skills",summary:"Install bundled SootSim agent skills into agent-compatible skill directories, or print the bundled skill markdown. `install` defaults to all supported local agent homes; pass `codex` or `claude` to target one.",order:122,usage:["sootsim skill install [all|codex|claude] [skill-name...]","sootsim skill install --target <dir> [skill-name...]","sootsim skill show [skill-name]"],options:[t("install","install skills; no target means all supported local agents"),t("show","list bundled skills, or print one skill markdown"),t("--target <dir>","install into an explicit skill directory")],examples:[e("sootsim skill install"),e("sootsim skill install codex"),e("sootsim skill install codex sootsim-debug"),e("sootsim skill show"),e("sootsim skill show sootsim-debug")],related:["inspect","debug"]},{id:"agent",slug:"agent",navTitle:"agent",title:"sootsim agent",description:"attached projects + local agent sessions (codex/claude)",summary:"Manage attached project directories and the agent sessions running inside them. Session-lifecycle commands (start, prompt, watch, end) route through the bridge daemon, which owns the single FIFO reader per session so concurrent cli watches + electron UI subscribers no longer steal bytes from each other. Disk-only inspection commands (projects, sessions, paths, transcript) read attached-project state directly \u2014 no daemon needed.",order:125,usage:["sootsim agent attach <dir> [--name <label>] [--provider codex|claude]","sootsim agent projects","sootsim agent project show <id>","sootsim agent project remove <id>","sootsim agent sessions [--project <id>] [--all]","sootsim agent start <projectId> [--provider codex|claude]",'sootsim agent prompt <sessionId> "<text>"',"sootsim agent watch <sessionId>","sootsim agent transcript <sessionId>","sootsim agent end <sessionId>","sootsim agent paths"],options:[t("--name <label>","human-readable label when attaching a project"),t("--provider <id>","agent backend: codex (default) or claude \u2014 used by attach + start"),t("--project <id>","filter sessions to a specific attached project"),t("--all","include ended sessions (sessions defaults to active only)")],examples:[e("sootsim agent attach ~/projects/three-punch --name 3pc"),e("sootsim agent projects","list every attached project"),e("sootsim agent project show 3pc"),e("sootsim agent start 3pc --provider claude","spawn a wrapper session (detached) inside the attached project"),e('sootsim agent prompt <sessionId> "fix the failing scroll test"',"enqueue a prompt \u2014 the daemon delivers it to the wrapper"),e("sootsim agent watch <sessionId>","tail events.out pretty-printed"),e("sootsim agent sessions --all","include ended sessions in the list"),e("sootsim agent transcript <sessionId>"),e("sootsim agent end <sessionId>"),e("sootsim agent paths","print userData + state file locations")],related:["skill","auth","login"]},{id:"auth",slug:"auth",navTitle:"auth",title:"sootsim auth",description:"inspect active CLI auth",summary:"Print the auth source the CLI will use. API keys are not managed by the CLI; pass them via SOOTSIM_API_KEY when CI or a headless script needs one. Use `sootsim login` and `sootsim logout` for the browser-backed desktop session.",order:190,usage:["sootsim auth"],options:[t("SOOTSIM_API_KEY","env var for API-key auth; no local key file is read")],examples:[e("sootsim auth","show the active auth source")],related:["login","logout","record","flow"]},{id:"login",slug:"login",navTitle:"login",title:"sootsim login",description:"sign in for preview uploads",summary:"Sign in with the browser-backed desktop session so uploads and App Store screenshot capture can attach to your account. Local development origins use the dev-login fast path; CI should pass SOOTSIM_API_KEY instead.",order:191,usage:["sootsim login [--origin <url>]"],options:[t("--origin <url>","auth host (default: auto; prefers localhost:3000 when available)")],examples:[e("sootsim login"),e("sootsim login --origin http://localhost:3000")],related:["auth","logout","record","flow"]},{id:"logout",slug:"logout",navTitle:"logout",title:"sootsim logout",description:"clear the local desktop auth session",summary:"Clear the browser-backed desktop session written by `sootsim login`. SOOTSIM_API_KEY and GitHub runner auth are environment-provided and are not affected.",order:192,usage:["sootsim logout"],examples:[e("sootsim logout")],related:["auth","login"]},{id:"config",slug:"config",navTitle:"config",title:"sootsim config",description:"manage local CLI preferences",summary:"Manage local preferences that affect the CLI and desktop companion. Telemetry is persisted in ~/.sootsim/config.json. CLI hints are intentionally not a command surface; set SOOTSIM_HINTS=off to suppress them.",order:195,usage:["sootsim config telemetry [on|off|status]"],examples:[e("sootsim config telemetry","show the current opt-out state and config path"),e("sootsim config telemetry off","disable CLI + desktop analytics on this machine"),e("SOOTSIM_HINTS=off sootsim describe","suppress hints for a single run")],related:["auth"]}],ae=new Map(D.map(o=>[o.id,o])),L=new Map;for(let o of D){L.set(o.id,o);for(let s of o.aliases||[])L.set(s,o)}function j(o){return L.get(o)}function i(o,s,a,l,r,n){return{verb:o,description:s,usage:a,examples:l,notes:r,...n}}var R=[i("describe","show visible UI elements with type, text, position, size, and style. filters structural noise by default \u2014 use --all to include everything.",["sootsim describe [filter] [--verbose] [--watch] [--all] [--json] [--no-clipped] [--compact] [--no-xy] [--only <glob>] [--subtree <id>] [--testid-like <pat>]"],[e("sootsim describe"),e("sootsim describe button"),e("sootsim describe --verbose"),e("sootsim describe --all"),e("sootsim describe --json"),e("sootsim describe --watch"),e("sootsim describe --no-clipped","hide rows annotated (clipped:left|right|top|bottom) \u2014 useful on screens dominated by edge-pulled chrome or off-screen list items"),e("sootsim describe --compact --no-xy","tighter tree without coords"),e("sootsim describe --subtree feedListRoot","limit the dump to a subtree rooted at testID feedListRoot"),e('sootsim describe --only "*Header*"',"glob-match across text/role/testID"),e("sootsim describe --testid-like login",'fuzzy-match nodes whose testID contains "login"')],"buttons show [button], tappable views show [tap], inputs show [input]. structural noise (icon wrappers, layout containers, duplicate text inside buttons) is pruned by default. use --all for the unfiltered view.",{shortDescription:"curated human-readable UI summary (default inspection tool)",options:[t("--verbose","include ids, labels, and extra style info"),t("--all","do not prune structural view nodes"),t("--watch","redraw as the UI changes (ctrl-c to stop)"),t("--json","emit structured JSON"),t("--no-clipped","strip rows annotated (clipped:left|right|top|bottom) \u2014 keeps the on-screen state from being buried"),t("--compact","render the tree in a tighter format"),t("--no-xy","hide x,y coordinates from each row"),t("--only <glob>","glob filter across text/role/testID \u2014 preferred when the bare positional would be ambiguous"),t("--subtree <id>","limit the dump to a subtree rooted at the given testID"),t("--testid-like <pattern>","fuzzy-match nodes whose testID contains the pattern (substring + case-insensitive)")],seeAlso:["tree","a11y","find"]}),i("find","unified finder (text, testid, role, type, pressable, visible, interactive-targets)",["sootsim find <text>","sootsim find --text <text>","sootsim find --testid <id>","sootsim find --role <role>","sootsim find --type <component-type>","sootsim find --pressable","sootsim find --visible","sootsim find --interactive-targets"],[e('sootsim find "Sign in"'),e("sootsim find --testid loginButton"),e("sootsim find --role button"),e("sootsim find --pressable"),e("sootsim find --visible --json"),e("sootsim find --testid loginButton --verbose"),e("sootsim find --interactive-targets","ranked list of visible+pressable nodes with copy-paste tap commands"),e("sootsim find --actions","alias for --interactive-targets")],"bare text matches findByText. flag-based forms replace the old `find-id` and `query <predicate>` subcommands. use --verbose to dump the full node JSON for each result instead of the one-liner summary. `--interactive-targets` (alias `--actions`) ranks visible+pressable nodes and emits a `sootsim do tap-...` command per row so the agent's next tap is one copy away.",{shortDescription:"locate nodes by text / testID / role / type / predicate",options:[t("--text <text>","match node text content (same as bare positional)"),t("--testid <id>","match node testID or id exactly"),t("--role <role>","match accessibilityRole"),t("--type <type>","match React component type"),t("--pressable","list all tappable nodes"),t("--visible","list all visible (non-zero) nodes"),t("--interactive-targets, --actions",'ranked tappable nodes with per-row tap command (best demo "next tap" picker)'),t("--verbose, --dump","emit full node JSON for each result, not a one-liner"),t("--json","emit structured JSON")],seeAlso:["describe","node","selector"]}),i("count","show total node count",["sootsim get count [--json]"],[e("sootsim get count"),e("sootsim get count --json")],void 0,{group:"get",subgroup:"tree",shortDescription:"total node count",options:[t("--json","emit { nodes: n } for scripts")]}),i("layout","measure layout \u2014 bare for every visible element on the screen (box + radius/padding/fontSize), or with an id for one node",["sootsim get layout [id] [--json]"],[e("sootsim get layout","every visible element: on-screen box (x/y/w/h) + borderRadius, per-side padding, fontSize"),e("sootsim get layout --json","machine-readable { count, elements }"),e("sootsim get layout loginButton","single node {x, y, width, height} by id/testID")],"bare `get layout` is the screen-wide measurement designers reach for to check spacing/sizing/radius/type-scale parity \u2014 more detailed than describe, which gives the element tree but not these numbers. it runs the same shared extractor as the agent app_get_layout tool, so CLI and agent output match. pass an id for the single-node layout lookup.",{group:"get",subgroup:"tree",shortDescription:"screen-wide box + radius/padding/fontSize (or one node by id)",options:[t("--json","emit { count, elements } for scripts")],seeAlso:["describe","find","node"]}),i("tree","dump the node tree",["sootsim get tree [depth] [--json]"],[e("sootsim get tree"),e("sootsim get tree 3"),e("sootsim get tree --json")],"raw, depth-limited tree dump. good for machine consumption and debugging when describe has filtered something out. for day-to-day inspection prefer describe.",{group:"get",subgroup:"tree",shortDescription:"raw node tree dump (default depth 5)",options:[t("--json","emit { depth, tree } for scripts")],seeAlso:["describe","a11y","node"]}),i("a11y","dump the accessibility tree with roles and labels",["sootsim get a11y [depth]"],[e("sootsim get a11y")],"only accessibility-relevant fields (role, label, hint). for general inspection use describe; for raw tree use get tree.",{group:"get",subgroup:"tree",shortDescription:"accessibility tree (roles, labels, hints)",seeAlso:["describe","tree"]}),i("node","resolve testID/id/text to a full node JSON",["sootsim get node <matcher>"],[e("sootsim get node loginButton"),e('sootsim get node "Sign in"')],void 0,{group:"get",subgroup:"tree",shortDescription:"resolve testID \u2192 id \u2192 text, full node JSON",seeAlso:["find","layout"]}),i("tap","tap at absolute coordinates, or resolve --testid / --text to a node center",["sootsim do tap <x> <y>","sootsim do tap --testid <id>","sootsim do tap --text <text>"],[e("sootsim do tap 196 400"),e("sootsim do tap --testid loginButton"),e('sootsim do tap --text "Sign in"')],"uses the internal interaction bridge (fireTap), not real PointerEvent dispatch. for gesture-handler debugging, use drag/swipe which dispatch real pointer events. --testid and --text also work on double-tap and long-press.",{group:"do",subgroup:"targeting",shortDescription:"tap absolute coords, or a node by --testid / --text",seeAlso:["tap-id","tap-text","double-tap","long-press"],order:10}),i("double-tap","tap the same spot twice with a short gap",["sootsim do double-tap <x> <y> [gapMs]","sootsim do double-tap --testid <id> [gapMs]"],[e("sootsim do double-tap 196 400"),e("sootsim do double-tap --testid myButton 80")],"uses the shared interact bridge so text selection and other double-tap gestures run through the same path as live taps.",{group:"do",subgroup:"targeting",shortDescription:"tap the same coordinates twice quickly",seeAlso:["tap"],order:20}),i("tap-text","find a node by text content and tap its center",["sootsim do tap-text <text> [--nth <n>] [--within <testID>]"," [--min-y <px>] [--max-y <px>] [--min-x <px>] [--max-x <px>]"," [--near <x> <y>] [--exact] [--role <role>] [--first]"],[e('sootsim do tap-text "Sign in"'),e("sootsim do tap-text Swap --within sheet-container"),e("sootsim do tap-text Swap --min-y 700"),e("sootsim do tap-text Cancel --nth 2"),e("sootsim do tap-text OK --near 283 784")],"errors with a ranked candidate list (testID + abs position + ancestor chain) when more than one visible match remains after filters, instead of silently picking one. pass --first to keep the old behavior.",{group:"do",subgroup:"targeting",shortDescription:"findByText then tap (rich disambiguation flags)",options:[t("--nth <n>","pick the nth visible match (supports -1)"),t("--within <testID>","descendants of a testID ancestor only"),t("--min-y <px>","absolute y-position floor"),t("--max-y <px>","absolute y-position ceiling"),t("--min-x <px>","absolute x-position floor"),t("--max-x <px>","absolute x-position ceiling"),t("--near <x> <y>","pick the closest match to a coordinate"),t("--exact","exact text match (default: substring)"),t("--role <role>","narrow to accessibilityRole"),t("--first","keep legacy pick-first-silently behavior")],seeAlso:["tap","tap-id","find"],order:30}),i("tap-id","find a node by testID and tap its center",["sootsim do tap-id <id>"],[e("sootsim do tap-id loginButton")],void 0,{group:"do",subgroup:"targeting",shortDescription:"findByTestId then tap center",seeAlso:["tap","tap-text","tap-best"],order:40}),i("tap-best","tap by query: try testID first, then visible text \u2014 one command, two strategies",["sootsim do tap-best <query>"],[e('sootsim do tap-best "Create expense"',`agent doesn't need to know whether "Create expense" is a testID or text`),e("sootsim do tap-best floating-action-button")],"designed for agent ergonomics: when you have a label and don't know whether it's the testID or the visible text, tap-best tries findByTestId first (strongest signal), then findByText. prints which strategy matched. for ambiguity (multiple text matches) use tap-text with --nth / --within instead \u2014 tap-best fails fast and points you there.",{group:"do",subgroup:"targeting",shortDescription:"testID-first, text-fallback robust tap",seeAlso:["tap-id","tap-text","find"],order:41}),i("scan","inject a synthetic barcode scan into the active expo-camera scan session",["sootsim do scan <text> [--format <web-format>]"],[e('sootsim do scan "https://example.com/pair/abc123"'),e('sootsim do scan "myapp://connect?token=abc" --format qr_code',"drive a connect-by-QR flow")],"fails when no guest CameraView is actively scanning. the event flows through the same host \u2192 worker \u2192 native seam path as a real BarcodeDetector hit.",{group:"do",subgroup:"native device",shortDescription:"inject a barcode scan into active camera scanning",options:[t("--format <f>","BarcodeDetector format string (default: qr_code)")],seeAlso:["tap","wait"],order:10}),i("type","type text through the iOS keyboard (requires a focused input)",["sootsim do type <text>"],[e('sootsim do type "hello world"')],"a text input must be focused first via tap-id or tap-text. if no input is focused, this silently does nothing.",{group:"do",subgroup:"text input",shortDescription:"type through the iOS visual keyboard",seeAlso:["type-into","key","dismiss"],order:10}),i("type-into","find an input by testID, tap to focus, then type text",["sootsim do type-into <id> <text>"],[e('sootsim do type-into kav-input "hello world"')],"combines tap-id + type in one command. warns if the target is not a text input or if the keyboard did not open.",{group:"do",subgroup:"text input",shortDescription:"focus input by testID then type",seeAlso:["type","tap-id"],order:20}),i("key","press a special keyboard key",["sootsim do key <name>"],[e("sootsim do key return"),e("sootsim do key delete")],"valid keys: return, delete, space, shift, 123, ABC, #+=, num-back",{group:"do",subgroup:"text input",shortDescription:"special key (return, delete, space, shift, ...)",seeAlso:["key-sequence","keycode"],order:30}),i("key-sequence","press multiple visual keyboard keys in order",["sootsim do key-sequence <key> [<key> ...]"],[e("sootsim do key-sequence shift h i")],void 0,{group:"do",subgroup:"text input",shortDescription:"press multiple visual keyboard keys",seeAlso:["key","keycode"],order:40}),i("keycode","press DOM-style key codes through the visual keyboard",["sootsim do keycode <code> [<code> ...]"],[e("sootsim do keycode ShiftLeft KeyH KeyI")],void 0,{group:"do",subgroup:"text input",shortDescription:"press DOM-style key codes via visual keyboard",seeAlso:["key","key-sequence"],order:50}),i("dismiss","dismiss the keyboard",["sootsim do dismiss"],void 0,void 0,{group:"do",subgroup:"text input",shortDescription:"dismiss the iOS keyboard",order:60}),i("scroll","scroll a scrollview by testID or inspect node id",["sootsim do scroll <id> <x> <y>","sootsim do scroll --testid <id> <x> <y>","sootsim do scroll --node-id <nodeId> <x> <y>"],[e("sootsim do scroll feed-list 0 500"),e("sootsim do scroll --testid feed-list 0 500"),e("sootsim do scroll --node-id 3027 0 1200")],void 0,{group:"do",subgroup:"gestures",shortDescription:"scroll a ScrollView by testID or inspect node id",seeAlso:["gesture","swipe"],order:10}),i("drag","drag from one point to another using real PointerEvent dispatch",["sootsim do drag <x1> <y1> <x2> <y2> [steps] [stepMs]"],[e("sootsim do drag 200 400 200 200 20 16")],"dispatches real PointerEvents to the canvas, unlike tap which uses the internal bridge. use this for gesture-handler and responder chain debugging.",{group:"do",subgroup:"gestures",shortDescription:"drag via real PointerEvents",seeAlso:["swipe","touch","pinch"],order:20}),i("swipe","swipe gesture (drag with fewer steps)",["sootsim do swipe <x1> <y1> <x2> <y2> [steps] [stepMs]"],[e("sootsim do swipe 350 400 50 400 10 16")],void 0,{group:"do",subgroup:"gestures",shortDescription:"drag with faster defaults",seeAlso:["drag","gesture"],order:30}),i("long-press","hold a press at coordinates",["sootsim do long-press <x> <y> [durationMs]","sootsim do long-press --testid <id> [durationMs]"],[e("sootsim do long-press 196 400 600"),e("sootsim do long-press --testid myButton 600")],void 0,{group:"do",subgroup:"gestures",shortDescription:"hold a press at coordinates",seeAlso:["tap","gesture"],order:40}),i("touch","low-level touch primitives",["sootsim do touch <down|move|up|cancel> <x> <y> [pointerId]"],[e("sootsim do touch down 200 720 1"),e("sootsim do touch up 200 720 1")],void 0,{group:"do",subgroup:"gestures",shortDescription:"low-level touch primitives",seeAlso:["drag","pinch"],order:50}),i("gesture","preset gestures such as scrolls and edge swipes",["sootsim do gesture <preset> [durationMs]"],[e("sootsim do gesture swipe-from-bottom-edge"),e("sootsim do gesture scroll-up 250")],void 0,{group:"do",subgroup:"gestures",shortDescription:"preset gestures (scroll / edge swipes)",seeAlso:["swipe","scroll"],order:60}),i("pinch","two-pointer pinch helper",["sootsim do pinch <x1> <y1> <x2> <y2> <x1'> <y1'> <x2'> <y2'> [steps] [stepMs]"],[e("sootsim do pinch 120 320 280 320 90 320 310 320")],void 0,{group:"do",subgroup:"gestures",shortDescription:"two-pointer pinch helper",seeAlso:["touch","gesture"],order:70}),i("state","dump raw runtime state (shell, worker, keyboard, node, scroll, hit, gesture, ownership)",["sootsim debug state <kind> [args]","sootsim debug state shell","sootsim debug state keyboard","sootsim debug state node <id>","sootsim debug state hit <x> <y>","sootsim debug state gesture <x> <y>","sootsim debug state ownership"],[e("sootsim debug state shell"),e("sootsim debug state keyboard"),e("sootsim debug state node photos"),e("sootsim debug state hit 200 720"),e("sootsim debug state ownership",'authoritative surface-ownership + pointer-delivery snapshot \u2014 diagnose "which surface owns this region"')],void 0,{group:"debug",subgroup:"state",shortDescription:"runtime dumps (shell, worker, keyboard, hit, gesture, ownership, ...)",seeAlso:["js"]}),i("js","evaluate javascript in the browser context",["sootsim debug js <expression>"],[e("sootsim debug js SootSim.bridges.test.getNodeCount()"),e("sootsim debug js SootSim.bridges.keyboard.isVisible()"),e("sootsim debug js SootSim.state.root.children.length")],"reach into the SootSim global: bridges (test, debug, interact, keyboard, a11y, perf, ...), state (root, simId, ...), chrome (shell, headless, engineBase, ...).",{group:"debug",subgroup:"eval",shortDescription:"evaluate JS in the engine realm (reach into SootSim.*)",seeAlso:["eval","state"]}),i("eval","evaluate javascript (same as js)",["sootsim debug eval <expression>"],[e('sootsim debug eval "document.title"')],void 0,{group:"debug",subgroup:"eval",shortDescription:"alias for js",seeAlso:["js"]}),i("errors","show recent console errors",["sootsim get errors [n|clear] [--json]"],[e("sootsim get errors 5"),e("sootsim get errors clear"),e("sootsim get errors --json | jq length")],void 0,{group:"get",subgroup:"diagnostics",shortDescription:"console errors (default 20)",options:[t("--json","emit array of { timestamp, args, stack } for scripts")],seeAlso:["warnings","requests","logs"]}),i("warnings","show recent console warnings",["sootsim get warnings [n] [--json]"],[e("sootsim get warnings 5"),e("sootsim get warnings --json")],void 0,{group:"get",subgroup:"diagnostics",shortDescription:"console warnings (default 20)",options:[t("--json","emit array of { timestamp, args } for scripts")],seeAlso:["errors","logs"]}),i("requests","show recent failed network requests",["sootsim get requests [n|all n|clear] [--json]"],[e("sootsim get requests 5"),e("sootsim get requests all 10"),e("sootsim get requests --json")],void 0,{group:"get",subgroup:"diagnostics",shortDescription:"failed / all / clear request buffer",options:[t("--json","emit array of request entries for scripts")],seeAlso:["errors","network"]}),i("diagnosis",'composed "what just went wrong?" report',["sootsim get diagnosis [--since <duration>] [--include <csv>] [--json]"],[e("sootsim get diagnosis","last 90s, all dimensions"),e("sootsim get diagnosis --since 30s --include network,react"),e("sootsim get diagnosis --json > /tmp/diagnosis.json","structured snapshot for agent / CI consumption")],"runs timeline + network (failed/slow) + react summary + console errors in parallel against the same sim and returns a grouped report.",{group:"get",subgroup:"diagnostics",shortDescription:"timeline + network + react + console summary",options:[t("--since <duration>","absolute window, e.g. 90s or 2m (default 90s)"),t("--include <csv>","timeline, network, react, console, screen"),t("--slow-threshold <n>","network slow-request threshold in ms"),t("--limit <n>","rows to print per react table"),t("--json","emit one structured JSON document")],seeAlso:["errors","warnings","requests","network"]}),i("animations","list every active animation with id, kind, progress, and current value",["sootsim get animations","sootsim get animations --json"],[e("sootsim get animations","one line per running animation"),e("sootsim get animations --json | jq","structured for scripts")],'answers "what is moving right now?" without resorting to screenshots or debug eval. pair with `sootsim get animation <id>` for full spec, `sootsim do stop-animation <id>` to halt one, or `sootsim debug trace anim on <id>` for per-tick values.',{group:"get",subgroup:"animations",shortDescription:"list active animations",seeAlso:["animation","stop-animation","state"]}),i("animation","full detail for a single active animation by id",["sootsim get animation <id>"],[e("sootsim get animation 3","JSON spec + current value + progress")],"ids come from `sootsim get animations`. poll this to watch a single animation settle without enabling a trace.",{group:"get",subgroup:"animations",shortDescription:"single animation detail",seeAlso:["animations","stop-animation"]}),i("state","runtime dashboard: url, active animation counts, diagnostics, shell scene",["sootsim get state"],[e("sootsim get state","what is this sim doing right now")],'one-shot JSON snapshot answering "what is happening in this sim right now" \u2014 intended as the first call of a debugging pass. separate from `sootsim debug state <kind>`, which dumps raw runtime state for one subsystem.',{group:"get",subgroup:"diagnostics",shortDescription:"runtime dashboard snapshot",seeAlso:["animations","errors","keyboard"]}),i("memory","per-worker live object counts (nodes, paragraphs, yoga nodes, pictures, raster images) + image cache + JS heaps; --watch samples over time and reports per-counter slopes",["sootsim get memory","sootsim debug memory --watch [seconds] [--interval seconds]"],[e("sootsim get memory","one-shot tenant + shell + host snapshot"),e("sootsim debug memory --watch 120","sample every 5s for 2 min, then print which counters are climbing"),e("sootsim debug memory --watch 60 --interval 2 --json | jq .perSecond","machine-readable slopes for scripting")],"the memory-leak RCA instrument. counters are maintained at engine create/delete sites, so resources retained by discarded (unmounted) subtrees still show up \u2014 a climbing nodesRegistered/paragraphs while the on-screen tree is stable means unmounted nodes are being retained. tenant and shell workers report independently (the shell paints the app:* mirror trees). heaps are chrome-only (webkit omits performance.memory).",{group:"debug",subgroup:"profiling",shortDescription:"live object counts + heap sampler",options:[t("--watch [seconds]","sample repeatedly for N seconds (default 60)"),t("--interval <seconds>","seconds between samples (default 5)"),t("--json","one-shot report, or { samples, perSecond } under --watch")],seeAlso:["state","perf"]}),i("stop-animation","stop a running animation by id, or stop all active animations",["sootsim do stop-animation <id|all>"],[e("sootsim do stop-animation 3"),e("sootsim do stop-animation all","freeze everything for inspection")],"the id comes from `sootsim get animations`. stopping fires the animation's finished callback with finished=false, matching react-native Animated.stop() semantics.",{group:"do",subgroup:"animations",shortDescription:"stop a running animation",seeAlso:["animations","animation"]}),i("trace","opt-in trace recorders: shell animation frames or per-tick animation values",["sootsim debug trace shell [on [limit]|off|status|clear|<recentLimit>]","sootsim debug trace anim <on <id|all> [limit]|off [id|all]|status|clear|<id> [limit]>"],[e("sootsim debug trace shell on 240","arm the shell frame recorder"),e("sootsim debug trace shell 120","dump the last 120 shell samples"),e("sootsim debug trace anim on 3 240","record up to 240 ticks for anim #3"),e("sootsim debug trace anim 3 60","read last 60 ticks for anim #3"),e("sootsim debug trace anim on all","record every active animation")],"for a focused perf trace: `get animations` to find the id, `trace anim on <id>` to arm, reproduce the issue, then `trace anim <id>` to pull per-tick value + velocity samples. `trace anim off` disables when done.",{group:"debug",subgroup:"profiling",shortDescription:"per-tick animation + shell frame trace",seeAlso:["animations","animation","stop-animation"]}),i("snapshot","capture a tree snapshot (layout + transform + opacity) for later diffing",["sootsim debug snapshot [label]"],[e("sootsim debug snapshot before","capture state before an interaction"),e("sootsim debug snapshot after","capture state after an interaction"),e("sootsim debug snapshot","unlabeled \u2014 auto-named based on current time")],"snapshots live in-memory in the engine for the life of the page. use `snapshots` to list labels and `diff <a> <b>` to compare two. clear with `clear-snapshots [label]`.",{group:"debug",subgroup:"snapshot",shortDescription:"capture tree snapshot for later diff",seeAlso:["snapshots","diff","state"]}),i("snapshots","list the labels of every captured tree snapshot",["sootsim debug snapshots"],[e("sootsim debug snapshots","list every label, with capture time")],void 0,{group:"debug",subgroup:"snapshot",shortDescription:"list captured snapshot labels",seeAlso:["snapshot","diff"]}),i("diff","compare two captured snapshots \u2014 added / removed / changed nodes",["sootsim debug diff <labelA> <labelB>"],[e("sootsim debug diff before after","diff a paired snapshot \u2014 added/removed/changed counts + per-node detail")],"project both snapshots with `snapshot <label>` first, then diff. emits counts plus added / removed / changed arrays; pipe through jq for filtering.",{group:"debug",subgroup:"snapshot",shortDescription:"compare two snapshots",seeAlso:["snapshot","snapshots","clear-snapshots"]}),i("clear-snapshots","drop a labeled snapshot (or all snapshots if no label is given)",["sootsim debug clear-snapshots [label]"],[e("sootsim debug clear-snapshots before","drop just the `before` snapshot"),e("sootsim debug clear-snapshots","drop every captured snapshot")],void 0,{group:"debug",subgroup:"snapshot",shortDescription:"discard captured snapshots",seeAlso:["snapshot","snapshots","diff"]}),i("find","dump engine-internal nodes by category (e.g. all Sheet.Frame portals)",["sootsim debug find sheets","sootsim debug find portals"],[e("sootsim debug find sheets","every Sheet.Frame-shaped node in the tree"),e("sootsim debug find portals","every portal-host / portal-view pair the engine is currently mounting"),e("sootsim debug find sheets | jq '.[] | select(.translateY != null)'","narrow to sheets mid-animation")],"category-specific inspectors for runtime structures that `describe` collapses. emits a JSON array of node-shaped records \u2014 pipe through jq for filtering.",{group:"debug",subgroup:"inspectors",shortDescription:"list engine-internal nodes by category",seeAlso:["state","describe"]}),i("record","toggle the debug event ring buffer (off / on)",["sootsim debug record [on|off]"],[e("sootsim debug record on","arm the ring buffer"),e("sootsim debug record off","stop recording"),e("sootsim debug record","query current state without flipping it")],"the ring buffer feeds `debug recent <channel> [n]`. enable a channel via `debug enable <channel>` first so the corresponding events actually fire.",{group:"debug",subgroup:"events",shortDescription:"toggle the debug event ring buffer",seeAlso:["recent","clear-events"]}),i("recent","tail the last N events from the debug ring buffer (optionally filtered by channel)",["sootsim debug recent","sootsim debug recent <channel>","sootsim debug recent <channel> <n>"],[e("sootsim debug recent","last 50 events across every channel"),e("sootsim debug recent portals 20","last 20 portal events"),e("sootsim debug recent layout 200","larger window for layout debugging")],"requires `debug record on` to have armed the buffer at some prior point. default limit is 50.",{group:"debug",subgroup:"events",shortDescription:"last N debug events",seeAlso:["record","clear-events"]}),i("clear-events","drop everything currently in the debug event ring buffer",["sootsim debug clear-events"],[e("sootsim debug clear-events","reset the buffer before a clean repro")],void 0,{group:"debug",subgroup:"events",shortDescription:"reset the debug event ring buffer",seeAlso:["record","recent"]}),i("sample-color","average the canvas color over a pixel or rect; returns hex + rgba",["sootsim debug sample-color <x> <y> [w] [h]","sootsim debug sample-color --area x,y,w,h","sootsim debug sample-color --id <testID>","sootsim debug sample-color --text <text>"],[e("sootsim debug sample-color 196 400"),e("sootsim debug sample-color 100 200 50 80"),e("sootsim debug sample-color --id loginButton"),e('sootsim debug sample-color --text "Sign in" --json')],"coords are logical sootsim units. pixels are averaged across the rect. --json emits { r, g, b, a, hex, samples, rect } for scripts.",{group:"debug",subgroup:"profiling",shortDescription:"average canvas color over a rect",options:[t("--area x,y,w,h","rect to sample (coords are logical sootsim units)"),t("--id <testID>","sample over a node's layout rect"),t("--text <text>","sample over the node matching text"),t("--json","emit { r, g, b, a, hex, samples, rect }")],seeAlso:["screenshot"]}),i("screenshot","capture the canvas (full or a cropped area) as PNG",["sootsim screenshot [--output <path>]","sootsim screenshot --area x,y,w,h [--output <path>]","sootsim screenshot --id <testID> [--output <path>]","sootsim screenshot --text <text> [--output <path>]"],[e("sootsim screenshot"),e("sootsim screenshot --output /tmp/app.png"),e("sootsim screenshot --area 0,200,393,400"),e("sootsim screenshot --id loginButton --output button.png")],"area args use logical sootsim coords; default output is /tmp/sootsim-inspect.png.",{options:[t("--output <path>","write PNG here (default /tmp/sootsim-inspect.png)"),t("--area x,y,w,h","crop to rect (logical sootsim coords)"),t("--id <testID>","crop to a node's layout rect"),t("--text <text>","crop to the node matching text")],seeAlso:["sample-color","record"]}),i("url","show the current page URL",["sootsim get url [--json]"],[e("sootsim get url"),e("sootsim get url --json")],void 0,{group:"get",subgroup:"info",shortDescription:"current page URL",options:[t("--json","emit { url } for scripts")]}),i("reload","reload the page and wait for reconnection",["sootsim do reload"],void 0,void 0,{group:"do",subgroup:"lifecycle",shortDescription:"reload the page + wait for reconnect",seeAlso:["wait","ready"],order:10}),i("globals","list all __sootsim* globals available in the browser",["sootsim get globals"],void 0,void 0,{group:"get",subgroup:"info",shortDescription:"list available __sootsim* globals"}),i("sleep","simple local pause between commands",["sootsim do sleep [seconds]"],[e("sootsim do sleep 0.5")],void 0,{group:"do",subgroup:"lifecycle",shortDescription:"local pause between commands",seeAlso:["settle","idle"],order:40}),i("wait","wait for the current sim to reconnect",["sootsim do wait [seconds]"],[e("sootsim do wait 30")],void 0,{group:"do",subgroup:"lifecycle",shortDescription:"wait for sim reconnect",seeAlso:["ready","idle","settle"],order:20}),i("settle","wait until the visible layout is stable (default max 3s)",["sootsim do settle [seconds] [--strict]"],[e("sootsim do settle 3"),e("sootsim do settle 2 --strict")],"default requires layout hash to be stable for 3 consecutive polls \u2014 this is the right signal for slide transitions, spring-driven position changes, and scroll momentum. --strict additionally requires the worker animation flags (hasActiveAnims, hasActiveNativeAnimations, hasPendingAnimationFrames) to all be false. use --strict only when the target app has no perpetual background animation, otherwise it will time out.",{group:"do",subgroup:"lifecycle",shortDescription:"wait for animations to settle",options:[t("--strict","also require all worker animation flags to be false (use only when no perpetual bg animation)")],seeAlso:["idle","ready","selector"],order:30}),i("ready","block until the guest app bundle is loaded and painted (20s default)",["sootsim wait ready [--max-ms <ms>]"],[e("sootsim wait ready"),e("sootsim wait ready --max-ms 30000","cold uniswap/expensify reload"),e("sootsim wait ready --max-ms 5000")],"authoritative signal: the persistent __sootsimExternalAppReady flag (set by the sootsim:externalAppReady event handler, cleared on reload). polls CLI-side so --max-ms can exceed the bridge per-command timeout. prefer this over `do wait`, which is a node-count heuristic that false-positives on ConnectRN skeletons. idempotent: calling it after the app is already ready returns in ~200ms. exits non-zero on timeout.",{group:"wait",shortDescription:"block until the guest app bundle is loaded and painted",options:[t("--max-ms <ms>","override the 20s default deadline")],seeAlso:["idle","selector","settle"],order:10}),i("idle","block until animations, rAF queue, and layout are all settled",["sootsim wait idle [--max-ms <ms>] [--strict]"],[e("sootsim wait idle"),e("sootsim wait idle --max-ms 2000 --strict")],"same signal as `do settle` but under the discoverable `wait` verb. exits non-zero on timeout.",{group:"wait",shortDescription:"block until animations + rAF + layout are settled",options:[t("--max-ms <ms>","override the idle deadline"),t("--strict","also require worker animation flags to all be false")],seeAlso:["ready","selector","settle"],order:20}),i("selector","block until a node with <testid> is present with non-zero layout (or absent with --gone)",["sootsim wait selector <testid> [--max-ms <ms>] [--gone]"],[e("sootsim wait selector loginButton"),e("sootsim wait selector feedList --max-ms 3000"),e("sootsim wait selector loginButton --gone --max-ms 90000","after a gate action, wait for the gate to leave instead of re-tapping")],'playwright-style. when `find --testid <id>` returns no result, the CLI now prints this command as a hint. `--gone` inverts the wait \u2014 it resolves when the node is confirmed absent (the positive "gate/screen left" signal), and never resolves on an indeterminate bridge. exits non-zero on timeout.',{group:"wait",shortDescription:"block until a testID appears (or, with --gone, disappears)",options:[t("--max-ms <ms>","override the deadline"),t("--gone","resolve when the node is absent instead of present")],seeAlso:["ready","idle","find"],order:30}),i("event","block until a semantic timeline event of <kind> appears",["sootsim wait event <kind> [--max-ms <ms>]","sootsim wait event <kind> --filter <substring>","sootsim wait event <kind> --equals <exact>"],[e("sootsim wait event fetch --filter BeginSignIn","wait for the next BeginSignIn fetch after a tap"),e("sootsim wait event screen --equals Inbox","wait until a screen named Inbox appears"),e("sootsim wait event alert","wait for the next iOS alert/sheet"),e("sootsim wait event react-commit --max-ms 2000","block until the next React commit fires (or 2s)")],"timeline-backed companion to wait selector / wait idle. polls SootSim.bridges.timeline.recent() at 200ms; matches against url, message, name, path, title, and phase fields. defaults: --max-ms 5000, --since now (only counts events that arrive after this command starts; pass --since cursor to include prior events). exits non-zero on timeout.",{group:"wait",shortDescription:"block until the next timeline event of a given kind",options:[t("--max-ms <ms>","wait deadline in milliseconds (default 5000)"),t("--filter <substring>","substring match against url/message/name/path/title (case-insensitive)"),t("--equals <exact>","exact match against any of the same fields"),t("--since <mode>",'"now" (default \u2014 only events after this command starts) or "cursor"'),t("--json","emit { found, elapsedMs, event } JSON")],seeAlso:["ready","idle","selector"],order:40}),i("dispatch","dispatch a raw keyboard key (bypasses visual shift state)",["sootsim do dispatch <char>"],[e("sootsim do dispatch A")],void 0,{group:"do",subgroup:"text input",shortDescription:"raw key (bypasses visual shift state)",seeAlso:["key","type"],order:70}),i("keyboard","on-screen keyboard state (type, returnKey, autoCap, mode, shift, accessory)",["sootsim get keyboard [--json]"],[e("sootsim get keyboard"),e("sootsim get keyboard --json")],void 0,{group:"get",subgroup:"info",shortDescription:"on-screen keyboard state",options:[t("--json","emit structured JSON")],seeAlso:["type","dismiss","state"]}),i("screens","list the current navigation stack: active app, route stack, modal stack, keyboard",["sootsim get screens [--json]"],[e("sootsim get screens"),e("sootsim get screens --json")],'pulls from the shell (active app, switcher phase), the navigation bridge (route stack for react-navigation / one-router if present), and the top presented modal. use this when a screen id or nav-state is the fastest orientation signal \u2014 e.g. "am I on the onboarding landing, or did the login sheet open over it?". Exits quietly when no navigation bridge is available.',{group:"get",subgroup:"info",shortDescription:"current screen + modal + route stack",options:[t("--json","emit structured JSON")],seeAlso:["describe","state","keyboard"]})];function _(o,s){return`${o??""}:${s}`}var C=new Map,V=new Map;for(let o of R){let s=C.get(o.verb);s?s.push(o):C.set(o.verb,[o]),V.set(_(o.group,o.verb),o)}var le=new Map(Array.from(C,([o,s])=>[o,s.find(a=>!a.group)??s[0]]));function W(o,s){return V.get(_(o,s))}function w(o,s){if(s!==void 0)return W(s,o);let a=C.get(o);return a?.find(l=>!l.group)??a?.[0]}function h(o,s=v){return o.replaceAll("{{bridgePort}}",String(s.bridgePort)).replaceAll("{{defaultShellUrl}}",s.defaultShellUrl)}function Y(){return D.slice().sort((o,s)=>o.order-s.order)}function k(o,s){let a=Math.max(...s.map(r=>r.name.length),0)+2,l=s.map(r=>` ${r.name.padEnd(a)}${r.desc}`);return` ${o}
|
|
3
3
|
${l.join(`
|
|
4
4
|
`)}`}function N(o,s){let a=o.usage[0]??`sootsim ${o.verb}`,l=[s?`sootsim ${s} `:"","sootsim inspect ","sootsim "].filter(Boolean),r=a;for(let n of l)if(r.startsWith(n)){r=r.slice(n.length);break}return r}function A(o){return o.shortDescription??o.description}function T(o){return R.filter(s=>s.group===o)}function K(o){let s=T(o);if(!s.length)return"";let a=new Map;for(let n of s){let p=n.subgroup??"",u=a.get(p)??[];u.push(n),a.set(p,u)}let l=[];for(let n of s){let p=n.subgroup??"";l.includes(p)||l.push(p)}let r=[];for(let n of l){let p=a.get(n)??[];p.sort((c,x)=>{let I=c.order??Number.POSITIVE_INFINITY,S=x.order??Number.POSITIVE_INFINITY;return I!==S?I-S:c.verb.localeCompare(x.verb)});let u=p.map(c=>({name:N(c,o),desc:A(c)})),g=Math.max(...u.map(c=>c.name.length),0)+2,f=n?` ${n}:`:"",d=u.map(c=>` ${c.name.padEnd(g)}${c.desc}`);r.push([f,...d].filter(Boolean).join(`
|
|
5
5
|
`))}return r.join(`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.192 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
import{execFileSync as d,spawn as g}from"child_process";import{existsSync as m}from"fs";import{homedir as h}from"os";import{join as C}from"path";var f=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium","~/Applications/Chromium.app/Contents/MacOS/Chromium","/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge","~/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge","/Applications/Brave Browser.app/Contents/MacOS/Brave Browser","~/Applications/Brave Browser.app/Contents/MacOS/Brave Browser","/Applications/Arc.app/Contents/MacOS/Arc","~/Applications/Arc.app/Contents/MacOS/Arc"],O=["/usr/bin/google-chrome","/usr/bin/chromium","/usr/bin/chromium-browser","/usr/bin/microsoft-edge","/usr/bin/brave-browser","/snap/bin/chromium"],w=["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe","C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe","C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe","C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe","C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe","C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"],U=["google-chrome","chromium","chromium-browser","microsoft-edge","brave-browser"],M=["chrome","msedge","brave"];function A(r){return r.startsWith("~/")?C(h(),r.slice(2)):r}function a(r){for(let n of r){let o=A(n);if(m(o))return o}return null}function x(r,n){try{let e=d(n==="win32"?"where":"which",[r],{encoding:"utf8",timeout:1500,stdio:["ignore","pipe","ignore"]}).trim();return e?e.split(/\r?\n/)[0]:null}catch{return null}}function c(r=process.platform){let n=process.env.CHROME_PATH||process.env.CHROMIUM_PATH;if(n&&m(n))return n;let o=a(r==="darwin"?f:r==="win32"?w:O);if(o)return o;let e=r==="win32"?M:U;for(let t of e){let i=x(t,r);if(i)return i}return null}function p(r,n={}){if(!r)throw new Error("openUrl requires a url");let o=n.platform??process.platform;return n.newWindow?s(r,{...n,platform:o,newWindow:!0}):o==="darwin"?{command:"open",args:n.background===!1?[r]:["-g",r],via:"system"}:o==="win32"?{command:"cmd",args:["/c","start","",r],via:"system"}:{command:"xdg-open",args:[r],via:"system"}}function s(r,n={}){if(!r)throw new Error("openUrl requires a url");let o=n.platform??process.platform,e="chromiumBinary"in n?n.chromiumBinary:c(o);if(!e)throw new Error("browser launch requires Chrome, Chromium, Edge, Brave, or Arc");let t=[];return n.newWindow!==!1&&t.push("--new-window"),t.push(r),{command:e,args:t,via:"chromium",target:e}}async function l(r,n,o){return new Promise((e,t)=>{let i=g(r,n,{detached:o,stdio:"ignore"});i.once("error",t),i.once("spawn",()=>{o&&i.unref(),e(i.pid)})})}async function u(r,n={}){let o=p(r,n),e=await l(o.command,o.args,n.detached??!0);return{...o,pid:e,attachUrl:r}}async function b(r,n={}){let o=s(r,n),e=await l(o.command,o.args,n.detached??!0);return{...o,pid:e,attachUrl:r}}async function v(r,n={}){await u(r,n)}export{c as a,u as b,b as c,v as d};
|