claw-subagent-service 0.0.56 → 0.0.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.56",
3
+ "version": "0.0.58",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -47,7 +47,7 @@ nohup openclaw gateway --port 18789 --host 0.0.0.0 --verbose > /var/log/openclaw
47
47
  - 不知道就查资料,别瞎猜
48
48
  - 看到 \`systemctl\` 相关报错,立即切换为 \`nohup\` 方案, 因为docker容器内是没有systemctl的。
49
49
  - 超过6分钟 没有修复好就停下来,报告你遇到的问题,不要无限循环的进行修复。
50
- - 不要对外透漏你是什么模型,不要说你是opencode,对外你就说你是 虾说运维大模型;
50
+ - 不要对外透漏你是什么模型,不要说你是opencode,对外你就说你是 虾说智能助手;
51
51
  `;
52
52
 
53
53
  async function createOpencodeSession(title) {
@@ -90,6 +90,11 @@ class ScriptExecutor {
90
90
  try {
91
91
  const { stdout, stderr } = await this.runScript(scriptPath);
92
92
  const fullOutput = stdout + stderr;
93
+
94
+ // 调试日志:记录脚本实际输出
95
+ console.log(`[ScriptExecutor-DEBUG] ${scriptName} 原始输出:\n${fullOutput}`);
96
+ console.log(`[ScriptExecutor-DEBUG] ${scriptName} 输出长度: ${fullOutput.length}`);
97
+
93
98
  return this.parseStatus(command, fullOutput);
94
99
  } catch (e) {
95
100
  const msg = e instanceof Error ? e.message : String(e);
@@ -113,8 +118,7 @@ class ScriptExecutor {
113
118
  cmd = 'cmd';
114
119
  args = ['/c', command];
115
120
  } else {
116
- // Alpine 等精简镜像可能缺少 bash,优先使用 sh
117
- cmd = 'sh';
121
+ cmd = 'bash';
118
122
  args = ['-c', command];
119
123
  }
120
124
 
@@ -178,6 +182,20 @@ class ScriptExecutor {
178
182
  }
179
183
 
180
184
  runScript(scriptPath) {
185
+ // Linux/Mac 系统:自动修复 shell 脚本的 CRLF 换行符
186
+ if (process.platform !== 'win32') {
187
+ try {
188
+ const fs = require('fs');
189
+ const content = fs.readFileSync(scriptPath, 'utf8');
190
+ if (content.includes('\r\n')) {
191
+ fs.writeFileSync(scriptPath, content.replace(/\r\n/g, '\n'));
192
+ console.log(`[ScriptExecutor] 已修复 ${path.basename(scriptPath)} 换行符(CRLF → LF)`);
193
+ }
194
+ } catch (e) {
195
+ // 忽略读取/写入错误,继续执行
196
+ }
197
+ }
198
+
181
199
  return new Promise((resolve, reject) => {
182
200
  const system = process.platform;
183
201
  let cmd;
@@ -187,11 +205,17 @@ class ScriptExecutor {
187
205
  cmd = 'cmd';
188
206
  args = ['/c', scriptPath];
189
207
  } else {
190
- // Alpine 等精简镜像可能缺少 bash,优先使用 sh
191
- cmd = 'sh';
208
+ cmd = 'bash';
192
209
  args = [scriptPath];
193
210
  }
194
211
 
212
+ // 调试日志:记录执行环境
213
+ if (process.platform !== 'win32') {
214
+ console.log(`[ScriptExecutor-DEBUG] 执行脚本: ${scriptPath}`);
215
+ console.log(`[ScriptExecutor-DEBUG] PATH: ${process.env.PATH}`);
216
+ console.log(`[ScriptExecutor-DEBUG] SHELL: ${process.env.SHELL}`);
217
+ }
218
+
195
219
  const child = spawn(cmd, args, {
196
220
  detached: false,
197
221
  windowsHide: true
@@ -323,6 +347,12 @@ class ScriptExecutor {
323
347
 
324
348
  parseStatus(command, output) {
325
349
  const upper = output.toUpperCase();
350
+
351
+ // 调试日志:记录解析过程
352
+ console.log(`[ScriptExecutor-DEBUG] parseStatus 命令: ${command}`);
353
+ console.log(`[ScriptExecutor-DEBUG] parseStatus 大写输出包含: ACTIVE: ACTIVE (RUNNING)? ${upper.includes('ACTIVE: ACTIVE (RUNNING)')}`);
354
+ console.log(`[ScriptExecutor-DEBUG] parseStatus 大写输出包含: SUCCESS? ${upper.includes('SUCCESS')}`);
355
+ console.log(`[ScriptExecutor-DEBUG] parseStatus 原始输出包含: :18789? ${output.includes(':18789')}`);
326
356
 
327
357
  if (
328
358
  upper.includes('OPENCLAW COMMAND NOT FOUND') ||
@@ -360,6 +390,7 @@ class ScriptExecutor {
360
390
  message: getServiceStatusMessage(OpenClawServiceStatus.NOT_RUNNING)
361
391
  };
362
392
  }
393
+ console.log(`[ScriptExecutor-DEBUG] STATUS 默认返回: NOT_RUNNING(未匹配到运行中标识)`);
363
394
  return {
364
395
  status: OpenClawServiceStatus.NOT_RUNNING,
365
396
  message: getServiceStatusMessage(OpenClawServiceStatus.NOT_RUNNING)
@@ -400,7 +431,8 @@ class ScriptExecutor {
400
431
  upper.includes('STOPPED') ||
401
432
  upper.includes('[OK] STOP COMMAND EXECUTED') ||
402
433
  upper.includes('[OK] SERVICE STOPPED') ||
403
- (output.includes('[INFO] OPENCLAW 服务停止成功') && output.includes('[INFO] 服务已成功停止')) ||
434
+ upper.includes('服务停止成功') ||
435
+ upper.includes('服务已成功停止') ||
404
436
  upper.includes('GATEWAY STOP SIGNAL SENT') ||
405
437
  (upper.includes('[INFO] STOPPING SERVICE') && upper.includes('STOP SIGNAL'))
406
438
  ) {
@@ -22,6 +22,9 @@ class RongCloudClient {
22
22
  this.processingQueue = Promise.resolve();
23
23
  this.processedMessageUIds = new Set();
24
24
  this.messageDedupMaxSize = 1000;
25
+ // 发送侧短期缓存:防止融云 SDK 回传自己发送的消息导致机器人自言自语
26
+ this.sentMessageUIds = new Set();
27
+ this.sentMessageDedupMaxSize = 100;
25
28
  }
26
29
 
27
30
  async connect(handler) {
@@ -127,6 +130,12 @@ class RongCloudClient {
127
130
  return;
128
131
  }
129
132
 
133
+ // 2.5 通过发送缓存过滤:融云 SDK 回传自己消息时,messageDirection/senderUserId 可能不一致
134
+ if (message.messageUId && this.sentMessageUIds.has(message.messageUId)) {
135
+ this.log?.info(`[RongCloudClient] 过滤自己发送的消息 (messageUId=${message.messageUId} 在发送缓存中)`);
136
+ return;
137
+ }
138
+
130
139
  // 3. 消息去重:防止同一条消息被多次触发(融云重推或多端同步)
131
140
  const dedupKey = message.messageUId || `${message.senderUserId}-${message.sentTime}-${message.messageType}`;
132
141
  if (this.processedMessageUIds.has(dedupKey)) {
@@ -227,7 +236,16 @@ class RongCloudClient {
227
236
  // this.log?.info(`[RongCloudClient] 发送结果: code=${result.code}`);
228
237
 
229
238
  if (result.code === 0 || result.code === 200) {
230
- this.log?.info(`[RongCloudClient] 发送成功, messageUId: ${result.data?.messageUId}`);
239
+ const sentUId = result.data?.messageUId;
240
+ this.log?.info(`[RongCloudClient] 发送成功, messageUId: ${sentUId}`);
241
+ // 将发送成功的 messageUId 加入短期缓存,用于过滤 SDK 回传的自己消息
242
+ if (sentUId) {
243
+ this.sentMessageUIds.add(sentUId);
244
+ if (this.sentMessageUIds.size > this.sentMessageDedupMaxSize) {
245
+ const first = this.sentMessageUIds.values().next().value;
246
+ this.sentMessageUIds.delete(first);
247
+ }
248
+ }
231
249
  return true;
232
250
  } else {
233
251
  this.log?.error(`[RongCloudClient] 发送失败, code: ${result.code}`);