appium-mcp 1.1.4 → 1.1.6
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 +12 -0
- package/README.md +1 -1
- package/dist/locators/generate-all-locators.js +2 -1
- package/dist/locators/generate-all-locators.js.map +1 -1
- package/dist/resources/index.js +2 -1
- package/dist/resources/index.js.map +1 -1
- package/dist/tools/answer-appium.js +2 -1
- package/dist/tools/answer-appium.js.map +1 -1
- package/dist/tools/boot-simulator.js +2 -1
- package/dist/tools/boot-simulator.js.map +1 -1
- package/dist/tools/delete-session.js +2 -1
- package/dist/tools/delete-session.js.map +1 -1
- package/dist/tools/documentation/index.js +7 -6
- package/dist/tools/documentation/index.js.map +1 -1
- package/dist/tools/documentation/reasoning-rag.js +16 -15
- package/dist/tools/documentation/reasoning-rag.js.map +1 -1
- package/dist/tools/documentation/sentence-transformers-embeddings.js +8 -7
- package/dist/tools/documentation/sentence-transformers-embeddings.js.map +1 -1
- package/dist/tools/documentation/simple-pdf-indexer.js +48 -47
- package/dist/tools/documentation/simple-pdf-indexer.js.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/install-wda.js +6 -5
- package/dist/tools/install-wda.js.map +1 -1
- package/dist/tools/interactions/get-page-source.d.ts +2 -0
- package/dist/tools/interactions/get-page-source.js +48 -0
- package/dist/tools/interactions/get-page-source.js.map +1 -0
- package/dist/tools/locators.js +2 -3
- package/dist/tools/locators.js.map +1 -1
- package/dist/tools/scroll.js +5 -4
- package/dist/tools/scroll.js.map +1 -1
- package/dist/tools/session-store.js +6 -5
- package/dist/tools/session-store.js.map +1 -1
- package/package.json +1 -1
- package/src/locators/generate-all-locators.ts +2 -1
- package/src/resources/index.ts +2 -1
- package/src/tools/README.md +2 -1
- package/src/tools/answer-appium.ts +2 -1
- package/src/tools/boot-simulator.ts +2 -1
- package/src/tools/delete-session.ts +2 -1
- package/src/tools/documentation/index.ts +7 -6
- package/src/tools/documentation/reasoning-rag.ts +16 -15
- package/src/tools/documentation/sentence-transformers-embeddings.ts +9 -7
- package/src/tools/documentation/simple-pdf-indexer.ts +48 -51
- package/src/tools/index.ts +2 -0
- package/src/tools/install-wda.ts +6 -5
- package/src/tools/interactions/get-page-source.ts +52 -0
- package/src/tools/locators.ts +3 -4
- package/src/tools/scroll.ts +5 -4
- package/src/tools/session-store.ts +6 -5
|
@@ -16,6 +16,7 @@ import { fileURLToPath } from 'url';
|
|
|
16
16
|
|
|
17
17
|
// Initialize embeddings using sentence-transformers (no API key required)
|
|
18
18
|
import { SentenceTransformersEmbeddings } from './sentence-transformers-embeddings.js';
|
|
19
|
+
import log from '../../locators/logger.js';
|
|
19
20
|
|
|
20
21
|
let embeddings: SentenceTransformersEmbeddings | null = null;
|
|
21
22
|
|
|
@@ -30,11 +31,11 @@ function getEmbeddings(): SentenceTransformersEmbeddings {
|
|
|
30
31
|
|
|
31
32
|
try {
|
|
32
33
|
// Use local sentence-transformers (no API key required)
|
|
33
|
-
|
|
34
|
+
log.info('Using local sentence-transformers embeddings');
|
|
34
35
|
const modelName =
|
|
35
36
|
process.env.SENTENCE_TRANSFORMERS_MODEL || 'Xenova/all-MiniLM-L6-v2';
|
|
36
37
|
embeddings = new SentenceTransformersEmbeddings({ modelName });
|
|
37
|
-
|
|
38
|
+
log.info(`Using sentence-transformers model: ${modelName}`);
|
|
38
39
|
} catch (error) {
|
|
39
40
|
throw new Error(
|
|
40
41
|
`Failed to initialize embeddings: ${
|
|
@@ -85,12 +86,12 @@ async function saveDocuments(
|
|
|
85
86
|
if (existingContent) {
|
|
86
87
|
const existingSerialized = JSON.parse(existingContent);
|
|
87
88
|
allSerialized = [...existingSerialized, ...serializedNew];
|
|
88
|
-
|
|
89
|
+
log.info(
|
|
89
90
|
`Appending ${serializedNew.length} documents to existing ${existingSerialized.length} documents`
|
|
90
91
|
);
|
|
91
92
|
}
|
|
92
93
|
} catch (readError) {
|
|
93
|
-
|
|
94
|
+
log.warn(
|
|
94
95
|
'Error reading existing documents, overwriting instead:',
|
|
95
96
|
readError
|
|
96
97
|
);
|
|
@@ -99,13 +100,13 @@ async function saveDocuments(
|
|
|
99
100
|
|
|
100
101
|
// Write to file
|
|
101
102
|
fs.writeFileSync(DOCUMENTS_PATH, JSON.stringify(allSerialized));
|
|
102
|
-
|
|
103
|
+
log.info(
|
|
103
104
|
`${
|
|
104
105
|
append ? 'Appended to' : 'Saved'
|
|
105
106
|
} documents in ${DOCUMENTS_PATH} (total: ${allSerialized.length})`
|
|
106
107
|
);
|
|
107
108
|
} catch (error) {
|
|
108
|
-
|
|
109
|
+
log.error('Error saving documents:', error);
|
|
109
110
|
throw error;
|
|
110
111
|
}
|
|
111
112
|
}
|
|
@@ -117,10 +118,10 @@ async function clearDocumentsFile(): Promise<void> {
|
|
|
117
118
|
try {
|
|
118
119
|
if (fs.existsSync(DOCUMENTS_PATH)) {
|
|
119
120
|
fs.writeFileSync(DOCUMENTS_PATH, JSON.stringify([]));
|
|
120
|
-
|
|
121
|
+
log.info(`Cleared documents file at ${DOCUMENTS_PATH}`);
|
|
121
122
|
}
|
|
122
123
|
} catch (error) {
|
|
123
|
-
|
|
124
|
+
log.error('Error clearing documents file:', error);
|
|
124
125
|
throw error;
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -132,7 +133,7 @@ async function clearDocumentsFile(): Promise<void> {
|
|
|
132
133
|
async function loadDocuments(): Promise<Document[] | null> {
|
|
133
134
|
try {
|
|
134
135
|
if (!fs.existsSync(DOCUMENTS_PATH)) {
|
|
135
|
-
|
|
136
|
+
log.info('No saved documents found');
|
|
136
137
|
return null;
|
|
137
138
|
}
|
|
138
139
|
|
|
@@ -148,10 +149,10 @@ async function loadDocuments(): Promise<Document[] | null> {
|
|
|
148
149
|
})
|
|
149
150
|
);
|
|
150
151
|
|
|
151
|
-
|
|
152
|
+
log.info(`${documents.length} documents loaded from ${DOCUMENTS_PATH}`);
|
|
152
153
|
return documents;
|
|
153
154
|
} catch (error) {
|
|
154
|
-
|
|
155
|
+
log.error('Error loading documents:', error);
|
|
155
156
|
return null;
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -166,7 +167,7 @@ async function extractTextFromMarkdown(markdownPath: string): Promise<string> {
|
|
|
166
167
|
const text = fs.readFileSync(markdownPath, 'utf-8');
|
|
167
168
|
return text;
|
|
168
169
|
} catch (error) {
|
|
169
|
-
|
|
170
|
+
log.error('Error extracting text from Markdown:', error);
|
|
170
171
|
throw new Error(
|
|
171
172
|
`Failed to extract text from Markdown: ${
|
|
172
173
|
error instanceof Error ? error.message : String(error)
|
|
@@ -188,13 +189,13 @@ export async function initializeVectorStore(
|
|
|
188
189
|
chunkOverlap: number = 200
|
|
189
190
|
): Promise<MemoryVectorStore> {
|
|
190
191
|
try {
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
log.info(`Initializing vector store for Markdown: ${markdownPath}`);
|
|
193
|
+
log.info(`Using chunk size: ${chunkSize}, overlap: ${chunkOverlap}`);
|
|
193
194
|
|
|
194
195
|
// Extract text from Markdown
|
|
195
|
-
|
|
196
|
+
log.info('Extracting text from Markdown...');
|
|
196
197
|
const markdownText = await extractTextFromMarkdown(markdownPath);
|
|
197
|
-
|
|
198
|
+
log.info(`Extracted ${markdownText.length} characters from Markdown`);
|
|
198
199
|
|
|
199
200
|
// Create text splitter
|
|
200
201
|
const textSplitter = new RecursiveCharacterTextSplitter({
|
|
@@ -203,12 +204,12 @@ export async function initializeVectorStore(
|
|
|
203
204
|
});
|
|
204
205
|
|
|
205
206
|
// Split text into documents
|
|
206
|
-
|
|
207
|
+
log.info('Splitting text into chunks...');
|
|
207
208
|
const documents = await textSplitter.createDocuments([markdownText]);
|
|
208
|
-
|
|
209
|
+
log.info(`Created ${documents.length} document chunks`);
|
|
209
210
|
|
|
210
211
|
// Store documents in memory vector store
|
|
211
|
-
|
|
212
|
+
log.info('Storing documents in memory vector store...');
|
|
212
213
|
const vectorStore = await MemoryVectorStore.fromDocuments(
|
|
213
214
|
documents,
|
|
214
215
|
getEmbeddings()
|
|
@@ -220,10 +221,10 @@ export async function initializeVectorStore(
|
|
|
220
221
|
// Save documents to file for persistence
|
|
221
222
|
await saveDocuments(documents, false); // Don't append for single file indexing
|
|
222
223
|
|
|
223
|
-
|
|
224
|
+
log.info('Successfully stored documents in memory vector store');
|
|
224
225
|
return vectorStore;
|
|
225
226
|
} catch (error) {
|
|
226
|
-
|
|
227
|
+
log.error('Error initializing vector store:', error);
|
|
227
228
|
throw error;
|
|
228
229
|
}
|
|
229
230
|
}
|
|
@@ -242,7 +243,7 @@ export async function getMarkdownFilesInDirectory(
|
|
|
242
243
|
|
|
243
244
|
// Check if directory exists
|
|
244
245
|
if (!fs.existsSync(dirPath)) {
|
|
245
|
-
|
|
246
|
+
log.error(`Directory does not exist: ${dirPath}`);
|
|
246
247
|
return [];
|
|
247
248
|
}
|
|
248
249
|
|
|
@@ -268,10 +269,10 @@ export async function getMarkdownFilesInDirectory(
|
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
await scanDirectory(dirPath);
|
|
271
|
-
|
|
272
|
+
log.info(`Found ${markdownFiles.length} Markdown files in ${dirPath}`);
|
|
272
273
|
return markdownFiles;
|
|
273
274
|
} catch (error) {
|
|
274
|
-
|
|
275
|
+
log.error('Error getting Markdown files:', error);
|
|
275
276
|
return [];
|
|
276
277
|
}
|
|
277
278
|
}
|
|
@@ -288,14 +289,14 @@ export async function indexMarkdown(
|
|
|
288
289
|
chunkOverlap: number = 200
|
|
289
290
|
): Promise<void> {
|
|
290
291
|
try {
|
|
291
|
-
|
|
292
|
+
log.info('Starting Markdown indexing process...');
|
|
292
293
|
|
|
293
294
|
// Initialize vector store
|
|
294
295
|
await initializeVectorStore(markdownPath, chunkSize, chunkOverlap);
|
|
295
296
|
|
|
296
|
-
|
|
297
|
+
log.info('Markdown indexing completed successfully');
|
|
297
298
|
} catch (error) {
|
|
298
|
-
|
|
299
|
+
log.error('Markdown indexing failed:', error);
|
|
299
300
|
throw error;
|
|
300
301
|
}
|
|
301
302
|
}
|
|
@@ -313,7 +314,7 @@ export async function indexAllMarkdownFiles(
|
|
|
313
314
|
chunkOverlap: number = 200
|
|
314
315
|
): Promise<string[]> {
|
|
315
316
|
try {
|
|
316
|
-
|
|
317
|
+
log.info(
|
|
317
318
|
`Starting indexing of all Markdown files in directory: ${dirPath}`
|
|
318
319
|
);
|
|
319
320
|
|
|
@@ -321,7 +322,7 @@ export async function indexAllMarkdownFiles(
|
|
|
321
322
|
const markdownFiles = await getMarkdownFilesInDirectory(dirPath);
|
|
322
323
|
|
|
323
324
|
if (markdownFiles.length === 0) {
|
|
324
|
-
|
|
325
|
+
log.info('No Markdown files found in the directory');
|
|
325
326
|
return [];
|
|
326
327
|
}
|
|
327
328
|
|
|
@@ -333,16 +334,14 @@ export async function indexAllMarkdownFiles(
|
|
|
333
334
|
for (let i = 0; i < markdownFiles.length; i++) {
|
|
334
335
|
const markdownFile = markdownFiles[i];
|
|
335
336
|
try {
|
|
336
|
-
|
|
337
|
+
log.info(
|
|
337
338
|
`Indexing Markdown ${i + 1}/${markdownFiles.length}: ${markdownFile}`
|
|
338
339
|
);
|
|
339
340
|
|
|
340
341
|
// Extract text from Markdown
|
|
341
|
-
|
|
342
|
+
log.info('Extracting text from Markdown...');
|
|
342
343
|
const markdownText = await extractTextFromMarkdown(markdownFile);
|
|
343
|
-
|
|
344
|
-
`Extracted ${markdownText.length} characters from Markdown`
|
|
345
|
-
);
|
|
344
|
+
log.info(`Extracted ${markdownText.length} characters from Markdown`);
|
|
346
345
|
|
|
347
346
|
// Create text splitter
|
|
348
347
|
const textSplitter = new RecursiveCharacterTextSplitter({
|
|
@@ -351,9 +350,9 @@ export async function indexAllMarkdownFiles(
|
|
|
351
350
|
});
|
|
352
351
|
|
|
353
352
|
// Split text into documents
|
|
354
|
-
|
|
353
|
+
log.info('Splitting text into chunks...');
|
|
355
354
|
const documents = await textSplitter.createDocuments([markdownText]);
|
|
356
|
-
|
|
355
|
+
log.info(`Created ${documents.length} document chunks`);
|
|
357
356
|
|
|
358
357
|
// Add file metadata to each document
|
|
359
358
|
const filename = path.basename(markdownFile);
|
|
@@ -368,7 +367,7 @@ export async function indexAllMarkdownFiles(
|
|
|
368
367
|
});
|
|
369
368
|
|
|
370
369
|
// Store documents in memory vector store
|
|
371
|
-
|
|
370
|
+
log.info('Storing documents in memory vector store...');
|
|
372
371
|
if (i === 0) {
|
|
373
372
|
// For the first Markdown file, create a new vector store
|
|
374
373
|
memoryVectorStore = await MemoryVectorStore.fromDocuments(
|
|
@@ -384,19 +383,19 @@ export async function indexAllMarkdownFiles(
|
|
|
384
383
|
await saveDocuments(documents, i > 0);
|
|
385
384
|
|
|
386
385
|
indexedFiles.push(markdownFile);
|
|
387
|
-
|
|
386
|
+
log.info(`Successfully indexed Markdown: ${filename}`);
|
|
388
387
|
} catch (error) {
|
|
389
|
-
|
|
388
|
+
log.error(`Error indexing Markdown ${markdownFile}:`, error);
|
|
390
389
|
// Continue with next file even if one fails
|
|
391
390
|
}
|
|
392
391
|
}
|
|
393
392
|
|
|
394
|
-
|
|
393
|
+
log.info(
|
|
395
394
|
`Successfully indexed ${indexedFiles.length} out of ${markdownFiles.length} Markdown files`
|
|
396
395
|
);
|
|
397
396
|
return indexedFiles;
|
|
398
397
|
} catch (error) {
|
|
399
|
-
|
|
398
|
+
log.error('Error indexing all Markdown files:', error);
|
|
400
399
|
throw error;
|
|
401
400
|
}
|
|
402
401
|
}
|
|
@@ -419,7 +418,7 @@ export async function queryVectorStore(
|
|
|
419
418
|
|
|
420
419
|
// If documents exist, create a new vector store
|
|
421
420
|
if (documents && documents.length > 0) {
|
|
422
|
-
|
|
421
|
+
log.info('Creating vector store from saved documents...');
|
|
423
422
|
memoryVectorStore = await MemoryVectorStore.fromDocuments(
|
|
424
423
|
documents,
|
|
425
424
|
getEmbeddings()
|
|
@@ -436,7 +435,7 @@ export async function queryVectorStore(
|
|
|
436
435
|
|
|
437
436
|
return results;
|
|
438
437
|
} catch (error) {
|
|
439
|
-
|
|
438
|
+
log.error('Error querying vector store:', error);
|
|
440
439
|
throw error;
|
|
441
440
|
}
|
|
442
441
|
}
|
|
@@ -477,32 +476,30 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
477
476
|
}
|
|
478
477
|
|
|
479
478
|
// Log embeddings provider that will be used
|
|
480
|
-
|
|
479
|
+
log.info('Using sentence-transformers embeddings (no API key required)');
|
|
481
480
|
|
|
482
481
|
// Run the indexing process
|
|
483
482
|
if (indexSingleFile) {
|
|
484
483
|
// Index a single Markdown file
|
|
485
|
-
|
|
484
|
+
log.info(`Indexing single Markdown file: ${markdownPath}`);
|
|
486
485
|
indexMarkdown(markdownPath, chunkSize, chunkOverlap)
|
|
487
486
|
.then(() => {
|
|
488
487
|
process.exit(0);
|
|
489
488
|
})
|
|
490
489
|
.catch(error => {
|
|
491
|
-
|
|
490
|
+
log.error('Indexing failed:', error);
|
|
492
491
|
process.exit(1);
|
|
493
492
|
});
|
|
494
493
|
} else {
|
|
495
494
|
// Index all Markdown files in the directory
|
|
496
|
-
|
|
495
|
+
log.info(`Indexing all Markdown files in directory: ${markdownPath}`);
|
|
497
496
|
indexAllMarkdownFiles(markdownPath, chunkSize, chunkOverlap)
|
|
498
497
|
.then(indexedFiles => {
|
|
499
|
-
|
|
500
|
-
`Successfully indexed ${indexedFiles.length} Markdown files`
|
|
501
|
-
);
|
|
498
|
+
log.info(`Successfully indexed ${indexedFiles.length} Markdown files`);
|
|
502
499
|
process.exit(0);
|
|
503
500
|
})
|
|
504
501
|
.catch(error => {
|
|
505
|
-
|
|
502
|
+
log.error('Indexing failed:', error);
|
|
506
503
|
process.exit(1);
|
|
507
504
|
});
|
|
508
505
|
}
|
package/src/tools/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ import clickElement from './interactions/click.js';
|
|
|
31
31
|
import doubleTap from './interactions/double-tap.js';
|
|
32
32
|
import setValue from './interactions/set-value.js';
|
|
33
33
|
import getText from './interactions/get-text.js';
|
|
34
|
+
import getPageSource from './interactions/get-page-source.js';
|
|
34
35
|
import screenshot from './interactions/screenshot.js';
|
|
35
36
|
import activateApp from './interactions/activate-app.js';
|
|
36
37
|
import installApp from './interactions/install-app.js';
|
|
@@ -127,6 +128,7 @@ export default function registerTools(server: FastMCP): void {
|
|
|
127
128
|
doubleTap(server);
|
|
128
129
|
setValue(server);
|
|
129
130
|
getText(server);
|
|
131
|
+
getPageSource(server);
|
|
130
132
|
screenshot(server);
|
|
131
133
|
generateTest(server);
|
|
132
134
|
log.info('All tools registered');
|
package/src/tools/install-wda.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { access, readdir, stat } from 'fs/promises';
|
|
|
9
9
|
import { constants } from 'fs';
|
|
10
10
|
import fs from 'fs'; // Keep for createWriteStream if used
|
|
11
11
|
import os from 'os';
|
|
12
|
+
import log from '../locators/logger.js';
|
|
12
13
|
|
|
13
14
|
const execAsync = promisify(exec);
|
|
14
15
|
|
|
@@ -228,7 +229,7 @@ export default function installWDA(server: any): void {
|
|
|
228
229
|
);
|
|
229
230
|
}
|
|
230
231
|
|
|
231
|
-
|
|
232
|
+
log.info(
|
|
232
233
|
`Installing WDA from ${appPath} on simulator ${targetSimulator}...`
|
|
233
234
|
);
|
|
234
235
|
|
|
@@ -250,14 +251,14 @@ export default function installWDA(server: any): void {
|
|
|
250
251
|
// Install the app (only if not already installed)
|
|
251
252
|
if (!isInstalled) {
|
|
252
253
|
await installAppOnSimulator(appPath, targetSimulator);
|
|
253
|
-
|
|
254
|
+
log.info('WDA app installed successfully');
|
|
254
255
|
} else {
|
|
255
|
-
|
|
256
|
+
log.info('WDA app already installed, skipping installation');
|
|
256
257
|
}
|
|
257
258
|
|
|
258
259
|
// Get bundle ID and launch the app
|
|
259
260
|
const bundleId = await getAppBundleId(appPath);
|
|
260
|
-
|
|
261
|
+
log.info(`Launching WDA with bundle ID: ${bundleId}`);
|
|
261
262
|
await launchAppOnSimulator(bundleId, targetSimulator);
|
|
262
263
|
|
|
263
264
|
return {
|
|
@@ -269,7 +270,7 @@ export default function installWDA(server: any): void {
|
|
|
269
270
|
],
|
|
270
271
|
};
|
|
271
272
|
} catch (error: any) {
|
|
272
|
-
|
|
273
|
+
log.error('Error installing WDA:', error);
|
|
273
274
|
throw new Error(`Failed to install WebDriverAgent: ${error.message}`);
|
|
274
275
|
}
|
|
275
276
|
},
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FastMCP } from 'fastmcp/dist/FastMCP.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getDriver } from '../session-store.js';
|
|
4
|
+
|
|
5
|
+
export default function getPageSource(server: FastMCP): void {
|
|
6
|
+
server.addTool({
|
|
7
|
+
name: 'appium_get_page_source',
|
|
8
|
+
description: 'Get the page source (XML) from the current screen',
|
|
9
|
+
parameters: z.object({}),
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
openWorldHint: false,
|
|
13
|
+
},
|
|
14
|
+
execute: async (args: any, context: any): Promise<any> => {
|
|
15
|
+
const driver = getDriver();
|
|
16
|
+
if (!driver) {
|
|
17
|
+
throw new Error('No driver found. Please create a session first.');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const pageSource = await driver.getPageSource();
|
|
22
|
+
|
|
23
|
+
if (!pageSource) {
|
|
24
|
+
throw new Error('Page source is empty or null');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
type: 'text',
|
|
31
|
+
text:
|
|
32
|
+
'Page source retrieved successfully: \n' +
|
|
33
|
+
'```xml ' +
|
|
34
|
+
pageSource +
|
|
35
|
+
'```',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
} catch (err: any) {
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: `Failed to get page source. Error: ${err.toString()}`,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
package/src/tools/locators.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { z } from 'zod';
|
|
13
13
|
import { getDriver } from './session-store.js';
|
|
14
14
|
import { generateAllElementLocators } from '../locators/generate-all-locators.js';
|
|
15
|
+
import log from '../locators/logger.js';
|
|
15
16
|
|
|
16
17
|
export default function generateLocators(server: any): void {
|
|
17
18
|
server.addTool({
|
|
@@ -34,8 +35,6 @@ export default function generateLocators(server: any): void {
|
|
|
34
35
|
);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
console.log('Getting page source');
|
|
38
|
-
|
|
39
38
|
try {
|
|
40
39
|
// Get the page source from the driver
|
|
41
40
|
const pageSource = await driver.getPageSource();
|
|
@@ -71,11 +70,11 @@ export default function generateLocators(server: any): void {
|
|
|
71
70
|
],
|
|
72
71
|
};
|
|
73
72
|
} catch (parseError: any) {
|
|
74
|
-
|
|
73
|
+
log.error('Error parsing XML:', parseError);
|
|
75
74
|
throw new Error(`Failed to parse XML: ${parseError.message}`);
|
|
76
75
|
}
|
|
77
76
|
} catch (error: any) {
|
|
78
|
-
|
|
77
|
+
log.error('Error getting page source:', error);
|
|
79
78
|
throw new Error(`Failed to get page source: ${error.message}`);
|
|
80
79
|
}
|
|
81
80
|
},
|
package/src/tools/scroll.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { getDriver, getPlatformName } from './session-store.js';
|
|
3
|
+
import log from '../locators/logger.js';
|
|
3
4
|
|
|
4
5
|
export default function scroll(server: any): void {
|
|
5
6
|
server.addTool({
|
|
@@ -25,7 +26,7 @@ export default function scroll(server: any): void {
|
|
|
25
26
|
|
|
26
27
|
try {
|
|
27
28
|
const { width, height } = await driver.getWindowSize();
|
|
28
|
-
|
|
29
|
+
log.info('Device screen size:', { width, height });
|
|
29
30
|
const startX = Math.floor(width / 2);
|
|
30
31
|
// calculate start and end Y positions for scrolling depending on the direction
|
|
31
32
|
// startY is at 80% of the height, endY is at 20% of the height for downward scroll
|
|
@@ -42,8 +43,8 @@ export default function scroll(server: any): void {
|
|
|
42
43
|
? Math.floor(height * 0.2)
|
|
43
44
|
: Math.floor(height * 0.8);
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
log.info('Going to scroll from:', { startX, startY });
|
|
47
|
+
log.info('Going to scroll to:', { startX, endY });
|
|
47
48
|
|
|
48
49
|
if (getPlatformName(driver) === 'Android') {
|
|
49
50
|
await driver.performActions([
|
|
@@ -60,7 +61,7 @@ export default function scroll(server: any): void {
|
|
|
60
61
|
],
|
|
61
62
|
},
|
|
62
63
|
]);
|
|
63
|
-
|
|
64
|
+
log.info('Scroll action completed successfully.');
|
|
64
65
|
} else if (getPlatformName(driver) === 'iOS') {
|
|
65
66
|
await driver.execute('mobile: scroll', {
|
|
66
67
|
direction: args.direction,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver';
|
|
2
2
|
import { XCUITestDriver } from 'appium-xcuitest-driver';
|
|
3
|
+
import log from '../locators/logger.js';
|
|
3
4
|
|
|
4
5
|
let driver: any = null;
|
|
5
6
|
let sessionId: string | null = null;
|
|
@@ -33,13 +34,13 @@ export function hasActiveSession(): boolean {
|
|
|
33
34
|
export async function safeDeleteSession(): Promise<boolean> {
|
|
34
35
|
// Check if there's no session to delete
|
|
35
36
|
if (!driver || !sessionId) {
|
|
36
|
-
|
|
37
|
+
log.info('No active session to delete.');
|
|
37
38
|
return false;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
// Check if deletion is already in progress
|
|
41
42
|
if (isDeletingSession) {
|
|
42
|
-
|
|
43
|
+
log.info('Session deletion already in progress, skipping...');
|
|
43
44
|
return false;
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -47,17 +48,17 @@ export async function safeDeleteSession(): Promise<boolean> {
|
|
|
47
48
|
isDeletingSession = true;
|
|
48
49
|
|
|
49
50
|
try {
|
|
50
|
-
|
|
51
|
+
log.info('Deleting current session');
|
|
51
52
|
await driver.deleteSession();
|
|
52
53
|
|
|
53
54
|
// Clear the session from store
|
|
54
55
|
driver = null;
|
|
55
56
|
sessionId = null;
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
log.info('Session deleted successfully.');
|
|
58
59
|
return true;
|
|
59
60
|
} catch (error) {
|
|
60
|
-
|
|
61
|
+
log.error('Error deleting session:', error);
|
|
61
62
|
throw error;
|
|
62
63
|
} finally {
|
|
63
64
|
// Always release lock
|