shellx-ai 1.0.10 → 1.0.11

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/dist/index.d.ts CHANGED
@@ -25,7 +25,6 @@ export interface PendingTask {
25
25
  reject: (err: Error) => void;
26
26
  timer: number;
27
27
  type: string;
28
- commandType?: string;
29
28
  }
30
29
  /**
31
30
  * Enhanced WebSocket Task Client with protocol-aware task methods
@@ -59,7 +58,7 @@ export declare class ConnectionTaskClient {
59
58
  private handleMessage;
60
59
  private processServerMessage;
61
60
  private handleJsonDataResponse;
62
- sendMessage(message: WsClient, taskType?: string, commandType?: string): Promise<any>;
61
+ sendMessage(message: WsClient, taskType?: string, timeout?: number): Promise<any>;
63
62
  /**
64
63
  * Find UI elements on the screen
65
64
  */
@@ -90,7 +89,7 @@ export declare class ConnectionTaskClient {
90
89
  /**
91
90
  * Execute an action sequence
92
91
  */
93
- executeAction(actionSequence: ActionSequence, taskId?: string): Promise<any>;
92
+ executeAction(actionSequence: ActionSequence, taskId?: string, timeeout?: number): Promise<any>;
94
93
  /**
95
94
  * Execute promptflow actions
96
95
  */
@@ -130,7 +129,7 @@ export declare class ConnectionTaskClient {
130
129
  * @param taskType 任务类型
131
130
  * @returns Promise<{taskId: string, promise: Promise<any>}>
132
131
  */
133
- sendMessageWithTaskId(message: WsClient, taskType?: string, definedTaskId?: string): Promise<{
132
+ sendMessageWithTaskId(message: WsClient, taskType: string, definedTaskId?: string, timeout?: number): Promise<{
134
133
  taskId: string;
135
134
  promise: Promise<any>;
136
135
  }>;
@@ -168,7 +167,6 @@ export declare class ConnectionTaskClient {
168
167
  */
169
168
  getTaskInfo(taskId: string): {
170
169
  type: string;
171
- commandType?: string;
172
170
  } | null;
173
171
  /**
174
172
  * 批量完成指定类型的任务
package/dist/index.js CHANGED
@@ -81,6 +81,9 @@ function getWebSocket() {
81
81
  }
82
82
  });
83
83
  }
84
+ function isPendingTask(taskType) {
85
+ return taskType && taskType !== "command";
86
+ }
84
87
  /**
85
88
  * Enhanced WebSocket Task Client with protocol-aware task methods
86
89
  */
@@ -373,12 +376,16 @@ class ConnectionTaskClient {
373
376
  }
374
377
  break;
375
378
  case 'action':
376
- /*
377
379
  if (jsonData.action_event) {
378
- responseData = jsonData.action_event;
379
- shouldResolve = true;
380
- }*/
381
- // 命令,按键,滑动,点击,等待,查找,等待,屏幕截图,屏幕信息,屏幕变化,应用列表, 需要自己处理
380
+ responseData = jsonData.action_event;
381
+ shouldResolve = true;
382
+ }
383
+ break;
384
+ case 'actions':
385
+ if (jsonData.actions) {
386
+ responseData = jsonData.actions;
387
+ shouldResolve = true;
388
+ }
382
389
  break;
383
390
  }
384
391
  if (shouldResolve) {
@@ -394,21 +401,20 @@ class ConnectionTaskClient {
394
401
  }
395
402
  }
396
403
  }
397
- sendMessage(message, taskType, commandType) {
404
+ sendMessage(message, taskType, timeout) {
398
405
  return __awaiter(this, void 0, void 0, function* () {
399
406
  return new Promise((resolve, reject) => {
400
407
  const taskId = (0, uuid_1.v4)();
401
408
  if (taskType) {
402
409
  const timer = setTimeout(() => {
403
410
  this.pendingTasks.delete(taskId);
404
- reject(new Error(`Task ${taskType} timeout (${this.config.timeout}ms)`));
405
- }, this.config.timeout);
411
+ reject(new Error(`Task ${taskType} timeout (${timeout ? timeout : this.config.timeout}ms)`));
412
+ }, timeout ? timeout : this.config.timeout);
406
413
  this.pendingTasks.set(taskId, {
407
414
  resolve,
408
415
  reject,
409
416
  timer,
410
- type: taskType,
411
- commandType,
417
+ type: taskType
412
418
  });
413
419
  console.log(`📋 [ShellX] 创建任务: ${taskId}, 类型: ${taskType}}`);
414
420
  }
@@ -510,9 +516,9 @@ class ConnectionTaskClient {
510
516
  /**
511
517
  * Execute an action sequence
512
518
  */
513
- executeAction(actionSequence, taskId) {
519
+ executeAction(actionSequence, taskId, timeeout) {
514
520
  return __awaiter(this, void 0, void 0, function* () {
515
- return this.sendMessageWithTaskId({ actions: actionSequence }, 'action', taskId);
521
+ return this.sendMessageWithTaskId({ actions: actionSequence }, 'action', taskId, timeeout);
516
522
  });
517
523
  }
518
524
  /**
@@ -579,19 +585,19 @@ class ConnectionTaskClient {
579
585
  * @param taskType 任务类型
580
586
  * @returns Promise<{taskId: string, promise: Promise<any>}>
581
587
  */
582
- sendMessageWithTaskId(message, taskType, definedTaskId) {
588
+ sendMessageWithTaskId(message, taskType, definedTaskId, timeout) {
583
589
  return new Promise((resolve) => {
584
590
  let taskId = definedTaskId;
585
591
  if (taskId == null) {
586
592
  taskId = (0, uuid_1.v4)();
587
593
  }
588
- if (taskType) {
594
+ if (isPendingTask(taskType)) {
589
595
  const timer = setTimeout(() => {
590
596
  if (taskId != null) {
591
597
  this.pendingTasks.delete(taskId);
592
598
  }
593
599
  console.log(`⏰ [ShellX] 任务超时: ${taskId}, 类型: ${taskType}`);
594
- }, this.config.timeout);
600
+ }, timeout ? timeout : this.config.timeout);
595
601
  this.pendingTasks.set(taskId, {
596
602
  resolve: () => { },
597
603
  reject: () => { },
@@ -605,7 +611,7 @@ class ConnectionTaskClient {
605
611
  console.log(Date.now() + ' 📤 [ShellX] 发送消息:', JSON.stringify(message));
606
612
  this.ws.send((0, cbor_1.encode)(message));
607
613
  const promise = new Promise((promiseResolve, promiseReject) => {
608
- if (taskType) {
614
+ if (isPendingTask(taskType)) {
609
615
  if (taskId != null) {
610
616
  const task = this.pendingTasks.get(taskId);
611
617
  if (task) {
@@ -621,7 +627,7 @@ class ConnectionTaskClient {
621
627
  resolve({ taskId, promise });
622
628
  }
623
629
  catch (error) {
624
- if (taskType) {
630
+ if (isPendingTask(taskType)) {
625
631
  this.pendingTasks.delete(taskId);
626
632
  }
627
633
  resolve({ taskId, promise: Promise.reject(error) });
@@ -760,8 +766,7 @@ class ConnectionTaskClient {
760
766
  return null;
761
767
  }
762
768
  return {
763
- type: task.type,
764
- commandType: task.commandType,
769
+ type: task.type
765
770
  };
766
771
  }
767
772
  /**
package/dist/shellx.d.ts CHANGED
@@ -40,10 +40,6 @@ export declare class ShellX {
40
40
  * 处理 shell 输出数据
41
41
  */
42
42
  handleShellOutput(chunks: [any, number, Uint8Array[]]): void;
43
- /**
44
- * 判断输出是否属于特定命令
45
- */
46
- private isOutputForCommand;
47
43
  /**
48
44
  * 清理命令输出,去除输入的命令内容
49
45
  */
@@ -52,30 +48,6 @@ export declare class ShellX {
52
48
  * 合并多个 session 的输出
53
49
  */
54
50
  private combineSessionOutputs;
55
- /**
56
- * 转义正则表达式特殊字符
57
- */
58
- private escapeRegExp;
59
- /**
60
- * 检查命令是否完成
61
- */
62
- private checkCommandCompletion;
63
- /**
64
- * 检查输出是否包含错误指示器
65
- */
66
- private hasErrorIndicators;
67
- /**
68
- * 判断命令是否完成(基于时间)
69
- */
70
- private isCommandComplete;
71
- /**
72
- * 解析命令 Promise
73
- */
74
- private resolveCommand;
75
- /**
76
- * 生成命令唯一标识
77
- */
78
- private generateCommandKey;
79
51
  /**
80
52
  * 通用重试机制
81
53
  */
package/dist/shellx.js CHANGED
@@ -16,11 +16,8 @@ exports.ShellX = void 0;
16
16
  exports.createShellX = createShellX;
17
17
  exports.createShellXWithShellMonitoring = createShellXWithShellMonitoring;
18
18
  const uuid_1 = require("uuid");
19
- const utils_1 = require("./utils");
20
19
  // 导入 WebSocketTaskClient 类
21
20
  const index_1 = __importDefault(require("./index"));
22
- // 安全地获取环境变量,兼容浏览器和Node.js环境
23
- let authKey = (0, utils_1.getEnvVar)('SHELLX_AUTH_KEY');
24
21
  const COMMAND_PTY_SID = 999;
25
22
  /**
26
23
  * ShellX automation utilities for common patterns
@@ -63,27 +60,24 @@ class ShellX {
63
60
  for (const data of dataArrays) {
64
61
  output += new TextDecoder().decode(data);
65
62
  }
66
- console.log(`📟 [Shell] 收到输出 (Session ${sessionId}): ${output.trim()}`);
63
+ /*console.log(
64
+ `📟 [Shell] 收到输出 (Session ${sessionId}): ${output.trim()}`,
65
+ );*/
67
66
  // 为每个等待的命令累积输出
68
- for (const [commandKey, commandPromise] of this.shellCommandPromises.entries()) {
69
- // 检查是否该命令相关的输出
70
- if (this.isOutputForCommand(output, commandPromise.command, sessionId)) {
71
- // 存储该 session 的输出
72
- if (!commandPromise.sessionOutputs.has(sessionId)) {
73
- commandPromise.sessionOutputs.set(sessionId, '');
74
- }
75
- const currentSessionOutput = commandPromise.sessionOutputs.get(sessionId) || '';
76
- commandPromise.sessionOutputs.set(sessionId, currentSessionOutput + output);
77
- // 更新总输出
78
- commandPromise.output = this.combineSessionOutputs(commandPromise.sessionOutputs);
79
- console.log(`📊 [Shell] 命令 ${commandKey} 累积输出长度: ${commandPromise.output.length}`);
80
- // 调用输出回调(传递清理后的输出)
81
- if (commandPromise.options.onOutput) {
82
- const cleanOutput = this.cleanCommandOutput(output, commandPromise.command);
83
- commandPromise.options.onOutput(cleanOutput);
84
- }
85
- // 检查是否满足完成条件
86
- this.checkCommandCompletion(commandKey, commandPromise, output);
67
+ for (const [commandKey, commandPromise,] of this.shellCommandPromises.entries()) {
68
+ if (!commandPromise.sessionOutputs.has(sessionId)) {
69
+ commandPromise.sessionOutputs.set(sessionId, '');
70
+ }
71
+ const currentSessionOutput = commandPromise.sessionOutputs.get(sessionId) || '';
72
+ commandPromise.sessionOutputs.set(sessionId, currentSessionOutput + output);
73
+ commandPromise.output = this.combineSessionOutputs(commandPromise.sessionOutputs);
74
+ /*console.log(
75
+ `📊 [Shell] 命令 ${commandKey} 累积输出长度: ${commandPromise.output.length}`,
76
+ );*/
77
+ // 调用输出回调(传递清理后的输出)
78
+ if (commandPromise.options.onOutput) {
79
+ const cleanOutput = this.cleanCommandOutput(output, commandPromise.command);
80
+ commandPromise.options.onOutput(cleanOutput);
87
81
  }
88
82
  }
89
83
  }
@@ -92,56 +86,11 @@ class ShellX {
92
86
  }
93
87
  }
94
88
  }
95
- /**
96
- * 判断输出是否属于特定命令
97
- */
98
- isOutputForCommand(output, command, sessionId) {
99
- // 如果输出包含命令本身,说明是命令回显
100
- if (output.includes(command)) {
101
- return true;
102
- }
103
- // 如果有多个命令在等待,按时间顺序分配
104
- const waitingCommands = Array.from(this.shellCommandPromises.keys());
105
- if (waitingCommands.length === 1) {
106
- return true; // 只有一个命令在等待,所有输出都属于它
107
- }
108
- // 多个命令时,根据 sessionId 和命令创建时间进行启发式匹配
109
- return true; // 暂时返回 true,让所有命令都接收输出
110
- }
111
89
  /**
112
90
  * 清理命令输出,去除输入的命令内容
113
91
  */
114
92
  cleanCommandOutput(output, command) {
115
- if (!output || !command) {
116
- return output;
117
- }
118
- let cleanOutput = output;
119
- // 去除命令回显(命令本身)
120
- cleanOutput = cleanOutput.replace(new RegExp(this.escapeRegExp(command), 'g'), '');
121
- // 去除可能的命令提示符前缀和后缀
122
- const promptPatterns = [
123
- /^\s*[^$#>\s]*[#$>]\s*/, // 匹配提示符前缀
124
- /^\s*[^$#>\s]*@[^$#>\s]*[#$>]\s*/, // 匹配 user@host 格式
125
- /^\s*[^$#>\s]*:\s*[^$#>\s]*[#$>]\s*/, // 匹配 path: 格式
126
- /\s*[^$#>\s]*[#$>]\s*$/, // 匹配提示符后缀
127
- /\s*[^$#>\s]*@[^$#>\s]*[#$>]\s*$/, // 匹配 user@host 后缀
128
- /\s*[^$#>\s]*:\s*[^$#>\s]*[#$>]\s*$/, // 匹配 path: 后缀
129
- /\s*\d+\|[^$#>\s]*[#$>]\s*$/, // 匹配 Android 格式后缀
130
- ];
131
- for (const pattern of promptPatterns) {
132
- cleanOutput = cleanOutput.replace(pattern, '');
133
- }
134
- // 去除多余的空行和空格
135
- cleanOutput = cleanOutput.replace(/^\s+|\s+$/g, ''); // 去除首尾空白
136
- cleanOutput = cleanOutput.replace(/\n\s*\n/g, '\n'); // 去除多余空行
137
- // 如果清理后为空,返回空字符串
138
- if (cleanOutput.trim().length === 0) {
139
- return '';
140
- }
141
- console.log(`🧹 [Shell] 清理命令输出:`);
142
- console.log(` 原始: "${output.trim()}"`);
143
- console.log(` 清理后: "${cleanOutput.trim()}"`);
144
- return cleanOutput;
93
+ return output.replace(command, '');
145
94
  }
146
95
  /**
147
96
  * 合并多个 session 的输出
@@ -155,74 +104,6 @@ class ShellX {
155
104
  }
156
105
  return combined;
157
106
  }
158
- /**
159
- * 转义正则表达式特殊字符
160
- */
161
- escapeRegExp(string) {
162
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
163
- }
164
- /**
165
- * 检查命令是否完成
166
- */
167
- checkCommandCompletion(commandKey, commandPromise, newOutput) {
168
- const { resolve, startTime, options, output, command } = commandPromise;
169
- console.log(`🔍 [Shell] 检查命令 "${command}" 完成条件,当前输出长度: ${output.length}`);
170
- if (this.isCommandComplete(output, command)) {
171
- console.log(`✅ [Shell] 命令 "${command}" 执行完成 (检测到提示符)`);
172
- this.resolveCommand(commandKey, {
173
- success: true,
174
- output: output.trim(),
175
- duration: Date.now() - startTime
176
- });
177
- return;
178
- }
179
- console.log(`⏳ [Shell] 命令 "${command}" 继续等待完成...`);
180
- }
181
- /**
182
- * 检查输出是否包含错误指示器
183
- */
184
- hasErrorIndicators(output) {
185
- const errorPatterns = [
186
- /error/i,
187
- /failed/i,
188
- /not found/i,
189
- /permission denied/i,
190
- /command not found/i,
191
- /no such file/i,
192
- /syntax error/i
193
- ];
194
- return errorPatterns.some(pattern => pattern.test(output));
195
- }
196
- /**
197
- * 判断命令是否完成(基于时间)
198
- */
199
- isCommandComplete(output, command) {
200
- // 简化逻辑:只基于时间判断,不依赖提示符检测
201
- // 命令完成由超时机制控制
202
- return false; // 让超时机制处理命令完成
203
- }
204
- /**
205
- * 解析命令 Promise
206
- */
207
- resolveCommand(commandKey, result) {
208
- const commandPromise = this.shellCommandPromises.get(commandKey);
209
- if (commandPromise) {
210
- console.log(`✅ [Shell] 解析命令 Promise: ${commandKey}`);
211
- // 清理最终输出结果
212
- const cleanResult = Object.assign(Object.assign({}, result), { output: this.cleanCommandOutput(result.output, commandPromise.command) });
213
- commandPromise.resolve(cleanResult);
214
- this.shellCommandPromises.delete(commandKey);
215
- }
216
- else {
217
- console.log(`⚠️ [Shell] 未找到命令 Promise: ${commandKey}`);
218
- }
219
- }
220
- /**
221
- * 生成命令唯一标识
222
- */
223
- generateCommandKey(command) {
224
- return `cmd_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
225
- }
226
107
  /**
227
108
  * 通用重试机制
228
109
  */
@@ -1005,27 +886,17 @@ class ShellX {
1005
886
  // 设置超时
1006
887
  const timeoutId = setTimeout(() => {
1007
888
  if (this.shellCommandPromises.has(commandKey)) {
889
+ console.log(`✅ [Shell] 命令 ${command} 执行完成`);
1008
890
  const commandPromise = this.shellCommandPromises.get(commandKey);
1009
891
  this.shellCommandPromises.delete(commandKey);
1010
- if (commandPromise && commandPromise.output.trim().length > 0) {
1011
- resolve({
1012
- success: true,
1013
- output: commandPromise.output.trim(),
1014
- duration: Date.now() - startTime
1015
- });
1016
- }
1017
- else {
1018
- resolve({
1019
- success: true,
1020
- output: "",
1021
- error: `Command timeout after ${timeout}ms, but got partial output`,
1022
- duration: Date.now() - startTime
1023
- });
1024
- }
892
+ resolve({
893
+ success: true,
894
+ output: commandPromise ? commandPromise.output.trim() : "",
895
+ duration: Date.now() - startTime
896
+ });
1025
897
  }
1026
898
  }, timeout);
1027
899
  try {
1028
- // 构建 shell 命令操作
1029
900
  const shellAction = {
1030
901
  title,
1031
902
  actions: [{
@@ -1038,7 +909,7 @@ class ShellX {
1038
909
  }
1039
910
  };
1040
911
  // 发送命令
1041
- yield this.client.executeAction(shellAction, commandKey);
912
+ yield this.client.sendMessageWithTaskId({ actions: shellAction }, 'command', commandKey, timeout);
1042
913
  console.log(`📤 [Shell] 命令已发送: ${commandKey}`);
1043
914
  }
1044
915
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shellx-ai",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "shellx is a powerful WebSocket-based client for controlling shell commands and UI automation on remote devices.",
5
5
  "repository": {
6
6
  "url": "git+https://github.com/10cl/shellx.git",