mobile-debug-mcp 0.34.0 → 0.35.0

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 (432) hide show
  1. package/.agents/skills/mcp-builder/SKILL.md +44 -64
  2. package/.agents/skills/mcp-builder/references/build-flags.md +44 -43
  3. package/.agents/skills/mcp-builder/references/diagnostics-schema.md +4 -1
  4. package/.agents/skills/mcp-builder/references/toolchain-details.md +49 -62
  5. package/.agents/skills/spec-review/references/spec-review-checklist.md +7 -0
  6. package/.agents/skills/test-authoring/SKILL.md +7 -6
  7. package/.agents/skills/test-authoring/references/repo-test-layout.md +3 -1
  8. package/.agents/skills/test-authoring/references/test-authoring-workflow.md +16 -7
  9. package/.agents/skills/test-authoring/references/test-quality-checklist.md +2 -1
  10. package/.github/copilot-instructions.md +14 -36
  11. package/.github/workflows/ci.yml +4 -4
  12. package/AGENTS.md +12 -3
  13. package/CONTRIBUTING.md +79 -0
  14. package/README.md +156 -129
  15. package/agent-plugin/.claude-plugin/plugin.json +2 -2
  16. package/agent-plugin/.codex-plugin/plugin.json +1 -1
  17. package/agent-plugin/.cursor-plugin/plugin.json +2 -2
  18. package/agent-plugin/.mcp.json +1 -1
  19. package/agent-plugin/README.md +16 -6
  20. package/agent-plugin/mcp.json +1 -1
  21. package/agent-plugin/plugin.json +1 -1
  22. package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +27 -2
  23. package/dist/contracts/execution-controls.js +24 -0
  24. package/dist/contracts/selector.js +8 -0
  25. package/dist/contracts/target.js +15 -0
  26. package/dist/contracts/ui.js +1 -0
  27. package/dist/debugger/android.js +2 -1
  28. package/dist/debugger/diagnostics.js +54 -0
  29. package/dist/debugger/protocol.js +33 -0
  30. package/dist/debugger/sessions.js +104 -62
  31. package/dist/debugger/worker.js +53 -42
  32. package/dist/interact/adjustment/adjustment-context.js +41 -0
  33. package/dist/interact/adjustment/adjustment-gestures.js +55 -0
  34. package/dist/interact/adjustment/adjustment-plan.js +18 -0
  35. package/dist/interact/adjustment/adjustment-resolution.js +127 -0
  36. package/dist/interact/adjustment/adjustment-result.js +19 -0
  37. package/dist/interact/adjustment/adjustment-semantic.js +64 -0
  38. package/dist/interact/adjustment/adjustment-verification.js +35 -0
  39. package/dist/interact/adjustment/adjustment.js +52 -0
  40. package/dist/interact/adjustment/control-geometry.js +87 -0
  41. package/dist/interact/adjustment/control-values.js +136 -0
  42. package/dist/interact/adjustment/slider-labels.js +84 -0
  43. package/dist/interact/assertions/screen-assertion.js +37 -0
  44. package/dist/interact/assertions/state-assertion-context.js +35 -0
  45. package/dist/interact/assertions/state-assertion.js +76 -0
  46. package/dist/interact/assertions/state-comparison.js +141 -0
  47. package/dist/interact/assertions/visibility-assertion.js +34 -0
  48. package/dist/interact/conditional-action.js +12 -7
  49. package/dist/interact/index.js +65 -3090
  50. package/dist/interact/input-service.js +1 -0
  51. package/dist/interact/interaction-trace.js +21 -0
  52. package/dist/interact/model.js +1 -0
  53. package/dist/interact/observation.js +1 -0
  54. package/dist/interact/targeting/candidate-ancestor.js +58 -0
  55. package/dist/interact/targeting/candidate-result.js +23 -0
  56. package/dist/interact/targeting/candidate-scoring.js +50 -0
  57. package/dist/interact/targeting/element-helpers.js +216 -0
  58. package/dist/interact/targeting/find-element.js +65 -0
  59. package/dist/interact/targeting/nearby-control.js +56 -0
  60. package/dist/interact/targeting/resolved-elements.js +21 -0
  61. package/dist/interact/targeting/tap-target.js +17 -0
  62. package/dist/interact/targeting/target-scope.js +104 -0
  63. package/dist/interact/waits/legacy-log-wait.js +38 -0
  64. package/dist/interact/waits/legacy-wait-observations.js +103 -0
  65. package/dist/interact/waits/legacy-wait-state.js +34 -0
  66. package/dist/interact/waits/legacy-wait.js +48 -0
  67. package/dist/interact/waits/screen-wait.js +49 -0
  68. package/dist/interact/waits/ui-change-helpers.js +157 -0
  69. package/dist/interact/waits/ui-change-state.js +18 -0
  70. package/dist/interact/waits/ui-change-wait.js +77 -0
  71. package/dist/interact/waits/ui-wait-condition.js +56 -0
  72. package/dist/interact/waits/ui-wait-state.js +38 -0
  73. package/dist/interact/waits/ui-wait.js +106 -0
  74. package/dist/manage/android.js +55 -51
  75. package/dist/manage/index.js +38 -75
  76. package/dist/manage/ios/build-types.js +1 -0
  77. package/dist/manage/ios/build.js +210 -0
  78. package/dist/manage/ios/project-discovery.js +29 -0
  79. package/dist/manage/ios/scheme.js +18 -0
  80. package/dist/manage/ios.js +42 -256
  81. package/dist/observe/android/context.js +1 -0
  82. package/dist/observe/android/current-screen.js +55 -0
  83. package/dist/observe/android/fingerprint.js +13 -0
  84. package/dist/observe/android/log-stream.js +132 -0
  85. package/dist/observe/android/logs.js +107 -0
  86. package/dist/observe/android/screenshot.js +70 -0
  87. package/dist/observe/android/ui-tree.js +107 -0
  88. package/dist/observe/android.js +16 -520
  89. package/dist/observe/evidence.js +114 -75
  90. package/dist/observe/index.js +16 -263
  91. package/dist/observe/ios/context.js +16 -0
  92. package/dist/observe/ios/fingerprint.js +12 -0
  93. package/dist/observe/ios/log-stream.js +105 -0
  94. package/dist/observe/ios/logs.js +168 -0
  95. package/dist/observe/ios/screenshot.js +22 -0
  96. package/dist/observe/ios/ui-elements.js +241 -0
  97. package/dist/observe/ios/ui-tree.js +137 -0
  98. package/dist/observe/ios.js +17 -715
  99. package/dist/observe/logs/model.js +1 -0
  100. package/dist/{network → observe/network}/index.js +2 -2
  101. package/dist/observe/readiness-service.js +4 -2
  102. package/dist/observe/readiness.js +29 -10
  103. package/dist/observe/screenshot-encoding.js +41 -0
  104. package/dist/observe/snapshot-collection.js +79 -0
  105. package/dist/observe/snapshot-logs.js +30 -0
  106. package/dist/observe/snapshot-metadata.js +43 -31
  107. package/dist/observe/snapshot-semantic.js +115 -0
  108. package/dist/observe/system-trace.js +22 -13
  109. package/dist/runtime/action-results.js +270 -0
  110. package/dist/runtime/clock.js +4 -0
  111. package/dist/server/common.js +1 -256
  112. package/dist/server/definitions/assert.js +162 -0
  113. package/dist/server/definitions/diagnostic.js +118 -0
  114. package/dist/server/definitions/input.js +274 -0
  115. package/dist/server/definitions/manage.js +194 -0
  116. package/dist/server/definitions/observe.js +149 -0
  117. package/dist/server/definitions/target.js +138 -0
  118. package/dist/server/definitions/wait.js +105 -0
  119. package/dist/server/handlers/action-execution.js +163 -0
  120. package/dist/server/handlers/correlation.js +23 -0
  121. package/dist/server/{debugger-handlers.js → handlers/debugger-handlers.js} +22 -12
  122. package/dist/server/handlers/debugger-response.js +9 -0
  123. package/dist/server/handlers/diagnostic.js +69 -0
  124. package/dist/server/handlers/handler-types.js +1 -0
  125. package/dist/server/handlers/input.js +154 -0
  126. package/dist/server/handlers/interact.js +113 -0
  127. package/dist/server/handlers/journey-assertions.js +35 -0
  128. package/dist/server/handlers/journey.js +147 -0
  129. package/dist/server/handlers/manage.js +119 -0
  130. package/dist/server/handlers/observe.js +95 -0
  131. package/dist/server/handlers/payload.js +4 -0
  132. package/dist/server/handlers/tool-handlers.js +160 -0
  133. package/dist/server/schemas/condition-schema.js +2 -0
  134. package/dist/server/{debugger-schema.js → schemas/debugger-schema.js} +11 -6
  135. package/dist/server/{journey-schema.js → schemas/journey-schema.js} +7 -22
  136. package/dist/server/tool-definitions.js +58 -1135
  137. package/dist/server-core.js +2 -2
  138. package/dist/system/android-status.js +101 -0
  139. package/dist/system/android.js +37 -27
  140. package/dist/system/index.js +13 -439
  141. package/dist/system/ios-status.js +132 -0
  142. package/dist/system/ios.js +11 -8
  143. package/dist/system/model.js +1 -0
  144. package/dist/system/probes.js +105 -0
  145. package/dist/system/status-summary.js +43 -0
  146. package/dist/system/unsupported-status.js +52 -0
  147. package/dist/utils/android/commands.js +89 -0
  148. package/dist/utils/android/gradle.js +139 -0
  149. package/dist/utils/android/logs.js +103 -0
  150. package/dist/utils/android/ui-tree.js +233 -0
  151. package/dist/utils/android/utils.js +6 -564
  152. package/dist/utils/cli/idb/idb-helper.js +4 -6
  153. package/dist/utils/cli/idb/install-idb.js +13 -9
  154. package/dist/utils/cli/ios/preflight-ios.js +42 -38
  155. package/dist/utils/ios/utils.js +45 -46
  156. package/dist/utils/java.js +65 -49
  157. package/dist/utils/resolve-device.js +4 -2
  158. package/dist/utils/ui/index.js +26 -26
  159. package/docs/CHANGELOG.md +44 -0
  160. package/docs/README.md +38 -0
  161. package/docs/benchmarks/README.md +18 -0
  162. package/docs/benchmarks/interaction-latency/README.md +14 -0
  163. package/docs/benchmarks/interaction-latency/final.md +4 -1
  164. package/docs/benchmarks/interaction-latency/ios-validation.md +2 -0
  165. package/docs/benchmarks/ui-tree-performance/README.md +24 -16
  166. package/docs/benchmarks/ui-tree-performance/comparison.md +11 -10
  167. package/docs/code-structure.md +118 -0
  168. package/docs/specs/001-state-verification/spec.md +16 -14
  169. package/docs/specs/002-richer-element-identity/spec.md +12 -10
  170. package/docs/specs/003-wait-and-synchronization-reliability/spec.md +12 -10
  171. package/docs/specs/004-action-verification-routing/spec.md +3 -3
  172. package/docs/specs/005-unified-action-execution-and-verification-model/spec.md +2 -0
  173. package/docs/specs/006-runtime-action-instrumentation-and-binding-layer/spec.md +2 -0
  174. package/docs/specs/007-actionability-resolution-and-executable-target-selection/spec.md +3 -1
  175. package/docs/specs/008-adjustable-control-support-and-semantic-value-manipulation/spec.md +3 -4
  176. package/docs/specs/009-semantic-control-modeling-for-custom-and-composite-controls/spec.md +2 -0
  177. package/docs/specs/010-verification-stabilization-and-temporal-convergence/spec.md +2 -2
  178. package/docs/specs/011-recovery-and-replanning-for-failed-or-ambiguous-interaction-flows/spec.md +2 -2
  179. package/docs/specs/011.1-recovery-contract-types-and-runtime-wiring-spec/spec.md +2 -0
  180. package/docs/specs/012-action-trace-and-xecution-observability/spec.md +2 -3
  181. package/docs/specs/013-wait-and-synchronization-reliability/spec.md +19 -19
  182. package/docs/specs/014-actionability-resolution/spec.md +20 -18
  183. package/docs/specs/015-adjustable-control-support/spec.md +17 -15
  184. package/docs/specs/016-environment-tools/spec.md +20 -20
  185. package/docs/specs/018-interaction-latency-and-batched-journeys/spec.md +2 -0
  186. package/docs/specs/019-ui-tree-observation-performance/spec.md +3 -1
  187. package/docs/specs/020-conditional-actions/intent.md +5 -3
  188. package/docs/specs/020-conditional-actions/plan.md +8 -9
  189. package/docs/specs/020-conditional-actions/spec.md +4 -2
  190. package/docs/specs/021-app-readiness-signals/intent.md +4 -2
  191. package/docs/specs/021-app-readiness-signals/plan.md +7 -6
  192. package/docs/specs/021-app-readiness-signals/spec.md +3 -1
  193. package/docs/specs/022-correlated-evidence/intent.md +4 -4
  194. package/docs/specs/022-correlated-evidence/plan.md +10 -11
  195. package/docs/specs/022-correlated-evidence/spec.md +3 -1
  196. package/docs/specs/023-android-system-traces/intent.md +3 -2
  197. package/docs/specs/023-android-system-traces/plan.md +5 -7
  198. package/docs/specs/023-android-system-traces/spec.md +3 -1
  199. package/docs/specs/024-android-heap-dump-capture/intent.md +3 -1
  200. package/docs/specs/025-android-runtime-debugger/intent.md +4 -3
  201. package/docs/specs/025-android-runtime-debugger/plan.md +3 -1
  202. package/docs/specs/025-android-runtime-debugger/spec.md +4 -3
  203. package/docs/specs/026-code-structure-and-quality-gates/health-plan.md +88 -0
  204. package/docs/specs/026-code-structure-and-quality-gates/intent.md +47 -0
  205. package/docs/specs/026-code-structure-and-quality-gates/plan.md +191 -0
  206. package/docs/specs/026-code-structure-and-quality-gates/spec.md +138 -0
  207. package/docs/specs/026-code-structure-and-quality-gates/verification-final.json +200 -0
  208. package/docs/specs/026-code-structure-and-quality-gates/verification-thin-facade.json +154 -0
  209. package/docs/specs/026-code-structure-and-quality-gates/verification.json +136 -0
  210. package/docs/specs/027-debugger-failure-diagnostics/intent.md +43 -0
  211. package/docs/specs/027-debugger-failure-diagnostics/plan.md +86 -0
  212. package/docs/specs/027-debugger-failure-diagnostics/spec.md +133 -0
  213. package/docs/specs/028-compact-debugger-responses/intent.md +41 -0
  214. package/docs/specs/028-compact-debugger-responses/plan.md +112 -0
  215. package/docs/specs/028-compact-debugger-responses/spec.md +108 -0
  216. package/docs/specs/029-kotlin-locals-validation/report.md +119 -0
  217. package/docs/specs/030-android-coroutine-validation/evidence.json +475 -0
  218. package/docs/specs/030-android-coroutine-validation/intent.md +47 -0
  219. package/docs/specs/030-android-coroutine-validation/plan.md +147 -0
  220. package/docs/specs/030-android-coroutine-validation/report.md +240 -0
  221. package/docs/specs/030-android-coroutine-validation/spec.md +107 -0
  222. package/docs/tools/TOOLS.md +31 -18
  223. package/docs/tools/{evidence.md → correlated-evidence.md} +9 -1
  224. package/docs/tools/debugger.md +76 -0
  225. package/docs/tools/interact.md +42 -20
  226. package/docs/tools/manage.md +25 -44
  227. package/docs/tools/observe.md +55 -23
  228. package/docs/tools/system-traces.md +9 -1
  229. package/docs/tools/system.md +12 -5
  230. package/package.json +11 -8
  231. package/scripts/architecture-graph.mjs +69 -0
  232. package/scripts/check-architecture.mjs +47 -0
  233. package/scripts/code-quality-baseline.json +1 -0
  234. package/scripts/code-quality.mjs +161 -0
  235. package/src/contracts/execution-controls.ts +26 -0
  236. package/src/contracts/selector.ts +17 -0
  237. package/src/contracts/target.ts +19 -0
  238. package/src/contracts/ui.ts +94 -0
  239. package/src/debugger/android.ts +2 -1
  240. package/src/debugger/diagnostics.ts +43 -0
  241. package/src/debugger/guard.ts +6 -1
  242. package/{worker → src/debugger/java}/DebuggerWorker.java +9 -3
  243. package/src/debugger/protocol.ts +37 -0
  244. package/src/debugger/sessions.ts +314 -155
  245. package/src/debugger/worker.ts +51 -38
  246. package/src/interact/adjustment/adjustment-context.ts +83 -0
  247. package/src/interact/adjustment/adjustment-gestures.ts +48 -0
  248. package/src/interact/adjustment/adjustment-plan.ts +23 -0
  249. package/src/interact/adjustment/adjustment-resolution.ts +104 -0
  250. package/src/interact/adjustment/adjustment-result.ts +34 -0
  251. package/src/interact/adjustment/adjustment-semantic.ts +53 -0
  252. package/src/interact/adjustment/adjustment-verification.ts +60 -0
  253. package/src/interact/adjustment/adjustment.ts +49 -0
  254. package/src/interact/adjustment/control-geometry.ts +120 -0
  255. package/src/interact/adjustment/control-values.ts +141 -0
  256. package/src/interact/adjustment/slider-labels.ts +84 -0
  257. package/src/interact/assertions/screen-assertion.ts +39 -0
  258. package/src/interact/assertions/state-assertion-context.ts +48 -0
  259. package/src/interact/assertions/state-assertion.ts +64 -0
  260. package/src/interact/assertions/state-comparison.ts +168 -0
  261. package/src/interact/assertions/visibility-assertion.ts +41 -0
  262. package/src/interact/conditional-action.ts +18 -12
  263. package/src/interact/index.ts +76 -3492
  264. package/src/interact/input-service.ts +11 -0
  265. package/src/interact/interaction-trace.ts +36 -0
  266. package/src/interact/model.ts +109 -0
  267. package/src/interact/observation.ts +7 -0
  268. package/src/interact/targeting/candidate-ancestor.ts +49 -0
  269. package/src/interact/targeting/candidate-result.ts +24 -0
  270. package/src/interact/targeting/candidate-scoring.ts +42 -0
  271. package/src/interact/targeting/element-helpers.ts +243 -0
  272. package/src/interact/targeting/find-element.ts +47 -0
  273. package/src/interact/targeting/nearby-control.ts +46 -0
  274. package/src/interact/targeting/resolved-elements.ts +20 -0
  275. package/src/interact/targeting/tap-target.ts +22 -0
  276. package/src/interact/targeting/target-scope.ts +121 -0
  277. package/src/interact/waits/legacy-log-wait.ts +30 -0
  278. package/src/interact/waits/legacy-wait-observations.ts +55 -0
  279. package/src/interact/waits/legacy-wait-state.ts +48 -0
  280. package/src/interact/waits/legacy-wait.ts +34 -0
  281. package/src/interact/waits/screen-wait.ts +37 -0
  282. package/src/interact/waits/ui-change-helpers.ts +184 -0
  283. package/src/interact/waits/ui-change-state.ts +26 -0
  284. package/src/interact/waits/ui-change-wait.ts +59 -0
  285. package/src/interact/waits/ui-wait-condition.ts +52 -0
  286. package/src/interact/waits/ui-wait-state.ts +55 -0
  287. package/src/interact/waits/ui-wait.ts +84 -0
  288. package/src/manage/android.ts +56 -50
  289. package/src/manage/index.ts +63 -93
  290. package/src/manage/ios/build-types.ts +14 -0
  291. package/src/manage/ios/build.ts +230 -0
  292. package/src/manage/ios/project-discovery.ts +26 -0
  293. package/src/manage/ios/scheme.ts +16 -0
  294. package/src/manage/ios.ts +65 -298
  295. package/src/observe/android/context.ts +1 -0
  296. package/src/observe/android/current-screen.ts +63 -0
  297. package/src/observe/android/fingerprint.ts +13 -0
  298. package/src/observe/android/log-stream.ts +127 -0
  299. package/src/observe/android/logs.ts +110 -0
  300. package/src/observe/android/screenshot.ts +79 -0
  301. package/src/observe/android/ui-tree.ts +113 -0
  302. package/src/observe/android.ts +17 -531
  303. package/src/observe/evidence.ts +122 -70
  304. package/src/observe/index.ts +24 -286
  305. package/src/observe/ios/context.ts +22 -0
  306. package/src/observe/ios/fingerprint.ts +12 -0
  307. package/src/observe/ios/log-stream.ts +103 -0
  308. package/src/observe/ios/logs.ts +179 -0
  309. package/src/observe/ios/screenshot.ts +26 -0
  310. package/src/observe/ios/ui-elements.ts +266 -0
  311. package/src/observe/ios/ui-tree.ts +143 -0
  312. package/src/observe/ios.ts +18 -749
  313. package/src/observe/logs/model.ts +11 -0
  314. package/src/{network → observe/network}/index.ts +2 -2
  315. package/src/observe/readiness-service.ts +5 -3
  316. package/src/observe/readiness.ts +39 -18
  317. package/src/observe/screenshot-encoding.ts +32 -0
  318. package/src/observe/snapshot-collection.ts +69 -0
  319. package/src/observe/snapshot-logs.ts +26 -0
  320. package/src/observe/snapshot-metadata.ts +51 -31
  321. package/src/observe/snapshot-semantic.ts +153 -0
  322. package/src/observe/system-trace.ts +24 -15
  323. package/src/runtime/action-results.ts +376 -0
  324. package/src/runtime/clock.ts +9 -0
  325. package/src/server/common.ts +9 -359
  326. package/src/server/definitions/assert.ts +164 -0
  327. package/src/server/definitions/diagnostic.ts +120 -0
  328. package/src/server/definitions/input.ts +276 -0
  329. package/src/server/definitions/manage.ts +196 -0
  330. package/src/server/definitions/observe.ts +151 -0
  331. package/src/server/definitions/target.ts +140 -0
  332. package/src/server/definitions/wait.ts +107 -0
  333. package/src/server/handlers/action-execution.ts +164 -0
  334. package/src/server/handlers/correlation.ts +20 -0
  335. package/src/server/handlers/debugger-handlers.ts +39 -0
  336. package/src/server/handlers/debugger-response.ts +7 -0
  337. package/src/server/handlers/diagnostic.ts +79 -0
  338. package/src/server/handlers/handler-types.ts +7 -0
  339. package/src/server/handlers/input.ts +173 -0
  340. package/src/server/handlers/interact.ts +135 -0
  341. package/src/server/handlers/journey-assertions.ts +39 -0
  342. package/src/server/handlers/journey.ts +132 -0
  343. package/src/server/handlers/manage.ts +141 -0
  344. package/src/server/handlers/observe.ts +116 -0
  345. package/src/server/handlers/payload.ts +36 -0
  346. package/src/server/handlers/tool-handlers.ts +159 -0
  347. package/src/server/schemas/condition-schema.ts +2 -0
  348. package/src/server/{debugger-schema.ts → schemas/debugger-schema.ts} +13 -7
  349. package/src/server/{journey-schema.ts → schemas/journey-schema.ts} +7 -22
  350. package/src/server/{system-trace-schema.ts → schemas/system-trace-schema.ts} +3 -3
  351. package/src/server/tool-definitions.ts +67 -1143
  352. package/src/server-core.ts +2 -2
  353. package/src/server.ts +1 -1
  354. package/src/system/android-status.ts +124 -0
  355. package/src/system/android.ts +33 -21
  356. package/src/system/index.ts +21 -525
  357. package/src/system/ios-status.ts +147 -0
  358. package/src/system/ios.ts +14 -10
  359. package/src/system/model.ts +41 -0
  360. package/src/system/probes.ts +114 -0
  361. package/src/system/status-summary.ts +47 -0
  362. package/src/system/unsupported-status.ts +55 -0
  363. package/src/types.ts +16 -106
  364. package/src/utils/android/commands.ts +81 -0
  365. package/src/utils/android/gradle.ts +132 -0
  366. package/src/utils/android/logs.ts +103 -0
  367. package/src/utils/android/ui-tree.ts +239 -0
  368. package/src/utils/android/utils.ts +16 -556
  369. package/src/utils/cli/idb/check-idb.ts +4 -4
  370. package/src/utils/cli/idb/idb-helper.ts +6 -8
  371. package/src/utils/cli/idb/install-idb.ts +15 -9
  372. package/src/utils/cli/ios/preflight-ios.ts +39 -31
  373. package/src/utils/cli/ios/run-ios-ui-tree-tap.ts +4 -4
  374. package/src/utils/ios/utils.ts +57 -61
  375. package/src/utils/java.ts +62 -43
  376. package/src/utils/resolve-device.ts +9 -6
  377. package/src/utils/ui/index.ts +28 -28
  378. package/test/device/automated/debugger/coroutine-lifecycle.ts +27 -0
  379. package/test/device/automated/debugger/coroutine-support.ts +140 -0
  380. package/test/device/automated/debugger/coroutine.android.test.ts +169 -0
  381. package/test/device/automated/debugger/kotlin.android.test.ts +127 -0
  382. package/test/device/automated/debugger/runtime.android.test.ts +19 -3
  383. package/test/device/automated/interact/interaction.android.test.ts +56 -0
  384. package/test/device/automated/observe/system-trace.smoke.ts +1 -1
  385. package/test/device/manual/interact/modul8_selector_tap.manual.ts +1 -1
  386. package/test/fixtures/contracts/tool-definitions.json +3536 -0
  387. package/test/fixtures/coroutine-app/MainActivity.kt +100 -0
  388. package/test/fixtures/coroutine-app/README.md +48 -0
  389. package/test/fixtures/coroutine-app/build.ts +35 -0
  390. package/test/fixtures/debugger-app/MainActivity.java +21 -0
  391. package/test/fixtures/debugger-app/MainActivity.kt +32 -0
  392. package/test/fixtures/debugger-app/README.md +52 -0
  393. package/test/fixtures/debugger-app/build.ts +25 -15
  394. package/test/fixtures/latency-journey-app/README.md +2 -0
  395. package/test/fixtures/readiness-app/README.md +2 -0
  396. package/test/unit/debugger/coroutine-lifecycle.test.ts +43 -0
  397. package/test/unit/debugger/diagnostic-sessions.test.ts +67 -0
  398. package/test/unit/debugger/diagnostics.test.ts +80 -0
  399. package/test/unit/debugger/guards.test.ts +4 -0
  400. package/test/unit/debugger/preparation.test.ts +32 -0
  401. package/test/unit/debugger/protocol.test.ts +15 -0
  402. package/test/unit/debugger/sessions.test.ts +1 -1
  403. package/test/unit/interact/adjustment_service.test.ts +42 -0
  404. package/test/unit/interact/adjustment_verification.test.ts +35 -0
  405. package/test/unit/interact/clock_dependencies.test.ts +63 -0
  406. package/test/unit/interact/element_helpers.test.ts +19 -0
  407. package/test/unit/interact/legacy_wait_service.test.ts +17 -0
  408. package/test/unit/interact/state_comparison.test.ts +20 -0
  409. package/test/unit/interact/target_scope.test.ts +35 -0
  410. package/test/unit/network/get_network_activity.test.ts +1 -1
  411. package/test/unit/observe/screenshot-encoding.test.ts +30 -0
  412. package/test/unit/observe/snapshot-logs.test.ts +14 -0
  413. package/test/unit/quality/architecture.test.ts +60 -0
  414. package/test/unit/quality/code-quality.test.ts +58 -0
  415. package/test/unit/quality/interaction_boundaries.test.ts +24 -0
  416. package/test/unit/server/conditional_actions.test.ts +1 -1
  417. package/test/unit/server/conditional_schema.test.ts +2 -2
  418. package/test/unit/server/debugger-response.test.ts +63 -0
  419. package/test/unit/server/tool_definitions_parity.test.ts +8 -0
  420. package/dist/server/tool-handlers.js +0 -1000
  421. package/docs/ROADMAP.md +0 -646
  422. package/docs/benchmarks/ui-tree-performance/bridge-probe.json +0 -29
  423. package/docs/benchmarks/ui-tree-performance/initial-baseline.json +0 -59560
  424. package/docs/specs/baseline-spec-v0.md +0 -312
  425. package/docs/specs/mcp-tooling-spec-v1.md +0 -446
  426. package/src/server/debugger-handlers.ts +0 -29
  427. package/src/server/tool-handlers.ts +0 -1008
  428. /package/dist/{server/condition-schema.js → contracts/condition.js} +0 -0
  429. /package/dist/server/{readiness-schema.js → schemas/readiness-schema.js} +0 -0
  430. /package/dist/server/{system-trace-schema.js → schemas/system-trace-schema.js} +0 -0
  431. /package/src/{server/condition-schema.ts → contracts/condition.ts} +0 -0
  432. /package/src/server/{readiness-schema.ts → schemas/readiness-schema.ts} +0 -0
@@ -0,0 +1,147 @@
1
+ import { checkIOS } from './ios.js'
2
+ import { getIdbCmd, getXcrunCmd } from '../utils/ios/utils.js'
3
+ import { probeIdb } from '../utils/cli/idb/idb-helper.js'
4
+ import type { HostOs, PlatformStatus, DiagnosticFailure, PlatformEntry } from './model.js'
5
+ import { probeCommand, makeFailure, makeToolEntry, describeXcrunDiscovery, describeIdbDiscovery } from './probes.js'
6
+
7
+ export function buildIOSPlatform(ios: Awaited<ReturnType<typeof checkIOS>>, hostSupported: boolean, hostOs: HostOs): PlatformEntry {
8
+ const platformUnsupported = !hostSupported || hostOs === 'linux' || hostOs === 'windows'
9
+ if (platformUnsupported) {
10
+ return {
11
+ status: 'unsupported',
12
+ tools: {},
13
+ providers: {},
14
+ capabilities: {},
15
+ devices: [],
16
+ failures: [
17
+ makeFailure('PLATFORM_UNAVAILABLE', 'ios', 'iOS tooling is only supported on macOS.', {
18
+ tool: null,
19
+ searchedLocations: [],
20
+ selectedProvider: null,
21
+ rawVersion: null,
22
+ remediation: ['Run Mobile Debug MCP on macOS for iOS toolchain discovery.']
23
+ })
24
+ ]
25
+ }
26
+ }
27
+
28
+ const { xcrunCmd, xcrunProbe, idbProbe, xcrunTool, idbTool, idbCompanionTool, lldbTool } = iosTools(ios, hostSupported, hostOs)
29
+ const simctlAvailable = !!ios.iosAvailable
30
+ const idbAvailable = !!idbProbe.ok
31
+ const bootedDevices = ios.iosDevices > 0
32
+ ? Array.from({ length: ios.iosDevices }, (_, index) => ({
33
+ id: `ios-simulator-${index + 1}`,
34
+ state: 'booted'
35
+ }))
36
+ : []
37
+
38
+ const { platformUnavailableFailure, deviceFailure } = iosFailures(platformUnsupported, simctlAvailable, bootedDevices.length, xcrunCmd, xcrunProbe.raw)
39
+ const selectedInstallProvider = idbAvailable ? 'idb' : simctlAvailable ? 'simctl' : null
40
+ const selectedDebugProvider = simctlAvailable ? 'LLDB' : null
41
+ const selectedDiscoveryProvider = idbAvailable ? 'idb' : simctlAvailable ? 'simctl' : null
42
+
43
+ const status: PlatformStatus = platformUnsupported
44
+ ? 'unsupported'
45
+ : !simctlAvailable
46
+ ? 'unavailable'
47
+ : !bootedDevices.length
48
+ ? 'partially_ready'
49
+ : 'ready'
50
+
51
+ const iosFailure = platformUnsupported
52
+ ? makeFailure('PLATFORM_UNAVAILABLE', 'ios', 'iOS tooling is only supported on macOS.', {
53
+ tool: null,
54
+ searchedLocations: [],
55
+ selectedProvider: null,
56
+ rawVersion: null,
57
+ remediation: ['Run Mobile Debug MCP on macOS for iOS toolchain discovery.']
58
+ })
59
+ : platformUnavailableFailure ?? deviceFailure ?? null
60
+
61
+ const failureList = [iosFailure].filter((value): value is DiagnosticFailure => value !== null)
62
+
63
+ return {
64
+ status,
65
+ tools: {
66
+ xcrun: xcrunTool,
67
+ idb: idbTool,
68
+ idb_companion: idbCompanionTool,
69
+ lldb: lldbTool
70
+ },
71
+ providers: {
72
+ idb: { available: idbAvailable, selected: selectedInstallProvider === 'idb', tool: 'idb' },
73
+ simctl: { available: simctlAvailable, selected: selectedInstallProvider === 'simctl', tool: 'xcrun' },
74
+ lldb: { available: simctlAvailable, selected: selectedDebugProvider === 'LLDB', tool: 'xcrun' }
75
+ },
76
+ capabilities: iosCapabilities(selectedDiscoveryProvider, selectedInstallProvider, selectedDebugProvider, simctlAvailable, bootedDevices.length, deviceFailure, iosFailure),
77
+ devices: bootedDevices,
78
+ failures: failureList
79
+ }
80
+ }
81
+
82
+ function iosTools(ios: Awaited<ReturnType<typeof checkIOS>>, hostSupported: boolean, hostOs: HostOs) {
83
+ const xcrunCmd = getXcrunCmd()
84
+ const xcrunProbe = ios.iosAvailable ? probeCommand(xcrunCmd, ['--version']) : { ok: false, raw: null, parsedVersion: null }
85
+ const idbCmd = getIdbCmd()
86
+ const idbProbe = hostSupported && hostOs === 'macos' ? probeIdb(idbCmd) : { ok: false, raw: null, parsedVersion: null }
87
+ const idbCompanionProbe = hostSupported && hostOs === 'macos' ? probeCommand('idb_companion', ['--version']) : { ok: false, raw: null, parsedVersion: null }
88
+ const xcrunTool = makeToolEntry(xcrunCmd, describeXcrunDiscovery(xcrunCmd).discoverySource, xcrunProbe.raw, xcrunProbe.ok ? 'valid' : 'invalid')
89
+ const idbTool = makeToolEntry(idbCmd, describeIdbDiscovery(idbCmd).discoverySource, idbProbe.raw, idbProbe.ok ? 'valid' : 'invalid')
90
+ const idbCompanionTool = makeToolEntry('idb_companion', 'PATH', idbCompanionProbe.raw, idbCompanionProbe.ok ? 'valid' : 'invalid')
91
+ const lldbTool = makeToolEntry('xcrun lldb', 'xcrun', xcrunProbe.raw, xcrunProbe.ok ? 'valid' : 'invalid')
92
+
93
+ return { xcrunCmd, xcrunProbe, idbProbe, xcrunTool, idbTool, idbCompanionTool, lldbTool }
94
+ }
95
+
96
+ function iosFailures(platformUnsupported: boolean, simctlAvailable: boolean, deviceCount: number, xcrunCmd: string, rawVersion: string | null) {
97
+ const platformUnavailableFailure = !platformUnsupported && !simctlAvailable
98
+ ? makeFailure('PLATFORM_UNAVAILABLE', 'ios', 'iOS tooling is unavailable on this host.', {
99
+ tool: 'xcrun',
100
+ searchedLocations: describeXcrunDiscovery(xcrunCmd).searchedLocations,
101
+ selectedProvider: null,
102
+ rawVersion: rawVersion,
103
+ remediation: ['Install Xcode Command Line Tools and ensure xcrun is on PATH.']
104
+ })
105
+ : null
106
+
107
+ const deviceFailure = simctlAvailable && !deviceCount
108
+ ? makeFailure('DEVICE_NOT_FOUND', 'ios', 'No iOS simulators are booted.', {
109
+ tool: 'simctl',
110
+ searchedLocations: ['xcrun simctl list devices booted --json'],
111
+ selectedProvider: 'simctl',
112
+ rawVersion: rawVersion,
113
+ remediation: ['Boot a simulator in Xcode or via xcrun simctl boot.']
114
+ })
115
+ : null
116
+
117
+ return { platformUnavailableFailure, deviceFailure }
118
+ }
119
+
120
+ function iosCapabilities(selectedDiscoveryProvider: string | null, selectedInstallProvider: string | null, selectedDebugProvider: string | null, simctlAvailable: boolean, deviceCount: number, deviceFailure: DiagnosticFailure | null, iosFailure: DiagnosticFailure | null): PlatformEntry['capabilities'] {
121
+ const applicationCapability = {
122
+ availability: !!selectedInstallProvider && deviceCount > 0,
123
+ selectedProvider: selectedInstallProvider,
124
+ blockingFailure: selectedInstallProvider && deviceCount > 0 ? null : deviceFailure ?? iosFailure
125
+ }
126
+ return {
127
+ device_discovery: {
128
+ availability: !!selectedDiscoveryProvider,
129
+ selectedProvider: selectedDiscoveryProvider,
130
+ blockingFailure: selectedDiscoveryProvider ? null : iosFailure
131
+ },
132
+ install_app: { ...applicationCapability },
133
+ launch_app: { ...applicationCapability },
134
+ ui_interaction: { ...applicationCapability },
135
+ screenshot: { ...applicationCapability },
136
+ log_capture: {
137
+ availability: simctlAvailable && deviceCount > 0,
138
+ selectedProvider: simctlAvailable ? 'simctl' : null,
139
+ blockingFailure: simctlAvailable && deviceCount > 0 ? null : deviceFailure ?? iosFailure
140
+ },
141
+ debug: {
142
+ availability: !!selectedDebugProvider,
143
+ selectedProvider: selectedDebugProvider,
144
+ blockingFailure: selectedDebugProvider ? null : iosFailure
145
+ }
146
+ }
147
+ }
package/src/system/ios.ts CHANGED
@@ -8,19 +8,12 @@ export async function checkIOS() {
8
8
  try {
9
9
  const xcrun = getXcrunCmd()
10
10
  try {
11
- execSync(`${xcrun} --version`, { stdio: ['ignore','pipe','ignore'], timeout: 1500 })
11
+ execSync(`${xcrun} --version`, { stdio: ['ignore', 'pipe', 'ignore'], timeout: 1500 })
12
12
  iosAvailable = true
13
13
  try {
14
- const simOut = execSync(`${xcrun} simctl list devices booted --json`, { encoding: 'utf8', timeout: 1500, stdio: ['ignore','pipe','ignore'] })
14
+ const simOut = execSync(`${xcrun} simctl list devices booted --json`, { encoding: 'utf8', timeout: 1500, stdio: ['ignore', 'pipe', 'ignore'] })
15
15
  try {
16
- const data = JSON.parse(simOut)
17
- type SimDevice = { state?: string }
18
- let count = 0
19
- for (const k in data.devices) {
20
- const arr = data.devices[k]
21
- if (Array.isArray(arr)) count += arr.filter((d: SimDevice) => (d.state || '').toLowerCase() === 'booted').length
22
- }
23
- iosDevices = count
16
+ iosDevices = countBooted(simOut)
24
17
  } catch {
25
18
  // Some xcrun builds include extra text around the JSON response.
26
19
  // Fall back to counting explicit booted state markers so readiness remains deterministic.
@@ -33,3 +26,14 @@ export async function checkIOS() {
33
26
  } catch (e: unknown) { console.debug('[get_system_status] xcrun check failed: ' + String(e)) }
34
27
  return { iosAvailable, iosDevices, issues }
35
28
  }
29
+
30
+ function countBooted(simOut: string) {
31
+ const data = JSON.parse(simOut)
32
+ type SimDevice = { state?: string }
33
+ let count = 0
34
+ for (const k in data.devices) {
35
+ const arr = data.devices[k]
36
+ if (Array.isArray(arr)) count += arr.filter((d: SimDevice) => (d.state || '').toLowerCase() === 'booted').length
37
+ }
38
+ return count
39
+ }
@@ -0,0 +1,41 @@
1
+
2
+ export type HostOs = 'macos' | 'linux' | 'windows' | 'freebsd' | 'openbsd' | 'netbsd' | 'sunos' | 'unknown'
3
+
4
+ export type PlatformStatus = 'ready' | 'partially_ready' | 'unavailable' | 'unsupported'
5
+
6
+ export type ValidationStatus = 'valid' | 'invalid' | 'missing' | 'unsupported' | 'unknown'
7
+
8
+ export interface DiagnosticFailure {
9
+ code: string
10
+ platform: 'android' | 'ios'
11
+ tool: string | null
12
+ message: string
13
+ searchedLocations: string[]
14
+ selectedProvider: string | null
15
+ rawVersion: string | null
16
+ remediation: string[]
17
+ }
18
+
19
+ export interface ToolEntry {
20
+ resolvedPath: string | null
21
+ discoverySource: string | null
22
+ parsedVersion: string | null
23
+ rawVersionOutput: string | null
24
+ validationStatus: ValidationStatus
25
+ }
26
+
27
+ export interface CapabilityEntry {
28
+ probeRequired?: string
29
+ availability: boolean
30
+ selectedProvider: string | null
31
+ blockingFailure: DiagnosticFailure | null
32
+ }
33
+
34
+ export interface PlatformEntry {
35
+ status: PlatformStatus
36
+ tools: Record<string, ToolEntry>
37
+ providers: Record<string, { available: boolean; selected: boolean; tool: string | null; probeRequired?: string }>
38
+ capabilities: Record<string, CapabilityEntry>
39
+ devices: Array<Record<string, unknown>>
40
+ failures: DiagnosticFailure[]
41
+ }
@@ -0,0 +1,114 @@
1
+ import { spawnSync } from 'child_process'
2
+ import path from 'path'
3
+ import type { HostOs, ValidationStatus, DiagnosticFailure, ToolEntry } from './model.js'
4
+
5
+ export function normalizeHostOs(platform: NodeJS.Platform): HostOs {
6
+ switch (platform) {
7
+ case 'darwin':
8
+ return 'macos'
9
+ case 'linux':
10
+ return 'linux'
11
+ case 'win32':
12
+ return 'windows'
13
+ case 'freebsd':
14
+ case 'openbsd':
15
+ case 'netbsd':
16
+ case 'sunos':
17
+ return platform
18
+ default:
19
+ return 'unknown'
20
+ }
21
+ }
22
+
23
+ export function isSupportedHost(hostOs: HostOs): boolean {
24
+ return hostOs === 'macos' || hostOs === 'linux' || hostOs === 'windows'
25
+ }
26
+
27
+ export function firstVersionToken(raw: string | null | undefined): string | null {
28
+ if (!raw) return null
29
+ const match = String(raw).match(/(\d+(?:\.\d+)+|\d+)/)
30
+ return match?.[1] ?? null
31
+ }
32
+
33
+ export function probeCommand(command: string, args: string[], timeoutMs = 2000): { ok: boolean, raw: string | null, parsedVersion: string | null } {
34
+ try {
35
+ const result = spawnSync(command, args, { encoding: 'utf8', timeout: timeoutMs, stdio: ['ignore', 'pipe', 'pipe'] })
36
+ const raw = `${result.stdout || ''}${result.stderr || ''}`.trim() || null
37
+ return {
38
+ ok: result.status === 0,
39
+ raw,
40
+ parsedVersion: firstVersionToken(raw)
41
+ }
42
+ } catch {
43
+ return { ok: false, raw: null, parsedVersion: null }
44
+ }
45
+ }
46
+
47
+ export function makeFailure(
48
+ code: string,
49
+ platform: 'android' | 'ios',
50
+ message: string,
51
+ opts: Partial<DiagnosticFailure> = {}
52
+ ): DiagnosticFailure {
53
+ return {
54
+ code,
55
+ platform,
56
+ tool: opts.tool ?? null,
57
+ message,
58
+ searchedLocations: opts.searchedLocations ?? [],
59
+ selectedProvider: opts.selectedProvider ?? null,
60
+ rawVersion: opts.rawVersion ?? null,
61
+ remediation: opts.remediation ?? []
62
+ }
63
+ }
64
+
65
+ export function makeToolEntry(
66
+ resolvedPath: string | null,
67
+ discoverySource: string | null,
68
+ rawVersionOutput: string | null,
69
+ validationStatus: ValidationStatus
70
+ ): ToolEntry {
71
+ return {
72
+ resolvedPath,
73
+ discoverySource,
74
+ parsedVersion: firstVersionToken(rawVersionOutput),
75
+ rawVersionOutput,
76
+ validationStatus
77
+ }
78
+ }
79
+
80
+ export function describeAdbDiscovery(adbCmd: string): { discoverySource: string | null, searchedLocations: string[] } {
81
+ const searchedLocations: string[] = ['ADB_PATH', 'ANDROID_SDK_ROOT/platform-tools/adb', 'ANDROID_HOME/platform-tools/adb', '~/Library/Android/sdk/platform-tools/adb', 'PATH']
82
+ if (process.env.ADB_PATH && process.env.ADB_PATH.trim()) return { discoverySource: 'ADB_PATH', searchedLocations }
83
+ if (process.env.ANDROID_SDK_ROOT) return { discoverySource: 'ANDROID_SDK_ROOT', searchedLocations }
84
+ if (process.env.ANDROID_HOME) return { discoverySource: 'ANDROID_HOME', searchedLocations }
85
+ if (adbCmd.includes('Library/Android/sdk')) return { discoverySource: 'HOME_SDK', searchedLocations }
86
+ if (adbCmd === 'adb') return { discoverySource: 'PATH_OR_FALLBACK', searchedLocations }
87
+ return { discoverySource: 'PATH', searchedLocations }
88
+ }
89
+
90
+ export function describeXcrunDiscovery(xcrunCmd: string): { discoverySource: string | null, searchedLocations: string[] } {
91
+ const searchedLocations: string[] = ['XCRUN_PATH', 'PATH']
92
+ if (process.env.XCRUN_PATH && process.env.XCRUN_PATH.trim()) return { discoverySource: 'XCRUN_PATH', searchedLocations }
93
+ return { discoverySource: xcrunCmd === 'xcrun' ? 'PATH' : 'PATH', searchedLocations }
94
+ }
95
+
96
+ export function describeIdbDiscovery(idbCmd: string): { discoverySource: string | null, searchedLocations: string[] } {
97
+ const searchedLocations: string[] = ['MCP_IDB_PATH', 'IDB_PATH', 'mcp.config.json', '~/.mcp/config.json', 'PATH', '/opt/homebrew/bin/idb', '/usr/local/bin/idb']
98
+ if (process.env.MCP_IDB_PATH && process.env.MCP_IDB_PATH.trim()) return { discoverySource: 'MCP_IDB_PATH', searchedLocations }
99
+ if (process.env.IDB_PATH && process.env.IDB_PATH.trim()) return { discoverySource: 'IDB_PATH', searchedLocations }
100
+ return { discoverySource: idbCmd === 'idb' ? 'PATH_OR_FALLBACK' : 'PATH', searchedLocations }
101
+ }
102
+
103
+ export function describeJavaDiscovery(javaHome: string | null): { discoverySource: string | null, searchedLocations: string[] } {
104
+ const searchedLocations: string[] = ['GRADLE_JAVA_HOME', 'JAVA_HOME', 'GRADLE_HOME', 'detectJavaHome']
105
+ if (process.env.GRADLE_JAVA_HOME && process.env.GRADLE_JAVA_HOME.trim()) return { discoverySource: 'GRADLE_JAVA_HOME', searchedLocations }
106
+ if (process.env.JAVA_HOME && process.env.JAVA_HOME.trim()) return { discoverySource: 'JAVA_HOME', searchedLocations }
107
+ if (process.env.GRADLE_HOME && process.env.GRADLE_HOME.trim()) return { discoverySource: 'GRADLE_HOME', searchedLocations }
108
+ return { discoverySource: javaHome ? 'detected' : null, searchedLocations }
109
+ }
110
+
111
+ export function resolveJavaBinaryPath(javaHome: string, hostOs: HostOs): string {
112
+ const javaBinary = hostOs === 'windows' ? 'java.exe' : 'java'
113
+ return path.join(javaHome, 'bin', javaBinary)
114
+ }
@@ -0,0 +1,47 @@
1
+ import { checkGradle } from './gradle.js'
2
+ import type { PlatformEntry } from './model.js'
3
+
4
+ export function buildLegacySummary(androidStatus: PlatformEntry, iosStatus: PlatformEntry, gradle: Awaited<ReturnType<typeof checkGradle>>) {
5
+ const androidReady = androidStatus.status === 'ready'
6
+ const iosReady = iosStatus.status === 'ready'
7
+ const gradleReady = (gradle.issues || []).length === 0
8
+ const overallStatus = (androidReady || iosReady || gradleReady)
9
+ ? ((androidReady && iosReady && gradleReady) ? 'ready' : 'degraded')
10
+ : 'blocked'
11
+
12
+ return {
13
+ overall: overallStatus,
14
+ android: {
15
+ ready: androidReady,
16
+ summary: androidStatus.status === 'ready'
17
+ ? `${androidStatus.devices.length} Android device(s) connected; log access available`
18
+ : androidStatus.status === 'partially_ready'
19
+ ? 'Android toolchain available but device-dependent capabilities are limited'
20
+ : androidStatus.status === 'unsupported'
21
+ ? 'Android unsupported on this host'
22
+ : 'ADB unavailable',
23
+ blockers: androidStatus.failures.map((failure) => failure.message)
24
+ },
25
+ ios: {
26
+ ready: iosReady,
27
+ summary: iosStatus.status === 'ready'
28
+ ? `${iosStatus.devices.length} iOS simulator(s) booted`
29
+ : iosStatus.status === 'partially_ready'
30
+ ? 'iOS toolchain available but device-dependent capabilities are limited'
31
+ : iosStatus.status === 'unsupported'
32
+ ? 'iOS unsupported on this host'
33
+ : 'xcrun unavailable',
34
+ blockers: iosStatus.failures.map((failure) => failure.message)
35
+ },
36
+ gradle: {
37
+ ready: gradleReady,
38
+ summary: !gradle.gradleJavaHome
39
+ ? 'No explicit Gradle JDK override detected'
40
+ : gradleReady
41
+ ? `Gradle JDK configured at ${gradle.gradleJavaHome}`
42
+ : `Gradle JDK override invalid: ${gradle.gradleJavaHome}`,
43
+ blockers: gradle.issues || [],
44
+ suggestedFixes: gradle.suggestedFixes || []
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,55 @@
1
+ import type { HostOs } from './model.js'
2
+ import { makeFailure } from './probes.js'
3
+
4
+ export function buildUnsupportedHostStatus(hostOs: HostOs) {
5
+ const failureMessage = `Host operating system '${hostOs}' is not supported.`
6
+ const remediation = ['Run Mobile Debug MCP on macOS, Linux, or Windows.']
7
+ const failureAndroid = makeFailure('HOST_OS_UNSUPPORTED', 'android', failureMessage, {
8
+ remediation
9
+ })
10
+ const failureIos = makeFailure('HOST_OS_UNSUPPORTED', 'ios', failureMessage, {
11
+ remediation
12
+ })
13
+
14
+ return {
15
+ success: false,
16
+ status: 'blocked',
17
+ adbAvailable: false,
18
+ adbVersion: '',
19
+ devices: 0,
20
+ deviceStates: '',
21
+ logsAvailable: false,
22
+ envValid: false,
23
+ issues: [failureMessage],
24
+ appInstalled: undefined,
25
+ iosAvailable: false,
26
+ iosDevices: 0,
27
+ gradleJavaHome: undefined,
28
+ gradleValid: false,
29
+ gradleFilesChecked: [],
30
+ gradleSuggestedFixes: [],
31
+ host: { os: hostOs, supported: false },
32
+ android: {
33
+ status: 'unsupported',
34
+ tools: {},
35
+ providers: {},
36
+ capabilities: {},
37
+ devices: [],
38
+ failures: [failureAndroid]
39
+ },
40
+ ios: {
41
+ status: 'unsupported',
42
+ tools: {},
43
+ providers: {},
44
+ capabilities: {},
45
+ devices: [],
46
+ failures: [failureIos]
47
+ },
48
+ summary: {
49
+ overall: 'blocked',
50
+ android: { ready: false, summary: `Host operating system '${hostOs}' is not supported.`, blockers: [failureMessage] },
51
+ ios: { ready: false, summary: `Host operating system '${hostOs}' is not supported.`, blockers: [failureMessage] },
52
+ gradle: { ready: false, summary: 'Gradle status unavailable on unsupported host', blockers: [], suggestedFixes: [] }
53
+ }
54
+ }
55
+ }
package/src/types.ts CHANGED
@@ -1,9 +1,13 @@
1
+ export type { UIElementState, SelectorConfidence, UIResolutionSelector, UIElementSemanticMetadata, LoadingState, SnapshotDelta, StateDelta, UIElement, ReadinessSummary } from './contracts/ui.js'
2
+ import type { UIElementState, UIResolutionSelector, UIElementSemanticMetadata, LoadingState, SnapshotDelta, StateDelta, UIElement, ReadinessSummary } from './contracts/ui.js'
1
3
  export interface DeviceInfo {
2
4
  platform: string;
3
5
  id: string;
4
6
  osVersion: string;
5
7
  model: string;
6
8
  simulator: boolean;
9
+ appInstalled?: boolean;
10
+ booted?: boolean;
7
11
  }
8
12
 
9
13
  export interface StartAppResponse {
@@ -20,14 +24,14 @@ export interface StartAppResponse {
20
24
  matchedTarget?: boolean | null;
21
25
  };
22
26
  error?: string;
23
- diagnostics?: any;
27
+ diagnostics?: unknown;
24
28
  }
25
29
 
26
30
  export interface TerminateAppResponse {
27
31
  device: DeviceInfo;
28
32
  appTerminated: boolean;
29
33
  error?: string;
30
- diagnostics?: any;
34
+ diagnostics?: unknown;
31
35
  }
32
36
 
33
37
  export interface RestartAppResponse {
@@ -46,14 +50,14 @@ export interface RestartAppResponse {
46
50
  terminatedBeforeRestart?: boolean;
47
51
  terminateError?: string;
48
52
  error?: string;
49
- diagnostics?: any;
53
+ diagnostics?: unknown;
50
54
  }
51
55
 
52
56
  export interface ResetAppDataResponse {
53
57
  device: DeviceInfo;
54
58
  dataCleared: boolean;
55
59
  error?: string;
56
- diagnostics?: any;
60
+ diagnostics?: unknown;
57
61
  }
58
62
 
59
63
  export interface StructuredLogEntry {
@@ -71,7 +75,7 @@ export interface GetLogsResponse {
71
75
  // Source indicates the filtering method used: 'pid', 'package'/'process', or 'broad'
72
76
  source?: string;
73
77
  // Meta contains debugging information about how logs were collected and filters applied
74
- meta?: Record<string, any>;
78
+ meta?: Record<string, unknown>;
75
79
  }
76
80
 
77
81
  export interface GetCrashResponse {
@@ -79,43 +83,8 @@ export interface GetCrashResponse {
79
83
  crashes: string[];
80
84
  }
81
85
 
82
- export interface UIElementState {
83
- checked?: boolean | null;
84
- selected?: boolean | string | { id: string; label?: string } | null;
85
- focused?: boolean | null;
86
- expanded?: boolean | null;
87
- enabled?: boolean | null;
88
- text_value?: string | null;
89
- value?: number | string | null;
90
- raw_value?: number | string | null;
91
- value_range?: {
92
- min: number;
93
- max: number;
94
- step?: number | null;
95
- } | null;
96
- step?: number | null;
97
- }
98
-
99
- export interface SelectorConfidence {
100
- score: number;
101
- reason: string;
102
- }
103
-
104
- export interface UIResolutionSelector {
105
- value: string | null;
106
- confidence: SelectorConfidence | null;
107
- }
108
-
109
- export interface UIElementSemanticMetadata {
110
- is_clickable: boolean;
111
- is_container: boolean;
112
- semantic_role?: 'slider' | 'stepper' | 'dropdown' | 'segmented_control' | 'custom_adjustable' | 'composite_control' | null;
113
- supported_actions?: string[] | null;
114
- adjustable?: boolean | null;
115
- state_shape?: 'continuous' | 'discrete' | 'semantic' | null;
116
- }
117
-
118
86
  export type TraceStage = 'resolve' | 'execute' | 'verify' | 'stabilize' | 'recover';
87
+
119
88
  export type TraceResult = 'success' | 'failure' | 'retry';
120
89
 
121
90
  export interface TraceStep {
@@ -148,35 +117,11 @@ export type RecoveryStrategy =
148
117
  | 'retry_adjustment'
149
118
  | 'step_back';
150
119
 
151
- export interface LoadingState {
152
- active: boolean;
153
- signal: string;
154
- source: string;
155
- }
156
-
157
- export interface SnapshotDelta {
158
- previous_snapshot_revision: number | null;
159
- added_elements: number;
160
- removed_elements: number;
161
- mutated_elements: number;
162
- total_elements: number;
163
- }
164
-
165
- export interface StateDelta {
166
- base_snapshot_revision: number | null;
167
- snapshot_revision: number;
168
- added: UIElement[];
169
- removed: Array<{ stable_id?: string; resourceId?: string; contentDescription?: string; text?: string; index: number }>;
170
- changed: UIElement[];
171
- truncated: boolean;
172
- omitted_changes?: number;
173
- }
174
-
175
120
  export interface CaptureAndroidScreenResponse {
176
121
  device: DeviceInfo;
177
122
  screenshot: string; // base64 encoded string
178
123
  screenshot_mime?: string; // e.g. image/webp, image/jpeg, image/png
179
- screenshot_fallback?: string; // optional fallback base64 (e.g., jpeg)
124
+ screenshot_fallback?: string | null; // optional fallback base64 (e.g., jpeg)
180
125
  screenshot_fallback_mime?: string;
181
126
  resolution: {
182
127
  width: number;
@@ -188,7 +133,7 @@ export interface CaptureIOSScreenshotResponse {
188
133
  device: DeviceInfo;
189
134
  screenshot: string; // base64 encoded string
190
135
  screenshot_mime?: string; // e.g. image/webp, image/jpeg, image/png
191
- screenshot_fallback?: string; // optional fallback base64 (e.g., jpeg)
136
+ screenshot_fallback?: string | null; // optional fallback base64 (e.g., jpeg)
192
137
  screenshot_fallback_mime?: string;
193
138
  resolution: {
194
139
  width: number;
@@ -196,27 +141,6 @@ export interface CaptureIOSScreenshotResponse {
196
141
  };
197
142
  }
198
143
 
199
- export interface UIElement {
200
- text: string | null;
201
- contentDescription: string | null;
202
- type: string;
203
- clickable: boolean;
204
- enabled: boolean;
205
- visible: boolean;
206
- bounds: [number, number, number, number];
207
- resourceId: string | null;
208
- parentId?: number;
209
- children?: number[];
210
- center?: [number, number];
211
- depth?: number;
212
- state?: UIElementState | null;
213
- stable_id?: string | null;
214
- role?: string | null;
215
- test_tag?: string | null;
216
- selector?: UIResolutionSelector | null;
217
- semantic?: UIElementSemanticMetadata | null;
218
- }
219
-
220
144
  export interface GetUITreeResponse {
221
145
  readiness?: ReadinessSummary;
222
146
  device: DeviceInfo;
@@ -234,20 +158,6 @@ export interface GetUITreeResponse {
234
158
  error?: string;
235
159
  }
236
160
 
237
- export interface ReadinessSummary {
238
- state: 'loading' | 'transitioning' | 'settled' | 'unknown' | 'unresponsive' | 'debugger_paused';
239
- scope: 'device_ui';
240
- basis: 'observed' | 'heuristic' | 'insufficient';
241
- captured_at_ms: number | null;
242
- sample_count: number;
243
- stable_for_ms: number;
244
- snapshot_session_id: string | null;
245
- snapshot_revision: number | null;
246
- evidence: Array<{ code: string; source: string; captured_at_ms: number | null; snapshot_revision: number | null }>;
247
- limitations: string[];
248
- capabilities: { loading: boolean; transitioning: boolean; settled: boolean; unresponsive: boolean; debugger_paused: boolean };
249
- }
250
-
251
161
  export interface GetCurrentScreenResponse {
252
162
  device: DeviceInfo;
253
163
  package: string;
@@ -274,7 +184,7 @@ export interface CaptureDebugSnapshotRawResponse {
274
184
  fingerprint: string | null;
275
185
  screenshot: string | null;
276
186
  ui_tree: GetUITreeResponse | null;
277
- logs: StructuredLogEntry[];
187
+ logs: import('./observe/snapshot-logs.js').SnapshotLogEntry[];
278
188
  loading_state?: LoadingState | null;
279
189
  device?: DeviceInfo;
280
190
  screenshot_error?: string;
@@ -441,7 +351,7 @@ export interface ActionConditionResult {
441
351
  observed: GetUITreeResponse | null;
442
352
  elapsed_ms: number;
443
353
  reason?: 'BASELINE_UNAVAILABLE' | 'SESSION_MISMATCH' | 'DEVICE_MISMATCH' |
444
- 'OBSERVATION_FAILED' | 'OBSERVATION_INVALID' | 'CONDITION_TIMEOUT' | 'ACTION_NOT_REACHED';
354
+ 'OBSERVATION_FAILED' | 'OBSERVATION_INVALID' | 'CONDITION_TIMEOUT' | 'ACTION_NOT_REACHED';
445
355
  }
446
356
 
447
357
  export interface ActionExecutionResult {
@@ -505,7 +415,7 @@ export interface ExpectElementVisibleResponse {
505
415
  element?: ActionTargetResolved | null;
506
416
  observed?: {
507
417
  status?: string;
508
- matched_count?: number;
418
+ matched_count?: number | null;
509
419
  condition_satisfied?: boolean;
510
420
  selected_index?: number | null;
511
421
  last_matched_element?: ActionTargetResolved | null;
@@ -615,5 +525,5 @@ export interface InstallAppResponse {
615
525
  installed: boolean;
616
526
  output?: string;
617
527
  error?: string;
618
- diagnostics?: any;
528
+ diagnostics?: unknown;
619
529
  }