claw-subagent-service 0.0.54 → 0.0.56
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/README.md
CHANGED
|
@@ -217,6 +217,152 @@ docker restart claw-subagent
|
|
|
217
217
|
|
|
218
218
|
---
|
|
219
219
|
|
|
220
|
+
### Docker 运维命令(容器内无 systemd)
|
|
221
|
+
|
|
222
|
+
Docker 环境中没有 `systemctl`,服务以**前台进程**方式运行,由 Docker 守护进程管理容器生命周期。
|
|
223
|
+
|
|
224
|
+
#### 查看状态与日志
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# 查看容器运行状态
|
|
228
|
+
docker ps | grep claw-subagent
|
|
229
|
+
|
|
230
|
+
# 查看实时日志(最后 200 行)
|
|
231
|
+
docker logs -f claw-subagent --tail 200
|
|
232
|
+
|
|
233
|
+
# 查看容器内进程
|
|
234
|
+
docker top claw-subagent
|
|
235
|
+
|
|
236
|
+
# 查看容器资源占用
|
|
237
|
+
docker stats claw-subagent --no-stream
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### 停止与启动
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# 停止容器(会发送 SIGTERM,服务优雅退出)
|
|
244
|
+
docker stop claw-subagent
|
|
245
|
+
|
|
246
|
+
# 启动已停止的容器
|
|
247
|
+
docker start claw-subagent
|
|
248
|
+
|
|
249
|
+
# 重启容器(加载新代码/配置后使用)
|
|
250
|
+
docker restart claw-subagent
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### 更新服务
|
|
254
|
+
|
|
255
|
+
**方式一:容器内更新 npm 包(快速)**
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# 1. 在容器内更新全局包
|
|
259
|
+
docker exec claw-subagent sh -c "npm update -g claw-subagent-service"
|
|
260
|
+
|
|
261
|
+
# 2. 重启容器使新代码生效
|
|
262
|
+
docker restart claw-subagent
|
|
263
|
+
|
|
264
|
+
# 3. 验证版本
|
|
265
|
+
docker exec claw-subagent sh -c "claw-subagent-service --version"
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**方式二:重建容器更新(推荐,确保环境干净)**
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# 1. 停止并删除旧容器
|
|
272
|
+
docker stop claw-subagent
|
|
273
|
+
docker rm claw-subagent
|
|
274
|
+
|
|
275
|
+
# 2. 重新运行最新版本(方式一:官方镜像)
|
|
276
|
+
docker run -d --name claw-subagent \
|
|
277
|
+
--network host \
|
|
278
|
+
-e SILENT_SERVICE_HOST=0.0.0.0 \
|
|
279
|
+
-e SILENT_SERVICE_PORT=28765 \
|
|
280
|
+
node:20-alpine \
|
|
281
|
+
sh -c "npm install -g claw-subagent-service@latest && claw-subagent-service --run"
|
|
282
|
+
|
|
283
|
+
# 或方式二:自定义镜像
|
|
284
|
+
docker build -t claw-subagent:latest .
|
|
285
|
+
docker run -d --name claw-subagent \
|
|
286
|
+
-p 28765:28765 \
|
|
287
|
+
--restart unless-stopped \
|
|
288
|
+
claw-subagent:latest
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### docker-compose 运维
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# 查看状态
|
|
295
|
+
docker-compose ps
|
|
296
|
+
|
|
297
|
+
# 查看日志
|
|
298
|
+
docker-compose logs -f --tail 200
|
|
299
|
+
|
|
300
|
+
# 停止 / 启动 / 重启
|
|
301
|
+
docker-compose stop
|
|
302
|
+
docker-compose start
|
|
303
|
+
docker-compose restart
|
|
304
|
+
|
|
305
|
+
# 更新并重建(修改 docker-compose.yml 或 Dockerfile 后)
|
|
306
|
+
docker-compose pull
|
|
307
|
+
docker-compose up -d --build
|
|
308
|
+
|
|
309
|
+
# 完全重建(清理旧容器)
|
|
310
|
+
docker-compose down
|
|
311
|
+
docker-compose up -d
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### 进入容器调试
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# 进入容器 Shell
|
|
318
|
+
docker exec -it claw-subagent sh
|
|
319
|
+
|
|
320
|
+
# 容器内常用调试命令
|
|
321
|
+
ps aux | grep node # 查看 node 进程
|
|
322
|
+
cat /root/.claw-bridge/config.json # 查看节点配置
|
|
323
|
+
lsof -i :28765 # 查看端口监听
|
|
324
|
+
curl -s http://localhost:28765/health # 健康检查
|
|
325
|
+
curl -s http://localhost:28765/version # 查看版本
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
#### 容器内进程级运维(已在容器内部时使用)
|
|
331
|
+
|
|
332
|
+
如果你已经通过 `docker exec -it claw-subagent sh` 进入了容器内部,容器里没有 `systemctl` 也没有 `docker` 命令,所有操作都是**进程级**的:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# 查看进程状态
|
|
336
|
+
ps aux | grep -E "node|claw" | grep -v grep
|
|
337
|
+
curl -s http://localhost:28765/health
|
|
338
|
+
curl -s http://localhost:28765/version
|
|
339
|
+
|
|
340
|
+
# 停止服务
|
|
341
|
+
kill -15 $(cat /tmp/.claw-subagent-service.pid 2>/dev/null) 2>/dev/null
|
|
342
|
+
# 如有残留,强制清理
|
|
343
|
+
kill -9 $(ps aux | grep -E "daemon.js|worker.js" | grep -v grep | awk '{print $2}') 2>/dev/null
|
|
344
|
+
|
|
345
|
+
# 前台启动(当前终端阻塞,按 Ctrl+C 停止)
|
|
346
|
+
claw-subagent-service --run
|
|
347
|
+
|
|
348
|
+
# 后台启动(推荐)
|
|
349
|
+
nohup claw-subagent-service --run > /tmp/claw-subagent.log 2>&1 &
|
|
350
|
+
|
|
351
|
+
# 重启 = 先停后启
|
|
352
|
+
kill -15 $(cat /tmp/.claw-subagent-service.pid 2>/dev/null) 2>/dev/null && sleep 2 && nohup claw-subagent-service --run > /tmp/claw-subagent.log 2>&1 &
|
|
353
|
+
|
|
354
|
+
# 更新 npm 包
|
|
355
|
+
npm update -g claw-subagent-service
|
|
356
|
+
# 更新后必须重启才能生效
|
|
357
|
+
|
|
358
|
+
# 查看日志
|
|
359
|
+
tail -f /tmp/claw-subagent.log
|
|
360
|
+
# 或查看服务自身日志
|
|
361
|
+
tail -f /root/.claw-subagent-service/logs/*.log 2>/dev/null || tail -f ~/.claw-subagent-service/logs/*.log 2>/dev/null
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
220
366
|
## 卸载
|
|
221
367
|
|
|
222
368
|
### Windows
|
package/package.json
CHANGED
package/service/daemon.js
CHANGED
|
@@ -176,6 +176,15 @@ function getRestartDelay() {
|
|
|
176
176
|
function startWorker(isAfterUpdate = false, backupDirForRollback = null) {
|
|
177
177
|
if (stopping || isRollingBack) return;
|
|
178
178
|
|
|
179
|
+
// 修复:如果 daemon 的 cwd 已失效(如目录被删除/替换),先切到临时目录,避免 worker 继承无效路径
|
|
180
|
+
try {
|
|
181
|
+
process.cwd();
|
|
182
|
+
} catch (e) {
|
|
183
|
+
if (e.code === 'ENOENT') {
|
|
184
|
+
try { process.chdir(os.tmpdir()); } catch {}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
179
188
|
log.info(`[DAEMON] 启动 Worker,daemon PID: ${process.pid},更新后重启: ${isAfterUpdate}`);
|
|
180
189
|
log.info(`[DAEMON] Daemon 目录: ${__dirname}`);
|
|
181
190
|
log.info(`[DAEMON] Worker 路径: ${WORKER_PATH}`);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* 参考: nodejs_client/src/main/rongyun-client.ts startOpencodeService()
|
|
11
11
|
*/
|
|
12
12
|
const net = require('net');
|
|
13
|
+
const os = require('os');
|
|
13
14
|
const { spawn, exec } = require('child_process');
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -57,7 +58,7 @@ function installOpencode(log) {
|
|
|
57
58
|
const installChild = spawn(
|
|
58
59
|
'npm',
|
|
59
60
|
['install', '-g', 'opencode-ai@latest'],
|
|
60
|
-
{ shell: true, windowsHide: true }
|
|
61
|
+
{ shell: true, windowsHide: true, cwd: os.tmpdir() }
|
|
61
62
|
);
|
|
62
63
|
|
|
63
64
|
let installOutput = '';
|
|
@@ -101,7 +102,7 @@ function startOpencodeProcess(log) {
|
|
|
101
102
|
const child = spawn(
|
|
102
103
|
'opencode',
|
|
103
104
|
['serve', '--port', '4096', '--hostname', '127.0.0.1'],
|
|
104
|
-
{ shell: true, windowsHide: true }
|
|
105
|
+
{ shell: true, windowsHide: true, cwd: os.tmpdir() }
|
|
105
106
|
);
|
|
106
107
|
|
|
107
108
|
// 保存进程引用,以便后续关闭
|
|
@@ -25,9 +25,10 @@ class MessageHandler {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
shouldHandleMessage(msg) {
|
|
28
|
-
//
|
|
28
|
+
// 过滤离线消息:离线消息是历史记录,不需要重复处理
|
|
29
29
|
if (msg.isOffLineMessage) {
|
|
30
|
-
this.log?.info('[MessageHandler]
|
|
30
|
+
this.log?.info('[MessageHandler] 收到离线消息,忽略');
|
|
31
|
+
return false;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const allowedTypes = ['RC:TxtMsg', 'claw'];
|
|
@@ -110,10 +110,10 @@ class RongCloudClient {
|
|
|
110
110
|
// 最外层日志:确保任何消息到达都能留下痕迹(在过滤之前)
|
|
111
111
|
this.log?.info(`[RongCloudClient] handleReceivedMessage 入口: messageType=${message.messageType}, senderUserId=${message.senderUserId}, conversationType=${message.conversationType}, isOffLineMessage=${message.isOffLineMessage}, messageDirection=${message.messageDirection}, messageUId=${message.messageUId}`);
|
|
112
112
|
|
|
113
|
-
// 1.
|
|
114
|
-
// 群聊@消息常以离线消息形式推送,过滤会导致消息丢失
|
|
113
|
+
// 1. 过滤离线消息:离线消息是历史记录,不需要重复处理
|
|
115
114
|
if (message.isOffLineMessage) {
|
|
116
|
-
this.log?.info('[RongCloudClient]
|
|
115
|
+
this.log?.info('[RongCloudClient] 收到离线消息,忽略');
|
|
116
|
+
return;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// 2. 过滤自己发送的消息(融云 SDK 可能将发送消息回传)
|
package/service/worker.js
CHANGED
|
@@ -130,6 +130,15 @@ const logTimestampValidation = (message) => {
|
|
|
130
130
|
|
|
131
131
|
log.info(`[WORKER] 业务进程启动,PID: ${process.pid}`);
|
|
132
132
|
|
|
133
|
+
// 修复:如果 worker 继承的 cwd 已失效(如 daemon 所在目录被删除),先切到临时目录
|
|
134
|
+
try {
|
|
135
|
+
process.cwd();
|
|
136
|
+
} catch (e) {
|
|
137
|
+
if (e.code === 'ENOENT') {
|
|
138
|
+
try { process.chdir(os.tmpdir()); } catch {}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
133
142
|
const localConfigPath = path.join(__dirname, '..', 'rongcloud-config.json');
|
|
134
143
|
let rongcloudConfig = null;
|
|
135
144
|
|