mobile-debug-mcp 0.34.0 → 0.36.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 (500) 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/.cursor-plugin/marketplace.json +1 -1
  11. package/.github/copilot-instructions.md +14 -36
  12. package/.github/workflows/ci.yml +4 -4
  13. package/AGENTS.md +12 -3
  14. package/CONTRIBUTING.md +79 -0
  15. package/README.md +218 -129
  16. package/agent-plugin/.antigravity-plugin/README.md +48 -0
  17. package/agent-plugin/.antigravity-plugin/plugin.json +18 -0
  18. package/agent-plugin/.claude-plugin/plugin.json +2 -2
  19. package/agent-plugin/.codex-plugin/plugin.json +1 -1
  20. package/agent-plugin/.cursor-plugin/plugin.json +2 -2
  21. package/agent-plugin/.mcp.json +1 -1
  22. package/agent-plugin/README.md +50 -11
  23. package/agent-plugin/cursor/.cursor-plugin/plugin.json +23 -0
  24. package/agent-plugin/cursor/LICENSE +201 -0
  25. package/agent-plugin/cursor/README.md +9 -0
  26. package/agent-plugin/cursor/skills/mobile-debug-mcp/SKILL.md +253 -0
  27. package/agent-plugin/mcp.json +1 -1
  28. package/agent-plugin/mcp_config.json +13 -0
  29. package/agent-plugin/plugin.json +1 -1
  30. package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +62 -17
  31. package/dist/contracts/execution-controls.js +24 -0
  32. package/dist/contracts/selector.js +8 -0
  33. package/dist/contracts/target.js +15 -0
  34. package/dist/contracts/ui.js +1 -0
  35. package/dist/debugger/android.js +2 -1
  36. package/dist/debugger/diagnostics.js +54 -0
  37. package/dist/debugger/guard.js +4 -4
  38. package/dist/debugger/ios-worker.js +62 -0
  39. package/dist/debugger/ios.js +57 -0
  40. package/dist/debugger/protocol.js +33 -0
  41. package/dist/debugger/sessions.js +133 -74
  42. package/dist/debugger/worker.js +59 -46
  43. package/dist/interact/adjustment/adjustment-context.js +41 -0
  44. package/dist/interact/adjustment/adjustment-gestures.js +55 -0
  45. package/dist/interact/adjustment/adjustment-plan.js +18 -0
  46. package/dist/interact/adjustment/adjustment-resolution.js +127 -0
  47. package/dist/interact/adjustment/adjustment-result.js +19 -0
  48. package/dist/interact/adjustment/adjustment-semantic.js +64 -0
  49. package/dist/interact/adjustment/adjustment-verification.js +35 -0
  50. package/dist/interact/adjustment/adjustment.js +52 -0
  51. package/dist/interact/adjustment/control-geometry.js +87 -0
  52. package/dist/interact/adjustment/control-values.js +136 -0
  53. package/dist/interact/adjustment/slider-labels.js +84 -0
  54. package/dist/interact/assertions/screen-assertion.js +37 -0
  55. package/dist/interact/assertions/state-assertion-context.js +35 -0
  56. package/dist/interact/assertions/state-assertion.js +76 -0
  57. package/dist/interact/assertions/state-comparison.js +141 -0
  58. package/dist/interact/assertions/visibility-assertion.js +34 -0
  59. package/dist/interact/conditional-action.js +12 -7
  60. package/dist/interact/index.js +77 -3092
  61. package/dist/interact/input-service.js +1 -0
  62. package/dist/interact/interaction-trace.js +21 -0
  63. package/dist/interact/model.js +1 -0
  64. package/dist/interact/observation.js +1 -0
  65. package/dist/interact/targeting/candidate-ancestor.js +58 -0
  66. package/dist/interact/targeting/candidate-result.js +23 -0
  67. package/dist/interact/targeting/candidate-scoring.js +50 -0
  68. package/dist/interact/targeting/element-helpers.js +216 -0
  69. package/dist/interact/targeting/find-element.js +65 -0
  70. package/dist/interact/targeting/nearby-control.js +56 -0
  71. package/dist/interact/targeting/resolved-elements.js +21 -0
  72. package/dist/interact/targeting/tap-target.js +17 -0
  73. package/dist/interact/targeting/target-scope.js +104 -0
  74. package/dist/interact/waits/legacy-log-wait.js +38 -0
  75. package/dist/interact/waits/legacy-wait-observations.js +103 -0
  76. package/dist/interact/waits/legacy-wait-state.js +34 -0
  77. package/dist/interact/waits/legacy-wait.js +48 -0
  78. package/dist/interact/waits/screen-wait.js +49 -0
  79. package/dist/interact/waits/ui-change-helpers.js +157 -0
  80. package/dist/interact/waits/ui-change-state.js +18 -0
  81. package/dist/interact/waits/ui-change-wait.js +77 -0
  82. package/dist/interact/waits/ui-wait-condition.js +56 -0
  83. package/dist/interact/waits/ui-wait-state.js +38 -0
  84. package/dist/interact/waits/ui-wait.js +106 -0
  85. package/dist/manage/android.js +55 -51
  86. package/dist/manage/index.js +38 -75
  87. package/dist/manage/ios/build-types.js +1 -0
  88. package/dist/manage/ios/build.js +210 -0
  89. package/dist/manage/ios/project-discovery.js +29 -0
  90. package/dist/manage/ios/scheme.js +18 -0
  91. package/dist/manage/ios.js +44 -256
  92. package/dist/observe/android/context.js +1 -0
  93. package/dist/observe/android/current-screen.js +55 -0
  94. package/dist/observe/android/fingerprint.js +13 -0
  95. package/dist/observe/android/log-stream.js +132 -0
  96. package/dist/observe/android/logs.js +107 -0
  97. package/dist/observe/android/screenshot.js +70 -0
  98. package/dist/observe/android/ui-tree.js +107 -0
  99. package/dist/observe/android.js +16 -520
  100. package/dist/observe/evidence.js +114 -75
  101. package/dist/observe/index.js +16 -263
  102. package/dist/observe/ios/context.js +16 -0
  103. package/dist/observe/ios/fingerprint.js +12 -0
  104. package/dist/observe/ios/log-stream.js +105 -0
  105. package/dist/observe/ios/logs.js +168 -0
  106. package/dist/observe/ios/screenshot.js +22 -0
  107. package/dist/observe/ios/ui-elements.js +241 -0
  108. package/dist/observe/ios/ui-tree.js +137 -0
  109. package/dist/observe/ios-trace/artifact.js +63 -0
  110. package/dist/observe/ios-trace/capabilities.js +86 -0
  111. package/dist/observe/ios-trace/native.js +93 -0
  112. package/dist/observe/ios-trace/notification.js +35 -0
  113. package/dist/observe/ios-trace/process.js +98 -0
  114. package/dist/observe/ios-trace/sessions.js +244 -0
  115. package/dist/observe/ios.js +17 -715
  116. package/dist/observe/logs/model.js +1 -0
  117. package/dist/{network → observe/network}/index.js +2 -2
  118. package/dist/observe/readiness-service.js +5 -3
  119. package/dist/observe/readiness.js +33 -14
  120. package/dist/observe/screenshot-encoding.js +41 -0
  121. package/dist/observe/snapshot-collection.js +79 -0
  122. package/dist/observe/snapshot-logs.js +30 -0
  123. package/dist/observe/snapshot-metadata.js +43 -31
  124. package/dist/observe/snapshot-semantic.js +115 -0
  125. package/dist/observe/system-trace-error.js +7 -0
  126. package/dist/observe/system-trace-router.js +81 -0
  127. package/dist/observe/system-trace.js +26 -21
  128. package/dist/runtime/action-results.js +270 -0
  129. package/dist/runtime/clock.js +4 -0
  130. package/dist/server/common.js +1 -256
  131. package/dist/server/definitions/assert.js +162 -0
  132. package/dist/server/definitions/diagnostic.js +118 -0
  133. package/dist/server/definitions/input.js +274 -0
  134. package/dist/server/definitions/manage.js +194 -0
  135. package/dist/server/definitions/observe.js +149 -0
  136. package/dist/server/definitions/target.js +138 -0
  137. package/dist/server/definitions/wait.js +105 -0
  138. package/dist/server/handlers/action-execution.js +163 -0
  139. package/dist/server/handlers/correlation.js +23 -0
  140. package/dist/server/handlers/debugger-handlers.js +67 -0
  141. package/dist/server/handlers/debugger-response.js +9 -0
  142. package/dist/server/handlers/diagnostic.js +77 -0
  143. package/dist/server/handlers/handler-types.js +1 -0
  144. package/dist/server/handlers/input.js +154 -0
  145. package/dist/server/handlers/interact.js +113 -0
  146. package/dist/server/handlers/journey-assertions.js +35 -0
  147. package/dist/server/handlers/journey.js +147 -0
  148. package/dist/server/handlers/manage.js +119 -0
  149. package/dist/server/handlers/observe.js +95 -0
  150. package/dist/server/handlers/payload.js +4 -0
  151. package/dist/server/handlers/tool-handlers.js +170 -0
  152. package/dist/server/schemas/condition-schema.js +2 -0
  153. package/dist/server/{debugger-schema.js → schemas/debugger-schema.js} +20 -12
  154. package/dist/server/{journey-schema.js → schemas/journey-schema.js} +7 -22
  155. package/dist/server/schemas/system-trace-schema.js +22 -0
  156. package/dist/server/tool-definitions.js +58 -1135
  157. package/dist/server-core.js +2 -2
  158. package/dist/server.js +4 -4
  159. package/dist/system/android-status.js +101 -0
  160. package/dist/system/android.js +37 -27
  161. package/dist/system/index.js +13 -439
  162. package/dist/system/ios-status.js +132 -0
  163. package/dist/system/ios.js +11 -8
  164. package/dist/system/model.js +1 -0
  165. package/dist/system/probes.js +105 -0
  166. package/dist/system/status-summary.js +43 -0
  167. package/dist/system/unsupported-status.js +52 -0
  168. package/dist/utils/android/commands.js +89 -0
  169. package/dist/utils/android/gradle.js +139 -0
  170. package/dist/utils/android/logs.js +103 -0
  171. package/dist/utils/android/ui-tree.js +233 -0
  172. package/dist/utils/android/utils.js +6 -564
  173. package/dist/utils/cli/idb/idb-helper.js +4 -6
  174. package/dist/utils/cli/idb/install-idb.js +13 -9
  175. package/dist/utils/cli/ios/preflight-ios.js +42 -38
  176. package/dist/utils/ios/utils.js +48 -46
  177. package/dist/utils/java.js +65 -49
  178. package/dist/utils/resolve-device.js +4 -2
  179. package/dist/utils/ui/index.js +26 -26
  180. package/docs/CHANGELOG.md +67 -1
  181. package/docs/README.md +38 -0
  182. package/docs/agent-plugin-installation-verification.md +39 -0
  183. package/docs/benchmarks/README.md +18 -0
  184. package/docs/benchmarks/interaction-latency/README.md +14 -0
  185. package/docs/benchmarks/interaction-latency/final.md +4 -1
  186. package/docs/benchmarks/interaction-latency/ios-validation.md +2 -0
  187. package/docs/benchmarks/ui-tree-performance/README.md +24 -16
  188. package/docs/benchmarks/ui-tree-performance/comparison.md +11 -10
  189. package/docs/code-structure.md +120 -0
  190. package/docs/specs/001-state-verification/spec.md +16 -14
  191. package/docs/specs/002-richer-element-identity/spec.md +12 -10
  192. package/docs/specs/003-wait-and-synchronization-reliability/spec.md +12 -10
  193. package/docs/specs/004-action-verification-routing/spec.md +3 -3
  194. package/docs/specs/005-unified-action-execution-and-verification-model/spec.md +2 -0
  195. package/docs/specs/006-runtime-action-instrumentation-and-binding-layer/spec.md +2 -0
  196. package/docs/specs/007-actionability-resolution-and-executable-target-selection/spec.md +3 -1
  197. package/docs/specs/008-adjustable-control-support-and-semantic-value-manipulation/spec.md +3 -4
  198. package/docs/specs/009-semantic-control-modeling-for-custom-and-composite-controls/spec.md +2 -0
  199. package/docs/specs/010-verification-stabilization-and-temporal-convergence/spec.md +2 -2
  200. package/docs/specs/011-recovery-and-replanning-for-failed-or-ambiguous-interaction-flows/spec.md +2 -2
  201. package/docs/specs/011.1-recovery-contract-types-and-runtime-wiring-spec/spec.md +2 -0
  202. package/docs/specs/012-action-trace-and-xecution-observability/spec.md +2 -3
  203. package/docs/specs/013-wait-and-synchronization-reliability/spec.md +19 -19
  204. package/docs/specs/014-actionability-resolution/spec.md +20 -18
  205. package/docs/specs/015-adjustable-control-support/spec.md +17 -15
  206. package/docs/specs/016-environment-tools/spec.md +20 -20
  207. package/docs/specs/018-interaction-latency-and-batched-journeys/spec.md +2 -0
  208. package/docs/specs/019-ui-tree-observation-performance/spec.md +3 -1
  209. package/docs/specs/020-conditional-actions/intent.md +5 -3
  210. package/docs/specs/020-conditional-actions/plan.md +8 -9
  211. package/docs/specs/020-conditional-actions/spec.md +4 -2
  212. package/docs/specs/021-app-readiness-signals/intent.md +4 -2
  213. package/docs/specs/021-app-readiness-signals/plan.md +7 -6
  214. package/docs/specs/021-app-readiness-signals/spec.md +3 -1
  215. package/docs/specs/022-correlated-evidence/intent.md +4 -4
  216. package/docs/specs/022-correlated-evidence/plan.md +10 -11
  217. package/docs/specs/022-correlated-evidence/spec.md +3 -1
  218. package/docs/specs/023-android-system-traces/intent.md +3 -2
  219. package/docs/specs/023-android-system-traces/plan.md +5 -7
  220. package/docs/specs/023-android-system-traces/spec.md +3 -1
  221. package/docs/specs/024-android-heap-dump-capture/intent.md +3 -1
  222. package/docs/specs/025-android-runtime-debugger/intent.md +4 -3
  223. package/docs/specs/025-android-runtime-debugger/plan.md +3 -1
  224. package/docs/specs/025-android-runtime-debugger/spec.md +4 -3
  225. package/docs/specs/026-code-structure-and-quality-gates/health-plan.md +88 -0
  226. package/docs/specs/026-code-structure-and-quality-gates/intent.md +47 -0
  227. package/docs/specs/026-code-structure-and-quality-gates/plan.md +191 -0
  228. package/docs/specs/026-code-structure-and-quality-gates/spec.md +138 -0
  229. package/docs/specs/026-code-structure-and-quality-gates/verification-final.json +200 -0
  230. package/docs/specs/026-code-structure-and-quality-gates/verification-thin-facade.json +154 -0
  231. package/docs/specs/026-code-structure-and-quality-gates/verification.json +136 -0
  232. package/docs/specs/027-debugger-failure-diagnostics/intent.md +43 -0
  233. package/docs/specs/027-debugger-failure-diagnostics/plan.md +86 -0
  234. package/docs/specs/027-debugger-failure-diagnostics/spec.md +133 -0
  235. package/docs/specs/028-compact-debugger-responses/intent.md +41 -0
  236. package/docs/specs/028-compact-debugger-responses/plan.md +112 -0
  237. package/docs/specs/028-compact-debugger-responses/spec.md +108 -0
  238. package/docs/specs/029-kotlin-locals-validation/report.md +119 -0
  239. package/docs/specs/030-android-coroutine-validation/evidence.json +475 -0
  240. package/docs/specs/030-android-coroutine-validation/intent.md +47 -0
  241. package/docs/specs/030-android-coroutine-validation/plan.md +147 -0
  242. package/docs/specs/030-android-coroutine-validation/report.md +240 -0
  243. package/docs/specs/030-android-coroutine-validation/spec.md +107 -0
  244. package/docs/specs/031-ios-system-traces/intent.md +38 -0
  245. package/docs/specs/031-ios-system-traces/investigation.md +92 -0
  246. package/docs/specs/031-ios-system-traces/late-run-failure-evidence.json +32 -0
  247. package/docs/specs/031-ios-system-traces/plan.md +138 -0
  248. package/docs/specs/031-ios-system-traces/pr102-monitor-evidence.json +22 -0
  249. package/docs/specs/031-ios-system-traces/simulator-evidence.json +47 -0
  250. package/docs/specs/031-ios-system-traces/spec.md +135 -0
  251. package/docs/specs/032-ios-runtime-debugger/evidence.json +176 -0
  252. package/docs/specs/032-ios-runtime-debugger/intent.md +38 -0
  253. package/docs/specs/032-ios-runtime-debugger/plan.md +95 -0
  254. package/docs/specs/032-ios-runtime-debugger/report.md +205 -0
  255. package/docs/specs/032-ios-runtime-debugger/spec.md +153 -0
  256. package/docs/tools/TOOLS.md +31 -18
  257. package/docs/tools/{evidence.md → correlated-evidence.md} +9 -1
  258. package/docs/tools/debugger.md +120 -4
  259. package/docs/tools/interact.md +42 -20
  260. package/docs/tools/manage.md +25 -44
  261. package/docs/tools/observe.md +55 -23
  262. package/docs/tools/system-traces.md +89 -14
  263. package/docs/tools/system.md +12 -5
  264. package/package.json +12 -8
  265. package/scripts/agent-plugin.mjs +55 -5
  266. package/scripts/architecture-graph.mjs +69 -0
  267. package/scripts/check-architecture.mjs +47 -0
  268. package/scripts/code-quality-baseline.json +1 -0
  269. package/scripts/code-quality.mjs +161 -0
  270. package/src/contracts/execution-controls.ts +26 -0
  271. package/src/contracts/selector.ts +17 -0
  272. package/src/contracts/target.ts +19 -0
  273. package/src/contracts/ui.ts +94 -0
  274. package/src/debugger/android.ts +3 -2
  275. package/src/debugger/diagnostics.ts +43 -0
  276. package/src/debugger/guard.ts +10 -5
  277. package/src/debugger/ios-worker.ts +49 -0
  278. package/src/debugger/ios.ts +45 -0
  279. package/{worker → src/debugger/java}/DebuggerWorker.java +9 -3
  280. package/src/debugger/lldb/breakpoints.py +51 -0
  281. package/src/debugger/lldb/inspection.py +109 -0
  282. package/src/debugger/lldb/worker.py +203 -0
  283. package/src/debugger/protocol.ts +37 -0
  284. package/src/debugger/sessions.ts +326 -155
  285. package/src/debugger/worker.ts +57 -41
  286. package/src/interact/adjustment/adjustment-context.ts +83 -0
  287. package/src/interact/adjustment/adjustment-gestures.ts +48 -0
  288. package/src/interact/adjustment/adjustment-plan.ts +23 -0
  289. package/src/interact/adjustment/adjustment-resolution.ts +104 -0
  290. package/src/interact/adjustment/adjustment-result.ts +34 -0
  291. package/src/interact/adjustment/adjustment-semantic.ts +53 -0
  292. package/src/interact/adjustment/adjustment-verification.ts +60 -0
  293. package/src/interact/adjustment/adjustment.ts +49 -0
  294. package/src/interact/adjustment/control-geometry.ts +120 -0
  295. package/src/interact/adjustment/control-values.ts +141 -0
  296. package/src/interact/adjustment/slider-labels.ts +84 -0
  297. package/src/interact/assertions/screen-assertion.ts +39 -0
  298. package/src/interact/assertions/state-assertion-context.ts +48 -0
  299. package/src/interact/assertions/state-assertion.ts +64 -0
  300. package/src/interact/assertions/state-comparison.ts +168 -0
  301. package/src/interact/assertions/visibility-assertion.ts +41 -0
  302. package/src/interact/conditional-action.ts +18 -12
  303. package/src/interact/index.ts +89 -3494
  304. package/src/interact/input-service.ts +11 -0
  305. package/src/interact/interaction-trace.ts +36 -0
  306. package/src/interact/model.ts +109 -0
  307. package/src/interact/observation.ts +7 -0
  308. package/src/interact/targeting/candidate-ancestor.ts +49 -0
  309. package/src/interact/targeting/candidate-result.ts +24 -0
  310. package/src/interact/targeting/candidate-scoring.ts +42 -0
  311. package/src/interact/targeting/element-helpers.ts +243 -0
  312. package/src/interact/targeting/find-element.ts +47 -0
  313. package/src/interact/targeting/nearby-control.ts +46 -0
  314. package/src/interact/targeting/resolved-elements.ts +20 -0
  315. package/src/interact/targeting/tap-target.ts +22 -0
  316. package/src/interact/targeting/target-scope.ts +121 -0
  317. package/src/interact/waits/legacy-log-wait.ts +30 -0
  318. package/src/interact/waits/legacy-wait-observations.ts +55 -0
  319. package/src/interact/waits/legacy-wait-state.ts +48 -0
  320. package/src/interact/waits/legacy-wait.ts +34 -0
  321. package/src/interact/waits/screen-wait.ts +37 -0
  322. package/src/interact/waits/ui-change-helpers.ts +184 -0
  323. package/src/interact/waits/ui-change-state.ts +26 -0
  324. package/src/interact/waits/ui-change-wait.ts +59 -0
  325. package/src/interact/waits/ui-wait-condition.ts +52 -0
  326. package/src/interact/waits/ui-wait-state.ts +55 -0
  327. package/src/interact/waits/ui-wait.ts +84 -0
  328. package/src/manage/android.ts +56 -50
  329. package/src/manage/index.ts +63 -93
  330. package/src/manage/ios/build-types.ts +14 -0
  331. package/src/manage/ios/build.ts +230 -0
  332. package/src/manage/ios/project-discovery.ts +26 -0
  333. package/src/manage/ios/scheme.ts +16 -0
  334. package/src/manage/ios.ts +67 -298
  335. package/src/observe/android/context.ts +1 -0
  336. package/src/observe/android/current-screen.ts +63 -0
  337. package/src/observe/android/fingerprint.ts +13 -0
  338. package/src/observe/android/log-stream.ts +127 -0
  339. package/src/observe/android/logs.ts +110 -0
  340. package/src/observe/android/screenshot.ts +79 -0
  341. package/src/observe/android/ui-tree.ts +113 -0
  342. package/src/observe/android.ts +17 -531
  343. package/src/observe/evidence.ts +122 -70
  344. package/src/observe/index.ts +24 -286
  345. package/src/observe/ios/context.ts +22 -0
  346. package/src/observe/ios/fingerprint.ts +12 -0
  347. package/src/observe/ios/log-stream.ts +103 -0
  348. package/src/observe/ios/logs.ts +179 -0
  349. package/src/observe/ios/screenshot.ts +26 -0
  350. package/src/observe/ios/ui-elements.ts +266 -0
  351. package/src/observe/ios/ui-tree.ts +143 -0
  352. package/src/observe/ios-trace/artifact.ts +55 -0
  353. package/src/observe/ios-trace/capabilities.ts +74 -0
  354. package/src/observe/ios-trace/native.ts +72 -0
  355. package/src/observe/ios-trace/notification.ts +30 -0
  356. package/src/observe/ios-trace/process.ts +82 -0
  357. package/src/observe/ios-trace/sessions.ts +204 -0
  358. package/src/observe/ios.ts +18 -749
  359. package/src/observe/logs/model.ts +11 -0
  360. package/src/{network → observe/network}/index.ts +2 -2
  361. package/src/observe/readiness-service.ts +6 -4
  362. package/src/observe/readiness.ts +42 -21
  363. package/src/observe/screenshot-encoding.ts +32 -0
  364. package/src/observe/snapshot-collection.ts +69 -0
  365. package/src/observe/snapshot-logs.ts +26 -0
  366. package/src/observe/snapshot-metadata.ts +51 -31
  367. package/src/observe/snapshot-semantic.ts +153 -0
  368. package/src/observe/system-trace-error.ts +3 -0
  369. package/src/observe/system-trace-router.ts +61 -0
  370. package/src/observe/system-trace.ts +28 -19
  371. package/src/runtime/action-results.ts +376 -0
  372. package/src/runtime/clock.ts +9 -0
  373. package/src/server/common.ts +9 -359
  374. package/src/server/definitions/assert.ts +164 -0
  375. package/src/server/definitions/diagnostic.ts +120 -0
  376. package/src/server/definitions/input.ts +276 -0
  377. package/src/server/definitions/manage.ts +196 -0
  378. package/src/server/definitions/observe.ts +151 -0
  379. package/src/server/definitions/target.ts +140 -0
  380. package/src/server/definitions/wait.ts +107 -0
  381. package/src/server/handlers/action-execution.ts +164 -0
  382. package/src/server/handlers/correlation.ts +20 -0
  383. package/src/server/handlers/debugger-handlers.ts +58 -0
  384. package/src/server/handlers/debugger-response.ts +7 -0
  385. package/src/server/handlers/diagnostic.ts +86 -0
  386. package/src/server/handlers/handler-types.ts +7 -0
  387. package/src/server/handlers/input.ts +173 -0
  388. package/src/server/handlers/interact.ts +135 -0
  389. package/src/server/handlers/journey-assertions.ts +39 -0
  390. package/src/server/handlers/journey.ts +132 -0
  391. package/src/server/handlers/manage.ts +141 -0
  392. package/src/server/handlers/observe.ts +116 -0
  393. package/src/server/handlers/payload.ts +36 -0
  394. package/src/server/handlers/tool-handlers.ts +170 -0
  395. package/src/server/schemas/condition-schema.ts +2 -0
  396. package/src/server/schemas/debugger-schema.ts +46 -0
  397. package/src/server/{journey-schema.ts → schemas/journey-schema.ts} +7 -22
  398. package/src/server/schemas/system-trace-schema.ts +23 -0
  399. package/src/server/tool-definitions.ts +67 -1143
  400. package/src/server-core.ts +2 -2
  401. package/src/server.ts +4 -4
  402. package/src/system/android-status.ts +124 -0
  403. package/src/system/android.ts +33 -21
  404. package/src/system/index.ts +21 -525
  405. package/src/system/ios-status.ts +147 -0
  406. package/src/system/ios.ts +14 -10
  407. package/src/system/model.ts +41 -0
  408. package/src/system/probes.ts +114 -0
  409. package/src/system/status-summary.ts +47 -0
  410. package/src/system/unsupported-status.ts +55 -0
  411. package/src/types.ts +16 -106
  412. package/src/utils/android/commands.ts +81 -0
  413. package/src/utils/android/gradle.ts +132 -0
  414. package/src/utils/android/logs.ts +103 -0
  415. package/src/utils/android/ui-tree.ts +239 -0
  416. package/src/utils/android/utils.ts +16 -556
  417. package/src/utils/cli/idb/check-idb.ts +4 -4
  418. package/src/utils/cli/idb/idb-helper.ts +6 -8
  419. package/src/utils/cli/idb/install-idb.ts +15 -9
  420. package/src/utils/cli/ios/preflight-ios.ts +39 -31
  421. package/src/utils/cli/ios/run-ios-ui-tree-tap.ts +4 -4
  422. package/src/utils/ios/utils.ts +60 -61
  423. package/src/utils/java.ts +62 -43
  424. package/src/utils/resolve-device.ts +9 -6
  425. package/src/utils/ui/index.ts +28 -28
  426. package/test/device/automated/debugger/coroutine-lifecycle.ts +27 -0
  427. package/test/device/automated/debugger/coroutine-support.ts +140 -0
  428. package/test/device/automated/debugger/coroutine.android.test.ts +169 -0
  429. package/test/device/automated/debugger/kotlin.android.test.ts +127 -0
  430. package/test/device/automated/debugger/runtime.android.test.ts +19 -3
  431. package/test/device/automated/debugger/runtime.ios.test.ts +221 -0
  432. package/test/device/automated/interact/interaction.android.test.ts +56 -0
  433. package/test/device/automated/observe/ios-system-trace.smoke.ts +119 -0
  434. package/test/device/automated/observe/system-trace.smoke.ts +1 -1
  435. package/test/device/manual/interact/modul8_selector_tap.manual.ts +1 -1
  436. package/test/fixtures/contracts/tool-definitions.json +3696 -0
  437. package/test/fixtures/coroutine-app/MainActivity.kt +100 -0
  438. package/test/fixtures/coroutine-app/README.md +48 -0
  439. package/test/fixtures/coroutine-app/build.ts +35 -0
  440. package/test/fixtures/debugger-app/MainActivity.java +21 -0
  441. package/test/fixtures/debugger-app/MainActivity.kt +32 -0
  442. package/test/fixtures/debugger-app/README.md +52 -0
  443. package/test/fixtures/debugger-app/build.ts +25 -15
  444. package/test/fixtures/ios-debugger-app/Main.swift +95 -0
  445. package/test/fixtures/ios-debugger-app/README.md +27 -0
  446. package/test/fixtures/ios-debugger-app/build.ts +21 -0
  447. package/test/fixtures/latency-journey-app/README.md +2 -0
  448. package/test/fixtures/readiness-app/README.md +2 -0
  449. package/test/helpers/ios-trace-shutdown.ts +29 -0
  450. package/test/unit/debugger/coroutine-lifecycle.test.ts +43 -0
  451. package/test/unit/debugger/diagnostic-sessions.test.ts +67 -0
  452. package/test/unit/debugger/diagnostics.test.ts +80 -0
  453. package/test/unit/debugger/guards.test.ts +4 -0
  454. package/test/unit/debugger/handle-guards.test.ts +88 -0
  455. package/test/unit/debugger/ios-preparation.test.ts +57 -0
  456. package/test/unit/debugger/ios.test.ts +104 -0
  457. package/test/unit/debugger/lldb-worker.py +166 -0
  458. package/test/unit/debugger/lldb-worker.test.ts +10 -0
  459. package/test/unit/debugger/preparation.test.ts +32 -0
  460. package/test/unit/debugger/protocol.test.ts +15 -0
  461. package/test/unit/debugger/sessions.test.ts +1 -1
  462. package/test/unit/interact/adjustment_service.test.ts +42 -0
  463. package/test/unit/interact/adjustment_verification.test.ts +35 -0
  464. package/test/unit/interact/clock_dependencies.test.ts +63 -0
  465. package/test/unit/interact/element_helpers.test.ts +19 -0
  466. package/test/unit/interact/legacy_wait_service.test.ts +17 -0
  467. package/test/unit/interact/state_comparison.test.ts +20 -0
  468. package/test/unit/interact/target_scope.test.ts +35 -0
  469. package/test/unit/network/get_network_activity.test.ts +1 -1
  470. package/test/unit/observe/ios-trace-native.test.ts +90 -0
  471. package/test/unit/observe/ios-trace-sessions.test.ts +131 -0
  472. package/test/unit/observe/readiness.test.ts +1 -1
  473. package/test/unit/observe/screenshot-encoding.test.ts +30 -0
  474. package/test/unit/observe/snapshot-logs.test.ts +14 -0
  475. package/test/unit/observe/system-trace-router.test.ts +49 -0
  476. package/test/unit/quality/agent-plugin-export.test.ts +38 -0
  477. package/test/unit/quality/architecture.test.ts +60 -0
  478. package/test/unit/quality/code-quality.test.ts +58 -0
  479. package/test/unit/quality/interaction_boundaries.test.ts +24 -0
  480. package/test/unit/server/conditional_actions.test.ts +1 -1
  481. package/test/unit/server/conditional_schema.test.ts +2 -2
  482. package/test/unit/server/debugger-response.test.ts +63 -0
  483. package/test/unit/server/system-trace.test.ts +12 -3
  484. package/test/unit/server/tool_definitions_parity.test.ts +8 -0
  485. package/dist/server/debugger-handlers.js +0 -38
  486. package/dist/server/system-trace-schema.js +0 -17
  487. package/dist/server/tool-handlers.js +0 -1000
  488. package/docs/ROADMAP.md +0 -646
  489. package/docs/benchmarks/ui-tree-performance/bridge-probe.json +0 -29
  490. package/docs/benchmarks/ui-tree-performance/initial-baseline.json +0 -59560
  491. package/docs/specs/baseline-spec-v0.md +0 -312
  492. package/docs/specs/mcp-tooling-spec-v1.md +0 -446
  493. package/src/server/debugger-handlers.ts +0 -29
  494. package/src/server/debugger-schema.ts +0 -37
  495. package/src/server/system-trace-schema.ts +0 -17
  496. package/src/server/tool-handlers.ts +0 -1008
  497. /package/dist/{server/condition-schema.js → contracts/condition.js} +0 -0
  498. /package/dist/server/{readiness-schema.js → schemas/readiness-schema.js} +0 -0
  499. /package/src/{server/condition-schema.ts → contracts/condition.ts} +0 -0
  500. /package/src/server/{readiness-schema.ts → schemas/readiness-schema.ts} +0 -0
@@ -0,0 +1,38 @@
1
+ import assert from 'node:assert/strict'
2
+ import { spawnSync } from 'node:child_process'
3
+ import { mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'
4
+ import os from 'node:os'
5
+ import path from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+
8
+ const root = fileURLToPath(new URL('../../../', import.meta.url))
9
+ const temporary = await mkdtemp(path.join(os.tmpdir(), 'agent-plugin-export-'))
10
+ const output = path.join(temporary, 'plugin')
11
+ const exportPlugin = () => spawnSync(process.execPath, ['scripts/agent-plugin.mjs', '--export-antigravity', output], { cwd: root, encoding: 'utf8', timeout: 10000 })
12
+ try {
13
+ const exported = exportPlugin()
14
+ assert.equal(exported.status, 0, exported.stderr)
15
+ assert.deepEqual((await readdir(output)).sort(), ['LICENSE', 'README.md', 'assets', 'mcp_config.json', 'plugin.json', 'skills'])
16
+ for (const directory of ['skills', 'assets']) {
17
+ const files = await readdir(path.join(output, directory), { recursive: true })
18
+ assert.ok(files.every(file => path.basename(file) !== '.DS_Store' && !path.basename(file).startsWith('._')), 'Export must exclude Finder metadata')
19
+ }
20
+ const manifest = JSON.parse(await readFile(path.join(output, 'plugin.json'), 'utf8'))
21
+ assert.equal(manifest.$schema, 'https://antigravity.google/schemas/v1/plugin.json')
22
+ assert.ok((await readFile(path.join(output, manifest.logo))).length > 0)
23
+ const config = JSON.parse(await readFile(path.join(output, 'mcp_config.json'), 'utf8'))
24
+ assert.equal(Object.keys(config.mcpServers).length, 1)
25
+ const server = config.mcpServers['mobile-debug-mcp']
26
+ assert.equal(server.command, 'npx')
27
+ assert.equal(server.cwd, '${PLUGIN_DATA}')
28
+ assert.equal('type' in server, false, 'Antigravity infers stdio transport; type causes a strict warning')
29
+ const skill = 'skills/mobile-debug-mcp/SKILL.md'
30
+ assert.deepEqual(await readFile(path.join(output, skill)), await readFile(path.join(root, 'agent-plugin', skill)))
31
+ assert.deepEqual(await readFile(path.join(output, 'LICENSE')), await readFile(path.join(root, 'LICENSE')))
32
+ await writeFile(path.join(output, 'keep.txt'), 'existing user data')
33
+ assert.notEqual(exportPlugin().status, 0, 'Existing destinations must not be overwritten or merged')
34
+ assert.equal(await readFile(path.join(output, 'keep.txt'), 'utf8'), 'existing user data')
35
+ console.log('PASS Antigravity export: native inventory, shared skill/license, no foreign manifests, overwrite refusal')
36
+ } finally {
37
+ await rm(temporary, { recursive: true, force: true })
38
+ }
@@ -0,0 +1,60 @@
1
+ import assert from 'node:assert/strict'
2
+ import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises'
3
+ import { tmpdir } from 'node:os'
4
+ import path from 'node:path'
5
+ import { spawnSync } from 'node:child_process'
6
+ import { architectureGraph } from '../../../scripts/architecture-graph.mjs'
7
+ import { checkArchitecture } from '../../../scripts/check-architecture.mjs'
8
+
9
+ const root = await mkdtemp(path.join(tmpdir(), 'mcp-architecture-'))
10
+ try {
11
+ const files: Record<string, string> = {
12
+ 'package.json': JSON.stringify({ type: 'module' }),
13
+ 'tsconfig.json': JSON.stringify({ compilerOptions: {
14
+ module: 'NodeNext', moduleResolution: 'NodeNext', target: 'ES2022',
15
+ paths: { '@server/*': ['./src/server/*'] }
16
+ }, include: ['src/**/*.ts'] }),
17
+ 'src/server/entry.ts': 'export const value = 1',
18
+ 'src/contracts/bad.ts': "export { value } from '@server/entry.js'",
19
+ 'src/interact/entry.ts': "export const load = () => import('../server/entry.js')",
20
+ 'src/interact/adjustment/control-values.ts': "import { spawn } from 'node:child_process'; export const native = spawn",
21
+ 'src/cycle/a.ts': "export { b } from './b.js'; export const a = 1",
22
+ 'src/cycle/b.ts': "export const b = () => import('./a.js')",
23
+ 'src/type-cycle/a.ts': "import type { B } from './b.js'; export interface A { b: B }",
24
+ 'src/type-cycle/b.ts': "import { type A } from './a.js'; export interface B { a: A }",
25
+ 'src/import-equals.ts': "import entry = require('./server/entry.js'); export { entry }",
26
+ 'src/require.ts': "export const load = () => require('./server/entry.js')"
27
+ }
28
+ for (const [file, code] of Object.entries(files)) {
29
+ const target = path.join(root, file)
30
+ await mkdir(path.dirname(target), { recursive: true })
31
+ await writeFile(target, code)
32
+ }
33
+ const config = path.join(root, 'tsconfig.json')
34
+ const graph = await architectureGraph(config)
35
+ const edge = (source: string, target: string) => graph.find(item => item.source === source && item.target === target)
36
+ assert(edge('src/contracts/bad.ts', 'src/server/entry.ts'), 'Resolve aliased re-exports to .ts sources')
37
+ assert(edge('src/interact/entry.ts', 'src/server/entry.ts'), 'Resolve literal dynamic .js imports')
38
+ assert(edge('src/require.ts', 'src/server/entry.ts'), 'Resolve literal require calls')
39
+ assert(edge('src/interact/adjustment/control-values.ts', 'node:child_process'), 'Include Node builtins')
40
+ assert.deepEqual(edge('src/type-cycle/b.ts', 'src/type-cycle/a.ts')?.importKinds, ['type'])
41
+ assert(edge('src/import-equals.ts', 'src/server/entry.ts'), 'Resolve import-equals require syntax')
42
+ const rejected = spawnSync(process.execPath, ['scripts/check-architecture.mjs', config], { encoding: 'utf8' })
43
+ assert.equal(rejected.status, 1, rejected.stderr)
44
+ assert(rejected.stderr.includes('Production runtime dependencies must be cycle-free'))
45
+ const results = checkArchitecture(graph)
46
+ assert(results.every(result => result.violations.length > 0), 'Every rule must reject its deliberately broken fixture')
47
+ const cycles = JSON.stringify(results.at(-1)?.violations)
48
+ assert(cycles.includes('src/cycle/a.ts'), 'Catch a cycle through a re-export and dynamic import')
49
+ assert(!cycles.includes('src/type-cycle'), 'Type-only cycles are not runtime cycles')
50
+ assert(checkArchitecture([]).every(result => result.violations.length > 0), 'An empty graph must fail closed')
51
+
52
+ await writeFile(path.join(root, 'src/nonliteral.ts'), 'export const load = (name: string) => import(name)')
53
+ await assert.rejects(architectureGraph(config), /Nonliteral dependency/)
54
+ await rm(path.join(root, 'src/nonliteral.ts'))
55
+ await writeFile(path.join(root, 'src/unresolved.ts'), "import './missing.js'")
56
+ await assert.rejects(architectureGraph(config), /Unresolved dependency/)
57
+ console.log('PASS architecture negative controls: NodeNext, aliases, re-exports, dynamic/require imports, pure boundaries, runtime cycles, type-only cycles, empty and unresolved graphs')
58
+ } finally {
59
+ await rm(root, { recursive: true, force: true })
60
+ }
@@ -0,0 +1,58 @@
1
+ import assert from 'node:assert/strict'
2
+ import { measure, compare } from '../../../scripts/code-quality.mjs'
3
+
4
+ const file = 'src/interact/quality-fixture.ts'
5
+ const inspect = (code: string) => measure(file, code)
6
+ const has = (findings: Awaited<ReturnType<typeof inspect>>, rule: string) => findings.some(f => f.rule === rule)
7
+ const baseline = (findings: Awaited<ReturnType<typeof inspect>>) => findings.map(({ line: _line, ...entry }) => ({ ...entry, reason: 'Test legacy exception' }))
8
+
9
+ async function main() {
10
+ assert.deepEqual(await inspect('export const twice = (value: number) => value * 2'), [])
11
+ const hugeClass = await inspect(`export class Huge {\n${Array.from({ length: 301 }, (_, i) => `field${i} = ${i}`).join('\n')}\n}`)
12
+ assert(has(hugeClass, 'class-lines'))
13
+ const hugeFunction = await inspect(`export function work() {\n${Array.from({ length: 81 }, (_, i) => `console.log(${i})`).join('\n')}\n}`)
14
+ assert(has(hugeFunction, 'max-lines-per-function'))
15
+ assert(has(await inspect(`export const work = () => {\n${'console.log(1)\n'.repeat(81)}}`), 'max-lines-per-function'))
16
+ const hugeFile = await inspect(Array.from({ length: 501 }, (_, i) => `export const value${i} = ${i}`).join('\n'))
17
+ assert(has(hugeFile, 'max-lines'))
18
+ assert(!has(await inspect(`// A comment\n${'\n// comment\n'.repeat(600)}export const x = 1`), 'max-lines'))
19
+ const complex = await inspect(`export function decide(value: number) { ${'if(value) console.log(value);'.repeat(21)} }`)
20
+ assert(has(complex, 'complexity'))
21
+ assert(has(await inspect('export function nested(x: boolean) { if(x){if(x){if(x){if(x){if(x){console.log(x)}}}}} }'), 'max-depth'))
22
+ assert(has(await inspect("import { value } from '../server/tool-handlers.js'"), 'import-boundary'))
23
+ assert(has(await inspect("export { value } from '../server/common.js'"), 'import-boundary'))
24
+ assert(has(await inspect("type Args = import('../server/common.js').ToolCallArgs"), 'import-boundary'))
25
+ assert(has(await inspect("const transport = require('../server/common.js')"), 'import-boundary'))
26
+ assert(has(await inspect('/* eslint complexity: \"off\" */\nexport const value = 1'), 'inline-suppression'))
27
+ assert(!has(await inspect("import type { Value } from '../contracts/value.js'"), 'import-boundary'))
28
+ assert(has(await inspect('// eslint-disable\nexport const x = 1'), 'inline-suppression'))
29
+ assert(has(await inspect('// eslint-disable-next-line complexity\nexport function f() {}'), 'inline-suppression'))
30
+ const any = await inspect('export function legacy(value: any) { return value }')
31
+ assert(has(any, 'explicit-any'))
32
+ assert.deepEqual(compare(any, baseline(any)), [])
33
+ assert(compare(any, []).some(e => e.includes('explicit-any')))
34
+ const grown = await inspect('export function legacy(value: any): any { return value }')
35
+ assert(compare(grown, baseline(any)).some(e => e.includes('explicit-any')))
36
+ const renamed = await inspect('export function replacement(value: any) { return value }')
37
+ assert(compare(renamed, baseline(any)).length >= 2, 'renames do not inherit debt')
38
+ const moved = any.map(f => ({ ...f, file: 'src/interact/moved.ts' }))
39
+ assert(compare(moved, baseline(any)).length >= 2, 'moves do not inherit debt')
40
+ assert(compare([], baseline(any)).some(e => e.includes('obsolete')))
41
+ assert(compare(any, baseline(grown)).some(e => e.includes('Lower baseline')))
42
+ assert(compare(any, [...baseline(any), ...baseline(any)]).some(e => e.includes('Duplicate')))
43
+ assert(compare(any, [{ ...baseline(any)[0], reason: '' }]).some(e => e.includes('Invalid')))
44
+ const collision = await inspect('function same(x: number) {return x} function same(x: number) {return x}')
45
+ assert(has(collision, 'duplicate-symbol'))
46
+ assert(compare(collision, baseline(collision)).some(e => e.includes('duplicate-symbol')), 'identity collisions cannot be baseline exceptions')
47
+ const suppressed = await inspect('// eslint-disable max-lines-per-function\n'+`function huge(){\n${'console.log(1)\n'.repeat(81)}}`)
48
+ assert(has(suppressed, 'max-lines-per-function'), 'inline directives cannot hide metrics')
49
+ const typeDebt = await inspect('type First = any; type Second = number')
50
+ const shiftedTypeDebt = await inspect('type First = number; type Second = any')
51
+ assert(compare(shiftedTypeDebt, baseline(typeDebt)).length >= 2, 'unrelated type declarations cannot offset each other')
52
+ const java = await measure('src/debugger/java/Fixture.java', 'int field;\n'.repeat(501))
53
+ assert(has(java, 'max-lines'))
54
+ assert.deepEqual(await measure('src/debugger/java/Fixture.java', '// comment\n'.repeat(501)), [])
55
+ assert(!has(await inspect('class Accessor { get value() { return 1 } set value(value: number) { console.log(value) } }'), 'duplicate-symbol'))
56
+ console.log('PASS structural metrics, debt ratchet, boundaries and suppression protection')
57
+ }
58
+ main().catch(error => { console.error(error); process.exitCode = 1 })
@@ -0,0 +1,24 @@
1
+ import assert from 'node:assert/strict'
2
+ import { readdir, readFile } from 'node:fs/promises'
3
+ import { measure } from '../../../scripts/code-quality.mjs'
4
+
5
+ // Refactored interaction services must meet defaults even if someone adds a legacy allowance.
6
+ const legacy = new Set(['android.ts', 'ios.ts', 'conditional-action.ts', 'classify.ts'])
7
+ async function sourceFiles(directory = ''): Promise<string[]> {
8
+ const entries = await readdir(`src/interact/${directory}`, { withFileTypes: true })
9
+ const paths: string[] = []
10
+ for (const entry of entries) {
11
+ const relative = directory ? `${directory}/${entry.name}` : entry.name
12
+ if (entry.isDirectory()) paths.push(...await sourceFiles(relative))
13
+ else if (relative.endsWith('.ts') && !legacy.has(relative)) paths.push(relative)
14
+ }
15
+ return paths
16
+ }
17
+ const files = await sourceFiles()
18
+ const baseline = JSON.parse(await readFile('scripts/code-quality-baseline.json', 'utf8')) as Array<{ file: string }>
19
+ for (const file of files) {
20
+ const path = `src/interact/${file}`
21
+ assert.deepEqual(await measure(path, await readFile(path, 'utf8')), [], `${path} must meet default structural and typing limits`)
22
+ assert(!baseline.some(entry => entry.file === path), `${path} cannot inherit legacy exceptions`)
23
+ }
24
+ console.log(`PASS default quality limits and no legacy exceptions across ${files.length} interaction modules`)
@@ -4,7 +4,7 @@ import { tmpdir } from 'node:os'
4
4
  import path from 'node:path'
5
5
  import { handleToolCall, toolDefinitions } from '../../../src/server-core.js'
6
6
  import { ToolsObserve } from '../../../src/observe/index.js'
7
- import { ToolsNetwork } from '../../../src/network/index.js'
7
+ import { ToolsNetwork } from '../../../src/observe/network/index.js'
8
8
  import { deriveSnapshotMetadata, getSnapshotSessionId, resetSnapshotMetadataForTests } from '../../../src/observe/snapshot-metadata.js'
9
9
  import { _setDeviceListersForTests, _resetDeviceListersForTests } from '../../../src/utils/resolve-device.js'
10
10
  import { runWithBudget } from '../../../src/utils/operation-budget.js'
@@ -1,8 +1,8 @@
1
1
  import assert from 'node:assert/strict'
2
2
  import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv'
3
3
  import { toolDefinitions } from '../../../src/server/tool-definitions.js'
4
- import { conditionalTools, validateExpectedState } from '../../../src/server/condition-schema.js'
5
- import { journeySchema } from '../../../src/server/journey-schema.js'
4
+ import { conditionalTools, validateExpectedState } from '../../../src/server/schemas/condition-schema.js'
5
+ import { journeySchema } from '../../../src/server/schemas/journey-schema.js'
6
6
 
7
7
  const provider = new AjvJsonSchemaValidator()
8
8
  const expectedState = { snapshotSessionId: 'session-fixture', snapshotRevision: 1 }
@@ -0,0 +1,63 @@
1
+ import assert from 'node:assert/strict'
2
+ import { debuggerResponse } from '../../../src/server/handlers/debugger-response.js'
3
+ import { handleDebugger } from '../../../src/server/handlers/debugger-handlers.js'
4
+ import { debuggerContracts, debuggerTools } from '../../../src/server/schemas/debugger-schema.js'
5
+ import { debuggerSessions } from '../../../src/debugger/sessions.js'
6
+ import { DebuggerError } from '../../../src/debugger/worker.js'
7
+ import { diagnostic } from '../../../src/debugger/diagnostics.js'
8
+
9
+ const baseline = ['capabilities', 'attach', 'state']
10
+ const payload = {
11
+ success: false, debug_session_id: 'session', device: { id: 'device' }, target: { pid: 42 }, capabilities: { locals: true },
12
+ state: 'paused', captured_at_ms: 123, reason: null, stop: { stop_id: 'stop', thread_id: 'thread' },
13
+ limitations: ['SHALLOW_LOCALS'], cleanup: { status: 'failed', remaining_resources: ['forward:tcp:123'] },
14
+ error: { code: 'DEBUGGER_CLEANUP_FAILED', retryable: false, diagnostic: diagnostic('cleanup', 'operation_failed') },
15
+ execution_state: 'unknown', result: { frames: [{ frame_id: 'frame' }], truncated: true, availability: 'unknown' },
16
+ breakpoints: [], events: [], next_cursor: 4, overflow: true, timed_out: false, future_field: { preserve: true }
17
+ }
18
+ const expected = structuredClone(payload) as Record<string, unknown>
19
+ for (const key of ['device', 'target', 'capabilities']) delete expected[key]
20
+ const before = structuredClone(payload)
21
+ for (const tool of debuggerTools) {
22
+ const contract = debuggerContracts[tool.name]
23
+ assert.deepEqual(tool.inputSchema.properties.responseMode, { type: 'string', enum: ['compact', 'debug'], default: 'debug' })
24
+ const shape = contract.schema.shape
25
+ assert.equal(shape.responseMode.parse(undefined), 'debug')
26
+ for (const mode of ['compact', 'debug']) assert.equal(shape.responseMode.parse(mode), mode)
27
+ assert.equal(shape.responseMode.safeParse('full').success, false)
28
+ assert.deepEqual(debuggerResponse(contract.command, 'debug', payload), payload)
29
+ assert.deepEqual(debuggerResponse(contract.command, 'compact', payload), baseline.includes(contract.command) ? payload : expected)
30
+ const success = { ...payload, success: true, error: undefined, cleanup: { status: 'pending', remaining_resources: ['jdi_worker'] } }
31
+ assert.deepEqual(debuggerResponse(contract.command, 'compact', success), baseline.includes(contract.command) ? success : { ...expected, success: true, error: undefined, cleanup: success.cleanup })
32
+ const noSession = { ...payload, debug_session_id: null }
33
+ assert.deepEqual(debuggerResponse(contract.command, 'compact', noSession), noSession)
34
+ }
35
+ assert.deepEqual(payload, before, 'projection must not mutate nested or shared objects')
36
+
37
+ // This self-running test has its own process; restore the singleton seam in finally.
38
+ const original = debuggerSessions.command
39
+ try {
40
+ debuggerSessions.command = async (_id, _command, args) => {
41
+ assert.ok(!Object.hasOwn(args!, 'responseMode'), 'presentation input must not reach worker')
42
+ return { ...payload, success: true } as unknown as Awaited<ReturnType<typeof original>>
43
+ }
44
+ for (const mode of [undefined, 'debug', 'compact']) {
45
+ const response = await handleDebugger('get_debugger_locals', { debugSessionId: 'session', stopId: 'stop', frameId: 'frame', ...(mode ? { responseMode: mode } : {}) })
46
+ assert.equal(response.isError, undefined)
47
+ assert.deepEqual(JSON.parse(response.content[0].text), { ...(mode === 'compact' ? expected : payload), success: true })
48
+ }
49
+ for (const code of ['DEBUGGER_STALE_REFERENCE', 'DEBUGGER_NOT_FOUND', 'DEBUGGER_WORKER_FAILED', 'DEBUGGER_TIMEOUT', 'DEBUGGER_CANCELLED']) {
50
+ debuggerSessions.command = async () => { throw new DebuggerError(code, diagnostic('command', 'unknown')) }
51
+ for (const responseMode of ['compact', 'debug']) {
52
+ const response = await handleDebugger('resume_debugger', { debugSessionId: 'absent', stopId: 'old', responseMode })
53
+ const value = JSON.parse(response.content[0].text)
54
+ assert.equal(response.isError, true)
55
+ assert.equal(value.error.code, code)
56
+ assert.equal(Object.hasOwn(value, 'capabilities'), responseMode === 'debug')
57
+ assert.equal(value.debug_session_id, 'absent')
58
+ }
59
+ }
60
+ const invalid = await handleDebugger('detach_debugger', { debugSessionId: 'session', responseMode: 'full' })
61
+ assert.equal(JSON.parse(invalid.content[0].text).error.code, 'INVALID_ARGUMENT')
62
+ } finally { debuggerSessions.command = original }
63
+ console.log('PASS debugger response defaults, exact retention, failures, immutable projection and argument isolation')
@@ -8,6 +8,7 @@ import { withEvidence, bindSystemTrace, bindEvidenceDevice } from '../../../src/
8
8
  const parse = (r: any) => JSON.parse(r.content[0].text)
9
9
  async function run() {
10
10
  const originalLink = systemTraces.link, originalStart = systemTraces.start, originalControl = systemTraces.control
11
+ const originalCapabilities = systemTraces.iosCapabilities
11
12
  const originalApp = AndroidManage.prototype.startApp
12
13
  const id = '62a51510-c303-4a1b-af0e-f97cc976d740'
13
14
  let dispatched = 0, starts = 0
@@ -24,8 +25,16 @@ async function run() {
24
25
  }
25
26
  systemTraces.start = async () => { starts++; throw new Error('must not run') }
26
27
  const ios = await handleToolCall('start_system_trace', { platform: 'ios' })
27
- assert.equal(parse(ios).error.code, 'UNSUPPORTED_PLATFORM'); assert.equal(starts, 0)
28
- assert.equal(parse(await handleToolCall('get_system_trace_capabilities', { platform: 'ios' })).supported, false)
28
+ assert.equal(parse(ios).error.code, 'INVALID_ARGUMENT'); assert.equal(starts, 0)
29
+ assert.equal(parse(await handleToolCall('get_system_trace_capabilities', { platform: 'ios' })).error.code, 'INVALID_ARGUMENT')
30
+ for (const args of [{platform:'ios',deviceId:'sim'}, {platform:'android',appId:'fixture'}, {platform:'android',template:'Time Profiler'}, {platform:'ios',deviceId:'sim',appId:'fixture',template:'Other'}, {platform:'ios',deviceId:'sim',appId:'invalid bundle'}]) {
31
+ assert.equal(parse(await handleToolCall('start_system_trace', args)).error.code, 'INVALID_ARGUMENT')
32
+ }
33
+ systemTraces.iosCapabilities = async (deviceId, appId, template) => {
34
+ assert.equal(deviceId, 'sim'); assert.equal(appId, 'fixture'); assert.equal(template, 'Time Profiler')
35
+ return {supported: false, backend:'xctrace'} as any
36
+ }
37
+ assert.equal(parse(await handleToolCall('get_system_trace_capabilities', {platform:'ios',deviceId:'sim',appId:'fixture',template:'Time Profiler'})).backend, 'xctrace')
29
38
  for (const name of ['stop_system_trace', 'cancel_system_trace', 'get_system_trace_status']) {
30
39
  assert.equal(parse(await handleToolCall(name, { traceId: id, deviceId: 'wrong' })).error.code, 'INVALID_ARGUMENT')
31
40
  assert.equal(parse(await handleToolCall(name, { traceId: id })).error.code, 'TRACE_NOT_FOUND')
@@ -57,7 +66,7 @@ async function run() {
57
66
  assert.equal(independent.evidence.trace_context.trace_id, null)
58
67
  console.log('system trace tool contracts and journey evidence: PASS')
59
68
  } finally {
60
- systemTraces.link = originalLink; systemTraces.start = originalStart; systemTraces.control = originalControl
69
+ systemTraces.iosCapabilities = originalCapabilities; systemTraces.link = originalLink; systemTraces.start = originalStart; systemTraces.control = originalControl
61
70
  AndroidManage.prototype.startApp = originalApp; _resetDeviceListersForTests()
62
71
  }
63
72
  }
@@ -0,0 +1,8 @@
1
+ import assert from 'node:assert/strict'
2
+ import { readFile } from 'node:fs/promises'
3
+ import { toolDefinitions } from '../../../src/server/tool-definitions.js'
4
+
5
+ // Captured before structural refactoring: changes require an intentional contract review.
6
+ const baseline = JSON.parse(await readFile(new URL('../../fixtures/contracts/tool-definitions.json', import.meta.url), 'utf8'))
7
+ assert.deepEqual(toolDefinitions, baseline, 'Public tool order, schemas, defaults and descriptions must remain compatible')
8
+ console.log('PASS public tool-definition compatibility baseline')
@@ -1,38 +0,0 @@
1
- import { debuggerContracts } from './debugger-schema.js';
2
- import { debuggerSessions, debuggerCapabilities } from '../debugger/sessions.js';
3
- import { DebuggerError, withDebuggerBudget } from '../debugger/worker.js';
4
- import { wrapResponse } from './common.js';
5
- function failure(code, summary = {}) {
6
- return { ...wrapResponse({ debug_session_id: null, device: null, target: null, state: null,
7
- captured_at_ms: Date.now(), capabilities: debuggerCapabilities, limitations: [], cleanup: null,
8
- ...summary, success: false, error: { code, message: code, retryable: false } }), isError: true };
9
- }
10
- export async function handleDebugger(name, args, signal) {
11
- const parsed = debuggerContracts[name].schema.safeParse(args);
12
- if (!parsed.success)
13
- return failure('INVALID_ARGUMENT');
14
- const a = parsed.data;
15
- const command = debuggerContracts[name].command;
16
- try {
17
- if (signal?.aborted)
18
- throw new DebuggerError('DEBUGGER_CANCELLED');
19
- const result = await withDebuggerBudget(a.timeoutMs, signal, async () => command === 'capabilities' ? await debuggerSessions.capabilities(a.deviceId, a.appId, a.processId) :
20
- command === 'attach' ? await debuggerSessions.attach(a.deviceId, a.appId, a.processId, a.timeoutMs) :
21
- await debuggerSessions.command(a.debugSessionId, command, { ...a, signal: command === 'events' ? signal : undefined }, a.timeoutMs));
22
- if (signal?.aborted && command === 'capabilities')
23
- throw new DebuggerError('DEBUGGER_CANCELLED');
24
- return { ...wrapResponse(result), ...(!result.success ? { isError: true } : {}) };
25
- }
26
- catch (e) {
27
- const code = e instanceof DebuggerError ? e.code : 'DEBUGGER_WORKER_FAILED';
28
- let summary = {};
29
- if (a.debugSessionId) {
30
- try {
31
- summary = debuggerSessions.summary(a.debugSessionId);
32
- }
33
- catch { /* Unknown session */ }
34
- }
35
- return failure(code, { debug_session_id: a.debugSessionId ?? null,
36
- device: a.deviceId ? { platform: 'android', id: a.deviceId } : null, ...summary });
37
- }
38
- }
@@ -1,17 +0,0 @@
1
- import { z } from 'zod';
2
- const target = { platform: z.enum(['android', 'ios']), deviceId: z.string().min(1).optional() };
3
- export const traceTargetSchema = z.object(target).strict();
4
- export const traceStartSchema = z.object({ ...target, durationMs: z.number().int().min(1000).max(120000).default(30000) }).strict();
5
- export const traceControlSchema = z.object({ traceId: z.string().uuid() }).strict();
6
- const properties = { platform: { type: 'string', enum: ['android', 'ios'] }, deviceId: { type: 'string', minLength: 1 } };
7
- export const systemTraceTools = [
8
- { name: 'get_system_trace_capabilities', description: 'Probe Android Perfetto prerequisites without recording. Device-wide system tracing is optional; iOS is unsupported.',
9
- inputSchema: { type: 'object', additionalProperties: false, required: ['platform'], properties } },
10
- { name: 'start_system_trace', description: 'Start bounded Android Perfetto recording, returning an owned trace_id. Run an existing journey with systemTraceId, then stop to retrieve a local artifact or cancel to discard. Device-wide traces may contain sensitive system annotations; no upload.',
11
- inputSchema: { type: 'object', additionalProperties: false, required: ['platform'], properties: { ...properties, durationMs: { type: 'integer', minimum: 1000, maximum: 120000, default: 30000 } } } },
12
- ...['get_system_trace_status', 'stop_system_trace', 'cancel_system_trace'].map(name => ({ name,
13
- description: name === 'get_system_trace_status' ? 'Reconcile an owned trace and retrieve its state; finalise duration-completed capture.' :
14
- name === 'stop_system_trace' ? 'Stop owned capture gracefully and retrieve a local Perfetto artifact. Retry after a transfer/cleanup failure.' : 'Stop owned capture and discard partial files. Already completed local artifacts are retained.',
15
- inputSchema: { type: 'object', additionalProperties: false, required: ['traceId'], properties: { traceId: { type: 'string', format: 'uuid' } } }
16
- }))
17
- ];