react-native-mcp-kit 4.0.0 → 4.1.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 (50) hide show
  1. package/README.md +3 -3
  2. package/dist/babel/testIdPlugin.d.ts.map +1 -1
  3. package/dist/babel/testIdPlugin.js +22 -13
  4. package/dist/babel/testIdPlugin.js.map +1 -1
  5. package/dist/bin/ios-hid +0 -0
  6. package/dist/client/core/McpClient.d.ts.map +1 -1
  7. package/dist/client/core/McpClient.js +16 -2
  8. package/dist/client/core/McpClient.js.map +1 -1
  9. package/dist/server/bridge.d.ts +1 -0
  10. package/dist/server/bridge.d.ts.map +1 -1
  11. package/dist/server/bridge.js +1 -0
  12. package/dist/server/bridge.js.map +1 -1
  13. package/dist/server/host/coredevice/dtx.d.ts +79 -0
  14. package/dist/server/host/coredevice/dtx.d.ts.map +1 -0
  15. package/dist/server/host/coredevice/dtx.js +453 -0
  16. package/dist/server/host/coredevice/dtx.js.map +1 -0
  17. package/dist/server/host/coredevice/nska.d.ts +6 -0
  18. package/dist/server/host/coredevice/nska.d.ts.map +1 -0
  19. package/dist/server/host/coredevice/nska.js +277 -0
  20. package/dist/server/host/coredevice/nska.js.map +1 -0
  21. package/dist/server/host/coredevice/rsd.d.ts +20 -0
  22. package/dist/server/host/coredevice/rsd.d.ts.map +1 -0
  23. package/dist/server/host/coredevice/rsd.js +244 -0
  24. package/dist/server/host/coredevice/rsd.js.map +1 -0
  25. package/dist/server/host/coredevice/screenshot.d.ts +11 -0
  26. package/dist/server/host/coredevice/screenshot.d.ts.map +1 -0
  27. package/dist/server/host/coredevice/screenshot.js +84 -0
  28. package/dist/server/host/coredevice/screenshot.js.map +1 -0
  29. package/dist/server/host/coredevice/tunnel.d.ts +29 -0
  30. package/dist/server/host/coredevice/tunnel.d.ts.map +1 -0
  31. package/dist/server/host/coredevice/tunnel.js +222 -0
  32. package/dist/server/host/coredevice/tunnel.js.map +1 -0
  33. package/dist/server/host/coredevice/xpc.d.ts +21 -0
  34. package/dist/server/host/coredevice/xpc.d.ts.map +1 -0
  35. package/dist/server/host/coredevice/xpc.js +318 -0
  36. package/dist/server/host/coredevice/xpc.js.map +1 -0
  37. package/dist/server/host/deviceResolver.d.ts +8 -0
  38. package/dist/server/host/deviceResolver.d.ts.map +1 -1
  39. package/dist/server/host/deviceResolver.js +128 -62
  40. package/dist/server/host/deviceResolver.js.map +1 -1
  41. package/dist/server/host/tools/capture.d.ts.map +1 -1
  42. package/dist/server/host/tools/capture.js +26 -0
  43. package/dist/server/host/tools/capture.js.map +1 -1
  44. package/dist/server/mcpServer.d.ts.map +1 -1
  45. package/dist/server/mcpServer.js +1 -0
  46. package/dist/server/mcpServer.js.map +1 -1
  47. package/dist/shared/protocol.d.ts +2 -1
  48. package/dist/shared/protocol.d.ts.map +1 -1
  49. package/dist/shared/protocol.js +1 -1
  50. package/package.json +3 -1
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.captureScreenshot = void 0;
4
+ const dtx_1 = require("./dtx");
5
+ const nska_1 = require("./nska");
6
+ const rsd_1 = require("./rsd");
7
+ const tunnel_1 = require("./tunnel");
8
+ // Public entry point for taking a screenshot of a real iOS device via
9
+ // the CoreDevice tunnel.
10
+ //
11
+ // Flow:
12
+ // 1. `startTunnel` brings up the CoreDevice tunnel.
13
+ // 2. `fetchPeerInfo` enumerates services via RSD.
14
+ // 3. Open a DTX connection to `com.apple.instruments.dtservicehub`.
15
+ // 4. `_notifyOfPublishedCapabilities:` on channel 0 — DTX handshake.
16
+ // 5. `_requestChannelWithCode:identifier:` on channel 0 — binds our
17
+ // chosen channel code to the screenshot service.
18
+ // 6. `takeScreenshot` on the new channel. The reply payload is an
19
+ // NSKeyedArchive of an NSData holding the PNG bytes.
20
+ const DTSERVICEHUB_SERVICE = 'com.apple.instruments.dtservicehub';
21
+ const SCREENSHOT_SERVICE = 'com.apple.instruments.server.services.screenshot';
22
+ // Channel 0 is Apple's well-known control channel — `_notifyOfPublishedCapabilities:`
23
+ // and `_requestChannelWithCode:identifier:` land here. `1` is arbitrary; we
24
+ // pass it to `_requestChannelWithCode:` and Apple binds it to the screenshot
25
+ // service for the remainder of the connection.
26
+ const CONTROL_CHANNEL = 0;
27
+ const SCREENSHOT_CHANNEL = 1;
28
+ const DEFAULT_CAPABILITIES = {
29
+ 'com.apple.private.DTXBlockCompression': 0,
30
+ 'com.apple.private.DTXConnection': 1,
31
+ };
32
+ class CaptureScreenshotError extends Error {
33
+ constructor(message) {
34
+ super(message);
35
+ this.name = 'CaptureScreenshotError';
36
+ }
37
+ }
38
+ const captureScreenshot = async (coreDeviceIdentifier, options = {}) => {
39
+ const totalBudgetMs = options.timeoutMs ?? 30_000;
40
+ const deadline = Date.now() + totalBudgetMs;
41
+ const remaining = () => {
42
+ return Math.max(1_000, deadline - Date.now());
43
+ };
44
+ const tunnel = await (0, tunnel_1.startTunnel)(coreDeviceIdentifier, {
45
+ startupTimeoutMs: remaining(),
46
+ });
47
+ try {
48
+ const peer = await (0, rsd_1.fetchPeerInfo)(tunnel.info.deviceAddress, tunnel.info.hostAddress, tunnel.info.rsdPort, { timeoutMs: remaining() });
49
+ const hubEntry = peer.services[DTSERVICEHUB_SERVICE];
50
+ if (!hubEntry) {
51
+ throw new CaptureScreenshotError(`${DTSERVICEHUB_SERVICE} not in peer Services dict`);
52
+ }
53
+ const dtx = await dtx_1.DtxConnection.open(tunnel.info.deviceAddress, tunnel.info.hostAddress, hubEntry.port, { timeoutMs: remaining() });
54
+ try {
55
+ let messageId = 0;
56
+ const nextId = () => {
57
+ messageId += 1;
58
+ return messageId;
59
+ };
60
+ await dtx.invoke(CONTROL_CHANNEL, (0, nska_1.encodeNska)('_notifyOfPublishedCapabilities:'), (0, dtx_1.buildDtxAux)([DEFAULT_CAPABILITIES]), { identifier: nextId(), wantsReply: false });
61
+ // Bind SCREENSHOT_CHANNEL → screenshot service. DtxConnection rejects
62
+ // with DtxConnectionError on an Error reply, so we don't need a
63
+ // separate branch here.
64
+ await dtx.invoke(CONTROL_CHANNEL, (0, nska_1.encodeNska)('_requestChannelWithCode:identifier:'), (0, dtx_1.buildDtxAux)([(0, dtx_1.dtxInt32)(SCREENSHOT_CHANNEL), SCREENSHOT_SERVICE]), { identifier: nextId(), timeoutMs: remaining() });
65
+ const reply = await dtx.invoke(SCREENSHOT_CHANNEL, (0, nska_1.encodeNska)('takeScreenshot'), Buffer.alloc(0), { identifier: nextId(), timeoutMs: remaining() });
66
+ const decoded = (0, nska_1.decodeNska)(reply.payload);
67
+ if (!Buffer.isBuffer(decoded)) {
68
+ const desc = decoded && typeof decoded === 'object' && !Array.isArray(decoded)
69
+ ? `object with keys [${Object.keys(decoded).join(', ')}]`
70
+ : typeof decoded;
71
+ throw new CaptureScreenshotError(`takeScreenshot reply was ${desc}, expected NSData`);
72
+ }
73
+ return decoded;
74
+ }
75
+ finally {
76
+ dtx.close();
77
+ }
78
+ }
79
+ finally {
80
+ await tunnel.close();
81
+ }
82
+ };
83
+ exports.captureScreenshot = captureScreenshot;
84
+ //# sourceMappingURL=screenshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../../../src/server/host/coredevice/screenshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ interface TunnelInfo {
2
+ /** Device's IPv6 address through the CoreDevice tunnel (the `fd…::1`-style ULA). */
3
+ deviceAddress: string;
4
+ /**
5
+ * Mac-side IPv6 of the same tunnel (`fd…::2`). Sockets MUST bind to this
6
+ * address before connecting to the device; default routing picks the wrong
7
+ * utun on hosts with multiple tunnels (Tailscale, WireGuard, …).
8
+ */
9
+ hostAddress: string;
10
+ /** Tunnel interface name on the Mac, e.g. `utun6`. */
11
+ interfaceName: string;
12
+ /**
13
+ * Port the device's RemoteServiceDiscovery listens on inside the tunnel.
14
+ * Dynamic per session; we lift it from the system log.
15
+ */
16
+ rsdPort: number;
17
+ }
18
+ interface TunnelHandle {
19
+ /** Stops the tunnel keeper. The OS tears the tunnel down within a few seconds. */
20
+ close: () => Promise<void>;
21
+ info: TunnelInfo;
22
+ }
23
+ interface StartTunnelOptions {
24
+ /** Maximum time to wait for the tunnel to come up. Default 30s. */
25
+ startupTimeoutMs?: number;
26
+ }
27
+ export declare const startTunnel: (coreDeviceIdentifier: string, options?: StartTunnelOptions) => Promise<TunnelHandle>;
28
+ export {};
29
+ //# sourceMappingURL=tunnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../../../src/server/host/coredevice/tunnel.ts"],"names":[],"mappings":"AAaA,UAAU,UAAU;IAClB,oFAAoF;IACpF,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,YAAY;IACpB,kFAAkF;IAClF,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,UAAU,kBAAkB;IAC1B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAuND,eAAO,MAAM,WAAW,yBACA,MAAM,YACnB,kBAAkB,KAC1B,OAAO,CAAC,YAAY,CAoBtB,CAAC"}
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startTunnel = void 0;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_dns_1 = require("node:dns");
6
+ const node_os_1 = require("node:os");
7
+ const DEFAULT_STARTUP_TIMEOUT_MS = 30_000;
8
+ const KEEPER_POLL_INTERVAL_MS = 750;
9
+ const POLL_INTERVAL_MS = 250;
10
+ // `log show` for a focused predicate over 60 seconds is normally tens of KB;
11
+ // 4 MiB is a hard ceiling so a runaway logger can't OOM us. On overflow we
12
+ // SIGKILL the child and parse what we got so far — we only need a single
13
+ // "for server port" line.
14
+ const LOG_SHOW_MAX_BYTES = 4 * 1024 * 1024;
15
+ class TunnelStartupError extends Error {
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = 'TunnelStartupError';
19
+ }
20
+ }
21
+ const sleep = (ms) => {
22
+ return new Promise((resolve) => {
23
+ setTimeout(resolve, ms);
24
+ });
25
+ };
26
+ // Apple's CoreDevice tunnel is brought up on-demand by whatever process holds
27
+ // a "usage assertion" against the device. devicectl acquires one for the
28
+ // duration of any subcommand it runs; when devicectl exits, the OS tears the
29
+ // tunnel down within a few seconds. We piggy-back on this by running a cheap
30
+ // `devicectl device info processes` command repeatedly. As long as a keeper
31
+ // op is in-flight, the tunnel stays up.
32
+ class TunnelKeeper {
33
+ coreDeviceIdentifier;
34
+ active = true;
35
+ currentChild = null;
36
+ constructor(coreDeviceIdentifier) {
37
+ this.coreDeviceIdentifier = coreDeviceIdentifier;
38
+ }
39
+ start() {
40
+ void this.loop();
41
+ }
42
+ async loop() {
43
+ while (this.active) {
44
+ await this.runOneIteration();
45
+ if (!this.active)
46
+ break;
47
+ await sleep(KEEPER_POLL_INTERVAL_MS);
48
+ }
49
+ }
50
+ runOneIteration() {
51
+ return new Promise((resolve) => {
52
+ const child = (0, node_child_process_1.spawn)('xcrun', ['devicectl', 'device', 'info', 'processes', '--device', this.coreDeviceIdentifier], { stdio: ['ignore', 'ignore', 'ignore'] });
53
+ this.currentChild = child;
54
+ child.on('close', () => {
55
+ this.currentChild = null;
56
+ resolve();
57
+ });
58
+ child.on('error', () => {
59
+ this.currentChild = null;
60
+ resolve();
61
+ });
62
+ });
63
+ }
64
+ stop() {
65
+ this.active = false;
66
+ const child = this.currentChild;
67
+ if (child && child.exitCode === null && child.signalCode === null) {
68
+ child.kill('SIGTERM');
69
+ }
70
+ return new Promise((resolve) => {
71
+ if (!child || child.exitCode !== null || child.signalCode !== null) {
72
+ resolve();
73
+ return;
74
+ }
75
+ child.on('close', () => {
76
+ resolve();
77
+ });
78
+ });
79
+ }
80
+ }
81
+ const resolveDeviceAddress = async (coreDeviceIdentifier, deadline) => {
82
+ const hostname = `${coreDeviceIdentifier.toLowerCase()}.coredevice.local`;
83
+ let lastError = null;
84
+ while (Date.now() < deadline) {
85
+ try {
86
+ const result = await node_dns_1.promises.lookup(hostname, { family: 6 });
87
+ if (result.address && result.address.includes(':')) {
88
+ return result.address;
89
+ }
90
+ }
91
+ catch (err) {
92
+ lastError = err;
93
+ }
94
+ await sleep(POLL_INTERVAL_MS);
95
+ }
96
+ throw new TunnelStartupError(`Could not resolve ${hostname} to an IPv6 address (last error: ${lastError?.message ?? 'unknown'})`);
97
+ };
98
+ // Find the utun interface the OS just brought up for this device. We match
99
+ // by /64 ULA prefix: the device sits at `fd<…>::1`, the Mac end at
100
+ // `fd<…>::2`. Multiple coexisting tunnels each get their own ULA, so prefix
101
+ // match is unique. (CoreDevice's utun uses MTU 16000 — would be a nice extra
102
+ // discriminator if Node's `os.networkInterfaces()` surfaced MTU, but it
103
+ // doesn't.)
104
+ const findTunnelInterface = async (deviceAddress, deadline) => {
105
+ while (Date.now() < deadline) {
106
+ const interfaces = (0, node_os_1.networkInterfaces)();
107
+ for (const [name, addrs] of Object.entries(interfaces)) {
108
+ if (!name.startsWith('utun') || !addrs)
109
+ continue;
110
+ for (const addr of addrs) {
111
+ if (addr.family !== 'IPv6')
112
+ continue;
113
+ if (!addr.address.startsWith('fd'))
114
+ continue;
115
+ const devPrefix = deviceAddress.replace(/::1$/, '::');
116
+ const hostPrefix = addr.address.replace(/::2$/, '::');
117
+ if (devPrefix === hostPrefix) {
118
+ return { hostAddress: addr.address, interfaceName: name };
119
+ }
120
+ }
121
+ }
122
+ await sleep(POLL_INTERVAL_MS);
123
+ }
124
+ throw new TunnelStartupError(`Could not find utun interface matching device ${deviceAddress}. Is the tunnel up?`);
125
+ };
126
+ // Stdout-capped subprocess runner — guards against a chatty `log show` filling
127
+ // memory if our predicate ever stops being selective. On overflow we SIGKILL
128
+ // the child and resolve with what we got; we only need the most recent "for
129
+ // server port" line, which lands in the first KB.
130
+ const runProcessCapture = (command, args, timeoutMs, maxStdoutBytes = LOG_SHOW_MAX_BYTES) => {
131
+ return new Promise((resolve, reject) => {
132
+ const child = (0, node_child_process_1.spawn)(command, [...args], { stdio: ['ignore', 'pipe', 'pipe'] });
133
+ const stdoutChunks = [];
134
+ let stdoutSize = 0;
135
+ let stdoutCapped = false;
136
+ let stderr = '';
137
+ const timer = setTimeout(() => {
138
+ child.kill('SIGKILL');
139
+ reject(new Error(`${command} timed out after ${timeoutMs}ms`));
140
+ }, timeoutMs);
141
+ child.stdout?.on('data', (chunk) => {
142
+ if (stdoutCapped)
143
+ return;
144
+ const remaining = maxStdoutBytes - stdoutSize;
145
+ if (chunk.length <= remaining) {
146
+ stdoutChunks.push(chunk);
147
+ stdoutSize += chunk.length;
148
+ return;
149
+ }
150
+ stdoutChunks.push(chunk.subarray(0, remaining));
151
+ stdoutSize = maxStdoutBytes;
152
+ stdoutCapped = true;
153
+ child.kill('SIGKILL');
154
+ });
155
+ child.stderr?.on('data', (chunk) => {
156
+ // stderr is informational only; cap at the same budget for symmetry.
157
+ if (stderr.length >= maxStdoutBytes)
158
+ return;
159
+ stderr += chunk.toString('utf8');
160
+ });
161
+ child.on('close', () => {
162
+ clearTimeout(timer);
163
+ resolve({ stderr, stdout: Buffer.concat(stdoutChunks, stdoutSize).toString('utf8') });
164
+ });
165
+ child.on('error', (err) => {
166
+ clearTimeout(timer);
167
+ reject(err);
168
+ });
169
+ });
170
+ };
171
+ const RSD_PORT_PATTERN = /for server port (\d+)/g;
172
+ // The RSD port the device is listening on is logged by remotepairingd at
173
+ // tunnel establish time. Most predicates redact it as `<private>`; the
174
+ // "for server port" line slips through. We scan the last minute of log
175
+ // output; the tunnel was brought up within the last few seconds.
176
+ const findRsdPort = async (deadline) => {
177
+ while (Date.now() < deadline) {
178
+ const result = await runProcessCapture('log', [
179
+ 'show',
180
+ '--last',
181
+ '60s',
182
+ '--info',
183
+ '--debug',
184
+ '--predicate',
185
+ 'eventMessage CONTAINS "for server port"',
186
+ '--style',
187
+ 'compact',
188
+ ], 5_000);
189
+ let lastPort;
190
+ let match;
191
+ while ((match = RSD_PORT_PATTERN.exec(result.stdout)) !== null) {
192
+ lastPort = Number(match[1]);
193
+ }
194
+ RSD_PORT_PATTERN.lastIndex = 0;
195
+ if (lastPort)
196
+ return lastPort;
197
+ await sleep(POLL_INTERVAL_MS);
198
+ }
199
+ throw new TunnelStartupError('RSD port not found in system log. Is the tunnel up and is `log` available?');
200
+ };
201
+ const startTunnel = async (coreDeviceIdentifier, options = {}) => {
202
+ const deadline = Date.now() + (options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS);
203
+ const keeper = new TunnelKeeper(coreDeviceIdentifier);
204
+ keeper.start();
205
+ try {
206
+ const deviceAddress = await resolveDeviceAddress(coreDeviceIdentifier, deadline);
207
+ const { hostAddress, interfaceName } = await findTunnelInterface(deviceAddress, deadline);
208
+ const rsdPort = await findRsdPort(deadline);
209
+ return {
210
+ close: () => {
211
+ return keeper.stop();
212
+ },
213
+ info: { deviceAddress, hostAddress, interfaceName, rsdPort },
214
+ };
215
+ }
216
+ catch (err) {
217
+ await keeper.stop();
218
+ throw err;
219
+ }
220
+ };
221
+ exports.startTunnel = startTunnel;
222
+ //# sourceMappingURL=tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../../../src/server/host/coredevice/tunnel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type XpcValue = null | boolean | bigint | number | string | Buffer | XpcValue[] | {
2
+ [key: string]: XpcValue;
3
+ };
4
+ export declare const XpcFlags: {
5
+ readonly ALWAYS_SET: 1;
6
+ readonly DATA_PRESENT: 256;
7
+ readonly INIT_HANDSHAKE: 4194304;
8
+ readonly PING: 2;
9
+ readonly REPLY: 131072;
10
+ readonly WANTING_REPLY: 65536;
11
+ };
12
+ export interface XpcWrapperParsed {
13
+ flags: number;
14
+ messageId: bigint;
15
+ payload: XpcValue | null;
16
+ /** Total bytes consumed from the input buffer. */
17
+ totalSize: number;
18
+ }
19
+ export declare const buildXpcWrapper: (flags: number, messageId: bigint, payload: XpcValue | null) => Buffer;
20
+ export declare const parseXpcWrapper: (buf: Buffer, offset?: number) => XpcWrapperParsed;
21
+ //# sourceMappingURL=xpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xpc.d.ts","sourceRoot":"","sources":["../../../../src/server/host/coredevice/xpc.ts"],"names":[],"mappings":"AAmIA,MAAM,MAAM,QAAQ,GAChB,IAAI,GACJ,OAAO,GACP,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,QAAQ,EAAE,GACV;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAC;AAuJhC,eAAO,MAAM,QAAQ;;;;;;;CAOX,CAAC;AAEX,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,eAAe,UACnB,MAAM,aACF,MAAM,WACR,QAAQ,GAAG,IAAI,KACvB,MAeF,CAAC;AAEF,eAAO,MAAM,eAAe,QAAS,MAAM,sBAAe,gBAwBzD,CAAC"}