@kernel.chat/kbot 3.70.0 → 3.72.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.
@@ -112,13 +112,107 @@ export declare class AbletonM4L {
112
112
  /** Generic LOM method call — call any method at any path */
113
113
  lomCall(path: string, method: string, args?: unknown[]): Promise<M4LResponse>;
114
114
  }
115
+ export interface BrowserSearchResult {
116
+ name: string;
117
+ uri: string;
118
+ is_loadable: boolean;
119
+ is_device: boolean;
120
+ }
121
+ export interface BrowserCategory {
122
+ name: string;
123
+ display_name: string;
124
+ child_count: number;
125
+ }
126
+ /**
127
+ * Client for the KBotBridge Remote Script (TCP 9997).
128
+ *
129
+ * This is separate from the M4L bridge (9999) because the Browser API
130
+ * (browser.load_item) is ONLY available from Python Remote Scripts,
131
+ * not from Max for Live.
132
+ *
133
+ * Use this to programmatically load any native device (Saturator,
134
+ * EQ Eight, Compressor, etc.) onto any track.
135
+ */
136
+ export declare class AbletonBrowserBridge {
137
+ private static instance;
138
+ private socket;
139
+ private connected;
140
+ private pending;
141
+ private nextId;
142
+ private buffer;
143
+ static PORT: number;
144
+ static HOST: string;
145
+ static TIMEOUT: number;
146
+ private constructor();
147
+ static getInstance(): AbletonBrowserBridge;
148
+ /**
149
+ * Connect to the KBotBridge Remote Script on port 9997.
150
+ * Returns true if connected and the bridge responds to ping.
151
+ */
152
+ connect(): Promise<boolean>;
153
+ disconnect(): void;
154
+ send(cmd: Omit<M4LCommand, 'id'> & {
155
+ action: string;
156
+ }): Promise<M4LResponse>;
157
+ get isConnected(): boolean;
158
+ private handleResponse;
159
+ private handleDisconnect;
160
+ ping(): Promise<boolean>;
161
+ /**
162
+ * Search Ableton's browser for items matching a query.
163
+ * @param query - Search string (case-insensitive)
164
+ * @param category - instruments/audio_effects/midi_effects/drums/samples/all
165
+ */
166
+ browserSearch(query: string, category?: string): Promise<BrowserSearchResult[]>;
167
+ /**
168
+ * Load a browser item by URI onto a track.
169
+ * Use the URI from a browserSearch() result.
170
+ */
171
+ browserLoad(track: number, uri: string): Promise<M4LResponse>;
172
+ /**
173
+ * Search + load in one step. Finds first loadable match and loads it.
174
+ * @param track - 0-indexed track number
175
+ * @param name - Device name to search for (e.g., "Saturator", "EQ Eight")
176
+ * @param category - instruments/audio_effects/midi_effects/drums/samples/all
177
+ */
178
+ browserLoadByName(track: number, name: string, category?: string): Promise<M4LResponse>;
179
+ /**
180
+ * List top-level browser categories with child counts.
181
+ */
182
+ browserCategories(): Promise<BrowserCategory[]>;
183
+ /**
184
+ * List all tracks with names and device counts.
185
+ */
186
+ listTracks(): Promise<M4LResponse>;
187
+ /**
188
+ * List devices on a track with full parameter details.
189
+ */
190
+ listDevices(track: number): Promise<M4LResponse>;
191
+ }
115
192
  /**
116
193
  * Get a connected M4L bridge instance.
117
194
  * Throws if the bridge is not available.
118
195
  */
119
196
  export declare function ensureM4L(): Promise<AbletonM4L>;
197
+ /**
198
+ * Get a connected Browser bridge instance (KBotBridge Remote Script on port 9997).
199
+ * Throws if not available.
200
+ */
201
+ export declare function ensureBrowserBridge(): Promise<AbletonBrowserBridge>;
202
+ /**
203
+ * Connect to both M4L bridge (9999) and Browser bridge (9997).
204
+ * Returns whichever connections succeed. At least one must connect.
205
+ */
206
+ export declare function connectBrowser(): Promise<{
207
+ m4l: AbletonM4L | null;
208
+ browser: AbletonBrowserBridge | null;
209
+ }>;
120
210
  /**
121
211
  * Format a friendly error message for M4L connection failures.
122
212
  */
123
213
  export declare function formatM4LError(): string;
214
+ /**
215
+ * Format a friendly error message for Browser bridge connection failures.
216
+ */
217
+ export declare function formatBrowserBridgeError(): string;
124
218
  //# sourceMappingURL=ableton-m4l.d.ts.map
@@ -301,7 +301,204 @@ export class AbletonM4L {
301
301
  return this.send({ action: 'lom_call', path, method, args });
302
302
  }
303
303
  }
304
- // ── Convenience export ──────────────────────────────────────────────
304
+ /**
305
+ * Client for the KBotBridge Remote Script (TCP 9997).
306
+ *
307
+ * This is separate from the M4L bridge (9999) because the Browser API
308
+ * (browser.load_item) is ONLY available from Python Remote Scripts,
309
+ * not from Max for Live.
310
+ *
311
+ * Use this to programmatically load any native device (Saturator,
312
+ * EQ Eight, Compressor, etc.) onto any track.
313
+ */
314
+ export class AbletonBrowserBridge {
315
+ static instance = null;
316
+ socket = null;
317
+ connected = false;
318
+ pending = new Map();
319
+ nextId = 1;
320
+ buffer = '';
321
+ static PORT = 9997;
322
+ static HOST = '127.0.0.1';
323
+ static TIMEOUT = 15_000; // Browser operations can be slow
324
+ constructor() { }
325
+ static getInstance() {
326
+ if (!AbletonBrowserBridge.instance) {
327
+ AbletonBrowserBridge.instance = new AbletonBrowserBridge();
328
+ }
329
+ return AbletonBrowserBridge.instance;
330
+ }
331
+ /**
332
+ * Connect to the KBotBridge Remote Script on port 9997.
333
+ * Returns true if connected and the bridge responds to ping.
334
+ */
335
+ async connect() {
336
+ if (this.connected && this.socket) {
337
+ try {
338
+ await this.send({ action: 'ping' });
339
+ return true;
340
+ }
341
+ catch {
342
+ this.disconnect();
343
+ }
344
+ }
345
+ return new Promise((resolve) => {
346
+ this.socket = new net.Socket();
347
+ this.buffer = '';
348
+ this.socket.on('data', (data) => {
349
+ this.buffer += data.toString();
350
+ const lines = this.buffer.split('\n');
351
+ this.buffer = lines.pop() || '';
352
+ for (const line of lines) {
353
+ const trimmed = line.trim();
354
+ if (!trimmed)
355
+ continue;
356
+ try {
357
+ const response = JSON.parse(trimmed);
358
+ this.handleResponse(response);
359
+ }
360
+ catch {
361
+ // Malformed JSON — skip
362
+ }
363
+ }
364
+ });
365
+ this.socket.on('error', () => {
366
+ if (!this.connected)
367
+ resolve(false);
368
+ this.handleDisconnect();
369
+ });
370
+ this.socket.on('close', () => {
371
+ this.handleDisconnect();
372
+ });
373
+ this.socket.connect(AbletonBrowserBridge.PORT, AbletonBrowserBridge.HOST, async () => {
374
+ this.connected = true;
375
+ try {
376
+ const pong = await this.send({ action: 'ping' });
377
+ resolve(pong.ok);
378
+ }
379
+ catch {
380
+ resolve(false);
381
+ }
382
+ });
383
+ setTimeout(() => {
384
+ if (!this.connected) {
385
+ this.socket?.destroy();
386
+ resolve(false);
387
+ }
388
+ }, 5000);
389
+ });
390
+ }
391
+ disconnect() {
392
+ this.connected = false;
393
+ if (this.socket) {
394
+ this.socket.destroy();
395
+ this.socket = null;
396
+ }
397
+ for (const [, req] of this.pending) {
398
+ clearTimeout(req.timer);
399
+ req.reject(new Error('Disconnected'));
400
+ }
401
+ this.pending.clear();
402
+ this.buffer = '';
403
+ }
404
+ async send(cmd) {
405
+ if (!this.connected || !this.socket) {
406
+ throw new Error('Not connected to KBotBridge Remote Script.\n' +
407
+ 'Make sure KBotBridge is selected as a Control Surface in Ableton Preferences.');
408
+ }
409
+ const id = this.nextId++;
410
+ const fullCmd = { id, ...cmd };
411
+ return new Promise((resolve, reject) => {
412
+ const timer = setTimeout(() => {
413
+ this.pending.delete(id);
414
+ reject(new Error(`Timeout: ${cmd.action}`));
415
+ }, AbletonBrowserBridge.TIMEOUT);
416
+ this.pending.set(id, { resolve, reject, timer });
417
+ this.socket.write(JSON.stringify(fullCmd) + '\n');
418
+ });
419
+ }
420
+ get isConnected() {
421
+ return this.connected;
422
+ }
423
+ handleResponse(response) {
424
+ if (response.id && this.pending.has(response.id)) {
425
+ const req = this.pending.get(response.id);
426
+ this.pending.delete(response.id);
427
+ clearTimeout(req.timer);
428
+ req.resolve(response);
429
+ }
430
+ }
431
+ handleDisconnect() {
432
+ if (!this.connected)
433
+ return;
434
+ this.connected = false;
435
+ this.socket = null;
436
+ for (const [, req] of this.pending) {
437
+ clearTimeout(req.timer);
438
+ req.reject(new Error('Connection lost'));
439
+ }
440
+ this.pending.clear();
441
+ }
442
+ // ── Browser convenience methods ─────────────────────────────────
443
+ async ping() {
444
+ try {
445
+ const r = await this.send({ action: 'ping' });
446
+ return r.ok;
447
+ }
448
+ catch {
449
+ return false;
450
+ }
451
+ }
452
+ /**
453
+ * Search Ableton's browser for items matching a query.
454
+ * @param query - Search string (case-insensitive)
455
+ * @param category - instruments/audio_effects/midi_effects/drums/samples/all
456
+ */
457
+ async browserSearch(query, category = 'all') {
458
+ const r = await this.send({ action: 'browser_search', query, category });
459
+ if (!r.ok)
460
+ throw new Error(r.error || 'Browser search failed');
461
+ return r.results || [];
462
+ }
463
+ /**
464
+ * Load a browser item by URI onto a track.
465
+ * Use the URI from a browserSearch() result.
466
+ */
467
+ async browserLoad(track, uri) {
468
+ return this.send({ action: 'browser_load', track, uri });
469
+ }
470
+ /**
471
+ * Search + load in one step. Finds first loadable match and loads it.
472
+ * @param track - 0-indexed track number
473
+ * @param name - Device name to search for (e.g., "Saturator", "EQ Eight")
474
+ * @param category - instruments/audio_effects/midi_effects/drums/samples/all
475
+ */
476
+ async browserLoadByName(track, name, category = 'all') {
477
+ return this.send({ action: 'browser_load_by_name', track, name, category });
478
+ }
479
+ /**
480
+ * List top-level browser categories with child counts.
481
+ */
482
+ async browserCategories() {
483
+ const r = await this.send({ action: 'browser_categories' });
484
+ if (!r.ok)
485
+ throw new Error(r.error || 'Failed to list categories');
486
+ return r.categories || [];
487
+ }
488
+ /**
489
+ * List all tracks with names and device counts.
490
+ */
491
+ async listTracks() {
492
+ return this.send({ action: 'list_tracks' });
493
+ }
494
+ /**
495
+ * List devices on a track with full parameter details.
496
+ */
497
+ async listDevices(track) {
498
+ return this.send({ action: 'list_devices', track });
499
+ }
500
+ }
501
+ // ── Convenience exports ─────────────────────────────────────────────
305
502
  /**
306
503
  * Get a connected M4L bridge instance.
307
504
  * Throws if the bridge is not available.
@@ -320,6 +517,41 @@ export async function ensureM4L() {
320
517
  }
321
518
  return m4l;
322
519
  }
520
+ /**
521
+ * Get a connected Browser bridge instance (KBotBridge Remote Script on port 9997).
522
+ * Throws if not available.
523
+ */
524
+ export async function ensureBrowserBridge() {
525
+ const bridge = AbletonBrowserBridge.getInstance();
526
+ if (bridge.isConnected)
527
+ return bridge;
528
+ const ok = await bridge.connect();
529
+ if (!ok) {
530
+ throw new Error('Cannot connect to KBotBridge Remote Script.\n\n' +
531
+ 'Make sure:\n' +
532
+ '1. Ableton Live is running\n' +
533
+ '2. KBotBridge is selected as a Control Surface in Preferences > Link, Tempo & MIDI\n' +
534
+ '3. Ableton status bar shows "KBotBridge: Listening on port 9997"\n\n' +
535
+ 'To install: kbot ableton install-bridge\n');
536
+ }
537
+ return bridge;
538
+ }
539
+ /**
540
+ * Connect to both M4L bridge (9999) and Browser bridge (9997).
541
+ * Returns whichever connections succeed. At least one must connect.
542
+ */
543
+ export async function connectBrowser() {
544
+ const m4l = AbletonM4L.getInstance();
545
+ const browser = AbletonBrowserBridge.getInstance();
546
+ const [m4lOk, browserOk] = await Promise.all([
547
+ m4l.connect().catch(() => false),
548
+ browser.connect().catch(() => false),
549
+ ]);
550
+ return {
551
+ m4l: m4lOk ? m4l : null,
552
+ browser: browserOk ? browser : null,
553
+ };
554
+ }
323
555
  /**
324
556
  * Format a friendly error message for M4L connection failures.
325
557
  */
@@ -335,4 +567,23 @@ export function formatM4LError() {
335
567
  'The M4L bridge gives kbot full control over Ableton — instruments, effects, clips, mixing, everything.',
336
568
  ].join('\n');
337
569
  }
570
+ /**
571
+ * Format a friendly error message for Browser bridge connection failures.
572
+ */
573
+ export function formatBrowserBridgeError() {
574
+ return [
575
+ '**KBotBridge Remote Script not connected**',
576
+ '',
577
+ 'The Browser API (for loading native devices) requires the KBotBridge Remote Script:',
578
+ '1. Install: `kbot ableton install-bridge`',
579
+ '2. Open Ableton Live Preferences (Cmd+,)',
580
+ '3. Go to Link, Tempo & MIDI',
581
+ '4. Set a Control Surface to "KBotBridge"',
582
+ '5. Close Preferences',
583
+ '',
584
+ 'This runs alongside the M4L bridge — they use different ports:',
585
+ '- KBotBridge: TCP 9997 (Browser API, device loading)',
586
+ '- M4L Bridge: TCP 9999 (LOM access, clips, mixing)',
587
+ ].join('\n');
588
+ }
338
589
  //# sourceMappingURL=ableton-m4l.js.map
@@ -0,0 +1,23 @@
1
+ /**
2
+ * install-remote-script.ts — Install KBotBridge Remote Script into Ableton Live
3
+ *
4
+ * Copies the KBotBridge Python Remote Script to Ableton's User Library,
5
+ * enabling the Browser API bridge on TCP port 9997.
6
+ *
7
+ * The Remote Script exposes Ableton's browser.load_item() API, which is
8
+ * ONLY available from Python Remote Scripts (not from Max for Live).
9
+ * This lets kbot programmatically load any native device (Saturator,
10
+ * EQ Eight, Compressor, etc.) onto any track.
11
+ *
12
+ * Usage:
13
+ * npx tsx packages/kbot/src/integrations/install-remote-script.ts
14
+ * kbot ableton install-bridge
15
+ */
16
+ export declare function installKBotBridge(): Promise<string>;
17
+ export declare function isKBotBridgeInstalled(): boolean;
18
+ export declare function uninstallKBotBridge(): string;
19
+ /**
20
+ * Get the path to the KBotBridge log file inside Ableton's Remote Scripts.
21
+ */
22
+ export declare function getKBotBridgeLogPath(): string | null;
23
+ //# sourceMappingURL=install-remote-script.d.ts.map
@@ -0,0 +1,121 @@
1
+ /**
2
+ * install-remote-script.ts — Install KBotBridge Remote Script into Ableton Live
3
+ *
4
+ * Copies the KBotBridge Python Remote Script to Ableton's User Library,
5
+ * enabling the Browser API bridge on TCP port 9997.
6
+ *
7
+ * The Remote Script exposes Ableton's browser.load_item() API, which is
8
+ * ONLY available from Python Remote Scripts (not from Max for Live).
9
+ * This lets kbot programmatically load any native device (Saturator,
10
+ * EQ Eight, Compressor, etc.) onto any track.
11
+ *
12
+ * Usage:
13
+ * npx tsx packages/kbot/src/integrations/install-remote-script.ts
14
+ * kbot ableton install-bridge
15
+ */
16
+ import * as fs from 'node:fs';
17
+ import * as path from 'node:path';
18
+ import * as os from 'node:os';
19
+ const SCRIPT_NAME = 'KBotBridge';
20
+ const SOURCE_FILES = [
21
+ '__init__.py',
22
+ 'kbot_control_surface.py',
23
+ 'tcp_server.py',
24
+ ];
25
+ function getRemoteScriptsDir() {
26
+ const home = os.homedir();
27
+ return path.join(home, 'Music', 'Ableton', 'User Library', 'Remote Scripts');
28
+ }
29
+ function getDestDir() {
30
+ return path.join(getRemoteScriptsDir(), SCRIPT_NAME);
31
+ }
32
+ function getSourceDir() {
33
+ // Source files live alongside this installer in the integrations directory
34
+ return path.join(__dirname, SCRIPT_NAME);
35
+ }
36
+ export async function installKBotBridge() {
37
+ const lines = [];
38
+ const log = (msg) => { lines.push(msg); console.log(msg); };
39
+ log('Installing KBotBridge Remote Script...');
40
+ log('');
41
+ const sourceDir = getSourceDir();
42
+ const destDir = getDestDir();
43
+ const remoteScriptsDir = getRemoteScriptsDir();
44
+ // Verify source files exist
45
+ for (const file of SOURCE_FILES) {
46
+ const srcPath = path.join(sourceDir, file);
47
+ if (!fs.existsSync(srcPath)) {
48
+ log(` ERROR: Source file missing: ${srcPath}`);
49
+ log(' Run from the kbot package directory.');
50
+ return lines.join('\n');
51
+ }
52
+ }
53
+ // Create Remote Scripts directory if it doesn't exist
54
+ if (!fs.existsSync(remoteScriptsDir)) {
55
+ fs.mkdirSync(remoteScriptsDir, { recursive: true });
56
+ log(` Created: ${remoteScriptsDir}`);
57
+ }
58
+ // Remove old installation if present
59
+ if (fs.existsSync(destDir)) {
60
+ fs.rmSync(destDir, { recursive: true });
61
+ log(' Removed previous KBotBridge installation');
62
+ }
63
+ // Copy files
64
+ fs.mkdirSync(destDir, { recursive: true });
65
+ for (const file of SOURCE_FILES) {
66
+ const src = path.join(sourceDir, file);
67
+ const dst = path.join(destDir, file);
68
+ fs.copyFileSync(src, dst);
69
+ log(` Copied: ${file}`);
70
+ }
71
+ // Create logs directory (the script will log here)
72
+ const logsDir = path.join(destDir, 'logs');
73
+ if (!fs.existsSync(logsDir)) {
74
+ fs.mkdirSync(logsDir, { recursive: true });
75
+ }
76
+ log('');
77
+ log(`KBotBridge installed to: ${destDir}`);
78
+ log('');
79
+ log('To activate:');
80
+ log(' 1. Open Ableton Live (or restart if already running)');
81
+ log(' 2. Preferences (Cmd+,) > Link, Tempo & MIDI');
82
+ log(' 3. Set a Control Surface slot to "KBotBridge"');
83
+ log(' 4. Input/Output can be left as "None"');
84
+ log(' 5. Close Preferences');
85
+ log('');
86
+ log('Verify:');
87
+ log(' - Ableton status bar shows "KBotBridge: Listening on port 9997"');
88
+ log(' - Run: echo \'{"id":1,"action":"ping"}\\n\' | nc localhost 9997');
89
+ log('');
90
+ log('KBotBridge runs alongside AbletonOSC — they use different ports:');
91
+ log(' - KBotBridge: TCP 9997 (Browser API, device loading)');
92
+ log(' - M4L Bridge: TCP 9999 (LOM access, clips, mixing)');
93
+ log(' - AbletonOSC: UDP 11000/11001 (OSC, legacy)');
94
+ return lines.join('\n');
95
+ }
96
+ export function isKBotBridgeInstalled() {
97
+ const destDir = getDestDir();
98
+ return fs.existsSync(path.join(destDir, '__init__.py'))
99
+ && fs.existsSync(path.join(destDir, 'kbot_control_surface.py'))
100
+ && fs.existsSync(path.join(destDir, 'tcp_server.py'));
101
+ }
102
+ export function uninstallKBotBridge() {
103
+ const destDir = getDestDir();
104
+ if (fs.existsSync(destDir)) {
105
+ fs.rmSync(destDir, { recursive: true });
106
+ return `KBotBridge removed from ${destDir}`;
107
+ }
108
+ return 'KBotBridge was not installed.';
109
+ }
110
+ /**
111
+ * Get the path to the KBotBridge log file inside Ableton's Remote Scripts.
112
+ */
113
+ export function getKBotBridgeLogPath() {
114
+ const logPath = path.join(getDestDir(), 'logs', 'kbot_bridge.log');
115
+ return fs.existsSync(logPath) ? logPath : null;
116
+ }
117
+ // ── CLI entrypoint ──────────────────────────────────────────────────
118
+ if (require.main === module || process.argv[1]?.includes('install-remote-script')) {
119
+ installKBotBridge().catch(console.error);
120
+ }
121
+ //# sourceMappingURL=install-remote-script.js.map
@@ -0,0 +1,111 @@
1
+ /**
2
+ * mobile-mcp-client.ts — kbot <-> mobile-mcp integration
3
+ *
4
+ * Singleton client that manages the mobile-mcp server process lifecycle.
5
+ * Communicates via MCP protocol over stdio transport.
6
+ * Auto-installs @mobilenext/mobile-mcp via npm if not present.
7
+ *
8
+ * mobile-mcp provides native accessibility-tree-based automation for
9
+ * iOS and Android devices connected via USB or WiFi.
10
+ *
11
+ * @see https://github.com/mobile-next/mobile-mcp
12
+ */
13
+ export interface MobileDevice {
14
+ id: string;
15
+ name: string;
16
+ platform: 'ios' | 'android';
17
+ type: 'real' | 'simulator' | 'emulator';
18
+ version: string;
19
+ state: 'online' | 'offline';
20
+ }
21
+ export interface MobileElement {
22
+ type: string;
23
+ text?: string;
24
+ label?: string;
25
+ name?: string;
26
+ value?: string;
27
+ identifier?: string;
28
+ x: number;
29
+ y: number;
30
+ width: number;
31
+ height: number;
32
+ }
33
+ export interface MobileScreenSize {
34
+ width: number;
35
+ height: number;
36
+ }
37
+ export declare class MobileMCPClient {
38
+ private static instance;
39
+ private process;
40
+ private messageId;
41
+ private pending;
42
+ private buffer;
43
+ private initialized;
44
+ private activeDeviceId;
45
+ static getInstance(): MobileMCPClient;
46
+ /** Whether the MCP server process is running and initialized */
47
+ get isConnected(): boolean;
48
+ /** The device ID currently being controlled */
49
+ get currentDeviceId(): string | null;
50
+ /** Start the mobile-mcp server process and perform MCP handshake */
51
+ start(): Promise<void>;
52
+ /** Stop the mobile-mcp server process */
53
+ stop(): void;
54
+ private parseMessages;
55
+ private sendRequest;
56
+ private sendNotification;
57
+ /** Call a tool on the mobile-mcp server */
58
+ callTool(toolName: string, args: Record<string, unknown>): Promise<unknown>;
59
+ /** Extract text content from an MCP tool result */
60
+ extractText(result: unknown): string;
61
+ /** Extract image content (base64) from an MCP tool result */
62
+ extractImage(result: unknown): {
63
+ data: string;
64
+ mimeType: string;
65
+ } | null;
66
+ /** List all available devices */
67
+ listDevices(): Promise<MobileDevice[]>;
68
+ /** Set the active device for subsequent operations */
69
+ setActiveDevice(deviceId: string): void;
70
+ /** Get the active device ID, throwing if none set */
71
+ private requireDevice;
72
+ /** List apps on the active device */
73
+ listApps(deviceId?: string): Promise<string>;
74
+ /** Launch an app by bundle ID */
75
+ launchApp(packageName: string, deviceId?: string): Promise<string>;
76
+ /** Take a screenshot, returns base64 image data */
77
+ takeScreenshot(deviceId?: string): Promise<{
78
+ data: string;
79
+ mimeType: string;
80
+ } | string>;
81
+ /** Save screenshot to a file */
82
+ saveScreenshot(saveTo: string, deviceId?: string): Promise<string>;
83
+ /** List UI elements on screen via accessibility tree */
84
+ listElements(deviceId?: string): Promise<string>;
85
+ /** Tap at coordinates */
86
+ tap(x: number, y: number, deviceId?: string): Promise<string>;
87
+ /** Swipe on screen */
88
+ swipe(direction: 'up' | 'down' | 'left' | 'right', opts?: {
89
+ x?: number;
90
+ y?: number;
91
+ distance?: number;
92
+ deviceId?: string;
93
+ }): Promise<string>;
94
+ /** Type text */
95
+ typeText(text: string, submit?: boolean, deviceId?: string): Promise<string>;
96
+ /** Press a device button */
97
+ pressButton(button: 'HOME' | 'BACK' | 'VOLUME_UP' | 'VOLUME_DOWN' | 'ENTER', deviceId?: string): Promise<string>;
98
+ /** Get screen size */
99
+ getScreenSize(deviceId?: string): Promise<string>;
100
+ /** Open a URL in the device browser */
101
+ openUrl(url: string, deviceId?: string): Promise<string>;
102
+ /** Get device orientation */
103
+ getOrientation(deviceId?: string): Promise<string>;
104
+ /** Terminate an app */
105
+ terminateApp(packageName: string, deviceId?: string): Promise<string>;
106
+ /** Double tap at coordinates */
107
+ doubleTap(x: number, y: number, deviceId?: string): Promise<string>;
108
+ /** Long press at coordinates */
109
+ longPress(x: number, y: number, duration?: number, deviceId?: string): Promise<string>;
110
+ }
111
+ //# sourceMappingURL=mobile-mcp-client.d.ts.map