mobile-debug-mcp 0.30.1 → 0.31.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 (60) hide show
  1. package/README.md +50 -5
  2. package/dist/interact/index.js +546 -133
  3. package/dist/manage/ios.js +1 -1
  4. package/dist/server/tool-definitions.js +13 -9
  5. package/dist/server/tool-handlers.js +4 -4
  6. package/dist/server-core.js +1 -1
  7. package/dist/system/index.js +485 -48
  8. package/dist/system/ios.js +15 -7
  9. package/dist/utils/android/utils.js +4 -4
  10. package/dist/utils/cli/idb/check-idb.js +10 -3
  11. package/dist/utils/cli/idb/idb-helper.js +47 -13
  12. package/dist/utils/ios/utils.js +5 -9
  13. package/docs/CHANGELOG.md +6 -0
  14. package/docs/ROADMAP.md +88 -212
  15. package/docs/specs/baseline-spec-v0.md +1 -1
  16. package/docs/specs-deltas/015-adjustable-control-support.md +541 -0
  17. package/docs/specs-deltas/016-environment-tools.md +533 -0
  18. package/docs/tools/TOOLS.md +2 -0
  19. package/docs/tools/manage.md +4 -2
  20. package/docs/tools/system.md +9 -2
  21. package/package.json +1 -1
  22. package/skills/spec-review/SKILL.md +52 -0
  23. package/skills/spec-review/references/spec-review-checklist.md +13 -0
  24. package/skills/spec-review/references/spec-review-template.md +28 -0
  25. package/src/interact/index.ts +581 -138
  26. package/src/manage/ios.ts +1 -1
  27. package/src/server/tool-definitions.ts +13 -9
  28. package/src/server/tool-handlers.ts +4 -4
  29. package/src/server-core.ts +1 -1
  30. package/src/system/index.ts +572 -50
  31. package/src/system/ios.ts +14 -7
  32. package/src/types.ts +2 -0
  33. package/src/utils/android/utils.ts +3 -3
  34. package/src/utils/cli/idb/check-idb.ts +11 -2
  35. package/src/utils/cli/idb/idb-helper.ts +49 -12
  36. package/src/utils/ios/utils.ts +4 -8
  37. package/test/unit/interact/adjust_control.test.ts +586 -33
  38. package/test/unit/interact/tap_element.test.ts +1 -1
  39. package/test/unit/server/contract.test.ts +4 -0
  40. package/test/unit/system/get_system_status.test.ts +3 -0
  41. package/test/unit/system/system_status.test.ts +40 -0
  42. package/test/unit/utils/idb_health.test.ts +74 -0
  43. package/skills/rfc-review/SKILL.md +0 -52
  44. package/skills/rfc-review/references/rfc-review-checklist.md +0 -12
  45. package/skills/rfc-review/references/rfc-review-template.md +0 -28
  46. /package/docs/{rfcs → specs-deltas}/001-state-verification.md +0 -0
  47. /package/docs/{rfcs → specs-deltas}/002-richer-element-identity +0 -0
  48. /package/docs/{rfcs → specs-deltas}/003-wait-and-synchronization-reliability.md +0 -0
  49. /package/docs/{rfcs → specs-deltas}/004-action-verification-routing.md +0 -0
  50. /package/docs/{rfcs → specs-deltas}/005-unified-action-execution-and-verification-model.md +0 -0
  51. /package/docs/{rfcs → specs-deltas}/006-runtime-action-instrumentation-and-binding-layer.md +0 -0
  52. /package/docs/{rfcs → specs-deltas}/007-actionability-resolution-and-executable-target-selection.md +0 -0
  53. /package/docs/{rfcs → specs-deltas}/008-adjustable-control-support-and-semantic-value-manipulation.md +0 -0
  54. /package/docs/{rfcs → specs-deltas}/009-semantic-control-modeling-for-custom-and-composite-controls.md +0 -0
  55. /package/docs/{rfcs → specs-deltas}/010-verification-stabilization-and-temporal-convergence.md +0 -0
  56. /package/docs/{rfcs → specs-deltas}/011-recovery-and-replanning-for-failed-or-ambiguous-interaction-flows.md +0 -0
  57. /package/docs/{rfcs → specs-deltas}/011.1-recovery-contract-types-and-runtime-wiring-spec.md +0 -0
  58. /package/docs/{rfcs → specs-deltas}/012-action-trace-and-xecution-observability.md +0 -0
  59. /package/docs/{rfcs → specs-deltas}/013-wait-and-synchronization-reliability.md +0 -0
  60. /package/docs/{rfcs → specs-deltas}/014-actionability-resolution.md +0 -0
@@ -70,6 +70,10 @@ async function run() {
70
70
  const adjustControl = toolDefinitions.find((tool) => tool.name === 'adjust_control')
71
71
  assert(adjustControl, 'adjust_control should be registered')
72
72
  assert.deepStrictEqual((adjustControl as any).inputSchema.required, ['targetValue'])
73
+ assert.deepStrictEqual((adjustControl as any).inputSchema.oneOf, [
74
+ { required: ['selector'] },
75
+ { required: ['element_id'] }
76
+ ])
73
77
  assert.strictEqual((adjustControl as any).inputSchema.properties.targetValue.type, 'number')
74
78
  assert.match((adjustControl as any).description, /numeric control value/i)
75
79
  assert.match((adjustControl as any).description, /expect_state/i)
@@ -9,6 +9,9 @@ async function run() {
9
9
  assert(typeof (payload as any).status === 'string')
10
10
  assert(Array.isArray(payload.issues))
11
11
  assert((payload as any).summary && typeof (payload as any).summary.overall === 'string')
12
+ assert((payload as any).host && typeof (payload as any).host.os === 'string')
13
+ assert((payload as any).android && typeof (payload as any).android.status === 'string')
14
+ assert((payload as any).ios && typeof (payload as any).ios.status === 'string')
12
15
 
13
16
  const adb = ensureAdbAvailable()
14
17
  assert(adb && typeof adb.ok === 'boolean')
@@ -74,6 +74,7 @@ async function run() {
74
74
  XCRUN_VERSION_OUTPUT: process.env.XCRUN_VERSION_OUTPUT,
75
75
  XCRUN_VERSION_STATUS: process.env.XCRUN_VERSION_STATUS,
76
76
  SIMCTL_LIST_OUTPUT: process.env.SIMCTL_LIST_OUTPUT,
77
+ MOBILE_DEBUG_MCP_HOST_OS: process.env.MOBILE_DEBUG_MCP_HOST_OS,
77
78
  }
78
79
 
79
80
  try {
@@ -82,6 +83,7 @@ async function run() {
82
83
  process.env.XCRUN_PATH = xcrunPath
83
84
 
84
85
  setScenario({
86
+ MOBILE_DEBUG_MCP_HOST_OS: 'darwin',
85
87
  ADB_VERSION_STATUS: '0',
86
88
  ADB_VERSION_OUTPUT: '8.1.0\n',
87
89
  ADB_DEVICES_OUTPUT: 'List of devices attached\nemulator-5554\tdevice product:sdk\n',
@@ -94,12 +96,16 @@ async function run() {
94
96
  const healthy = await systemStatus.getSystemStatus()
95
97
  assert.strictEqual(healthy.success, true)
96
98
  assert.strictEqual((healthy as any).status, 'ready')
99
+ assert.strictEqual((healthy as any).host.supported, true)
97
100
  assert.strictEqual(healthy.adbAvailable, true)
98
101
  assert.strictEqual(typeof healthy.adbVersion, 'string')
102
+ assert.strictEqual((healthy as any).android.status, 'ready')
103
+ assert.strictEqual((healthy as any).ios.status, 'ready')
99
104
  assert.strictEqual((healthy as any).summary.android.ready, true)
100
105
  assert.strictEqual(typeof (healthy as any).summary.ios.summary, 'string')
101
106
 
102
107
  setScenario({
108
+ MOBILE_DEBUG_MCP_HOST_OS: 'darwin',
103
109
  ADB_VERSION_STATUS: '1',
104
110
  ADB_VERSION_OUTPUT: 'not found',
105
111
  ADB_DEVICES_OUTPUT: 'List of devices attached\n',
@@ -112,6 +118,7 @@ async function run() {
112
118
  assert(missingAdb.issues.some((issue: string) => issue.includes('ADB')))
113
119
 
114
120
  setScenario({
121
+ MOBILE_DEBUG_MCP_HOST_OS: 'darwin',
115
122
  ADB_VERSION_STATUS: '0',
116
123
  ADB_VERSION_OUTPUT: '8.1.0\n',
117
124
  ADB_DEVICES_OUTPUT: 'List of devices attached\nserial1\tunauthorized\nserial2\toffline\n',
@@ -125,6 +132,7 @@ async function run() {
125
132
  assert(unauthorized.issues.some((issue: string) => issue.includes('offline')))
126
133
 
127
134
  setScenario({
135
+ MOBILE_DEBUG_MCP_HOST_OS: 'darwin',
128
136
  ADB_VERSION_STATUS: '0',
129
137
  ADB_VERSION_OUTPUT: '8.1.0\n',
130
138
  ADB_DEVICES_OUTPUT: 'List of devices attached\nemulator-5554\tdevice product:sdk\n',
@@ -136,6 +144,38 @@ async function run() {
136
144
  assert.strictEqual(missingXcrun.adbAvailable, true)
137
145
  assert.strictEqual(Array.isArray(missingXcrun.issues), true)
138
146
  assert.strictEqual((missingXcrun as any).summary.ios.ready, false)
147
+ assert.strictEqual((missingXcrun as any).ios.status, 'unavailable')
148
+
149
+ setScenario({
150
+ MOBILE_DEBUG_MCP_HOST_OS: 'win32',
151
+ ADB_VERSION_STATUS: '0',
152
+ ADB_VERSION_OUTPUT: '8.1.0\n',
153
+ ADB_DEVICES_OUTPUT: 'List of devices attached\nemulator-5554\tdevice product:sdk\n',
154
+ XCRUN_VERSION_STATUS: '1',
155
+ XCRUN_VERSION_OUTPUT: 'not found',
156
+ })
157
+ const windowsHost = await systemStatus.getSystemStatus()
158
+ assert.strictEqual((windowsHost as any).host.os, 'windows')
159
+ assert.strictEqual((windowsHost as any).host.supported, true)
160
+ assert.strictEqual((windowsHost as any).ios.status, 'unsupported')
161
+ assert.deepStrictEqual((windowsHost as any).ios.tools, {})
162
+ assert.deepStrictEqual((windowsHost as any).ios.providers, {})
163
+ assert.deepStrictEqual((windowsHost as any).ios.capabilities, {})
164
+ assert.deepStrictEqual((windowsHost as any).ios.devices, [])
165
+ assert.strictEqual((windowsHost as any).ios.failures[0].code, 'PLATFORM_UNAVAILABLE')
166
+ assert.strictEqual((windowsHost as any).summary.ios.ready, false)
167
+
168
+ setScenario({ MOBILE_DEBUG_MCP_HOST_OS: 'freebsd' })
169
+ const unsupported = await systemStatus.getSystemStatus()
170
+ assert.strictEqual((unsupported as any).host.os, 'freebsd')
171
+ assert.strictEqual((unsupported as any).host.supported, false)
172
+ assert.strictEqual((unsupported as any).android.status, 'unsupported')
173
+ assert.strictEqual((unsupported as any).ios.status, 'unsupported')
174
+ assert.strictEqual((unsupported as any).android.failures[0].code, 'HOST_OS_UNSUPPORTED')
175
+ assert.strictEqual((unsupported as any).ios.failures[0].code, 'HOST_OS_UNSUPPORTED')
176
+ assert.strictEqual(unsupported.adbAvailable, false)
177
+ assert.strictEqual(unsupported.iosAvailable, false)
178
+ assert.strictEqual((unsupported as any).summary.overall, 'blocked')
139
179
 
140
180
  console.log('system_status checks passed')
141
181
  } finally {
@@ -0,0 +1,74 @@
1
+ import assert from 'assert'
2
+ import fs from 'fs/promises'
3
+ import os from 'os'
4
+ import path from 'path'
5
+
6
+ import { isIDBInstalled, probeIdb } from '../../../src/utils/cli/idb/idb-helper.js'
7
+
8
+ async function run() {
9
+ const binDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-idb-health-'))
10
+ const idbPath = path.join(binDir, 'idb')
11
+ const python3Path = path.join(binDir, 'python3')
12
+ const pythonPath = path.join(binDir, 'python')
13
+ const pythonLog = path.join(binDir, 'python.log')
14
+ const originalIdbPath = process.env.MCP_IDB_PATH
15
+ const originalPath = process.env.PATH
16
+
17
+ try {
18
+ await fs.writeFile(idbPath, `#!/bin/sh
19
+ if [ "$1" = "list-targets" ] && [ "$2" = "--json" ]; then
20
+ printf '{"targets":[]}\n'
21
+ exit 0
22
+ fi
23
+ if [ "$1" = "--version" ]; then
24
+ printf 'idb: error: unrecognized arguments: --version\n' >&2
25
+ exit 2
26
+ fi
27
+ exit 0
28
+ `, { mode: 0o755 })
29
+
30
+ await fs.writeFile(python3Path, `#!/bin/sh
31
+ printf 'python3 called\\n' >> "${pythonLog}"
32
+ exit 0
33
+ `, { mode: 0o755 })
34
+
35
+ await fs.writeFile(pythonPath, `#!/bin/sh
36
+ printf 'python called\\n' >> "${pythonLog}"
37
+ exit 0
38
+ `, { mode: 0o755 })
39
+
40
+ process.env.MCP_IDB_PATH = idbPath
41
+ process.env.PATH = `${binDir}${path.delimiter}${originalPath || ''}`
42
+
43
+ const probe = probeIdb(idbPath)
44
+ assert.strictEqual(probe.ok, true)
45
+ assert.strictEqual(isIDBInstalled(), true)
46
+ assert(probe.raw === null || typeof probe.raw === 'string')
47
+
48
+ await fs.rm(pythonLog, { force: true }).catch(() => {})
49
+ const failedIdbPath = path.join(binDir, 'idb-failing')
50
+ await fs.writeFile(failedIdbPath, `#!/bin/sh
51
+ if [ "$1" = "list-targets" ] && [ "$2" = "--json" ]; then
52
+ printf 'idb unavailable\\n' >&2
53
+ exit 2
54
+ fi
55
+ exit 2
56
+ `, { mode: 0o755 })
57
+
58
+ const failureProbe = probeIdb(failedIdbPath)
59
+ assert.strictEqual(failureProbe.ok, false)
60
+ assert.strictEqual(await fs.readFile(pythonLog, 'utf8').catch(() => ''), '')
61
+
62
+ console.log('idb health probe test passed')
63
+ } finally {
64
+ if (originalIdbPath === undefined) delete process.env.MCP_IDB_PATH
65
+ else process.env.MCP_IDB_PATH = originalIdbPath
66
+
67
+ if (originalPath === undefined) delete process.env.PATH
68
+ else process.env.PATH = originalPath
69
+
70
+ await fs.rm(binDir, { recursive: true, force: true }).catch(() => {})
71
+ }
72
+ }
73
+
74
+ run().catch((error) => { console.error(error); process.exit(1) })
@@ -1,52 +0,0 @@
1
- # RFC Review skill
2
-
3
- name: rfc-review
4
- version: 0.1.1
5
- summary: Reusable workflow for reviewing RFCs/specs in this repository with a consistent readiness rubric and output template.
6
-
7
- # Purpose
8
- Help an agent review an RFC for clarity, implementation readiness, and alignment with the current codebase. Use a common template so reviews stay consistent across documents and reviewers.
9
-
10
- # Activation conditions
11
- Activate when an agent needs to:
12
- - review a new or revised RFC
13
- - assess whether an RFC is implementation-ready
14
- - identify whether feedback is an RFC issue or an implementation issue
15
- - compare a spec against the current `src/` contract surface and docs
16
-
17
- # Surface area (actions)
18
- - locate-rfc
19
- - compare-against-code
20
- - assess-contract-completeness
21
- - classify-gaps
22
- - produce-review
23
-
24
- # Core guidance
25
- 1. Read the RFC first, then compare it against the relevant code, docs, and tests.
26
- 2. Separate **spec gaps** from **implementation gaps**.
27
- 3. Check for: problem clarity, scope boundaries, explicit contracts, acceptance criteria, non-goals, and consistency with existing behavior.
28
- 4. Prefer precise feedback that names the missing contract, unclear rule, or inconsistent behavior.
29
- 5. Use the shared review template in `references/rfc-review-template.md` for the final output.
30
- 6. If the RFC is not ready, say exactly what must be clarified before implementation can start.
31
- 7. Classify each blocker as either a **spec gap** or an **implementation contract gap** and stop at that boundary.
32
-
33
- # Inputs & outputs
34
- - review-rfc(input: { rfcPath, relatedPaths?, focusAreas? }) -> { verdict, risks, specGaps, implementationGaps, recommendations }
35
- - compare-against-code(input: { rfcPath, codePaths[] }) -> { matches, mismatches, notes }
36
- - produce-review(input: { rfcPath, findings[] }) -> { summary, verdict, checklist, nextStep }
37
-
38
- # Failure handling
39
- - If the RFC file is missing, stop and report the missing path explicitly.
40
- - If the RFC is ambiguous, classify each concern as either "spec" or "implementation" instead of blending them.
41
- - If the review cannot be grounded in the current repo, state that the RFC is not reviewable yet.
42
-
43
- # Progressive disclosure
44
- - Keep this file short.
45
- - Load the reference template only when writing the final review.
46
-
47
- # References
48
- - `references/rfc-review-template.md` — standard review format and verdict rubric
49
- - `references/rfc-review-checklist.md` — questions to apply while reviewing an RFC
50
-
51
- # License
52
- Same as repository (MIT).
@@ -1,12 +0,0 @@
1
- # RFC Review Checklist
2
-
3
- Ask these questions while reviewing:
4
-
5
- 1. Is the problem statement specific and grounded in current failures?
6
- 2. Are non-goals explicit?
7
- 3. Are contracts concrete enough to implement?
8
- 4. Are acceptance criteria testable?
9
- 5. Does the RFC define the source of truth for new fields or behaviors?
10
- 6. Does it match existing code paths and public tool surfaces?
11
- 7. Can each open concern be classified as a spec issue or an implementation issue?
12
- 8. Is the RFC ready to implement without further interpretation?
@@ -1,28 +0,0 @@
1
- # RFC Review Template
2
-
3
- Use this structure for every RFC review:
4
-
5
- ## Verdict
6
- - Ready / Needs clarification / Needs implementation contract / Not ready
7
-
8
- ## Summary
9
- - One short paragraph on the RFC's current quality.
10
-
11
- ## What is good
12
- - List the strongest parts of the RFC.
13
-
14
- ## Issues
15
- For each issue, include:
16
- - **Type:** spec / implementation / implementation contract / doc
17
- - **Severity:** low / medium / high
18
- - **Why it matters:** one sentence
19
- - **Fix:** exact change needed
20
-
21
- ## Missing contract surfaces
22
- - List any API shapes, response fields, state transitions, or invariants that are still undefined.
23
-
24
- ## Codebase alignment
25
- - Note whether the RFC matches current `src/`, docs, and tests.
26
-
27
- ## Next step
28
- - State the smallest next action needed to move the RFC forward.