too-many-claw 1.0.21 → 1.0.23

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/dist/cli.js CHANGED
@@ -1475,6 +1475,25 @@ var ConfigManager = class {
1475
1475
  getOpenClawConfigPath() {
1476
1476
  return this.openclawConfigPath;
1477
1477
  }
1478
+ /**
1479
+ * Get the OpenClaw Gateway authentication token
1480
+ * First checks environment variable OPENCLAW_GATEWAY_TOKEN,
1481
+ * then falls back to openclaw.json gateway.token or gateway.password
1482
+ */
1483
+ getGatewayToken() {
1484
+ const envToken = process.env.OPENCLAW_GATEWAY_TOKEN;
1485
+ if (envToken) {
1486
+ return envToken;
1487
+ }
1488
+ const config = this.readOpenClawConfig();
1489
+ if (config?.gateway?.token) {
1490
+ return config.gateway.token;
1491
+ }
1492
+ if (config?.gateway?.password) {
1493
+ return config.gateway.password;
1494
+ }
1495
+ return void 0;
1496
+ }
1478
1497
  // ============================================
1479
1498
  // Validation & Repair
1480
1499
  // ============================================
@@ -2330,6 +2349,7 @@ import WebSocket from "ws";
2330
2349
  import { EventEmitter } from "events";
2331
2350
  var DEFAULT_CONFIG2 = {
2332
2351
  url: "ws://127.0.0.1:18789",
2352
+ gatewayToken: "",
2333
2353
  reconnect: {
2334
2354
  enabled: true,
2335
2355
  maxAttempts: 10,
@@ -2337,7 +2357,8 @@ var DEFAULT_CONFIG2 = {
2337
2357
  maxDelay: 3e4
2338
2358
  },
2339
2359
  heartbeatInterval: 3e4,
2340
- connectionTimeout: 1e4
2360
+ connectionTimeout: 1e4,
2361
+ verbose: false
2341
2362
  };
2342
2363
  function extractTextContent(content) {
2343
2364
  if (!content) {
@@ -2503,6 +2524,10 @@ var GatewayClient = class extends EventEmitter {
2503
2524
  return;
2504
2525
  }
2505
2526
  this.emit("message", message);
2527
+ if (message.type === "event" && message.event === "connect.challenge") {
2528
+ this.handleConnectChallenge(message);
2529
+ return;
2530
+ }
2506
2531
  const roleBasedMessage = message;
2507
2532
  if (roleBasedMessage.role) {
2508
2533
  this.handleRoleBasedMessage(roleBasedMessage);
@@ -2701,6 +2726,43 @@ var GatewayClient = class extends EventEmitter {
2701
2726
  this.heartbeatTimer = null;
2702
2727
  }
2703
2728
  }
2729
+ /**
2730
+ * Handle OpenClaw Gateway connect.challenge event
2731
+ * Responds with authentication token to complete connection handshake
2732
+ */
2733
+ handleConnectChallenge(message) {
2734
+ const payload = message.payload || {};
2735
+ const nonce = payload.nonce;
2736
+ const ts = payload.ts;
2737
+ this.log(`Received connect.challenge (nonce: ${nonce?.substring(0, 8)}...)`);
2738
+ if (!this.config.gatewayToken) {
2739
+ this.log("Warning: No gateway token configured, authentication may fail");
2740
+ }
2741
+ const connectResponse = {
2742
+ type: "connect",
2743
+ token: this.config.gatewayToken,
2744
+ nonce,
2745
+ ts,
2746
+ client: {
2747
+ name: "too-many-claw",
2748
+ version: "1.0.0"
2749
+ }
2750
+ };
2751
+ const sent = this.send(connectResponse);
2752
+ if (sent) {
2753
+ this.log("Sent connect response with authentication token");
2754
+ } else {
2755
+ this.log("Failed to send connect response");
2756
+ }
2757
+ }
2758
+ /**
2759
+ * Log message if verbose mode is enabled
2760
+ */
2761
+ log(message) {
2762
+ if (this.config.verbose) {
2763
+ console.log(`[GatewayClient] ${message}`);
2764
+ }
2765
+ }
2704
2766
  };
2705
2767
 
2706
2768
  // src/discord/BotMessageMonitor.ts
@@ -2817,7 +2879,8 @@ var BotMessageMonitor = class extends EventEmitter2 {
2817
2879
  agentId,
2818
2880
  timestamp: Date.now()
2819
2881
  });
2820
- this.log(`Registered pending message for agent ${agentId}: ${content.substring(0, 50)}...`);
2882
+ this.forceLog(`\u{1F4DD} Registered pending: ${agentId} \u2192 "${content.substring(0, 40)}..."`);
2883
+ this.log(` Hash: ${hash.substring(0, 50)}`);
2821
2884
  this.cleanupPendingMessages();
2822
2885
  }
2823
2886
  /**
@@ -2851,9 +2914,12 @@ var BotMessageMonitor = class extends EventEmitter2 {
2851
2914
  lookupPendingAgent(content) {
2852
2915
  const hash = this.hashContent(content);
2853
2916
  const pending = this.pendingMessages.get(hash);
2917
+ this.log(`Looking up agent for content: "${content.substring(0, 40)}..."`);
2918
+ this.log(` Generated hash: ${hash.substring(0, 50)}`);
2919
+ this.log(` Pending messages count: ${this.pendingMessages.size}`);
2854
2920
  if (pending && Date.now() - pending.timestamp < this.PENDING_MESSAGE_TTL) {
2855
2921
  this.pendingMessages.delete(hash);
2856
- this.log(`Found pending agent ${pending.agentId} for message`);
2922
+ this.forceLog(`\u2713 Found pending agent ${pending.agentId} via exact hash match`);
2857
2923
  return pending.agentId;
2858
2924
  }
2859
2925
  const normalizedContent = content.trim().toLowerCase();
@@ -2862,11 +2928,17 @@ var BotMessageMonitor = class extends EventEmitter2 {
2862
2928
  if (normalizedContent.includes(pendingContent.substring(0, 100)) || pendingContent.includes(normalizedContent.substring(0, 100))) {
2863
2929
  if (Date.now() - data.timestamp < this.PENDING_MESSAGE_TTL) {
2864
2930
  this.pendingMessages.delete(pendingHash);
2865
- this.log(`Found pending agent ${data.agentId} via partial match`);
2931
+ this.forceLog(`\u2713 Found pending agent ${data.agentId} via partial match`);
2866
2932
  return data.agentId;
2867
2933
  }
2868
2934
  }
2869
2935
  }
2936
+ if (this.pendingMessages.size > 0) {
2937
+ this.log(`No match found. Current pending messages:`);
2938
+ for (const [pendingHash, data] of this.pendingMessages) {
2939
+ this.log(` - ${data.agentId}: ${pendingHash.substring(0, 50)}...`);
2940
+ }
2941
+ }
2870
2942
  return null;
2871
2943
  }
2872
2944
  /**
@@ -2928,12 +3000,12 @@ var BotMessageMonitor = class extends EventEmitter2 {
2928
3000
  if (pendingAgentId) {
2929
3001
  agent = this.agentMapper.resolve(pendingAgentId) || this.agentMapper.getDefaultAgent();
2930
3002
  cleanContent = message.content;
2931
- this.log(`Using agent ${agent.id} from Gateway event`);
3003
+ this.forceLog(`\u2192 Using agent ${agent.emoji} ${agent.name} from Gateway event`);
2932
3004
  } else {
2933
3005
  const extracted = this.extractAgentFromContent(message.content);
2934
3006
  agent = extracted.agent;
2935
3007
  cleanContent = extracted.cleanContent;
2936
- this.log(`Using agent ${agent.id} from content extraction (fallback)`);
3008
+ this.forceLog(`\u2192 Using agent ${agent.emoji} ${agent.name} from content extraction (fallback)`);
2937
3009
  }
2938
3010
  this.emit("intercepted", message.id, message.channel.id, agent.id);
2939
3011
  this.forceLog(`\u{1F980} Intercepted message \u2192 ${agent.emoji} ${agent.name}`);
@@ -3086,6 +3158,10 @@ var AgentMapper = class {
3086
3158
  this.idMap.set(agent.id.toLowerCase(), agent);
3087
3159
  const normalizedName = this.normalizeName(agent.name);
3088
3160
  this.nameMap.set(normalizedName, agent);
3161
+ const openClawName = `${agent.emoji} ${agent.name}`.toLowerCase();
3162
+ this.nameMap.set(openClawName, agent);
3163
+ this.nameMap.set(this.normalizeName(openClawName), agent);
3164
+ this.aliasMap.set(agent.emoji, agent);
3089
3165
  this.buildAliases(agent);
3090
3166
  }
3091
3167
  }
@@ -3136,9 +3212,18 @@ var AgentMapper = class {
3136
3212
  if (!identifier) {
3137
3213
  return this.getDefaultAgent();
3138
3214
  }
3139
- const normalized = identifier.toLowerCase().trim();
3215
+ let cleanIdentifier = identifier.trim();
3216
+ const emojiMatch = cleanIdentifier.match(/^([\p{Emoji}])\s*/u);
3217
+ if (emojiMatch) {
3218
+ const emoji = emojiMatch[1];
3219
+ const byEmoji = this.aliasMap.get(emoji);
3220
+ if (byEmoji) return byEmoji;
3221
+ }
3222
+ const normalized = cleanIdentifier.toLowerCase().trim();
3140
3223
  const byId = this.idMap.get(normalized);
3141
3224
  if (byId) return byId;
3225
+ const byOpenClawName = this.nameMap.get(normalized);
3226
+ if (byOpenClawName) return byOpenClawName;
3142
3227
  const byName = this.nameMap.get(this.normalizeName(identifier));
3143
3228
  if (byName) return byName;
3144
3229
  const byAlias = this.aliasMap.get(normalized);
@@ -3223,8 +3308,14 @@ var OpenClawDaemon = class extends EventEmitter3 {
3223
3308
  this.configManager = new ConfigManager();
3224
3309
  this.webhookManager = new WebhookManager();
3225
3310
  this.agentMapper = new AgentMapper();
3311
+ const gatewayToken = this.configManager.getGatewayToken();
3312
+ if (!gatewayToken) {
3313
+ this.forceLog("Warning: No gateway token found. Set OPENCLAW_GATEWAY_TOKEN env var or configure in openclaw.json");
3314
+ }
3226
3315
  this.gatewayClient = new GatewayClient({
3227
3316
  url: this.config.gatewayUrl,
3317
+ gatewayToken,
3318
+ verbose: this.config.verbose,
3228
3319
  reconnect: {
3229
3320
  enabled: true,
3230
3321
  maxAttempts: -1,
@@ -3453,9 +3544,12 @@ var OpenClawDaemon = class extends EventEmitter3 {
3453
3544
  */
3454
3545
  registerPendingMessageForMonitor(message) {
3455
3546
  if (!this.botMessageMonitor) return;
3456
- const agentIdentifier = message.agentId || message.agentName || message.agent || message.name;
3547
+ const agentIdentifier = this.extractAgentIdentifier(message);
3457
3548
  const agent = this.agentMapper.resolve(agentIdentifier);
3458
3549
  const agentId = agent?.id || "base";
3550
+ if (this.config.verbose) {
3551
+ this.log(`registerPendingMessageForMonitor - identifier: ${agentIdentifier}, resolved to: ${agentId}`);
3552
+ }
3459
3553
  let content = "";
3460
3554
  if (typeof message.content === "string") {
3461
3555
  content = message.content;
@@ -3487,6 +3581,15 @@ var OpenClawDaemon = class extends EventEmitter3 {
3487
3581
  if (message.stream) {
3488
3582
  this.log(` Stream: ${message.stream}`);
3489
3583
  }
3584
+ if (message.agentId) {
3585
+ this.log(` AgentId: ${message.agentId}`);
3586
+ }
3587
+ if (message.runId) {
3588
+ this.log(` RunId: ${message.runId}`);
3589
+ }
3590
+ if (message.data) {
3591
+ this.log(` Data keys: ${Object.keys(message.data).join(", ")}`);
3592
+ }
3490
3593
  }
3491
3594
  }
3492
3595
  /**
@@ -3495,7 +3598,10 @@ var OpenClawDaemon = class extends EventEmitter3 {
3495
3598
  * because the message_sent event handler will intercept and resend via webhook.
3496
3599
  */
3497
3600
  async handleAgentResponse(message) {
3498
- const agentIdentifier = message.agentId || message.agentName || message.agent || message.name;
3601
+ const agentIdentifier = this.extractAgentIdentifier(message);
3602
+ if (this.config.verbose) {
3603
+ this.log(`Agent response - extracted identifier: ${agentIdentifier}`);
3604
+ }
3499
3605
  let content = "";
3500
3606
  if (typeof message.content === "string") {
3501
3607
  content = message.content;
@@ -3517,11 +3623,43 @@ var OpenClawDaemon = class extends EventEmitter3 {
3517
3623
  }
3518
3624
  await this.forwardToWebhook(agent, content);
3519
3625
  }
3626
+ /**
3627
+ * Extract agent identifier from OpenClaw Gateway message
3628
+ * Checks multiple fields since OpenClaw may send agent info in different places
3629
+ */
3630
+ extractAgentIdentifier(message) {
3631
+ if (message.agentId) return message.agentId;
3632
+ if (message.agentName) return message.agentName;
3633
+ if (message.agent) return message.agent;
3634
+ if (message.name) return message.name;
3635
+ const data = message.data;
3636
+ if (data) {
3637
+ if (data.agentId) return data.agentId;
3638
+ if (data.agentName) return data.agentName;
3639
+ if (data.agent) return data.agent;
3640
+ if (data.name) return data.name;
3641
+ }
3642
+ const runId = message.id || message.runId;
3643
+ if (runId && typeof runId === "string") {
3644
+ const runIdMatch = runId.match(/^([a-z][a-z0-9-]*)-[a-z0-9]+$/i);
3645
+ if (runIdMatch) {
3646
+ const potentialAgent = runIdMatch[1];
3647
+ if (this.agentMapper.resolve(potentialAgent)) {
3648
+ return potentialAgent;
3649
+ }
3650
+ }
3651
+ }
3652
+ if (this.config.verbose) {
3653
+ this.log(`Could not extract agent from message. Keys: ${Object.keys(message).join(", ")}`);
3654
+ this.log(` Full message: ${JSON.stringify(message).substring(0, 300)}`);
3655
+ }
3656
+ return "assistant";
3657
+ }
3520
3658
  /**
3521
3659
  * Handle streaming delta (partial response)
3522
3660
  */
3523
3661
  handleAgentDelta(message) {
3524
- const agentIdentifier = message.agentId || message.agentName || message.agent || "assistant";
3662
+ const agentIdentifier = this.extractAgentIdentifier(message);
3525
3663
  let delta = "";
3526
3664
  if (typeof message.delta === "string") {
3527
3665
  delta = message.delta;
@@ -3573,7 +3711,10 @@ var OpenClawDaemon = class extends EventEmitter3 {
3573
3711
  */
3574
3712
  async handleAgentEnd(message) {
3575
3713
  const messageId = message.id || message.runId || message.agentId || message.agentName || "default";
3576
- const agentIdentifier = message.agentId || message.agentName || message.agent || "assistant";
3714
+ const agentIdentifier = this.extractAgentIdentifier(message);
3715
+ if (this.config.verbose) {
3716
+ this.log(`Agent end - messageId: ${messageId}, extracted identifier: ${agentIdentifier}`);
3717
+ }
3577
3718
  this.log(`Agent end event [${messageId}] from: ${agentIdentifier}`);
3578
3719
  const skipWebhook = this.botMessageMonitor && this.botMessageMonitor.isEnabled();
3579
3720
  const buffered = this.responseBuffers.get(messageId);