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.
@@ -0,0 +1,333 @@
1
+ /**
2
+ * UI Analyzer - Extract online count and comments from UI hierarchy
3
+ * Direct implementation using ShellX API
4
+ */
5
+ /**
6
+ * Get all UI elements from current screen
7
+ */
8
+ export async function getAllUIElements(findElement) {
9
+ // Find all elements by using empty selector with multiple=true
10
+ const result = await findElement({ text: '' }, // Empty text to match all
11
+ {
12
+ multiple: true,
13
+ maxResults: 1000,
14
+ visibleOnly: false,
15
+ clickableOnly: false,
16
+ });
17
+ if (!result?.success || !result?.elements) {
18
+ return [];
19
+ }
20
+ return result.elements;
21
+ }
22
+ /**
23
+ * Extract online count from top-right corner
24
+ */
25
+ export function extractOnlineCount(elements, screenWidth, screenHeight) {
26
+ // Define top-right corner area
27
+ const topRightThresholdX = screenWidth * 0.7; // Right 30%
28
+ const topRightThresholdY = screenHeight * 0.25; // Top 25%
29
+ // Number patterns (with optional separators)
30
+ const numberPatterns = [
31
+ /^\d+$/, // Pure numbers: "1234"
32
+ /^\d{1,3}(,\d{3})+$/, // Comma separated: "1,234"
33
+ /^\d+\.\d+[kKmM]?$/, // With decimals/suffixes: "1.2k", "1.5m"
34
+ /^\d+[\d,\.]*[kKmM]?$/, // Mixed: "1,234.5k"
35
+ ];
36
+ const candidates = [];
37
+ for (const el of elements) {
38
+ if (!el.text || !el.visible) {
39
+ continue;
40
+ }
41
+ const trimmedText = el.text.trim();
42
+ const isNumber = numberPatterns.some(pattern => pattern.test(trimmedText));
43
+ if (!isNumber) {
44
+ continue;
45
+ }
46
+ const centerX = (el.bounds.left + el.bounds.right) / 2;
47
+ const centerY = (el.bounds.top + el.bounds.bottom) / 2;
48
+ // Check if in top-right corner
49
+ if (centerX > topRightThresholdX && centerY < topRightThresholdY) {
50
+ // Calculate priority (closer to top-right corner = higher priority)
51
+ const distanceToCorner = Math.sqrt(Math.pow(screenWidth - centerX, 2) + Math.pow(centerY, 2));
52
+ // Also prefer smaller text (labels vs large numbers)
53
+ const textSize = el.bounds.bottom - el.bounds.top;
54
+ candidates.push({
55
+ element: el,
56
+ centerX,
57
+ centerY,
58
+ priority: -distanceToCorner - textSize * 0.5,
59
+ });
60
+ }
61
+ }
62
+ if (candidates.length === 0) {
63
+ return null;
64
+ }
65
+ // Sort by priority and get best match
66
+ candidates.sort((a, b) => b.priority - a.priority);
67
+ const best = candidates[0]?.element;
68
+ if (!best) {
69
+ return null;
70
+ }
71
+ // Parse the count
72
+ let count = 0;
73
+ const text = best.text.trim();
74
+ // Handle different formats
75
+ if (text.includes('k') || text.includes('K')) {
76
+ count = Math.floor(parseFloat(text.replace(/[kK,]/g, '')) * 1000);
77
+ }
78
+ else if (text.includes('m') || text.includes('M')) {
79
+ count = Math.floor(parseFloat(text.replace(/[mM,]/g, '')) * 1000000);
80
+ }
81
+ else {
82
+ count = parseInt(text.replace(/,/g, ''), 10);
83
+ }
84
+ return {
85
+ count: isNaN(count) ? 0 : count,
86
+ text,
87
+ bounds: {
88
+ left: best.bounds.left,
89
+ top: best.bounds.top,
90
+ right: best.bounds.right,
91
+ bottom: best.bounds.bottom,
92
+ },
93
+ confidence: candidates.length === 1 ? 'high' : 'medium',
94
+ };
95
+ }
96
+ /**
97
+ * Extract comment information from elements
98
+ * Looks for text elements that are likely comments based on position and content
99
+ */
100
+ export function extractComments(elements, maxComments = 20) {
101
+ const comments = [];
102
+ const seen = new Set();
103
+ // Get screen bounds to identify comment sections
104
+ // Comments are typically in the middle/lower part of the screen
105
+ let minY = Infinity;
106
+ let maxY = -Infinity;
107
+ for (const el of elements) {
108
+ if (el.text && el.text.trim().length > 0) {
109
+ minY = Math.min(minY, el.bounds.top);
110
+ maxY = Math.max(maxY, el.bounds.bottom);
111
+ }
112
+ }
113
+ const screenHeight = maxY - minY;
114
+ const commentAreaTop = minY + screenHeight * 0.3; // Comments start below top 30%
115
+ const commentAreaBottom = maxY - screenHeight * 0.1; // Comments end before bottom 10%
116
+ // Filter elements that look like comments
117
+ for (const el of elements) {
118
+ if (!el.text || el.text.trim().length === 0) {
119
+ continue;
120
+ }
121
+ const trimmedText = el.text.trim();
122
+ const centerY = (el.bounds.top + el.bounds.bottom) / 2;
123
+ // Skip if not in comment area
124
+ if (centerY < commentAreaTop || centerY > commentAreaBottom) {
125
+ continue;
126
+ }
127
+ // Skip very short texts (likely buttons/labels)
128
+ if (trimmedText.length < 3) {
129
+ continue;
130
+ }
131
+ // Skip elements that look like UI controls
132
+ if (el.clickable) {
133
+ continue;
134
+ }
135
+ // Skip common button/label patterns
136
+ const skipPatterns = [
137
+ /^(发送|取消|确定|关闭|返回|更多|展开|收起|关注|私信|分享)$/i,
138
+ /^(Send|Cancel|OK|Close|Back|More|Expand|Collapse|Follow|Message|Share)$/i,
139
+ /^\d+$/, // Pure numbers
140
+ /^\d{1,2}:\d{2}$/, // Time patterns like "14:15"
141
+ /^店铺销量/, // Shop sales info
142
+ /^保修期/, // Warranty info
143
+ /^(维度|内容|型号)$/, // Product specs
144
+ /^\d+年$/, // "1年", "2年" etc
145
+ ];
146
+ if (skipPatterns.some(pattern => pattern.test(trimmedText))) {
147
+ continue;
148
+ }
149
+ // Skip single character or very short labels
150
+ if (trimmedText.length <= 3 && !containsChinese(trimmedText)) {
151
+ continue;
152
+ }
153
+ // Skip store/shop names (usually short and contain "店" or "旗舰店")
154
+ if (trimmedText.includes('旗舰店') || trimmedText.includes('专卖店') || trimmedText.includes('店')) {
155
+ // Only skip if it's short (likely a shop name, not a comment mentioning a shop)
156
+ if (trimmedText.length < 10) {
157
+ continue;
158
+ }
159
+ }
160
+ // Deduplicate by text content
161
+ const key = trimmedText.toLowerCase();
162
+ if (seen.has(key)) {
163
+ continue;
164
+ }
165
+ seen.add(key);
166
+ comments.push({
167
+ text: trimmedText,
168
+ bounds: {
169
+ left: el.bounds.left,
170
+ top: el.bounds.top,
171
+ right: el.bounds.right,
172
+ bottom: el.bounds.bottom,
173
+ },
174
+ className: el.className,
175
+ });
176
+ if (comments.length >= maxComments) {
177
+ break;
178
+ }
179
+ }
180
+ // Sort by vertical position (top to bottom)
181
+ comments.sort((a, b) => a.bounds.top - b.bounds.top);
182
+ return comments;
183
+ }
184
+ /**
185
+ * Check if text contains Chinese characters
186
+ */
187
+ function containsChinese(text) {
188
+ return /[一-龥]/.test(text);
189
+ }
190
+ /**
191
+ * Analyze screen and provide summary
192
+ */
193
+ export function analyzeScreen(elements, screenWidth, screenHeight) {
194
+ const elementsByClass = {};
195
+ let elementsWithText = 0;
196
+ let clickableElements = 0;
197
+ for (const el of elements) {
198
+ // Count by class
199
+ elementsByClass[el.className] = (elementsByClass[el.className] || 0) + 1;
200
+ // Count elements with text
201
+ if (el.text && el.text.trim().length > 0) {
202
+ elementsWithText++;
203
+ }
204
+ // Count clickable elements
205
+ if (el.clickable) {
206
+ clickableElements++;
207
+ }
208
+ }
209
+ return {
210
+ screenWidth,
211
+ screenHeight,
212
+ totalElements: elements.length,
213
+ elementsWithText,
214
+ clickableElements,
215
+ elementsByClass,
216
+ };
217
+ }
218
+ /**
219
+ * Format screen analysis as readable text
220
+ */
221
+ export function formatScreenAnalysis(analysis) {
222
+ const lines = [
223
+ '=== 屏幕分析 ===',
224
+ `屏幕尺寸: ${analysis.screenWidth}x${analysis.screenHeight}`,
225
+ `总元素数: ${analysis.totalElements}`,
226
+ `包含文本的元素: ${analysis.elementsWithText}`,
227
+ `可点击元素: ${analysis.clickableElements}`,
228
+ '',
229
+ '=== 元素类别统计 ===',
230
+ ];
231
+ // Sort by count and show top 15
232
+ const sortedClasses = Object.entries(analysis.elementsByClass)
233
+ .sort((a, b) => b[1] - a[1])
234
+ .slice(0, 15);
235
+ for (const [className, count] of sortedClasses) {
236
+ lines.push(` ${className}: ${count}`);
237
+ }
238
+ return lines.join('\n');
239
+ }
240
+ /**
241
+ * Format online count result as readable text
242
+ */
243
+ export function formatOnlineCount(info) {
244
+ if (!info) {
245
+ return '=== 在线人数 ===\n未找到在线人数';
246
+ }
247
+ return [
248
+ '=== 在线人数 ===',
249
+ `数量: ${info.count}`,
250
+ `原文: "${info.text}"`,
251
+ `位置: [${info.bounds.left}, ${info.bounds.top} → ${info.bounds.right}, ${info.bounds.bottom}]`,
252
+ `置信度: ${info.confidence === 'high' ? '高' : info.confidence === 'medium' ? '中' : '低'}`,
253
+ ].join('\n');
254
+ }
255
+ /**
256
+ * Format comments as readable text
257
+ */
258
+ export function formatComments(comments) {
259
+ if (comments.length === 0) {
260
+ return '=== 评论信息 ===\n未找到评论';
261
+ }
262
+ const lines = [
263
+ '=== 评论信息 ===',
264
+ `找到 ${comments.length} 条评论`,
265
+ '',
266
+ ];
267
+ for (let i = 0; i < comments.length; i++) {
268
+ const comment = comments[i];
269
+ if (!comment)
270
+ continue;
271
+ lines.push(`${i + 1}. ${comment.text}`);
272
+ lines.push(` 位置: [${comment.bounds.left}, ${comment.bounds.top} → ${comment.bounds.right}, ${comment.bounds.bottom}]`);
273
+ lines.push(` 类型: ${comment.className}`);
274
+ lines.push('');
275
+ }
276
+ return lines.join('\n');
277
+ }
278
+ /**
279
+ * Extract all meaningful text content from elements
280
+ * Returns all text elements that might be useful (comments, descriptions, etc.)
281
+ */
282
+ export function extractAllTextContent(elements, maxLength = 50) {
283
+ const results = [];
284
+ for (const el of elements) {
285
+ if (!el.text || !el.visible) {
286
+ continue;
287
+ }
288
+ const trimmedText = el.text.trim();
289
+ // Skip very short or empty text
290
+ if (trimmedText.length < 2) {
291
+ continue;
292
+ }
293
+ // Skip single characters that are likely UI elements
294
+ if (trimmedText.length === 1 && !containsChinese(trimmedText)) {
295
+ continue;
296
+ }
297
+ results.push({
298
+ text: trimmedText.length > maxLength ? trimmedText.substring(0, maxLength) + '...' : trimmedText,
299
+ className: el.className,
300
+ bounds: {
301
+ left: el.bounds.left,
302
+ top: el.bounds.top,
303
+ right: el.bounds.right,
304
+ bottom: el.bounds.bottom,
305
+ },
306
+ });
307
+ }
308
+ // Sort by vertical position
309
+ results.sort((a, b) => a.bounds.top - b.bounds.top);
310
+ return results;
311
+ }
312
+ /**
313
+ * Format all text content as readable text
314
+ */
315
+ export function formatAllTextContent(contents) {
316
+ if (contents.length === 0) {
317
+ return '=== 所有文本内容 ===\n无文本内容';
318
+ }
319
+ const lines = [
320
+ '=== 所有文本内容 ===',
321
+ `共 ${contents.length} 条`,
322
+ '',
323
+ ];
324
+ for (let i = 0; i < contents.length; i++) {
325
+ const item = contents[i];
326
+ if (!item)
327
+ continue;
328
+ lines.push(`${i + 1}. ${item.text}`);
329
+ lines.push(` [${item.bounds.left}, ${item.bounds.top} → ${item.bounds.right}, ${item.bounds.bottom}] ${item.className}`);
330
+ }
331
+ return lines.join('\n');
332
+ }
333
+ //# sourceMappingURL=ui-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-analyzer.js","sourceRoot":"","sources":["../src/ui-analyzer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "shellx-ai",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "type": "module",
5
5
  "description": "A powerful TypeScript library for Android device automation and UI control via WebSocket",
6
6
  "workspaces": [
7
- "example"
7
+ "example",
8
+ "phone-agent",
9
+ "shellx-cli",
10
+ "gui-agent"
8
11
  ],
9
12
  "keywords": [
10
13
  "android",
@@ -44,8 +47,11 @@
44
47
  ],
45
48
  "scripts": {
46
49
  "build": "tsc",
50
+ "build:gui-agent": "cd gui-agent && npm run build:all",
47
51
  "build:phone-agent": "cd phone-agent && npm run build:all",
48
- "build:all": "npm run build && npm run build:phone-agent",
52
+ "build:shellx-cli": "cd shellx-cli && npm run build",
53
+ "build:example": "cd example && npm run build",
54
+ "build:all": "npm run build && npm run build:gui-agent && npm run build:phone-agent && npm run build:shellx-cli && npm run build:example",
49
55
  "build:watch": "tsc --watch",
50
56
  "type-check": "tsc --noEmit",
51
57
  "lint": "eslint src --ext .ts",
@@ -55,11 +61,13 @@
55
61
  "test": "jest",
56
62
  "test:coverage": "jest --coverage",
57
63
  "test:watch": "jest --watch",
58
- "clean": "rimraf dist && cd phone-agent && rimraf dist",
64
+ "clean": "rimraf dist && cd gui-agent && rimraf dist && cd ../phone-agent && rimraf dist && cd ../shellx-cli && rimraf dist && cd ../example && rimraf dist",
59
65
  "prepublishOnly": "npm run clean && npm run build && npm run type-check",
60
66
  "prepare": "husky install || echo 'Husky not available'"
61
67
  },
62
68
  "dependencies": {
69
+ "@mariozechner/pi-agent-core": "^0.65.2",
70
+ "@mariozechner/pi-ai": "^0.65.2",
63
71
  "cbor": "^9.0.0",
64
72
  "dotenv": "^16.4.5",
65
73
  "ofetch": "^1.4.1",
@@ -72,18 +80,31 @@
72
80
  "ws": "^8.14.2"
73
81
  },
74
82
  "devDependencies": {
83
+ "@eslint/plugin-kit": "^0.4.1",
75
84
  "@types/jest": "^30.0.0",
76
85
  "@types/node": "^24.0.13",
86
+ "@types/react": "^19.2.11",
87
+ "@types/uuid": "^9.0.7",
77
88
  "@types/ws": "^8.18.1",
78
89
  "@typescript-eslint/eslint-plugin": "^8.0.0",
79
90
  "@typescript-eslint/parser": "^8.0.0",
91
+ "autocomplete-cli": "^0.0.2",
92
+ "chalk": "^5.6.2",
93
+ "esbuild": "^0.27.4",
94
+ "esbuild-node-externals": "^1.20.1",
80
95
  "eslint": "^9.0.0",
81
96
  "eslint-config-prettier": "^9.1.0",
82
97
  "eslint-plugin-prettier": "^5.2.0",
98
+ "ink": "^6.6.0",
99
+ "ink-spinner": "^5.0.0",
100
+ "ink-text-input": "^6.0.0",
83
101
  "jest": "^30.0.4",
84
102
  "prettier": "^3.3.0",
103
+ "prettier-linter-helpers": "^1.0.1",
104
+ "react": "^19.2.4",
85
105
  "rimraf": "^6.0.0",
86
106
  "ts-jest": "^29.4.0",
107
+ "tsx": "^4.19.2",
87
108
  "typescript": "^5.8.3"
88
109
  },
89
110
  "engines": {
@@ -1,152 +0,0 @@
1
- /**
2
- * OutputBuffer - A module for managing shell command output buffering
3
- *
4
- * This module handles buffering, processing, and managing output from shell commands
5
- * across multiple sessions, with support for output cleaning and combination.
6
- */
7
- /**
8
- * Options for shell command execution
9
- */
10
- export interface ShellCommandOptions {
11
- /** Title for the command (used for logging) */
12
- title?: string;
13
- /** Timeout in milliseconds */
14
- timeout?: number;
15
- /** Wait time after command execution in milliseconds */
16
- waitAfterMs?: number;
17
- /** Callback for handling output chunks as they arrive */
18
- onOutput?: (output: string) => void;
19
- /** Callback for handling error messages */
20
- onError?: (error: string) => void;
21
- /** Expected output pattern (string or RegExp) */
22
- expectedOutput?: string | RegExp;
23
- /** Success pattern to match in output (string or RegExp) */
24
- successPattern?: string | RegExp;
25
- /** Whether to allow returning partial results on timeout */
26
- allowPartialResult?: boolean;
27
- /** Whether to automatically set Android PATH (default: true) */
28
- setAndroidPath?: boolean;
29
- }
30
- /**
31
- * Result of a shell command execution
32
- */
33
- export interface ShellCommandResult {
34
- /** Whether the command executed successfully */
35
- success: boolean;
36
- /** The command output */
37
- output: string;
38
- /** Error message if command failed */
39
- error?: string;
40
- /** Exit code of the command */
41
- exitCode?: number;
42
- /** Duration of command execution in milliseconds */
43
- duration: number;
44
- }
45
- /**
46
- * Internal promise representation for a pending shell command
47
- */
48
- interface CommandPromise {
49
- /** Resolve function for the promise */
50
- resolve: (result: ShellCommandResult) => void;
51
- /** Reject function for the promise */
52
- reject: (error: Error) => void;
53
- /** Start time of the command */
54
- startTime: number;
55
- /** Execution options */
56
- options: ShellCommandOptions;
57
- /** Accumulated output */
58
- output: string;
59
- /** Session-specific outputs */
60
- sessionOutputs: Map<number, string>;
61
- /** Original command string */
62
- command: string;
63
- }
64
- /**
65
- * OutputBuffer class manages shell command output buffering and processing
66
- *
67
- * This class handles:
68
- * - Buffering output from multiple shell command sessions
69
- * - Managing pending command promises
70
- * - Cleaning and combining output from different sessions
71
- * - Providing access to accumulated command results
72
- */
73
- export declare class OutputBuffer {
74
- /** Map of pending command promises keyed by command ID */
75
- private commandPromises;
76
- /**
77
- * Register a new command promise for tracking
78
- *
79
- * @param commandId - Unique identifier for the command
80
- * @param resolve - Promise resolve function
81
- * @param reject - Promise reject function
82
- * @param startTime - Command start timestamp
83
- * @param options - Command execution options
84
- * @param command - Original command string
85
- */
86
- registerCommand(commandId: string, resolve: (result: ShellCommandResult) => void, reject: (error: Error) => void, startTime: number, options: ShellCommandOptions, command: string): void;
87
- /**
88
- * Unregister and resolve a command promise
89
- *
90
- * @param commandId - Unique identifier for the command
91
- * @returns The command promise data if found, undefined otherwise
92
- */
93
- unregisterCommand(commandId: string): CommandPromise | undefined;
94
- /**
95
- * Get a registered command promise
96
- *
97
- * @param commandId - Unique identifier for the command
98
- * @returns The command promise data if found, undefined otherwise
99
- */
100
- getCommand(commandId: string): CommandPromise | undefined;
101
- /**
102
- * Check if a command is registered
103
- *
104
- * @param commandId - Unique identifier for the command
105
- * @returns True if the command is registered, false otherwise
106
- */
107
- hasCommand(commandId: string): boolean;
108
- /**
109
- * Get the number of pending commands
110
- *
111
- * @returns The number of currently registered commands
112
- */
113
- getPendingCount(): number;
114
- /**
115
- * Handle incoming shell output chunks
116
- *
117
- * This method processes output from shell sessions and distributes it
118
- * to all waiting commands.
119
- *
120
- * @param sessionId - The session ID for the output
121
- * @param chunks - Array of Uint8Array data chunks
122
- */
123
- handleShellOutput(sessionId: number, chunks: Uint8Array[]): void;
124
- /**
125
- * Clean command output by removing the command itself
126
- *
127
- * @param output - The raw output string
128
- * @param command - The command string to remove
129
- * @returns Cleaned output string
130
- */
131
- cleanCommandOutput(output: string, command: string): string;
132
- /**
133
- * Combine outputs from multiple sessions into a single string
134
- *
135
- * @param sessionOutputs - Map of session IDs to their outputs
136
- * @returns Combined output string
137
- */
138
- private combineSessionOutputs;
139
- /**
140
- * Clear all registered commands
141
- *
142
- * This method is useful for cleanup or reset scenarios
143
- */
144
- clear(): void;
145
- /**
146
- * Get all registered command IDs
147
- *
148
- * @returns Array of command IDs
149
- */
150
- getCommandIds(): string[];
151
- }
152
- export {};