claw-subagent-service 0.0.50 → 0.0.52

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.50",
3
+ "version": "0.0.52",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -111,8 +111,13 @@ function getGatewayToken() {
111
111
  if (fs.existsSync(filePath)) {
112
112
  const content = fs.readFileSync(filePath, 'utf-8');
113
113
  const config = JSON.parse(content);
114
- // 可能的 token 字段名
115
- const token = config.gatewayToken || config.token || config.apiKey || config.api_key || config.password;
114
+ // 可能的 token 字段名(支持嵌套路径 gateway.auth.token)
115
+ const token = config.gatewayToken
116
+ || (config.gateway?.auth?.token)
117
+ || config.token
118
+ || config.apiKey
119
+ || config.api_key
120
+ || config.password;
116
121
  if (token) {
117
122
  return String(token);
118
123
  }
@@ -191,6 +196,30 @@ function startOpenClawGateway(log) {
191
196
  }
192
197
 
193
198
  class OpenClawClient {
199
+ // 全局并发限制:同时最多运行 N 个 openclaw agent 进程
200
+ static maxConcurrency = 2;
201
+ static runningCount = 0;
202
+ static waitQueue = [];
203
+ // Session 级串行锁:确保同一 session 不会并发 spawn 多个进程
204
+ static sessionLocks = new Map();
205
+
206
+ static async acquireSlot() {
207
+ if (OpenClawClient.runningCount < OpenClawClient.maxConcurrency) {
208
+ OpenClawClient.runningCount++;
209
+ return;
210
+ }
211
+ return new Promise(resolve => OpenClawClient.waitQueue.push(resolve));
212
+ }
213
+
214
+ static releaseSlot() {
215
+ OpenClawClient.runningCount--;
216
+ if (OpenClawClient.waitQueue.length > 0) {
217
+ const next = OpenClawClient.waitQueue.shift();
218
+ OpenClawClient.runningCount++;
219
+ next();
220
+ }
221
+ }
222
+
194
223
  constructor(log) {
195
224
  this.log = log;
196
225
  this.gatewayStarting = false;
@@ -255,6 +284,35 @@ class OpenClawClient {
255
284
 
256
285
  async chatViaCLI(message, fromUser) {
257
286
  const sessionId = `clawmessenger-${fromUser}`;
287
+
288
+ // 1. Session 级串行锁:同一用户的消息排队执行,避免多个进程竞争同一 session 文件
289
+ const previousLock = OpenClawClient.sessionLocks.get(sessionId);
290
+ let resolveLock;
291
+ const currentLock = new Promise(r => { resolveLock = r; });
292
+ OpenClawClient.sessionLocks.set(sessionId, currentLock);
293
+ if (previousLock) {
294
+ this.log?.info(`[OpenClawClient] session ${sessionId} 正在处理中,排队等待...`);
295
+ await previousLock;
296
+ }
297
+
298
+ // 2. 全局并发槽位限制:所有实例共享,防止服务器资源耗尽
299
+ await OpenClawClient.acquireSlot();
300
+ this.log?.info(`[OpenClawClient] 获得执行槽位 (当前运行: ${OpenClawClient.runningCount}/${OpenClawClient.maxConcurrency})`);
301
+
302
+ try {
303
+ return await this._runAgentCLI(message, fromUser, sessionId);
304
+ } finally {
305
+ OpenClawClient.releaseSlot();
306
+ this.log?.info(`[OpenClawClient] 释放执行槽位 (当前运行: ${OpenClawClient.runningCount}/${OpenClawClient.maxConcurrency})`);
307
+ // 释放 session 锁
308
+ resolveLock();
309
+ if (OpenClawClient.sessionLocks.get(sessionId) === currentLock) {
310
+ OpenClawClient.sessionLocks.delete(sessionId);
311
+ }
312
+ }
313
+ }
314
+
315
+ _runAgentCLI(message, fromUser, sessionId) {
258
316
  const escapedMessage = message
259
317
  .replace(/\\/g, '\\\\')
260
318
  .replace(/"/g, '\\"')