mobile-debug-mcp 0.33.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 (448) 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 +23 -2
  12. package/AGENTS.md +12 -3
  13. package/CONTRIBUTING.md +79 -0
  14. package/README.md +158 -124
  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 +20 -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 +113 -4
  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 +79 -0
  28. package/dist/debugger/diagnostics.js +54 -0
  29. package/dist/debugger/guard.js +30 -0
  30. package/dist/debugger/protocol.js +33 -0
  31. package/dist/debugger/sessions.js +304 -0
  32. package/dist/debugger/worker.js +176 -0
  33. package/dist/interact/adjustment/adjustment-context.js +41 -0
  34. package/dist/interact/adjustment/adjustment-gestures.js +55 -0
  35. package/dist/interact/adjustment/adjustment-plan.js +18 -0
  36. package/dist/interact/adjustment/adjustment-resolution.js +127 -0
  37. package/dist/interact/adjustment/adjustment-result.js +19 -0
  38. package/dist/interact/adjustment/adjustment-semantic.js +64 -0
  39. package/dist/interact/adjustment/adjustment-verification.js +35 -0
  40. package/dist/interact/adjustment/adjustment.js +52 -0
  41. package/dist/interact/adjustment/control-geometry.js +87 -0
  42. package/dist/interact/adjustment/control-values.js +136 -0
  43. package/dist/interact/adjustment/slider-labels.js +84 -0
  44. package/dist/interact/assertions/screen-assertion.js +37 -0
  45. package/dist/interact/assertions/state-assertion-context.js +35 -0
  46. package/dist/interact/assertions/state-assertion.js +76 -0
  47. package/dist/interact/assertions/state-comparison.js +141 -0
  48. package/dist/interact/assertions/visibility-assertion.js +34 -0
  49. package/dist/interact/conditional-action.js +12 -7
  50. package/dist/interact/index.js +65 -3074
  51. package/dist/interact/input-service.js +1 -0
  52. package/dist/interact/interaction-trace.js +21 -0
  53. package/dist/interact/model.js +1 -0
  54. package/dist/interact/observation.js +1 -0
  55. package/dist/interact/targeting/candidate-ancestor.js +58 -0
  56. package/dist/interact/targeting/candidate-result.js +23 -0
  57. package/dist/interact/targeting/candidate-scoring.js +50 -0
  58. package/dist/interact/targeting/element-helpers.js +216 -0
  59. package/dist/interact/targeting/find-element.js +65 -0
  60. package/dist/interact/targeting/nearby-control.js +56 -0
  61. package/dist/interact/targeting/resolved-elements.js +21 -0
  62. package/dist/interact/targeting/tap-target.js +17 -0
  63. package/dist/interact/targeting/target-scope.js +104 -0
  64. package/dist/interact/waits/legacy-log-wait.js +38 -0
  65. package/dist/interact/waits/legacy-wait-observations.js +103 -0
  66. package/dist/interact/waits/legacy-wait-state.js +34 -0
  67. package/dist/interact/waits/legacy-wait.js +48 -0
  68. package/dist/interact/waits/screen-wait.js +49 -0
  69. package/dist/interact/waits/ui-change-helpers.js +157 -0
  70. package/dist/interact/waits/ui-change-state.js +18 -0
  71. package/dist/interact/waits/ui-change-wait.js +77 -0
  72. package/dist/interact/waits/ui-wait-condition.js +56 -0
  73. package/dist/interact/waits/ui-wait-state.js +38 -0
  74. package/dist/interact/waits/ui-wait.js +106 -0
  75. package/dist/manage/android.js +55 -51
  76. package/dist/manage/index.js +38 -75
  77. package/dist/manage/ios/build-types.js +1 -0
  78. package/dist/manage/ios/build.js +210 -0
  79. package/dist/manage/ios/project-discovery.js +29 -0
  80. package/dist/manage/ios/scheme.js +18 -0
  81. package/dist/manage/ios.js +42 -256
  82. package/dist/observe/android/context.js +1 -0
  83. package/dist/observe/android/current-screen.js +55 -0
  84. package/dist/observe/android/fingerprint.js +13 -0
  85. package/dist/observe/android/log-stream.js +132 -0
  86. package/dist/observe/android/logs.js +107 -0
  87. package/dist/observe/android/screenshot.js +70 -0
  88. package/dist/observe/android/ui-tree.js +107 -0
  89. package/dist/observe/android.js +16 -520
  90. package/dist/observe/evidence.js +122 -76
  91. package/dist/observe/index.js +16 -263
  92. package/dist/observe/ios/context.js +16 -0
  93. package/dist/observe/ios/fingerprint.js +12 -0
  94. package/dist/observe/ios/log-stream.js +105 -0
  95. package/dist/observe/ios/logs.js +168 -0
  96. package/dist/observe/ios/screenshot.js +22 -0
  97. package/dist/observe/ios/ui-elements.js +241 -0
  98. package/dist/observe/ios/ui-tree.js +137 -0
  99. package/dist/observe/ios.js +17 -715
  100. package/dist/observe/logs/model.js +1 -0
  101. package/dist/{network → observe/network}/index.js +2 -2
  102. package/dist/observe/readiness-service.js +13 -2
  103. package/dist/observe/readiness.js +44 -18
  104. package/dist/observe/screenshot-encoding.js +41 -0
  105. package/dist/observe/snapshot-collection.js +79 -0
  106. package/dist/observe/snapshot-logs.js +30 -0
  107. package/dist/observe/snapshot-metadata.js +43 -31
  108. package/dist/observe/snapshot-semantic.js +115 -0
  109. package/dist/observe/system-trace-android.js +135 -0
  110. package/dist/observe/system-trace.js +294 -0
  111. package/dist/runtime/action-results.js +270 -0
  112. package/dist/runtime/clock.js +4 -0
  113. package/dist/server/common.js +1 -256
  114. package/dist/server/definitions/assert.js +162 -0
  115. package/dist/server/definitions/diagnostic.js +118 -0
  116. package/dist/server/definitions/input.js +274 -0
  117. package/dist/server/definitions/manage.js +194 -0
  118. package/dist/server/definitions/observe.js +149 -0
  119. package/dist/server/definitions/target.js +138 -0
  120. package/dist/server/definitions/wait.js +105 -0
  121. package/dist/server/handlers/action-execution.js +163 -0
  122. package/dist/server/handlers/correlation.js +23 -0
  123. package/dist/server/handlers/debugger-handlers.js +48 -0
  124. package/dist/server/handlers/debugger-response.js +9 -0
  125. package/dist/server/handlers/diagnostic.js +69 -0
  126. package/dist/server/handlers/handler-types.js +1 -0
  127. package/dist/server/handlers/input.js +154 -0
  128. package/dist/server/handlers/interact.js +113 -0
  129. package/dist/server/handlers/journey-assertions.js +35 -0
  130. package/dist/server/handlers/journey.js +147 -0
  131. package/dist/server/handlers/manage.js +119 -0
  132. package/dist/server/handlers/observe.js +95 -0
  133. package/dist/server/handlers/payload.js +4 -0
  134. package/dist/server/handlers/tool-handlers.js +160 -0
  135. package/dist/server/schemas/condition-schema.js +2 -0
  136. package/dist/server/schemas/debugger-schema.js +47 -0
  137. package/dist/server/{journey-schema.js → schemas/journey-schema.js} +8 -22
  138. package/dist/server/schemas/system-trace-schema.js +17 -0
  139. package/dist/server/tool-definitions.js +62 -1134
  140. package/dist/server-core.js +4 -4
  141. package/dist/server.js +34 -0
  142. package/dist/system/android-status.js +101 -0
  143. package/dist/system/android.js +37 -27
  144. package/dist/system/index.js +13 -438
  145. package/dist/system/ios-status.js +132 -0
  146. package/dist/system/ios.js +11 -8
  147. package/dist/system/model.js +1 -0
  148. package/dist/system/probes.js +105 -0
  149. package/dist/system/status-summary.js +43 -0
  150. package/dist/system/unsupported-status.js +52 -0
  151. package/dist/utils/android/commands.js +89 -0
  152. package/dist/utils/android/gradle.js +139 -0
  153. package/dist/utils/android/logs.js +103 -0
  154. package/dist/utils/android/ui-tree.js +233 -0
  155. package/dist/utils/android/utils.js +6 -564
  156. package/dist/utils/cli/idb/idb-helper.js +4 -6
  157. package/dist/utils/cli/idb/install-idb.js +13 -9
  158. package/dist/utils/cli/ios/preflight-ios.js +42 -38
  159. package/dist/utils/exec.js +2 -0
  160. package/dist/utils/ios/utils.js +45 -46
  161. package/dist/utils/java.js +75 -57
  162. package/dist/utils/operation-budget.js +2 -0
  163. package/dist/utils/resolve-device.js +6 -2
  164. package/dist/utils/ui/index.js +26 -26
  165. package/docs/CHANGELOG.md +48 -0
  166. package/docs/README.md +38 -0
  167. package/docs/benchmarks/README.md +18 -0
  168. package/docs/benchmarks/interaction-latency/README.md +14 -0
  169. package/docs/benchmarks/interaction-latency/final.md +4 -1
  170. package/docs/benchmarks/interaction-latency/ios-validation.md +2 -0
  171. package/docs/benchmarks/ui-tree-performance/README.md +24 -16
  172. package/docs/benchmarks/ui-tree-performance/comparison.md +11 -10
  173. package/docs/code-structure.md +118 -0
  174. package/docs/specs/001-state-verification/spec.md +16 -14
  175. package/docs/specs/002-richer-element-identity/spec.md +12 -10
  176. package/docs/specs/003-wait-and-synchronization-reliability/spec.md +12 -10
  177. package/docs/specs/004-action-verification-routing/spec.md +3 -3
  178. package/docs/specs/005-unified-action-execution-and-verification-model/spec.md +2 -0
  179. package/docs/specs/006-runtime-action-instrumentation-and-binding-layer/spec.md +2 -0
  180. package/docs/specs/007-actionability-resolution-and-executable-target-selection/spec.md +3 -1
  181. package/docs/specs/008-adjustable-control-support-and-semantic-value-manipulation/spec.md +3 -4
  182. package/docs/specs/009-semantic-control-modeling-for-custom-and-composite-controls/spec.md +2 -0
  183. package/docs/specs/010-verification-stabilization-and-temporal-convergence/spec.md +2 -2
  184. package/docs/specs/011-recovery-and-replanning-for-failed-or-ambiguous-interaction-flows/spec.md +2 -2
  185. package/docs/specs/011.1-recovery-contract-types-and-runtime-wiring-spec/spec.md +2 -0
  186. package/docs/specs/012-action-trace-and-xecution-observability/spec.md +2 -3
  187. package/docs/specs/013-wait-and-synchronization-reliability/spec.md +19 -19
  188. package/docs/specs/014-actionability-resolution/spec.md +20 -18
  189. package/docs/specs/015-adjustable-control-support/spec.md +17 -15
  190. package/docs/specs/016-environment-tools/spec.md +20 -20
  191. package/docs/specs/018-interaction-latency-and-batched-journeys/spec.md +2 -0
  192. package/docs/specs/019-ui-tree-observation-performance/spec.md +3 -1
  193. package/docs/specs/020-conditional-actions/intent.md +5 -3
  194. package/docs/specs/020-conditional-actions/plan.md +8 -9
  195. package/docs/specs/020-conditional-actions/spec.md +4 -2
  196. package/docs/specs/021-app-readiness-signals/intent.md +4 -2
  197. package/docs/specs/021-app-readiness-signals/plan.md +7 -6
  198. package/docs/specs/021-app-readiness-signals/spec.md +3 -1
  199. package/docs/specs/022-correlated-evidence/intent.md +4 -4
  200. package/docs/specs/022-correlated-evidence/plan.md +10 -11
  201. package/docs/specs/022-correlated-evidence/spec.md +3 -1
  202. package/docs/specs/023-android-system-traces/device-evidence.json +38 -0
  203. package/docs/specs/023-android-system-traces/emulator-recheck.json +38 -0
  204. package/docs/specs/023-android-system-traces/intent.md +41 -0
  205. package/docs/specs/023-android-system-traces/plan.md +115 -0
  206. package/docs/specs/023-android-system-traces/spec.md +122 -0
  207. package/docs/specs/024-android-heap-dump-capture/intent.md +41 -0
  208. package/docs/specs/025-android-runtime-debugger/intent.md +41 -0
  209. package/docs/specs/025-android-runtime-debugger/plan.md +106 -0
  210. package/docs/specs/025-android-runtime-debugger/spec.md +183 -0
  211. package/docs/specs/026-code-structure-and-quality-gates/health-plan.md +88 -0
  212. package/docs/specs/026-code-structure-and-quality-gates/intent.md +47 -0
  213. package/docs/specs/026-code-structure-and-quality-gates/plan.md +191 -0
  214. package/docs/specs/026-code-structure-and-quality-gates/spec.md +138 -0
  215. package/docs/specs/026-code-structure-and-quality-gates/verification-final.json +200 -0
  216. package/docs/specs/026-code-structure-and-quality-gates/verification-thin-facade.json +154 -0
  217. package/docs/specs/026-code-structure-and-quality-gates/verification.json +136 -0
  218. package/docs/specs/027-debugger-failure-diagnostics/intent.md +43 -0
  219. package/docs/specs/027-debugger-failure-diagnostics/plan.md +86 -0
  220. package/docs/specs/027-debugger-failure-diagnostics/spec.md +133 -0
  221. package/docs/specs/028-compact-debugger-responses/intent.md +41 -0
  222. package/docs/specs/028-compact-debugger-responses/plan.md +112 -0
  223. package/docs/specs/028-compact-debugger-responses/spec.md +108 -0
  224. package/docs/specs/029-kotlin-locals-validation/report.md +119 -0
  225. package/docs/specs/030-android-coroutine-validation/evidence.json +475 -0
  226. package/docs/specs/030-android-coroutine-validation/intent.md +47 -0
  227. package/docs/specs/030-android-coroutine-validation/plan.md +147 -0
  228. package/docs/specs/030-android-coroutine-validation/report.md +240 -0
  229. package/docs/specs/030-android-coroutine-validation/spec.md +107 -0
  230. package/docs/tools/TOOLS.md +31 -16
  231. package/docs/tools/{evidence.md → correlated-evidence.md} +14 -3
  232. package/docs/tools/debugger.md +180 -0
  233. package/docs/tools/interact.md +42 -20
  234. package/docs/tools/manage.md +25 -44
  235. package/docs/tools/observe.md +64 -25
  236. package/docs/tools/system-traces.md +134 -0
  237. package/docs/tools/system.md +12 -5
  238. package/package.json +11 -8
  239. package/scripts/architecture-graph.mjs +69 -0
  240. package/scripts/check-architecture.mjs +47 -0
  241. package/scripts/code-quality-baseline.json +1 -0
  242. package/scripts/code-quality.mjs +161 -0
  243. package/src/contracts/execution-controls.ts +26 -0
  244. package/src/contracts/selector.ts +17 -0
  245. package/src/contracts/target.ts +19 -0
  246. package/src/contracts/ui.ts +94 -0
  247. package/src/debugger/android.ts +66 -0
  248. package/src/debugger/diagnostics.ts +43 -0
  249. package/src/debugger/guard.ts +31 -0
  250. package/src/debugger/java/DebuggerWorker.java +166 -0
  251. package/src/debugger/protocol.ts +37 -0
  252. package/src/debugger/sessions.ts +327 -0
  253. package/src/debugger/worker.ts +135 -0
  254. package/src/interact/adjustment/adjustment-context.ts +83 -0
  255. package/src/interact/adjustment/adjustment-gestures.ts +48 -0
  256. package/src/interact/adjustment/adjustment-plan.ts +23 -0
  257. package/src/interact/adjustment/adjustment-resolution.ts +104 -0
  258. package/src/interact/adjustment/adjustment-result.ts +34 -0
  259. package/src/interact/adjustment/adjustment-semantic.ts +53 -0
  260. package/src/interact/adjustment/adjustment-verification.ts +60 -0
  261. package/src/interact/adjustment/adjustment.ts +49 -0
  262. package/src/interact/adjustment/control-geometry.ts +120 -0
  263. package/src/interact/adjustment/control-values.ts +141 -0
  264. package/src/interact/adjustment/slider-labels.ts +84 -0
  265. package/src/interact/assertions/screen-assertion.ts +39 -0
  266. package/src/interact/assertions/state-assertion-context.ts +48 -0
  267. package/src/interact/assertions/state-assertion.ts +64 -0
  268. package/src/interact/assertions/state-comparison.ts +168 -0
  269. package/src/interact/assertions/visibility-assertion.ts +41 -0
  270. package/src/interact/conditional-action.ts +18 -12
  271. package/src/interact/index.ts +76 -3491
  272. package/src/interact/input-service.ts +11 -0
  273. package/src/interact/interaction-trace.ts +36 -0
  274. package/src/interact/model.ts +109 -0
  275. package/src/interact/observation.ts +7 -0
  276. package/src/interact/targeting/candidate-ancestor.ts +49 -0
  277. package/src/interact/targeting/candidate-result.ts +24 -0
  278. package/src/interact/targeting/candidate-scoring.ts +42 -0
  279. package/src/interact/targeting/element-helpers.ts +243 -0
  280. package/src/interact/targeting/find-element.ts +47 -0
  281. package/src/interact/targeting/nearby-control.ts +46 -0
  282. package/src/interact/targeting/resolved-elements.ts +20 -0
  283. package/src/interact/targeting/tap-target.ts +22 -0
  284. package/src/interact/targeting/target-scope.ts +121 -0
  285. package/src/interact/waits/legacy-log-wait.ts +30 -0
  286. package/src/interact/waits/legacy-wait-observations.ts +55 -0
  287. package/src/interact/waits/legacy-wait-state.ts +48 -0
  288. package/src/interact/waits/legacy-wait.ts +34 -0
  289. package/src/interact/waits/screen-wait.ts +37 -0
  290. package/src/interact/waits/ui-change-helpers.ts +184 -0
  291. package/src/interact/waits/ui-change-state.ts +26 -0
  292. package/src/interact/waits/ui-change-wait.ts +59 -0
  293. package/src/interact/waits/ui-wait-condition.ts +52 -0
  294. package/src/interact/waits/ui-wait-state.ts +55 -0
  295. package/src/interact/waits/ui-wait.ts +84 -0
  296. package/src/manage/android.ts +56 -50
  297. package/src/manage/index.ts +63 -93
  298. package/src/manage/ios/build-types.ts +14 -0
  299. package/src/manage/ios/build.ts +230 -0
  300. package/src/manage/ios/project-discovery.ts +26 -0
  301. package/src/manage/ios/scheme.ts +16 -0
  302. package/src/manage/ios.ts +65 -298
  303. package/src/observe/android/context.ts +1 -0
  304. package/src/observe/android/current-screen.ts +63 -0
  305. package/src/observe/android/fingerprint.ts +13 -0
  306. package/src/observe/android/log-stream.ts +127 -0
  307. package/src/observe/android/logs.ts +110 -0
  308. package/src/observe/android/screenshot.ts +79 -0
  309. package/src/observe/android/ui-tree.ts +113 -0
  310. package/src/observe/android.ts +17 -531
  311. package/src/observe/evidence.ts +130 -71
  312. package/src/observe/index.ts +24 -286
  313. package/src/observe/ios/context.ts +22 -0
  314. package/src/observe/ios/fingerprint.ts +12 -0
  315. package/src/observe/ios/log-stream.ts +103 -0
  316. package/src/observe/ios/logs.ts +179 -0
  317. package/src/observe/ios/screenshot.ts +26 -0
  318. package/src/observe/ios/ui-elements.ts +266 -0
  319. package/src/observe/ios/ui-tree.ts +143 -0
  320. package/src/observe/ios.ts +18 -749
  321. package/src/observe/logs/model.ts +11 -0
  322. package/src/{network → observe/network}/index.ts +2 -2
  323. package/src/observe/readiness-service.ts +10 -3
  324. package/src/observe/readiness.ts +49 -22
  325. package/src/observe/screenshot-encoding.ts +32 -0
  326. package/src/observe/snapshot-collection.ts +69 -0
  327. package/src/observe/snapshot-logs.ts +26 -0
  328. package/src/observe/snapshot-metadata.ts +51 -31
  329. package/src/observe/snapshot-semantic.ts +153 -0
  330. package/src/observe/system-trace-android.ts +133 -0
  331. package/src/observe/system-trace.ts +227 -0
  332. package/src/runtime/action-results.ts +376 -0
  333. package/src/runtime/clock.ts +9 -0
  334. package/src/server/common.ts +9 -359
  335. package/src/server/definitions/assert.ts +164 -0
  336. package/src/server/definitions/diagnostic.ts +120 -0
  337. package/src/server/definitions/input.ts +276 -0
  338. package/src/server/definitions/manage.ts +196 -0
  339. package/src/server/definitions/observe.ts +151 -0
  340. package/src/server/definitions/target.ts +140 -0
  341. package/src/server/definitions/wait.ts +107 -0
  342. package/src/server/handlers/action-execution.ts +164 -0
  343. package/src/server/handlers/correlation.ts +20 -0
  344. package/src/server/handlers/debugger-handlers.ts +39 -0
  345. package/src/server/handlers/debugger-response.ts +7 -0
  346. package/src/server/handlers/diagnostic.ts +79 -0
  347. package/src/server/handlers/handler-types.ts +7 -0
  348. package/src/server/handlers/input.ts +173 -0
  349. package/src/server/handlers/interact.ts +135 -0
  350. package/src/server/handlers/journey-assertions.ts +39 -0
  351. package/src/server/handlers/journey.ts +132 -0
  352. package/src/server/handlers/manage.ts +141 -0
  353. package/src/server/handlers/observe.ts +116 -0
  354. package/src/server/handlers/payload.ts +36 -0
  355. package/src/server/handlers/tool-handlers.ts +159 -0
  356. package/src/server/schemas/condition-schema.ts +2 -0
  357. package/src/server/schemas/debugger-schema.ts +43 -0
  358. package/src/server/{journey-schema.ts → schemas/journey-schema.ts} +8 -22
  359. package/src/server/schemas/system-trace-schema.ts +17 -0
  360. package/src/server/tool-definitions.ts +69 -1140
  361. package/src/server-core.ts +4 -4
  362. package/src/server.ts +25 -1
  363. package/src/system/android-status.ts +124 -0
  364. package/src/system/android.ts +33 -21
  365. package/src/system/index.ts +21 -523
  366. package/src/system/ios-status.ts +147 -0
  367. package/src/system/ios.ts +14 -10
  368. package/src/system/model.ts +41 -0
  369. package/src/system/probes.ts +114 -0
  370. package/src/system/status-summary.ts +47 -0
  371. package/src/system/unsupported-status.ts +55 -0
  372. package/src/types.ts +16 -106
  373. package/src/utils/android/commands.ts +81 -0
  374. package/src/utils/android/gradle.ts +132 -0
  375. package/src/utils/android/logs.ts +103 -0
  376. package/src/utils/android/ui-tree.ts +239 -0
  377. package/src/utils/android/utils.ts +16 -556
  378. package/src/utils/cli/idb/check-idb.ts +4 -4
  379. package/src/utils/cli/idb/idb-helper.ts +6 -8
  380. package/src/utils/cli/idb/install-idb.ts +15 -9
  381. package/src/utils/cli/ios/preflight-ios.ts +39 -31
  382. package/src/utils/cli/ios/run-ios-ui-tree-tap.ts +4 -4
  383. package/src/utils/exec.ts +2 -0
  384. package/src/utils/ios/utils.ts +57 -61
  385. package/src/utils/java.ts +71 -51
  386. package/src/utils/operation-budget.ts +2 -0
  387. package/src/utils/resolve-device.ts +11 -6
  388. package/src/utils/ui/index.ts +28 -28
  389. package/test/device/automated/debugger/coroutine-lifecycle.ts +27 -0
  390. package/test/device/automated/debugger/coroutine-support.ts +140 -0
  391. package/test/device/automated/debugger/coroutine.android.test.ts +169 -0
  392. package/test/device/automated/debugger/kotlin.android.test.ts +127 -0
  393. package/test/device/automated/debugger/runtime.android.test.ts +219 -0
  394. package/test/device/automated/interact/interaction.android.test.ts +56 -0
  395. package/test/device/automated/observe/system-trace.smoke.ts +104 -0
  396. package/test/device/manual/interact/modul8_selector_tap.manual.ts +1 -1
  397. package/test/fixtures/contracts/tool-definitions.json +3536 -0
  398. package/test/fixtures/coroutine-app/MainActivity.kt +100 -0
  399. package/test/fixtures/coroutine-app/README.md +48 -0
  400. package/test/fixtures/coroutine-app/build.ts +35 -0
  401. package/test/fixtures/debugger-app/MainActivity.java +67 -0
  402. package/test/fixtures/debugger-app/MainActivity.kt +32 -0
  403. package/test/fixtures/debugger-app/NoLocals.java +7 -0
  404. package/test/fixtures/debugger-app/README.md +65 -0
  405. package/test/fixtures/debugger-app/build.ts +39 -0
  406. package/test/fixtures/latency-journey-app/README.md +2 -0
  407. package/test/fixtures/readiness-app/README.md +2 -0
  408. package/test/helpers/perfetto.ts +59 -0
  409. package/test/unit/debugger/coroutine-lifecycle.test.ts +43 -0
  410. package/test/unit/debugger/diagnostic-sessions.test.ts +67 -0
  411. package/test/unit/debugger/diagnostics.test.ts +80 -0
  412. package/test/unit/debugger/guards.test.ts +50 -0
  413. package/test/unit/debugger/native.test.ts +33 -0
  414. package/test/unit/debugger/preparation.test.ts +32 -0
  415. package/test/unit/debugger/protocol.test.ts +15 -0
  416. package/test/unit/debugger/sessions.test.ts +83 -0
  417. package/test/unit/interact/adjustment_service.test.ts +42 -0
  418. package/test/unit/interact/adjustment_verification.test.ts +35 -0
  419. package/test/unit/interact/clock_dependencies.test.ts +63 -0
  420. package/test/unit/interact/element_helpers.test.ts +19 -0
  421. package/test/unit/interact/legacy_wait_service.test.ts +17 -0
  422. package/test/unit/interact/state_comparison.test.ts +20 -0
  423. package/test/unit/interact/target_scope.test.ts +35 -0
  424. package/test/unit/network/get_network_activity.test.ts +1 -1
  425. package/test/unit/observe/readiness.test.ts +3 -1
  426. package/test/unit/observe/screenshot-encoding.test.ts +30 -0
  427. package/test/unit/observe/snapshot-logs.test.ts +14 -0
  428. package/test/unit/observe/system-trace-android.test.ts +52 -0
  429. package/test/unit/observe/system-trace.test.ts +166 -0
  430. package/test/unit/quality/architecture.test.ts +60 -0
  431. package/test/unit/quality/code-quality.test.ts +58 -0
  432. package/test/unit/quality/interaction_boundaries.test.ts +24 -0
  433. package/test/unit/server/conditional_actions.test.ts +1 -1
  434. package/test/unit/server/conditional_schema.test.ts +2 -2
  435. package/test/unit/server/debugger-response.test.ts +63 -0
  436. package/test/unit/server/system-trace.test.ts +64 -0
  437. package/test/unit/server/tool_definitions_parity.test.ts +8 -0
  438. package/dist/server/tool-handlers.js +0 -893
  439. package/docs/ROADMAP.md +0 -646
  440. package/docs/benchmarks/ui-tree-performance/bridge-probe.json +0 -29
  441. package/docs/benchmarks/ui-tree-performance/initial-baseline.json +0 -59560
  442. package/docs/specs/baseline-spec-v0.md +0 -312
  443. package/docs/specs/mcp-tooling-spec-v1.md +0 -446
  444. package/src/server/tool-handlers.ts +0 -923
  445. /package/dist/{server/condition-schema.js → contracts/condition.js} +0 -0
  446. /package/dist/server/{readiness-schema.js → schemas/readiness-schema.js} +0 -0
  447. /package/src/{server/condition-schema.ts → contracts/condition.ts} +0 -0
  448. /package/src/server/{readiness-schema.ts → schemas/readiness-schema.ts} +0 -0
@@ -22,11 +22,10 @@ async function findFirst(root, patterns, maxDepth = 4) {
22
22
  console.error('DEBUG findFirst: entries', ents.map(e => e.name));
23
23
  for (const e of ents) {
24
24
  const full = path.join(dir, e.name);
25
- for (const p of patterns) {
26
- if (e.name.endsWith(p)) {
27
- console.error('DEBUG findFirst: matched', full);
28
- return full;
29
- }
25
+ const matched = patterns.some(pattern => e.name.endsWith(pattern));
26
+ if (matched) {
27
+ console.error('DEBUG findFirst: matched', full);
28
+ return full;
30
29
  }
31
30
  if (e.isDirectory() && depth < maxDepth)
32
31
  queue.push({ dir: full, depth: depth + 1 });
@@ -52,26 +51,7 @@ function startCompanionIfNeeded(companionPath, udid) {
52
51
  }
53
52
  }
54
53
  async function main() {
55
- const args = process.argv.slice(2);
56
- let projectArg;
57
- let udid;
58
- let startCompanion = false;
59
- let kmpBuild = null;
60
- for (let i = 0; i < args.length; i++) {
61
- const a = args[i];
62
- if (a === '--project' && args[i + 1]) {
63
- projectArg = args[i + 1];
64
- i++;
65
- }
66
- else if (a === '--udid' && args[i + 1]) {
67
- udid = args[i + 1];
68
- i++;
69
- }
70
- else if (a === '--start-companion')
71
- startCompanion = true;
72
- else if (!projectArg)
73
- projectArg = a;
74
- }
54
+ const { projectArg, udid, startCompanion, kmpBuild } = argumentsForPreflight(process.argv.slice(2));
75
55
  const cwd = process.cwd();
76
56
  const projectRoot = projectArg ? path.resolve(projectArg) : cwd;
77
57
  // If user passed a direct .xcodeproj or .xcworkspace path, accept it as the projectFile
@@ -108,15 +88,8 @@ async function main() {
108
88
  // 4) idb_companion
109
89
  const companionPath = commandWhich('idb_companion');
110
90
  const companionAvailable = !!companionPath;
111
- const suggestions = [];
112
- if (!projectFile)
113
- suggestions.push('Provide correct project path or ensure .xcodeproj/.xcworkspace exists in project dir');
114
- if (!kmpFramework)
115
- suggestions.push('Run KMP Gradle task to produce Shared.framework before xcodebuild (e.g., :shared:embedAndSignAppleFrameworkForXcode)');
116
- if (!idbAvailable)
117
- suggestions.push('Ensure idb is in PATH or set MCP_IDB_PATH / IDB_PATH');
118
- if (!companionAvailable)
119
- suggestions.push('Install idb_companion and ensure it is in PATH');
91
+ const suggestions = preflightSuggestions(projectFile, kmpFramework, idbAvailable, companionAvailable);
92
+ const companionInfo = { cmd: companionPath, installed: companionAvailable };
120
93
  const result = {
121
94
  ok: !!projectFile && !!idbAvailable,
122
95
  project: {
@@ -133,10 +106,7 @@ async function main() {
133
106
  cmd: idbPath,
134
107
  installed: idbAvailable
135
108
  },
136
- idb_companion: {
137
- cmd: companionPath,
138
- installed: companionAvailable
139
- },
109
+ idb_companion: companionInfo,
140
110
  suggestions
141
111
  };
142
112
  if (startCompanion && udid) {
@@ -153,3 +123,37 @@ main().catch(e => {
153
123
  console.log(JSON.stringify({ ok: false, error: e instanceof Error ? e.message : String(e) }, null, 2));
154
124
  process.exit(2);
155
125
  });
126
+ function argumentsForPreflight(args) {
127
+ let projectArg;
128
+ let udid;
129
+ let startCompanion = false;
130
+ const kmpBuild = null;
131
+ for (let i = 0; i < args.length; i++) {
132
+ const a = args[i];
133
+ if (a === '--project' && args[i + 1]) {
134
+ projectArg = args[i + 1];
135
+ i++;
136
+ }
137
+ else if (a === '--udid' && args[i + 1]) {
138
+ udid = args[i + 1];
139
+ i++;
140
+ }
141
+ else if (a === '--start-companion')
142
+ startCompanion = true;
143
+ else if (!projectArg)
144
+ projectArg = a;
145
+ }
146
+ return { projectArg, udid, startCompanion, kmpBuild };
147
+ }
148
+ function preflightSuggestions(projectFile, kmpFramework, idbAvailable, companionAvailable) {
149
+ const suggestions = [];
150
+ if (!projectFile)
151
+ suggestions.push('Provide correct project path or ensure .xcodeproj/.xcworkspace exists in project dir');
152
+ if (!kmpFramework)
153
+ suggestions.push('Run KMP Gradle task to produce Shared.framework before xcodebuild (e.g., :shared:embedAndSignAppleFrameworkForXcode)');
154
+ if (!idbAvailable)
155
+ suggestions.push('Ensure idb is in PATH or set MCP_IDB_PATH / IDB_PATH');
156
+ if (!companionAvailable)
157
+ suggestions.push('Install idb_companion and ensure it is in PATH');
158
+ return suggestions;
159
+ }
@@ -1,9 +1,11 @@
1
+ import { checkDebuggerGuard } from '../debugger/guard.js';
1
2
  import { remainingBudget } from './operation-budget.js';
2
3
  import { spawn } from 'child_process';
3
4
  export async function execCmd(cmd, args, opts = {}) {
4
5
  const { env, cwd, shell } = opts;
5
6
  const timeout = remainingBudget(opts.timeout ?? 0);
6
7
  return new Promise((resolve, reject) => {
8
+ checkDebuggerGuard();
7
9
  const child = spawn(cmd, args, { env: { ...process.env, ...(env || {}) }, cwd, shell });
8
10
  let stdout = '';
9
11
  let stderr = '';
@@ -19,16 +19,14 @@ export function getConfiguredIdbPath() {
19
19
  if (!p)
20
20
  continue;
21
21
  try {
22
- if (fs.existsSync(p)) {
23
- const raw = fs.readFileSync(p, 'utf8');
24
- const json = JSON.parse(raw);
25
- if (json) {
26
- if (json.idbPath)
27
- return json.idbPath;
28
- if (json.IDB_PATH)
29
- return json.IDB_PATH;
30
- }
31
- }
22
+ if (!fs.existsSync(p))
23
+ continue;
24
+ const raw = fs.readFileSync(p, 'utf8');
25
+ const json = JSON.parse(raw);
26
+ if (json?.idbPath)
27
+ return json.idbPath;
28
+ if (json?.IDB_PATH)
29
+ return json.IDB_PATH;
32
30
  }
33
31
  catch { }
34
32
  }
@@ -214,18 +212,18 @@ export async function getIOSDeviceMetadata(deviceId = "booted") {
214
212
  const devicesMap = data.devices || {};
215
213
  for (const runtime in devicesMap) {
216
214
  const devices = devicesMap[runtime];
217
- if (Array.isArray(devices)) {
218
- for (const device of devices) {
219
- if (deviceId === "booted" || device.udid === deviceId) {
220
- resolve({
221
- platform: "ios",
222
- id: device.udid,
223
- osVersion: parseRuntimeName(runtime),
224
- model: device.name,
225
- simulator: true,
226
- });
227
- return;
228
- }
215
+ if (!Array.isArray(devices))
216
+ continue;
217
+ for (const device of devices) {
218
+ if (deviceId === "booted" || device.udid === deviceId) {
219
+ resolve({
220
+ platform: "ios",
221
+ id: device.udid,
222
+ osVersion: parseRuntimeName(runtime),
223
+ model: device.name,
224
+ simulator: true,
225
+ });
226
+ return;
229
227
  }
230
228
  }
231
229
  }
@@ -257,36 +255,37 @@ export async function listIOSDevices(appId) {
257
255
  const bmap = bdata.devices || {};
258
256
  for (const rt in bmap) {
259
257
  const devs = bmap[rt];
260
- if (Array.isArray(devs))
261
- for (const d of devs)
262
- bootedSet.add(d.udid);
258
+ if (!Array.isArray(devs))
259
+ continue;
260
+ for (const d of devs)
261
+ bootedSet.add(d.udid);
263
262
  }
264
263
  }
265
264
  catch { }
266
265
  }
267
266
  for (const runtime in devicesMap) {
268
267
  const devices = devicesMap[runtime];
269
- if (Array.isArray(devices)) {
270
- for (const device of devices) {
271
- const info = {
272
- platform: 'ios',
273
- id: device.udid,
274
- osVersion: parseRuntimeName(runtime),
275
- model: device.name,
276
- simulator: true,
277
- booted: bootedSet.has(device.udid)
278
- };
279
- if (appId) {
280
- // check if installed
281
- const p = execCommand(['simctl', 'get_app_container', device.udid, appId, 'data'], device.udid)
282
- .then(() => { info.appInstalled = true; })
283
- .catch(() => { info.appInstalled = false; })
284
- .then(() => { out.push(info); });
285
- checks.push(p);
286
- }
287
- else {
288
- out.push(info);
289
- }
268
+ if (!Array.isArray(devices))
269
+ continue;
270
+ for (const device of devices) {
271
+ const info = {
272
+ platform: 'ios',
273
+ id: device.udid,
274
+ osVersion: parseRuntimeName(runtime),
275
+ model: device.name,
276
+ simulator: true,
277
+ booted: bootedSet.has(device.udid)
278
+ };
279
+ if (appId) {
280
+ // check if installed
281
+ const p = execCommand(['simctl', 'get_app_container', device.udid, appId, 'data'], device.udid)
282
+ .then(() => { info.appInstalled = true; })
283
+ .catch(() => { info.appInstalled = false; })
284
+ .then(() => { out.push(info); });
285
+ checks.push(p);
286
+ }
287
+ else {
288
+ out.push(info);
290
289
  }
291
290
  }
292
291
  }
@@ -25,52 +25,36 @@ function javaVersionOf(javaBin) {
25
25
  return undefined;
26
26
  }
27
27
  }
28
- export async function detectJavaHome() {
28
+ export async function detectJavaHome(options = {}) {
29
+ const debug = (...args) => { if (!options.quiet)
30
+ console.debug(...args); };
29
31
  try {
30
32
  // 1) Honor explicit ANDROID_STUDIO_JDK env (highest priority)
31
33
  const envStudio = process.env.ANDROID_STUDIO_JDK || process.env.ANDROID_STUDIO_JBR;
32
34
  if (envStudio && existsSync(path.join(envStudio, 'bin', 'java'))) {
33
35
  const v = javaVersionOf(path.join(envStudio, 'bin', 'java'));
34
36
  if (isJavaVersionAcceptable(v)) {
35
- console.debug('[java.detect] Using ANDROID_STUDIO_JDK from env:', envStudio);
37
+ debug('[java.detect] Using ANDROID_STUDIO_JDK from env:', envStudio);
36
38
  return envStudio;
37
39
  }
38
- console.debug('[java.detect] ANDROID_STUDIO_JDK present but java -version did not match expected versions');
39
- }
40
- // 2) Android Studio JBR candidates (prefer these over JAVA_HOME)
41
- const jbrCandidates = [
42
- '/Applications/Android Studio.app/Contents/jbr',
43
- '/Applications/Android Studio.app/Contents/jbr/Contents/Home',
44
- '/Applications/Android Studio Preview.app/Contents/jbr',
45
- '/Applications/Android Studio Preview.app/Contents/jbr/Contents/Home',
46
- '/Applications/Android Studio Preview 2022.3.app/Contents/jbr',
47
- '/Applications/Android Studio Preview 2022.3.app/Contents/jbr/Contents/Home',
48
- '/Applications/Android Studio Preview 2023.1.app/Contents/jbr',
49
- '/Applications/Android Studio Preview 2023.1.app/Contents/jbr/Contents/Home'
50
- ];
51
- for (const p of jbrCandidates) {
52
- const javaBin = path.join(p, 'bin', 'java');
53
- if (existsSync(javaBin)) {
54
- const v = javaVersionOf(javaBin);
55
- if (isJavaVersionAcceptable(v)) {
56
- console.debug('[java.detect] Found Android Studio JBR at:', p);
57
- return p;
58
- }
59
- }
40
+ debug('[java.detect] ANDROID_STUDIO_JDK present but java -version did not match expected versions');
60
41
  }
42
+ const jbr = findStudioJava(debug);
43
+ if (jbr)
44
+ return jbr;
61
45
  // 3) If JAVA_HOME set, validate it (accept 17 or 21)
62
46
  if (process.env.JAVA_HOME) {
63
47
  try {
64
48
  const javaBin = path.join(process.env.JAVA_HOME, 'bin', 'java');
65
49
  const v = javaVersionOf(javaBin);
66
50
  if (isJavaVersionAcceptable(v)) {
67
- console.debug('[java.detect] Using JAVA_HOME from env:', process.env.JAVA_HOME);
51
+ debug('[java.detect] Using JAVA_HOME from env:', process.env.JAVA_HOME);
68
52
  return process.env.JAVA_HOME;
69
53
  }
70
- console.debug('[java.detect] Existing JAVA_HOME does not appear to be acceptable Java (17/21), will search');
54
+ debug('[java.detect] Existing JAVA_HOME does not appear to be acceptable Java (17/21), will search');
71
55
  }
72
56
  catch {
73
- console.debug('[java.detect] Failed to validate existing JAVA_HOME, searching for JDK');
57
+ debug('[java.detect] Failed to validate existing JAVA_HOME, searching for JDK');
74
58
  }
75
59
  }
76
60
  // 4) macOS explicit path for JDK 17
@@ -84,7 +68,7 @@ export async function detectJavaHome() {
84
68
  return out17;
85
69
  }
86
70
  catch (e) {
87
- console.debug('[java.detect] /usr/libexec/java_home -v 17 failed: ' + String(e));
71
+ debug('[java.detect] /usr/libexec/java_home -v 17 failed: ' + String(e));
88
72
  }
89
73
  try {
90
74
  const out21 = execSync('/usr/libexec/java_home -v 21', { stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
@@ -92,42 +76,76 @@ export async function detectJavaHome() {
92
76
  return out21;
93
77
  }
94
78
  catch (e) {
95
- console.debug('[java.detect] /usr/libexec/java_home -v 21 failed: ' + String(e));
79
+ debug('[java.detect] /usr/libexec/java_home -v 21 failed: ' + String(e));
96
80
  }
97
- // 6) macOS common JDK locations
98
- try {
99
- const homes = execSync('ls -1 /Library/Java/JavaVirtualMachines || true', { stdio: ['ignore', 'pipe', 'inherit'] }).toString().split(/\r?\n/).filter(Boolean);
100
- for (const h of homes) {
101
- if (h.toLowerCase().includes('17') || h.toLowerCase().includes('jdk-17') || h.toLowerCase().includes('21') || h.toLowerCase().includes('jdk-21')) {
102
- const candidate = `/Library/Java/JavaVirtualMachines/${h}/Contents/Home`;
103
- return candidate;
104
- }
81
+ const commonHome = findMacJavaHome(debug);
82
+ if (commonHome)
83
+ return commonHome;
84
+ return findLinuxJavaHome(debug);
85
+ }
86
+ catch (e) {
87
+ debug('[java.detect] error detecting java home:', e instanceof Error ? e.message : String(e));
88
+ }
89
+ return undefined;
90
+ }
91
+ function findStudioJava(debug) {
92
+ // 2) Android Studio JBR candidates (prefer these over JAVA_HOME)
93
+ const jbrCandidates = [
94
+ '/Applications/Android Studio.app/Contents/jbr',
95
+ '/Applications/Android Studio.app/Contents/jbr/Contents/Home',
96
+ '/Applications/Android Studio Preview.app/Contents/jbr',
97
+ '/Applications/Android Studio Preview.app/Contents/jbr/Contents/Home',
98
+ '/Applications/Android Studio Preview 2022.3.app/Contents/jbr',
99
+ '/Applications/Android Studio Preview 2022.3.app/Contents/jbr/Contents/Home',
100
+ '/Applications/Android Studio Preview 2023.1.app/Contents/jbr',
101
+ '/Applications/Android Studio Preview 2023.1.app/Contents/jbr/Contents/Home'
102
+ ];
103
+ for (const p of jbrCandidates) {
104
+ const javaBin = path.join(p, 'bin', 'java');
105
+ if (existsSync(javaBin)) {
106
+ const v = javaVersionOf(javaBin);
107
+ if (isJavaVersionAcceptable(v)) {
108
+ debug('[java.detect] Found Android Studio JBR at:', p);
109
+ return p;
105
110
  }
106
111
  }
107
- catch (e) {
108
- console.debug('[java.detect] listing /Library/Java/JavaVirtualMachines failed: ' + String(e));
109
- }
110
- // 7) Linux locations
111
- const linuxCandidates = [
112
- '/usr/lib/jvm/java-17-openjdk-amd64',
113
- '/usr/lib/jvm/java-17-openjdk',
114
- '/usr/lib/jvm/zulu17',
115
- '/usr/lib/jvm/temurin-17-jdk',
116
- '/usr/lib/jvm/temurin-21-jdk',
117
- '/usr/lib/jvm/java-21-openjdk-amd64'
118
- ];
119
- for (const p of linuxCandidates) {
120
- try {
121
- if (existsSync(p))
122
- return p;
123
- }
124
- catch (e) {
125
- console.debug(`[java.detect] checking linux candidate ${p} failed: ${String(e)}`);
112
+ }
113
+ return undefined;
114
+ }
115
+ function findMacJavaHome(debug) {
116
+ // 6) macOS common JDK locations
117
+ try {
118
+ const homes = execSync('ls -1 /Library/Java/JavaVirtualMachines || true', { stdio: ['ignore', 'pipe', 'inherit'] }).toString().split(/\r?\n/).filter(Boolean);
119
+ for (const h of homes) {
120
+ if (h.toLowerCase().includes('17') || h.toLowerCase().includes('jdk-17') || h.toLowerCase().includes('21') || h.toLowerCase().includes('jdk-21')) {
121
+ const candidate = `/Library/Java/JavaVirtualMachines/${h}/Contents/Home`;
122
+ return candidate;
126
123
  }
127
124
  }
128
125
  }
129
126
  catch (e) {
130
- console.debug('[java.detect] error detecting java home:', e instanceof Error ? e.message : String(e));
127
+ debug('[java.detect] listing /Library/Java/JavaVirtualMachines failed: ' + String(e));
128
+ }
129
+ return undefined;
130
+ }
131
+ function findLinuxJavaHome(debug) {
132
+ // 7) Linux locations
133
+ const linuxCandidates = [
134
+ '/usr/lib/jvm/java-17-openjdk-amd64',
135
+ '/usr/lib/jvm/java-17-openjdk',
136
+ '/usr/lib/jvm/zulu17',
137
+ '/usr/lib/jvm/temurin-17-jdk',
138
+ '/usr/lib/jvm/temurin-21-jdk',
139
+ '/usr/lib/jvm/java-21-openjdk-amd64'
140
+ ];
141
+ for (const p of linuxCandidates) {
142
+ try {
143
+ if (existsSync(p))
144
+ return p;
145
+ }
146
+ catch (e) {
147
+ debug(`[java.detect] checking linux candidate ${p} failed: ${String(e)}`);
148
+ }
131
149
  }
132
150
  return undefined;
133
151
  }
@@ -1,3 +1,4 @@
1
+ import { checkDebuggerGuard } from '../debugger/guard.js';
1
2
  import { AsyncLocalStorage } from 'node:async_hooks';
2
3
  const budgets = new AsyncLocalStorage();
3
4
  export function hasFiniteBudget() { return Number.isFinite(budgets.getStore()?.deadline); }
@@ -38,6 +39,7 @@ export async function runWithSeparateBudget(timeoutMs, operation) {
38
39
  }
39
40
  }
40
41
  export function markDispatchStarted() {
42
+ checkDebuggerGuard(true);
41
43
  remainingBudget();
42
44
  let budget = budgets.getStore();
43
45
  while (budget) {
@@ -1,3 +1,4 @@
1
+ import { checkDebuggerGuard } from '../debugger/guard.js';
1
2
  import { bindEvidenceDevice } from '../observe/evidence.js';
2
3
  import { retainConnectedDeviceSnapshots } from '../observe/snapshot-metadata.js';
3
4
  import { measure } from './timing.js';
@@ -42,6 +43,7 @@ export function withResolvedDevice(device, operation) {
42
43
  return deviceContext.run(device, operation);
43
44
  }
44
45
  export async function resolveTargetDevice(opts) {
46
+ checkDebuggerGuard();
45
47
  const device = await resolveDevice(opts);
46
48
  bindEvidenceDevice(device);
47
49
  return device;
@@ -64,6 +66,9 @@ async function resolveDevice(opts) {
64
66
  throw new Error(`Device '${deviceId}' not found for platform ${platform}`);
65
67
  return found;
66
68
  }
69
+ return selectDevice(devices, platform, appId, prefer);
70
+ }
71
+ function selectDevice(devices, platform, appId, prefer) {
67
72
  let candidates = devices.slice();
68
73
  if (prefer === "physical")
69
74
  candidates = candidates.filter(d => !d.simulator);
@@ -97,8 +102,7 @@ async function resolveDevice(opts) {
97
102
  return candidates[0];
98
103
  }
99
104
  const list = candidates.map(d => ({ id: d.id, platform: d.platform, osVersion: d.osVersion, model: d.model, simulator: d.simulator, appInstalled: d.appInstalled }));
100
- const err = new Error(`Multiple matching devices found: ${JSON.stringify(list, null, 2)}`);
101
- err.devices = list;
105
+ const err = Object.assign(new Error(`Multiple matching devices found: ${JSON.stringify(list, null, 2)}`), { devices: list });
102
106
  throw err;
103
107
  }
104
108
  throw new Error(`No devices found for platform ${platform}`);
@@ -73,36 +73,11 @@ export function computeScreenFingerprint(tree, current, platform, limit = 50) {
73
73
  }
74
74
  export async function scrollToElementShared(opts) {
75
75
  const { selector, direction = 'down', maxScrolls = 10, scrollAmount = 0.7, deviceId, fetchTree, swipe, stabilizationDelayMs = 350 } = opts;
76
- const matchElement = (el) => {
77
- if (!el)
78
- return false;
79
- if (selector.text !== undefined && selector.text !== el.text)
80
- return false;
81
- if (selector.resourceId !== undefined && selector.resourceId !== el.resourceId)
82
- return false;
83
- if (selector.contentDesc !== undefined && selector.contentDesc !== el.contentDescription)
84
- return false;
85
- if (selector.className !== undefined && selector.className !== el.type)
86
- return false;
87
- return true;
88
- };
89
- const isVisible = (el, resolution) => {
90
- if (!el)
91
- return false;
92
- if (el.visible === false)
93
- return false;
94
- if (!el.bounds || !resolution || !resolution.width || !resolution.height)
95
- return (el.visible === undefined ? true : !!el.visible);
96
- const [left, top, right, bottom] = el.bounds;
97
- const withinY = bottom > 0 && top < resolution.height;
98
- const withinX = right > 0 && left < resolution.width;
99
- return withinX && withinY;
100
- };
101
76
  const findVisibleMatch = (elements, resolution) => {
102
77
  if (!Array.isArray(elements))
103
78
  return null;
104
79
  for (const e of elements) {
105
- if (matchElement(e) && isVisible(e, resolution))
80
+ if (matchElement(selector, e) && isVisible(e, resolution))
106
81
  return e;
107
82
  }
108
83
  return null;
@@ -169,3 +144,28 @@ export async function scrollToElementShared(opts) {
169
144
  }
170
145
  return { success: false, reason: 'Element not found after scrolling', scrollsPerformed: scrollsPerformed };
171
146
  }
147
+ function matchElement(selector, el) {
148
+ if (!el)
149
+ return false;
150
+ if (selector.text !== undefined && selector.text !== el.text)
151
+ return false;
152
+ if (selector.resourceId !== undefined && selector.resourceId !== el.resourceId)
153
+ return false;
154
+ if (selector.contentDesc !== undefined && selector.contentDesc !== el.contentDescription)
155
+ return false;
156
+ if (selector.className !== undefined && selector.className !== el.type)
157
+ return false;
158
+ return true;
159
+ }
160
+ function isVisible(el, resolution) {
161
+ if (!el)
162
+ return false;
163
+ if (el.visible === false)
164
+ return false;
165
+ if (!el.bounds || !resolution || !resolution.width || !resolution.height)
166
+ return (el.visible === undefined ? true : !!el.visible);
167
+ const [left, top, right, bottom] = el.bounds;
168
+ const withinY = bottom > 0 && top < resolution.height;
169
+ const withinX = right > 0 && left < resolution.width;
170
+ return withinX && withinY;
171
+ }
package/docs/CHANGELOG.md CHANGED
@@ -1,8 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ [Documentation](README.md)
4
+
5
+ Entries describe their release at the time it was recorded. Historical source
6
+ paths and commands may have moved; use the [contribution guide](../CONTRIBUTING.md)
7
+ and [tool reference](tools/TOOLS.md) for the current checkout.
8
+
3
9
  All notable changes to the **Mobile Debug MCP** project will be documented in this file.
4
10
 
5
11
  ## Unreleased
12
+
13
+ ## [0.35.0]
14
+
15
+ - Updated the agent plugin to `0.0.4`, pinned to MCP `0.35.0`.
16
+
17
+ - Added an opt-in isolated Android coroutine debugger assessment fixture for
18
+ suspension, dispatcher changes, nested work, stepping and cancellation, with
19
+ explicit local dependencies. This does not add coroutine reconstruction.
20
+ - Added an opt-in isolated Kotlin debugger validation journey for named locals
21
+ before/after assignment, compiler scope tables, stale references and app recovery.
22
+ This adds evidence and regression coverage without changing debugger behaviour.
23
+ - Added opt-in debugger `responseMode: "compact"` to omit repeated target metadata
24
+ from routine commands while retaining diagnostics, execution state and cleanup.
25
+ Existing full responses remain the default; discovery and state stay complete.
26
+ - Android debugger failures now include bounded, sanitized stage/reason diagnostics
27
+ and static recovery guidance while preserving error codes. Capability probes
28
+ report ordered prerequisite diagnostics; terminal summaries retain failure evidence.
29
+ Raw stderr, exception messages and app locals are excluded from diagnostics.
30
+
31
+ - **Runtime requirement:** Node.js 22 or newer is now required. Updated Sharp,
32
+ Zod and transitive dependencies to clear the dependency audit findings; CI
33
+ configuration now uses Node 22. Public tool definitions remain unchanged.
34
+ - Split observation, snapshot, iOS build, Android utility and system diagnostic
35
+ responsibilities into typed services. Removed all 136 legacy quality exceptions;
36
+ production source meets the default size, complexity, nesting and explicit-any
37
+ limits. Added screenshot encoding and snapshot log normalization regressions.
38
+
39
+ - Split server handlers by capability, share target/execution-control contracts, and inject clocks into interaction polling services while preserving tool contracts. Added deterministic timing tests and an Android labelled-slider convergence journey.
40
+
41
+ - Added ArchUnitTS architecture checks to lint and CI for shared contracts, server boundaries, pure interaction calculations and runtime dependency cycles. Negative controls cover NodeNext resolution, aliases, dynamic imports and re-exports.
42
+
43
+ - Group interaction services by adjustment, targeting, waits and assertions; separate server schemas and handlers, and place log-derived network observations under `observe/network`. Tool contracts and behaviour are unchanged.
44
+
45
+ - Reduced `ToolsInteract` to a typed composition facade within the enforced class budget. Extracted adjustment, candidate resolution, synchronization and assertion services without new legacy exceptions, and added an isolated Android interaction journey plus a permanent default-budget regression check.
46
+
47
+ - Added code-quality gates to lint and CI for source/class/function size, complexity, nesting, explicit `any`, and interaction/runtime import boundaries. Legacy exceptions have per-symbol ceilings that cannot grow unnoticed.
48
+ - Extracted typed UI/control helpers, bounded handle storage, action-result construction and capability-specific tool definitions; clarified and typed debugger session operations and worker protocol messages while retaining public tool contracts.
49
+ - Fixed the debugger device check to fingerprint Java sources in `src/debugger/java/` after the worker relocation.
50
+
51
+ ## [0.34.0]
52
+ - Added optional Android JDI runtime debugging: explicit device/process attach, source breakpoints/events, bounded stacks and shallow locals, stepping/resume, stale-reference rejection, pause-aware UI guards/readiness, expiry and owned detach/cleanup. Requires a host JDK 17+ and a running debuggable app; evaluation, mutation, native/coroutine and iOS debugging remain unsupported.
53
+ - Added optional bounded Android Perfetto capture with capability/start/status/stop/cancel tools, explicit journey trace linkage, local artifacts, process-ownership checks and retryable cleanup. iOS tracing and automatic trace analysis remain unsupported.
6
54
  - Made readiness unit-test polling time deterministic while retaining exact sample-count and timeout assertions, eliminating host timer-rounding flakes.
7
55
  - Isolated snapshot unit tests from physical device discovery and native handlers so they run without connected devices. Readiness deadline expiry now retains the last valid observation instead of intermittently resetting loading to unknown.
8
56
 
package/docs/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Documentation
2
+
3
+ Mobile Debug MCP provides tools for building, controlling, and inspecting Android
4
+ and iOS apps. Start with the [project README](../README.md) for requirements,
5
+ installation, and client configuration.
6
+
7
+ ## Choose a starting point
8
+
9
+ - **New to the server?** See the [project overview and installation options](../README.md#start-here).
10
+ - **Looking up a tool?** Use the [tool reference](tools/TOOLS.md) for inputs,
11
+ responses, examples, and shared interaction principles.
12
+ - **Troubleshooting setup?** Check [environment diagnostics](tools/system.md) and
13
+ the [tool path settings](../README.md#environment-setup).
14
+ - **Investigating an app failure?** Start with [observations](tools/observe.md)
15
+ and [evidence correlation](tools/correlated-evidence.md). For deeper Android
16
+ investigation, use [system traces](tools/system-traces.md) or the
17
+ [runtime debugger](tools/debugger.md).
18
+ - **Installing a client plugin?** See [client installation](../README.md#agent-plugin)
19
+ and the [plugin guide](../agent-plugin/README.md) for packaging and versioning.
20
+
21
+ ## Contributing
22
+
23
+ - [Contribution guide](../CONTRIBUTING.md): local setup, validation, and documentation conventions.
24
+ - [Code structure and quality checks](code-structure.md): module ownership, enforced limits, and existing debt.
25
+ - [Development process](specs/process.md): maintenance and feature workflows.
26
+ - [Agent entrypoint](../AGENTS.md) and [repository skills](../.agents/skills/README.md).
27
+
28
+ ## Design and evidence
29
+
30
+ - [Design records](specs/): feature intent, specifications, and dated verification
31
+ records, grouped by feature.
32
+ - [Changelog](CHANGELOG.md): release history.
33
+ - [Benchmark index](benchmarks/README.md): reproducible performance checks and recorded limits.
34
+
35
+ The tool reference describes the current checkout. Specifications record design
36
+ intent and may contain earlier contracts; approval alone does not establish that
37
+ a feature shipped. Verification records describe the named build and environment,
38
+ not every supported platform or the currently published npm package.
@@ -0,0 +1,18 @@
1
+ # Benchmarks
2
+
3
+ [Documentation](../README.md)
4
+
5
+ Use these guides to run a benchmark or inspect its recorded results. Each
6
+ benchmark has one directory containing its instructions, report, and supporting
7
+ data. Generated filenames are retained so the harness can update them directly.
8
+
9
+ These reports describe particular builds and devices. Passing a smoke check does
10
+ not establish a performance improvement, and Android timings do not establish
11
+ iOS latency.
12
+
13
+ | Benchmark | Protocol | Recorded results | Design |
14
+ | --- | --- | --- | --- |
15
+ | Interaction latency | [Run the benchmark](interaction-latency/README.md) | [Android measurements](interaction-latency/final.md), [iOS interaction validation](interaction-latency/ios-validation.md) | [018](../specs/018-interaction-latency-and-batched-journeys/spec.md) |
16
+ | UI-tree observation | [Run the paired benchmark](ui-tree-performance/README.md) | [Comparison and limitations](ui-tree-performance/comparison.md) | [019](../specs/019-ui-tree-observation-performance/spec.md) |
17
+
18
+ Fixture instructions: [latency journey app](../../test/fixtures/latency-journey-app/README.md).