claw-subagent-service 0.0.163 → 0.0.165

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/service/worker.js +106 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.163",
3
+ "version": "0.0.165",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/service/worker.js CHANGED
@@ -289,7 +289,105 @@ async function refreshRongCloudToken() {
289
289
  log.error(`[WORKER] 刷新 token 失败: ${resp.data?.message || '未知错误'}`);
290
290
  return false;
291
291
  } catch (err) {
292
- log.error(`[WORKER] 刷新 token 异常: ${err.message}`);
292
+ log.error(`[WORKER] 刷新 token 异常: ${err.message}`);
293
+ return false;
294
+ }
295
+ }
296
+
297
+ /**
298
+ * 从后端系统配置同步客服账号ID
299
+ * 如果数据库配置的 customer_service_account_id 与当前 accountId 不一致,
300
+ * 则获取新账号的融云 token 并更新本地配置,使前端消息能正确送达
301
+ *
302
+ * 设计原理:
303
+ * - 客服账号由管理员在系统配置表(im_system_config)中管理,支持频繁更新
304
+ * - silent-service 本地 config.json 的 nodeId 由 clawmessenger 注册时决定
305
+ * - 两者可能不一致,导致前端将消息发给 ID-A,但 silent-service 在 ID-B 上监听
306
+ * - 此函数在启动时拉取数据库配置,自动对齐
307
+ *
308
+ * @returns {Promise<boolean>} 配置是否已更新
309
+ */
310
+ async function syncCustomerServiceAccountId() {
311
+ if (!rongcloudConfig?.apiBaseUrl) {
312
+ log.warn('[WORKER] 无法同步客服账号: 缺少 apiBaseUrl');
313
+ return false;
314
+ }
315
+
316
+ try {
317
+ const resp = await axios.get(
318
+ `${rongcloudConfig.apiBaseUrl}/im/api/system/config/customer_service_account_id`,
319
+ { timeout: 10000 }
320
+ );
321
+
322
+ if (resp.data?.code === 200 && resp.data?.data?.value) {
323
+ const csAccountId = resp.data.data.value;
324
+ const currentAccountId = rongcloudConfig.accountId;
325
+
326
+ if (csAccountId === currentAccountId) {
327
+ log.info(`[WORKER] 客服账号一致: ${csAccountId},无需变更`);
328
+ return false;
329
+ }
330
+
331
+ log.info(`[WORKER] 客服账号不一致: 当前=${currentAccountId}, 数据库配置=${csAccountId},正在同步...`);
332
+
333
+ // 获取新账号的融云 token(节点必须已注册)
334
+ // 用独立 try-catch 包裹,与外部"配置不存在"的区分开
335
+ try {
336
+ const serverUrl = process.env.DM_SERVER_URL || 'https://newsradar.dreamdt.cn/im';
337
+ const tokenResp = await axios.get(
338
+ `${serverUrl}/api/claw/token/${csAccountId}`,
339
+ { timeout: 15000 }
340
+ );
341
+
342
+ if (tokenResp.data?.code === 200) {
343
+ const newToken = tokenResp.data.data?.token || tokenResp.data.token || '';
344
+ if (newToken) {
345
+ log.info(`[WORKER] 获取客服账号 token 成功: ${csAccountId}`);
346
+
347
+ // 更新内存配置(影响后续融云连接)
348
+ rongcloudConfig.accountId = csAccountId;
349
+ rongcloudConfig.token = newToken;
350
+
351
+ // 持久化到本地 config.json(确保重启后仍使用新配置)
352
+ try {
353
+ if (fs.existsSync(clawBridgeConfigPath)) {
354
+ const clawConfig = JSON.parse(fs.readFileSync(clawBridgeConfigPath, 'utf8'));
355
+ clawConfig.nodeId = csAccountId;
356
+ clawConfig.token = newToken;
357
+ clawConfig.expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1000; // 7天
358
+ fs.writeFileSync(clawBridgeConfigPath, JSON.stringify(clawConfig, null, 2));
359
+ log.info(`[WORKER] 客服账号已持久化到 config.json: ${csAccountId}`);
360
+ }
361
+ } catch (err) {
362
+ log.error(`[WORKER] 持久化客服账号到 config.json 失败: ${err.message}`);
363
+ }
364
+
365
+ return true;
366
+ }
367
+ }
368
+ } catch (tokenErr) {
369
+ if (tokenErr.response?.status === 404) {
370
+ log.warn(`[WORKER] 客服账号 ${csAccountId} 未注册为 claw 节点,无法获取 token。请先使用 clawmessenger 注册该账号`);
371
+ } else {
372
+ log.warn(`[WORKER] 获取客服账号 token 失败: ${tokenErr.message}`);
373
+ }
374
+ }
375
+
376
+ log.warn(`[WORKER] 保持当前配置: ${currentAccountId}`);
377
+ return false;
378
+ }
379
+
380
+ // API 返回了非 200(如配置不存在时 404),静默忽略
381
+ return false;
382
+ } catch (err) {
383
+ // 网络错误在后端未就绪时常见,静默失败不影响启动
384
+ if (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT' || err.code === 'ENOTFOUND') {
385
+ log.warn(`[WORKER] 无法连接后端同步客服账号: ${err.message},保持当前配置`);
386
+ } else if (err.response?.status === 404) {
387
+ log.info('[WORKER] 客服账号未在系统配置中设置,使用当前配置');
388
+ } else {
389
+ log.error(`[WORKER] 同步客服账号异常: ${err.message}`);
390
+ }
293
391
  return false;
294
392
  }
295
393
  }
@@ -298,6 +396,13 @@ async function initRongCloud() {
298
396
  if (!rongcloudConfig) return;
299
397
 
300
398
  log.info(`[WORKER] Worker 启动,目录: ${__dirname}`);
399
+
400
+ // 从后端同步客服账号配置
401
+ // 确保前端发送的客服消息能正确路由到 silent-service 的融云连接账号
402
+ const configChanged = await syncCustomerServiceAccountId();
403
+ if (configChanged) {
404
+ log.info('[WORKER] 客服账号已切换到数据库配置的 ID,将使用新配置连接融云');
405
+ }
301
406
  log.info(`[WORKER] 代码版本特征: isOffLineMessage-pass-through, messageDirection-log, addEventListener-exclusive`);
302
407
 
303
408
  // 启动 opencode 服务(与桌面客户端对齐)