@metamask/device-mcp 0.1.0 → 0.3.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.
- package/CHANGELOG.md +29 -14
- package/LICENSE +6 -0
- package/LICENSE.APACHE2 +201 -0
- package/LICENSE.MIT +21 -0
- package/README.md +114 -33
- package/dist/backends/adb-backend.cjs +21 -5
- package/dist/backends/adb-backend.cjs.map +1 -1
- package/dist/backends/adb-backend.d.cts +9 -2
- package/dist/backends/adb-backend.d.cts.map +1 -1
- package/dist/backends/adb-backend.d.mts +9 -2
- package/dist/backends/adb-backend.d.mts.map +1 -1
- package/dist/backends/adb-backend.mjs +21 -5
- package/dist/backends/adb-backend.mjs.map +1 -1
- package/dist/backends/appium-backend.cjs +25 -7
- package/dist/backends/appium-backend.cjs.map +1 -1
- package/dist/backends/appium-backend.d.cts +9 -2
- package/dist/backends/appium-backend.d.cts.map +1 -1
- package/dist/backends/appium-backend.d.mts +9 -2
- package/dist/backends/appium-backend.d.mts.map +1 -1
- package/dist/backends/appium-backend.mjs +25 -7
- package/dist/backends/appium-backend.mjs.map +1 -1
- package/dist/backends/idb-backend.cjs +96 -38
- package/dist/backends/idb-backend.cjs.map +1 -1
- package/dist/backends/idb-backend.d.cts +9 -2
- package/dist/backends/idb-backend.d.cts.map +1 -1
- package/dist/backends/idb-backend.d.mts +9 -2
- package/dist/backends/idb-backend.d.mts.map +1 -1
- package/dist/backends/idb-backend.mjs +97 -39
- package/dist/backends/idb-backend.mjs.map +1 -1
- package/dist/backends/index.cjs +37 -15
- package/dist/backends/index.cjs.map +1 -1
- package/dist/backends/index.d.cts +8 -11
- package/dist/backends/index.d.cts.map +1 -1
- package/dist/backends/index.d.mts +8 -11
- package/dist/backends/index.d.mts.map +1 -1
- package/dist/backends/index.mjs +38 -16
- package/dist/backends/index.mjs.map +1 -1
- package/dist/backends/types.cjs.map +1 -1
- package/dist/backends/types.d.cts +20 -1
- package/dist/backends/types.d.cts.map +1 -1
- package/dist/backends/types.d.mts +20 -1
- package/dist/backends/types.d.mts.map +1 -1
- package/dist/backends/types.mjs.map +1 -1
- package/dist/cli/device-mcp.cjs +11 -2
- package/dist/cli/device-mcp.cjs.map +1 -1
- package/dist/cli/device-mcp.mjs +11 -2
- package/dist/cli/device-mcp.mjs.map +1 -1
- package/dist/hermes/hermes-cdp.cjs +674 -0
- package/dist/hermes/hermes-cdp.cjs.map +1 -0
- package/dist/hermes/hermes-cdp.d.cts +248 -0
- package/dist/hermes/hermes-cdp.d.cts.map +1 -0
- package/dist/hermes/hermes-cdp.d.mts +248 -0
- package/dist/hermes/hermes-cdp.d.mts.map +1 -0
- package/dist/hermes/hermes-cdp.mjs +665 -0
- package/dist/hermes/hermes-cdp.mjs.map +1 -0
- package/dist/hermes/session.cjs +196 -0
- package/dist/hermes/session.cjs.map +1 -0
- package/dist/hermes/session.d.cts +163 -0
- package/dist/hermes/session.d.cts.map +1 -0
- package/dist/hermes/session.d.mts +163 -0
- package/dist/hermes/session.d.mts.map +1 -0
- package/dist/hermes/session.mjs +189 -0
- package/dist/hermes/session.mjs.map +1 -0
- package/dist/index.cjs +19 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +8 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/dist/server.cjs +8 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +9 -1
- package/dist/server.mjs.map +1 -1
- package/dist/tools/get-element-text.cjs +46 -0
- package/dist/tools/get-element-text.cjs.map +1 -0
- package/dist/tools/get-element-text.d.cts +4 -0
- package/dist/tools/get-element-text.d.cts.map +1 -0
- package/dist/tools/get-element-text.d.mts +4 -0
- package/dist/tools/get-element-text.d.mts.map +1 -0
- package/dist/tools/get-element-text.mjs +43 -0
- package/dist/tools/get-element-text.mjs.map +1 -0
- package/dist/tools/hermes-cdp.cjs +102 -0
- package/dist/tools/hermes-cdp.cjs.map +1 -0
- package/dist/tools/hermes-cdp.d.cts +18 -0
- package/dist/tools/hermes-cdp.d.cts.map +1 -0
- package/dist/tools/hermes-cdp.d.mts +18 -0
- package/dist/tools/hermes-cdp.d.mts.map +1 -0
- package/dist/tools/hermes-cdp.mjs +99 -0
- package/dist/tools/hermes-cdp.mjs.map +1 -0
- package/dist/tools/hermes-targets.cjs +127 -0
- package/dist/tools/hermes-targets.cjs.map +1 -0
- package/dist/tools/hermes-targets.d.cts +20 -0
- package/dist/tools/hermes-targets.d.cts.map +1 -0
- package/dist/tools/hermes-targets.d.mts +20 -0
- package/dist/tools/hermes-targets.d.mts.map +1 -0
- package/dist/tools/hermes-targets.mjs +124 -0
- package/dist/tools/hermes-targets.mjs.map +1 -0
- package/dist/tools/index.cjs +11 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.cts +5 -0
- package/dist/tools/index.d.cts.map +1 -1
- package/dist/tools/index.d.mts +5 -0
- package/dist/tools/index.d.mts.map +1 -1
- package/dist/tools/index.mjs +5 -0
- package/dist/tools/index.mjs.map +1 -1
- package/dist/tools/list-devices.cjs +36 -0
- package/dist/tools/list-devices.cjs.map +1 -0
- package/dist/tools/list-devices.d.cts +4 -0
- package/dist/tools/list-devices.d.cts.map +1 -0
- package/dist/tools/list-devices.d.mts +4 -0
- package/dist/tools/list-devices.d.mts.map +1 -0
- package/dist/tools/list-devices.mjs +33 -0
- package/dist/tools/list-devices.mjs.map +1 -0
- package/dist/tools/screenshot.cjs +8 -3
- package/dist/tools/screenshot.cjs.map +1 -1
- package/dist/tools/screenshot.d.cts.map +1 -1
- package/dist/tools/screenshot.d.mts.map +1 -1
- package/dist/tools/screenshot.mjs +8 -3
- package/dist/tools/screenshot.mjs.map +1 -1
- package/dist/tools/select-device.cjs +38 -0
- package/dist/tools/select-device.cjs.map +1 -0
- package/dist/tools/select-device.d.cts +4 -0
- package/dist/tools/select-device.d.cts.map +1 -0
- package/dist/tools/select-device.d.mts +4 -0
- package/dist/tools/select-device.d.mts.map +1 -0
- package/dist/tools/select-device.mjs +35 -0
- package/dist/tools/select-device.mjs.map +1 -0
- package/dist/utils/exec.cjs +11 -9
- package/dist/utils/exec.cjs.map +1 -1
- package/dist/utils/exec.d.cts.map +1 -1
- package/dist/utils/exec.d.mts.map +1 -1
- package/dist/utils/exec.mjs +11 -9
- package/dist/utils/exec.mjs.map +1 -1
- package/dist/utils/output-path.cjs +128 -0
- package/dist/utils/output-path.cjs.map +1 -0
- package/dist/utils/output-path.d.cts +41 -0
- package/dist/utils/output-path.d.cts.map +1 -0
- package/dist/utils/output-path.d.mts +41 -0
- package/dist/utils/output-path.d.mts.map +1 -0
- package/dist/utils/output-path.mjs +123 -0
- package/dist/utils/output-path.mjs.map +1 -0
- package/dist/utils/platform.cjs +121 -36
- package/dist/utils/platform.cjs.map +1 -1
- package/dist/utils/platform.d.cts +14 -3
- package/dist/utils/platform.d.cts.map +1 -1
- package/dist/utils/platform.d.mts +14 -3
- package/dist/utils/platform.d.mts.map +1 -1
- package/dist/utils/platform.mjs +117 -36
- package/dist/utils/platform.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { errorResult } from "./shared.mjs";
|
|
3
|
+
import { fetchDiscoveryTargets, hasAmbiguousTarget, LEGACY_SYNTHETIC_TITLE, selectHermesTarget } from "../hermes/hermes-cdp.mjs";
|
|
4
|
+
import { getHermesSession } from "../hermes/session.mjs";
|
|
5
|
+
const DISCOVERY_TIMEOUT_MS = 10000;
|
|
6
|
+
function formatTarget(target) {
|
|
7
|
+
const { reactNative } = target;
|
|
8
|
+
return [
|
|
9
|
+
` id: ${target.id ?? '<unknown>'}`,
|
|
10
|
+
` title: ${target.title ?? '<unknown>'}`,
|
|
11
|
+
` appId: ${target.appId ?? '<unknown>'}`,
|
|
12
|
+
` logicalDeviceId: ${reactNative?.logicalDeviceId ?? '<missing>'}`,
|
|
13
|
+
` nativePageReloads: ${reactNative?.capabilities?.nativePageReloads ?? '<unset>'}`,
|
|
14
|
+
` wsUrl: ${target.webSocketDebuggerUrl ?? '<missing>'}`,
|
|
15
|
+
].join('\n');
|
|
16
|
+
}
|
|
17
|
+
function describeMetroDown(error) {
|
|
18
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
19
|
+
if (message.includes('ECONNREFUSED') || message.includes('fetch failed')) {
|
|
20
|
+
return 'Metro not running or no debuggable app registered.';
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Registers the `hermes_targets` MCP tool, which lists and diagnoses the
|
|
26
|
+
* debuggable Hermes targets that Metro's inspector proxy currently exposes
|
|
27
|
+
* (iOS and Android).
|
|
28
|
+
*
|
|
29
|
+
* The handler is THIN: it resolves the Metro port/appId from
|
|
30
|
+
* {@link getHermesSession}, delegates discovery to {@link fetchDiscoveryTargets}
|
|
31
|
+
* and selection/ambiguity reporting to {@link selectHermesTarget} /
|
|
32
|
+
* {@link hasAmbiguousTarget}, and formats a readable report. With `all` set,
|
|
33
|
+
* it bypasses the appId filter so agents can discover the real appId / confirm
|
|
34
|
+
* Metro is up. No discovery or selection LOGIC lives in this file.
|
|
35
|
+
*
|
|
36
|
+
* @param server - The MCP server to register the tool on.
|
|
37
|
+
* @param backend - The lazy device backend, used at call time only to read the
|
|
38
|
+
* live platform so the session can resolve the correct default app bundle ID.
|
|
39
|
+
*/
|
|
40
|
+
export function registerHermesTargetsTool(server, backend) {
|
|
41
|
+
server.registerTool('hermes_targets', {
|
|
42
|
+
title: 'Hermes Targets',
|
|
43
|
+
description: 'List and diagnose the debuggable React Native Hermes targets that ' +
|
|
44
|
+
'Metro\u2019s inspector proxy currently exposes (iOS and Android). ' +
|
|
45
|
+
'Reports each candidate (id / title / appId / logicalDeviceId / ' +
|
|
46
|
+
'nativePageReloads / wsUrl) plus which target would be chosen or why ' +
|
|
47
|
+
'it is ambiguous. Use it to confirm Metro is running and your app is ' +
|
|
48
|
+
'registered. Requires a DEBUG build with Metro running.',
|
|
49
|
+
inputSchema: {
|
|
50
|
+
metroPort: z
|
|
51
|
+
.number()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Override the Metro inspector proxy port for this call.'),
|
|
54
|
+
appId: z
|
|
55
|
+
.string()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('Override the expected app bundle identifier.'),
|
|
58
|
+
all: z
|
|
59
|
+
.boolean()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe('Bypass the appId filter and list ALL candidates (diagnostics).'),
|
|
62
|
+
},
|
|
63
|
+
annotations: { readOnlyHint: true },
|
|
64
|
+
}, async ({ metroPort, appId, all }) => {
|
|
65
|
+
try {
|
|
66
|
+
const resolved = getHermesSession().resolve({
|
|
67
|
+
metroPort,
|
|
68
|
+
appId,
|
|
69
|
+
platform: backend.platform,
|
|
70
|
+
});
|
|
71
|
+
const targets = await fetchDiscoveryTargets(resolved.metroPort, DISCOVERY_TIMEOUT_MS);
|
|
72
|
+
if (targets.length === 0) {
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: 'text',
|
|
77
|
+
text: 'Metro not running or no debuggable app registered.',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const candidates = all
|
|
83
|
+
? targets
|
|
84
|
+
: targets
|
|
85
|
+
.filter((target) => Boolean(target.webSocketDebuggerUrl))
|
|
86
|
+
.filter((target) => target.title !== LEGACY_SYNTHETIC_TITLE)
|
|
87
|
+
.filter((target) => target.appId === resolved.appId);
|
|
88
|
+
const lines = [
|
|
89
|
+
`Metro port: ${resolved.metroPort}`,
|
|
90
|
+
`Expected appId: ${resolved.appId}${all ? ' (filter bypassed by all=true)' : ''}`,
|
|
91
|
+
`Targets discovered: ${targets.length}`,
|
|
92
|
+
`Candidates listed: ${candidates.length}`,
|
|
93
|
+
'',
|
|
94
|
+
];
|
|
95
|
+
candidates.forEach((target, index) => {
|
|
96
|
+
lines.push(`Candidate ${index + 1}:`, formatTarget(target), '');
|
|
97
|
+
});
|
|
98
|
+
const selection = selectHermesTarget(targets, resolved.appId, resolved.pinnedDeviceId);
|
|
99
|
+
if (selection.ok) {
|
|
100
|
+
lines.push(`Chosen target: ${selection.target.id ?? '<unknown>'} (device=${selection.target.reactNative?.logicalDeviceId ?? '<missing>'})`);
|
|
101
|
+
}
|
|
102
|
+
else if (selection.code === 'HERMES_MULTIPLE_DEVICES' &&
|
|
103
|
+
hasAmbiguousTarget(candidates)) {
|
|
104
|
+
lines.push(`Ambiguous: ${selection.message}`);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
lines.push(`No target chosen: [${selection.code}] ${selection.message}`);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: 'text', text: lines.join('\n') }],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
const metroDown = describeMetroDown(error);
|
|
115
|
+
if (metroDown) {
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: 'text', text: metroDown }],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return errorResult(error);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=hermes-targets.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-targets.mjs","sourceRoot":"","sources":["../../src/tools/hermes-targets.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,YAAY;AAExB,OAAO,EAAE,WAAW,EAAE,qBAAoB;AAE1C,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EACnB,iCAAgC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,8BAA6B;AAExD,MAAM,oBAAoB,GAAG,KAAM,CAAC;AAEpC,SAAS,YAAY,CAAC,MAAoB;IACxC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAC/B,OAAO;QACL,SAAS,MAAM,CAAC,EAAE,IAAI,WAAW,EAAE;QACnC,YAAY,MAAM,CAAC,KAAK,IAAI,WAAW,EAAE;QACzC,YAAY,MAAM,CAAC,KAAK,IAAI,WAAW,EAAE;QACzC,sBAAsB,WAAW,EAAE,eAAe,IAAI,WAAW,EAAE;QACnE,wBACE,WAAW,EAAE,YAAY,EAAE,iBAAiB,IAAI,SAClD,EAAE;QACF,YAAY,MAAM,CAAC,oBAAoB,IAAI,WAAW,EAAE;KACzD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACzE,OAAO,oDAAoD,CAAC;IAC9D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EACT,oEAAoE;YACpE,oEAAoE;YACpE,iEAAiE;YACjE,sEAAsE;YACtE,sEAAsE;YACtE,wDAAwD;QAC1D,WAAW,EAAE;YACX,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,8CAA8C,CAAC;YAC3D,GAAG,EAAE,CAAC;iBACH,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CACP,gEAAgE,CACjE;SACJ;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACpC,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC,OAAO,CAAC;gBAC1C,SAAS;gBACT,KAAK;gBACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC3B,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,qBAAqB,CACzC,QAAQ,CAAC,SAAS,EAClB,oBAAoB,CACrB,CAAC;YAEF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,oDAAoD;yBAC3D;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,GAAG;gBACpB,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,OAAO;qBACJ,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;qBACxD,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,sBAAsB,CAAC;qBAC3D,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC;YAE3D,MAAM,KAAK,GAAa;gBACtB,eAAe,QAAQ,CAAC,SAAS,EAAE;gBACnC,mBAAmB,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE,EAAE;gBACjF,uBAAuB,OAAO,CAAC,MAAM,EAAE;gBACvC,sBAAsB,UAAU,CAAC,MAAM,EAAE;gBACzC,EAAE;aACH,CAAC;YAEF,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;gBACnC,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YAClE,CAAC,CAAC,CAAC;YAEH,MAAM,SAAS,GAAG,kBAAkB,CAClC,OAAO,EACP,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,cAAc,CACxB,CAAC;YACF,IAAI,SAAS,CAAC,EAAE,EAAE,CAAC;gBACjB,KAAK,CAAC,IAAI,CACR,kBAAkB,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,WAAW,YAClD,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,eAAe,IAAI,WACnD,GAAG,CACJ,CAAC;YACJ,CAAC;iBAAM,IACL,SAAS,CAAC,IAAI,KAAK,yBAAyB;gBAC5C,kBAAkB,CAAC,UAAU,CAAC,EAC9B,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,cAAc,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CACR,sBAAsB,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,OAAO,EAAE,CAC7D,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aAC7D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;iBACtD,CAAC;YACJ,CAAC;YACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { errorResult } from './shared.js';\nimport type { DeviceBackend } from '../backends/types.js';\nimport {\n fetchDiscoveryTargets,\n hasAmbiguousTarget,\n LEGACY_SYNTHETIC_TITLE,\n selectHermesTarget,\n} from '../hermes/hermes-cdp.js';\nimport type { HermesTarget } from '../hermes/hermes-cdp.js';\nimport { getHermesSession } from '../hermes/session.js';\n\nconst DISCOVERY_TIMEOUT_MS = 10_000;\n\nfunction formatTarget(target: HermesTarget): string {\n const { reactNative } = target;\n return [\n ` id: ${target.id ?? '<unknown>'}`,\n ` title: ${target.title ?? '<unknown>'}`,\n ` appId: ${target.appId ?? '<unknown>'}`,\n ` logicalDeviceId: ${reactNative?.logicalDeviceId ?? '<missing>'}`,\n ` nativePageReloads: ${\n reactNative?.capabilities?.nativePageReloads ?? '<unset>'\n }`,\n ` wsUrl: ${target.webSocketDebuggerUrl ?? '<missing>'}`,\n ].join('\\n');\n}\n\nfunction describeMetroDown(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes('ECONNREFUSED') || message.includes('fetch failed')) {\n return 'Metro not running or no debuggable app registered.';\n }\n return undefined;\n}\n\n/**\n * Registers the `hermes_targets` MCP tool, which lists and diagnoses the\n * debuggable Hermes targets that Metro's inspector proxy currently exposes\n * (iOS and Android).\n *\n * The handler is THIN: it resolves the Metro port/appId from\n * {@link getHermesSession}, delegates discovery to {@link fetchDiscoveryTargets}\n * and selection/ambiguity reporting to {@link selectHermesTarget} /\n * {@link hasAmbiguousTarget}, and formats a readable report. With `all` set,\n * it bypasses the appId filter so agents can discover the real appId / confirm\n * Metro is up. No discovery or selection LOGIC lives in this file.\n *\n * @param server - The MCP server to register the tool on.\n * @param backend - The lazy device backend, used at call time only to read the\n * live platform so the session can resolve the correct default app bundle ID.\n */\nexport function registerHermesTargetsTool(\n server: McpServer,\n backend: DeviceBackend,\n): void {\n server.registerTool(\n 'hermes_targets',\n {\n title: 'Hermes Targets',\n description:\n 'List and diagnose the debuggable React Native Hermes targets that ' +\n 'Metro\\u2019s inspector proxy currently exposes (iOS and Android). ' +\n 'Reports each candidate (id / title / appId / logicalDeviceId / ' +\n 'nativePageReloads / wsUrl) plus which target would be chosen or why ' +\n 'it is ambiguous. Use it to confirm Metro is running and your app is ' +\n 'registered. Requires a DEBUG build with Metro running.',\n inputSchema: {\n metroPort: z\n .number()\n .optional()\n .describe('Override the Metro inspector proxy port for this call.'),\n appId: z\n .string()\n .optional()\n .describe('Override the expected app bundle identifier.'),\n all: z\n .boolean()\n .optional()\n .describe(\n 'Bypass the appId filter and list ALL candidates (diagnostics).',\n ),\n },\n annotations: { readOnlyHint: true },\n },\n async ({ metroPort, appId, all }) => {\n try {\n const resolved = getHermesSession().resolve({\n metroPort,\n appId,\n platform: backend.platform,\n });\n const targets = await fetchDiscoveryTargets(\n resolved.metroPort,\n DISCOVERY_TIMEOUT_MS,\n );\n\n if (targets.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Metro not running or no debuggable app registered.',\n },\n ],\n };\n }\n\n const candidates = all\n ? targets\n : targets\n .filter((target) => Boolean(target.webSocketDebuggerUrl))\n .filter((target) => target.title !== LEGACY_SYNTHETIC_TITLE)\n .filter((target) => target.appId === resolved.appId);\n\n const lines: string[] = [\n `Metro port: ${resolved.metroPort}`,\n `Expected appId: ${resolved.appId}${all ? ' (filter bypassed by all=true)' : ''}`,\n `Targets discovered: ${targets.length}`,\n `Candidates listed: ${candidates.length}`,\n '',\n ];\n\n candidates.forEach((target, index) => {\n lines.push(`Candidate ${index + 1}:`, formatTarget(target), '');\n });\n\n const selection = selectHermesTarget(\n targets,\n resolved.appId,\n resolved.pinnedDeviceId,\n );\n if (selection.ok) {\n lines.push(\n `Chosen target: ${selection.target.id ?? '<unknown>'} (device=${\n selection.target.reactNative?.logicalDeviceId ?? '<missing>'\n })`,\n );\n } else if (\n selection.code === 'HERMES_MULTIPLE_DEVICES' &&\n hasAmbiguousTarget(candidates)\n ) {\n lines.push(`Ambiguous: ${selection.message}`);\n } else {\n lines.push(\n `No target chosen: [${selection.code}] ${selection.message}`,\n );\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n } catch (error) {\n const metroDown = describeMetroDown(error);\n if (metroDown) {\n return {\n content: [{ type: 'text' as const, text: metroDown }],\n };\n }\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
package/dist/tools/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerGenerateLocatorsTool = exports.registerScreenRecordingTool = exports.registerClipboardTool = exports.registerContextTool = exports.registerWindowSizeTool = exports.registerAlertTextTool = exports.registerScrollToElementTool = exports.registerLogsTool = exports.registerDismissAlertTool = exports.registerDismissKeyboardTool = exports.registerPressButtonTool = exports.registerCloseAppTool = exports.registerOpenAppTool = exports.registerDeviceInfoTool = exports.registerAppStateTool = exports.registerWaitForTool = exports.registerLongPressTool = exports.registerSwipeTool = exports.registerTypeTool = exports.registerTapCoordinatesTool = exports.registerTapElementTool = exports.registerScreenshotTool = exports.registerSnapshotTool = void 0;
|
|
3
|
+
exports.registerHermesTargetsTool = exports.registerHermesCdpTool = exports.registerSelectDeviceTool = exports.registerListDevicesTool = exports.registerGetElementTextTool = exports.registerGenerateLocatorsTool = exports.registerScreenRecordingTool = exports.registerClipboardTool = exports.registerContextTool = exports.registerWindowSizeTool = exports.registerAlertTextTool = exports.registerScrollToElementTool = exports.registerLogsTool = exports.registerDismissAlertTool = exports.registerDismissKeyboardTool = exports.registerPressButtonTool = exports.registerCloseAppTool = exports.registerOpenAppTool = exports.registerDeviceInfoTool = exports.registerAppStateTool = exports.registerWaitForTool = exports.registerLongPressTool = exports.registerSwipeTool = exports.registerTypeTool = exports.registerTapCoordinatesTool = exports.registerTapElementTool = exports.registerScreenshotTool = exports.registerSnapshotTool = void 0;
|
|
4
4
|
var snapshot_js_1 = require("./snapshot.cjs");
|
|
5
5
|
Object.defineProperty(exports, "registerSnapshotTool", { enumerable: true, get: function () { return snapshot_js_1.registerSnapshotTool; } });
|
|
6
6
|
var screenshot_js_1 = require("./screenshot.cjs");
|
|
@@ -47,4 +47,14 @@ var screen_recording_js_1 = require("./screen-recording.cjs");
|
|
|
47
47
|
Object.defineProperty(exports, "registerScreenRecordingTool", { enumerable: true, get: function () { return screen_recording_js_1.registerScreenRecordingTool; } });
|
|
48
48
|
var generate_locators_js_1 = require("./generate-locators.cjs");
|
|
49
49
|
Object.defineProperty(exports, "registerGenerateLocatorsTool", { enumerable: true, get: function () { return generate_locators_js_1.registerGenerateLocatorsTool; } });
|
|
50
|
+
var get_element_text_js_1 = require("./get-element-text.cjs");
|
|
51
|
+
Object.defineProperty(exports, "registerGetElementTextTool", { enumerable: true, get: function () { return get_element_text_js_1.registerGetElementTextTool; } });
|
|
52
|
+
var list_devices_js_1 = require("./list-devices.cjs");
|
|
53
|
+
Object.defineProperty(exports, "registerListDevicesTool", { enumerable: true, get: function () { return list_devices_js_1.registerListDevicesTool; } });
|
|
54
|
+
var select_device_js_1 = require("./select-device.cjs");
|
|
55
|
+
Object.defineProperty(exports, "registerSelectDeviceTool", { enumerable: true, get: function () { return select_device_js_1.registerSelectDeviceTool; } });
|
|
56
|
+
var hermes_cdp_js_1 = require("./hermes-cdp.cjs");
|
|
57
|
+
Object.defineProperty(exports, "registerHermesCdpTool", { enumerable: true, get: function () { return hermes_cdp_js_1.registerHermesCdpTool; } });
|
|
58
|
+
var hermes_targets_js_1 = require("./hermes-targets.cjs");
|
|
59
|
+
Object.defineProperty(exports, "registerHermesTargetsTool", { enumerable: true, get: function () { return hermes_targets_js_1.registerHermesTargetsTool; } });
|
|
50
60
|
//# sourceMappingURL=index.cjs.map
|
package/dist/tools/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":";;;AAAA,8CAAqD;AAA5C,mHAAA,oBAAoB,OAAA;AAC7B,kDAAyD;AAAhD,uHAAA,sBAAsB,OAAA;AAC/B,oDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,4DAAkE;AAAzD,gIAAA,0BAA0B,OAAA;AACnC,gDAAkD;AAAzC,gHAAA,gBAAgB,OAAA;AACzB,wCAA+C;AAAtC,6GAAA,iBAAiB,OAAA;AAC1B,kDAAwD;AAA/C,sHAAA,qBAAqB,OAAA;AAC9B,8CAAoD;AAA3C,kHAAA,mBAAmB,OAAA;AAC5B,gDAAsD;AAA7C,oHAAA,oBAAoB,OAAA;AAC7B,oDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,8CAAoD;AAA3C,kHAAA,mBAAmB,OAAA;AAC5B,gDAAsD;AAA7C,oHAAA,oBAAoB,OAAA;AAC7B,sDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,8DAAoE;AAA3D,kIAAA,2BAA2B,OAAA;AACpC,wDAA8D;AAArD,4HAAA,wBAAwB,OAAA;AACjC,sCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AACzB,gEAAqE;AAA5D,mIAAA,2BAA2B,OAAA;AACpC,kDAAwD;AAA/C,sHAAA,qBAAqB,OAAA;AAC9B,oDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,4CAAmD;AAA1C,iHAAA,mBAAmB,OAAA;AAC5B,gDAAuD;AAA9C,qHAAA,qBAAqB,OAAA;AAC9B,8DAAoE;AAA3D,kIAAA,2BAA2B,OAAA;AACpC,gEAAsE;AAA7D,oIAAA,4BAA4B,OAAA","sourcesContent":["export { registerSnapshotTool } from './snapshot.js';\nexport { registerScreenshotTool } from './screenshot.js';\nexport { registerTapElementTool } from './tap-element.js';\nexport { registerTapCoordinatesTool } from './tap-coordinates.js';\nexport { registerTypeTool } from './type-text.js';\nexport { registerSwipeTool } from './swipe.js';\nexport { registerLongPressTool } from './long-press.js';\nexport { registerWaitForTool } from './wait-for.js';\nexport { registerAppStateTool } from './app-state.js';\nexport { registerDeviceInfoTool } from './device-info.js';\nexport { registerOpenAppTool } from './open-app.js';\nexport { registerCloseAppTool } from './close-app.js';\nexport { registerPressButtonTool } from './press-button.js';\nexport { registerDismissKeyboardTool } from './dismiss-keyboard.js';\nexport { registerDismissAlertTool } from './dismiss-alert.js';\nexport { registerLogsTool } from './logs.js';\nexport { registerScrollToElementTool } from './scroll-to-element.js';\nexport { registerAlertTextTool } from './alert-text.js';\nexport { registerWindowSizeTool } from './window-size.js';\nexport { registerContextTool } from './context.js';\nexport { registerClipboardTool } from './clipboard.js';\nexport { registerScreenRecordingTool } from './screen-recording.js';\nexport { registerGenerateLocatorsTool } from './generate-locators.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":";;;AAAA,8CAAqD;AAA5C,mHAAA,oBAAoB,OAAA;AAC7B,kDAAyD;AAAhD,uHAAA,sBAAsB,OAAA;AAC/B,oDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,4DAAkE;AAAzD,gIAAA,0BAA0B,OAAA;AACnC,gDAAkD;AAAzC,gHAAA,gBAAgB,OAAA;AACzB,wCAA+C;AAAtC,6GAAA,iBAAiB,OAAA;AAC1B,kDAAwD;AAA/C,sHAAA,qBAAqB,OAAA;AAC9B,8CAAoD;AAA3C,kHAAA,mBAAmB,OAAA;AAC5B,gDAAsD;AAA7C,oHAAA,oBAAoB,OAAA;AAC7B,oDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,8CAAoD;AAA3C,kHAAA,mBAAmB,OAAA;AAC5B,gDAAsD;AAA7C,oHAAA,oBAAoB,OAAA;AAC7B,sDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,8DAAoE;AAA3D,kIAAA,2BAA2B,OAAA;AACpC,wDAA8D;AAArD,4HAAA,wBAAwB,OAAA;AACjC,sCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AACzB,gEAAqE;AAA5D,mIAAA,2BAA2B,OAAA;AACpC,kDAAwD;AAA/C,sHAAA,qBAAqB,OAAA;AAC9B,oDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,4CAAmD;AAA1C,iHAAA,mBAAmB,OAAA;AAC5B,gDAAuD;AAA9C,qHAAA,qBAAqB,OAAA;AAC9B,8DAAoE;AAA3D,kIAAA,2BAA2B,OAAA;AACpC,gEAAsE;AAA7D,oIAAA,4BAA4B,OAAA;AACrC,8DAAmE;AAA1D,iIAAA,0BAA0B,OAAA;AACnC,sDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,wDAA8D;AAArD,4HAAA,wBAAwB,OAAA;AACjC,kDAAwD;AAA/C,sHAAA,qBAAqB,OAAA;AAC9B,0DAAgE;AAAvD,8HAAA,yBAAyB,OAAA","sourcesContent":["export { registerSnapshotTool } from './snapshot.js';\nexport { registerScreenshotTool } from './screenshot.js';\nexport { registerTapElementTool } from './tap-element.js';\nexport { registerTapCoordinatesTool } from './tap-coordinates.js';\nexport { registerTypeTool } from './type-text.js';\nexport { registerSwipeTool } from './swipe.js';\nexport { registerLongPressTool } from './long-press.js';\nexport { registerWaitForTool } from './wait-for.js';\nexport { registerAppStateTool } from './app-state.js';\nexport { registerDeviceInfoTool } from './device-info.js';\nexport { registerOpenAppTool } from './open-app.js';\nexport { registerCloseAppTool } from './close-app.js';\nexport { registerPressButtonTool } from './press-button.js';\nexport { registerDismissKeyboardTool } from './dismiss-keyboard.js';\nexport { registerDismissAlertTool } from './dismiss-alert.js';\nexport { registerLogsTool } from './logs.js';\nexport { registerScrollToElementTool } from './scroll-to-element.js';\nexport { registerAlertTextTool } from './alert-text.js';\nexport { registerWindowSizeTool } from './window-size.js';\nexport { registerContextTool } from './context.js';\nexport { registerClipboardTool } from './clipboard.js';\nexport { registerScreenRecordingTool } from './screen-recording.js';\nexport { registerGenerateLocatorsTool } from './generate-locators.js';\nexport { registerGetElementTextTool } from './get-element-text.js';\nexport { registerListDevicesTool } from './list-devices.js';\nexport { registerSelectDeviceTool } from './select-device.js';\nexport { registerHermesCdpTool } from './hermes-cdp.js';\nexport { registerHermesTargetsTool } from './hermes-targets.js';\n"]}
|
package/dist/tools/index.d.cts
CHANGED
|
@@ -21,4 +21,9 @@ export { registerContextTool } from "./context.cjs";
|
|
|
21
21
|
export { registerClipboardTool } from "./clipboard.cjs";
|
|
22
22
|
export { registerScreenRecordingTool } from "./screen-recording.cjs";
|
|
23
23
|
export { registerGenerateLocatorsTool } from "./generate-locators.cjs";
|
|
24
|
+
export { registerGetElementTextTool } from "./get-element-text.cjs";
|
|
25
|
+
export { registerListDevicesTool } from "./list-devices.cjs";
|
|
26
|
+
export { registerSelectDeviceTool } from "./select-device.cjs";
|
|
27
|
+
export { registerHermesCdpTool } from "./hermes-cdp.cjs";
|
|
28
|
+
export { registerHermesTargetsTool } from "./hermes-targets.cjs";
|
|
24
29
|
//# sourceMappingURL=index.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAsB;AACrD,OAAO,EAAE,sBAAsB,EAAE,yBAAwB;AACzD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,0BAA0B,EAAE,8BAA6B;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAuB;AAClD,OAAO,EAAE,iBAAiB,EAAE,oBAAmB;AAC/C,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,gBAAgB,EAAE,mBAAkB;AAC7C,OAAO,EAAE,2BAA2B,EAAE,gCAA+B;AACrE,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,sBAAqB;AACnD,OAAO,EAAE,qBAAqB,EAAE,wBAAuB;AACvD,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,4BAA4B,EAAE,gCAA+B"}
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAsB;AACrD,OAAO,EAAE,sBAAsB,EAAE,yBAAwB;AACzD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,0BAA0B,EAAE,8BAA6B;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAuB;AAClD,OAAO,EAAE,iBAAiB,EAAE,oBAAmB;AAC/C,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,gBAAgB,EAAE,mBAAkB;AAC7C,OAAO,EAAE,2BAA2B,EAAE,gCAA+B;AACrE,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,sBAAqB;AACnD,OAAO,EAAE,qBAAqB,EAAE,wBAAuB;AACvD,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,4BAA4B,EAAE,gCAA+B;AACtE,OAAO,EAAE,0BAA0B,EAAE,+BAA8B;AACnE,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,yBAAyB,EAAE,6BAA4B"}
|
package/dist/tools/index.d.mts
CHANGED
|
@@ -21,4 +21,9 @@ export { registerContextTool } from "./context.mjs";
|
|
|
21
21
|
export { registerClipboardTool } from "./clipboard.mjs";
|
|
22
22
|
export { registerScreenRecordingTool } from "./screen-recording.mjs";
|
|
23
23
|
export { registerGenerateLocatorsTool } from "./generate-locators.mjs";
|
|
24
|
+
export { registerGetElementTextTool } from "./get-element-text.mjs";
|
|
25
|
+
export { registerListDevicesTool } from "./list-devices.mjs";
|
|
26
|
+
export { registerSelectDeviceTool } from "./select-device.mjs";
|
|
27
|
+
export { registerHermesCdpTool } from "./hermes-cdp.mjs";
|
|
28
|
+
export { registerHermesTargetsTool } from "./hermes-targets.mjs";
|
|
24
29
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAsB;AACrD,OAAO,EAAE,sBAAsB,EAAE,yBAAwB;AACzD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,0BAA0B,EAAE,8BAA6B;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAuB;AAClD,OAAO,EAAE,iBAAiB,EAAE,oBAAmB;AAC/C,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,gBAAgB,EAAE,mBAAkB;AAC7C,OAAO,EAAE,2BAA2B,EAAE,gCAA+B;AACrE,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,sBAAqB;AACnD,OAAO,EAAE,qBAAqB,EAAE,wBAAuB;AACvD,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,4BAA4B,EAAE,gCAA+B"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAsB;AACrD,OAAO,EAAE,sBAAsB,EAAE,yBAAwB;AACzD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,0BAA0B,EAAE,8BAA6B;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAuB;AAClD,OAAO,EAAE,iBAAiB,EAAE,oBAAmB;AAC/C,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,gBAAgB,EAAE,mBAAkB;AAC7C,OAAO,EAAE,2BAA2B,EAAE,gCAA+B;AACrE,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,sBAAqB;AACnD,OAAO,EAAE,qBAAqB,EAAE,wBAAuB;AACvD,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,4BAA4B,EAAE,gCAA+B;AACtE,OAAO,EAAE,0BAA0B,EAAE,+BAA8B;AACnE,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,yBAAyB,EAAE,6BAA4B"}
|
package/dist/tools/index.mjs
CHANGED
|
@@ -21,4 +21,9 @@ export { registerContextTool } from "./context.mjs";
|
|
|
21
21
|
export { registerClipboardTool } from "./clipboard.mjs";
|
|
22
22
|
export { registerScreenRecordingTool } from "./screen-recording.mjs";
|
|
23
23
|
export { registerGenerateLocatorsTool } from "./generate-locators.mjs";
|
|
24
|
+
export { registerGetElementTextTool } from "./get-element-text.mjs";
|
|
25
|
+
export { registerListDevicesTool } from "./list-devices.mjs";
|
|
26
|
+
export { registerSelectDeviceTool } from "./select-device.mjs";
|
|
27
|
+
export { registerHermesCdpTool } from "./hermes-cdp.mjs";
|
|
28
|
+
export { registerHermesTargetsTool } from "./hermes-targets.mjs";
|
|
24
29
|
//# sourceMappingURL=index.mjs.map
|
package/dist/tools/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAsB;AACrD,OAAO,EAAE,sBAAsB,EAAE,yBAAwB;AACzD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,0BAA0B,EAAE,8BAA6B;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAuB;AAClD,OAAO,EAAE,iBAAiB,EAAE,oBAAmB;AAC/C,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,gBAAgB,EAAE,mBAAkB;AAC7C,OAAO,EAAE,2BAA2B,EAAE,gCAA+B;AACrE,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,sBAAqB;AACnD,OAAO,EAAE,qBAAqB,EAAE,wBAAuB;AACvD,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,4BAA4B,EAAE,gCAA+B","sourcesContent":["export { registerSnapshotTool } from './snapshot.js';\nexport { registerScreenshotTool } from './screenshot.js';\nexport { registerTapElementTool } from './tap-element.js';\nexport { registerTapCoordinatesTool } from './tap-coordinates.js';\nexport { registerTypeTool } from './type-text.js';\nexport { registerSwipeTool } from './swipe.js';\nexport { registerLongPressTool } from './long-press.js';\nexport { registerWaitForTool } from './wait-for.js';\nexport { registerAppStateTool } from './app-state.js';\nexport { registerDeviceInfoTool } from './device-info.js';\nexport { registerOpenAppTool } from './open-app.js';\nexport { registerCloseAppTool } from './close-app.js';\nexport { registerPressButtonTool } from './press-button.js';\nexport { registerDismissKeyboardTool } from './dismiss-keyboard.js';\nexport { registerDismissAlertTool } from './dismiss-alert.js';\nexport { registerLogsTool } from './logs.js';\nexport { registerScrollToElementTool } from './scroll-to-element.js';\nexport { registerAlertTextTool } from './alert-text.js';\nexport { registerWindowSizeTool } from './window-size.js';\nexport { registerContextTool } from './context.js';\nexport { registerClipboardTool } from './clipboard.js';\nexport { registerScreenRecordingTool } from './screen-recording.js';\nexport { registerGenerateLocatorsTool } from './generate-locators.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAsB;AACrD,OAAO,EAAE,sBAAsB,EAAE,yBAAwB;AACzD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,0BAA0B,EAAE,8BAA6B;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAuB;AAClD,OAAO,EAAE,iBAAiB,EAAE,oBAAmB;AAC/C,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,uBAAsB;AACpD,OAAO,EAAE,oBAAoB,EAAE,wBAAuB;AACtD,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,gBAAgB,EAAE,mBAAkB;AAC7C,OAAO,EAAE,2BAA2B,EAAE,gCAA+B;AACrE,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,sBAAsB,EAAE,0BAAyB;AAC1D,OAAO,EAAE,mBAAmB,EAAE,sBAAqB;AACnD,OAAO,EAAE,qBAAqB,EAAE,wBAAuB;AACvD,OAAO,EAAE,2BAA2B,EAAE,+BAA8B;AACpE,OAAO,EAAE,4BAA4B,EAAE,gCAA+B;AACtE,OAAO,EAAE,0BAA0B,EAAE,+BAA8B;AACnE,OAAO,EAAE,uBAAuB,EAAE,2BAA0B;AAC5D,OAAO,EAAE,wBAAwB,EAAE,4BAA2B;AAC9D,OAAO,EAAE,qBAAqB,EAAE,yBAAwB;AACxD,OAAO,EAAE,yBAAyB,EAAE,6BAA4B","sourcesContent":["export { registerSnapshotTool } from './snapshot.js';\nexport { registerScreenshotTool } from './screenshot.js';\nexport { registerTapElementTool } from './tap-element.js';\nexport { registerTapCoordinatesTool } from './tap-coordinates.js';\nexport { registerTypeTool } from './type-text.js';\nexport { registerSwipeTool } from './swipe.js';\nexport { registerLongPressTool } from './long-press.js';\nexport { registerWaitForTool } from './wait-for.js';\nexport { registerAppStateTool } from './app-state.js';\nexport { registerDeviceInfoTool } from './device-info.js';\nexport { registerOpenAppTool } from './open-app.js';\nexport { registerCloseAppTool } from './close-app.js';\nexport { registerPressButtonTool } from './press-button.js';\nexport { registerDismissKeyboardTool } from './dismiss-keyboard.js';\nexport { registerDismissAlertTool } from './dismiss-alert.js';\nexport { registerLogsTool } from './logs.js';\nexport { registerScrollToElementTool } from './scroll-to-element.js';\nexport { registerAlertTextTool } from './alert-text.js';\nexport { registerWindowSizeTool } from './window-size.js';\nexport { registerContextTool } from './context.js';\nexport { registerClipboardTool } from './clipboard.js';\nexport { registerScreenRecordingTool } from './screen-recording.js';\nexport { registerGenerateLocatorsTool } from './generate-locators.js';\nexport { registerGetElementTextTool } from './get-element-text.js';\nexport { registerListDevicesTool } from './list-devices.js';\nexport { registerSelectDeviceTool } from './select-device.js';\nexport { registerHermesCdpTool } from './hermes-cdp.js';\nexport { registerHermesTargetsTool } from './hermes-targets.js';\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerListDevicesTool = registerListDevicesTool;
|
|
4
|
+
const shared_js_1 = require("./shared.cjs");
|
|
5
|
+
function registerListDevicesTool(server, backend) {
|
|
6
|
+
server.registerTool('device_list_devices', {
|
|
7
|
+
title: 'List Devices',
|
|
8
|
+
description: 'List all connected devices and simulators/emulators.',
|
|
9
|
+
inputSchema: {},
|
|
10
|
+
annotations: { readOnlyHint: true },
|
|
11
|
+
}, async () => {
|
|
12
|
+
try {
|
|
13
|
+
const devices = await backend.listDevices();
|
|
14
|
+
if (devices.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: 'No connected devices found. Boot a simulator/emulator or connect a device.',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const header = 'Platform\tDevice ID';
|
|
25
|
+
const rows = devices.map((d) => `${d.platform}\t${d.deviceId}`);
|
|
26
|
+
const text = [header, ...rows].join('\n');
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return (0, shared_js_1.errorResult)(error);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=list-devices.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-devices.cjs","sourceRoot":"","sources":["../../src/tools/list-devices.ts"],"names":[],"mappings":";;AAKA,0DAuCC;AA1CD,4CAA0C;AAG1C,SAAgB,uBAAuB,CACrC,MAAiB,EACjB,OAA0B;IAE1B,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,sDAAsD;QACnE,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACpC,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;YAE5C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,4EAA4E;yBACnF;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,qBAAqB,CAAC;YACrC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE1C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;aAC3C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAA,uBAAW,EAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { errorResult } from './shared.js';\nimport type { LazyDeviceBackend } from '../backends/index.js';\n\nexport function registerListDevicesTool(\n server: McpServer,\n backend: LazyDeviceBackend,\n): void {\n server.registerTool(\n 'device_list_devices',\n {\n title: 'List Devices',\n description: 'List all connected devices and simulators/emulators.',\n inputSchema: {},\n annotations: { readOnlyHint: true },\n },\n async () => {\n try {\n const devices = await backend.listDevices();\n\n if (devices.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'No connected devices found. Boot a simulator/emulator or connect a device.',\n },\n ],\n };\n }\n\n const header = 'Platform\\tDevice ID';\n const rows = devices.map((d) => `${d.platform}\\t${d.deviceId}`);\n const text = [header, ...rows].join('\\n');\n\n return {\n content: [{ type: 'text' as const, text }],\n };\n } catch (error) {\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { LazyDeviceBackend } from "../backends/index.cjs";
|
|
3
|
+
export declare function registerListDevicesTool(server: McpServer, backend: LazyDeviceBackend): void;
|
|
4
|
+
//# sourceMappingURL=list-devices.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-devices.d.cts","sourceRoot":"","sources":["../../src/tools/list-devices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAGzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA6B;AAE9D,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { LazyDeviceBackend } from "../backends/index.mjs";
|
|
3
|
+
export declare function registerListDevicesTool(server: McpServer, backend: LazyDeviceBackend): void;
|
|
4
|
+
//# sourceMappingURL=list-devices.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-devices.d.mts","sourceRoot":"","sources":["../../src/tools/list-devices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAGzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA6B;AAE9D,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { errorResult } from "./shared.mjs";
|
|
2
|
+
export function registerListDevicesTool(server, backend) {
|
|
3
|
+
server.registerTool('device_list_devices', {
|
|
4
|
+
title: 'List Devices',
|
|
5
|
+
description: 'List all connected devices and simulators/emulators.',
|
|
6
|
+
inputSchema: {},
|
|
7
|
+
annotations: { readOnlyHint: true },
|
|
8
|
+
}, async () => {
|
|
9
|
+
try {
|
|
10
|
+
const devices = await backend.listDevices();
|
|
11
|
+
if (devices.length === 0) {
|
|
12
|
+
return {
|
|
13
|
+
content: [
|
|
14
|
+
{
|
|
15
|
+
type: 'text',
|
|
16
|
+
text: 'No connected devices found. Boot a simulator/emulator or connect a device.',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const header = 'Platform\tDevice ID';
|
|
22
|
+
const rows = devices.map((d) => `${d.platform}\t${d.deviceId}`);
|
|
23
|
+
const text = [header, ...rows].join('\n');
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: 'text', text }],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return errorResult(error);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=list-devices.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-devices.mjs","sourceRoot":"","sources":["../../src/tools/list-devices.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,qBAAoB;AAG1C,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,OAA0B;IAE1B,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,sDAAsD;QACnE,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACpC,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;YAE5C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,4EAA4E;yBACnF;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,qBAAqB,CAAC;YACrC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE1C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;aAC3C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { errorResult } from './shared.js';\nimport type { LazyDeviceBackend } from '../backends/index.js';\n\nexport function registerListDevicesTool(\n server: McpServer,\n backend: LazyDeviceBackend,\n): void {\n server.registerTool(\n 'device_list_devices',\n {\n title: 'List Devices',\n description: 'List all connected devices and simulators/emulators.',\n inputSchema: {},\n annotations: { readOnlyHint: true },\n },\n async () => {\n try {\n const devices = await backend.listDevices();\n\n if (devices.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'No connected devices found. Boot a simulator/emulator or connect a device.',\n },\n ],\n };\n }\n\n const header = 'Platform\\tDevice ID';\n const rows = devices.map((d) => `${d.platform}\\t${d.deviceId}`);\n const text = [header, ...rows].join('\\n');\n\n return {\n content: [{ type: 'text' as const, text }],\n };\n } catch (error) {\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
|
@@ -17,14 +17,19 @@ function registerScreenshotTool(server, backend) {
|
|
|
17
17
|
annotations: { readOnlyHint: true },
|
|
18
18
|
}, async ({ outputPath }) => {
|
|
19
19
|
try {
|
|
20
|
-
const result = await backend.screenshot(outputPath);
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const result = await backend.screenshot(outputPath, { encode: true });
|
|
21
|
+
const imageContent = result.data
|
|
22
|
+
? [
|
|
23
23
|
{
|
|
24
24
|
type: 'image',
|
|
25
25
|
data: result.data,
|
|
26
26
|
mimeType: `image/${result.format}`,
|
|
27
27
|
},
|
|
28
|
+
]
|
|
29
|
+
: [];
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
...imageContent,
|
|
28
33
|
{
|
|
29
34
|
type: 'text',
|
|
30
35
|
text: result.path
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.cjs","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":";;AAMA,
|
|
1
|
+
{"version":3,"file":"screenshot.cjs","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":";;AAMA,wDA+CC;AApDD,6BAAwB;AAExB,4CAA0C;AAG1C,SAAgB,sBAAsB,CACpC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,YAAY;QACnB,WAAW,EACT,qDAAqD;YACrD,mEAAmE;QACrE,WAAW,EAAE;YACX,UAAU,EAAE,OAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,6CAA6C,CAAC;SAC3D;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACpC,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI;gBAC9B,CAAC,CAAC;oBACE;wBACE,IAAI,EAAE,OAAgB;wBACtB,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,QAAQ,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE;qBACnC;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,OAAO;gBACL,OAAO,EAAE;oBACP,GAAG,YAAY;oBACf;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,MAAM,CAAC,IAAI;4BACf,CAAC,CAAC,uBAAuB,MAAM,CAAC,IAAI,EAAE;4BACtC,CAAC,CAAC,qBAAqB;qBAC1B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAA,uBAAW,EAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { errorResult } from './shared.js';\nimport type { DeviceBackend } from '../backends/types.js';\n\nexport function registerScreenshotTool(\n server: McpServer,\n backend: DeviceBackend,\n): void {\n server.registerTool(\n 'device_screenshot',\n {\n title: 'Screenshot',\n description:\n 'Capture a screenshot of the current device screen. ' +\n 'Returns base64-encoded PNG data. Optionally saves to a file path.',\n inputSchema: {\n outputPath: z\n .string()\n .optional()\n .describe('File path to save the screenshot (optional)'),\n },\n annotations: { readOnlyHint: true },\n },\n async ({ outputPath }) => {\n try {\n const result = await backend.screenshot(outputPath, { encode: true });\n const imageContent = result.data\n ? [\n {\n type: 'image' as const,\n data: result.data,\n mimeType: `image/${result.format}`,\n },\n ]\n : [];\n return {\n content: [\n ...imageContent,\n {\n type: 'text' as const,\n text: result.path\n ? `Screenshot saved to ${result.path}`\n : 'Screenshot captured',\n },\n ],\n };\n } catch (error) {\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.d.cts","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAIzE,OAAO,KAAK,EAAE,aAAa,EAAE,8BAA6B;AAE1D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,aAAa,GACrB,IAAI,
|
|
1
|
+
{"version":3,"file":"screenshot.d.cts","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAIzE,OAAO,KAAK,EAAE,aAAa,EAAE,8BAA6B;AAE1D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,aAAa,GACrB,IAAI,CA4CN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.d.mts","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAIzE,OAAO,KAAK,EAAE,aAAa,EAAE,8BAA6B;AAE1D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,aAAa,GACrB,IAAI,
|
|
1
|
+
{"version":3,"file":"screenshot.d.mts","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAIzE,OAAO,KAAK,EAAE,aAAa,EAAE,8BAA6B;AAE1D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,aAAa,GACrB,IAAI,CA4CN"}
|
|
@@ -14,14 +14,19 @@ export function registerScreenshotTool(server, backend) {
|
|
|
14
14
|
annotations: { readOnlyHint: true },
|
|
15
15
|
}, async ({ outputPath }) => {
|
|
16
16
|
try {
|
|
17
|
-
const result = await backend.screenshot(outputPath);
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const result = await backend.screenshot(outputPath, { encode: true });
|
|
18
|
+
const imageContent = result.data
|
|
19
|
+
? [
|
|
20
20
|
{
|
|
21
21
|
type: 'image',
|
|
22
22
|
data: result.data,
|
|
23
23
|
mimeType: `image/${result.format}`,
|
|
24
24
|
},
|
|
25
|
+
]
|
|
26
|
+
: [];
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
...imageContent,
|
|
25
30
|
{
|
|
26
31
|
type: 'text',
|
|
27
32
|
text: result.path
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.mjs","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,YAAY;AAExB,OAAO,EAAE,WAAW,EAAE,qBAAoB;AAG1C,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,YAAY;QACnB,WAAW,EACT,qDAAqD;YACrD,mEAAmE;QACrE,WAAW,EAAE;YACX,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,6CAA6C,CAAC;SAC3D;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACpC,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"screenshot.mjs","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,YAAY;AAExB,OAAO,EAAE,WAAW,EAAE,qBAAoB;AAG1C,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,YAAY;QACnB,WAAW,EACT,qDAAqD;YACrD,mEAAmE;QACrE,WAAW,EAAE;YACX,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,6CAA6C,CAAC;SAC3D;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACpC,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI;gBAC9B,CAAC,CAAC;oBACE;wBACE,IAAI,EAAE,OAAgB;wBACtB,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,QAAQ,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE;qBACnC;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,OAAO;gBACL,OAAO,EAAE;oBACP,GAAG,YAAY;oBACf;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,MAAM,CAAC,IAAI;4BACf,CAAC,CAAC,uBAAuB,MAAM,CAAC,IAAI,EAAE;4BACtC,CAAC,CAAC,qBAAqB;qBAC1B;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { errorResult } from './shared.js';\nimport type { DeviceBackend } from '../backends/types.js';\n\nexport function registerScreenshotTool(\n server: McpServer,\n backend: DeviceBackend,\n): void {\n server.registerTool(\n 'device_screenshot',\n {\n title: 'Screenshot',\n description:\n 'Capture a screenshot of the current device screen. ' +\n 'Returns base64-encoded PNG data. Optionally saves to a file path.',\n inputSchema: {\n outputPath: z\n .string()\n .optional()\n .describe('File path to save the screenshot (optional)'),\n },\n annotations: { readOnlyHint: true },\n },\n async ({ outputPath }) => {\n try {\n const result = await backend.screenshot(outputPath, { encode: true });\n const imageContent = result.data\n ? [\n {\n type: 'image' as const,\n data: result.data,\n mimeType: `image/${result.format}`,\n },\n ]\n : [];\n return {\n content: [\n ...imageContent,\n {\n type: 'text' as const,\n text: result.path\n ? `Screenshot saved to ${result.path}`\n : 'Screenshot captured',\n },\n ],\n };\n } catch (error) {\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSelectDeviceTool = registerSelectDeviceTool;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const shared_js_1 = require("./shared.cjs");
|
|
6
|
+
function registerSelectDeviceTool(server, backend) {
|
|
7
|
+
server.registerTool('device_select_device', {
|
|
8
|
+
title: 'Select Device',
|
|
9
|
+
description: 'Select a device to use for this session. Call device_list_devices first to see available devices.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
deviceId: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.describe('Device ID to select (UDID for iOS, serial for Android)'),
|
|
14
|
+
},
|
|
15
|
+
}, async ({ deviceId }) => {
|
|
16
|
+
try {
|
|
17
|
+
backend.selectDevice(deviceId);
|
|
18
|
+
const info = await backend.getDeviceInfo();
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: 'text',
|
|
23
|
+
text: [
|
|
24
|
+
`Selected device: ${info.name}`,
|
|
25
|
+
`Platform: ${info.platform}`,
|
|
26
|
+
`OS: ${info.osVersion}`,
|
|
27
|
+
`ID: ${info.deviceId}`,
|
|
28
|
+
].join('\n'),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
return (0, shared_js_1.errorResult)(error);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=select-device.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-device.cjs","sourceRoot":"","sources":["../../src/tools/select-device.ts"],"names":[],"mappings":";;AAMA,4DAuCC;AA5CD,6BAAwB;AAExB,4CAA0C;AAG1C,SAAgB,wBAAwB,CACtC,MAAiB,EACjB,OAA0B;IAE1B,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EACT,mGAAmG;QACrG,WAAW,EAAE;YACX,QAAQ,EAAE,OAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CAAC,wDAAwD,CAAC;SACtE;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;YAE3C,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;4BACJ,oBAAoB,IAAI,CAAC,IAAI,EAAE;4BAC/B,aAAa,IAAI,CAAC,QAAQ,EAAE;4BAC5B,OAAO,IAAI,CAAC,SAAS,EAAE;4BACvB,OAAO,IAAI,CAAC,QAAQ,EAAE;yBACvB,CAAC,IAAI,CAAC,IAAI,CAAC;qBACb;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAA,uBAAW,EAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { errorResult } from './shared.js';\nimport type { LazyDeviceBackend } from '../backends/index.js';\n\nexport function registerSelectDeviceTool(\n server: McpServer,\n backend: LazyDeviceBackend,\n): void {\n server.registerTool(\n 'device_select_device',\n {\n title: 'Select Device',\n description:\n 'Select a device to use for this session. Call device_list_devices first to see available devices.',\n inputSchema: {\n deviceId: z\n .string()\n .describe('Device ID to select (UDID for iOS, serial for Android)'),\n },\n },\n async ({ deviceId }) => {\n try {\n backend.selectDevice(deviceId);\n const info = await backend.getDeviceInfo();\n\n return {\n content: [\n {\n type: 'text' as const,\n text: [\n `Selected device: ${info.name}`,\n `Platform: ${info.platform}`,\n `OS: ${info.osVersion}`,\n `ID: ${info.deviceId}`,\n ].join('\\n'),\n },\n ],\n };\n } catch (error) {\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { LazyDeviceBackend } from "../backends/index.cjs";
|
|
3
|
+
export declare function registerSelectDeviceTool(server: McpServer, backend: LazyDeviceBackend): void;
|
|
4
|
+
//# sourceMappingURL=select-device.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-device.d.cts","sourceRoot":"","sources":["../../src/tools/select-device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAIzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA6B;AAE9D,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { LazyDeviceBackend } from "../backends/index.mjs";
|
|
3
|
+
export declare function registerSelectDeviceTool(server: McpServer, backend: LazyDeviceBackend): void;
|
|
4
|
+
//# sourceMappingURL=select-device.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-device.d.mts","sourceRoot":"","sources":["../../src/tools/select-device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gDAAgD;AAIzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,8BAA6B;AAE9D,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { errorResult } from "./shared.mjs";
|
|
3
|
+
export function registerSelectDeviceTool(server, backend) {
|
|
4
|
+
server.registerTool('device_select_device', {
|
|
5
|
+
title: 'Select Device',
|
|
6
|
+
description: 'Select a device to use for this session. Call device_list_devices first to see available devices.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
deviceId: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe('Device ID to select (UDID for iOS, serial for Android)'),
|
|
11
|
+
},
|
|
12
|
+
}, async ({ deviceId }) => {
|
|
13
|
+
try {
|
|
14
|
+
backend.selectDevice(deviceId);
|
|
15
|
+
const info = await backend.getDeviceInfo();
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: 'text',
|
|
20
|
+
text: [
|
|
21
|
+
`Selected device: ${info.name}`,
|
|
22
|
+
`Platform: ${info.platform}`,
|
|
23
|
+
`OS: ${info.osVersion}`,
|
|
24
|
+
`ID: ${info.deviceId}`,
|
|
25
|
+
].join('\n'),
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return errorResult(error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=select-device.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-device.mjs","sourceRoot":"","sources":["../../src/tools/select-device.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,YAAY;AAExB,OAAO,EAAE,WAAW,EAAE,qBAAoB;AAG1C,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,OAA0B;IAE1B,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EACT,mGAAmG;QACrG,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CAAC,wDAAwD,CAAC;SACtE;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;YAE3C,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;4BACJ,oBAAoB,IAAI,CAAC,IAAI,EAAE;4BAC/B,aAAa,IAAI,CAAC,QAAQ,EAAE;4BAC5B,OAAO,IAAI,CAAC,SAAS,EAAE;4BACvB,OAAO,IAAI,CAAC,QAAQ,EAAE;yBACvB,CAAC,IAAI,CAAC,IAAI,CAAC;qBACb;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { errorResult } from './shared.js';\nimport type { LazyDeviceBackend } from '../backends/index.js';\n\nexport function registerSelectDeviceTool(\n server: McpServer,\n backend: LazyDeviceBackend,\n): void {\n server.registerTool(\n 'device_select_device',\n {\n title: 'Select Device',\n description:\n 'Select a device to use for this session. Call device_list_devices first to see available devices.',\n inputSchema: {\n deviceId: z\n .string()\n .describe('Device ID to select (UDID for iOS, serial for Android)'),\n },\n },\n async ({ deviceId }) => {\n try {\n backend.selectDevice(deviceId);\n const info = await backend.getDeviceInfo();\n\n return {\n content: [\n {\n type: 'text' as const,\n text: [\n `Selected device: ${info.name}`,\n `Platform: ${info.platform}`,\n `OS: ${info.osVersion}`,\n `ID: ${info.deviceId}`,\n ].join('\\n'),\n },\n ],\n };\n } catch (error) {\n return errorResult(error);\n }\n },\n );\n}\n"]}
|
package/dist/utils/exec.cjs
CHANGED
|
@@ -21,17 +21,19 @@ async function exec(command, args, options) {
|
|
|
21
21
|
timeout: timeoutMs,
|
|
22
22
|
maxBuffer: 10 * 1024 * 1024, // 10MB — UI hierarchies can be large
|
|
23
23
|
}, (error, stdout, stderr) => {
|
|
24
|
-
if (error
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
if (error) {
|
|
25
|
+
const errno = error;
|
|
26
|
+
if (errno.code === 'ENOENT' ||
|
|
27
|
+
errno.code === 'EACCES' ||
|
|
28
|
+
errno.code === 'EPERM') {
|
|
29
|
+
reject(new Error(error.message));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
resolve({
|
|
30
34
|
stdout: stdout?.toString() ?? '',
|
|
31
35
|
stderr: stderr?.toString() ?? '',
|
|
32
|
-
exitCode: error
|
|
33
|
-
? 1
|
|
34
|
-
: (child.exitCode ?? 0),
|
|
36
|
+
exitCode: child.exitCode ?? (error ? 1 : 0),
|
|
35
37
|
});
|
|
36
38
|
});
|
|
37
39
|
});
|
|
@@ -47,8 +49,8 @@ async function execStrict(command, args, options) {
|
|
|
47
49
|
}
|
|
48
50
|
async function isCommandAvailable(command) {
|
|
49
51
|
try {
|
|
50
|
-
await exec('which', [command], { timeoutMs: 5000 });
|
|
51
|
-
return
|
|
52
|
+
const result = await exec('which', [command], { timeoutMs: 5000 });
|
|
53
|
+
return result.exitCode === 0;
|
|
52
54
|
}
|
|
53
55
|
catch {
|
|
54
56
|
return false;
|