sootsim 0.1.112 → 0.1.113

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.
Files changed (146) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-7LGWSKBP.js → agent-3JTU2UL4.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-GRVMTBFJ.js → agent-wrapper-CR7GJ7FP.js} +2 -2
  4. package/dist-cli/chunks/{assert-GSP3A337.js → assert-N2OG5JQ3.js} +2 -2
  5. package/dist-cli/chunks/auto-bootstrap-RUMSH2SU.js +2 -0
  6. package/dist-cli/chunks/beta-WAJQAPBI.js +2 -0
  7. package/dist-cli/chunks/{chunk-QJL6QTAW.js → chunk-2OGV4GCY.js} +1 -1
  8. package/dist-cli/chunks/{chunk-RY25ZLAP.js → chunk-2SXHMBEC.js} +1 -1
  9. package/dist-cli/chunks/{chunk-ZGFOEFIT.js → chunk-3EQEJK4E.js} +2 -2
  10. package/dist-cli/chunks/chunk-3J3AQWIW.js +1 -0
  11. package/dist-cli/chunks/{chunk-YEG6THC2.js → chunk-3MBITUPW.js} +1 -1
  12. package/dist-cli/chunks/{chunk-QXBSCY2G.js → chunk-3OUCFCUV.js} +2 -2
  13. package/dist-cli/chunks/{chunk-3EE7UVER.js → chunk-4IA3F7NN.js} +2 -2
  14. package/dist-cli/chunks/{chunk-UFHLNGFE.js → chunk-4K22TYNZ.js} +2 -2
  15. package/dist-cli/chunks/{chunk-O7T3S7GK.js → chunk-5ALMZP2C.js} +7 -7
  16. package/dist-cli/chunks/{chunk-5DW7CLVT.js → chunk-5QY6UIVH.js} +2 -2
  17. package/dist-cli/chunks/{chunk-FTRDTDJF.js → chunk-73HWAXE2.js} +2 -2
  18. package/dist-cli/chunks/{chunk-DKZKYTOM.js → chunk-7HFQ2NWW.js} +2 -2
  19. package/dist-cli/chunks/{chunk-K6U4PNYP.js → chunk-AC7WDB6V.js} +1 -1
  20. package/dist-cli/chunks/{chunk-FKL3NMR5.js → chunk-BKUVXSRQ.js} +1 -1
  21. package/dist-cli/chunks/{chunk-RCDZBNJW.js → chunk-D43UWL27.js} +2 -2
  22. package/dist-cli/chunks/{chunk-P37J53P3.js → chunk-D5KQSLTO.js} +2 -2
  23. package/dist-cli/chunks/{chunk-AL4B57VD.js → chunk-E3H5ZULL.js} +1 -1
  24. package/dist-cli/chunks/{chunk-P74E724D.js → chunk-EBWNCJET.js} +2 -2
  25. package/dist-cli/chunks/{chunk-MACTWR2J.js → chunk-FXSPK6L3.js} +1 -1
  26. package/dist-cli/chunks/{chunk-GN7LBY6G.js → chunk-H7MKPGGV.js} +3 -3
  27. package/dist-cli/chunks/{chunk-WIO2R4W7.js → chunk-IZYZPIRZ.js} +2 -2
  28. package/dist-cli/chunks/chunk-K24H4XOV.js +1 -0
  29. package/dist-cli/chunks/{chunk-7CCONVJK.js → chunk-K5LENBS5.js} +1 -1
  30. package/dist-cli/chunks/{chunk-XR6VRNF4.js → chunk-L76VLJIZ.js} +2 -2
  31. package/dist-cli/chunks/{chunk-ZTBVBNY2.js → chunk-LQTTCT5C.js} +1 -1
  32. package/dist-cli/chunks/{chunk-DY7HYEEP.js → chunk-LW3KJUVL.js} +1 -1
  33. package/dist-cli/chunks/{chunk-ERD5IQRP.js → chunk-MWQUK6QO.js} +2 -2
  34. package/dist-cli/chunks/{chunk-MSZWCIEH.js → chunk-MYNBI2ND.js} +1 -1
  35. package/dist-cli/chunks/{chunk-UQ4WCJOG.js → chunk-NIUQAJCI.js} +2 -2
  36. package/dist-cli/chunks/{chunk-ALVFKTMD.js → chunk-OIWS3EXW.js} +2 -2
  37. package/dist-cli/chunks/{chunk-GMXUIARA.js → chunk-RMJMYLLR.js} +2 -2
  38. package/dist-cli/chunks/{chunk-TOETDEFL.js → chunk-RURKHOVS.js} +1 -1
  39. package/dist-cli/chunks/{chunk-KSQTJY3Z.js → chunk-UUFG4HVZ.js} +1 -1
  40. package/dist-cli/chunks/chunk-VX6D2AI3.js +1 -0
  41. package/dist-cli/chunks/{chunk-DYBNT4T7.js → chunk-WGJRZVLO.js} +1 -1
  42. package/dist-cli/chunks/{chunk-6WK4XJLI.js → chunk-WOKSYJIY.js} +2 -2
  43. package/dist-cli/chunks/{chunk-GGBWCCP2.js → chunk-WSGVQEXB.js} +3 -3
  44. package/dist-cli/chunks/{chunk-BYFAYZRV.js → chunk-XK275OXC.js} +1 -1
  45. package/dist-cli/chunks/{chunk-E3JNCJMG.js → chunk-XKKCAC3J.js} +2 -2
  46. package/dist-cli/chunks/{chunk-OXFTMHJQ.js → chunk-XODSEUOW.js} +2 -2
  47. package/dist-cli/chunks/{chunk-6TPWDY6K.js → chunk-XU6LOLAB.js} +2 -2
  48. package/dist-cli/chunks/{chunk-QTVNFT2F.js → chunk-XXORXONW.js} +2 -2
  49. package/dist-cli/chunks/chunk-YHK6RX3N.js +2 -0
  50. package/dist-cli/chunks/{chunk-SJPXB24I.js → chunk-ZVE6F53R.js} +2 -2
  51. package/dist-cli/chunks/cli-version-2F4UFHUR.js +2 -0
  52. package/dist-cli/chunks/{compat-TDDZ65HJ.js → compat-F6VRDJEA.js} +3 -3
  53. package/dist-cli/chunks/{config-ZYXUW3HJ.js → config-K2VVAYH6.js} +2 -2
  54. package/dist-cli/chunks/control-UCTK6SGP.js +2 -0
  55. package/dist-cli/chunks/{cpu-profile-Q3TJ6RXT.js → cpu-profile-6SQKDUCL.js} +2 -2
  56. package/dist-cli/chunks/{daemon-RITDRE4H.js → daemon-AWSYWILR.js} +2 -2
  57. package/dist-cli/chunks/{debug-XKFB4225.js → debug-PX35BAY4.js} +3 -3
  58. package/dist-cli/chunks/{detox-XIZ3DBRQ.js → detox-5SPMUGEX.js} +2 -2
  59. package/dist-cli/chunks/{device-GZBJJJEB.js → device-ACGNWZ3G.js} +2 -2
  60. package/dist-cli/chunks/{diagnose-H2KIQ752.js → diagnose-V2VT4ASE.js} +2 -2
  61. package/dist-cli/chunks/drivers-G4ZQAYTR.js +2 -0
  62. package/dist-cli/chunks/{electron-VFZYBO4G.js → electron-Y6E5R4SF.js} +3 -3
  63. package/dist-cli/chunks/flow-I642RDRA.js +2 -0
  64. package/dist-cli/chunks/help-BPNT2YES.js +2 -0
  65. package/dist-cli/chunks/{hints-NYSBGRRV.js → hints-2V7ZHG6L.js} +2 -2
  66. package/dist-cli/chunks/{home-paths-ISIMYDEJ.js → home-paths-MVPKADD6.js} +2 -2
  67. package/dist-cli/chunks/inspect-DNRAUTAB.js +974 -0
  68. package/dist-cli/chunks/install-BMWYQTOZ.js +2 -0
  69. package/dist-cli/chunks/{install-desktop-GACFW2HY.js → install-desktop-CYJDYA53.js} +3 -3
  70. package/dist-cli/chunks/{keys-LZLQVCHR.js → keys-FUYSXI2L.js} +2 -2
  71. package/dist-cli/chunks/{launch-JYZNGXU6.js → launch-PQ6QTEP7.js} +3 -3
  72. package/dist-cli/chunks/{login-WY3VAO3Y.js → login-BMFJHJ3B.js} +4 -4
  73. package/dist-cli/chunks/{logout-F74SOJ54.js → logout-PG2JFWQL.js} +2 -2
  74. package/dist-cli/chunks/{maestro-ENB7YUJM.js → maestro-2QFWLFF4.js} +2 -2
  75. package/dist-cli/chunks/{preview-KF5L3JID.js → preview-L6YAPMSD.js} +2 -2
  76. package/dist-cli/chunks/{profile-IWEB6CZL.js → profile-2QQGLQBN.js} +2 -2
  77. package/dist-cli/chunks/{react-D2YTYZIP.js → react-ZKAMEZ6H.js} +2 -2
  78. package/dist-cli/chunks/{record-BOUB4J4P.js → record-XZNFFK4K.js} +2 -2
  79. package/dist-cli/chunks/runtime-4X66LQCP.js +2 -0
  80. package/dist-cli/chunks/{runtime-delivery-GZ5VNBLN.js → runtime-delivery-R5E2YPXP.js} +2 -2
  81. package/dist-cli/chunks/{screenshot-TXB77HDC.js → screenshot-5BDZO36S.js} +2 -2
  82. package/dist-cli/chunks/{screenshot-mode-D7K5IYF3.js → screenshot-mode-OUMQT4EP.js} +2 -2
  83. package/dist-cli/chunks/{screenshots-RUJ5NM3X.js → screenshots-RTIXDSFS.js} +2 -2
  84. package/dist-cli/chunks/{server-KWY5Q5KH.js → server-ZF2XUVP7.js} +2 -2
  85. package/dist-cli/chunks/setup-repo-BBC3QXE7.js +2 -0
  86. package/dist-cli/chunks/{skills-S4H3WCQE.js → skills-YN2QLIXK.js} +2 -2
  87. package/dist-cli/chunks/{start-MTI2FM7W.js → start-5HZPS3B6.js} +4 -4
  88. package/dist-cli/chunks/store-JJAGDHAI.js +2 -0
  89. package/dist-cli/chunks/telemetry-MRP2ISHT.js +2 -0
  90. package/dist-cli/chunks/{test-MNVKQFII.js → test-RQWNRURE.js} +3 -3
  91. package/dist-cli/chunks/{three-mode-V75AD5VC.js → three-mode-STWOAVTT.js} +2 -2
  92. package/dist-cli/chunks/{timeline-PFHSMH67.js → timeline-NZS6LDPR.js} +2 -2
  93. package/dist-cli/chunks/{upgrade-INEYUJTS.js → upgrade-PM4RZ7CD.js} +2 -2
  94. package/dist-cli/chunks/upload-LLA3GT6U.js +2 -0
  95. package/dist-cli/chunks/{web-L7FHHETW.js → web-YQE55355.js} +2 -2
  96. package/dist-cli/chunks/{what-happened-NY72VJPW.js → what-happened-4HEXIQ23.js} +2 -2
  97. package/dist-cli/chunks/{whoami-XTTFI7QK.js → whoami-RZVBLNXN.js} +2 -2
  98. package/dist-lib/agent-daemon-client.cjs +1 -1
  99. package/dist-lib/agent-events.cjs +1 -1
  100. package/dist-lib/agent-sessions.cjs +1 -1
  101. package/dist-lib/attached-projects.cjs +1 -1
  102. package/dist-lib/auth/shared-session.cjs +1 -1
  103. package/dist-lib/backend-origin.cjs +1 -1
  104. package/dist-lib/beta.cjs +1 -1
  105. package/dist-lib/beta.mjs +1 -1
  106. package/dist-lib/bridge-constants.cjs +1 -1
  107. package/dist-lib/cli-constants.cjs +1 -1
  108. package/dist-lib/config.cjs +1 -1
  109. package/dist-lib/detox/index.cjs +1 -1
  110. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  111. package/dist-lib/home-paths.cjs +1 -1
  112. package/dist-lib/host/bridge-host.cjs +1 -1
  113. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  114. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  115. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  116. package/dist-lib/host/websocket-proxy.cjs +1 -1
  117. package/dist-lib/index.cjs +1 -1
  118. package/dist-lib/metro.cjs +1 -1
  119. package/dist-lib/profiles.cjs +1 -1
  120. package/dist-lib/render-mode.cjs +1 -1
  121. package/dist-lib/scripts/demo-app-registry.cjs +1 -1
  122. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  123. package/dist-lib/sdk.cjs +1440 -0
  124. package/dist-lib/sdk.mjs +1360 -0
  125. package/dist-lib/skills.cjs +1 -1
  126. package/dist-lib/vite.cjs +1 -1
  127. package/package.json +7 -1
  128. package/src/sdk.ts +7 -0
  129. package/dist-cli/chunks/auto-bootstrap-736PQWPN.js +0 -2
  130. package/dist-cli/chunks/beta-BKLH7QSW.js +0 -2
  131. package/dist-cli/chunks/chunk-2ZZUG4LB.js +0 -2
  132. package/dist-cli/chunks/chunk-3ISNSUXK.js +0 -1
  133. package/dist-cli/chunks/chunk-ILDC36C5.js +0 -1
  134. package/dist-cli/chunks/chunk-LSPX3IR3.js +0 -1
  135. package/dist-cli/chunks/cli-version-7YTDRSHR.js +0 -2
  136. package/dist-cli/chunks/control-N5OQDWFT.js +0 -2
  137. package/dist-cli/chunks/drivers-KJ55BQZI.js +0 -2
  138. package/dist-cli/chunks/flow-TBVVFAO5.js +0 -2
  139. package/dist-cli/chunks/help-XPU3EWZ7.js +0 -2
  140. package/dist-cli/chunks/inspect-FVGSOR3L.js +0 -980
  141. package/dist-cli/chunks/install-HW4GGTYA.js +0 -2
  142. package/dist-cli/chunks/runtime-4HPGMK52.js +0 -2
  143. package/dist-cli/chunks/setup-repo-6ZFTYKUS.js +0 -2
  144. package/dist-cli/chunks/store-6Q4Y5VIK.js +0 -2
  145. package/dist-cli/chunks/telemetry-DJTKUHAH.js +0 -2
  146. package/dist-cli/chunks/upload-4GNZRMI4.js +0 -2
@@ -0,0 +1,1440 @@
1
+ /*! sootsim v0.1.113 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
+ "use strict";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/sdk.ts
23
+ var sdk_exports = {};
24
+ __export(sdk_exports, {
25
+ DEBUG_CHANNELS: () => DEBUG_CHANNELS,
26
+ READY_CONTENT_NODE_FLOOR: () => READY_CONTENT_NODE_FLOOR,
27
+ READY_NODE_STABLE_MS: () => READY_NODE_STABLE_MS,
28
+ WAIT_READY_PROBE: () => WAIT_READY_PROBE,
29
+ WAIT_READY_PROGRESS_INTERVAL_MS: () => WAIT_READY_PROGRESS_INTERVAL_MS,
30
+ clearConsole: () => clearConsole,
31
+ clearLogs: () => clearLogs,
32
+ clearRequests: () => clearRequests,
33
+ filterLogEntries: () => filterLogEntries,
34
+ formatTimelineSummary: () => formatTimelineSummary,
35
+ getShellState: () => getShellState,
36
+ inspectAccessibilityTree: () => inspectAccessibilityTree,
37
+ inspectDebugFind: () => inspectDebugFind,
38
+ inspectDebugFlags: () => inspectDebugFlags,
39
+ inspectDebugRecent: () => inspectDebugRecent,
40
+ inspectDebugStatus: () => inspectDebugStatus,
41
+ inspectDescribe: () => inspectDescribe,
42
+ inspectErrors: () => inspectErrors,
43
+ inspectFind: () => inspectFind,
44
+ inspectKeyboard: () => inspectKeyboard,
45
+ inspectLogs: () => inspectLogs,
46
+ inspectMemory: () => inspectMemory,
47
+ inspectNodeCount: () => inspectNodeCount,
48
+ inspectRequests: () => inspectRequests,
49
+ inspectScreens: () => inspectScreens,
50
+ inspectScrollStateAt: () => inspectScrollStateAt,
51
+ inspectTimelineAdvanceCursor: () => inspectTimelineAdvanceCursor,
52
+ inspectTimelineRecent: () => inspectTimelineRecent,
53
+ inspectTimelineSummary: () => inspectTimelineSummary,
54
+ inspectTree: () => inspectTree,
55
+ inspectUrl: () => inspectUrl,
56
+ inspectWaitReady: () => inspectWaitReady,
57
+ inspectWaitSelector: () => inspectWaitSelector,
58
+ inspectWarnings: () => inspectWarnings,
59
+ isInspectModeActive: () => isInspectModeActive,
60
+ isInspectPickCommand: () => isInspectPickCommand,
61
+ isShellCommandUnavailable: () => isShellCommandUnavailable,
62
+ isTapSuccess: () => isTapSuccess,
63
+ rankInteractive: () => rankInteractive,
64
+ readyProbeHasContent: () => readyProbeHasContent,
65
+ resolveFindMode: () => resolveFindMode,
66
+ resolveMaxMsFlag: () => resolveMaxMsFlag,
67
+ scoreInteractive: () => scoreInteractive,
68
+ setDebugChannels: () => setDebugChannels,
69
+ shouldSkipAutoSettleForInspectPick: () => shouldSkipAutoSettleForInspectPick,
70
+ tapBest: () => tapBest,
71
+ tapById: () => tapById,
72
+ tapByText: () => tapByText,
73
+ tapCommandForNode: () => tapCommandForNode,
74
+ tapCoordinates: () => tapCoordinates,
75
+ tapResolvedTarget: () => tapResolvedTarget,
76
+ tapTargetFromPayload: () => tapTargetFromPayload,
77
+ waitForSootsimIdle: () => waitForSootsimIdle,
78
+ waitReadyReason: () => waitReadyReason
79
+ });
80
+ module.exports = __toCommonJS(sdk_exports);
81
+
82
+ // cli/commands/inspect/core.ts
83
+ function resolveMaxMsFlag(args, fallbackMs) {
84
+ const aliases = ["--max-ms", "--maxMs", "--maxms", "--max_ms"];
85
+ for (const flag of aliases) {
86
+ const i = args.indexOf(flag);
87
+ if (i >= 0 && args[i + 1]) {
88
+ const n = Number(args[i + 1]);
89
+ if (Number.isFinite(n)) return Math.max(100, n);
90
+ }
91
+ }
92
+ return fallbackMs;
93
+ }
94
+ var INSPECT_PICK_COMMANDS = /* @__PURE__ */ new Set([
95
+ "tap",
96
+ "double-tap",
97
+ "tap-text",
98
+ "tap-id",
99
+ "long-press",
100
+ "touch"
101
+ ]);
102
+ function isInspectPickCommand(subcommand) {
103
+ return typeof subcommand === "string" && INSPECT_PICK_COMMANDS.has(subcommand);
104
+ }
105
+ async function isInspectModeActive(bridge) {
106
+ const active = await bridge.send({
107
+ type: "evaluate",
108
+ code: "window.__sootsimEngineState?.inspectActive === true"
109
+ });
110
+ return active === true;
111
+ }
112
+ async function shouldSkipAutoSettleForInspectPick(bridge, subcommand) {
113
+ if (!isInspectPickCommand(subcommand)) return false;
114
+ try {
115
+ return await isInspectModeActive(bridge);
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+ async function inspectNodeCount(bridge) {
121
+ const count = await bridge.send({
122
+ type: "evaluate",
123
+ code: "(async () => await window.__sootsimTest.getNodeCount())()"
124
+ });
125
+ return { nodes: typeof count === "number" ? count : 0 };
126
+ }
127
+ async function inspectTree(bridge, depth = 5) {
128
+ const tree = await bridge.send({
129
+ type: "evaluate",
130
+ code: `(async () => await window.__sootsimTest.dumpTree(${depth}))()`
131
+ });
132
+ return { depth, tree };
133
+ }
134
+ async function inspectUrl(bridge) {
135
+ const url = await bridge.send({ type: "evaluate", code: "window.location.href" });
136
+ return { url: typeof url === "string" ? url : "" };
137
+ }
138
+ async function inspectDescribe(bridge, dumpOpts) {
139
+ const code = `(async () => {
140
+ const t = window.__sootsimTest
141
+ const mainShell = window.SootSim?.bridges?.mainShell
142
+ const kb = window.__sootsimKeyboard
143
+ if (!t) return { error: 'no test bridge' }
144
+
145
+ let shell = null
146
+ try {
147
+ shell = typeof mainShell?.getState === 'function' ? await mainShell.getState() : null
148
+ } catch {}
149
+
150
+ const tree = await t.dumpTree(12, ${JSON.stringify(dumpOpts)})
151
+ const nodeCount = (await t.getNodeCount?.()) || 0
152
+ const keyboard = kb && typeof kb.getLayout === 'function' ? kb.getLayout() : null
153
+ return { tree, shell, nodeCount, keyboard }
154
+ })()`;
155
+ const result = await bridge.send({ type: "evaluate", code });
156
+ return result ?? {};
157
+ }
158
+ var INSPECT_A11Y_CODE = `(async () => {
159
+ const t = window.__sootsimTest
160
+ if (!t) return []
161
+
162
+ const readLayout = (n) => n?.layout || null
163
+ const readAbs = (n) => n?.absolutePosition || n?.absolute || null
164
+ const readRole = (n) => n?.accessibilityRole || n?.role || null
165
+ const readLabel = (n) => n?.accessibilityLabel || n?.label || n?.text || null
166
+ const readHint = (n) => n?.accessibilityHint || n?.hint || null
167
+ const readState = (n) => n?.accessibilityState || n?.state || null
168
+ const readTestId = (n) => n?.testID || n?.testId || null
169
+ const readType = (n) => typeof n?.type === 'string' ? n.type.toLowerCase() : n?.type
170
+ const readPressable = (n) => {
171
+ if (n?.pressable) return true
172
+ const handlers = Array.isArray(n?.handlers) ? n.handlers : []
173
+ const role = readRole(n)
174
+ return handlers.length > 0 || role === 'button' || role === 'link' || role === 'tab'
175
+ }
176
+ const isTextInput = (n) => n?.isTextInput === true
177
+ const isTextNode = (n) => readType(n) === 'text'
178
+ const isVisibleTarget = (n) => {
179
+ const layout = readLayout(n)
180
+ if (!layout || layout.width <= 0 || layout.height <= 0) return false
181
+ const abs = readAbs(n)
182
+ if (!abs) return true
183
+ const device = n?.device || {}
184
+ const screenW = Number(device.width) || window.innerWidth || 0
185
+ const screenH = Number(device.height) || window.innerHeight || 0
186
+ return (
187
+ abs.x + layout.width > 0 &&
188
+ abs.y + layout.height > 0 &&
189
+ abs.x < screenW &&
190
+ abs.y < screenH
191
+ )
192
+ }
193
+ const hasAccessibleSignal = (n) => {
194
+ const role = readRole(n)
195
+ const label = readLabel(n)
196
+ const hint = readHint(n)
197
+ if (role) return true
198
+ if (hint) return true
199
+ if (isTextInput(n)) return true
200
+ if (readPressable(n)) return true
201
+ if (isTextNode(n) && n?.text) return true
202
+ if (typeof label === 'string' && label.length <= 30 && label !== n?.text) return true
203
+ return false
204
+ }
205
+ const normalize = (n) => {
206
+ const layout = readLayout(n)
207
+ const abs = readAbs(n)
208
+ const role = readRole(n) || (readPressable(n) ? 'button' : isTextInput(n) ? 'textfield' : isTextNode(n) ? 'statictext' : 'none')
209
+ return {
210
+ role,
211
+ label: readLabel(n),
212
+ hint: readHint(n),
213
+ state: readState(n),
214
+ testID: readTestId(n),
215
+ position: abs ? { x: Math.round(abs.x), y: Math.round(abs.y) } : null,
216
+ size: layout ? { w: Math.round(layout.width), h: Math.round(layout.height) } : null,
217
+ }
218
+ }
219
+
220
+ if (typeof t.listInspectable === 'function') {
221
+ const list = await t.listInspectable({})
222
+ if (Array.isArray(list)) {
223
+ return list.filter(n => isVisibleTarget(n) && hasAccessibleSignal(n)).map(normalize)
224
+ }
225
+ }
226
+
227
+ const all = await t.queryAll({ pruneHidden: true })
228
+ return all
229
+ .filter(n => isVisibleTarget(n) && hasAccessibleSignal(n))
230
+ .map(normalize)
231
+ })()`;
232
+ async function inspectAccessibilityTree(bridge) {
233
+ const nodes = await bridge.send({ type: "evaluate", code: INSPECT_A11Y_CODE });
234
+ return Array.isArray(nodes) ? nodes : [];
235
+ }
236
+ var FIND_INSPECTABLE_TARGETS = `
237
+ const fromInspectable = async () => {
238
+ if (typeof t.listInspectable !== 'function') return null
239
+ const list = await t.listInspectable({})
240
+ if (!Array.isArray(list)) return null
241
+ return list.map((n) => {
242
+ const role = n.accessibilityRole ?? n.role
243
+ const label = n.accessibilityLabel ?? n.label
244
+ const layout = n.layout
245
+ const absolutePosition = n.absolutePosition ?? n.absolute
246
+ const screenW = Number(n.device?.width) || window.innerWidth || 0
247
+ const screenH = Number(n.device?.height) || window.innerHeight || 0
248
+ const visibleFrame = layout && absolutePosition
249
+ ? {
250
+ x: Math.max(0, absolutePosition.x),
251
+ y: Math.max(0, absolutePosition.y),
252
+ width: Math.max(
253
+ 0,
254
+ Math.min(screenW, absolutePosition.x + layout.width) -
255
+ Math.max(0, absolutePosition.x),
256
+ ),
257
+ height: Math.max(
258
+ 0,
259
+ Math.min(screenH, absolutePosition.y + layout.height) -
260
+ Math.max(0, absolutePosition.y),
261
+ ),
262
+ }
263
+ : null
264
+ const handlers = Array.isArray(n.handlers) ? n.handlers : []
265
+ const pressable =
266
+ handlers.length > 0 ||
267
+ role === 'button' ||
268
+ role === 'link' ||
269
+ role === 'tab'
270
+ return {
271
+ type: typeof n.type === 'string' ? n.type.toLowerCase() : n.type,
272
+ id: n.id ?? n.nodeId,
273
+ nodeId: n.nodeId,
274
+ testID: n.testID ?? n.testId,
275
+ text: n.text,
276
+ layout,
277
+ absolutePosition,
278
+ visibleFrame,
279
+ style: n.computedStyle ?? n.style ?? {},
280
+ childCount: n.childCount ?? 0,
281
+ pressed: n.pressed ?? false,
282
+ pressable,
283
+ isTextInput: n.isTextInput ?? false,
284
+ accessible: n.accessible ?? true,
285
+ accessibilityLabel: label,
286
+ accessibilityRole: role,
287
+ accessibilityHint: n.accessibilityHint,
288
+ accessibilityState: n.accessibilityState,
289
+ accessibilityValue: n.accessibilityValue,
290
+ }
291
+ })
292
+ }
293
+ const isVisibleTarget = (n) => {
294
+ if (!n?.layout) return false
295
+ const frame = n.visibleFrame
296
+ if (frame) return frame.width > 0 && frame.height > 0
297
+ const abs = n.absolutePosition
298
+ if (!abs) return n.layout.width > 0 && n.layout.height > 0
299
+ const screenW = window.innerWidth || 0
300
+ const screenH = window.innerHeight || 0
301
+ return (
302
+ abs.x + n.layout.width > 0 &&
303
+ abs.y + n.layout.height > 0 &&
304
+ abs.x < screenW &&
305
+ abs.y < screenH
306
+ )
307
+ }
308
+ `;
309
+ function resolveFindMode(q) {
310
+ if (q.testId) {
311
+ return {
312
+ mode: "testid",
313
+ code: `(async () => {
314
+ const t = window.__sootsimTest
315
+ return (await t.findByTestId(${JSON.stringify(q.testId)})) || (await t.findById(${JSON.stringify(q.testId)}))
316
+ })()`
317
+ };
318
+ }
319
+ if (q.role) {
320
+ return {
321
+ mode: "role",
322
+ code: `(async () => await window.__sootsimTest.queryAll({ hasRole: ${JSON.stringify(q.role)}, pruneHidden: true }))()`
323
+ };
324
+ }
325
+ if (q.type) {
326
+ return {
327
+ mode: "type",
328
+ code: `(async () => await window.__sootsimTest.queryAll({ type: ${JSON.stringify(q.type)}, pruneHidden: true }))()`
329
+ };
330
+ }
331
+ if (q.pressable) {
332
+ return {
333
+ mode: "pressable",
334
+ code: `(async () => {
335
+ const t = window.__sootsimTest
336
+ ${FIND_INSPECTABLE_TARGETS}
337
+ const inspectable = await fromInspectable()
338
+ if (inspectable) return inspectable.filter(n => n.pressable && isVisibleTarget(n))
339
+ const all = await t.queryAll({ pruneHidden: true })
340
+ return all.filter(n => n.pressable && isVisibleTarget(n))
341
+ })()`
342
+ };
343
+ }
344
+ if (q.interactive) {
345
+ return {
346
+ mode: "interactive-targets",
347
+ code: `(async () => {
348
+ const t = window.__sootsimTest
349
+ ${FIND_INSPECTABLE_TARGETS}
350
+ const inspectable = await fromInspectable()
351
+ if (inspectable) {
352
+ return inspectable.filter(n => n.pressable && isVisibleTarget(n))
353
+ }
354
+ const all = await t.queryAll({ pruneHidden: true })
355
+ return all.filter(n => n.pressable && isVisibleTarget(n))
356
+ })()`
357
+ };
358
+ }
359
+ if (q.visible) {
360
+ return {
361
+ mode: "visible",
362
+ code: `(async () => {
363
+ const all = await window.__sootsimTest.queryAll({ pruneHidden: true })
364
+ return all.filter(n => n.layout && n.layout.width > 0 && n.layout.height > 0)
365
+ })()`
366
+ };
367
+ }
368
+ if (q.text) {
369
+ return {
370
+ mode: "text",
371
+ code: `(async () => await window.__sootsimTest.findByText(${JSON.stringify(q.text)}))()`
372
+ };
373
+ }
374
+ return null;
375
+ }
376
+ async function inspectFind(bridge, q) {
377
+ const resolved = resolveFindMode(q);
378
+ if (!resolved) return null;
379
+ const result = await bridge.send({ type: "evaluate", code: resolved.code });
380
+ return { mode: resolved.mode, result };
381
+ }
382
+ function rankInteractive(nodes) {
383
+ return [...nodes].sort((a, b) => scoreInteractive(b) - scoreInteractive(a));
384
+ }
385
+ function scoreInteractive(n) {
386
+ let score = 0;
387
+ if (n.testID) score += 100;
388
+ if (typeof n.text === "string" && n.text.trim().length > 0) score += 60;
389
+ if (typeof n.accessibilityLabel === "string" && n.accessibilityLabel.trim().length > 0) {
390
+ score += 30;
391
+ }
392
+ if (n.accessibilityRole) score += 15;
393
+ const w = n.layout?.width ?? 0;
394
+ const h = n.layout?.height ?? 0;
395
+ const area = w * h;
396
+ if (area >= 400 && area <= 6e4) score += 25;
397
+ else if (area > 6e4) score -= 20;
398
+ const y = n.absolutePosition?.y ?? 0;
399
+ if (y < 0) score -= 30;
400
+ return score;
401
+ }
402
+ function tapCommandForNode(n) {
403
+ if (n.testID) return `sootsim do tap-id ${shellEscape(n.testID)}`;
404
+ const text = typeof n.text === "string" ? n.text.trim() : "";
405
+ if (text.length > 0 && text.length <= 80)
406
+ return `sootsim do tap-text ${shellEscape(text)}`;
407
+ const x = Math.round(((n.absolutePosition?.x ?? 0) + (n.layout?.width ?? 0) / 2) * 10) / 10;
408
+ const y = Math.round(((n.absolutePosition?.y ?? 0) + (n.layout?.height ?? 0) / 2) * 10) / 10;
409
+ return `sootsim do tap ${x} ${y}`;
410
+ }
411
+ function shellEscape(value) {
412
+ if (/^[A-Za-z0-9_./@:-]+$/.test(value)) return value;
413
+ return `'${value.replace(/'/g, `'\\''`)}'`;
414
+ }
415
+ var WAIT_READY_PROBE = `(async () => {
416
+ const t = window.__sootsimTest
417
+ let nodes = 0
418
+ try { nodes = (await t?.getNodeCount?.()) || 0 } catch {}
419
+ let targets = 0
420
+ let loadingText = ''
421
+ try {
422
+ if (typeof t?.listInspectable === 'function') {
423
+ const list = await t.listInspectable({})
424
+ if (Array.isArray(list)) {
425
+ const screenW = window.innerWidth || 0
426
+ const screenH = window.innerHeight || 0
427
+ const isVisible = (n) => {
428
+ const layout = n?.layout
429
+ if (!layout || layout.width <= 0 || layout.height <= 0) return false
430
+ const abs = n?.absolutePosition || n?.absolute
431
+ if (!abs) return true
432
+ const device = n?.device || {}
433
+ const w = Number(device.width) || screenW
434
+ const h = Number(device.height) || screenH
435
+ return (
436
+ abs.x + layout.width > 0 &&
437
+ abs.y + layout.height > 0 &&
438
+ abs.x < w &&
439
+ abs.y < h
440
+ )
441
+ }
442
+ const hasContentSignal = (n) => {
443
+ const role = n?.accessibilityRole || n?.role
444
+ const label = n?.accessibilityLabel || n?.label
445
+ const handlers = Array.isArray(n?.handlers) ? n.handlers : []
446
+ const text = typeof n?.text === 'string' ? n.text.trim() : ''
447
+ const testID = typeof (n?.testID || n?.testId) === 'string' ? (n.testID || n.testId) : ''
448
+ if (!loadingText && /^(opening app|loading|capturing|connecting)$/i.test(text)) {
449
+ loadingText = text
450
+ }
451
+ if (handlers.length > 0) return true
452
+ if (role) return true
453
+ if (n?.isTextInput) return true
454
+ if (text) return true
455
+ if (label) return true
456
+ if (testID && !/^splash|loading/i.test(testID)) return true
457
+ return false
458
+ }
459
+ targets = list.filter(n => isVisible(n) && hasContentSignal(n)).length
460
+ }
461
+ }
462
+ } catch {}
463
+ let externalReady = null
464
+ let externalStatus = ''
465
+ let externalError = ''
466
+ try {
467
+ const getExternalAppState = t?.getExternalAppState
468
+ const external = typeof getExternalAppState === 'function'
469
+ ? await Promise.race([
470
+ getExternalAppState(),
471
+ new Promise((resolve) => setTimeout(
472
+ () => resolve({
473
+ state: {
474
+ ready: false,
475
+ loading: true,
476
+ status: 'waiting for tenant worker...',
477
+ },
478
+ }),
479
+ 1000,
480
+ )),
481
+ ])
482
+ : null
483
+ const state = external?.state
484
+ if (state && typeof state === 'object') {
485
+ externalReady = state.ready === true
486
+ if (typeof state.status === 'string') externalStatus = state.status
487
+ if (typeof state.error === 'string') externalError = state.error
488
+ }
489
+ if (!externalError && Array.isArray(external?.entryErrors)) {
490
+ const entry = external.entryErrors.find((item) => {
491
+ return item && typeof item.message === 'string' && item.message.trim()
492
+ })
493
+ if (entry) externalError = entry.message
494
+ }
495
+ if (externalReady === false && externalStatus) loadingText = externalStatus
496
+ } catch {}
497
+ let errors = 0
498
+ try { errors = window.__sootsimConsole?.count?.()?.errors ?? 0 } catch {}
499
+ return {
500
+ flag: (window).__sootsimExternalAppReady,
501
+ at: (window).__sootsimExternalAppReadyAt || 0,
502
+ nodes,
503
+ targets,
504
+ errors,
505
+ loadingText,
506
+ externalReady,
507
+ externalStatus,
508
+ externalError,
509
+ }
510
+ })()`;
511
+ var READY_CONTENT_NODE_FLOOR = 100;
512
+ var READY_NODE_STABLE_MS = 750;
513
+ var WAIT_READY_PROGRESS_INTERVAL_MS = 2e3;
514
+ function readyProbeHasContent(probe) {
515
+ return probe.targets > 0 || probe.nodes >= READY_CONTENT_NODE_FLOOR;
516
+ }
517
+ function waitReadyReason(status) {
518
+ return status.externalError ? `guest app errored: ${status.externalError}` : status.loadingText ? `still showing "${status.loadingText}"` : status.externalReady === false ? "guest app is still loading" : status.flag !== true ? "guest app has not emitted sootsim:externalAppReady" : status.targets <= 0 ? "ready flag emitted but no visible app content is inspectable yet" : "node tree is still changing";
519
+ }
520
+ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
521
+ const start = Date.now();
522
+ const deadline = start + timeoutMs;
523
+ const progressIntervalMs = options.progressIntervalMs ?? WAIT_READY_PROGRESS_INTERVAL_MS;
524
+ let nextProgressAt = start + progressIntervalMs;
525
+ let lastNodes = -1;
526
+ let nodeStableSince = start;
527
+ let last = {
528
+ flag: void 0,
529
+ at: 0,
530
+ nodes: 0,
531
+ targets: 0,
532
+ errors: 0,
533
+ loadingText: "",
534
+ externalReady: null,
535
+ externalStatus: "",
536
+ externalError: ""
537
+ };
538
+ while (Date.now() < deadline) {
539
+ try {
540
+ last = await bridge.send({ type: "evaluate", code: WAIT_READY_PROBE }) ?? last;
541
+ } catch {
542
+ }
543
+ const now = Date.now();
544
+ const status = {
545
+ ready: false,
546
+ elapsedMs: now - start,
547
+ nodes: last.nodes,
548
+ targets: last.targets,
549
+ flag: last.flag,
550
+ loadingText: last.loadingText,
551
+ externalReady: last.externalReady,
552
+ externalStatus: last.externalStatus,
553
+ externalError: last.externalError,
554
+ errors: last.errors
555
+ };
556
+ if (last.nodes !== lastNodes) {
557
+ lastNodes = last.nodes;
558
+ nodeStableSince = now;
559
+ }
560
+ if (last.flag === true) {
561
+ if (last.externalReady !== false && !last.externalError && !last.loadingText && readyProbeHasContent(last)) {
562
+ if (now - nodeStableSince >= READY_NODE_STABLE_MS) {
563
+ return {
564
+ ...status,
565
+ ready: true
566
+ };
567
+ }
568
+ }
569
+ }
570
+ if (options.onProgress && progressIntervalMs > 0 && now >= nextProgressAt) {
571
+ options.onProgress(status);
572
+ do {
573
+ nextProgressAt += progressIntervalMs;
574
+ } while (now >= nextProgressAt);
575
+ }
576
+ await new Promise((r) => setTimeout(r, 150));
577
+ }
578
+ return {
579
+ ready: false,
580
+ elapsedMs: Date.now() - start,
581
+ nodes: last.nodes,
582
+ targets: last.targets,
583
+ flag: last.flag,
584
+ loadingText: last.loadingText,
585
+ externalReady: last.externalReady,
586
+ externalStatus: last.externalStatus,
587
+ externalError: last.externalError,
588
+ errors: last.errors
589
+ };
590
+ }
591
+ async function inspectWaitSelector(bridge, testId, timeoutMs = 5e3, opts = {}) {
592
+ const gone = opts.gone === true;
593
+ const result = await bridge.send(
594
+ {
595
+ type: "evaluate",
596
+ code: `(async () => {
597
+ const start = Date.now()
598
+ const deadline = start + ${timeoutMs}
599
+ const gone = ${gone}
600
+ const ID = ${JSON.stringify(testId)}
601
+ const present = (node) => !!(node && node.layout && node.layout.width > 0 && node.layout.height > 0)
602
+ const find = async () => {
603
+ const t = window.__sootsimTest
604
+ if (!t) return undefined // bridge not ready \u2014 indeterminate, not "gone"
605
+ try {
606
+ const matches = await t.queryAll?.({ hasId: ID, pruneHidden: true })
607
+ if (!Array.isArray(matches)) return undefined
608
+ return matches.find(present) || null
609
+ } catch {
610
+ return undefined
611
+ }
612
+ }
613
+ let goneStreak = 0
614
+ while (Date.now() < deadline) {
615
+ const node = await find()
616
+ if (gone) {
617
+ if (node === null) {
618
+ goneStreak += 1
619
+ if (goneStreak >= 2) return { found: true, elapsed: Date.now() - start }
620
+ } else {
621
+ goneStreak = 0
622
+ }
623
+ } else if (present(node)) {
624
+ return { found: true, node, elapsed: Date.now() - start }
625
+ }
626
+ await new Promise((r) => setTimeout(r, 80))
627
+ }
628
+ return { found: false, elapsed: Date.now() - start }
629
+ })()`
630
+ },
631
+ {
632
+ timeoutMs: timeoutMs + 1e3
633
+ }
634
+ );
635
+ return result ?? { found: false, elapsed: timeoutMs };
636
+ }
637
+ async function inspectErrors(bridge, limit = 20) {
638
+ const result = await bridge.send({
639
+ type: "evaluate",
640
+ code: `window.__sootsimConsole?.getErrors(${limit}) || []`
641
+ });
642
+ return Array.isArray(result) ? result : [];
643
+ }
644
+ async function inspectWarnings(bridge, limit = 20) {
645
+ const result = await bridge.send({
646
+ type: "evaluate",
647
+ code: `window.__sootsimConsole?.getWarnings(${limit}) || []`
648
+ });
649
+ return Array.isArray(result) ? result : [];
650
+ }
651
+ async function clearConsole(bridge) {
652
+ await bridge.send({
653
+ type: "evaluate",
654
+ code: 'window.__sootsimConsole?.clear(); "cleared"'
655
+ });
656
+ }
657
+ async function inspectRequests(bridge, opts = {}) {
658
+ const limit = opts.limit ?? 20;
659
+ const method = opts.failed === false ? "getRequests" : "getFailedRequests";
660
+ const result = await bridge.send({
661
+ type: "call",
662
+ path: `__sootsimTest.${method}`,
663
+ args: [limit]
664
+ });
665
+ return Array.isArray(result) ? result : [];
666
+ }
667
+ async function clearRequests(bridge) {
668
+ await bridge.send({ type: "call", path: "__sootsimTest.clearRequests", args: [] });
669
+ }
670
+ async function inspectScrollStateAt(bridge, x, y) {
671
+ const result = await bridge.send({
672
+ type: "call",
673
+ path: "__sootsimTest.getScrollStateAt",
674
+ args: [x, y]
675
+ });
676
+ return result && typeof result === "object" ? result : null;
677
+ }
678
+ async function inspectLogs(bridge) {
679
+ const res = await bridge.send({
680
+ type: "evaluate",
681
+ code: `(() => {
682
+ const obs = window.__sootsimObservability;
683
+ if (!obs) return { ok: false };
684
+ return { ok: true, entries: obs.logs.getSnapshot() };
685
+ })()`
686
+ });
687
+ if (!res || !res.ok) return [];
688
+ return res.entries ?? [];
689
+ }
690
+ async function clearLogs(bridge) {
691
+ await bridge.send({
692
+ type: "evaluate",
693
+ code: 'window.__sootsimObservability?.logs.clear(); "cleared"'
694
+ });
695
+ }
696
+ function isForwardedWorkerLogTwin(a, b) {
697
+ if (a.source === b.source) return false;
698
+ if (a.level !== b.level) return false;
699
+ if (Math.abs(a.ts - b.ts) > 1e3) return false;
700
+ if (a.args.length !== b.args.length) return false;
701
+ const sources = /* @__PURE__ */ new Set([a.source, b.source]);
702
+ if (!sources.has("sootsim-worker")) return false;
703
+ if (!sources.has("render-worker") && !sources.has("forwarded-render-worker")) {
704
+ return false;
705
+ }
706
+ return a.args.every((arg, index) => arg === b.args[index]);
707
+ }
708
+ function filterLogEntries(entries, opts = {}) {
709
+ let out = [];
710
+ for (const entry of entries) {
711
+ if (out.some((candidate) => isForwardedWorkerLogTwin(candidate, entry))) {
712
+ continue;
713
+ }
714
+ out.push(entry);
715
+ }
716
+ if (!opts.showInternal) {
717
+ out = out.filter((e) => {
718
+ const first = e.args[0];
719
+ return !(typeof first === "string" && first.startsWith("[sootsim]"));
720
+ });
721
+ }
722
+ if (opts.level) out = out.filter((e) => opts.level.has(e.level));
723
+ if (opts.filter) {
724
+ const lf = opts.filter.toLowerCase();
725
+ out = out.filter((e) => e.args.join(" ").toLowerCase().includes(lf));
726
+ }
727
+ return out;
728
+ }
729
+ async function inspectTimelineSummary(bridge, query) {
730
+ return await bridge.send({
731
+ type: "call",
732
+ path: "SootSim.bridges.timeline.summary",
733
+ args: [query]
734
+ });
735
+ }
736
+ async function inspectTimelineRecent(bridge, query) {
737
+ return await bridge.send({
738
+ type: "call",
739
+ path: "SootSim.bridges.timeline.recent",
740
+ args: [query]
741
+ });
742
+ }
743
+ async function inspectTimelineAdvanceCursor(bridge, cursorKey, watermark) {
744
+ await bridge.send({
745
+ type: "call",
746
+ path: "SootSim.bridges.timeline.cursorAdvance",
747
+ args: [cursorKey, watermark]
748
+ });
749
+ }
750
+ async function inspectKeyboard(bridge) {
751
+ const result = await bridge.send({
752
+ type: "evaluate",
753
+ code: `(() => {
754
+ const kb = window.__sootsimKeyboard
755
+ if (!kb || typeof kb.getLayout !== 'function') {
756
+ return { error: 'keyboard bridge getLayout() not available' }
757
+ }
758
+ return kb.getLayout()
759
+ })()`
760
+ });
761
+ return result ?? { error: "keyboard bridge returned no result" };
762
+ }
763
+ function isShellCommandUnavailable(error) {
764
+ const message = error instanceof Error ? error.message : String(error);
765
+ return message.includes("call target not found: SootSim.bridges.mainShell") || message.includes("test bridge unavailable before app-in-worker boot");
766
+ }
767
+ async function getShellState(bridge, readyTimeoutMs = 0) {
768
+ const deadline = Date.now() + Math.max(0, readyTimeoutMs);
769
+ while (true) {
770
+ try {
771
+ return await bridge.send({
772
+ type: "call",
773
+ path: "SootSim.bridges.mainShell.getState",
774
+ args: []
775
+ });
776
+ } catch (error) {
777
+ if (!isShellCommandUnavailable(error) || Date.now() >= deadline) throw error;
778
+ await new Promise((r) => setTimeout(r, 50));
779
+ }
780
+ }
781
+ }
782
+ async function inspectScreens(bridge) {
783
+ const payload = await bridge.send({
784
+ type: "evaluate",
785
+ code: `(async () => {
786
+ const test = window.__sootsimTest
787
+ const kb = window.__sootsimKeyboard
788
+ const navSnap =
789
+ test && typeof test.getNavigationSnapshot === 'function'
790
+ ? await test.getNavigationSnapshot()
791
+ : null
792
+ const keyboard =
793
+ kb && typeof kb.getLayout === 'function'
794
+ ? (() => {
795
+ const layout = kb.getLayout()
796
+ return layout ? {
797
+ visible: layout.visible,
798
+ mode: layout.mode,
799
+ spec: layout.spec
800
+ ? {
801
+ keyboardType: layout.spec.keyboardType,
802
+ returnKeyType: layout.spec.returnKeyType,
803
+ }
804
+ : null,
805
+ } : null
806
+ })()
807
+ : null
808
+ return { nav: navSnap, keyboard }
809
+ })()`
810
+ });
811
+ const shell = await getShellState(bridge, 500).catch(() => null);
812
+ return {
813
+ shell,
814
+ nav: payload?.nav ?? null,
815
+ keyboard: payload?.keyboard ?? null
816
+ };
817
+ }
818
+ var DEBUG_CHANNELS = [
819
+ "portals",
820
+ "sheets",
821
+ "layout",
822
+ "onlayout",
823
+ "animated",
824
+ "render",
825
+ "touch",
826
+ "yoga"
827
+ ];
828
+ async function inspectDebugStatus(bridge) {
829
+ return bridge.send({ type: "evaluate", code: "window.__sootsimDebug.status()" });
830
+ }
831
+ async function inspectDebugFlags(bridge) {
832
+ return bridge.send({ type: "evaluate", code: "window.__sootsimDebug.flags()" });
833
+ }
834
+ async function inspectDebugFind(bridge, target) {
835
+ const method = target === "sheets" ? "findSheets" : "findPortals";
836
+ return bridge.send({
837
+ type: "evaluate",
838
+ code: `window.__sootsimDebug.${method}()`
839
+ });
840
+ }
841
+ async function inspectDebugRecent(bridge, channel, limit = 50) {
842
+ const code = channel && channel !== "all" ? `window.__sootsimDebug.recent(${JSON.stringify(channel)}, ${limit})` : `window.__sootsimDebug.recent(undefined, ${limit})`;
843
+ return bridge.send({ type: "evaluate", code });
844
+ }
845
+ async function setDebugChannels(bridge, action, channels) {
846
+ const args = channels.length > 0 ? channels.map((c) => JSON.stringify(c)).join(", ") : action === "disable" ? "'all'" : "";
847
+ return bridge.send({
848
+ type: "evaluate",
849
+ code: `window.__sootsimDebug.${action}(${args})`
850
+ });
851
+ }
852
+ async function inspectMemory(bridge) {
853
+ const result = await bridge.send({
854
+ type: "evaluate",
855
+ code: `(async () => {
856
+ const host = window.__sootsimRenderHost
857
+ const stats = host?.queryStats ? await host.queryStats() : null
858
+ const hostMem = performance.memory
859
+ ? {
860
+ usedJSHeapSize: performance.memory.usedJSHeapSize,
861
+ totalJSHeapSize: performance.memory.totalJSHeapSize,
862
+ jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
863
+ }
864
+ : null
865
+ return {
866
+ imageLoader: stats?.memory?.imageLoader ?? null,
867
+ workerHeap: stats?.memory?.workerHeap ?? null,
868
+ hostHeap: hostMem,
869
+ }
870
+ })()`
871
+ });
872
+ return result ?? { imageLoader: null, workerHeap: null, hostHeap: null };
873
+ }
874
+ function formatTimelineSummary(summary) {
875
+ if (summary.total === 0) return "nothing recorded";
876
+ const parts = [];
877
+ const ORDER = [
878
+ "error",
879
+ "warning",
880
+ "console",
881
+ "fetch",
882
+ "toast",
883
+ "alert",
884
+ "actionsheet",
885
+ "picker",
886
+ "notification",
887
+ "screen",
888
+ "route",
889
+ "keyboard",
890
+ "app-launch",
891
+ "shell",
892
+ "scroll",
893
+ "gesture",
894
+ "text-input",
895
+ "react-commit",
896
+ "animation",
897
+ "reanimated"
898
+ ];
899
+ const seen = /* @__PURE__ */ new Set();
900
+ for (const k of ORDER) {
901
+ const n = summary.byKind[k];
902
+ if (n) {
903
+ parts.push(`${n} ${k}${n === 1 ? "" : "s"}`);
904
+ seen.add(k);
905
+ }
906
+ }
907
+ for (const [k, n] of Object.entries(summary.byKind)) {
908
+ if (!seen.has(k) && n) parts.push(`${n} ${k}${n === 1 ? "" : "s"}`);
909
+ }
910
+ return parts.join(" \xB7 ");
911
+ }
912
+
913
+ // cli/commands/inspect/settling.ts
914
+ async function waitForSootsimIdle({
915
+ bridge,
916
+ simId,
917
+ maxMs,
918
+ pollMs = 50,
919
+ stablePolls = 3,
920
+ strict = false
921
+ }) {
922
+ const result = await bridge.send(
923
+ {
924
+ type: "evaluate",
925
+ simId,
926
+ code: `(async () => {
927
+ const start = Date.now()
928
+ const deadline = start + ${Math.max(0, Math.round(maxMs))}
929
+ const pollMs = ${Math.max(1, Math.round(pollMs))}
930
+ const requiredStablePolls = ${Math.max(1, Math.round(stablePolls))}
931
+ const strict = ${strict ? "true" : "false"}
932
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
933
+
934
+ // route-aware settle: a tap that pushes/pops a screen is async \u2014 the
935
+ // old screen still renders for a moment, then the new one mounts and
936
+ // its content loads. a pure layout-hash check reports "idle" on the
937
+ // outgoing screen or on the incoming skeleton, so a driver re-taps
938
+ // and stacks duplicate navigations. drain any in-flight screen
939
+ // transition FIRST, bounded by the overall budget. when no
940
+ // transition is happening this returns in ~80ms (startWindowMs), so
941
+ // a plain button tap barely pays for it.
942
+ try {
943
+ const wfst = window.__sootsimTest?.waitForScreenTransitions
944
+ if (typeof wfst === 'function') {
945
+ const remaining = deadline - Date.now()
946
+ if (remaining > 120) {
947
+ await wfst({
948
+ timeoutMs: Math.min(remaining - 80, 4000),
949
+ settleMs: 64,
950
+ startWindowMs: 80,
951
+ })
952
+ }
953
+ }
954
+ } catch {}
955
+
956
+ const readSnapshot = async () => {
957
+ let animating = false
958
+ let pendingFetches = 0
959
+ let requestTotal = 0
960
+ let requestInFlight = 0
961
+ try {
962
+ const stats = await window.__sootsimRenderHost?.queryStats?.()
963
+ if (stats) {
964
+ animating =
965
+ stats.hasActiveAnims === true ||
966
+ stats.hasActiveNativeAnimations === true ||
967
+ stats.hasPendingAnimationFrames === true
968
+ // a freshly-pushed screen showing a skeleton is layout-stable
969
+ // but not actually settled \u2014 its data/images are still in
970
+ // flight. treat bounded image-loader fetches as not-idle so
971
+ // settle waits for real content, capped by the budget.
972
+ const pf = stats.memory && stats.memory.imageLoader
973
+ ? stats.memory.imageLoader.pendingFetches
974
+ : 0
975
+ pendingFetches = typeof pf === 'number' ? pf : 0
976
+ }
977
+ } catch {}
978
+ try {
979
+ const counts = await window.__sootsimTest?.getRequestCounts?.()
980
+ requestTotal = typeof counts?.total === 'number' ? counts.total : 0
981
+ requestInFlight = typeof counts?.inFlight === 'number' ? counts.inFlight : 0
982
+ } catch {}
983
+ const root = window.__sootsimRoot
984
+ const nodes = []
985
+ if (root) {
986
+ const walk = (n) => {
987
+ if (n.layout && n.layout.width > 0) {
988
+ nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
989
+ }
990
+ for (const c of n.children || []) walk(c)
991
+ }
992
+ walk(root)
993
+ }
994
+ return { layout: nodes.join(';'), animating, pendingFetches, requestTotal, requestInFlight }
995
+ }
996
+
997
+ let lastLayout = ''
998
+ let lastRequestTotal = -1
999
+ let stable = 0
1000
+ while (Date.now() < deadline) {
1001
+ const snapshot = await readSnapshot()
1002
+ const strictOk = !strict || !snapshot.animating
1003
+ const contentReady = snapshot.pendingFetches === 0 && snapshot.requestInFlight === 0
1004
+ const requestsStable = snapshot.requestTotal === lastRequestTotal
1005
+ if (strictOk && contentReady && requestsStable && snapshot.layout === lastLayout) {
1006
+ stable++
1007
+ if (stable >= requiredStablePolls) {
1008
+ return { settled: true, elapsed: Date.now() - start }
1009
+ }
1010
+ } else {
1011
+ stable = 0
1012
+ }
1013
+ lastLayout = snapshot.layout
1014
+ lastRequestTotal = snapshot.requestTotal
1015
+ await sleep(pollMs)
1016
+ }
1017
+ return { settled: false, elapsed: Date.now() - start }
1018
+ })()`
1019
+ },
1020
+ {
1021
+ timeoutMs: maxMs + 1e3
1022
+ }
1023
+ );
1024
+ const { elapsed, settled } = result ?? {};
1025
+ return {
1026
+ elapsed: typeof elapsed === "number" ? elapsed : maxMs,
1027
+ settled: settled === true
1028
+ };
1029
+ }
1030
+
1031
+ // cli/commands/inspect/actions.ts
1032
+ var DEFAULT_AGENT_TIMING = {
1033
+ initialWaitMs: 3e3,
1034
+ deadlineMs: 5e3,
1035
+ retryWaitMs: 700
1036
+ };
1037
+ var DEFAULT_INTERACTIVE_TIMING = {
1038
+ initialWaitMs: 1200,
1039
+ deadlineMs: 2500,
1040
+ retryWaitMs: 700
1041
+ };
1042
+ function tapTiming(agent, opts = {}) {
1043
+ return {
1044
+ ...agent ? DEFAULT_AGENT_TIMING : DEFAULT_INTERACTIVE_TIMING,
1045
+ ...opts
1046
+ };
1047
+ }
1048
+ function isTapSuccess(result) {
1049
+ if (!result || result.hit === false || result.ok === false) return false;
1050
+ if (result.pointerTapHandled === false && !result.keyboardOpened && !result.isTextInput) {
1051
+ return false;
1052
+ }
1053
+ return true;
1054
+ }
1055
+ function tapTargetFromPayload(payload, textFallback) {
1056
+ return {
1057
+ id: payload.target?.id ?? payload.match?.id ?? payload.node?.id ?? null,
1058
+ testID: payload.target?.testID ?? payload.match?.testID ?? payload.node?.testID ?? null,
1059
+ text: payload.target?.text ?? payload.target?.accessibilityLabel ?? payload.match?.text ?? payload.match?.accessibilityLabel ?? payload.node?.text ?? textFallback ?? null,
1060
+ type: payload.target?.type ?? payload.match?.type ?? payload.node?.type ?? null
1061
+ };
1062
+ }
1063
+ async function tapResolvedTarget(bridge, args) {
1064
+ const timing = tapTiming(!!args.agent, args.timing);
1065
+ let attempts = 0;
1066
+ let lastPayload = null;
1067
+ let lastResult = null;
1068
+ try {
1069
+ await waitForSootsimIdle({
1070
+ bridge,
1071
+ maxMs: timing.initialWaitMs,
1072
+ pollMs: 32,
1073
+ stablePolls: 2
1074
+ });
1075
+ } catch {
1076
+ }
1077
+ const deadline = Date.now() + timing.deadlineMs;
1078
+ while (Date.now() <= deadline || attempts === 0) {
1079
+ attempts++;
1080
+ const payload = await args.resolve();
1081
+ lastPayload = payload;
1082
+ if (payload?.error === "bridge-not-ready" || payload?.ambiguous || payload?.nthOutOfRange) {
1083
+ return { payload, result: null, attempts, failure: "special" };
1084
+ }
1085
+ if (payload && typeof payload.cx === "number" && typeof payload.cy === "number") {
1086
+ const result = await bridge.send({
1087
+ type: "tap",
1088
+ x: payload.cx,
1089
+ y: payload.cy,
1090
+ target: tapTargetFromPayload(payload, args.textFallback)
1091
+ });
1092
+ lastResult = result;
1093
+ if (isTapSuccess(result)) return { payload, result, attempts };
1094
+ }
1095
+ const remaining = deadline - Date.now();
1096
+ if (remaining <= 0) break;
1097
+ try {
1098
+ await waitForSootsimIdle({
1099
+ bridge,
1100
+ maxMs: Math.min(remaining, timing.retryWaitMs),
1101
+ pollMs: 32,
1102
+ stablePolls: 2
1103
+ });
1104
+ } catch {
1105
+ await new Promise((resolve) => setTimeout(resolve, Math.min(120, remaining)));
1106
+ }
1107
+ }
1108
+ return {
1109
+ payload: lastPayload,
1110
+ result: lastResult,
1111
+ attempts,
1112
+ failure: lastPayload && typeof lastPayload.cx === "number" ? "missed" : "not-found"
1113
+ };
1114
+ }
1115
+ async function tapCoordinates(bridge, x, y, target) {
1116
+ return bridge.send({
1117
+ type: "tap",
1118
+ x,
1119
+ y,
1120
+ ...target ? { target } : {}
1121
+ });
1122
+ }
1123
+ async function tapById(bridge, query, opts = {}) {
1124
+ const arg = JSON.stringify(query);
1125
+ return tapResolvedTarget(bridge, {
1126
+ agent: opts.agent,
1127
+ timing: opts.timing,
1128
+ resolve: () => bridge.send({
1129
+ type: "evaluate",
1130
+ code: `(async () => {
1131
+ const t = window.__sootsimTest
1132
+ if (!t) return null
1133
+ const n = (await t.findByTestId(${arg})) || (await t.findById(${arg}))
1134
+ if (!n || !n.absolutePosition || !n.layout) return { cx: null }
1135
+ const resolved =
1136
+ typeof n.nodeId === 'number' && typeof t.resolveTapTarget === 'function'
1137
+ ? await t.resolveTapTarget(n.nodeId)
1138
+ : null
1139
+ const target = (resolved && resolved.target) || n
1140
+ const cx =
1141
+ resolved && typeof resolved.cx === 'number'
1142
+ ? resolved.cx
1143
+ : n.absolutePosition.x + (n.layout.width || 0) / 2
1144
+ const cy =
1145
+ resolved && typeof resolved.cy === 'number'
1146
+ ? resolved.cy
1147
+ : n.absolutePosition.y + (n.layout.height || 0) / 2
1148
+ return {
1149
+ cx,
1150
+ cy,
1151
+ match: {
1152
+ nodeId: n.nodeId ?? null,
1153
+ id: n.id,
1154
+ testID: n.testID,
1155
+ text: n.text ?? n.accessibilityLabel ?? null,
1156
+ type: n.type,
1157
+ },
1158
+ target: {
1159
+ nodeId: target.nodeId ?? null,
1160
+ id: target.id,
1161
+ testID: target.testID,
1162
+ text:
1163
+ target.text ??
1164
+ target.accessibilityLabel ??
1165
+ n.text ??
1166
+ n.accessibilityLabel ??
1167
+ null,
1168
+ type: target.type,
1169
+ },
1170
+ strategy: (resolved && resolved.strategy) || 'matched-node',
1171
+ }
1172
+ })()`
1173
+ })
1174
+ });
1175
+ }
1176
+ async function tapByText(bridge, query, options = {}, opts = {}) {
1177
+ const filterArg = JSON.stringify({
1178
+ query,
1179
+ exact: !!options.exact,
1180
+ role: options.role ?? null,
1181
+ within: options.within ?? null,
1182
+ minX: options.minX ?? null,
1183
+ maxX: options.maxX ?? null,
1184
+ minY: options.minY ?? null,
1185
+ maxY: options.maxY ?? null,
1186
+ near: options.near ?? null,
1187
+ nth: options.nth ?? null,
1188
+ first: !!options.first
1189
+ });
1190
+ return tapResolvedTarget(bridge, {
1191
+ agent: opts.agent,
1192
+ timing: opts.timing,
1193
+ textFallback: query,
1194
+ resolve: () => bridge.send({
1195
+ type: "evaluate",
1196
+ code: `(async () => {
1197
+ const t = window.__sootsimTest
1198
+ if (!t) return { error: 'bridge-not-ready' }
1199
+ const F = ${filterArg}
1200
+
1201
+ const res = await t.queryTextCandidates({
1202
+ query: F.query,
1203
+ exact: !!F.exact,
1204
+ ...(F.role ? { role: F.role } : {}),
1205
+ })
1206
+
1207
+ let candidates = res.candidates || []
1208
+
1209
+ candidates = candidates.filter((c) => {
1210
+ const ax = c.info.absolutePosition && c.info.absolutePosition.x
1211
+ const ay = c.info.absolutePosition && c.info.absolutePosition.y
1212
+ if (F.minX !== null && !(ax >= F.minX)) return false
1213
+ if (F.maxX !== null && !(ax <= F.maxX)) return false
1214
+ if (F.minY !== null && !(ay >= F.minY)) return false
1215
+ if (F.maxY !== null && !(ay <= F.maxY)) return false
1216
+ if (F.within && !c.ancestorTestIDs.includes(F.within)) return false
1217
+ return true
1218
+ })
1219
+
1220
+ if (F.near) {
1221
+ candidates.sort((a, b) => {
1222
+ const ax = (a.info.absolutePosition && a.info.absolutePosition.x) || 0
1223
+ const ay = (a.info.absolutePosition && a.info.absolutePosition.y) || 0
1224
+ const bx = (b.info.absolutePosition && b.info.absolutePosition.x) || 0
1225
+ const by = (b.info.absolutePosition && b.info.absolutePosition.y) || 0
1226
+ return (
1227
+ Math.hypot(ax - F.near.x, ay - F.near.y) -
1228
+ Math.hypot(bx - F.near.x, by - F.near.y)
1229
+ )
1230
+ })
1231
+ } else {
1232
+ candidates.sort((a, b) => {
1233
+ const ay = (a.info.absolutePosition && a.info.absolutePosition.y) || 0
1234
+ const by = (b.info.absolutePosition && b.info.absolutePosition.y) || 0
1235
+ if (Math.abs(ay - by) > 2) return ay - by
1236
+ const ax = (a.info.absolutePosition && a.info.absolutePosition.x) || 0
1237
+ const bx = (b.info.absolutePosition && b.info.absolutePosition.x) || 0
1238
+ return ax - bx
1239
+ })
1240
+ }
1241
+
1242
+ const total = candidates.length
1243
+ if (total === 0) return { matched: 0, total: 0 }
1244
+
1245
+ let idx = 0
1246
+ if (F.nth !== null) {
1247
+ idx = F.nth < 0 ? total + F.nth : F.nth
1248
+ if (idx < 0 || idx >= total) {
1249
+ return { matched: 0, total, nthOutOfRange: true, nth: F.nth }
1250
+ }
1251
+ } else if (total > 1 && !F.first && !F.near) {
1252
+ return {
1253
+ ambiguous: true,
1254
+ total,
1255
+ candidates: candidates.slice(0, 10).map((c, i) => ({
1256
+ idx: i,
1257
+ nodeId: c.info.nodeId,
1258
+ type: c.info.type,
1259
+ testID: c.info.testID,
1260
+ text: (c.info.text || '').slice(0, 60),
1261
+ abs: c.info.absolutePosition,
1262
+ layout: c.info.layout
1263
+ ? {
1264
+ width: Math.round(c.info.layout.width || 0),
1265
+ height: Math.round(c.info.layout.height || 0),
1266
+ }
1267
+ : null,
1268
+ ancestorTestIDs: (c.ancestorTestIDs || []).slice(0, 5),
1269
+ })),
1270
+ }
1271
+ }
1272
+
1273
+ const picked = candidates[idx]
1274
+ const n = picked.info
1275
+ if (!n.absolutePosition || !n.layout) return { matched: 0, total }
1276
+
1277
+ const resolved =
1278
+ typeof n.nodeId === 'number' &&
1279
+ typeof t.resolveTapTarget === 'function'
1280
+ ? await t.resolveTapTarget(n.nodeId)
1281
+ : null
1282
+ const target = (resolved && resolved.target) || n
1283
+ const cx =
1284
+ resolved && typeof resolved.cx === 'number'
1285
+ ? resolved.cx
1286
+ : n.absolutePosition.x + (n.layout.width || 0) / 2
1287
+ const cy =
1288
+ resolved && typeof resolved.cy === 'number'
1289
+ ? resolved.cy
1290
+ : n.absolutePosition.y + (n.layout.height || 0) / 2
1291
+ return {
1292
+ cx,
1293
+ cy,
1294
+ match: {
1295
+ nodeId: n.nodeId ?? null,
1296
+ id: n.id,
1297
+ testID: n.testID,
1298
+ type: n.type,
1299
+ },
1300
+ target: {
1301
+ nodeId: target.nodeId ?? null,
1302
+ id: target.id,
1303
+ testID: target.testID,
1304
+ text:
1305
+ target.text ??
1306
+ target.accessibilityLabel ??
1307
+ n.text ??
1308
+ n.accessibilityLabel ??
1309
+ null,
1310
+ type: target.type,
1311
+ },
1312
+ strategy: (resolved && resolved.strategy) || 'matched-node',
1313
+ total,
1314
+ idx,
1315
+ }
1316
+ })()`
1317
+ })
1318
+ });
1319
+ }
1320
+ async function tapBest(bridge, query, opts = {}) {
1321
+ const arg = JSON.stringify(query);
1322
+ return tapResolvedTarget(bridge, {
1323
+ agent: opts.agent,
1324
+ timing: opts.timing,
1325
+ textFallback: query,
1326
+ resolve: async () => {
1327
+ const payload = await bridge.send({
1328
+ type: "evaluate",
1329
+ code: `(async () => {
1330
+ const t = window.__sootsimTest
1331
+ if (!t) return { error: 'bridge-not-ready' }
1332
+ const byTestId =
1333
+ (await t.findByTestId(${arg})) || (await t.findById(${arg}))
1334
+ if (byTestId && byTestId.absolutePosition && byTestId.layout) {
1335
+ return {
1336
+ strategy: 'testid',
1337
+ node: {
1338
+ nodeId: byTestId.nodeId ?? null,
1339
+ id: byTestId.id,
1340
+ testID: byTestId.testID,
1341
+ type: byTestId.type,
1342
+ text: byTestId.text,
1343
+ absolutePosition: byTestId.absolutePosition,
1344
+ layout: byTestId.layout,
1345
+ },
1346
+ }
1347
+ }
1348
+ const byText = await t.findByText(${arg})
1349
+ if (byText && byText.absolutePosition && byText.layout) {
1350
+ return {
1351
+ strategy: 'text',
1352
+ node: {
1353
+ nodeId: byText.nodeId ?? null,
1354
+ id: byText.id,
1355
+ testID: byText.testID,
1356
+ type: byText.type,
1357
+ text: byText.text,
1358
+ absolutePosition: byText.absolutePosition,
1359
+ layout: byText.layout,
1360
+ },
1361
+ }
1362
+ }
1363
+ return { strategy: 'none' }
1364
+ })()`
1365
+ });
1366
+ if (!payload || !("node" in payload)) return payload;
1367
+ const node = payload.node;
1368
+ const cx = node.absolutePosition.x + node.layout.width / 2;
1369
+ const cy = node.absolutePosition.y + node.layout.height / 2;
1370
+ return {
1371
+ ...payload,
1372
+ cx,
1373
+ cy,
1374
+ target: {
1375
+ id: node.id,
1376
+ testID: node.testID,
1377
+ text: payload.strategy === "text" ? query : node.text,
1378
+ type: node.type
1379
+ }
1380
+ };
1381
+ }
1382
+ });
1383
+ }
1384
+ // Annotate the CommonJS export names for ESM import in node:
1385
+ 0 && (module.exports = {
1386
+ DEBUG_CHANNELS,
1387
+ READY_CONTENT_NODE_FLOOR,
1388
+ READY_NODE_STABLE_MS,
1389
+ WAIT_READY_PROBE,
1390
+ WAIT_READY_PROGRESS_INTERVAL_MS,
1391
+ clearConsole,
1392
+ clearLogs,
1393
+ clearRequests,
1394
+ filterLogEntries,
1395
+ formatTimelineSummary,
1396
+ getShellState,
1397
+ inspectAccessibilityTree,
1398
+ inspectDebugFind,
1399
+ inspectDebugFlags,
1400
+ inspectDebugRecent,
1401
+ inspectDebugStatus,
1402
+ inspectDescribe,
1403
+ inspectErrors,
1404
+ inspectFind,
1405
+ inspectKeyboard,
1406
+ inspectLogs,
1407
+ inspectMemory,
1408
+ inspectNodeCount,
1409
+ inspectRequests,
1410
+ inspectScreens,
1411
+ inspectScrollStateAt,
1412
+ inspectTimelineAdvanceCursor,
1413
+ inspectTimelineRecent,
1414
+ inspectTimelineSummary,
1415
+ inspectTree,
1416
+ inspectUrl,
1417
+ inspectWaitReady,
1418
+ inspectWaitSelector,
1419
+ inspectWarnings,
1420
+ isInspectModeActive,
1421
+ isInspectPickCommand,
1422
+ isShellCommandUnavailable,
1423
+ isTapSuccess,
1424
+ rankInteractive,
1425
+ readyProbeHasContent,
1426
+ resolveFindMode,
1427
+ resolveMaxMsFlag,
1428
+ scoreInteractive,
1429
+ setDebugChannels,
1430
+ shouldSkipAutoSettleForInspectPick,
1431
+ tapBest,
1432
+ tapById,
1433
+ tapByText,
1434
+ tapCommandForNode,
1435
+ tapCoordinates,
1436
+ tapResolvedTarget,
1437
+ tapTargetFromPayload,
1438
+ waitForSootsimIdle,
1439
+ waitReadyReason
1440
+ });