shellx-ai 1.1.1 → 1.1.3
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/README.md +201 -666
- package/dist/automation/element-finder.d.ts +0 -8
- package/dist/automation/element-finder.js +0 -7
- package/dist/automation/element-finder.js.map +1 -1
- package/dist/automation/ui-action-handler.d.ts +1 -1
- package/dist/automation/ui-action-handler.js +66 -32
- package/dist/automation/ui-action-handler.js.map +1 -1
- package/dist/cbor-compat.js +8 -10
- package/dist/cbor-compat.js.map +1 -1
- package/dist/data/index.d.ts +9 -0
- package/dist/data/index.js +11 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/types.d.ts +351 -0
- package/dist/data/types.js +8 -0
- package/dist/data/types.js.map +1 -0
- package/dist/domain-manager.js +4 -5
- package/dist/domain-manager.js.map +1 -1
- package/dist/errors.js +4 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +48 -25
- package/dist/index.js +226 -51
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +28 -5
- package/dist/shellx.d.ts +139 -56
- package/dist/shellx.js +211 -93
- package/dist/shellx.js.map +1 -1
- package/dist/types.d.ts +38 -1
- package/dist/ui-analyzer.d.ts +90 -0
- package/dist/ui-analyzer.js +333 -0
- package/dist/ui-analyzer.js.map +1 -0
- package/package.json +25 -4
- package/dist/shell/output-buffer.d.ts +0 -152
- package/dist/shell/output-buffer.js +0 -176
- package/dist/shell/output-buffer.js.map +0 -1
- package/dist/shell/shell-command-executor.d.ts +0 -182
- package/dist/shell/shell-command-executor.js +0 -404
- package/dist/shell/shell-command-executor.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,666 +1,201 @@
|
|
|
1
|
-
# ShellX
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
Click on an element by text, ID, or coordinates.
|
|
203
|
-
|
|
204
|
-
**Simplified form (click by text):**
|
|
205
|
-
```typescript
|
|
206
|
-
await shellx.click('Submit');
|
|
207
|
-
await shellx.click('Submit', { clickType: 'long' });
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
**Full form:**
|
|
211
|
-
```typescript
|
|
212
|
-
await shellx.click({
|
|
213
|
-
text: 'Submit', // Click by text
|
|
214
|
-
elementId: 'btn123', // Or by element ID
|
|
215
|
-
resourceId: 'submit_btn', // Or by resource ID
|
|
216
|
-
x: 500, // Or by coordinates
|
|
217
|
-
y: 1000,
|
|
218
|
-
clickType: 'single', // 'single' | 'double' | 'long' | 'normal'
|
|
219
|
-
timeout: 5000
|
|
220
|
-
});
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### Input
|
|
224
|
-
|
|
225
|
-
Input text into a field.
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
await shellx.input({
|
|
229
|
-
elementId: 'field123',
|
|
230
|
-
text: 'Hello World',
|
|
231
|
-
clear: true, // Clear field before input
|
|
232
|
-
hideKeyboard: true // Hide keyboard after input
|
|
233
|
-
});
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Swipe
|
|
237
|
-
|
|
238
|
-
Perform swipe gesture.
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
await shellx.swipe({
|
|
242
|
-
fromX: 500,
|
|
243
|
-
fromY: 1000,
|
|
244
|
-
toX: 500,
|
|
245
|
-
toY: 500,
|
|
246
|
-
duration: 800 // Duration in ms
|
|
247
|
-
});
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Press
|
|
251
|
-
|
|
252
|
-
Press hardware key.
|
|
253
|
-
|
|
254
|
-
**Simplified:**
|
|
255
|
-
```typescript
|
|
256
|
-
await shellx.press('BACK');
|
|
257
|
-
await shellx.press('HOME');
|
|
258
|
-
await shellx.press('MENU', { longPress: true });
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
**Full:**
|
|
262
|
-
```typescript
|
|
263
|
-
await shellx.press({
|
|
264
|
-
key: 'BACK',
|
|
265
|
-
longPress: false
|
|
266
|
-
});
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Wait
|
|
270
|
-
|
|
271
|
-
Wait for an element condition.
|
|
272
|
-
|
|
273
|
-
**Simplified:**
|
|
274
|
-
```typescript
|
|
275
|
-
await shellx.wait('Submit');
|
|
276
|
-
await shellx.wait('Loading', { timeout: 10000 });
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
**Full:**
|
|
280
|
-
```typescript
|
|
281
|
-
await shellx.wait({
|
|
282
|
-
text: 'Submit',
|
|
283
|
-
condition: 'visible', // 'visible' | 'gone' | 'enabled'
|
|
284
|
-
timeout: 5000
|
|
285
|
-
});
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### Find
|
|
289
|
-
|
|
290
|
-
Find UI elements.
|
|
291
|
-
|
|
292
|
-
**Simplified:**
|
|
293
|
-
```typescript
|
|
294
|
-
const result = await shellx.find('Button');
|
|
295
|
-
const all = await shellx.find('Button', { multiple: true, maxResults: 10 });
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
**Full:**
|
|
299
|
-
```typescript
|
|
300
|
-
const result = await shellx.find({
|
|
301
|
-
text: 'Submit',
|
|
302
|
-
multiple: false,
|
|
303
|
-
maxResults: 100,
|
|
304
|
-
pressClick: true // Auto-click after find
|
|
305
|
-
});
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### Command
|
|
309
|
-
|
|
310
|
-
Execute shell command.
|
|
311
|
-
|
|
312
|
-
**Simplified:**
|
|
313
|
-
```typescript
|
|
314
|
-
const result = await shellx.command('ls -la');
|
|
315
|
-
const result = await shellx.command('ls -la', { timeout: 5000 });
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
**Full:**
|
|
319
|
-
```typescript
|
|
320
|
-
const result = await shellx.command({
|
|
321
|
-
cmd: 'ls -la',
|
|
322
|
-
timeout: 10000,
|
|
323
|
-
wait: 1000 // Wait after command
|
|
324
|
-
});
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Screenshot
|
|
328
|
-
|
|
329
|
-
Take screenshot.
|
|
330
|
-
|
|
331
|
-
```typescript
|
|
332
|
-
const screenshot = await shellx.takeScreenshot({
|
|
333
|
-
format: 'png', // 'png' | 'jpeg'
|
|
334
|
-
quality: 100, // 0-100 for JPEG
|
|
335
|
-
saveToFile: true
|
|
336
|
-
});
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
### Clipboard
|
|
340
|
-
|
|
341
|
-
Clipboard operations.
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
// Get clipboard
|
|
345
|
-
const result = await shellx.clipboard({ get: true });
|
|
346
|
-
|
|
347
|
-
// Set clipboard
|
|
348
|
-
await shellx.clipboard({ text: 'Hello' });
|
|
349
|
-
|
|
350
|
-
// Paste clipboard
|
|
351
|
-
await shellx.clipboard({ paste: true });
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### ExecuteActions (Batch)
|
|
355
|
-
|
|
356
|
-
Execute multiple actions in sequence.
|
|
357
|
-
|
|
358
|
-
```typescript
|
|
359
|
-
const result = await shellx.executeActions([
|
|
360
|
-
{ text: 'Settings' }, // Click
|
|
361
|
-
{ cmd: 'ls -la' }, // Command
|
|
362
|
-
{ fromX: 500, fromY: 1000, toX: 500, toY: 500 }, // Swipe
|
|
363
|
-
{ key: 'BACK' } // Press
|
|
364
|
-
]);
|
|
365
|
-
|
|
366
|
-
console.log(`Success: ${result.successCount}/${result.results.length}`);
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
## Complete Working Example
|
|
372
|
-
|
|
373
|
-
Here's a complete example that you can run directly:
|
|
374
|
-
|
|
375
|
-
```typescript
|
|
376
|
-
// File: example.ts
|
|
377
|
-
import { ShellX } from 'shellx-ai';
|
|
378
|
-
|
|
379
|
-
async function main() {
|
|
380
|
-
// 1. Create ShellX instance
|
|
381
|
-
const shellx = new ShellX({
|
|
382
|
-
deviceId: process.env.DEVICE_ID || 'your-device-id',
|
|
383
|
-
onOpen: () => console.log('✅ Connected!')
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
try {
|
|
387
|
-
// 2. Wait for connection
|
|
388
|
-
await shellx.ready();
|
|
389
|
-
console.log('📱 Connected to device');
|
|
390
|
-
|
|
391
|
-
// 3. Get screen info
|
|
392
|
-
const screen = await shellx.getScreenInfo();
|
|
393
|
-
console.log(`Screen: ${screen.width}x${screen.height}`);
|
|
394
|
-
|
|
395
|
-
// 4. Click element
|
|
396
|
-
await shellx.click('Settings');
|
|
397
|
-
console.log('✅ Clicked Settings');
|
|
398
|
-
|
|
399
|
-
// 5. Press back
|
|
400
|
-
await shellx.press('BACK');
|
|
401
|
-
console.log('✅ Pressed BACK');
|
|
402
|
-
|
|
403
|
-
// 6. Execute command
|
|
404
|
-
const result = await shellx.command('getprop ro.build.version.release');
|
|
405
|
-
console.log(`Android: ${result.output.trim()}`);
|
|
406
|
-
|
|
407
|
-
// 7. Take screenshot
|
|
408
|
-
const screenshot = await shellx.takeScreenshot({ format: 'png' });
|
|
409
|
-
console.log(`Screenshot: ${screenshot.imagePath}`);
|
|
410
|
-
|
|
411
|
-
// 8. Batch operations
|
|
412
|
-
const batch = await shellx.executeActions([
|
|
413
|
-
{ text: 'Settings' },
|
|
414
|
-
{ cmd: 'wm size' }
|
|
415
|
-
]);
|
|
416
|
-
console.log(`Batch: ${batch.successCount}/${batch.results.length} successful`);
|
|
417
|
-
|
|
418
|
-
console.log('🎉 All operations completed!');
|
|
419
|
-
} catch (error) {
|
|
420
|
-
console.error('❌ Error:', error);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
main();
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
Compile and run:
|
|
428
|
-
|
|
429
|
-
```bash
|
|
430
|
-
# Install dependencies
|
|
431
|
-
npm install shellx-ai dotenv
|
|
432
|
-
|
|
433
|
-
# Create .env file
|
|
434
|
-
echo "DEVICE_ID=your-device-id" > .env
|
|
435
|
-
|
|
436
|
-
# Run with tsx
|
|
437
|
-
npx tsx example.ts
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
---
|
|
441
|
-
|
|
442
|
-
## Response Types
|
|
443
|
-
|
|
444
|
-
All operations return a result object with the following structure:
|
|
445
|
-
|
|
446
|
-
```typescript
|
|
447
|
-
interface Result {
|
|
448
|
-
success: boolean; // Operation success status
|
|
449
|
-
error?: string; // Error message if failed
|
|
450
|
-
duration: number; // Operation duration in ms
|
|
451
|
-
timestamp: number; // Operation timestamp
|
|
452
|
-
// ... additional fields specific to each operation
|
|
453
|
-
}
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### CommandResult
|
|
457
|
-
|
|
458
|
-
```typescript
|
|
459
|
-
{
|
|
460
|
-
success: boolean;
|
|
461
|
-
output: string; // Command output
|
|
462
|
-
error?: string;
|
|
463
|
-
exitCode?: number;
|
|
464
|
-
duration: number;
|
|
465
|
-
cmd: string;
|
|
466
|
-
timestamp: number;
|
|
467
|
-
}
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
### FindResult
|
|
471
|
-
|
|
472
|
-
```typescript
|
|
473
|
-
{
|
|
474
|
-
success: boolean;
|
|
475
|
-
found: boolean;
|
|
476
|
-
count: number; // Number of elements found
|
|
477
|
-
elements: Array<{
|
|
478
|
-
id: string;
|
|
479
|
-
text: string;
|
|
480
|
-
class: string;
|
|
481
|
-
left: number;
|
|
482
|
-
top: number;
|
|
483
|
-
right: number;
|
|
484
|
-
bottom: number;
|
|
485
|
-
visible: boolean;
|
|
486
|
-
clickable: boolean;
|
|
487
|
-
}>;
|
|
488
|
-
duration: number;
|
|
489
|
-
timestamp: number;
|
|
490
|
-
}
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### ScreenInfoResult
|
|
494
|
-
|
|
495
|
-
```typescript
|
|
496
|
-
{
|
|
497
|
-
success: boolean;
|
|
498
|
-
width: number;
|
|
499
|
-
height: number;
|
|
500
|
-
density: number;
|
|
501
|
-
screenOn: boolean;
|
|
502
|
-
screenUnlocked: boolean;
|
|
503
|
-
foregroundApp?: string;
|
|
504
|
-
foregroundActivity?: string;
|
|
505
|
-
model?: string;
|
|
506
|
-
androidVersion?: string;
|
|
507
|
-
manufacturer?: string;
|
|
508
|
-
duration: number;
|
|
509
|
-
timestamp: number;
|
|
510
|
-
}
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
---
|
|
514
|
-
|
|
515
|
-
## Logging
|
|
516
|
-
|
|
517
|
-
Control logging level:
|
|
518
|
-
|
|
519
|
-
```typescript
|
|
520
|
-
const shellx = new ShellX({
|
|
521
|
-
deviceId: 'your-device-id',
|
|
522
|
-
logLevel: 3 // 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
// Or at runtime
|
|
526
|
-
shellx.setLogLevel(4); // Enable debug logging
|
|
527
|
-
shellx.enableDebugLogging(); // Shortcut
|
|
528
|
-
shellx.disableLogging(); // Disable all logging
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
---
|
|
532
|
-
|
|
533
|
-
## Error Handling
|
|
534
|
-
|
|
535
|
-
```typescript
|
|
536
|
-
try {
|
|
537
|
-
await shellx.click('Settings');
|
|
538
|
-
} catch (error) {
|
|
539
|
-
if (error instanceof Error) {
|
|
540
|
-
console.error('Click failed:', error.message);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Or check result
|
|
545
|
-
const result = await shellx.click('Settings');
|
|
546
|
-
if (!result.success) {
|
|
547
|
-
console.error('Failed:', result.error);
|
|
548
|
-
}
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
---
|
|
552
|
-
|
|
553
|
-
## Advanced Usage
|
|
554
|
-
|
|
555
|
-
### Wait for Multiple Elements
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
const result = await shellx.waitAnyElement([
|
|
559
|
-
{ text: 'OK' },
|
|
560
|
-
{ text: 'Confirm' },
|
|
561
|
-
{ text: 'Submit' }
|
|
562
|
-
], 10000);
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
### Scroll to Find Element
|
|
566
|
-
|
|
567
|
-
```typescript
|
|
568
|
-
const element = await shellx.scrollToFindElement(
|
|
569
|
-
{ text: 'Target Item' },
|
|
570
|
-
5, // max scroll attempts
|
|
571
|
-
'down' // direction
|
|
572
|
-
);
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### Find with Retry
|
|
576
|
-
|
|
577
|
-
```typescript
|
|
578
|
-
const element = await shellx.findElementWithRetry(
|
|
579
|
-
{ text: 'Submit', visible: true },
|
|
580
|
-
3, // max retries
|
|
581
|
-
1000 // retry delay
|
|
582
|
-
);
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
---
|
|
586
|
-
|
|
587
|
-
## Platform Support
|
|
588
|
-
|
|
589
|
-
### Node.js
|
|
590
|
-
|
|
591
|
-
```bash
|
|
592
|
-
npm install shellx-ai ws
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
```typescript
|
|
596
|
-
import { ShellX } from 'shellx-ai';
|
|
597
|
-
const shellx = new ShellX({ deviceId: 'device-id' });
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
### Browser
|
|
601
|
-
|
|
602
|
-
```bash
|
|
603
|
-
npm install shellx-ai
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
```typescript
|
|
607
|
-
import { ShellX } from 'shellx-ai';
|
|
608
|
-
const shellx = new ShellX({ deviceId: 'device-id' });
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
---
|
|
612
|
-
|
|
613
|
-
## Troubleshooting
|
|
614
|
-
|
|
615
|
-
### Connection Issues
|
|
616
|
-
|
|
617
|
-
```typescript
|
|
618
|
-
const shellx = new ShellX({
|
|
619
|
-
deviceId: 'your-device-id',
|
|
620
|
-
timeout: 10000, // Increase timeout
|
|
621
|
-
reconnect: true, // Enable auto-reconnect
|
|
622
|
-
reconnectMaxAttempts: 10, // More attempts
|
|
623
|
-
onError: (error) => console.error('Connection error:', error)
|
|
624
|
-
});
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
### Element Not Found
|
|
628
|
-
|
|
629
|
-
```typescript
|
|
630
|
-
// Wait for element first
|
|
631
|
-
await shellx.wait('Submit', { timeout: 10000 });
|
|
632
|
-
|
|
633
|
-
// Then click
|
|
634
|
-
await shellx.click('Submit');
|
|
635
|
-
```
|
|
636
|
-
|
|
637
|
-
### Command Timeout
|
|
638
|
-
|
|
639
|
-
```typescript
|
|
640
|
-
const result = await shellx.command({
|
|
641
|
-
cmd: 'long-running-command',
|
|
642
|
-
timeout: 30000 // 30 seconds
|
|
643
|
-
});
|
|
644
|
-
```
|
|
645
|
-
|
|
646
|
-
---
|
|
647
|
-
|
|
648
|
-
## See Also
|
|
649
|
-
|
|
650
|
-
- [API-GUIDE.md](./API-GUIDE.md) - Detailed API guide
|
|
651
|
-
- [API-QUICK-REFERENCE.md](./API-QUICK-REFERENCE.md) - Quick reference
|
|
652
|
-
- [example/](./example/) - Complete working examples
|
|
653
|
-
|
|
654
|
-
---
|
|
655
|
-
|
|
656
|
-
## License
|
|
657
|
-
|
|
658
|
-
MIT License - see [LICENSE](LICENSE) file.
|
|
659
|
-
|
|
660
|
-
---
|
|
661
|
-
|
|
662
|
-
## Support
|
|
663
|
-
|
|
664
|
-
- 📚 [Documentation](https://github.com/10cl/shellx)
|
|
665
|
-
- 🐛 [Issues](https://github.com/10cl/shellx/issues)
|
|
666
|
-
- 💬 [Discussions](https://github.com/10cl/shellx/discussions)
|
|
1
|
+
# ShellX-AI 数据采集与监控系统
|
|
2
|
+
|
|
3
|
+
一个完整的数据采集、传输和可视化监控系统,使用 ShellX-AI SDK 进行设备数据采集,Node.js 后端接收和存储数据,Web 界面实时展示。
|
|
4
|
+
|
|
5
|
+
## 📋 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ 使用 ShellX-AI SDK 自动采集设备屏幕数据
|
|
8
|
+
- ✅ 实时提取数值数据(点赞数、评论数、分享数等)
|
|
9
|
+
- ✅ 实时提取文本数据
|
|
10
|
+
- ✅ Node.js 后端接收和存储数据
|
|
11
|
+
- ✅ Web 界面实时展示和监控
|
|
12
|
+
- ✅ 历史数据记录和趋势分析
|
|
13
|
+
- ✅ 统计指标计算
|
|
14
|
+
|
|
15
|
+
## 🚀 快速开始
|
|
16
|
+
|
|
17
|
+
### 1. 安装依赖
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. 启动系统
|
|
24
|
+
|
|
25
|
+
**方式一:分别启动**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 终端1:启动后端服务器
|
|
29
|
+
npm run server
|
|
30
|
+
|
|
31
|
+
# 终端2:启动数据采集
|
|
32
|
+
npm run collect
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**方式二:同时启动(推荐)**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. 访问监控面板
|
|
42
|
+
|
|
43
|
+
打开浏览器访问:`http://localhost:3000`
|
|
44
|
+
|
|
45
|
+
## 📁 项目结构
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
.
|
|
49
|
+
├── collect_douyin_data.ts # 数据采集脚本(使用 ShellX-AI SDK)
|
|
50
|
+
├── server.ts # Node.js 后端服务器
|
|
51
|
+
├── package.json # 项目配置和依赖
|
|
52
|
+
├── README.md # 项目说明文档
|
|
53
|
+
└── public/
|
|
54
|
+
└── index.html # 数据展示页面
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 🔧 配置说明
|
|
58
|
+
|
|
59
|
+
### 修改采集间隔
|
|
60
|
+
|
|
61
|
+
在 `collect_douyin_data.ts` 中修改:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// 每5秒采集一次
|
|
65
|
+
setInterval(async () => {
|
|
66
|
+
try {
|
|
67
|
+
await collectVideoData();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('采集出错:', error.message);
|
|
70
|
+
}
|
|
71
|
+
}, 5000); // 修改这个值(毫秒)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 修改后端端口
|
|
75
|
+
|
|
76
|
+
在 `server.ts` 中修改:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const PORT = 3000; // 修改为你想要的端口
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 修改API地址
|
|
83
|
+
|
|
84
|
+
在 `collect_douyin_data.ts` 中修改:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const API_URL = 'http://localhost:3000/api/data';
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 📊 数据格式
|
|
91
|
+
|
|
92
|
+
### 发送到后端的数据格式
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
{
|
|
96
|
+
timestamp: string; // 时间戳
|
|
97
|
+
app: string; // 当前应用
|
|
98
|
+
screen: { // 屏幕信息
|
|
99
|
+
width: number;
|
|
100
|
+
height: number;
|
|
101
|
+
};
|
|
102
|
+
metrics: {
|
|
103
|
+
numericData: Array<{ // 数值数据
|
|
104
|
+
label: string;
|
|
105
|
+
value: number;
|
|
106
|
+
raw: string;
|
|
107
|
+
}>;
|
|
108
|
+
textData: Array<{ // 文本数据
|
|
109
|
+
text: string;
|
|
110
|
+
id: string;
|
|
111
|
+
}>;
|
|
112
|
+
};
|
|
113
|
+
elementCount: number; // 元素总数
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 🌐 API 接口
|
|
118
|
+
|
|
119
|
+
### POST /api/data
|
|
120
|
+
接收采集的数据
|
|
121
|
+
|
|
122
|
+
**请求体:** 数据采集对象
|
|
123
|
+
|
|
124
|
+
**响应:** `{ success: true, message: 'Data received' }`
|
|
125
|
+
|
|
126
|
+
### GET /api/data
|
|
127
|
+
获取所有数据
|
|
128
|
+
|
|
129
|
+
**响应:** 完整的数据存储对象
|
|
130
|
+
|
|
131
|
+
### GET /api/history?limit=50
|
|
132
|
+
获取历史数据
|
|
133
|
+
|
|
134
|
+
**参数:**
|
|
135
|
+
- `limit`: 返回的记录数(默认50)
|
|
136
|
+
|
|
137
|
+
**响应:** 历史数据数组
|
|
138
|
+
|
|
139
|
+
### GET /api/metrics
|
|
140
|
+
获取统计指标
|
|
141
|
+
|
|
142
|
+
**响应:** 统计指标对象
|
|
143
|
+
|
|
144
|
+
### POST /api/clear
|
|
145
|
+
清空所有数据
|
|
146
|
+
|
|
147
|
+
**响应:** `{ success: true, message: 'Data cleared' }`
|
|
148
|
+
|
|
149
|
+
## 📱 支持的应用
|
|
150
|
+
|
|
151
|
+
当前脚本针对抖音(`com.ss.android.ugc.aweme`)进行了优化,但可以轻松适配其他应用:
|
|
152
|
+
|
|
153
|
+
1. 修改 `collect_douyin_data.ts` 中的数据提取逻辑
|
|
154
|
+
2. 根据目标应用的 UI 结构调整过滤条件
|
|
155
|
+
|
|
156
|
+
## 🔍 数据采集原理
|
|
157
|
+
|
|
158
|
+
1. **获取设备信息**:使用 `shellx.getScreenInfo()` 获取屏幕状态
|
|
159
|
+
2. **获取UI元素**:使用 `shellx.findElementsWithRetry()` 获取屏幕所有元素
|
|
160
|
+
3. **数据过滤**:
|
|
161
|
+
- 数值数据:匹配数字格式(支持"1.2万"、"10w"等)
|
|
162
|
+
- 文本数据:过滤出有意义的长文本
|
|
163
|
+
4. **数据传输**:通过 HTTP POST 发送到后端
|
|
164
|
+
5. **数据展示**:Web 界面实时更新和可视化
|
|
165
|
+
|
|
166
|
+
## 🛠️ 技术栈
|
|
167
|
+
|
|
168
|
+
- **数据采集**: ShellX-AI SDK
|
|
169
|
+
- **后端**: Node.js + Express + TypeScript
|
|
170
|
+
- **前端**: HTML + CSS + JavaScript
|
|
171
|
+
- **数据传输**: REST API + JSON
|
|
172
|
+
|
|
173
|
+
## 📝 注意事项
|
|
174
|
+
|
|
175
|
+
1. 确保设备已连接并授权 ShellX-AI
|
|
176
|
+
2. 后端服务器必须先启动才能接收数据
|
|
177
|
+
3. 数据采集频率不宜过高,避免对设备性能产生影响
|
|
178
|
+
4. 根据实际需求调整数据过滤和提取逻辑
|
|
179
|
+
|
|
180
|
+
## 🚨 故障排除
|
|
181
|
+
|
|
182
|
+
### 数据无法显示
|
|
183
|
+
|
|
184
|
+
1. 检查后端服务器是否正常运行
|
|
185
|
+
2. 检查采集脚本是否正常启动
|
|
186
|
+
3. 检查浏览器控制台是否有错误信息
|
|
187
|
+
4. 确认 API 地址配置正确
|
|
188
|
+
|
|
189
|
+
### 采集脚本报错
|
|
190
|
+
|
|
191
|
+
1. 检查设备连接状态
|
|
192
|
+
2. 确认 ShellX-AI SDK 已正确安装
|
|
193
|
+
3. 查看错误日志定位问题
|
|
194
|
+
|
|
195
|
+
## 📄 许可证
|
|
196
|
+
|
|
197
|
+
MIT License
|
|
198
|
+
|
|
199
|
+
## 🤝 贡献
|
|
200
|
+
|
|
201
|
+
欢迎提交 Issue 和 Pull Request!
|