claw-subagent-service 0.0.92 → 0.0.94

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.
@@ -4,7 +4,8 @@
4
4
  # 用法: ./restart.sh [选项]
5
5
  # 支持 systemd 和 Docker(无 systemd)双模式
6
6
 
7
- set -e
7
+ # 注意:不使用 set -e,因为我们已经实现了完善的错误处理和验证逻辑
8
+ # set -e 可能导致 pgrep/pidof 找不到进程时脚本意外退出
8
9
 
9
10
  # 颜色定义
10
11
  RED='\033[0;31m'
@@ -70,7 +71,7 @@ get_openclaw_pid() {
70
71
  fi
71
72
  fi
72
73
 
73
- # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具,最可靠)
74
+ # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
74
75
  # 端口 18789 的十六进制 = 0x4965
75
76
  local hex_port="4965"
76
77
  for proc_dir in /proc/[0-9]*; do
@@ -83,6 +84,30 @@ get_openclaw_pid() {
83
84
  fi
84
85
  done
85
86
 
87
+ # 方法6: 通过进程名查找(当服务未监听预期端口时)
88
+ if command -v pgrep &>/dev/null; then
89
+ pid=$(pgrep -f "openclaw" | head -1)
90
+ if [ -n "$pid" ]; then
91
+ echo "$pid"
92
+ return
93
+ fi
94
+ fi
95
+
96
+ if command -v pidof &>/dev/null; then
97
+ pid=$(pidof openclaw | awk '{print $1}')
98
+ if [ -n "$pid" ]; then
99
+ echo "$pid"
100
+ return
101
+ fi
102
+ fi
103
+
104
+ # 最后尝试 ps
105
+ pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
106
+ if [ -n "$pid" ]; then
107
+ echo "$pid"
108
+ return
109
+ fi
110
+
86
111
  echo ""
87
112
  }
88
113
 
@@ -4,7 +4,8 @@
4
4
  # 用法: ./start.sh [选项]
5
5
  # 支持 systemd 和 Docker(无 systemd)双模式
6
6
 
7
- set -e
7
+ # 注意:不使用 set -e,因为我们已经实现了完善的错误处理和验证逻辑
8
+ # set -e 可能导致 pgrep/pidof 找不到进程时脚本意外退出
8
9
 
9
10
  # 颜色定义
10
11
  RED='\033[0;31m'
@@ -70,7 +71,7 @@ get_openclaw_pid() {
70
71
  fi
71
72
  fi
72
73
 
73
- # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具,最可靠)
74
+ # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
74
75
  # 端口 18789 的十六进制 = 0x4965
75
76
  local hex_port="4965"
76
77
  for proc_dir in /proc/[0-9]*; do
@@ -83,6 +84,30 @@ get_openclaw_pid() {
83
84
  fi
84
85
  done
85
86
 
87
+ # 方法6: 通过进程名查找(当服务未监听预期端口时)
88
+ if command -v pgrep &>/dev/null; then
89
+ pid=$(pgrep -f "openclaw" | head -1)
90
+ if [ -n "$pid" ]; then
91
+ echo "$pid"
92
+ return
93
+ fi
94
+ fi
95
+
96
+ if command -v pidof &>/dev/null; then
97
+ pid=$(pidof openclaw | awk '{print $1}')
98
+ if [ -n "$pid" ]; then
99
+ echo "$pid"
100
+ return
101
+ fi
102
+ fi
103
+
104
+ # 最后尝试 ps
105
+ pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
106
+ if [ -n "$pid" ]; then
107
+ echo "$pid"
108
+ return
109
+ fi
110
+
86
111
  echo ""
87
112
  }
88
113
 
@@ -4,7 +4,8 @@
4
4
  # 用法: ./status.sh [选项]
5
5
  # 支持 systemd 和 Docker(无 systemd)双模式
6
6
 
7
- set -e
7
+ # 注意:不使用 set -e,因为我们已经实现了完善的错误处理和验证逻辑
8
+ # set -e 可能导致 pgrep/pidof 找不到进程时脚本意外退出
8
9
 
9
10
  # 颜色定义
10
11
  RED='\033[0;31m'
@@ -84,7 +85,7 @@ get_openclaw_pid() {
84
85
  fi
85
86
  fi
86
87
 
87
- # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具,最可靠)
88
+ # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
88
89
  # 端口 18789 的十六进制 = 0x4965
89
90
  local hex_port="4965"
90
91
  for proc_dir in /proc/[0-9]*; do
@@ -97,6 +98,30 @@ get_openclaw_pid() {
97
98
  fi
98
99
  done
99
100
 
101
+ # 方法6: 通过进程名查找(当服务未监听预期端口时)
102
+ if command -v pgrep &>/dev/null; then
103
+ pid=$(pgrep -f "openclaw" | head -1)
104
+ if [ -n "$pid" ]; then
105
+ echo "$pid"
106
+ return
107
+ fi
108
+ fi
109
+
110
+ if command -v pidof &>/dev/null; then
111
+ pid=$(pidof openclaw | awk '{print $1}')
112
+ if [ -n "$pid" ]; then
113
+ echo "$pid"
114
+ return
115
+ fi
116
+ fi
117
+
118
+ # 最后尝试 ps
119
+ pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
120
+ if [ -n "$pid" ]; then
121
+ echo "$pid"
122
+ return
123
+ fi
124
+
100
125
  echo ""
101
126
  }
102
127
 
@@ -4,7 +4,8 @@
4
4
  # 用法: ./stop.sh [选项]
5
5
  # 支持 systemd 和 Docker(无 systemd)双模式
6
6
 
7
- set -e
7
+ # 注意:不使用 set -e,因为我们已经实现了完善的错误处理和验证逻辑
8
+ # set -e 可能导致 pgrep/pidof 找不到进程时脚本意外退出
8
9
 
9
10
  # 颜色定义
10
11
  RED='\033[0;31m'
@@ -103,7 +104,7 @@ get_openclaw_pid() {
103
104
  fi
104
105
  fi
105
106
 
106
- # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具,最可靠)
107
+ # 方法5: 通过 /proc/net/tcp 查找(不需要外部工具)
107
108
  # 端口 18789 的十六进制 = 0x4965
108
109
  local hex_port="4965"
109
110
  for proc_dir in /proc/[0-9]*; do
@@ -116,18 +117,54 @@ get_openclaw_pid() {
116
117
  fi
117
118
  done
118
119
 
120
+ # 方法6: 通过进程名查找(当服务未监听预期端口时)
121
+ # 使用 pgrep/pidof/ps 查找 openclaw 进程
122
+ if command -v pgrep &>/dev/null; then
123
+ pid=$(pgrep -f "openclaw" | head -1)
124
+ if [ -n "$pid" ]; then
125
+ echo "$pid"
126
+ return
127
+ fi
128
+ fi
129
+
130
+ if command -v pidof &>/dev/null; then
131
+ pid=$(pidof openclaw | awk '{print $1}')
132
+ if [ -n "$pid" ]; then
133
+ echo "$pid"
134
+ return
135
+ fi
136
+ fi
137
+
138
+ # 最后尝试 ps
139
+ pid=$(ps aux | grep -v grep | grep "openclaw" | head -1 | awk '{print $2}')
140
+ if [ -n "$pid" ]; then
141
+ echo "$pid"
142
+ return
143
+ fi
144
+
119
145
  echo ""
120
146
  }
121
147
 
122
148
  # Docker 模式:停止服务
123
149
  stop_docker() {
150
+ log_info "检查 OpenClaw 服务状态..."
151
+
152
+ # 获取所有 openclaw 进程 PID
153
+ local all_pids=""
154
+ if command -v pgrep &>/dev/null; then
155
+ all_pids=$(pgrep -f "openclaw" | tr '\n' ' ')
156
+ elif command -v pidof &>/dev/null; then
157
+ all_pids=$(pidof openclaw)
158
+ else
159
+ all_pids=$(ps aux | grep -v grep | grep "openclaw" | awk '{print $2}' | tr '\n' ' ')
160
+ fi
161
+
124
162
  local pid
125
163
  pid=$(get_openclaw_pid)
126
164
 
127
165
  # 检查服务状态
128
- log_info "检查 OpenClaw 服务状态..."
129
- if [ -z "$pid" ]; then
130
- # 即使找不到 PID,也检查端口是否还在监听
166
+ if [ -z "$pid" ] && [ -z "$all_pids" ]; then
167
+ # 没有进程,检查端口
131
168
  if check_port "$PORT"; then
132
169
  log_warn "端口 $PORT 仍在监听,但无法获取 PID,尝试备选停止方案..."
133
170
  # 尝试通过 fuser 直接通过端口杀进程
@@ -139,38 +176,43 @@ stop_docker() {
139
176
  # 尝试通过 pkill 停止 openclaw 相关进程
140
177
  if check_port "$PORT"; then
141
178
  log_info "使用 pkill 停止 openclaw 进程..."
142
- pkill -f "openclaw" &>/dev/null || true
179
+ pkill -9 -f "openclaw" &>/dev/null || true
143
180
  sleep 2
144
181
  fi
145
- # 最终验证
146
- if ! check_port "$PORT"; then
147
- log_info "OpenClaw 服务已停止(通过备选方案)。"
148
- log_info "服务已成功停止。"
149
- log_info "Success"
150
- exit 0
151
- else
152
- log_error "OpenClaw 服务停止失败!所有停止方案均无效。"
153
- exit 1
154
- fi
155
182
  fi
156
- log_warn "OpenClaw 服务未在运行。"
157
- exit 0
183
+
184
+ if ! check_port "$PORT" && [ -z "$(ps aux | grep -v grep | grep 'openclaw' | awk '{print $2}')" ]; then
185
+ log_warn "OpenClaw 服务未在运行。"
186
+ exit 0
187
+ else
188
+ log_error "OpenClaw 服务停止失败!"
189
+ exit 1
190
+ fi
158
191
  fi
159
192
 
160
- log_info "OpenClaw 服务正在运行(PID: $pid),准备停止..."
193
+ log_info "发现 OpenClaw 进程: $all_pids"
161
194
 
162
- # 停止服务:先发送 SIGTERM(优雅停止)
195
+ # 停止所有 openclaw 进程:先发送 SIGTERM(优雅停止)
163
196
  log_info "正在停止 OpenClaw 服务(发送 SIGTERM)..."
164
- kill "$pid" &>/dev/null || true
197
+ for p in $all_pids; do
198
+ kill "$p" &>/dev/null || true
199
+ done
165
200
 
166
- # 等待服务完全停止(最多 10 秒),使用端口双重验证
201
+ # 等待服务完全停止(最多 10 秒)
167
202
  local elapsed=0
168
203
  while [ $elapsed -lt 10 ]; do
169
- # 双重验证:检查 PID 和端口
170
- local current_pid
171
- current_pid=$(get_openclaw_pid)
172
- if [ -z "$current_pid" ] && ! check_port "$PORT"; then
173
- log_info "OpenClaw 服务停止成功!(PID 和端口均已关闭)"
204
+ # 检查是否还有 openclaw 进程
205
+ local remaining_pids=""
206
+ if command -v pgrep &>/dev/null; then
207
+ remaining_pids=$(pgrep -f "openclaw" | tr '\n' ' ')
208
+ elif command -v pidof &>/dev/null; then
209
+ remaining_pids=$(pidof openclaw)
210
+ else
211
+ remaining_pids=$(ps aux | grep -v grep | grep "openclaw" | awk '{print $2}' | tr '\n' ' ')
212
+ fi
213
+
214
+ if [ -z "$remaining_pids" ] && ! check_port "$PORT"; then
215
+ log_info "OpenClaw 服务停止成功!(所有进程已退出,端口已关闭)"
174
216
  log_info "服务已成功停止。"
175
217
  log_info "Success"
176
218
  exit 0
@@ -181,17 +223,24 @@ stop_docker() {
181
223
 
182
224
  # 如果还在运行,强制停止(SIGKILL)
183
225
  log_warn "服务未在 10 秒内停止,正在强制停止..."
184
- kill -9 "$pid" &>/dev/null || true
185
-
186
- # 额外:尝试 pkill 确保所有相关进程都被停止
226
+ for p in $all_pids; do
227
+ kill -9 "$p" &>/dev/null || true
228
+ done
187
229
  pkill -9 -f "openclaw" &>/dev/null || true
188
230
 
189
231
  # 等待进程消失(最多 5 秒)
190
232
  elapsed=0
191
233
  while [ $elapsed -lt 5 ]; do
192
- local current_pid
193
- current_pid=$(get_openclaw_pid)
194
- if [ -z "$current_pid" ] && ! check_port "$PORT"; then
234
+ local remaining_pids=""
235
+ if command -v pgrep &>/dev/null; then
236
+ remaining_pids=$(pgrep -f "openclaw" | tr '\n' ' ')
237
+ elif command -v pidof &>/dev/null; then
238
+ remaining_pids=$(pidof openclaw)
239
+ else
240
+ remaining_pids=$(ps aux | grep -v grep | grep "openclaw" | awk '{print $2}' | tr '\n' ' ')
241
+ fi
242
+
243
+ if [ -z "$remaining_pids" ] && ! check_port "$PORT"; then
195
244
  log_info "OpenClaw 服务已强制停止。"
196
245
  log_info "服务已成功停止。"
197
246
  log_info "Success"
@@ -202,21 +251,26 @@ stop_docker() {
202
251
  done
203
252
 
204
253
  # 最终验证
205
- local current_pid
206
- current_pid=$(get_openclaw_pid)
207
- if [ -z "$current_pid" ] && ! check_port "$PORT"; then
254
+ local remaining_pids=""
255
+ if command -v pgrep &>/dev/null; then
256
+ remaining_pids=$(pgrep -f "openclaw" | tr '\n' ' ')
257
+ elif command -v pidof &>/dev/null; then
258
+ remaining_pids=$(pidof openclaw)
259
+ else
260
+ remaining_pids=$(ps aux | grep -v grep | grep "openclaw" | awk '{print $2}' | tr '\n' ' ')
261
+ fi
262
+
263
+ if [ -z "$remaining_pids" ] && ! check_port "$PORT"; then
208
264
  log_info "OpenClaw 服务已停止。"
209
265
  log_info "服务已成功停止。"
210
266
  log_info "Success"
211
267
  exit 0
212
- elif check_port "$PORT"; then
213
- log_error "OpenClaw 服务停止失败!端口 $PORT 仍在监听。"
268
+ elif [ -n "$remaining_pids" ]; then
269
+ log_error "OpenClaw 服务停止失败!进程仍然存在: $remaining_pids"
214
270
  exit 1
215
271
  else
216
- log_info "OpenClaw 服务已停止(端口已关闭)。"
217
- log_info "服务已成功停止。"
218
- log_info "Success"
219
- exit 0
272
+ log_error "OpenClaw 服务停止失败!端口 $PORT 仍在监听。"
273
+ exit 1
220
274
  fi
221
275
  }
222
276
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.92",
3
+ "version": "0.0.94",
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}`);
@@ -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();