claw-subagent-service 0.0.66 → 0.0.67

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/cli.js CHANGED
@@ -30,19 +30,22 @@ function runDaemon() {
30
30
  console.log(`[CLI] Daemon 路径: ${DAEMON_PATH}`);
31
31
 
32
32
  const daemon = spawn('node', [DAEMON_PATH], {
33
- stdio: 'inherit',
34
- detached: false
35
- });
36
-
37
- daemon.on('exit', (code) => {
38
- console.log(`[CLI] Daemon 退出,code=${code}`);
39
- process.exit(code);
40
- });
41
-
42
- daemon.on('error', (err) => {
43
- console.error(`[CLI] Daemon 启动失败: ${err.message}`);
44
- process.exit(1);
33
+ stdio: 'ignore',
34
+ detached: true
45
35
  });
36
+
37
+ daemon.unref();
38
+
39
+ // 不阻塞等待 Daemon 退出:
40
+ // detached: true 使 Daemon 成为独立进程组 leader,避免随 CLI 收到 SIGINT/SIGHUP;
41
+ // stdio: 'ignore' 防止 nohup 场景下 pipe 断开导致异常;
42
+ // unref() 让 CLI 事件循环不等待 Daemon,安装脚本可立即继续。
43
+ console.log(`[CLI] Daemon 已启动,PID=${daemon.pid}`);
44
+
45
+ // 短暂停留确认 Daemon 未立即崩溃,随后 CLI 退出(Daemon 继续后台运行)
46
+ setTimeout(() => {
47
+ process.exit(0);
48
+ }, 1500);
46
49
  }
47
50
 
48
51
  function installService() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.66",
3
+ "version": "0.0.67",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/service/daemon.js CHANGED
@@ -49,8 +49,13 @@ function checkSingleton() {
49
49
  log.error(`[DAEMON] 另一个 Daemon 实例已在运行 (PID: ${pid}, 权限不足),当前实例退出`);
50
50
  return false;
51
51
  }
52
- // 进程不存在,继续启动
52
+ // 进程不存在(ESRCH),清理 stale PID 文件
53
+ log.info(`[DAEMON] 发现 stale PID 文件 (PID: ${pid} 已不存在),清理中...`);
54
+ try { fs.unlinkSync(PID_FILE); } catch { /* 忽略 */ }
53
55
  }
56
+ } else {
57
+ // PID 文件内容无效,清理
58
+ try { fs.unlinkSync(PID_FILE); } catch { /* 忽略 */ }
54
59
  }
55
60
  }
56
61
  } catch {
@@ -129,7 +134,8 @@ function freePortIfNeeded(port) {
129
134
  ];
130
135
  for (const cmd of commands) {
131
136
  try {
132
- const out = execSync(cmd, { encoding: 'utf8', timeout: 5000 }).trim();
137
+ // 精简 Docker 镜像中部分命令可能极慢或不存在,缩短超时避免阻塞
138
+ const out = execSync(cmd, { encoding: 'utf8', timeout: 2000 }).trim();
133
139
  const firstLine = out.split(/\r?\n/)[0];
134
140
  const candidate = parseInt(firstLine, 10);
135
141
  if (candidate && candidate > 0 && candidate !== currentWorkerPid && candidate !== process.pid) {
@@ -148,7 +154,7 @@ function freePortIfNeeded(port) {
148
154
  // 所有端口查询命令都不可用(常见于精简 Docker 镜像)
149
155
  // 兜底:杀掉残留 Worker 进程(Daemon 自身的命令行不含 worker.js,不会自杀)
150
156
  try {
151
- execSync('pkill -9 -f "worker.js" 2>/dev/null || true', { timeout: 5000 });
157
+ execSync('pkill -9 -f "worker.js" 2>/dev/null || true', { timeout: 2000 });
152
158
  log.warn(`[DAEMON] 已尝试杀掉残留 Worker 进程`);
153
159
  } catch { /* 忽略 */ }
154
160
  }
@@ -340,8 +346,10 @@ function gracefulShutdown() {
340
346
  worker = null;
341
347
  }
342
348
 
343
- // 释放端口,确保下次启动时端口可用
344
- freePortIfNeeded(PORT);
349
+ // Worker 已被 SIGKILL,端口会立即释放,无需再执行可能阻塞的 freePortIfNeeded
350
+ // 旧代码在此处调用 freePortIfNeeded,其内部的 execSync 命令链在精简 Docker 中
351
+ // 可能阻塞 20+ 秒,导致 kill -15 后旧进程迟迟不退出,新实例 checkSingleton 失败。
352
+ cleanupPidFile();
345
353
  process.exit(0);
346
354
  }
347
355
 
@@ -411,9 +411,11 @@ class OpenClawClient {
411
411
  { role: 'user', content: message }
412
412
  ],
413
413
  stream: true,
414
- session_id: sessionId
414
+ max_tokens: 2048
415
415
  };
416
416
 
417
+ this.log?.info(`[OpenClawClient] SSE 请求 payload: ${JSON.stringify(payload)}`);
418
+
417
419
  let fullText = '';
418
420
  let buffer = '';
419
421
 
@@ -464,6 +466,10 @@ class OpenClawClient {
464
466
 
465
467
  response.data.on('end', async () => {
466
468
  this.log?.info(`[OpenClawClient] SSE 流结束,总长度: ${fullText.length}`);
469
+ if (fullText.length === 0) {
470
+ reject(new Error('OpenClaw SSE 返回空内容,可能模型未配置或 payload 格式不兼容'));
471
+ return;
472
+ }
467
473
  try {
468
474
  await onDone?.(fullText);
469
475
  resolve();