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
@@ -2,11 +2,11 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequestSchema, ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
3
3
  import { wrapResponse } from './server/common.js';
4
4
  import { toolDefinitions } from './server/tool-definitions.js';
5
- import { handleToolCall } from './server/tool-handlers.js';
5
+ import { handleToolCall } from './server/handlers/tool-handlers.js';
6
6
  export { wrapResponse, toolDefinitions, handleToolCall };
7
7
  export const serverInfo = {
8
8
  name: 'mobile-debug-mcp',
9
- version: '0.34.0'
9
+ version: '0.35.0'
10
10
  };
11
11
  export function createServer() {
12
12
  const server = new Server(serverInfo, {
@@ -0,0 +1,101 @@
1
+ import { resolveAdbCmd } from '../utils/android/utils.js';
2
+ import { makeFailure, makeToolEntry, describeAdbDiscovery } from './probes.js';
3
+ export function buildAndroidPlatform(android, hostSupported) {
4
+ const resolvedAdbCmd = resolveAdbCmd();
5
+ const adbDiscovery = describeAdbDiscovery(resolvedAdbCmd);
6
+ const adbTool = makeToolEntry(resolvedAdbCmd, adbDiscovery.discoverySource, android.adbVersion || null, android.adbAvailable ? 'valid' : 'invalid');
7
+ const adbAvailable = !!android.adbAvailable;
8
+ const deviceIssues = android.issues.filter((issue) => /unauthorized|offline|No Android devices connected/i.test(issue));
9
+ const { envFailure, adbFailure, deviceFailure, diagnosticFailures } = androidFailures(android, adbAvailable, adbDiscovery);
10
+ const status = !hostSupported
11
+ ? 'unsupported'
12
+ : !adbAvailable
13
+ ? 'unavailable'
14
+ : (android.devices === 0 || deviceIssues.length > 0 || !android.logsAvailable || !android.envValid)
15
+ ? 'partially_ready'
16
+ : 'ready';
17
+ const deviceEntries = android.devices > 0
18
+ ? Array.from({ length: android.devices }, (_, index) => ({
19
+ id: `android-device-${index + 1}`,
20
+ state: deviceIssues.length > 0 ? 'degraded' : 'connected'
21
+ }))
22
+ : [];
23
+ const installAvailable = adbAvailable && android.devices > 0 && deviceIssues.length === 0;
24
+ const logAvailable = adbAvailable && android.logsAvailable;
25
+ return {
26
+ status,
27
+ tools: {
28
+ adb: adbTool
29
+ },
30
+ providers: {
31
+ adb: { available: adbAvailable, selected: true, tool: 'adb' },
32
+ jdwp: { available: false, selected: false, tool: 'adb', probeRequired: 'get_debugger_capabilities' }
33
+ },
34
+ capabilities: androidCapabilities(adbAvailable, installAvailable, logAvailable, diagnosticFailures, deviceFailure, adbFailure, envFailure),
35
+ devices: deviceEntries,
36
+ failures: diagnosticFailures
37
+ };
38
+ }
39
+ function androidFailures(android, adbAvailable, adbDiscovery) {
40
+ const envFailure = !android.envValid
41
+ ? makeFailure('TOOL_VALIDATION_FAILED', 'android', 'Android environment prerequisites are incomplete.', {
42
+ tool: 'adb',
43
+ searchedLocations: ['ANDROID_SDK_ROOT', 'ANDROID_HOME', 'PATH'],
44
+ selectedProvider: 'adb',
45
+ rawVersion: android.adbVersion || null,
46
+ remediation: ['Set ANDROID_SDK_ROOT or ANDROID_HOME, or ensure adb is on PATH.']
47
+ })
48
+ : null;
49
+ const adbFailure = !adbAvailable
50
+ ? makeFailure(process.env.ADB_PATH && process.env.ADB_PATH.trim() ? 'TOOL_NOT_EXECUTABLE' : 'TOOL_NOT_FOUND', 'android', 'Android adb could not be resolved or executed.', {
51
+ tool: 'adb',
52
+ searchedLocations: adbDiscovery.searchedLocations,
53
+ selectedProvider: null,
54
+ rawVersion: android.adbVersion || null,
55
+ remediation: [
56
+ 'Install Android platform-tools.',
57
+ 'Set ADB_PATH or ANDROID_SDK_ROOT/ANDROID_HOME if adb is installed in a non-standard location.'
58
+ ]
59
+ })
60
+ : null;
61
+ const deviceFailure = adbAvailable && android.devices === 0
62
+ ? makeFailure('DEVICE_NOT_FOUND', 'android', 'No Android devices or emulators are connected.', {
63
+ tool: 'adb',
64
+ searchedLocations: ['adb devices -l'],
65
+ selectedProvider: 'adb',
66
+ rawVersion: android.adbVersion || null,
67
+ remediation: ['Start an emulator or connect a device, then re-run adb devices.']
68
+ })
69
+ : null;
70
+ const diagnosticFailures = [adbFailure, envFailure, deviceFailure].filter((value) => value !== null);
71
+ return { envFailure, adbFailure, deviceFailure, diagnosticFailures };
72
+ }
73
+ function androidCapabilities(adbAvailable, installAvailable, logAvailable, diagnosticFailures, deviceFailure, adbFailure, envFailure) {
74
+ const applicationCapability = {
75
+ availability: installAvailable,
76
+ selectedProvider: installAvailable ? 'adb' : null,
77
+ blockingFailure: installAvailable ? null : deviceFailure ?? adbFailure ?? envFailure
78
+ };
79
+ return {
80
+ device_discovery: {
81
+ availability: adbAvailable,
82
+ selectedProvider: adbAvailable ? 'adb' : null,
83
+ blockingFailure: adbAvailable ? null : diagnosticFailures[0] ?? null
84
+ },
85
+ install_app: { ...applicationCapability },
86
+ launch_app: { ...applicationCapability },
87
+ ui_interaction: { ...applicationCapability },
88
+ screenshot: { ...applicationCapability },
89
+ log_capture: {
90
+ availability: logAvailable,
91
+ selectedProvider: logAvailable ? 'adb' : null,
92
+ blockingFailure: logAvailable ? null : adbFailure ?? envFailure
93
+ },
94
+ debug: {
95
+ probeRequired: 'get_debugger_capabilities',
96
+ availability: false,
97
+ selectedProvider: null,
98
+ blockingFailure: deviceFailure ?? adbFailure ?? envFailure
99
+ }
100
+ };
101
+ }
@@ -18,23 +18,9 @@ export async function checkAndroid() {
18
18
  issues.push('ADB not available');
19
19
  try {
20
20
  const out = execSync(`${adbCmd} devices -l`, { encoding: 'utf8', timeout: 1500, stdio: ['ignore', 'pipe', 'ignore'] }).toString();
21
- const lines = out.split('\n').map(l => l.trim()).filter(Boolean);
22
- const deviceLines = lines.filter(l => !l.startsWith('List of devices'));
23
- const stateCounts = {};
24
- for (const l of deviceLines) {
25
- const parts = l.split(/\s+/);
26
- const state = parts[1] || '';
27
- stateCounts[state] = (stateCounts[state] || 0) + 1;
28
- }
29
- devices = deviceLines.length;
30
- const parts = Object.entries(stateCounts).map(([k, v]) => `${v} ${k}`);
31
- deviceStates = parts.join(', ');
32
- if (devices === 0)
33
- issues.push('No Android devices connected');
34
- if (stateCounts['unauthorized'])
35
- issues.push(`${stateCounts['unauthorized']} device(s) unauthorized`);
36
- if (stateCounts['offline'])
37
- issues.push(`${stateCounts['offline']} device(s) offline`);
21
+ const state = parseDevices(out, issues);
22
+ devices = state.devices;
23
+ deviceStates = state.deviceStates;
38
24
  }
39
25
  catch (e) {
40
26
  console.debug('[get_system_status] adb devices failed: ' + String(e));
@@ -58,16 +44,7 @@ export async function checkAndroid() {
58
44
  issues.push('ANDROID_SDK_ROOT/ANDROID_HOME missing and adb not found in PATH');
59
45
  const pkg = process.env.MCP_TARGET_PACKAGE || process.env.MCP_TARGET_APP_ID;
60
46
  if (pkg && adbAvailable && devices > 0) {
61
- try {
62
- const pm = execSync(`${adbCmd} shell pm path ${pkg}`, { encoding: 'utf8', timeout: 1500, stdio: ['ignore', 'pipe', 'ignore'] }).toString();
63
- appInstalled = (pm || '').includes('package:');
64
- if (!appInstalled)
65
- issues.push(`App ${pkg} not installed on devices`);
66
- }
67
- catch (e) {
68
- appInstalled = false;
69
- console.debug('[get_system_status] pm check failed: ' + String(e));
70
- }
47
+ appInstalled = probeAppInstalled(adbCmd, pkg, issues);
71
48
  }
72
49
  }
73
50
  catch (e) {
@@ -76,3 +53,36 @@ export async function checkAndroid() {
76
53
  }
77
54
  return { adbAvailable, adbVersion, devices, deviceStates, logsAvailable, envValid, appInstalled, issues };
78
55
  }
56
+ function parseDevices(out, issues) {
57
+ const lines = out.split('\n').map(l => l.trim()).filter(Boolean);
58
+ const deviceLines = lines.filter(l => !l.startsWith('List of devices'));
59
+ const stateCounts = {};
60
+ for (const l of deviceLines) {
61
+ const parts = l.split(/\s+/);
62
+ const state = parts[1] || '';
63
+ stateCounts[state] = (stateCounts[state] || 0) + 1;
64
+ }
65
+ const devices = deviceLines.length;
66
+ const parts = Object.entries(stateCounts).map(([k, v]) => `${v} ${k}`);
67
+ const deviceStates = parts.join(', ');
68
+ if (devices === 0)
69
+ issues.push('No Android devices connected');
70
+ if (stateCounts['unauthorized'])
71
+ issues.push(`${stateCounts['unauthorized']} device(s) unauthorized`);
72
+ if (stateCounts['offline'])
73
+ issues.push(`${stateCounts['offline']} device(s) offline`);
74
+ return { devices, deviceStates };
75
+ }
76
+ function probeAppInstalled(adbCmd, pkg, issues) {
77
+ try {
78
+ const pm = execSync(`${adbCmd} shell pm path ${pkg}`, { encoding: 'utf8', timeout: 1500, stdio: ['ignore', 'pipe', 'ignore'] }).toString();
79
+ const appInstalled = (pm || '').includes('package:');
80
+ if (!appInstalled)
81
+ issues.push(`App ${pkg} not installed on devices`);
82
+ return appInstalled;
83
+ }
84
+ catch (e) {
85
+ console.debug('[get_system_status] pm check failed: ' + String(e));
86
+ return false;
87
+ }
88
+ }
@@ -1,442 +1,12 @@
1
- import { spawnSync } from 'child_process';
2
- import path from 'path';
3
1
  import { checkAndroid } from './android.js';
4
2
  import { checkGradle } from './gradle.js';
5
3
  import { checkIOS } from './ios.js';
6
- import { resolveAdbCmd } from '../utils/android/utils.js';
7
- import { getIdbCmd, getXcrunCmd } from '../utils/ios/utils.js';
8
- import { probeIdb } from '../utils/cli/idb/idb-helper.js';
9
4
  import { detectJavaHome } from '../utils/java.js';
10
- function normalizeHostOs(platform) {
11
- switch (platform) {
12
- case 'darwin':
13
- return 'macos';
14
- case 'linux':
15
- return 'linux';
16
- case 'win32':
17
- return 'windows';
18
- case 'freebsd':
19
- case 'openbsd':
20
- case 'netbsd':
21
- case 'sunos':
22
- return platform;
23
- default:
24
- return 'unknown';
25
- }
26
- }
27
- function isSupportedHost(hostOs) {
28
- return hostOs === 'macos' || hostOs === 'linux' || hostOs === 'windows';
29
- }
30
- function firstVersionToken(raw) {
31
- if (!raw)
32
- return null;
33
- const match = String(raw).match(/(\d+(?:\.\d+)+|\d+)/);
34
- return match?.[1] ?? null;
35
- }
36
- function probeCommand(command, args, timeoutMs = 2000) {
37
- try {
38
- const result = spawnSync(command, args, { encoding: 'utf8', timeout: timeoutMs, stdio: ['ignore', 'pipe', 'pipe'] });
39
- const raw = `${result.stdout || ''}${result.stderr || ''}`.trim() || null;
40
- return {
41
- ok: result.status === 0,
42
- raw,
43
- parsedVersion: firstVersionToken(raw)
44
- };
45
- }
46
- catch {
47
- return { ok: false, raw: null, parsedVersion: null };
48
- }
49
- }
50
- function makeFailure(code, platform, message, opts = {}) {
51
- return {
52
- code,
53
- platform,
54
- tool: opts.tool ?? null,
55
- message,
56
- searchedLocations: opts.searchedLocations ?? [],
57
- selectedProvider: opts.selectedProvider ?? null,
58
- rawVersion: opts.rawVersion ?? null,
59
- remediation: opts.remediation ?? []
60
- };
61
- }
62
- function makeToolEntry(resolvedPath, discoverySource, rawVersionOutput, validationStatus) {
63
- return {
64
- resolvedPath,
65
- discoverySource,
66
- parsedVersion: firstVersionToken(rawVersionOutput),
67
- rawVersionOutput,
68
- validationStatus
69
- };
70
- }
71
- function describeAdbDiscovery(adbCmd) {
72
- const searchedLocations = ['ADB_PATH', 'ANDROID_SDK_ROOT/platform-tools/adb', 'ANDROID_HOME/platform-tools/adb', '~/Library/Android/sdk/platform-tools/adb', 'PATH'];
73
- if (process.env.ADB_PATH && process.env.ADB_PATH.trim())
74
- return { discoverySource: 'ADB_PATH', searchedLocations };
75
- if (process.env.ANDROID_SDK_ROOT)
76
- return { discoverySource: 'ANDROID_SDK_ROOT', searchedLocations };
77
- if (process.env.ANDROID_HOME)
78
- return { discoverySource: 'ANDROID_HOME', searchedLocations };
79
- if (adbCmd.includes('Library/Android/sdk'))
80
- return { discoverySource: 'HOME_SDK', searchedLocations };
81
- if (adbCmd === 'adb')
82
- return { discoverySource: 'PATH_OR_FALLBACK', searchedLocations };
83
- return { discoverySource: 'PATH', searchedLocations };
84
- }
85
- function describeXcrunDiscovery(xcrunCmd) {
86
- const searchedLocations = ['XCRUN_PATH', 'PATH'];
87
- if (process.env.XCRUN_PATH && process.env.XCRUN_PATH.trim())
88
- return { discoverySource: 'XCRUN_PATH', searchedLocations };
89
- return { discoverySource: xcrunCmd === 'xcrun' ? 'PATH' : 'PATH', searchedLocations };
90
- }
91
- function describeIdbDiscovery(idbCmd) {
92
- const searchedLocations = ['MCP_IDB_PATH', 'IDB_PATH', 'mcp.config.json', '~/.mcp/config.json', 'PATH', '/opt/homebrew/bin/idb', '/usr/local/bin/idb'];
93
- if (process.env.MCP_IDB_PATH && process.env.MCP_IDB_PATH.trim())
94
- return { discoverySource: 'MCP_IDB_PATH', searchedLocations };
95
- if (process.env.IDB_PATH && process.env.IDB_PATH.trim())
96
- return { discoverySource: 'IDB_PATH', searchedLocations };
97
- return { discoverySource: idbCmd === 'idb' ? 'PATH_OR_FALLBACK' : 'PATH', searchedLocations };
98
- }
99
- function describeJavaDiscovery(javaHome) {
100
- const searchedLocations = ['GRADLE_JAVA_HOME', 'JAVA_HOME', 'GRADLE_HOME', 'detectJavaHome'];
101
- if (process.env.GRADLE_JAVA_HOME && process.env.GRADLE_JAVA_HOME.trim())
102
- return { discoverySource: 'GRADLE_JAVA_HOME', searchedLocations };
103
- if (process.env.JAVA_HOME && process.env.JAVA_HOME.trim())
104
- return { discoverySource: 'JAVA_HOME', searchedLocations };
105
- if (process.env.GRADLE_HOME && process.env.GRADLE_HOME.trim())
106
- return { discoverySource: 'GRADLE_HOME', searchedLocations };
107
- return { discoverySource: javaHome ? 'detected' : null, searchedLocations };
108
- }
109
- function resolveJavaBinaryPath(javaHome, hostOs) {
110
- const javaBinary = hostOs === 'windows' ? 'java.exe' : 'java';
111
- return path.join(javaHome, 'bin', javaBinary);
112
- }
113
- function buildUnsupportedHostStatus(hostOs) {
114
- const failureMessage = `Host operating system '${hostOs}' is not supported.`;
115
- const remediation = ['Run Mobile Debug MCP on macOS, Linux, or Windows.'];
116
- const failureAndroid = makeFailure('HOST_OS_UNSUPPORTED', 'android', failureMessage, {
117
- remediation
118
- });
119
- const failureIos = makeFailure('HOST_OS_UNSUPPORTED', 'ios', failureMessage, {
120
- remediation
121
- });
122
- return {
123
- success: false,
124
- status: 'blocked',
125
- adbAvailable: false,
126
- adbVersion: '',
127
- devices: 0,
128
- deviceStates: '',
129
- logsAvailable: false,
130
- envValid: false,
131
- issues: [failureMessage],
132
- appInstalled: undefined,
133
- iosAvailable: false,
134
- iosDevices: 0,
135
- gradleJavaHome: undefined,
136
- gradleValid: false,
137
- gradleFilesChecked: [],
138
- gradleSuggestedFixes: [],
139
- host: { os: hostOs, supported: false },
140
- android: {
141
- status: 'unsupported',
142
- tools: {},
143
- providers: {},
144
- capabilities: {},
145
- devices: [],
146
- failures: [failureAndroid]
147
- },
148
- ios: {
149
- status: 'unsupported',
150
- tools: {},
151
- providers: {},
152
- capabilities: {},
153
- devices: [],
154
- failures: [failureIos]
155
- },
156
- summary: {
157
- overall: 'blocked',
158
- android: { ready: false, summary: `Host operating system '${hostOs}' is not supported.`, blockers: [failureMessage] },
159
- ios: { ready: false, summary: `Host operating system '${hostOs}' is not supported.`, blockers: [failureMessage] },
160
- gradle: { ready: false, summary: 'Gradle status unavailable on unsupported host', blockers: [], suggestedFixes: [] }
161
- }
162
- };
163
- }
164
- function buildAndroidPlatform(android, hostSupported) {
165
- const resolvedAdbCmd = resolveAdbCmd();
166
- const adbDiscovery = describeAdbDiscovery(resolvedAdbCmd);
167
- const adbTool = makeToolEntry(resolvedAdbCmd, adbDiscovery.discoverySource, android.adbVersion || null, android.adbAvailable ? 'valid' : 'invalid');
168
- const adbAvailable = !!android.adbAvailable;
169
- const deviceIssues = android.issues.filter((issue) => /unauthorized|offline|No Android devices connected/i.test(issue));
170
- const envFailure = !android.envValid
171
- ? makeFailure('TOOL_VALIDATION_FAILED', 'android', 'Android environment prerequisites are incomplete.', {
172
- tool: 'adb',
173
- searchedLocations: ['ANDROID_SDK_ROOT', 'ANDROID_HOME', 'PATH'],
174
- selectedProvider: 'adb',
175
- rawVersion: android.adbVersion || null,
176
- remediation: ['Set ANDROID_SDK_ROOT or ANDROID_HOME, or ensure adb is on PATH.']
177
- })
178
- : null;
179
- const adbFailure = !adbAvailable
180
- ? makeFailure(process.env.ADB_PATH && process.env.ADB_PATH.trim() ? 'TOOL_NOT_EXECUTABLE' : 'TOOL_NOT_FOUND', 'android', 'Android adb could not be resolved or executed.', {
181
- tool: 'adb',
182
- searchedLocations: adbDiscovery.searchedLocations,
183
- selectedProvider: null,
184
- rawVersion: android.adbVersion || null,
185
- remediation: [
186
- 'Install Android platform-tools.',
187
- 'Set ADB_PATH or ANDROID_SDK_ROOT/ANDROID_HOME if adb is installed in a non-standard location.'
188
- ]
189
- })
190
- : null;
191
- const deviceFailure = adbAvailable && android.devices === 0
192
- ? makeFailure('DEVICE_NOT_FOUND', 'android', 'No Android devices or emulators are connected.', {
193
- tool: 'adb',
194
- searchedLocations: ['adb devices -l'],
195
- selectedProvider: 'adb',
196
- rawVersion: android.adbVersion || null,
197
- remediation: ['Start an emulator or connect a device, then re-run adb devices.']
198
- })
199
- : null;
200
- const diagnosticFailures = [adbFailure, envFailure, deviceFailure].filter((value) => value !== null);
201
- const status = !hostSupported
202
- ? 'unsupported'
203
- : !adbAvailable
204
- ? 'unavailable'
205
- : (android.devices === 0 || deviceIssues.length > 0 || !android.logsAvailable || !android.envValid)
206
- ? 'partially_ready'
207
- : 'ready';
208
- const deviceEntries = android.devices > 0
209
- ? Array.from({ length: android.devices }, (_, index) => ({
210
- id: `android-device-${index + 1}`,
211
- state: deviceIssues.length > 0 ? 'degraded' : 'connected'
212
- }))
213
- : [];
214
- const deviceDiscoveryAvailable = adbAvailable;
215
- const installAvailable = adbAvailable && android.devices > 0 && deviceIssues.length === 0;
216
- const logAvailable = adbAvailable && android.logsAvailable;
217
- return {
218
- status,
219
- tools: {
220
- adb: adbTool
221
- },
222
- providers: {
223
- adb: { available: adbAvailable, selected: true, tool: 'adb' },
224
- jdwp: { available: false, selected: false, tool: 'adb', probeRequired: 'get_debugger_capabilities' }
225
- },
226
- capabilities: {
227
- device_discovery: {
228
- availability: deviceDiscoveryAvailable,
229
- selectedProvider: deviceDiscoveryAvailable ? 'adb' : null,
230
- blockingFailure: deviceDiscoveryAvailable ? null : diagnosticFailures[0] ?? null
231
- },
232
- install_app: {
233
- availability: installAvailable,
234
- selectedProvider: installAvailable ? 'adb' : null,
235
- blockingFailure: installAvailable ? null : deviceFailure ?? adbFailure ?? envFailure
236
- },
237
- launch_app: {
238
- availability: installAvailable,
239
- selectedProvider: installAvailable ? 'adb' : null,
240
- blockingFailure: installAvailable ? null : deviceFailure ?? adbFailure ?? envFailure
241
- },
242
- ui_interaction: {
243
- availability: installAvailable,
244
- selectedProvider: installAvailable ? 'adb' : null,
245
- blockingFailure: installAvailable ? null : deviceFailure ?? adbFailure ?? envFailure
246
- },
247
- screenshot: {
248
- availability: installAvailable,
249
- selectedProvider: installAvailable ? 'adb' : null,
250
- blockingFailure: installAvailable ? null : deviceFailure ?? adbFailure ?? envFailure
251
- },
252
- log_capture: {
253
- availability: logAvailable,
254
- selectedProvider: logAvailable ? 'adb' : null,
255
- blockingFailure: logAvailable ? null : adbFailure ?? envFailure
256
- },
257
- debug: {
258
- probeRequired: 'get_debugger_capabilities',
259
- availability: false,
260
- selectedProvider: null,
261
- blockingFailure: deviceFailure ?? adbFailure ?? envFailure
262
- }
263
- },
264
- devices: deviceEntries,
265
- failures: diagnosticFailures
266
- };
267
- }
268
- function buildIOSPlatform(ios, hostSupported, hostOs) {
269
- const platformUnsupported = !hostSupported || hostOs === 'linux' || hostOs === 'windows';
270
- if (platformUnsupported) {
271
- return {
272
- status: 'unsupported',
273
- tools: {},
274
- providers: {},
275
- capabilities: {},
276
- devices: [],
277
- failures: [
278
- makeFailure('PLATFORM_UNAVAILABLE', 'ios', 'iOS tooling is only supported on macOS.', {
279
- tool: null,
280
- searchedLocations: [],
281
- selectedProvider: null,
282
- rawVersion: null,
283
- remediation: ['Run Mobile Debug MCP on macOS for iOS toolchain discovery.']
284
- })
285
- ]
286
- };
287
- }
288
- const xcrunCmd = getXcrunCmd();
289
- const xcrunProbe = ios.iosAvailable ? probeCommand(xcrunCmd, ['--version']) : { ok: false, raw: null, parsedVersion: null };
290
- const idbCmd = getIdbCmd();
291
- const idbProbe = hostSupported && hostOs === 'macos' ? probeIdb(idbCmd) : { ok: false, raw: null, parsedVersion: null };
292
- const idbCompanionProbe = hostSupported && hostOs === 'macos' ? probeCommand('idb_companion', ['--version']) : { ok: false, raw: null, parsedVersion: null };
293
- const xcrunTool = makeToolEntry(xcrunCmd, describeXcrunDiscovery(xcrunCmd).discoverySource, xcrunProbe.raw, xcrunProbe.ok ? 'valid' : 'invalid');
294
- const idbTool = makeToolEntry(idbCmd, describeIdbDiscovery(idbCmd).discoverySource, idbProbe.raw, idbProbe.ok ? 'valid' : 'invalid');
295
- const idbCompanionTool = makeToolEntry('idb_companion', 'PATH', idbCompanionProbe.raw, idbCompanionProbe.ok ? 'valid' : 'invalid');
296
- const lldbTool = makeToolEntry('xcrun lldb', 'xcrun', xcrunProbe.raw, xcrunProbe.ok ? 'valid' : 'invalid');
297
- const simctlAvailable = !!ios.iosAvailable;
298
- const idbAvailable = !!idbProbe.ok;
299
- const bootedDevices = ios.iosDevices > 0
300
- ? Array.from({ length: ios.iosDevices }, (_, index) => ({
301
- id: `ios-simulator-${index + 1}`,
302
- state: 'booted'
303
- }))
304
- : [];
305
- const platformUnavailableFailure = !platformUnsupported && !simctlAvailable
306
- ? makeFailure('PLATFORM_UNAVAILABLE', 'ios', 'iOS tooling is unavailable on this host.', {
307
- tool: 'xcrun',
308
- searchedLocations: describeXcrunDiscovery(xcrunCmd).searchedLocations,
309
- selectedProvider: null,
310
- rawVersion: xcrunProbe.raw,
311
- remediation: ['Install Xcode Command Line Tools and ensure xcrun is on PATH.']
312
- })
313
- : null;
314
- const deviceFailure = simctlAvailable && !bootedDevices.length
315
- ? makeFailure('DEVICE_NOT_FOUND', 'ios', 'No iOS simulators are booted.', {
316
- tool: 'simctl',
317
- searchedLocations: ['xcrun simctl list devices booted --json'],
318
- selectedProvider: 'simctl',
319
- rawVersion: xcrunProbe.raw,
320
- remediation: ['Boot a simulator in Xcode or via xcrun simctl boot.']
321
- })
322
- : null;
323
- const selectedInstallProvider = idbAvailable ? 'idb' : simctlAvailable ? 'simctl' : null;
324
- const selectedDebugProvider = simctlAvailable ? 'LLDB' : null;
325
- const selectedDiscoveryProvider = idbAvailable ? 'idb' : simctlAvailable ? 'simctl' : null;
326
- const status = platformUnsupported
327
- ? 'unsupported'
328
- : !simctlAvailable
329
- ? 'unavailable'
330
- : !bootedDevices.length
331
- ? 'partially_ready'
332
- : 'ready';
333
- const iosFailure = platformUnsupported
334
- ? makeFailure('PLATFORM_UNAVAILABLE', 'ios', 'iOS tooling is only supported on macOS.', {
335
- tool: null,
336
- searchedLocations: [],
337
- selectedProvider: null,
338
- rawVersion: null,
339
- remediation: ['Run Mobile Debug MCP on macOS for iOS toolchain discovery.']
340
- })
341
- : platformUnavailableFailure ?? deviceFailure ?? null;
342
- const failureList = [iosFailure].filter((value) => value !== null);
343
- return {
344
- status,
345
- tools: {
346
- xcrun: xcrunTool,
347
- idb: idbTool,
348
- idb_companion: idbCompanionTool,
349
- lldb: lldbTool
350
- },
351
- providers: {
352
- idb: { available: idbAvailable, selected: selectedInstallProvider === 'idb', tool: 'idb' },
353
- simctl: { available: simctlAvailable, selected: selectedInstallProvider === 'simctl', tool: 'xcrun' },
354
- lldb: { available: simctlAvailable, selected: selectedDebugProvider === 'LLDB', tool: 'xcrun' }
355
- },
356
- capabilities: {
357
- device_discovery: {
358
- availability: !!selectedDiscoveryProvider,
359
- selectedProvider: selectedDiscoveryProvider,
360
- blockingFailure: selectedDiscoveryProvider ? null : iosFailure
361
- },
362
- install_app: {
363
- availability: !!selectedInstallProvider && bootedDevices.length > 0,
364
- selectedProvider: selectedInstallProvider,
365
- blockingFailure: selectedInstallProvider && bootedDevices.length > 0 ? null : deviceFailure ?? iosFailure
366
- },
367
- launch_app: {
368
- availability: !!selectedInstallProvider && bootedDevices.length > 0,
369
- selectedProvider: selectedInstallProvider,
370
- blockingFailure: selectedInstallProvider && bootedDevices.length > 0 ? null : deviceFailure ?? iosFailure
371
- },
372
- ui_interaction: {
373
- availability: !!selectedInstallProvider && bootedDevices.length > 0,
374
- selectedProvider: selectedInstallProvider,
375
- blockingFailure: selectedInstallProvider && bootedDevices.length > 0 ? null : deviceFailure ?? iosFailure
376
- },
377
- screenshot: {
378
- availability: !!selectedInstallProvider && bootedDevices.length > 0,
379
- selectedProvider: selectedInstallProvider,
380
- blockingFailure: selectedInstallProvider && bootedDevices.length > 0 ? null : deviceFailure ?? iosFailure
381
- },
382
- log_capture: {
383
- availability: simctlAvailable && bootedDevices.length > 0,
384
- selectedProvider: simctlAvailable ? 'simctl' : null,
385
- blockingFailure: simctlAvailable && bootedDevices.length > 0 ? null : deviceFailure ?? iosFailure
386
- },
387
- debug: {
388
- availability: !!selectedDebugProvider,
389
- selectedProvider: selectedDebugProvider,
390
- blockingFailure: selectedDebugProvider ? null : iosFailure
391
- }
392
- },
393
- devices: bootedDevices,
394
- failures: failureList
395
- };
396
- }
397
- function buildLegacySummary(androidStatus, iosStatus, gradle) {
398
- const androidReady = androidStatus.status === 'ready';
399
- const iosReady = iosStatus.status === 'ready';
400
- const gradleReady = (gradle.issues || []).length === 0;
401
- const overallStatus = (androidReady || iosReady || gradleReady)
402
- ? ((androidReady && iosReady && gradleReady) ? 'ready' : 'degraded')
403
- : 'blocked';
404
- return {
405
- overall: overallStatus,
406
- android: {
407
- ready: androidReady,
408
- summary: androidStatus.status === 'ready'
409
- ? `${androidStatus.devices.length} Android device(s) connected; log access available`
410
- : androidStatus.status === 'partially_ready'
411
- ? 'Android toolchain available but device-dependent capabilities are limited'
412
- : androidStatus.status === 'unsupported'
413
- ? 'Android unsupported on this host'
414
- : 'ADB unavailable',
415
- blockers: androidStatus.failures.map((failure) => failure.message)
416
- },
417
- ios: {
418
- ready: iosReady,
419
- summary: iosStatus.status === 'ready'
420
- ? `${iosStatus.devices.length} iOS simulator(s) booted`
421
- : iosStatus.status === 'partially_ready'
422
- ? 'iOS toolchain available but device-dependent capabilities are limited'
423
- : iosStatus.status === 'unsupported'
424
- ? 'iOS unsupported on this host'
425
- : 'xcrun unavailable',
426
- blockers: iosStatus.failures.map((failure) => failure.message)
427
- },
428
- gradle: {
429
- ready: gradleReady,
430
- summary: !gradle.gradleJavaHome
431
- ? 'No explicit Gradle JDK override detected'
432
- : gradleReady
433
- ? `Gradle JDK configured at ${gradle.gradleJavaHome}`
434
- : `Gradle JDK override invalid: ${gradle.gradleJavaHome}`,
435
- blockers: gradle.issues || [],
436
- suggestedFixes: gradle.suggestedFixes || []
437
- }
438
- };
439
- }
5
+ import { buildAndroidPlatform } from './android-status.js';
6
+ import { buildIOSPlatform } from './ios-status.js';
7
+ import { buildLegacySummary } from './status-summary.js';
8
+ import { buildUnsupportedHostStatus } from './unsupported-status.js';
9
+ import { normalizeHostOs, isSupportedHost, probeCommand, makeToolEntry, describeJavaDiscovery, resolveJavaBinaryPath } from './probes.js';
440
10
  export async function getSystemStatus() {
441
11
  const hostOs = normalizeHostOs((process.env.MOBILE_DEBUG_MCP_HOST_OS || process.platform));
442
12
  if (!isSupportedHost(hostOs)) {
@@ -459,10 +29,7 @@ export async function getSystemStatus() {
459
29
  const androidReady = androidRaw.adbAvailable && androidRaw.devices > 0 && !androidRaw.issues.some((issue) => /unauthorized|offline/i.test(issue));
460
30
  const iosReady = hostOs === 'macos' ? (iosRaw.iosAvailable && iosRaw.iosDevices > 0) : false;
461
31
  const overallStatus = success ? 'ready' : (androidReady || iosReady ? 'degraded' : 'blocked');
462
- const javaHome = gradle.gradleJavaHome || (await detectJavaHome().catch(() => undefined));
463
- const javaBin = javaHome ? resolveJavaBinaryPath(javaHome, hostOs) : null;
464
- const javaProbe = javaBin ? probeCommand(javaBin, ['-version']) : { ok: false, raw: null, parsedVersion: null };
465
- const javaTool = makeToolEntry(javaBin, describeJavaDiscovery(javaHome ?? null).discoverySource, javaProbe.raw, javaProbe.ok ? 'valid' : (javaHome ? 'invalid' : 'missing'));
32
+ const javaTool = await javaStatus(gradle, hostOs);
466
33
  return {
467
34
  success,
468
35
  status: overallStatus,
@@ -519,3 +86,10 @@ export async function getSystemStatus() {
519
86
  };
520
87
  }
521
88
  }
89
+ async function javaStatus(gradle, hostOs) {
90
+ const javaHome = gradle.gradleJavaHome || (await detectJavaHome().catch(() => undefined));
91
+ const javaBin = javaHome ? resolveJavaBinaryPath(javaHome, hostOs) : null;
92
+ const javaProbe = javaBin ? probeCommand(javaBin, ['-version']) : { ok: false, raw: null, parsedVersion: null };
93
+ const javaTool = makeToolEntry(javaBin, describeJavaDiscovery(javaHome ?? null).discoverySource, javaProbe.raw, javaProbe.ok ? 'valid' : (javaHome ? 'invalid' : 'missing'));
94
+ return javaTool;
95
+ }