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.
@@ -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
 
@@ -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
 
@@ -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
 
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.91",
3
+ "version": "0.0.93",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -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
- return (names[command] || 'unknown') + ext;
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} 检测为运行中(net.Socket)`);
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
- const svcMgr = new ServiceManager('claw-subagent-service', 'OpenClaw Guard CLI Client', process.argv[1], this.log);
276
- await svcMgr.stop();
277
- await svcMgr.uninstall();
276
+ // 先发送响应,再停止服务
278
277
  result = { status: 'success', message: '设备服务已禁用' };
279
- break;
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
- const svcMgr = new ServiceManager('claw-subagent-service', 'OpenClaw Guard CLI Client', process.argv[1], this.log);
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
- break;
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=端口监听正常, 2=进程存在但端口未监听, 0=未运行
331
- let statusMessage;
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=运行中, 2=进程存在但端口未监听, 0=未运行
348
+ open_claw_status: openClawStatus, // 1=运行中, 0=未运行
342
349
  status_message: statusMessage,
343
350
  mac_address: getMacAddress(),
344
351
  version: '0.0.20',