ai-helper-agent 1.9.1 → 1.9.2
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/package.json +3 -3
- package/src/executor.js +54 -8
- package/src/server.js +5 -1
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-helper-agent",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "AI Helper 代理服务 - 为 Chrome 扩展提供本地文件读写和系统命令执行能力",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"ai-helper-agent": "
|
|
9
|
-
"aha": "
|
|
8
|
+
"ai-helper-agent": "bin/agent.js",
|
|
9
|
+
"aha": "bin/agent.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"bin/",
|
package/src/executor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// agent/src/executor.js - 命令执行器(child_process + 流式输出)
|
|
2
|
-
import { spawn } from 'child_process';
|
|
2
|
+
import { spawn, exec } from 'child_process';
|
|
3
3
|
import crypto from 'crypto';
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import { loadConfig } from './config.js';
|
|
@@ -252,7 +252,33 @@ function addWsClient(execId, wsClient) {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
|
-
*
|
|
255
|
+
* 断开 WebSocket 客户端连接
|
|
256
|
+
* 当所有客户端都断开后,取消超时定时器,让进程自由运行(不再自动杀)
|
|
257
|
+
*/
|
|
258
|
+
function disconnectWsClient(execId, wsClient) {
|
|
259
|
+
const entry = runningProcesses.get(execId);
|
|
260
|
+
if (!entry) return false;
|
|
261
|
+
|
|
262
|
+
entry.wsClients.delete(wsClient);
|
|
263
|
+
|
|
264
|
+
// 所有客户端都断开了 → 取消超时,进程继续运行
|
|
265
|
+
if (entry.wsClients.size === 0) {
|
|
266
|
+
if (entry.timeoutId) {
|
|
267
|
+
clearTimeout(entry.timeoutId);
|
|
268
|
+
entry.timeoutId = null;
|
|
269
|
+
}
|
|
270
|
+
if (entry.forceKillId) {
|
|
271
|
+
clearTimeout(entry.forceKillId);
|
|
272
|
+
entry.forceKillId = null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* 停止正在运行的命令(跨平台兼容)
|
|
280
|
+
* - macOS/Linux: SIGTERM(优雅终止)→ 5s → SIGKILL(强制杀)
|
|
281
|
+
* - Windows: taskkill /PID(优雅终止)→ 5s → taskkill /F /PID(强制杀)
|
|
256
282
|
*/
|
|
257
283
|
function killProcess(execId) {
|
|
258
284
|
const entry = runningProcesses.get(execId);
|
|
@@ -260,11 +286,25 @@ function killProcess(execId) {
|
|
|
260
286
|
|
|
261
287
|
if (entry.process.exitCode !== null) return false; // 已退出
|
|
262
288
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
289
|
+
const isWin = os.platform() === 'win32';
|
|
290
|
+
const pid = entry.process.pid;
|
|
291
|
+
|
|
292
|
+
if (isWin) {
|
|
293
|
+
// Windows: taskkill 支持优雅终止(/PID 发送 WM_CLOSE)和强制终止(/F)
|
|
294
|
+
exec(`taskkill /PID ${pid}`, (err) => {
|
|
295
|
+
if (err) {
|
|
296
|
+
// 尝试强制杀
|
|
297
|
+
exec(`taskkill /F /PID ${pid}`, () => {});
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
} else {
|
|
301
|
+
// macOS/Linux: SIGTERM 优雅终止
|
|
302
|
+
try {
|
|
303
|
+
entry.process.kill('SIGTERM');
|
|
304
|
+
} catch {}
|
|
305
|
+
}
|
|
266
306
|
|
|
267
|
-
//
|
|
307
|
+
// 清理旧的定时器
|
|
268
308
|
if (entry.timeoutId) {
|
|
269
309
|
clearTimeout(entry.timeoutId);
|
|
270
310
|
entry.timeoutId = null;
|
|
@@ -272,10 +312,16 @@ function killProcess(execId) {
|
|
|
272
312
|
if (entry.forceKillId) {
|
|
273
313
|
clearTimeout(entry.forceKillId);
|
|
274
314
|
}
|
|
315
|
+
|
|
316
|
+
// 5秒后强制杀(绑定到 entry 对象防止闭包引用旧变量)
|
|
275
317
|
entry.forceKillId = setTimeout(() => {
|
|
276
318
|
try {
|
|
277
319
|
if (entry.process.exitCode === null) {
|
|
278
|
-
|
|
320
|
+
if (isWin) {
|
|
321
|
+
exec(`taskkill /F /PID ${pid}`, () => {});
|
|
322
|
+
} else {
|
|
323
|
+
entry.process.kill('SIGKILL');
|
|
324
|
+
}
|
|
279
325
|
}
|
|
280
326
|
} catch {}
|
|
281
327
|
entry.forceKillId = null;
|
|
@@ -295,4 +341,4 @@ function getRunningProcesses() {
|
|
|
295
341
|
return list;
|
|
296
342
|
}
|
|
297
343
|
|
|
298
|
-
export { executeCommand, executeCommandSync, addWsClient, killProcess, getRunningProcesses };
|
|
344
|
+
export { executeCommand, executeCommandSync, addWsClient, disconnectWsClient, killProcess, getRunningProcesses };
|
package/src/server.js
CHANGED
|
@@ -10,7 +10,7 @@ import os from 'os';
|
|
|
10
10
|
import { loadConfig } from './config.js';
|
|
11
11
|
import { verifyToken, getCurrentPairCode, startPairCodeRotation, stopPairCodeRotation, handlePairRequest } from './auth.js';
|
|
12
12
|
import { checkPath, checkCommand } from './security.js';
|
|
13
|
-
import { executeCommand, executeCommandSync, addWsClient, killProcess, getRunningProcesses } from './executor.js';
|
|
13
|
+
import { executeCommand, executeCommandSync, addWsClient, disconnectWsClient, killProcess, getRunningProcesses } from './executor.js';
|
|
14
14
|
import { setConsoleOutput, logAuth, logFs, logExec, logSecurity, logSystem, logError, queryLogs, getLogDates } from './logger.js';
|
|
15
15
|
import { initSearchTools, getSearchToolsAvailable, searchFiles, searchContent } from './search.js';
|
|
16
16
|
import {
|
|
@@ -991,6 +991,10 @@ export function startServer() {
|
|
|
991
991
|
if (!added) {
|
|
992
992
|
ws.send(JSON.stringify({ type: 'error', error: '进程不存在或已结束', execId }));
|
|
993
993
|
}
|
|
994
|
+
// 客户端断开时,从监听列表中移除;所有客户端都断开后取消超时
|
|
995
|
+
ws.on('close', () => {
|
|
996
|
+
disconnectWsClient(execId, ws);
|
|
997
|
+
});
|
|
994
998
|
});
|
|
995
999
|
} else {
|
|
996
1000
|
socket.destroy();
|