claw-subagent-service 0.0.91 → 0.0.93
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/command/linux/restart.sh +25 -1
- package/command/linux/start.sh +25 -1
- package/command/linux/status.sh +25 -1
- package/command/linux/stop.sh +26 -1
- package/package.json +1 -1
- package/service/modules/openclaw-control.js +16 -4
- package/service/modules/port-checker.js +6 -5
- package/service/modules/rongyun-message-handler.js +36 -29
package/command/linux/restart.sh
CHANGED
|
@@ -70,7 +70,7 @@ get_openclaw_pid() {
|
|
|
70
70
|
fi
|
|
71
71
|
fi
|
|
72
72
|
|
|
73
|
-
# 方法5: 通过 /proc/net/tcp
|
|
73
|
+
# 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
|
|
74
74
|
# 端口 18789 的十六进制 = 0x4965
|
|
75
75
|
local hex_port="4965"
|
|
76
76
|
for proc_dir in /proc/[0-9]*; do
|
|
@@ -83,6 +83,30 @@ get_openclaw_pid() {
|
|
|
83
83
|
fi
|
|
84
84
|
done
|
|
85
85
|
|
|
86
|
+
# 方法6: 通过进程名查找(当服务未监听预期端口时)
|
|
87
|
+
if command -v pgrep &>/dev/null; then
|
|
88
|
+
pid=$(pgrep -f "openclaw" | head -1)
|
|
89
|
+
if [ -n "$pid" ]; then
|
|
90
|
+
echo "$pid"
|
|
91
|
+
return
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
if command -v pidof &>/dev/null; then
|
|
96
|
+
pid=$(pidof openclaw | awk '{print $1}')
|
|
97
|
+
if [ -n "$pid" ]; then
|
|
98
|
+
echo "$pid"
|
|
99
|
+
return
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# 最后尝试 ps
|
|
104
|
+
pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
|
|
105
|
+
if [ -n "$pid" ]; then
|
|
106
|
+
echo "$pid"
|
|
107
|
+
return
|
|
108
|
+
fi
|
|
109
|
+
|
|
86
110
|
echo ""
|
|
87
111
|
}
|
|
88
112
|
|
package/command/linux/start.sh
CHANGED
|
@@ -70,7 +70,7 @@ get_openclaw_pid() {
|
|
|
70
70
|
fi
|
|
71
71
|
fi
|
|
72
72
|
|
|
73
|
-
# 方法5: 通过 /proc/net/tcp
|
|
73
|
+
# 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
|
|
74
74
|
# 端口 18789 的十六进制 = 0x4965
|
|
75
75
|
local hex_port="4965"
|
|
76
76
|
for proc_dir in /proc/[0-9]*; do
|
|
@@ -83,6 +83,30 @@ get_openclaw_pid() {
|
|
|
83
83
|
fi
|
|
84
84
|
done
|
|
85
85
|
|
|
86
|
+
# 方法6: 通过进程名查找(当服务未监听预期端口时)
|
|
87
|
+
if command -v pgrep &>/dev/null; then
|
|
88
|
+
pid=$(pgrep -f "openclaw" | head -1)
|
|
89
|
+
if [ -n "$pid" ]; then
|
|
90
|
+
echo "$pid"
|
|
91
|
+
return
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
if command -v pidof &>/dev/null; then
|
|
96
|
+
pid=$(pidof openclaw | awk '{print $1}')
|
|
97
|
+
if [ -n "$pid" ]; then
|
|
98
|
+
echo "$pid"
|
|
99
|
+
return
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# 最后尝试 ps
|
|
104
|
+
pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
|
|
105
|
+
if [ -n "$pid" ]; then
|
|
106
|
+
echo "$pid"
|
|
107
|
+
return
|
|
108
|
+
fi
|
|
109
|
+
|
|
86
110
|
echo ""
|
|
87
111
|
}
|
|
88
112
|
|
package/command/linux/status.sh
CHANGED
|
@@ -84,7 +84,7 @@ get_openclaw_pid() {
|
|
|
84
84
|
fi
|
|
85
85
|
fi
|
|
86
86
|
|
|
87
|
-
# 方法5: 通过 /proc/net/tcp
|
|
87
|
+
# 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
|
|
88
88
|
# 端口 18789 的十六进制 = 0x4965
|
|
89
89
|
local hex_port="4965"
|
|
90
90
|
for proc_dir in /proc/[0-9]*; do
|
|
@@ -97,6 +97,30 @@ get_openclaw_pid() {
|
|
|
97
97
|
fi
|
|
98
98
|
done
|
|
99
99
|
|
|
100
|
+
# 方法6: 通过进程名查找(当服务未监听预期端口时)
|
|
101
|
+
if command -v pgrep &>/dev/null; then
|
|
102
|
+
pid=$(pgrep -f "openclaw" | head -1)
|
|
103
|
+
if [ -n "$pid" ]; then
|
|
104
|
+
echo "$pid"
|
|
105
|
+
return
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
if command -v pidof &>/dev/null; then
|
|
110
|
+
pid=$(pidof openclaw | awk '{print $1}')
|
|
111
|
+
if [ -n "$pid" ]; then
|
|
112
|
+
echo "$pid"
|
|
113
|
+
return
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# 最后尝试 ps
|
|
118
|
+
pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
|
|
119
|
+
if [ -n "$pid" ]; then
|
|
120
|
+
echo "$pid"
|
|
121
|
+
return
|
|
122
|
+
fi
|
|
123
|
+
|
|
100
124
|
echo ""
|
|
101
125
|
}
|
|
102
126
|
|
package/command/linux/stop.sh
CHANGED
|
@@ -103,7 +103,7 @@ get_openclaw_pid() {
|
|
|
103
103
|
fi
|
|
104
104
|
fi
|
|
105
105
|
|
|
106
|
-
# 方法5: 通过 /proc/net/tcp
|
|
106
|
+
# 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
|
|
107
107
|
# 端口 18789 的十六进制 = 0x4965
|
|
108
108
|
local hex_port="4965"
|
|
109
109
|
for proc_dir in /proc/[0-9]*; do
|
|
@@ -116,6 +116,31 @@ get_openclaw_pid() {
|
|
|
116
116
|
fi
|
|
117
117
|
done
|
|
118
118
|
|
|
119
|
+
# 方法6: 通过进程名查找(当服务未监听预期端口时)
|
|
120
|
+
# 使用 pgrep/pidof/ps 查找 openclaw 进程
|
|
121
|
+
if command -v pgrep &>/dev/null; then
|
|
122
|
+
pid=$(pgrep -f "openclaw" | head -1)
|
|
123
|
+
if [ -n "$pid" ]; then
|
|
124
|
+
echo "$pid"
|
|
125
|
+
return
|
|
126
|
+
fi
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
if command -v pidof &>/dev/null; then
|
|
130
|
+
pid=$(pidof openclaw | awk '{print $1}')
|
|
131
|
+
if [ -n "$pid" ]; then
|
|
132
|
+
echo "$pid"
|
|
133
|
+
return
|
|
134
|
+
fi
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# 最后尝试 ps
|
|
138
|
+
pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
|
|
139
|
+
if [ -n "$pid" ]; then
|
|
140
|
+
echo "$pid"
|
|
141
|
+
return
|
|
142
|
+
fi
|
|
143
|
+
|
|
119
144
|
echo ""
|
|
120
145
|
}
|
|
121
146
|
|
package/package.json
CHANGED
|
@@ -38,9 +38,11 @@ function getScriptName(command) {
|
|
|
38
38
|
[OpenClawCommandEnum.START]: 'start',
|
|
39
39
|
[OpenClawCommandEnum.STOP]: 'stop',
|
|
40
40
|
[OpenClawCommandEnum.RESTART]: 'restart',
|
|
41
|
-
[OpenClawCommandEnum.STATUS]: 'status'
|
|
41
|
+
[OpenClawCommandEnum.STATUS]: 'status',
|
|
42
|
+
[OpenClawCommandEnum.CONFIG_FIX]: null // 配置修复不需要脚本
|
|
42
43
|
};
|
|
43
|
-
|
|
44
|
+
const name = names[command];
|
|
45
|
+
return name ? name + ext : null;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
function getCommandName(command) {
|
|
@@ -48,7 +50,8 @@ function getCommandName(command) {
|
|
|
48
50
|
[OpenClawCommandEnum.START]: '启动',
|
|
49
51
|
[OpenClawCommandEnum.STOP]: '停止',
|
|
50
52
|
[OpenClawCommandEnum.RESTART]: '重启',
|
|
51
|
-
[OpenClawCommandEnum.STATUS]: '状态检查'
|
|
53
|
+
[OpenClawCommandEnum.STATUS]: '状态检查',
|
|
54
|
+
[OpenClawCommandEnum.CONFIG_FIX]: '配置修复'
|
|
52
55
|
};
|
|
53
56
|
return names[command] || '未知命令';
|
|
54
57
|
}
|
|
@@ -73,6 +76,9 @@ async function manageWithServiceManager(command) {
|
|
|
73
76
|
case OpenClawCommandEnum.STATUS:
|
|
74
77
|
const status = await serviceMgr.status();
|
|
75
78
|
return { status: OpenClawServiceStatus.RUNNING, message: status };
|
|
79
|
+
case OpenClawCommandEnum.CONFIG_FIX:
|
|
80
|
+
// 配置修复不通过 ServiceManager,回退到脚本方式
|
|
81
|
+
return null;
|
|
76
82
|
default:
|
|
77
83
|
return { status: OpenClawServiceStatus.ERROR, message: '未知命令' };
|
|
78
84
|
}
|
|
@@ -124,6 +130,11 @@ async function verifyCommandResult(command, result, scriptOutput = '') {
|
|
|
124
130
|
|
|
125
131
|
const outputUpper = (scriptOutput || '').toUpperCase();
|
|
126
132
|
|
|
133
|
+
// 配置修复命令不需要端口验证
|
|
134
|
+
if (command === OpenClawCommandEnum.CONFIG_FIX) {
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
127
138
|
if (command === OpenClawCommandEnum.STOP) {
|
|
128
139
|
// 等待 3 秒后验证端口
|
|
129
140
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
@@ -219,7 +230,8 @@ async function executeCommand(command, window, sendResponse) {
|
|
|
219
230
|
// 输出日志
|
|
220
231
|
if (result.status === OpenClawServiceStatus.START_SUCCESS ||
|
|
221
232
|
result.status === OpenClawServiceStatus.STOP_SUCCESS ||
|
|
222
|
-
result.status === OpenClawServiceStatus.RESTART_SUCCESS
|
|
233
|
+
result.status === OpenClawServiceStatus.RESTART_SUCCESS ||
|
|
234
|
+
result.status === OpenClawServiceStatus.CONFIG_FIX_SUCCESS) {
|
|
223
235
|
console.log(`[OpenClawControl] ${cmdName} 成功: ${result.message}`);
|
|
224
236
|
} else if (result.status === OpenClawServiceStatus.ERROR) {
|
|
225
237
|
console.log(`[OpenClawControl] ${cmdName} 失败: ${result.message}`);
|
|
@@ -129,10 +129,13 @@ function checkProcessExists() {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
async function getOpenClawStatus(port = 18789) {
|
|
132
|
+
// 核心判断:只有端口在监听才算是真正运行
|
|
133
|
+
// openclaw gateway 的核心功能就是监听端口提供服务
|
|
134
|
+
|
|
132
135
|
// 方法1: 通过 net.Socket 检查端口
|
|
133
136
|
const isListening = await checkPortOnAllInterfaces(port);
|
|
134
137
|
if (isListening) {
|
|
135
|
-
console.log(`[PortChecker] 端口 ${port}
|
|
138
|
+
console.log(`[PortChecker] 端口 ${port} 检测为运行中`);
|
|
136
139
|
return 1;
|
|
137
140
|
}
|
|
138
141
|
|
|
@@ -143,12 +146,10 @@ async function getOpenClawStatus(port = 18789) {
|
|
|
143
146
|
return 1;
|
|
144
147
|
}
|
|
145
148
|
|
|
146
|
-
// 方法3:
|
|
149
|
+
// 方法3: 检查进程是否存在(仅用于日志,不改变判断结果)
|
|
147
150
|
const processExists = checkProcessExists();
|
|
148
151
|
if (processExists) {
|
|
149
|
-
console.warn(`[PortChecker] 警告: openclaw 进程存在,但端口 ${port}
|
|
150
|
-
// 进程存在但端口未监听,返回特殊状态 2
|
|
151
|
-
return 2;
|
|
152
|
+
console.warn(`[PortChecker] 警告: openclaw 进程存在,但端口 ${port} 未监听。服务可能未正确启动或已崩溃。`);
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
console.log(`[PortChecker] 端口 ${port} 检测为未运行`);
|
|
@@ -96,7 +96,7 @@ class RongyunMessageHandler {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
async handleCommand(data) {
|
|
99
|
-
const command = data.command;
|
|
99
|
+
const command = Number(data.command); // 确保是数字类型
|
|
100
100
|
const commandId = data.command_id;
|
|
101
101
|
const requestId = data.request_id;
|
|
102
102
|
const sourceId = data.source_im_id;
|
|
@@ -106,6 +106,7 @@ class RongyunMessageHandler {
|
|
|
106
106
|
// 验证命令是否有效
|
|
107
107
|
const validCommands = Object.values(OpenClawCommandEnum);
|
|
108
108
|
if (!validCommands.includes(command)) {
|
|
109
|
+
this.logError(`[RongyunMessageHandler] 未知命令: ${command}, 有效命令: ${validCommands.join(', ')}`);
|
|
109
110
|
await this.sendResponse(RongyunMessageTypeEnum.COMMAND_RESULT, {
|
|
110
111
|
command,
|
|
111
112
|
command_id: commandId,
|
|
@@ -272,11 +273,17 @@ class RongyunMessageHandler {
|
|
|
272
273
|
let result;
|
|
273
274
|
switch (command) {
|
|
274
275
|
case 'disable': {
|
|
275
|
-
|
|
276
|
-
await svcMgr.stop();
|
|
277
|
-
await svcMgr.uninstall();
|
|
276
|
+
// 先发送响应,再停止服务
|
|
278
277
|
result = { status: 'success', message: '设备服务已禁用' };
|
|
279
|
-
|
|
278
|
+
await this.sendDeviceControlResult(targetId, requestId, command, result.status, result.message, result.data);
|
|
279
|
+
|
|
280
|
+
setTimeout(async () => {
|
|
281
|
+
const svcMgr = new ServiceManager('claw-subagent-service', 'OpenClaw Guard CLI Client', process.argv[1], this.log);
|
|
282
|
+
try { await svcMgr.stop(); } catch (e) {}
|
|
283
|
+
try { await svcMgr.uninstall(); } catch (e) {}
|
|
284
|
+
}, 2000);
|
|
285
|
+
|
|
286
|
+
return;
|
|
280
287
|
}
|
|
281
288
|
case 'enable': {
|
|
282
289
|
const svcMgr = new ServiceManager('claw-subagent-service', 'OpenClaw Guard CLI Client', process.argv[1], this.log);
|
|
@@ -285,21 +292,28 @@ class RongyunMessageHandler {
|
|
|
285
292
|
break;
|
|
286
293
|
}
|
|
287
294
|
case 'delete': {
|
|
288
|
-
|
|
289
|
-
try { await svcMgr.stop(); } catch (e) {}
|
|
290
|
-
try { await svcMgr.uninstall(); } catch (e) {}
|
|
291
|
-
const homeDir = os.homedir();
|
|
292
|
-
const configPaths = [
|
|
293
|
-
path.join(homeDir, '.claw-bridge', 'config.json'),
|
|
294
|
-
path.join(__dirname, '..', '..', 'rongcloud-config.json')
|
|
295
|
-
];
|
|
296
|
-
for (const p of configPaths) {
|
|
297
|
-
if (fs.existsSync(p)) {
|
|
298
|
-
fs.unlinkSync(p);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
295
|
+
// 先发送响应,再停止服务(否则服务停止后无法发送响应)
|
|
301
296
|
result = { status: 'success', message: '设备已删除,本地配置已清除' };
|
|
302
|
-
|
|
297
|
+
await this.sendDeviceControlResult(targetId, requestId, command, result.status, result.message, result.data);
|
|
298
|
+
|
|
299
|
+
// 延迟执行实际的删除操作
|
|
300
|
+
setTimeout(async () => {
|
|
301
|
+
const svcMgr = new ServiceManager('claw-subagent-service', 'OpenClaw Guard CLI Client', process.argv[1], this.log);
|
|
302
|
+
try { await svcMgr.stop(); } catch (e) {}
|
|
303
|
+
try { await svcMgr.uninstall(); } catch (e) {}
|
|
304
|
+
const homeDir = os.homedir();
|
|
305
|
+
const configPaths = [
|
|
306
|
+
path.join(homeDir, '.claw-bridge', 'config.json'),
|
|
307
|
+
path.join(__dirname, '..', '..', 'rongcloud-config.json')
|
|
308
|
+
];
|
|
309
|
+
for (const p of configPaths) {
|
|
310
|
+
if (fs.existsSync(p)) {
|
|
311
|
+
fs.unlinkSync(p);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}, 2000);
|
|
315
|
+
|
|
316
|
+
return; // 已经发送了响应,直接返回
|
|
303
317
|
}
|
|
304
318
|
case 'status': {
|
|
305
319
|
const dashboard = await collectDashboardData();
|
|
@@ -327,18 +341,11 @@ class RongyunMessageHandler {
|
|
|
327
341
|
const openClawStatus = await getOpenClawStatus();
|
|
328
342
|
|
|
329
343
|
// 构建状态数据
|
|
330
|
-
// openClawStatus: 1
|
|
331
|
-
|
|
332
|
-
if (openClawStatus === 1) {
|
|
333
|
-
statusMessage = '运行中';
|
|
334
|
-
} else if (openClawStatus === 2) {
|
|
335
|
-
statusMessage = '运行中(端口异常)';
|
|
336
|
-
} else {
|
|
337
|
-
statusMessage = '未运行';
|
|
338
|
-
}
|
|
344
|
+
// openClawStatus: 1=端口监听正常(服务可用), 0=未运行(端口未监听)
|
|
345
|
+
const statusMessage = openClawStatus === 1 ? '运行中' : '未运行';
|
|
339
346
|
|
|
340
347
|
const statusData = {
|
|
341
|
-
open_claw_status: openClawStatus, // 1=运行中,
|
|
348
|
+
open_claw_status: openClawStatus, // 1=运行中, 0=未运行
|
|
342
349
|
status_message: statusMessage,
|
|
343
350
|
mac_address: getMacAddress(),
|
|
344
351
|
version: '0.0.20',
|