mobile-debug-mcp 0.35.0 → 0.37.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 (247) hide show
  1. package/.cursor-plugin/marketplace.json +1 -1
  2. package/.github/workflows/ci.yml +1 -1
  3. package/README.md +96 -24
  4. package/agent-plugin/.antigravity-plugin/README.md +48 -0
  5. package/agent-plugin/.antigravity-plugin/plugin.json +18 -0
  6. package/agent-plugin/.claude-plugin/plugin.json +2 -2
  7. package/agent-plugin/.codex-plugin/plugin.json +1 -1
  8. package/agent-plugin/.cursor-plugin/plugin.json +2 -2
  9. package/agent-plugin/.mcp.json +1 -1
  10. package/agent-plugin/README.md +37 -8
  11. package/agent-plugin/cursor/.cursor-plugin/plugin.json +23 -0
  12. package/agent-plugin/cursor/LICENSE +201 -0
  13. package/agent-plugin/cursor/README.md +9 -0
  14. package/agent-plugin/cursor/skills/mobile-debug-mcp/SKILL.md +261 -0
  15. package/agent-plugin/mcp.json +1 -1
  16. package/agent-plugin/mcp_config.json +13 -0
  17. package/agent-plugin/plugin.json +1 -1
  18. package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +46 -18
  19. package/dist/contracts/device-readiness.js +1 -0
  20. package/dist/debugger/guard.js +4 -4
  21. package/dist/debugger/ios-worker.js +62 -0
  22. package/dist/debugger/ios.js +57 -0
  23. package/dist/debugger/sessions.js +33 -16
  24. package/dist/debugger/worker.js +6 -4
  25. package/dist/interact/index.js +12 -2
  26. package/dist/interact/waits/ui-change-wait.js +9 -2
  27. package/dist/interact/waits/ui-wait.js +7 -3
  28. package/dist/manage/index.js +3 -0
  29. package/dist/manage/ios.js +2 -0
  30. package/dist/observe/device-readiness.js +116 -0
  31. package/dist/observe/evidence.js +31 -0
  32. package/dist/observe/ios-trace/artifact.js +63 -0
  33. package/dist/observe/ios-trace/capabilities.js +86 -0
  34. package/dist/observe/ios-trace/native.js +93 -0
  35. package/dist/observe/ios-trace/notification.js +35 -0
  36. package/dist/observe/ios-trace/process.js +98 -0
  37. package/dist/observe/ios-trace/sessions.js +246 -0
  38. package/dist/observe/readiness-service.js +22 -10
  39. package/dist/observe/readiness.js +34 -4
  40. package/dist/observe/screenshot-encoding.js +4 -0
  41. package/dist/observe/snapshot-collection.js +7 -2
  42. package/dist/observe/system-trace-error.js +7 -0
  43. package/dist/observe/system-trace-router.js +81 -0
  44. package/dist/observe/system-trace.js +4 -8
  45. package/dist/server/definitions/manage.js +3 -2
  46. package/dist/server/handlers/action-execution.js +23 -14
  47. package/dist/server/handlers/compact-interaction.js +106 -0
  48. package/dist/server/handlers/compact-state.js +47 -0
  49. package/dist/server/handlers/debugger-handlers.js +27 -8
  50. package/dist/server/handlers/diagnostic.js +12 -4
  51. package/dist/server/handlers/input.js +2 -0
  52. package/dist/server/handlers/interact.js +2 -0
  53. package/dist/server/handlers/interaction-diagnostics.js +62 -0
  54. package/dist/server/handlers/journey.js +18 -20
  55. package/dist/server/handlers/observe.js +2 -1
  56. package/dist/server/handlers/tool-handlers.js +28 -14
  57. package/dist/server/schemas/debugger-schema.js +10 -7
  58. package/dist/server/schemas/interaction-diagnostics.js +9 -0
  59. package/dist/server/schemas/system-trace-schema.js +14 -9
  60. package/dist/server/tool-definitions.js +9 -4
  61. package/dist/server-core.js +5 -2
  62. package/dist/server.js +5 -5
  63. package/dist/system/android.js +19 -15
  64. package/dist/system/index.js +2 -1
  65. package/dist/utils/android/utils.js +7 -16
  66. package/dist/utils/app-installation.js +77 -0
  67. package/dist/utils/benchmark-metrics.js +43 -0
  68. package/dist/utils/exec.js +4 -0
  69. package/dist/utils/ios/utils.js +7 -11
  70. package/dist/utils/resolve-device.js +3 -2
  71. package/dist/utils/timing.js +3 -3
  72. package/docs/CHANGELOG.md +48 -1
  73. package/docs/agent-plugin-installation-verification.md +39 -0
  74. package/docs/benchmarks/README.md +1 -0
  75. package/docs/benchmarks/end-to-end-latency/README.md +98 -0
  76. package/docs/benchmarks/end-to-end-latency/android-snapshot-pair.json +6532 -0
  77. package/docs/benchmarks/end-to-end-latency/android-snapshot-pair.md +30 -0
  78. package/docs/benchmarks/end-to-end-latency/baseline-attempt-1.json +15901 -0
  79. package/docs/benchmarks/end-to-end-latency/baseline-attempt-1.md +14 -0
  80. package/docs/benchmarks/end-to-end-latency/baseline.json +233843 -0
  81. package/docs/benchmarks/end-to-end-latency/baseline.md +21 -0
  82. package/docs/benchmarks/end-to-end-latency/investigation.md +128 -0
  83. package/docs/benchmarks/end-to-end-latency/ios-smoke.json +84 -0
  84. package/docs/benchmarks/end-to-end-latency/ios-smoke.md +9 -0
  85. package/docs/benchmarks/end-to-end-latency/smoke.json +19601 -0
  86. package/docs/benchmarks/end-to-end-latency/smoke.md +21 -0
  87. package/docs/code-structure.md +3 -1
  88. package/docs/specs/031-ios-system-traces/intent.md +38 -0
  89. package/docs/specs/031-ios-system-traces/investigation.md +92 -0
  90. package/docs/specs/031-ios-system-traces/late-run-failure-evidence.json +32 -0
  91. package/docs/specs/031-ios-system-traces/plan.md +166 -0
  92. package/docs/specs/031-ios-system-traces/pr102-monitor-evidence.json +22 -0
  93. package/docs/specs/031-ios-system-traces/simulator-evidence.json +47 -0
  94. package/docs/specs/031-ios-system-traces/spec.md +135 -0
  95. package/docs/specs/032-ios-runtime-debugger/evidence.json +176 -0
  96. package/docs/specs/032-ios-runtime-debugger/intent.md +38 -0
  97. package/docs/specs/032-ios-runtime-debugger/plan.md +95 -0
  98. package/docs/specs/032-ios-runtime-debugger/report.md +205 -0
  99. package/docs/specs/032-ios-runtime-debugger/spec.md +153 -0
  100. package/docs/specs/033-device-readiness-blockers/android-evidence.json +437 -0
  101. package/docs/specs/033-device-readiness-blockers/android-physical-evidence.json +28 -0
  102. package/docs/specs/033-device-readiness-blockers/android-physical-power-evidence.json +29 -0
  103. package/docs/specs/033-device-readiness-blockers/intent.md +41 -0
  104. package/docs/specs/033-device-readiness-blockers/ios-investigation.md +55 -0
  105. package/docs/specs/033-device-readiness-blockers/ios-probe-evidence.json +24 -0
  106. package/docs/specs/033-device-readiness-blockers/ios-tool-evidence.json +73 -0
  107. package/docs/specs/033-device-readiness-blockers/plan.md +249 -0
  108. package/docs/specs/033-device-readiness-blockers/spec.md +134 -0
  109. package/docs/specs/034-app-installation-status/intent.md +41 -0
  110. package/docs/specs/034-app-installation-status/native-evidence.json +654 -0
  111. package/docs/specs/034-app-installation-status/plan.md +73 -0
  112. package/docs/specs/034-app-installation-status/spec.md +114 -0
  113. package/docs/specs/035-compact-interaction-results/baseline.md +45 -0
  114. package/docs/specs/035-compact-interaction-results/intent.md +38 -0
  115. package/docs/specs/035-compact-interaction-results/plan.md +43 -0
  116. package/docs/specs/035-compact-interaction-results/spec.md +118 -0
  117. package/docs/specs/035-compact-interaction-results/verification.md +111 -0
  118. package/docs/specs/036-end-to-end-interaction-latency/android-snapshot-amendment.md +60 -0
  119. package/docs/specs/036-end-to-end-interaction-latency/android-snapshot-plan.md +32 -0
  120. package/docs/specs/036-end-to-end-interaction-latency/intent.md +37 -0
  121. package/docs/specs/036-end-to-end-interaction-latency/plan.md +59 -0
  122. package/docs/specs/036-end-to-end-interaction-latency/spec.md +126 -0
  123. package/docs/specs/036-end-to-end-interaction-latency/verification.md +87 -0
  124. package/docs/tools/TOOLS.md +3 -2
  125. package/docs/tools/compact-interactions.md +56 -0
  126. package/docs/tools/correlated-evidence.md +6 -0
  127. package/docs/tools/debugger.md +45 -5
  128. package/docs/tools/interact.md +17 -8
  129. package/docs/tools/manage.md +10 -2
  130. package/docs/tools/observe.md +42 -2
  131. package/docs/tools/system-traces.md +81 -14
  132. package/docs/tools/system.md +6 -0
  133. package/package.json +2 -1
  134. package/scripts/agent-plugin.mjs +55 -5
  135. package/src/contracts/device-readiness.ts +8 -0
  136. package/src/debugger/android.ts +1 -1
  137. package/src/debugger/guard.ts +5 -5
  138. package/src/debugger/ios-worker.ts +49 -0
  139. package/src/debugger/ios.ts +45 -0
  140. package/src/debugger/lldb/breakpoints.py +51 -0
  141. package/src/debugger/lldb/inspection.py +109 -0
  142. package/src/debugger/lldb/worker.py +203 -0
  143. package/src/debugger/sessions.ts +24 -12
  144. package/src/debugger/worker.ts +7 -4
  145. package/src/interact/index.ts +13 -2
  146. package/src/interact/waits/ui-change-wait.ts +7 -2
  147. package/src/interact/waits/ui-wait.ts +6 -3
  148. package/src/manage/index.ts +2 -0
  149. package/src/manage/ios.ts +2 -0
  150. package/src/observe/device-readiness.ts +96 -0
  151. package/src/observe/evidence.ts +30 -1
  152. package/src/observe/ios-trace/artifact.ts +55 -0
  153. package/src/observe/ios-trace/capabilities.ts +74 -0
  154. package/src/observe/ios-trace/native.ts +72 -0
  155. package/src/observe/ios-trace/notification.ts +30 -0
  156. package/src/observe/ios-trace/process.ts +82 -0
  157. package/src/observe/ios-trace/sessions.ts +206 -0
  158. package/src/observe/readiness-service.ts +22 -10
  159. package/src/observe/readiness.ts +37 -4
  160. package/src/observe/screenshot-encoding.ts +4 -0
  161. package/src/observe/snapshot-collection.ts +7 -2
  162. package/src/observe/system-trace-error.ts +3 -0
  163. package/src/observe/system-trace-router.ts +61 -0
  164. package/src/observe/system-trace.ts +4 -4
  165. package/src/server/common.ts +2 -2
  166. package/src/server/definitions/manage.ts +3 -2
  167. package/src/server/handlers/action-execution.ts +22 -14
  168. package/src/server/handlers/compact-interaction.ts +91 -0
  169. package/src/server/handlers/compact-state.ts +43 -0
  170. package/src/server/handlers/debugger-handlers.ts +28 -9
  171. package/src/server/handlers/diagnostic.ts +11 -4
  172. package/src/server/handlers/input.ts +2 -0
  173. package/src/server/handlers/interact.ts +2 -0
  174. package/src/server/handlers/interaction-diagnostics.ts +50 -0
  175. package/src/server/handlers/journey.ts +15 -17
  176. package/src/server/handlers/observe.ts +2 -1
  177. package/src/server/handlers/payload.ts +2 -1
  178. package/src/server/handlers/tool-handlers.ts +29 -14
  179. package/src/server/schemas/debugger-schema.ts +10 -7
  180. package/src/server/schemas/interaction-diagnostics.ts +10 -0
  181. package/src/server/schemas/system-trace-schema.ts +15 -9
  182. package/src/server/tool-definitions.ts +8 -4
  183. package/src/server-core.ts +5 -2
  184. package/src/server.ts +4 -4
  185. package/src/system/android.ts +18 -11
  186. package/src/system/index.ts +2 -1
  187. package/src/types.ts +2 -0
  188. package/src/utils/android/utils.ts +8 -10
  189. package/src/utils/app-installation.ts +73 -0
  190. package/src/utils/benchmark-metrics.ts +42 -0
  191. package/src/utils/exec.ts +5 -0
  192. package/src/utils/ios/utils.ts +7 -10
  193. package/src/utils/resolve-device.ts +4 -2
  194. package/src/utils/timing.ts +3 -2
  195. package/test/device/automated/debugger/runtime.android.test.ts +5 -0
  196. package/test/device/automated/debugger/runtime.ios.test.ts +227 -0
  197. package/test/device/automated/interact/compact-results.smoke.ts +58 -0
  198. package/test/device/automated/latency/end-to-end-environment.ts +61 -0
  199. package/test/device/automated/latency/end-to-end-report.ts +90 -0
  200. package/test/device/automated/latency/end-to-end-session.ts +98 -0
  201. package/test/device/automated/latency/end-to-end.ts +149 -0
  202. package/test/device/automated/latency/owned-transport.ts +81 -0
  203. package/test/device/automated/latency/snapshot-pair.ts +143 -0
  204. package/test/device/automated/latency-ios/benchmark.ts +126 -0
  205. package/test/device/automated/observe/correlated-evidence.smoke.ts +7 -5
  206. package/test/device/automated/observe/device-readiness-cleanup.ts +14 -0
  207. package/test/device/automated/observe/device-readiness.android.smoke.ts +78 -0
  208. package/test/device/automated/observe/ios-system-trace.smoke.ts +119 -0
  209. package/test/device/automated/observe/system-trace.smoke.ts +2 -2
  210. package/test/fixtures/contracts/tool-definitions.json +243 -47
  211. package/test/fixtures/ios-debugger-app/Main.swift +95 -0
  212. package/test/fixtures/ios-debugger-app/README.md +27 -0
  213. package/test/fixtures/ios-debugger-app/build.ts +21 -0
  214. package/test/fixtures/latency-journey-app/build.ts +3 -3
  215. package/test/helpers/ios-trace-shutdown.ts +29 -0
  216. package/test/unit/debugger/handle-guards.test.ts +89 -0
  217. package/test/unit/debugger/ios-preparation.test.ts +57 -0
  218. package/test/unit/debugger/ios.test.ts +104 -0
  219. package/test/unit/debugger/lldb-worker.py +166 -0
  220. package/test/unit/debugger/lldb-worker.test.ts +10 -0
  221. package/test/unit/interact/ui-change-readiness-interruption.test.ts +37 -0
  222. package/test/unit/observe/capture_debug_snapshot.test.ts +66 -12
  223. package/test/unit/observe/device-readiness-cleanup.test.ts +24 -0
  224. package/test/unit/observe/device-readiness.test.ts +97 -0
  225. package/test/unit/observe/ios-trace-native.test.ts +90 -0
  226. package/test/unit/observe/ios-trace-sessions.test.ts +154 -0
  227. package/test/unit/observe/readiness-retained-blockers.test.ts +40 -0
  228. package/test/unit/observe/readiness.test.ts +1 -1
  229. package/test/unit/observe/system-trace-router.test.ts +49 -0
  230. package/test/unit/quality/agent-plugin-export.test.ts +38 -0
  231. package/test/unit/server/compact-interaction.test.ts +87 -0
  232. package/test/unit/server/compact-journey-evidence.test.ts +40 -0
  233. package/test/unit/server/compact-review-regressions.test.ts +78 -0
  234. package/test/unit/server/conditional_actions.test.ts +7 -3
  235. package/test/unit/server/correlated-evidence.test.ts +18 -6
  236. package/test/unit/server/end-to-end-report.test.ts +46 -0
  237. package/test/unit/server/input-device-readiness.test.ts +55 -0
  238. package/test/unit/server/interaction-diagnostics.test.ts +45 -0
  239. package/test/unit/server/owned-benchmark-transport.test.ts +32 -0
  240. package/test/unit/server/readiness-retained-deadline.test.ts +32 -0
  241. package/test/unit/server/readiness.test.ts +24 -1
  242. package/test/unit/server/run_journey.test.ts +2 -1
  243. package/test/unit/server/selector_tap_target.test.ts +2 -1
  244. package/test/unit/server/system-trace.test.ts +18 -7
  245. package/test/unit/utils/app-installation.test.ts +78 -0
  246. package/test/unit/utils/benchmark-metrics.test.ts +36 -0
  247. package/test/unit/utils/resolve_device.test.ts +11 -0
@@ -0,0 +1,153 @@
1
+ # iOS runtime debugger — specification
2
+
3
+ Source: [issue #70](https://github.com/clivejefferies/mobile-debug-tools/issues/70).
4
+ Scope: [accepted intent](intent.md), approved by the user's “ok” on 2026-11-04.
5
+ Status: **approved** by the user's “ok” on 2026-11-04 in response to the complete
6
+ specification and approval request in this chat. Implementation authorised.
7
+
8
+ ## Behaviour and supported environment
9
+
10
+ Add optional LLDB-backed debugging for an already-running development app on an
11
+ explicit iOS simulator UDID, on macOS with full Xcode and its Swift-enabled LLDB.
12
+ Initial verification targets the installed Xcode 27.2, LLDB 2103.0.34.407 and Swift
13
+ 6.4.2 toolchain; other versions remain unverified until separately exercised.
14
+ Physical devices, remote hosts and production/optimised apps are unsupported in
15
+ this initial matrix. Normal mobile tools must not acquire an LLDB dependency.
16
+
17
+ Provide source breakpoints, stop events, bounded stacks and shallow locals,
18
+ into/over/out stepping, resume and detach through the existing eleven tools.
19
+ Attach may briefly stop the process for setup, but returns running unless an
20
+ actual stop event has been retained; never discard a racing breakpoint stop.
21
+ LLDB stops suspend the target process, not the whole simulator.
22
+
23
+ ## Tool contract and compatibility
24
+
25
+ Extend `get_debugger_capabilities` and `attach_debugger` to accept
26
+ `platform: "android" | "ios"`, existing explicit `deviceId`, `appId` and optional
27
+ positive `processId`. For iOS, require a simulator UDID and valid bundle identifier.
28
+ Probe without attaching or launching the app. Report missing prerequisites,
29
+ unsupported target types, absent apps/processes and ambiguous candidates
30
+ explicitly. A probe cannot guarantee that later attach permission will succeed.
31
+
32
+ Preserve all existing Android requests. Extend `set_debugger_breakpoint` with
33
+ optional `sourceFile` (nonempty absolute local source path, maximum 512 characters).
34
+ Require exactly one of `className` or `sourceFile`, with the existing positive
35
+ 1-based `line`. Android sessions require `className`; iOS sessions require
36
+ `sourceFile`. Invalid combinations fail `INVALID_ARGUMENT`. Resolve the full
37
+ path against loaded debug information, never a basename fallback or shell search.
38
+ Return owned breakpoint ID, pending/resolved/rejected status and actual locations.
39
+ Unloaded images can remain pending. Only exact executable line matches may be
40
+ enabled; locations silently moved by LLDB are rejected and removed.
41
+
42
+ Keep session, stop, thread and frame arguments, tool names, response modes,
43
+ pagination, defaults and timeout bounds unchanged. Existing common response and
44
+ error shapes remain: `success`, session/target/device metadata, state, timestamp,
45
+ capabilities, limitations, cleanup, reason, stop, operation `result`, and sanitized
46
+ `error: {code, message, retryable, diagnostic?}`. Device platform is correct on
47
+ success and failure. iOS target metadata carries bundle ID, PID, executable name,
48
+ process-start identity and nullable UID; Android retains its existing fields.
49
+
50
+ Capability values are backend-specific. iOS advertises supported core operations;
51
+ `evaluation`, `mutation`, `coroutines` and `native` remain false (`native` denotes
52
+ an exposed native-specific inspection capability, not LLDB's implementation).
53
+ Add iOS-only boolean `async_execution_inspection` and `async_stepping`; the former
54
+ requires the async acceptance journey below, the latter a separate demonstrated
55
+ step across suspension. False values carry explanatory limitations. No suspended
56
+ task enumeration, task identity API or logical-task reconstruction is promised.
57
+ Preserve compact mode's existing omissions and full attach/capabilities/state
58
+ responses. Unknown fields remain rejected.
59
+
60
+ ## Async semantics
61
+
62
+ Source breakpoints must work before and after a controlled Swift `await`, with
63
+ useful known primitive locals at each actual stop. Include nested child work,
64
+ actor/executor transitions and a separately triggered task cancellation path.
65
+ Use deterministic fixture gates and completion/cancellation UI state.
66
+
67
+ Stepping acknowledges delivery and resumes; only a subsequent event establishes
68
+ where execution stopped. Exercise ordinary helper into/over/out and an `await`
69
+ boundary. Delegate stepping to Swift-enabled LLDB; do not equate a physical
70
+ thread ID with stable task identity. If the tested LLDB route follows the async
71
+ continuation, report the observed source stop and advertise `async_stepping`.
72
+ Otherwise report it false with the limitation and demonstrate recovery through
73
+ independent after-await breakpoints. Unexpected missing async locals or source
74
+ stops fail core async acceptance rather than being labelled support.
75
+
76
+ Stacks describe LLDB's observed frames; label unavailable source/variable data
77
+ and generated frames honestly. Do not claim a complete logical async ancestry.
78
+ No expression evaluation, object descriptions, custom formatters that execute
79
+ code, property getters, dynamic method calls or continuation-field traversal.
80
+
81
+ ## Ownership, failure and safety
82
+
83
+ Resolve simulator, bundle executable and running PID together; validate executable
84
+ path, start identity and simulator membership before and after attach. Never attach
85
+ to an arbitrary host PID, launch a missing app or replace another debugger.
86
+ Reject identity changes and duplicate owned sessions. Serialize session mutations;
87
+ isolate sessions and guards by platform plus device, including identical IDs.
88
+
89
+ Reuse stop-scoped opaque references, the 256-event ring/100-event response limit,
90
+ 1000-frame cap, default 20/max 100 stack page, max 100 locals and 256-character
91
+ string bound. Object locals expose type/opaque identity only. Missing or
92
+ inaccessible variables are explicit; an empty list cannot prove availability.
93
+
94
+ Generalise pause guards/readiness to iOS lifecycle actions, input, waits and
95
+ assertions. Preserve device-wide conservative guarding, racing-dispatch
96
+ uncertainty and observation access within existing deadlines. Do not claim
97
+ foreground identity from debugger state.
98
+
99
+ Use a dedicated owned LLDB worker with bounded structured IPC, argument-array
100
+ subprocess calls, disabled user init files and no arbitrary command interface.
101
+ Sanitize errors using the existing bounded diagnostic catalog; iOS recovery
102
+ guidance names Xcode/LLDB rather than JDK/ADB. Never log worker messages, locals,
103
+ raw stderr, exception text or source contents. Debug inspection stays local and
104
+ request-scoped; public evidence uses only the disposable fixture.
105
+
106
+ Retain 100–30000 ms request bounds, 60-second pause, five-minute idle and
107
+ 30-minute session expiry, including independent worker watchdogs. Event-wait
108
+ cancellation preserves a usable session. Inspection timeouts preserve a known
109
+ session; uncertain attach or mutation outcomes trigger owned teardown and report
110
+ execution uncertainty. No automatic retries of attach/step/resume.
111
+
112
+ Detach releases owned suspension, breakpoints, step plans and worker resources;
113
+ never kill the app, another debugger or simulator. EOF/shutdown/expiry attempt
114
+ detach. Cleanup is idempotent and retryable with explicit remaining resources;
115
+ transport loss or forced host termination cannot imply confirmed recovery.
116
+
117
+ ## Acceptance and verification
118
+
119
+ 1. Real MCP simulator journey: attach, exact and pending source breakpoint,
120
+ stop, source stack, known locals, helper stepping, resume, removal and detach.
121
+ 2. Async journey: before/after-await locals, nested work and executor transition,
122
+ completion, cancellation recovery, and recorded boundary-step outcome.
123
+ 3. Safety: stale references, cross-session/device isolation, paused input and
124
+ readiness, cancelled event wait, process exit, attach failure, timeout,
125
+ automatic expiry and repeatable cleanup. Verify app usability after detach.
126
+ 4. Contract checks cover registration, runtime validation, dispatch, both response
127
+ modes, diagnostics and Android compatibility. Run `npm run verify`, applicable
128
+ `npm run test:device`, focused iOS MCP journeys and Android debugger regressions.
129
+ 5. Record fixture/server hashes, Xcode/LLDB/Swift/runtime versions, target UDID,
130
+ exact actions, observed values and independent UI-tree assertions. Report
131
+ physical-device and unavailable coverage as unrun, never inferred.
132
+
133
+ Likely affected areas: `src/debugger/`, debugger schemas/handlers/serialization,
134
+ iOS interaction/readiness boundaries, fixture/device/unit trees, packaging and
135
+ debugger tool documentation/README/changelog. Reuse worker/session abstractions
136
+ without routing Android through LLDB. Main risks are simulator process attribution,
137
+ LLDB/Python distribution, async metadata, source relocation and teardown races.
138
+
139
+ ## Investigation evidence and remaining prerequisites
140
+
141
+ On 2026-11-04, local version probes found the toolchain above. Sandboxed simctl
142
+ could not contact CoreSimulator; an authorised outside-sandbox read succeeded and
143
+ found no booted simulators. No existing iOS debugger implementation or live iOS
144
+ debug journey is claimed. Implementation verification requires booting an
145
+ available simulator and installing only the disposable development fixture.
146
+
147
+ Apple documents async-aware stepping since Swift 6.2 in
148
+ [What's new in Swift](https://developer.apple.com/videos/play/wwdc2025/245/).
149
+ The [LLDB SBFrame API](https://lldb.llvm.org/python_reference/lldb.SBFrame-class.html)
150
+ provides frame-variable access. These support the proposed route, not proof of
151
+ this server's behaviour; exact worker loading, attach and safe variable extraction
152
+ must be validated before claiming support. If unavailable, record the concrete
153
+ blocker and return for a scope decision rather than weakening acceptance.
@@ -0,0 +1,437 @@
1
+ {
2
+ "deviceId": "emulator-5554",
3
+ "server": "dist/server.js",
4
+ "server_sha256": "49fa8b8969b5f6bae270c56912b3b1259edb400087b551538dcf0b45855aae34",
5
+ "runtime": "v23.11.0",
6
+ "observations": [
7
+ {
8
+ "tool": "get_app_readiness",
9
+ "args": {},
10
+ "result": {
11
+ "success": true,
12
+ "device": {
13
+ "platform": "android",
14
+ "id": "emulator-5554",
15
+ "osVersion": "16",
16
+ "model": "sdk_gphone64_arm64",
17
+ "simulator": true,
18
+ "appInstalled": false
19
+ },
20
+ "readiness": {
21
+ "state": "settled",
22
+ "scope": "device_ui",
23
+ "basis": "observed",
24
+ "captured_at_ms": 1793824169556,
25
+ "snapshot_session_id": "760cfc72-9c17-4855-8a9e-4491f35284c1",
26
+ "snapshot_revision": 1,
27
+ "sample_count": 2,
28
+ "stable_for_ms": 2774.727875,
29
+ "evidence": [
30
+ {
31
+ "code": "INSUFFICIENT_SAMPLES",
32
+ "source": "ui_tree",
33
+ "captured_at_ms": 1793824166781,
34
+ "snapshot_revision": 1
35
+ },
36
+ {
37
+ "code": "SNAPSHOT_STABLE",
38
+ "source": "ui_tree",
39
+ "captured_at_ms": 1793824169556,
40
+ "snapshot_revision": 1
41
+ }
42
+ ],
43
+ "limitations": [
44
+ "NORMALIZED_UI_ONLY",
45
+ "FOREGROUND_APP_UNVERIFIED",
46
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
47
+ "MANAGED_DEBUGGER_ONLY"
48
+ ],
49
+ "capabilities": {
50
+ "loading": true,
51
+ "transitioning": true,
52
+ "settled": true,
53
+ "unresponsive": false,
54
+ "debugger_paused": true
55
+ }
56
+ },
57
+ "device_readiness": {
58
+ "wakefulness": "awake",
59
+ "lock_state": "unlocked",
60
+ "input_ready": null,
61
+ "blockers": [],
62
+ "evidence": [
63
+ {
64
+ "code": "DEVICE_AWAKE",
65
+ "source": "android_power",
66
+ "captured_at_ms": 1793824167338
67
+ },
68
+ {
69
+ "code": "DEVICE_UNLOCKED",
70
+ "source": "android_window",
71
+ "captured_at_ms": 1793824167382
72
+ }
73
+ ],
74
+ "limitations": []
75
+ },
76
+ "elapsed_ms": 5454.18075
77
+ }
78
+ },
79
+ {
80
+ "tool": "get_app_readiness",
81
+ "args": {},
82
+ "result": {
83
+ "success": true,
84
+ "device": {
85
+ "platform": "android",
86
+ "id": "emulator-5554",
87
+ "osVersion": "16",
88
+ "model": "sdk_gphone64_arm64",
89
+ "simulator": true,
90
+ "appInstalled": false
91
+ },
92
+ "readiness": {
93
+ "state": "unknown",
94
+ "scope": "device_ui",
95
+ "basis": "insufficient",
96
+ "captured_at_ms": null,
97
+ "sample_count": 0,
98
+ "stable_for_ms": 0,
99
+ "snapshot_session_id": null,
100
+ "snapshot_revision": null,
101
+ "evidence": [],
102
+ "limitations": [
103
+ "NORMALIZED_UI_ONLY",
104
+ "FOREGROUND_APP_UNVERIFIED",
105
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
106
+ "MANAGED_DEBUGGER_ONLY",
107
+ "INSUFFICIENT_SAMPLES",
108
+ "DEVICE_BLOCKED"
109
+ ],
110
+ "capabilities": {
111
+ "loading": true,
112
+ "transitioning": true,
113
+ "settled": true,
114
+ "unresponsive": false,
115
+ "debugger_paused": true
116
+ }
117
+ },
118
+ "device_readiness": {
119
+ "wakefulness": "asleep",
120
+ "lock_state": "unlocked",
121
+ "input_ready": false,
122
+ "blockers": [
123
+ "DEVICE_ASLEEP"
124
+ ],
125
+ "evidence": [
126
+ {
127
+ "code": "DEVICE_ASLEEP",
128
+ "source": "android_power",
129
+ "captured_at_ms": 1793824170627
130
+ },
131
+ {
132
+ "code": "DEVICE_UNLOCKED",
133
+ "source": "android_window",
134
+ "captured_at_ms": 1793824170662
135
+ }
136
+ ],
137
+ "limitations": []
138
+ },
139
+ "elapsed_ms": 1055.0427499999996
140
+ }
141
+ },
142
+ {
143
+ "tool": "start_app",
144
+ "args": {
145
+ "appId": "com.android.settings",
146
+ "verificationMode": "none",
147
+ "responseMode": "compact",
148
+ "actionTimeoutMs": 10000
149
+ },
150
+ "result": {
151
+ "action_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
152
+ "device_readiness": {
153
+ "wakefulness": "asleep",
154
+ "lock_state": "unlocked",
155
+ "input_ready": false,
156
+ "blockers": [
157
+ "DEVICE_ASLEEP"
158
+ ],
159
+ "evidence": [
160
+ {
161
+ "code": "DEVICE_ASLEEP",
162
+ "source": "android_power",
163
+ "captured_at_ms": 1793824171199
164
+ },
165
+ {
166
+ "code": "DEVICE_UNLOCKED",
167
+ "source": "android_window",
168
+ "captured_at_ms": 1793824171242
169
+ }
170
+ ],
171
+ "limitations": []
172
+ },
173
+ "action_type": "start_app",
174
+ "success": true,
175
+ "lifecycle_state": "pending_verification",
176
+ "delivery_status": "delivered",
177
+ "dispatch_started": true,
178
+ "verification": {
179
+ "mode": "none",
180
+ "status": "not_requested"
181
+ },
182
+ "timing": {
183
+ "total_ms": 579.8293329999997
184
+ },
185
+ "evidence": {
186
+ "session_id": "fe501f9e-b707-4763-854c-4a1c81931fe1",
187
+ "correlation_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
188
+ "action_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
189
+ "device": {
190
+ "platform": "android",
191
+ "id": "emulator-5554"
192
+ },
193
+ "association": "self",
194
+ "association_reason": null,
195
+ "operation_started_at_ms": 1793824170663,
196
+ "operation_completed_at_ms": 1793824171242,
197
+ "dispatch_started_at_ms": 1793824170713,
198
+ "dispatch_completed_at_ms": 1793824171015,
199
+ "verification_completed_at_ms": null,
200
+ "observations": [
201
+ {
202
+ "evidence_id": "2d8052cc-f6f2-4f77-98e9-ff1ca0f2e3a5",
203
+ "kind": "activity",
204
+ "status": "captured",
205
+ "capture_started_at_ms": 1793824171015,
206
+ "capture_completed_at_ms": 1793824171135,
207
+ "source_captured_at_ms": 1793824171135,
208
+ "age_ms": 106.934326171875,
209
+ "freshness": "fresh",
210
+ "freshness_reasons": [],
211
+ "device": {
212
+ "platform": "android",
213
+ "id": "emulator-5554"
214
+ },
215
+ "session_id": "fe501f9e-b707-4763-854c-4a1c81931fe1",
216
+ "correlation_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
217
+ "action_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
218
+ "association": "internal"
219
+ }
220
+ ],
221
+ "trace_context": {
222
+ "supported": false,
223
+ "trace_id": null,
224
+ "markers": []
225
+ }
226
+ }
227
+ }
228
+ },
229
+ {
230
+ "tool": "wait_for_app_ready",
231
+ "args": {
232
+ "timeoutMs": 1200,
233
+ "pollIntervalMs": 100
234
+ },
235
+ "result": {
236
+ "success": false,
237
+ "device": {
238
+ "platform": "android",
239
+ "id": "emulator-5554",
240
+ "osVersion": "16",
241
+ "model": "sdk_gphone64_arm64",
242
+ "simulator": true,
243
+ "appInstalled": false
244
+ },
245
+ "readiness": {
246
+ "state": "unknown",
247
+ "scope": "device_ui",
248
+ "basis": "insufficient",
249
+ "captured_at_ms": null,
250
+ "sample_count": 0,
251
+ "stable_for_ms": 0,
252
+ "snapshot_session_id": null,
253
+ "snapshot_revision": null,
254
+ "evidence": [],
255
+ "limitations": [
256
+ "NORMALIZED_UI_ONLY",
257
+ "FOREGROUND_APP_UNVERIFIED",
258
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
259
+ "MANAGED_DEBUGGER_ONLY",
260
+ "INSUFFICIENT_SAMPLES",
261
+ "DEVICE_BLOCKED",
262
+ "DEADLINE_EXCEEDED"
263
+ ],
264
+ "capabilities": {
265
+ "loading": true,
266
+ "transitioning": true,
267
+ "settled": true,
268
+ "unresponsive": false,
269
+ "debugger_paused": true
270
+ }
271
+ },
272
+ "device_readiness": {
273
+ "wakefulness": "unknown",
274
+ "lock_state": "unknown",
275
+ "input_ready": null,
276
+ "blockers": [],
277
+ "evidence": [],
278
+ "limitations": [
279
+ "DEVICE_POWER_OBSERVATION_FAILED",
280
+ "DEVICE_LOCK_OBSERVATION_FAILED"
281
+ ]
282
+ },
283
+ "elapsed_ms": 1245.8765839999996,
284
+ "failure_code": "READINESS_TIMEOUT"
285
+ }
286
+ },
287
+ {
288
+ "tool": "get_app_readiness",
289
+ "args": {},
290
+ "result": {
291
+ "success": true,
292
+ "device": {
293
+ "platform": "android",
294
+ "id": "emulator-5554",
295
+ "osVersion": "16",
296
+ "model": "sdk_gphone64_arm64",
297
+ "simulator": true,
298
+ "appInstalled": false
299
+ },
300
+ "readiness": {
301
+ "state": "settled",
302
+ "scope": "device_ui",
303
+ "basis": "observed",
304
+ "captured_at_ms": 1793824178604,
305
+ "snapshot_session_id": "760cfc72-9c17-4855-8a9e-4491f35284c1",
306
+ "snapshot_revision": 2,
307
+ "sample_count": 2,
308
+ "stable_for_ms": 2779.1579999999994,
309
+ "evidence": [
310
+ {
311
+ "code": "INSUFFICIENT_SAMPLES",
312
+ "source": "ui_tree",
313
+ "captured_at_ms": 1793824175825,
314
+ "snapshot_revision": 2
315
+ },
316
+ {
317
+ "code": "SNAPSHOT_STABLE",
318
+ "source": "ui_tree",
319
+ "captured_at_ms": 1793824178604,
320
+ "snapshot_revision": 2
321
+ }
322
+ ],
323
+ "limitations": [
324
+ "NORMALIZED_UI_ONLY",
325
+ "FOREGROUND_APP_UNVERIFIED",
326
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
327
+ "MANAGED_DEBUGGER_ONLY"
328
+ ],
329
+ "capabilities": {
330
+ "loading": true,
331
+ "transitioning": true,
332
+ "settled": true,
333
+ "unresponsive": false,
334
+ "debugger_paused": true
335
+ }
336
+ },
337
+ "device_readiness": {
338
+ "wakefulness": "awake",
339
+ "lock_state": "unlocked",
340
+ "input_ready": null,
341
+ "blockers": [],
342
+ "evidence": [
343
+ {
344
+ "code": "DEVICE_AWAKE",
345
+ "source": "android_power",
346
+ "captured_at_ms": 1793824176383
347
+ },
348
+ {
349
+ "code": "DEVICE_UNLOCKED",
350
+ "source": "android_window",
351
+ "captured_at_ms": 1793824176424
352
+ }
353
+ ],
354
+ "limitations": []
355
+ },
356
+ "elapsed_ms": 6075.207875
357
+ }
358
+ },
359
+ {
360
+ "tool": "wait_for_app_ready",
361
+ "args": {
362
+ "timeoutMs": 15000,
363
+ "stabilityMs": 100,
364
+ "pollIntervalMs": 100
365
+ },
366
+ "result": {
367
+ "success": true,
368
+ "device": {
369
+ "platform": "android",
370
+ "id": "emulator-5554",
371
+ "osVersion": "16",
372
+ "model": "sdk_gphone64_arm64",
373
+ "simulator": true,
374
+ "appInstalled": false
375
+ },
376
+ "readiness": {
377
+ "state": "settled",
378
+ "scope": "device_ui",
379
+ "basis": "observed",
380
+ "captured_at_ms": 1793824183495,
381
+ "snapshot_session_id": "760cfc72-9c17-4855-8a9e-4491f35284c1",
382
+ "snapshot_revision": 2,
383
+ "sample_count": 2,
384
+ "stable_for_ms": 2404.0407909999994,
385
+ "evidence": [
386
+ {
387
+ "code": "INSUFFICIENT_SAMPLES",
388
+ "source": "ui_tree",
389
+ "captured_at_ms": 1793824181091,
390
+ "snapshot_revision": 2
391
+ },
392
+ {
393
+ "code": "SNAPSHOT_STABLE",
394
+ "source": "ui_tree",
395
+ "captured_at_ms": 1793824183495,
396
+ "snapshot_revision": 2
397
+ }
398
+ ],
399
+ "limitations": [
400
+ "NORMALIZED_UI_ONLY",
401
+ "FOREGROUND_APP_UNVERIFIED",
402
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
403
+ "MANAGED_DEBUGGER_ONLY"
404
+ ],
405
+ "capabilities": {
406
+ "loading": true,
407
+ "transitioning": true,
408
+ "settled": true,
409
+ "unresponsive": false,
410
+ "debugger_paused": true
411
+ }
412
+ },
413
+ "device_readiness": {
414
+ "wakefulness": "awake",
415
+ "lock_state": "unlocked",
416
+ "input_ready": null,
417
+ "blockers": [],
418
+ "evidence": [
419
+ {
420
+ "code": "DEVICE_AWAKE",
421
+ "source": "android_power",
422
+ "captured_at_ms": 1793824181241
423
+ },
424
+ {
425
+ "code": "DEVICE_UNLOCKED",
426
+ "source": "android_window",
427
+ "captured_at_ms": 1793824181281
428
+ }
429
+ ],
430
+ "limitations": []
431
+ },
432
+ "elapsed_ms": 4855.992333
433
+ }
434
+ }
435
+ ],
436
+ "cleanup": "wake, dismiss disposable keyguard, Home; no security settings changed"
437
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "device": {
3
+ "platform": "android",
4
+ "id": "adb-51181FDAP0031Y-gxy7FO._adb-tls-connect._tcp"
5
+ },
6
+ "model": "Pixel 9 Pro",
7
+ "osVersion": "Android 17",
8
+ "runtime": "v23.11.0",
9
+ "scope": "read-only current state; no sleep/lock/unlock/input dispatched",
10
+ "result": {
11
+ "wakefulness": "unknown",
12
+ "lock_state": "locked",
13
+ "input_ready": false,
14
+ "blockers": [
15
+ "DEVICE_LOCKED"
16
+ ],
17
+ "evidence": [
18
+ {
19
+ "code": "DEVICE_LOCKED",
20
+ "source": "android_window",
21
+ "captured_at_ms": 1793824059095
22
+ }
23
+ ],
24
+ "limitations": [
25
+ "DEVICE_WAKEFULNESS_UNVERIFIED"
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "device": {
3
+ "platform": "android",
4
+ "id": "adb-51181FDAP0031Y-gxy7FO._adb-tls-connect._tcp"
5
+ },
6
+ "model": "Pixel 9 Pro",
7
+ "osVersion": "Android 17",
8
+ "runtime": "v23.11.0",
9
+ "scope": "read-only current state; main Power Manager State section; no input dispatched",
10
+ "result": {
11
+ "wakefulness": "awake",
12
+ "lock_state": "unlocked",
13
+ "input_ready": null,
14
+ "blockers": [],
15
+ "evidence": [
16
+ {
17
+ "code": "DEVICE_AWAKE",
18
+ "source": "android_power",
19
+ "captured_at_ms": 1793824124380
20
+ },
21
+ {
22
+ "code": "DEVICE_UNLOCKED",
23
+ "source": "android_window",
24
+ "captured_at_ms": 1793824124492
25
+ }
26
+ ],
27
+ "limitations": []
28
+ }
29
+ }
@@ -0,0 +1,41 @@
1
+ # Intent: device readiness blockers
2
+
3
+ Status: intent and revised specification approved; implementation authorised.
4
+ Originator: clivejefferies, GitHub issue #101, created 2026-11-04.
5
+ Captured: 2026-11-04.
6
+ Source: https://github.com/clivejefferies/mobile-debug-tools/issues/101
7
+
8
+ ## Problem
9
+
10
+ Recent agent feedback reports that a successful app launch left the agent
11
+ inspecting a sleeping or locked phone. Existing app readiness signals (#65)
12
+ need to distinguish launch dispatch from an app observed to be visible and
13
+ ready for input.
14
+
15
+ ## Desired outcome and scope
16
+
17
+ Extend existing launch, readiness, and relevant interaction results so MCP
18
+ clients can identify device-level readiness blockers on Android and iOS.
19
+ Report sleeping or locked states only when supported evidence establishes
20
+ them; otherwise expose explicit unknown or unsupported outcomes. Include
21
+ evidence timestamps and coordinate with existing debugger-paused reporting.
22
+
23
+ Success means launch dispatch alone cannot imply visibility or input readiness,
24
+ and supported awake/unlocked, sleeping, locked, transitioning, and debugger-paused
25
+ flows have recorded verification. Distinguish Android and iOS evidence and record
26
+ any inaccessible scenarios. Reproduce the reported flow where practical.
27
+
28
+ ## Constraints and questions
29
+
30
+ Preserve bounded waits, device targeting, and existing action contracts unless a
31
+ compatibility change is explicitly approved. Do not automatically unlock devices
32
+ or change security settings. New diagnostic capabilities are outside scope.
33
+
34
+ Investigation must establish which device states each platform can reliably
35
+ observe, which existing results need the evidence, and how stale or conflicting
36
+ observations should be represented. These decisions belong in the specification.
37
+
38
+ ## Approval
39
+
40
+ User approved this problem and scope with “ok” in the current chat on 2026-11-04,
41
+ in response to the captured intent and explicit intent-approval question.