@metamask/device-mcp 0.1.0 → 0.2.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 (110) hide show
  1. package/CHANGELOG.md +9 -14
  2. package/LICENSE +6 -0
  3. package/LICENSE.APACHE2 +201 -0
  4. package/LICENSE.MIT +21 -0
  5. package/README.md +61 -33
  6. package/dist/backends/adb-backend.cjs +9 -0
  7. package/dist/backends/adb-backend.cjs.map +1 -1
  8. package/dist/backends/adb-backend.d.cts +1 -0
  9. package/dist/backends/adb-backend.d.cts.map +1 -1
  10. package/dist/backends/adb-backend.d.mts +1 -0
  11. package/dist/backends/adb-backend.d.mts.map +1 -1
  12. package/dist/backends/adb-backend.mjs +9 -0
  13. package/dist/backends/adb-backend.mjs.map +1 -1
  14. package/dist/backends/appium-backend.cjs +9 -0
  15. package/dist/backends/appium-backend.cjs.map +1 -1
  16. package/dist/backends/appium-backend.d.cts +1 -0
  17. package/dist/backends/appium-backend.d.cts.map +1 -1
  18. package/dist/backends/appium-backend.d.mts +1 -0
  19. package/dist/backends/appium-backend.d.mts.map +1 -1
  20. package/dist/backends/appium-backend.mjs +9 -0
  21. package/dist/backends/appium-backend.mjs.map +1 -1
  22. package/dist/backends/idb-backend.cjs +84 -33
  23. package/dist/backends/idb-backend.cjs.map +1 -1
  24. package/dist/backends/idb-backend.d.cts +1 -0
  25. package/dist/backends/idb-backend.d.cts.map +1 -1
  26. package/dist/backends/idb-backend.d.mts +1 -0
  27. package/dist/backends/idb-backend.d.mts.map +1 -1
  28. package/dist/backends/idb-backend.mjs +85 -34
  29. package/dist/backends/idb-backend.mjs.map +1 -1
  30. package/dist/backends/index.cjs +33 -12
  31. package/dist/backends/index.cjs.map +1 -1
  32. package/dist/backends/index.d.cts +8 -11
  33. package/dist/backends/index.d.cts.map +1 -1
  34. package/dist/backends/index.d.mts +8 -11
  35. package/dist/backends/index.d.mts.map +1 -1
  36. package/dist/backends/index.mjs +34 -13
  37. package/dist/backends/index.mjs.map +1 -1
  38. package/dist/backends/types.cjs.map +1 -1
  39. package/dist/backends/types.d.cts +1 -0
  40. package/dist/backends/types.d.cts.map +1 -1
  41. package/dist/backends/types.d.mts +1 -0
  42. package/dist/backends/types.d.mts.map +1 -1
  43. package/dist/backends/types.mjs.map +1 -1
  44. package/dist/cli/device-mcp.cjs +11 -2
  45. package/dist/cli/device-mcp.cjs.map +1 -1
  46. package/dist/cli/device-mcp.mjs +11 -2
  47. package/dist/cli/device-mcp.mjs.map +1 -1
  48. package/dist/index.cjs +4 -1
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +3 -0
  51. package/dist/index.d.cts.map +1 -1
  52. package/dist/index.d.mts +3 -0
  53. package/dist/index.d.mts.map +1 -1
  54. package/dist/index.mjs +1 -0
  55. package/dist/index.mjs.map +1 -1
  56. package/dist/server.cjs +5 -0
  57. package/dist/server.cjs.map +1 -1
  58. package/dist/server.d.cts +2 -2
  59. package/dist/server.d.cts.map +1 -1
  60. package/dist/server.d.mts +2 -2
  61. package/dist/server.d.mts.map +1 -1
  62. package/dist/server.mjs +6 -1
  63. package/dist/server.mjs.map +1 -1
  64. package/dist/tools/get-element-text.cjs +46 -0
  65. package/dist/tools/get-element-text.cjs.map +1 -0
  66. package/dist/tools/get-element-text.d.cts +4 -0
  67. package/dist/tools/get-element-text.d.cts.map +1 -0
  68. package/dist/tools/get-element-text.d.mts +4 -0
  69. package/dist/tools/get-element-text.d.mts.map +1 -0
  70. package/dist/tools/get-element-text.mjs +43 -0
  71. package/dist/tools/get-element-text.mjs.map +1 -0
  72. package/dist/tools/index.cjs +7 -1
  73. package/dist/tools/index.cjs.map +1 -1
  74. package/dist/tools/index.d.cts +3 -0
  75. package/dist/tools/index.d.cts.map +1 -1
  76. package/dist/tools/index.d.mts +3 -0
  77. package/dist/tools/index.d.mts.map +1 -1
  78. package/dist/tools/index.mjs +3 -0
  79. package/dist/tools/index.mjs.map +1 -1
  80. package/dist/tools/list-devices.cjs +36 -0
  81. package/dist/tools/list-devices.cjs.map +1 -0
  82. package/dist/tools/list-devices.d.cts +4 -0
  83. package/dist/tools/list-devices.d.cts.map +1 -0
  84. package/dist/tools/list-devices.d.mts +4 -0
  85. package/dist/tools/list-devices.d.mts.map +1 -0
  86. package/dist/tools/list-devices.mjs +33 -0
  87. package/dist/tools/list-devices.mjs.map +1 -0
  88. package/dist/tools/select-device.cjs +38 -0
  89. package/dist/tools/select-device.cjs.map +1 -0
  90. package/dist/tools/select-device.d.cts +4 -0
  91. package/dist/tools/select-device.d.cts.map +1 -0
  92. package/dist/tools/select-device.d.mts +4 -0
  93. package/dist/tools/select-device.d.mts.map +1 -0
  94. package/dist/tools/select-device.mjs +35 -0
  95. package/dist/tools/select-device.mjs.map +1 -0
  96. package/dist/utils/exec.cjs +11 -9
  97. package/dist/utils/exec.cjs.map +1 -1
  98. package/dist/utils/exec.d.cts.map +1 -1
  99. package/dist/utils/exec.d.mts.map +1 -1
  100. package/dist/utils/exec.mjs +11 -9
  101. package/dist/utils/exec.mjs.map +1 -1
  102. package/dist/utils/platform.cjs +121 -36
  103. package/dist/utils/platform.cjs.map +1 -1
  104. package/dist/utils/platform.d.cts +14 -3
  105. package/dist/utils/platform.d.cts.map +1 -1
  106. package/dist/utils/platform.d.mts +14 -3
  107. package/dist/utils/platform.d.mts.map +1 -1
  108. package/dist/utils/platform.mjs +117 -36
  109. package/dist/utils/platform.mjs.map +1 -1
  110. package/package.json +2 -2
@@ -7,6 +7,7 @@ export declare class IdbBackend implements DeviceBackend {
7
7
  getDeviceInfo(): Promise<DeviceInfo>;
8
8
  snapshot(): Promise<SnapshotResult>;
9
9
  tapElement(query: ElementQuery): Promise<TapResult>;
10
+ getElementText(query: ElementQuery): Promise<string>;
10
11
  tapCoordinates(x: number, y: number): Promise<void>;
11
12
  typeText(text: string): Promise<void>;
12
13
  swipe(direction: 'up' | 'down' | 'left' | 'right', startX?: number, startY?: number, distance?: number): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"idb-backend.d.mts","sourceRoot":"","sources":["../../src/backends/idb-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,SAAS,EACT,UAAU,EACX,oBAAmB;AASpB,qBAAa,UAAW,YAAW,aAAa;;IAC9C,QAAQ,CAAC,QAAQ,EAAG,KAAK,CAAU;gBAUvB,IAAI,EAAE,MAAM;IAIlB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBhC,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAyBpC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAiBnC,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC;IAuBnD,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrC,KAAK,CACT,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAC3C,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAmBV,cAAc,CAClB,KAAK,EAAE,YAAY,EACnB,SAAS,SAAS,EAClB,UAAU,SAAM,GACf,OAAO,CAAC,SAAS,CAAC;IAef,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkBtD,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQ1D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzC,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAKhC,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5C,OAAO,CAAC,eAAe,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BnE,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IAgCrE,eAAe,CACnB,KAAK,EAAE,YAAY,EACnB,SAAS,GAAE,IAAI,GAAG,MAAe,EACjC,WAAW,SAAK,GACf,OAAO,CAAC,SAAS,CAAC;IAsBf,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAa/B,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IA6BpC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK/B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAazC,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAW7C;AAsCD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAoB1D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAiBtE"}
1
+ {"version":3,"file":"idb-backend.d.mts","sourceRoot":"","sources":["../../src/backends/idb-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,SAAS,EACT,UAAU,EACX,oBAAmB;AAUpB,qBAAa,UAAW,YAAW,aAAa;;IAC9C,QAAQ,CAAC,QAAQ,EAAG,KAAK,CAAU;gBAYvB,IAAI,EAAE,MAAM;IAIlB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAUhC,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAyBpC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAiBnC,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC;IAuBnD,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAapD,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrC,KAAK,CACT,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAC3C,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAmBV,cAAc,CAClB,KAAK,EAAE,YAAY,EACnB,SAAS,SAAS,EAClB,UAAU,SAAM,GACf,OAAO,CAAC,SAAS,CAAC;IAef,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkCtD,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQ1D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAczC,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAWhC,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5C,OAAO,CAAC,eAAe,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BnE,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IAgCrE,eAAe,CACnB,KAAK,EAAE,YAAY,EACnB,SAAS,GAAE,IAAI,GAAG,MAAe,EACjC,WAAW,SAAK,GACf,OAAO,CAAC,SAAS,CAAC;IAsBf,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAa/B,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IA6BpC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK/B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAazC,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAW7C;AAsCD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAoB1D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAiBtE"}
@@ -9,16 +9,19 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _IdbBackend_connected, _IdbBackend_udid, _IdbBackend_recordingProcess, _IdbBackend_recordingPath;
12
+ var _IdbBackend_instances, _IdbBackend_connected, _IdbBackend_udid, _IdbBackend_idbPath, _IdbBackend_recordingProcess, _IdbBackend_recordingPath, _IdbBackend_getAppStateViaSimctl;
13
13
  import { execFile as execFileCb, spawn } from "node:child_process";
14
14
  import { ACCEPT_LABELS, DENY_LABELS } from "../utils/alert-labels.mjs";
15
15
  import { findElement, describeElement, computeSwipeEnd } from "../utils/element.mjs";
16
- import { execStrict, exec, isCommandAvailable } from "../utils/exec.mjs";
16
+ import { execStrict, exec } from "../utils/exec.mjs";
17
+ import { resolveIdbPath } from "../utils/platform.mjs";
17
18
  export class IdbBackend {
18
19
  constructor(udid) {
20
+ _IdbBackend_instances.add(this);
19
21
  this.platform = 'ios';
20
22
  _IdbBackend_connected.set(this, false);
21
23
  _IdbBackend_udid.set(this, void 0);
24
+ _IdbBackend_idbPath.set(this, 'idb');
22
25
  _IdbBackend_recordingProcess.set(this, null);
23
26
  _IdbBackend_recordingPath.set(this, null);
24
27
  __classPrivateFieldSet(this, _IdbBackend_udid, udid, "f");
@@ -27,16 +30,13 @@ export class IdbBackend {
27
30
  if (__classPrivateFieldGet(this, _IdbBackend_connected, "f")) {
28
31
  return;
29
32
  }
30
- if (!(await isCommandAvailable('idb'))) {
31
- throw new Error('idb is not installed.\n' +
32
- 'Install: brew tap facebook/fb && brew install idb-companion && pip3 install fb-idb');
33
- }
34
- await exec('idb', ['connect', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
33
+ __classPrivateFieldSet(this, _IdbBackend_idbPath, await resolveIdbPath(), "f");
34
+ await exec(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), ['connect', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
35
35
  __classPrivateFieldSet(this, _IdbBackend_connected, true, "f");
36
36
  }
37
37
  async getDeviceInfo() {
38
38
  await this.ensureConnected();
39
- const raw = await execStrict('idb', [
39
+ const raw = await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
40
40
  'describe',
41
41
  '--udid',
42
42
  __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
@@ -59,7 +59,7 @@ export class IdbBackend {
59
59
  }
60
60
  async snapshot() {
61
61
  await this.ensureConnected();
62
- const raw = await execStrict('idb', [
62
+ const raw = await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
63
63
  'ui',
64
64
  'describe-all',
65
65
  '--udid',
@@ -91,9 +91,19 @@ export class IdbBackend {
91
91
  targetDescription: describeElement(element),
92
92
  };
93
93
  }
94
+ async getElementText(query) {
95
+ await this.ensureConnected();
96
+ const snapshot = await this.snapshot();
97
+ const element = findElement(snapshot.hierarchy, query);
98
+ if (!element) {
99
+ throw new Error(`Element not found: ${JSON.stringify(query)}\n` +
100
+ 'Use device_snapshot to inspect the current UI hierarchy.');
101
+ }
102
+ return element.label ?? element.value ?? '';
103
+ }
94
104
  async tapCoordinates(x, y) {
95
105
  await this.ensureConnected();
96
- await execStrict('idb', [
106
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
97
107
  'ui',
98
108
  'tap',
99
109
  String(x),
@@ -104,7 +114,7 @@ export class IdbBackend {
104
114
  }
105
115
  async typeText(text) {
106
116
  await this.ensureConnected();
107
- await exec('idb', [
117
+ await exec(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
108
118
  'ui',
109
119
  'key-sequence',
110
120
  '--',
@@ -112,8 +122,8 @@ export class IdbBackend {
112
122
  '--udid',
113
123
  __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
114
124
  ]);
115
- await exec('idb', ['ui', 'key', 'DELETE', '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
116
- await execStrict('idb', ['ui', 'text', text, '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
125
+ await exec(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), ['ui', 'key', 'DELETE', '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
126
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), ['ui', 'text', text, '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
117
127
  }
118
128
  async swipe(direction, startX, startY, distance) {
119
129
  await this.ensureConnected();
@@ -121,7 +131,7 @@ export class IdbBackend {
121
131
  const sx = startX ?? 200;
122
132
  const sy = startY ?? 400;
123
133
  const [endX, endY] = computeSwipeEnd(sx, sy, direction, d);
124
- await execStrict('idb', [
134
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
125
135
  'ui',
126
136
  'swipe',
127
137
  String(sx),
@@ -146,33 +156,62 @@ export class IdbBackend {
146
156
  }
147
157
  async getAppState(bundleId) {
148
158
  await this.ensureConnected();
149
- const raw = await execStrict('idb', ['list-apps', '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
150
- for (const line of raw.trim().split('\n')) {
151
- if (line.includes(bundleId)) {
152
- const parts = line.split('|').map((s) => s.trim());
153
- return {
154
- bundleId,
155
- state: parts[2] ?? 'Unknown',
156
- pid: parts[3] ? parseInt(parts[3], 10) : undefined,
157
- };
159
+ try {
160
+ const raw = await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
161
+ 'list-apps',
162
+ '--udid',
163
+ __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
164
+ ]);
165
+ for (const line of raw.trim().split('\n')) {
166
+ if (line.includes(bundleId)) {
167
+ const parts = line.split('|').map((s) => s.trim());
168
+ return {
169
+ bundleId,
170
+ state: parts[2] ?? 'Unknown',
171
+ pid: parts[3] ? parseInt(parts[3], 10) : undefined,
172
+ };
173
+ }
158
174
  }
175
+ return { bundleId, state: 'Not Installed' };
176
+ }
177
+ catch {
178
+ return __classPrivateFieldGet(this, _IdbBackend_instances, "m", _IdbBackend_getAppStateViaSimctl).call(this, bundleId);
159
179
  }
160
- return { bundleId, state: 'Not Installed' };
161
180
  }
162
181
  async screenshot(outputPath) {
163
182
  await this.ensureConnected();
164
183
  const path = outputPath ?? `/tmp/device-mcp-screenshot-${Date.now()}.png`;
165
- await execStrict('idb', ['screenshot', path, '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
184
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), ['screenshot', path, '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
166
185
  const data = await execStrict('base64', [path]);
167
186
  return { data: data.trim(), format: 'png', path };
168
187
  }
169
188
  async openApp(bundleId) {
170
189
  await this.ensureConnected();
171
- await execStrict('idb', ['launch', bundleId, '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
190
+ try {
191
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
192
+ 'launch',
193
+ bundleId,
194
+ '--udid',
195
+ __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
196
+ ]);
197
+ }
198
+ catch {
199
+ await execStrict('xcrun', ['simctl', 'launch', __classPrivateFieldGet(this, _IdbBackend_udid, "f"), bundleId]);
200
+ }
172
201
  }
173
202
  async closeApp(bundleId) {
174
203
  await this.ensureConnected();
175
- await execStrict('idb', ['terminate', bundleId, '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
204
+ try {
205
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
206
+ 'terminate',
207
+ bundleId,
208
+ '--udid',
209
+ __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
210
+ ]);
211
+ }
212
+ catch {
213
+ await execStrict('xcrun', ['simctl', 'terminate', __classPrivateFieldGet(this, _IdbBackend_udid, "f"), bundleId]);
214
+ }
176
215
  }
177
216
  async pressButton(button) {
178
217
  await this.ensureConnected();
@@ -182,7 +221,7 @@ export class IdbBackend {
182
221
  back: 'HOME',
183
222
  enter: 'RETURN',
184
223
  };
185
- await execStrict('idb', [
224
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
186
225
  'ui',
187
226
  'key',
188
227
  keyMap[button],
@@ -192,7 +231,13 @@ export class IdbBackend {
192
231
  }
193
232
  async dismissKeyboard() {
194
233
  await this.ensureConnected();
195
- await execStrict('idb', ['ui', 'key', 'RETURN', '--udid', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
234
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
235
+ 'ui',
236
+ 'key',
237
+ 'RETURN',
238
+ '--udid',
239
+ __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
240
+ ]);
196
241
  }
197
242
  async dismissAlert(accept) {
198
243
  await this.ensureConnected();
@@ -222,7 +267,7 @@ export class IdbBackend {
222
267
  if (filter) {
223
268
  args.push('--predicate', `eventMessage CONTAINS "${filter}"`);
224
269
  }
225
- const raw = await execStrict('idb', args);
270
+ const raw = await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), args);
226
271
  const entries = raw
227
272
  .trim()
228
273
  .split('\n')
@@ -244,7 +289,7 @@ export class IdbBackend {
244
289
  }
245
290
  const cx = Math.round(element.frame.x + element.frame.width / 2);
246
291
  const cy = Math.round(element.frame.y + element.frame.height / 2);
247
- await execStrict('idb', [
292
+ await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
248
293
  'ui',
249
294
  'tap',
250
295
  String(cx),
@@ -291,7 +336,7 @@ export class IdbBackend {
291
336
  }
292
337
  async getWindowSize() {
293
338
  await this.ensureConnected();
294
- const raw = await execStrict('idb', [
339
+ const raw = await execStrict(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
295
340
  'describe',
296
341
  '--udid',
297
342
  __classPrivateFieldGet(this, _IdbBackend_udid, "f"),
@@ -343,7 +388,7 @@ export class IdbBackend {
343
388
  }
344
389
  const path = outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`;
345
390
  __classPrivateFieldSet(this, _IdbBackend_recordingPath, path, "f");
346
- __classPrivateFieldSet(this, _IdbBackend_recordingProcess, spawn('idb', [
391
+ __classPrivateFieldSet(this, _IdbBackend_recordingProcess, spawn(__classPrivateFieldGet(this, _IdbBackend_idbPath, "f"), [
347
392
  'record-video',
348
393
  path,
349
394
  '--udid',
@@ -366,7 +411,13 @@ export class IdbBackend {
366
411
  return path;
367
412
  }
368
413
  }
369
- _IdbBackend_connected = new WeakMap(), _IdbBackend_udid = new WeakMap(), _IdbBackend_recordingProcess = new WeakMap(), _IdbBackend_recordingPath = new WeakMap();
414
+ _IdbBackend_connected = new WeakMap(), _IdbBackend_udid = new WeakMap(), _IdbBackend_idbPath = new WeakMap(), _IdbBackend_recordingProcess = new WeakMap(), _IdbBackend_recordingPath = new WeakMap(), _IdbBackend_instances = new WeakSet(), _IdbBackend_getAppStateViaSimctl = async function _IdbBackend_getAppStateViaSimctl(bundleId) {
415
+ const result = await exec('xcrun', ['simctl', 'listapps', __classPrivateFieldGet(this, _IdbBackend_udid, "f")]);
416
+ if (result.exitCode === 0 && result.stdout.includes(bundleId)) {
417
+ return { bundleId, state: 'Running' };
418
+ }
419
+ return { bundleId, state: 'Not Installed' };
420
+ };
370
421
  function collectAlertTexts(elements) {
371
422
  const texts = [];
372
423
  for (const el of elements) {
@@ -1 +1 @@
1
- {"version":3,"file":"idb-backend.mjs","sourceRoot":"","sources":["../../src/backends/idb-backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile as execFileCb, spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\n\nimport type {\n DeviceBackend,\n DeviceButton,\n DeviceInfo,\n SnapshotResult,\n ScreenshotResult,\n LogsResult,\n TapResult,\n AppStateResult,\n ElementQuery,\n UIElement,\n WindowSize,\n} from './types.js';\nimport { ACCEPT_LABELS, DENY_LABELS } from '../utils/alert-labels.js';\nimport {\n findElement,\n describeElement,\n computeSwipeEnd,\n} from '../utils/element.js';\nimport { execStrict, exec, isCommandAvailable } from '../utils/exec.js';\n\nexport class IdbBackend implements DeviceBackend {\n readonly platform = 'ios' as const;\n\n #connected = false;\n\n readonly #udid: string;\n\n #recordingProcess: ChildProcess | null = null;\n\n #recordingPath: string | null = null;\n\n constructor(udid: string) {\n this.#udid = udid;\n }\n\n async ensureConnected(): Promise<void> {\n if (this.#connected) {\n return;\n }\n\n if (!(await isCommandAvailable('idb'))) {\n throw new Error(\n 'idb is not installed.\\n' +\n 'Install: brew tap facebook/fb && brew install idb-companion && pip3 install fb-idb',\n );\n }\n\n await exec('idb', ['connect', this.#udid]);\n this.#connected = true;\n }\n\n async getDeviceInfo(): Promise<DeviceInfo> {\n await this.ensureConnected();\n const raw = await execStrict('idb', [\n 'describe',\n '--udid',\n this.#udid,\n '--json',\n ]);\n let info: Record<string, unknown>;\n try {\n info = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(\n `idb describe returned invalid JSON for device ${this.#udid}: ${raw.slice(0, 200)}`,\n );\n }\n return {\n platform: 'ios',\n deviceId: this.#udid,\n name: (info.name as string) ?? 'Unknown',\n osVersion: (info.os_version as string) ?? 'Unknown',\n state: (info.state as string) ?? 'Unknown',\n };\n }\n\n async snapshot(): Promise<SnapshotResult> {\n await this.ensureConnected();\n const raw = await execStrict('idb', [\n 'ui',\n 'describe-all',\n '--udid',\n this.#udid,\n ]);\n const hierarchy = parseIdbHierarchy(raw);\n return {\n platform: 'ios',\n hierarchy,\n raw,\n timestamp: Date.now(),\n };\n }\n\n async tapElement(query: ElementQuery): Promise<TapResult> {\n await this.ensureConnected();\n const snapshot = await this.snapshot();\n const element = findElement(snapshot.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n const x = Math.round(element.frame.x + element.frame.width / 2);\n const y = Math.round(element.frame.y + element.frame.height / 2);\n await this.tapCoordinates(x, y);\n\n return {\n success: true,\n x,\n y,\n targetDescription: describeElement(element),\n };\n }\n\n async tapCoordinates(x: number, y: number): Promise<void> {\n await this.ensureConnected();\n await execStrict('idb', [\n 'ui',\n 'tap',\n String(x),\n String(y),\n '--udid',\n this.#udid,\n ]);\n }\n\n async typeText(text: string): Promise<void> {\n await this.ensureConnected();\n await exec('idb', [\n 'ui',\n 'key-sequence',\n '--',\n 'cmd+a',\n '--udid',\n this.#udid,\n ]);\n await exec('idb', ['ui', 'key', 'DELETE', '--udid', this.#udid]);\n await execStrict('idb', ['ui', 'text', text, '--udid', this.#udid]);\n }\n\n async swipe(\n direction: 'up' | 'down' | 'left' | 'right',\n startX?: number,\n startY?: number,\n distance?: number,\n ): Promise<void> {\n await this.ensureConnected();\n const d = distance ?? 500;\n const sx = startX ?? 200;\n const sy = startY ?? 400;\n const [endX, endY] = computeSwipeEnd(sx, sy, direction, d);\n\n await execStrict('idb', [\n 'ui',\n 'swipe',\n String(sx),\n String(sy),\n String(endX),\n String(endY),\n '--udid',\n this.#udid,\n ]);\n }\n\n async waitForElement(\n query: ElementQuery,\n timeoutMs = 10_000,\n intervalMs = 500,\n ): Promise<UIElement> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n const snapshot = await this.snapshot();\n const element = findElement(snapshot.hierarchy, query);\n if (element) {\n return element;\n }\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n throw new Error(\n `Timed out waiting for element: ${JSON.stringify(query)} (${timeoutMs}ms)`,\n );\n }\n\n async getAppState(bundleId: string): Promise<AppStateResult> {\n await this.ensureConnected();\n const raw = await execStrict('idb', ['list-apps', '--udid', this.#udid]);\n\n for (const line of raw.trim().split('\\n')) {\n if (line.includes(bundleId)) {\n const parts = line.split('|').map((s) => s.trim());\n return {\n bundleId,\n state: parts[2] ?? 'Unknown',\n pid: parts[3] ? parseInt(parts[3], 10) : undefined,\n };\n }\n }\n\n return { bundleId, state: 'Not Installed' };\n }\n\n async screenshot(outputPath?: string): Promise<ScreenshotResult> {\n await this.ensureConnected();\n const path = outputPath ?? `/tmp/device-mcp-screenshot-${Date.now()}.png`;\n await execStrict('idb', ['screenshot', path, '--udid', this.#udid]);\n const data = await execStrict('base64', [path]);\n return { data: data.trim(), format: 'png', path };\n }\n\n async openApp(bundleId: string): Promise<void> {\n await this.ensureConnected();\n await execStrict('idb', ['launch', bundleId, '--udid', this.#udid]);\n }\n\n async closeApp(bundleId: string): Promise<void> {\n await this.ensureConnected();\n await execStrict('idb', ['terminate', bundleId, '--udid', this.#udid]);\n }\n\n async pressButton(button: DeviceButton): Promise<void> {\n await this.ensureConnected();\n const keyMap: Record<DeviceButton, string> = {\n home: 'HOME',\n lock: 'LOCK',\n back: 'HOME',\n enter: 'RETURN',\n };\n await execStrict('idb', [\n 'ui',\n 'key',\n keyMap[button],\n '--udid',\n this.#udid,\n ]);\n }\n\n async dismissKeyboard(): Promise<void> {\n await this.ensureConnected();\n await execStrict('idb', ['ui', 'key', 'RETURN', '--udid', this.#udid]);\n }\n\n async dismissAlert(accept: boolean): Promise<void> {\n await this.ensureConnected();\n const snap = await this.snapshot();\n const candidates = accept ? ACCEPT_LABELS : DENY_LABELS;\n\n for (const label of candidates) {\n const element = findElement(snap.hierarchy, { label });\n if (element) {\n const cx = Math.round(element.frame.x + element.frame.width / 2);\n const cy = Math.round(element.frame.y + element.frame.height / 2);\n await this.tapCoordinates(cx, cy);\n return;\n }\n }\n\n throw new Error(`No alert button found. Tried: ${candidates.join(', ')}`);\n }\n\n async getLogs(durationSeconds = 30, filter?: string): Promise<LogsResult> {\n await this.ensureConnected();\n const args = [\n 'log',\n '--udid',\n this.#udid,\n '--',\n '--last',\n `${durationSeconds}s`,\n ];\n if (filter) {\n args.push('--predicate', `eventMessage CONTAINS \"${filter}\"`);\n }\n const raw = await execStrict('idb', args);\n const entries = raw\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => ({\n timestamp: line.substring(0, 31).trim(),\n level: 'info',\n message: line.substring(31).trim(),\n }));\n return { entries, source: 'idb log' };\n }\n\n async longPress(query: ElementQuery, durationMs = 1000): Promise<TapResult> {\n await this.ensureConnected();\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n const cx = Math.round(element.frame.x + element.frame.width / 2);\n const cy = Math.round(element.frame.y + element.frame.height / 2);\n await execStrict('idb', [\n 'ui',\n 'tap',\n String(cx),\n String(cy),\n '--duration',\n String(durationMs / 1000),\n '--udid',\n this.#udid,\n ]);\n\n return {\n success: true,\n x: cx,\n y: cy,\n targetDescription: describeElement(element),\n };\n }\n\n async scrollToElement(\n query: ElementQuery,\n direction: 'up' | 'down' = 'down',\n maxAttempts = 10,\n ): Promise<UIElement> {\n await this.ensureConnected();\n let previousRaw = '';\n\n for (let i = 0; i < maxAttempts; i++) {\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (element) {\n return element;\n }\n if (snap.raw === previousRaw) {\n break;\n }\n previousRaw = snap.raw;\n await this.swipe(direction);\n }\n throw new Error(\n `Element not found after scrolling: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n async getAlertText(): Promise<string> {\n await this.ensureConnected();\n const snap = await this.snapshot();\n const texts = collectAlertTexts(snap.hierarchy);\n if (texts.length === 0) {\n throw new Error(\n 'No alert is currently displayed.\\n' +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n return texts.join('\\n');\n }\n\n async getWindowSize(): Promise<WindowSize> {\n await this.ensureConnected();\n const raw = await execStrict('idb', [\n 'describe',\n '--udid',\n this.#udid,\n '--json',\n ]);\n try {\n const info = JSON.parse(raw) as Record<string, unknown>;\n const dims = info.screen_dimensions as\n | { width: number; height: number }\n | undefined;\n if (dims?.width && dims?.height) {\n return { width: dims.width, height: dims.height };\n }\n } catch {\n // fall through to snapshot-based approach\n }\n const snap = await this.snapshot();\n if (snap.hierarchy.length > 0) {\n const root = snap.hierarchy[0];\n if (root.frame.width > 0 && root.frame.height > 0) {\n return { width: root.frame.width, height: root.frame.height };\n }\n }\n throw new Error('Unable to determine window size from device');\n }\n\n async getContexts(): Promise<string[]> {\n return ['NATIVE_APP'];\n }\n\n async setContext(context: string): Promise<void> {\n if (context === 'NATIVE_APP') {\n return;\n }\n throw new Error(\n 'Context switching requires Appium backend. IDB only supports NATIVE_APP.',\n );\n }\n\n async getClipboard(): Promise<string> {\n await this.ensureConnected();\n return execStrict('xcrun', ['simctl', 'pbpaste', this.#udid]);\n }\n\n async setClipboard(text: string): Promise<void> {\n await this.ensureConnected();\n await new Promise<void>((resolve, reject) => {\n const proc = execFileCb(\n 'xcrun',\n ['simctl', 'pbcopy', this.#udid],\n { timeout: 30_000 },\n (error) => (error ? reject(new Error(error.message)) : resolve()),\n );\n proc.stdin?.end(text);\n });\n }\n\n async startScreenRecording(outputPath?: string): Promise<void> {\n await this.ensureConnected();\n if (this.#recordingProcess) {\n throw new Error('Screen recording is already in progress');\n }\n const path = outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`;\n this.#recordingPath = path;\n this.#recordingProcess = spawn('idb', [\n 'record-video',\n path,\n '--udid',\n this.#udid,\n ]);\n this.#recordingProcess.on('error', () => {\n this.#recordingProcess = null;\n this.#recordingPath = null;\n });\n }\n\n async stopScreenRecording(): Promise<string> {\n if (!this.#recordingProcess || !this.#recordingPath) {\n throw new Error('No screen recording in progress');\n }\n const path = this.#recordingPath;\n this.#recordingProcess.kill('SIGINT');\n await new Promise((resolve) => setTimeout(resolve, 1000));\n this.#recordingProcess = null;\n this.#recordingPath = null;\n return path;\n }\n}\n\nfunction collectAlertTexts(elements: UIElement[]): string[] {\n const texts: string[] = [];\n for (const el of elements) {\n const isAlertContainer =\n el.type === 'Alert' || el.type === 'Sheet' || el.type.includes('Alert');\n if (isAlertContainer) {\n collectTextsFromChildren(el.children ?? [], texts);\n return texts;\n }\n if (el.children) {\n const found = collectAlertTexts(el.children);\n if (found.length > 0) {\n return found;\n }\n }\n }\n return texts;\n}\n\nfunction collectTextsFromChildren(\n elements: UIElement[],\n texts: string[],\n): void {\n for (const el of elements) {\n if (el.type === 'StaticText' || el.type === 'TextView') {\n const text = el.value ?? el.label;\n if (text) {\n texts.push(text);\n }\n }\n if (el.children) {\n collectTextsFromChildren(el.children, texts);\n }\n }\n}\n\nexport function parseIdbHierarchy(raw: string): UIElement[] {\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n return parsed.map(mapIdbElement);\n }\n if (parsed.children) {\n return parsed.children.map(mapIdbElement);\n }\n return [mapIdbElement(parsed)];\n } catch {\n return [\n {\n type: 'raw',\n label: raw.slice(0, 200),\n frame: { x: 0, y: 0, width: 0, height: 0 },\n enabled: true,\n },\n ];\n }\n}\n\nexport function mapIdbElement(node: Record<string, unknown>): UIElement {\n const frame = node.frame as\n | { x: number; y: number; width: number; height: number }\n | undefined;\n\n return {\n type: (node.type as string) ?? (node.AXType as string) ?? 'Unknown',\n label: (node.AXLabel as string) ?? (node.label as string) ?? undefined,\n value: (node.AXValue as string) ?? (node.value as string) ?? undefined,\n identifier:\n (node.AXUniqueId as string) ?? (node.identifier as string) ?? undefined,\n frame: frame ?? { x: 0, y: 0, width: 0, height: 0 },\n enabled: (node.enabled as boolean) ?? true,\n children: Array.isArray(node.children)\n ? node.children.map(mapIdbElement)\n : undefined,\n };\n}\n"]}
1
+ {"version":3,"file":"idb-backend.mjs","sourceRoot":"","sources":["../../src/backends/idb-backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile as execFileCb, spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\n\nimport type {\n DeviceBackend,\n DeviceButton,\n DeviceInfo,\n SnapshotResult,\n ScreenshotResult,\n LogsResult,\n TapResult,\n AppStateResult,\n ElementQuery,\n UIElement,\n WindowSize,\n} from './types.js';\nimport { ACCEPT_LABELS, DENY_LABELS } from '../utils/alert-labels.js';\nimport {\n findElement,\n describeElement,\n computeSwipeEnd,\n} from '../utils/element.js';\nimport { execStrict, exec } from '../utils/exec.js';\nimport { resolveIdbPath } from '../utils/platform.js';\n\nexport class IdbBackend implements DeviceBackend {\n readonly platform = 'ios' as const;\n\n #connected = false;\n\n readonly #udid: string;\n\n #idbPath = 'idb';\n\n #recordingProcess: ChildProcess | null = null;\n\n #recordingPath: string | null = null;\n\n constructor(udid: string) {\n this.#udid = udid;\n }\n\n async ensureConnected(): Promise<void> {\n if (this.#connected) {\n return;\n }\n\n this.#idbPath = await resolveIdbPath();\n await exec(this.#idbPath, ['connect', this.#udid]);\n this.#connected = true;\n }\n\n async getDeviceInfo(): Promise<DeviceInfo> {\n await this.ensureConnected();\n const raw = await execStrict(this.#idbPath, [\n 'describe',\n '--udid',\n this.#udid,\n '--json',\n ]);\n let info: Record<string, unknown>;\n try {\n info = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(\n `idb describe returned invalid JSON for device ${this.#udid}: ${raw.slice(0, 200)}`,\n );\n }\n return {\n platform: 'ios',\n deviceId: this.#udid,\n name: (info.name as string) ?? 'Unknown',\n osVersion: (info.os_version as string) ?? 'Unknown',\n state: (info.state as string) ?? 'Unknown',\n };\n }\n\n async snapshot(): Promise<SnapshotResult> {\n await this.ensureConnected();\n const raw = await execStrict(this.#idbPath, [\n 'ui',\n 'describe-all',\n '--udid',\n this.#udid,\n ]);\n const hierarchy = parseIdbHierarchy(raw);\n return {\n platform: 'ios',\n hierarchy,\n raw,\n timestamp: Date.now(),\n };\n }\n\n async tapElement(query: ElementQuery): Promise<TapResult> {\n await this.ensureConnected();\n const snapshot = await this.snapshot();\n const element = findElement(snapshot.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n const x = Math.round(element.frame.x + element.frame.width / 2);\n const y = Math.round(element.frame.y + element.frame.height / 2);\n await this.tapCoordinates(x, y);\n\n return {\n success: true,\n x,\n y,\n targetDescription: describeElement(element),\n };\n }\n\n async getElementText(query: ElementQuery): Promise<string> {\n await this.ensureConnected();\n const snapshot = await this.snapshot();\n const element = findElement(snapshot.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n return element.label ?? element.value ?? '';\n }\n\n async tapCoordinates(x: number, y: number): Promise<void> {\n await this.ensureConnected();\n await execStrict(this.#idbPath, [\n 'ui',\n 'tap',\n String(x),\n String(y),\n '--udid',\n this.#udid,\n ]);\n }\n\n async typeText(text: string): Promise<void> {\n await this.ensureConnected();\n await exec(this.#idbPath, [\n 'ui',\n 'key-sequence',\n '--',\n 'cmd+a',\n '--udid',\n this.#udid,\n ]);\n await exec(this.#idbPath, ['ui', 'key', 'DELETE', '--udid', this.#udid]);\n await execStrict(this.#idbPath, ['ui', 'text', text, '--udid', this.#udid]);\n }\n\n async swipe(\n direction: 'up' | 'down' | 'left' | 'right',\n startX?: number,\n startY?: number,\n distance?: number,\n ): Promise<void> {\n await this.ensureConnected();\n const d = distance ?? 500;\n const sx = startX ?? 200;\n const sy = startY ?? 400;\n const [endX, endY] = computeSwipeEnd(sx, sy, direction, d);\n\n await execStrict(this.#idbPath, [\n 'ui',\n 'swipe',\n String(sx),\n String(sy),\n String(endX),\n String(endY),\n '--udid',\n this.#udid,\n ]);\n }\n\n async waitForElement(\n query: ElementQuery,\n timeoutMs = 10_000,\n intervalMs = 500,\n ): Promise<UIElement> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n const snapshot = await this.snapshot();\n const element = findElement(snapshot.hierarchy, query);\n if (element) {\n return element;\n }\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n throw new Error(\n `Timed out waiting for element: ${JSON.stringify(query)} (${timeoutMs}ms)`,\n );\n }\n\n async getAppState(bundleId: string): Promise<AppStateResult> {\n await this.ensureConnected();\n try {\n const raw = await execStrict(this.#idbPath, [\n 'list-apps',\n '--udid',\n this.#udid,\n ]);\n\n for (const line of raw.trim().split('\\n')) {\n if (line.includes(bundleId)) {\n const parts = line.split('|').map((s) => s.trim());\n return {\n bundleId,\n state: parts[2] ?? 'Unknown',\n pid: parts[3] ? parseInt(parts[3], 10) : undefined,\n };\n }\n }\n\n return { bundleId, state: 'Not Installed' };\n } catch {\n return this.#getAppStateViaSimctl(bundleId);\n }\n }\n\n async #getAppStateViaSimctl(bundleId: string): Promise<AppStateResult> {\n const result = await exec('xcrun', ['simctl', 'listapps', this.#udid]);\n if (result.exitCode === 0 && result.stdout.includes(bundleId)) {\n return { bundleId, state: 'Running' };\n }\n return { bundleId, state: 'Not Installed' };\n }\n\n async screenshot(outputPath?: string): Promise<ScreenshotResult> {\n await this.ensureConnected();\n const path = outputPath ?? `/tmp/device-mcp-screenshot-${Date.now()}.png`;\n await execStrict(this.#idbPath, ['screenshot', path, '--udid', this.#udid]);\n const data = await execStrict('base64', [path]);\n return { data: data.trim(), format: 'png', path };\n }\n\n async openApp(bundleId: string): Promise<void> {\n await this.ensureConnected();\n try {\n await execStrict(this.#idbPath, [\n 'launch',\n bundleId,\n '--udid',\n this.#udid,\n ]);\n } catch {\n await execStrict('xcrun', ['simctl', 'launch', this.#udid, bundleId]);\n }\n }\n\n async closeApp(bundleId: string): Promise<void> {\n await this.ensureConnected();\n try {\n await execStrict(this.#idbPath, [\n 'terminate',\n bundleId,\n '--udid',\n this.#udid,\n ]);\n } catch {\n await execStrict('xcrun', ['simctl', 'terminate', this.#udid, bundleId]);\n }\n }\n\n async pressButton(button: DeviceButton): Promise<void> {\n await this.ensureConnected();\n const keyMap: Record<DeviceButton, string> = {\n home: 'HOME',\n lock: 'LOCK',\n back: 'HOME',\n enter: 'RETURN',\n };\n await execStrict(this.#idbPath, [\n 'ui',\n 'key',\n keyMap[button],\n '--udid',\n this.#udid,\n ]);\n }\n\n async dismissKeyboard(): Promise<void> {\n await this.ensureConnected();\n await execStrict(this.#idbPath, [\n 'ui',\n 'key',\n 'RETURN',\n '--udid',\n this.#udid,\n ]);\n }\n\n async dismissAlert(accept: boolean): Promise<void> {\n await this.ensureConnected();\n const snap = await this.snapshot();\n const candidates = accept ? ACCEPT_LABELS : DENY_LABELS;\n\n for (const label of candidates) {\n const element = findElement(snap.hierarchy, { label });\n if (element) {\n const cx = Math.round(element.frame.x + element.frame.width / 2);\n const cy = Math.round(element.frame.y + element.frame.height / 2);\n await this.tapCoordinates(cx, cy);\n return;\n }\n }\n\n throw new Error(`No alert button found. Tried: ${candidates.join(', ')}`);\n }\n\n async getLogs(durationSeconds = 30, filter?: string): Promise<LogsResult> {\n await this.ensureConnected();\n const args = [\n 'log',\n '--udid',\n this.#udid,\n '--',\n '--last',\n `${durationSeconds}s`,\n ];\n if (filter) {\n args.push('--predicate', `eventMessage CONTAINS \"${filter}\"`);\n }\n const raw = await execStrict(this.#idbPath, args);\n const entries = raw\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => ({\n timestamp: line.substring(0, 31).trim(),\n level: 'info',\n message: line.substring(31).trim(),\n }));\n return { entries, source: 'idb log' };\n }\n\n async longPress(query: ElementQuery, durationMs = 1000): Promise<TapResult> {\n await this.ensureConnected();\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n const cx = Math.round(element.frame.x + element.frame.width / 2);\n const cy = Math.round(element.frame.y + element.frame.height / 2);\n await execStrict(this.#idbPath, [\n 'ui',\n 'tap',\n String(cx),\n String(cy),\n '--duration',\n String(durationMs / 1000),\n '--udid',\n this.#udid,\n ]);\n\n return {\n success: true,\n x: cx,\n y: cy,\n targetDescription: describeElement(element),\n };\n }\n\n async scrollToElement(\n query: ElementQuery,\n direction: 'up' | 'down' = 'down',\n maxAttempts = 10,\n ): Promise<UIElement> {\n await this.ensureConnected();\n let previousRaw = '';\n\n for (let i = 0; i < maxAttempts; i++) {\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (element) {\n return element;\n }\n if (snap.raw === previousRaw) {\n break;\n }\n previousRaw = snap.raw;\n await this.swipe(direction);\n }\n throw new Error(\n `Element not found after scrolling: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n async getAlertText(): Promise<string> {\n await this.ensureConnected();\n const snap = await this.snapshot();\n const texts = collectAlertTexts(snap.hierarchy);\n if (texts.length === 0) {\n throw new Error(\n 'No alert is currently displayed.\\n' +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n return texts.join('\\n');\n }\n\n async getWindowSize(): Promise<WindowSize> {\n await this.ensureConnected();\n const raw = await execStrict(this.#idbPath, [\n 'describe',\n '--udid',\n this.#udid,\n '--json',\n ]);\n try {\n const info = JSON.parse(raw) as Record<string, unknown>;\n const dims = info.screen_dimensions as\n | { width: number; height: number }\n | undefined;\n if (dims?.width && dims?.height) {\n return { width: dims.width, height: dims.height };\n }\n } catch {\n // fall through to snapshot-based approach\n }\n const snap = await this.snapshot();\n if (snap.hierarchy.length > 0) {\n const root = snap.hierarchy[0];\n if (root.frame.width > 0 && root.frame.height > 0) {\n return { width: root.frame.width, height: root.frame.height };\n }\n }\n throw new Error('Unable to determine window size from device');\n }\n\n async getContexts(): Promise<string[]> {\n return ['NATIVE_APP'];\n }\n\n async setContext(context: string): Promise<void> {\n if (context === 'NATIVE_APP') {\n return;\n }\n throw new Error(\n 'Context switching requires Appium backend. IDB only supports NATIVE_APP.',\n );\n }\n\n async getClipboard(): Promise<string> {\n await this.ensureConnected();\n return execStrict('xcrun', ['simctl', 'pbpaste', this.#udid]);\n }\n\n async setClipboard(text: string): Promise<void> {\n await this.ensureConnected();\n await new Promise<void>((resolve, reject) => {\n const proc = execFileCb(\n 'xcrun',\n ['simctl', 'pbcopy', this.#udid],\n { timeout: 30_000 },\n (error) => (error ? reject(new Error(error.message)) : resolve()),\n );\n proc.stdin?.end(text);\n });\n }\n\n async startScreenRecording(outputPath?: string): Promise<void> {\n await this.ensureConnected();\n if (this.#recordingProcess) {\n throw new Error('Screen recording is already in progress');\n }\n const path = outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`;\n this.#recordingPath = path;\n this.#recordingProcess = spawn(this.#idbPath, [\n 'record-video',\n path,\n '--udid',\n this.#udid,\n ]);\n this.#recordingProcess.on('error', () => {\n this.#recordingProcess = null;\n this.#recordingPath = null;\n });\n }\n\n async stopScreenRecording(): Promise<string> {\n if (!this.#recordingProcess || !this.#recordingPath) {\n throw new Error('No screen recording in progress');\n }\n const path = this.#recordingPath;\n this.#recordingProcess.kill('SIGINT');\n await new Promise((resolve) => setTimeout(resolve, 1000));\n this.#recordingProcess = null;\n this.#recordingPath = null;\n return path;\n }\n}\n\nfunction collectAlertTexts(elements: UIElement[]): string[] {\n const texts: string[] = [];\n for (const el of elements) {\n const isAlertContainer =\n el.type === 'Alert' || el.type === 'Sheet' || el.type.includes('Alert');\n if (isAlertContainer) {\n collectTextsFromChildren(el.children ?? [], texts);\n return texts;\n }\n if (el.children) {\n const found = collectAlertTexts(el.children);\n if (found.length > 0) {\n return found;\n }\n }\n }\n return texts;\n}\n\nfunction collectTextsFromChildren(\n elements: UIElement[],\n texts: string[],\n): void {\n for (const el of elements) {\n if (el.type === 'StaticText' || el.type === 'TextView') {\n const text = el.value ?? el.label;\n if (text) {\n texts.push(text);\n }\n }\n if (el.children) {\n collectTextsFromChildren(el.children, texts);\n }\n }\n}\n\nexport function parseIdbHierarchy(raw: string): UIElement[] {\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n return parsed.map(mapIdbElement);\n }\n if (parsed.children) {\n return parsed.children.map(mapIdbElement);\n }\n return [mapIdbElement(parsed)];\n } catch {\n return [\n {\n type: 'raw',\n label: raw.slice(0, 200),\n frame: { x: 0, y: 0, width: 0, height: 0 },\n enabled: true,\n },\n ];\n }\n}\n\nexport function mapIdbElement(node: Record<string, unknown>): UIElement {\n const frame = node.frame as\n | { x: number; y: number; width: number; height: number }\n | undefined;\n\n return {\n type: (node.type as string) ?? (node.AXType as string) ?? 'Unknown',\n label: (node.AXLabel as string) ?? (node.label as string) ?? undefined,\n value: (node.AXValue as string) ?? (node.value as string) ?? undefined,\n identifier:\n (node.AXUniqueId as string) ?? (node.identifier as string) ?? undefined,\n frame: frame ?? { x: 0, y: 0, width: 0, height: 0 },\n enabled: (node.enabled as boolean) ?? true,\n children: Array.isArray(node.children)\n ? node.children.map(mapIdbElement)\n : undefined,\n };\n}\n"]}
@@ -14,7 +14,7 @@ var appium_backend_js_2 = require("./appium-backend.cjs");
14
14
  Object.defineProperty(exports, "AppiumBackend", { enumerable: true, get: function () { return appium_backend_js_2.AppiumBackend; } });
15
15
  var idb_backend_js_2 = require("./idb-backend.cjs");
16
16
  Object.defineProperty(exports, "IdbBackend", { enumerable: true, get: function () { return idb_backend_js_2.IdbBackend; } });
17
- async function createBackend(explicitDeviceId) {
17
+ async function createBackend(explicitDeviceId, explicitPlatform) {
18
18
  const sessionConfig = await (0, session_file_js_1.readSessionFile)();
19
19
  if (sessionConfig) {
20
20
  console.error(`Found .device-session (${sessionConfig.mode}, ${sessionConfig.platform})`);
@@ -22,30 +22,37 @@ async function createBackend(explicitDeviceId) {
22
22
  await backend.ensureConnected();
23
23
  return backend;
24
24
  }
25
- const { platform, deviceId } = await (0, platform_js_1.detectPlatform)(explicitDeviceId);
25
+ const { platform, deviceId } = await (0, platform_js_1.detectPlatform)(explicitDeviceId, explicitPlatform);
26
26
  const backend = platform === 'ios' ? new idb_backend_js_1.IdbBackend(deviceId) : new adb_backend_js_1.AdbBackend(deviceId);
27
27
  await backend.ensureConnected();
28
28
  return backend;
29
29
  }
30
- /**
31
- * Lazy backend that defers device detection to first tool call.
32
- * Allows the MCP server to start and complete the handshake
33
- * even when no device is connected yet.
34
- *
35
- * @param explicitDeviceId - Optional device ID override.
36
- * @returns A DeviceBackend that resolves on first use.
37
- */
38
- function createLazyBackend(explicitDeviceId) {
30
+ function createLazyBackend(explicitDeviceId, explicitPlatform) {
39
31
  let inner = null;
40
32
  let connecting = null;
33
+ let pendingDevices = null;
34
+ let selectedOverride = null;
41
35
  async function resolve() {
42
36
  if (inner) {
43
37
  return inner;
44
38
  }
39
+ if (pendingDevices && !selectedOverride) {
40
+ throw new platform_js_1.MultipleDevicesError(pendingDevices);
41
+ }
45
42
  if (!connecting) {
46
- connecting = createBackend(explicitDeviceId).then((backend) => {
43
+ const deviceId = selectedOverride ?? explicitDeviceId;
44
+ connecting = createBackend(deviceId, explicitPlatform)
45
+ .then((backend) => {
47
46
  inner = backend;
47
+ pendingDevices = null;
48
48
  return backend;
49
+ })
50
+ .catch((error) => {
51
+ connecting = null;
52
+ if (error instanceof platform_js_1.MultipleDevicesError) {
53
+ pendingDevices = error.devices;
54
+ }
55
+ throw error;
49
56
  });
50
57
  }
51
58
  return connecting;
@@ -54,6 +61,17 @@ function createLazyBackend(explicitDeviceId) {
54
61
  get platform() {
55
62
  return inner?.platform ?? 'ios';
56
63
  },
64
+ selectDevice(deviceId) {
65
+ selectedOverride = deviceId;
66
+ inner = null;
67
+ connecting = null;
68
+ },
69
+ async listDevices() {
70
+ if (pendingDevices) {
71
+ return pendingDevices;
72
+ }
73
+ return (0, platform_js_1.detectAllDevices)(explicitPlatform);
74
+ },
57
75
  async getDeviceInfo() {
58
76
  return (await resolve()).getDeviceInfo();
59
77
  },
@@ -129,6 +147,9 @@ function createLazyBackend(explicitDeviceId) {
129
147
  async stopScreenRecording() {
130
148
  return (await resolve()).stopScreenRecording();
131
149
  },
150
+ async getElementText(query) {
151
+ return (await resolve()).getElementText(query);
152
+ },
132
153
  };
133
154
  }
134
155
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { AdbBackend } from './adb-backend.js';\nimport { AppiumBackend } from './appium-backend.js';\nimport { IdbBackend } from './idb-backend.js';\nimport { readSessionFile } from './session-file.js';\nimport type {\n DeviceBackend,\n DeviceButton,\n DeviceInfo,\n LogsResult,\n ScreenshotResult,\n SnapshotResult,\n TapResult,\n AppStateResult,\n ElementQuery,\n UIElement,\n Platform,\n WindowSize,\n} from './types.js';\nimport { detectPlatform } from '../utils/platform.js';\n\nexport type { DeviceBackend } from './types.js';\nexport { AdbBackend } from './adb-backend.js';\nexport { AppiumBackend } from './appium-backend.js';\nexport { IdbBackend } from './idb-backend.js';\n\nexport async function createBackend(\n explicitDeviceId?: string,\n): Promise<DeviceBackend> {\n const sessionConfig = await readSessionFile();\n\n if (sessionConfig) {\n console.error(\n `Found .device-session (${sessionConfig.mode}, ${sessionConfig.platform})`,\n );\n const backend = new AppiumBackend(sessionConfig);\n await backend.ensureConnected();\n return backend;\n }\n\n const { platform, deviceId } = await detectPlatform(explicitDeviceId);\n\n const backend =\n platform === 'ios' ? new IdbBackend(deviceId) : new AdbBackend(deviceId);\n\n await backend.ensureConnected();\n return backend;\n}\n\n/**\n * Lazy backend that defers device detection to first tool call.\n * Allows the MCP server to start and complete the handshake\n * even when no device is connected yet.\n *\n * @param explicitDeviceId - Optional device ID override.\n * @returns A DeviceBackend that resolves on first use.\n */\nexport function createLazyBackend(explicitDeviceId?: string): DeviceBackend {\n let inner: DeviceBackend | null = null;\n let connecting: Promise<DeviceBackend> | null = null;\n\n async function resolve(): Promise<DeviceBackend> {\n if (inner) {\n return inner;\n }\n if (!connecting) {\n connecting = createBackend(explicitDeviceId).then((backend) => {\n inner = backend;\n return backend;\n });\n }\n return connecting;\n }\n\n return {\n get platform(): Platform {\n return inner?.platform ?? 'ios';\n },\n\n async getDeviceInfo(): Promise<DeviceInfo> {\n return (await resolve()).getDeviceInfo();\n },\n\n async snapshot(): Promise<SnapshotResult> {\n return (await resolve()).snapshot();\n },\n\n async tapElement(query: ElementQuery): Promise<TapResult> {\n return (await resolve()).tapElement(query);\n },\n\n async tapCoordinates(x: number, y: number): Promise<void> {\n return (await resolve()).tapCoordinates(x, y);\n },\n\n async typeText(text: string): Promise<void> {\n return (await resolve()).typeText(text);\n },\n\n async swipe(\n direction: 'up' | 'down' | 'left' | 'right',\n startX?: number,\n startY?: number,\n distance?: number,\n ): Promise<void> {\n return (await resolve()).swipe(direction, startX, startY, distance);\n },\n\n async waitForElement(\n query: ElementQuery,\n timeoutMs?: number,\n intervalMs?: number,\n ): Promise<UIElement> {\n return (await resolve()).waitForElement(query, timeoutMs, intervalMs);\n },\n\n async getAppState(bundleId: string): Promise<AppStateResult> {\n return (await resolve()).getAppState(bundleId);\n },\n\n async screenshot(outputPath?: string): Promise<ScreenshotResult> {\n return (await resolve()).screenshot(outputPath);\n },\n\n async openApp(bundleId: string): Promise<void> {\n return (await resolve()).openApp(bundleId);\n },\n\n async closeApp(bundleId: string): Promise<void> {\n return (await resolve()).closeApp(bundleId);\n },\n\n async pressButton(button: DeviceButton): Promise<void> {\n return (await resolve()).pressButton(button);\n },\n\n async dismissKeyboard(): Promise<void> {\n return (await resolve()).dismissKeyboard();\n },\n\n async dismissAlert(accept: boolean): Promise<void> {\n return (await resolve()).dismissAlert(accept);\n },\n\n async getLogs(\n durationSeconds?: number,\n filter?: string,\n ): Promise<LogsResult> {\n return (await resolve()).getLogs(durationSeconds, filter);\n },\n\n async longPress(\n query: ElementQuery,\n durationMs?: number,\n ): Promise<TapResult> {\n return (await resolve()).longPress(query, durationMs);\n },\n\n async scrollToElement(\n query: ElementQuery,\n direction?: 'up' | 'down',\n maxAttempts?: number,\n ): Promise<UIElement> {\n return (await resolve()).scrollToElement(query, direction, maxAttempts);\n },\n\n async getAlertText(): Promise<string> {\n return (await resolve()).getAlertText();\n },\n\n async getWindowSize(): Promise<WindowSize> {\n return (await resolve()).getWindowSize();\n },\n\n async getContexts(): Promise<string[]> {\n return (await resolve()).getContexts();\n },\n\n async setContext(context: string): Promise<void> {\n return (await resolve()).setContext(context);\n },\n\n async getClipboard(): Promise<string> {\n return (await resolve()).getClipboard();\n },\n\n async setClipboard(text: string): Promise<void> {\n return (await resolve()).setClipboard(text);\n },\n\n async startScreenRecording(outputPath?: string): Promise<void> {\n return (await resolve()).startScreenRecording(outputPath);\n },\n\n async stopScreenRecording(): Promise<string> {\n return (await resolve()).stopScreenRecording();\n },\n };\n}\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { AdbBackend } from './adb-backend.js';\nimport { AppiumBackend } from './appium-backend.js';\nimport { IdbBackend } from './idb-backend.js';\nimport { readSessionFile } from './session-file.js';\nimport type {\n DeviceBackend,\n DeviceButton,\n DeviceInfo,\n LogsResult,\n ScreenshotResult,\n SnapshotResult,\n TapResult,\n AppStateResult,\n ElementQuery,\n UIElement,\n Platform,\n WindowSize,\n} from './types.js';\nimport {\n detectPlatform,\n detectAllDevices,\n MultipleDevicesError,\n} from '../utils/platform.js';\nimport type { DetectedDevice } from '../utils/platform.js';\n\nexport type { DeviceBackend } from './types.js';\nexport { AdbBackend } from './adb-backend.js';\nexport { AppiumBackend } from './appium-backend.js';\nexport { IdbBackend } from './idb-backend.js';\n\nexport type LazyDeviceBackend = DeviceBackend & {\n selectDevice(deviceId: string): void;\n listDevices(): Promise<DetectedDevice[]>;\n};\n\nexport async function createBackend(\n explicitDeviceId?: string,\n explicitPlatform?: Platform,\n): Promise<DeviceBackend> {\n const sessionConfig = await readSessionFile();\n\n if (sessionConfig) {\n console.error(\n `Found .device-session (${sessionConfig.mode}, ${sessionConfig.platform})`,\n );\n const backend = new AppiumBackend(sessionConfig);\n await backend.ensureConnected();\n return backend;\n }\n\n const { platform, deviceId } = await detectPlatform(\n explicitDeviceId,\n explicitPlatform,\n );\n\n const backend =\n platform === 'ios' ? new IdbBackend(deviceId) : new AdbBackend(deviceId);\n\n await backend.ensureConnected();\n return backend;\n}\n\nexport function createLazyBackend(\n explicitDeviceId?: string,\n explicitPlatform?: Platform,\n): LazyDeviceBackend {\n let inner: DeviceBackend | null = null;\n let connecting: Promise<DeviceBackend> | null = null;\n let pendingDevices: DetectedDevice[] | null = null;\n let selectedOverride: string | null = null;\n\n async function resolve(): Promise<DeviceBackend> {\n if (inner) {\n return inner;\n }\n\n if (pendingDevices && !selectedOverride) {\n throw new MultipleDevicesError(pendingDevices);\n }\n\n if (!connecting) {\n const deviceId = selectedOverride ?? explicitDeviceId;\n connecting = createBackend(deviceId, explicitPlatform)\n .then((backend) => {\n inner = backend;\n pendingDevices = null;\n return backend;\n })\n .catch((error: unknown) => {\n connecting = null;\n if (error instanceof MultipleDevicesError) {\n pendingDevices = error.devices;\n }\n throw error;\n });\n }\n return connecting;\n }\n\n return {\n get platform(): Platform {\n return inner?.platform ?? 'ios';\n },\n\n selectDevice(deviceId: string): void {\n selectedOverride = deviceId;\n inner = null;\n connecting = null;\n },\n\n async listDevices(): Promise<DetectedDevice[]> {\n if (pendingDevices) {\n return pendingDevices;\n }\n return detectAllDevices(explicitPlatform);\n },\n\n async getDeviceInfo(): Promise<DeviceInfo> {\n return (await resolve()).getDeviceInfo();\n },\n\n async snapshot(): Promise<SnapshotResult> {\n return (await resolve()).snapshot();\n },\n\n async tapElement(query: ElementQuery): Promise<TapResult> {\n return (await resolve()).tapElement(query);\n },\n\n async tapCoordinates(x: number, y: number): Promise<void> {\n return (await resolve()).tapCoordinates(x, y);\n },\n\n async typeText(text: string): Promise<void> {\n return (await resolve()).typeText(text);\n },\n\n async swipe(\n direction: 'up' | 'down' | 'left' | 'right',\n startX?: number,\n startY?: number,\n distance?: number,\n ): Promise<void> {\n return (await resolve()).swipe(direction, startX, startY, distance);\n },\n\n async waitForElement(\n query: ElementQuery,\n timeoutMs?: number,\n intervalMs?: number,\n ): Promise<UIElement> {\n return (await resolve()).waitForElement(query, timeoutMs, intervalMs);\n },\n\n async getAppState(bundleId: string): Promise<AppStateResult> {\n return (await resolve()).getAppState(bundleId);\n },\n\n async screenshot(outputPath?: string): Promise<ScreenshotResult> {\n return (await resolve()).screenshot(outputPath);\n },\n\n async openApp(bundleId: string): Promise<void> {\n return (await resolve()).openApp(bundleId);\n },\n\n async closeApp(bundleId: string): Promise<void> {\n return (await resolve()).closeApp(bundleId);\n },\n\n async pressButton(button: DeviceButton): Promise<void> {\n return (await resolve()).pressButton(button);\n },\n\n async dismissKeyboard(): Promise<void> {\n return (await resolve()).dismissKeyboard();\n },\n\n async dismissAlert(accept: boolean): Promise<void> {\n return (await resolve()).dismissAlert(accept);\n },\n\n async getLogs(\n durationSeconds?: number,\n filter?: string,\n ): Promise<LogsResult> {\n return (await resolve()).getLogs(durationSeconds, filter);\n },\n\n async longPress(\n query: ElementQuery,\n durationMs?: number,\n ): Promise<TapResult> {\n return (await resolve()).longPress(query, durationMs);\n },\n\n async scrollToElement(\n query: ElementQuery,\n direction?: 'up' | 'down',\n maxAttempts?: number,\n ): Promise<UIElement> {\n return (await resolve()).scrollToElement(query, direction, maxAttempts);\n },\n\n async getAlertText(): Promise<string> {\n return (await resolve()).getAlertText();\n },\n\n async getWindowSize(): Promise<WindowSize> {\n return (await resolve()).getWindowSize();\n },\n\n async getContexts(): Promise<string[]> {\n return (await resolve()).getContexts();\n },\n\n async setContext(context: string): Promise<void> {\n return (await resolve()).setContext(context);\n },\n\n async getClipboard(): Promise<string> {\n return (await resolve()).getClipboard();\n },\n\n async setClipboard(text: string): Promise<void> {\n return (await resolve()).setClipboard(text);\n },\n\n async startScreenRecording(outputPath?: string): Promise<void> {\n return (await resolve()).startScreenRecording(outputPath);\n },\n\n async stopScreenRecording(): Promise<string> {\n return (await resolve()).stopScreenRecording();\n },\n\n async getElementText(query: ElementQuery): Promise<string> {\n return (await resolve()).getElementText(query);\n },\n };\n}\n"]}
@@ -1,16 +1,13 @@
1
- import type { DeviceBackend } from "./types.cjs";
1
+ import type { DeviceBackend, Platform } from "./types.cjs";
2
+ import type { DetectedDevice } from "../utils/platform.cjs";
2
3
  export type { DeviceBackend } from "./types.cjs";
3
4
  export { AdbBackend } from "./adb-backend.cjs";
4
5
  export { AppiumBackend } from "./appium-backend.cjs";
5
6
  export { IdbBackend } from "./idb-backend.cjs";
6
- export declare function createBackend(explicitDeviceId?: string): Promise<DeviceBackend>;
7
- /**
8
- * Lazy backend that defers device detection to first tool call.
9
- * Allows the MCP server to start and complete the handshake
10
- * even when no device is connected yet.
11
- *
12
- * @param explicitDeviceId - Optional device ID override.
13
- * @returns A DeviceBackend that resolves on first use.
14
- */
15
- export declare function createLazyBackend(explicitDeviceId?: string): DeviceBackend;
7
+ export type LazyDeviceBackend = DeviceBackend & {
8
+ selectDevice(deviceId: string): void;
9
+ listDevices(): Promise<DetectedDevice[]>;
10
+ };
11
+ export declare function createBackend(explicitDeviceId?: string, explicitPlatform?: Platform): Promise<DeviceBackend>;
12
+ export declare function createLazyBackend(explicitDeviceId?: string, explicitPlatform?: Platform): LazyDeviceBackend;
16
13
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,aAAa,EAYd,oBAAmB;AAGpB,YAAY,EAAE,aAAa,EAAE,oBAAmB;AAChD,OAAO,EAAE,UAAU,EAAE,0BAAyB;AAC9C,OAAO,EAAE,aAAa,EAAE,6BAA4B;AACpD,OAAO,EAAE,UAAU,EAAE,0BAAyB;AAE9C,wBAAsB,aAAa,CACjC,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,aAAa,CAAC,CAmBxB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,aAAa,CA6I1E"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,aAAa,EAUb,QAAQ,EAET,oBAAmB;AAMpB,OAAO,KAAK,EAAE,cAAc,EAAE,8BAA6B;AAE3D,YAAY,EAAE,aAAa,EAAE,oBAAmB;AAChD,OAAO,EAAE,UAAU,EAAE,0BAAyB;AAC9C,OAAO,EAAE,aAAa,EAAE,6BAA4B;AACpD,OAAO,EAAE,UAAU,EAAE,0BAAyB;AAE9C,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG;IAC9C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CAC1C,CAAC;AAEF,wBAAsB,aAAa,CACjC,gBAAgB,CAAC,EAAE,MAAM,EACzB,gBAAgB,CAAC,EAAE,QAAQ,GAC1B,OAAO,CAAC,aAAa,CAAC,CAsBxB;AAED,wBAAgB,iBAAiB,CAC/B,gBAAgB,CAAC,EAAE,MAAM,EACzB,gBAAgB,CAAC,EAAE,QAAQ,GAC1B,iBAAiB,CA+KnB"}
@@ -1,16 +1,13 @@
1
- import type { DeviceBackend } from "./types.mjs";
1
+ import type { DeviceBackend, Platform } from "./types.mjs";
2
+ import type { DetectedDevice } from "../utils/platform.mjs";
2
3
  export type { DeviceBackend } from "./types.mjs";
3
4
  export { AdbBackend } from "./adb-backend.mjs";
4
5
  export { AppiumBackend } from "./appium-backend.mjs";
5
6
  export { IdbBackend } from "./idb-backend.mjs";
6
- export declare function createBackend(explicitDeviceId?: string): Promise<DeviceBackend>;
7
- /**
8
- * Lazy backend that defers device detection to first tool call.
9
- * Allows the MCP server to start and complete the handshake
10
- * even when no device is connected yet.
11
- *
12
- * @param explicitDeviceId - Optional device ID override.
13
- * @returns A DeviceBackend that resolves on first use.
14
- */
15
- export declare function createLazyBackend(explicitDeviceId?: string): DeviceBackend;
7
+ export type LazyDeviceBackend = DeviceBackend & {
8
+ selectDevice(deviceId: string): void;
9
+ listDevices(): Promise<DetectedDevice[]>;
10
+ };
11
+ export declare function createBackend(explicitDeviceId?: string, explicitPlatform?: Platform): Promise<DeviceBackend>;
12
+ export declare function createLazyBackend(explicitDeviceId?: string, explicitPlatform?: Platform): LazyDeviceBackend;
16
13
  //# sourceMappingURL=index.d.mts.map