openclaw-quiubo 2.6.60 → 2.6.62

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/index.js CHANGED
@@ -13455,6 +13455,152 @@ function formatUptime(ms) {
13455
13455
  return `${minutes}m`;
13456
13456
  }
13457
13457
 
13458
+ // src/session-utils.ts
13459
+ function extractGroupIdFromSessionKey(key) {
13460
+ if (!key) return void 0;
13461
+ const match = key.match(
13462
+ /quiubo:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i
13463
+ );
13464
+ return match?.[1];
13465
+ }
13466
+ function extractAgentIdFromSessionKey(key) {
13467
+ if (!key) return "main";
13468
+ const match = key.match(/^agent:([^:]+):quiubo:/);
13469
+ return match?.[1] ?? "main";
13470
+ }
13471
+ function resolveAccountId(config, agentId) {
13472
+ const bindings = config?.bindings ?? [];
13473
+ const matched = bindings.find(
13474
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13475
+ (b) => b?.match?.channel === "quiubo" && b?.agentId === agentId
13476
+ );
13477
+ return matched?.match?.accountId ?? "default";
13478
+ }
13479
+
13480
+ // src/activity-hook.ts
13481
+ var activeToolCounts = /* @__PURE__ */ new Map();
13482
+ var lastSentAt = /* @__PURE__ */ new Map();
13483
+ var pendingIdle = /* @__PURE__ */ new Map();
13484
+ var DEBOUNCE_MS = 2e3;
13485
+ var IDLE_DELAY_MS = 8e3;
13486
+ function isSessionWorking(sessionKey) {
13487
+ return (activeToolCounts.get(sessionKey) ?? 0) > 0 || pendingIdle.has(sessionKey);
13488
+ }
13489
+ function generateLabel(toolName, params) {
13490
+ switch (toolName) {
13491
+ case "exec":
13492
+ case "bash":
13493
+ case "Bash": {
13494
+ const cmd = typeof params?.command === "string" ? params.command : "";
13495
+ const first = cmd.split(/[&&||;|]/)[0].trim();
13496
+ const word = first.split(/\s+/)[0] || "";
13497
+ if (!word) return "Running command...";
13498
+ const truncated = word.length > 50 ? word.slice(0, 50) + "\u2026" : word;
13499
+ return `Running ${truncated}...`;
13500
+ }
13501
+ case "read":
13502
+ case "Read":
13503
+ return "Reading files...";
13504
+ case "write":
13505
+ case "Write":
13506
+ case "edit":
13507
+ case "Edit":
13508
+ return "Writing code...";
13509
+ case "web_search":
13510
+ case "WebSearch":
13511
+ return "Searching the web...";
13512
+ case "web_fetch":
13513
+ case "WebFetch":
13514
+ return "Fetching page...";
13515
+ case "grep":
13516
+ case "Grep":
13517
+ case "glob":
13518
+ case "Glob":
13519
+ return "Searching codebase...";
13520
+ case "Task":
13521
+ return "Running sub-agent...";
13522
+ default:
13523
+ return "Working...";
13524
+ }
13525
+ }
13526
+ function registerActivityHook(api) {
13527
+ api.on(
13528
+ "before_tool_call",
13529
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13530
+ (_event, ctx) => {
13531
+ const sessionKey = ctx.sessionKey;
13532
+ const groupId = extractGroupIdFromSessionKey(sessionKey);
13533
+ if (!groupId) return;
13534
+ const key = sessionKey;
13535
+ const prev = activeToolCounts.get(key) ?? 0;
13536
+ activeToolCounts.set(key, prev + 1);
13537
+ const pendingTimer = pendingIdle.get(key);
13538
+ if (pendingTimer) {
13539
+ clearTimeout(pendingTimer);
13540
+ pendingIdle.delete(key);
13541
+ return;
13542
+ }
13543
+ if (prev === 0) {
13544
+ const now = Date.now();
13545
+ const last = lastSentAt.get(key) ?? 0;
13546
+ if (now - last < DEBOUNCE_MS) return;
13547
+ lastSentAt.set(key, now);
13548
+ const config = api.runtime?.config ?? api.config;
13549
+ const agentId = extractAgentIdFromSessionKey(sessionKey);
13550
+ const accountId = resolveAccountId(config, agentId);
13551
+ const client = clients.get(accountId);
13552
+ const accountCfg = accounts.get(accountId);
13553
+ if (!client || !accountCfg?.botIdentityId) return;
13554
+ const toolName = ctx.toolName ?? ctx.tool ?? "";
13555
+ const label = generateLabel(toolName, ctx.params ?? ctx.input);
13556
+ client.sendActivity(groupId, {
13557
+ identityId: accountCfg.botIdentityId,
13558
+ state: "working",
13559
+ tool: toolName || void 0,
13560
+ label
13561
+ }).catch((err) => {
13562
+ console.warn(`[quiubo] activity-hook working failed: ${err}`);
13563
+ });
13564
+ }
13565
+ },
13566
+ { name: "quiubo-activity-before" }
13567
+ );
13568
+ api.on(
13569
+ "after_tool_call",
13570
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13571
+ (_event, ctx) => {
13572
+ const sessionKey = ctx.sessionKey;
13573
+ const groupId = extractGroupIdFromSessionKey(sessionKey);
13574
+ if (!groupId) return;
13575
+ const key = sessionKey;
13576
+ const prev = activeToolCounts.get(key) ?? 0;
13577
+ const next = Math.max(0, prev - 1);
13578
+ activeToolCounts.set(key, next);
13579
+ if (next === 0) {
13580
+ const idleTimer = setTimeout(() => {
13581
+ pendingIdle.delete(key);
13582
+ lastSentAt.delete(key);
13583
+ if ((activeToolCounts.get(key) ?? 0) > 0) return;
13584
+ const config = api.runtime?.config ?? api.config;
13585
+ const agentId = extractAgentIdFromSessionKey(sessionKey);
13586
+ const accountId = resolveAccountId(config, agentId);
13587
+ const client = clients.get(accountId);
13588
+ const accountCfg = accounts.get(accountId);
13589
+ if (!client || !accountCfg?.botIdentityId) return;
13590
+ client.sendActivity(groupId, {
13591
+ identityId: accountCfg.botIdentityId,
13592
+ state: "idle"
13593
+ }).catch((err) => {
13594
+ console.warn(`[quiubo] activity-hook idle failed: ${err}`);
13595
+ });
13596
+ }, IDLE_DELAY_MS);
13597
+ pendingIdle.set(key, idleTimer);
13598
+ }
13599
+ },
13600
+ { name: "quiubo-activity-after" }
13601
+ );
13602
+ }
13603
+
13458
13604
  // src/channel.ts
13459
13605
  var KEYS_DIR = join2(process.env.HOME ?? process.env.USERPROFILE ?? "", ".openclaw", "cron");
13460
13606
  async function loadOrGenerateKeys(cfg, accountId) {
@@ -14769,7 +14915,10 @@ async function routeInboundMessage(opts) {
14769
14915
  }
14770
14916
  }
14771
14917
  log?.info?.(`[${accountId}] Quiubo: inbound from ${senderId} in group ${groupId}: ${text?.slice(0, 100)}${mediaPaths.length > 0 ? ` [${mediaPaths.length} image(s)]` : ""}`);
14918
+ const agentId = resolveAgentId(cfg, accountId);
14919
+ const sessionKey = buildSessionKey(agentId, groupId);
14772
14920
  const sendTyping = async () => {
14921
+ if (isSessionWorking(sessionKey)) return;
14773
14922
  try {
14774
14923
  await client.sendTypingIndicator(groupId, botIdentityId);
14775
14924
  log?.info?.(`[${accountId}] Quiubo: typing indicator sent for group ${groupId}`);
@@ -14779,8 +14928,6 @@ async function routeInboundMessage(opts) {
14779
14928
  };
14780
14929
  await sendTyping();
14781
14930
  const typingInterval = setInterval(sendTyping, 4e3);
14782
- const agentId = resolveAgentId(cfg, accountId);
14783
- const sessionKey = buildSessionKey(agentId, groupId);
14784
14931
  log?.info?.(`[${accountId}] [delivery:inbound] agentId=${agentId}, sessionKey=${sessionKey}, To=quiubo:${groupId}, ConversationLabel=quiubo:${groupId}`);
14785
14932
  const ctxPayload = runtime2.channel.reply.finalizeInboundContext({
14786
14933
  Body: text,
@@ -14929,30 +15076,6 @@ async function routeInboundMessage(opts) {
14929
15076
 
14930
15077
  // src/create-post-tool.ts
14931
15078
  import { readFile as readFile3 } from "fs/promises";
14932
-
14933
- // src/session-utils.ts
14934
- function extractGroupIdFromSessionKey(key) {
14935
- if (!key) return void 0;
14936
- const match = key.match(
14937
- /quiubo:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i
14938
- );
14939
- return match?.[1];
14940
- }
14941
- function extractAgentIdFromSessionKey(key) {
14942
- if (!key) return "main";
14943
- const match = key.match(/^agent:([^:]+):quiubo:/);
14944
- return match?.[1] ?? "main";
14945
- }
14946
- function resolveAccountId(config, agentId) {
14947
- const bindings = config?.bindings ?? [];
14948
- const matched = bindings.find(
14949
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14950
- (b) => b?.match?.channel === "quiubo" && b?.agentId === agentId
14951
- );
14952
- return matched?.match?.accountId ?? "default";
14953
- }
14954
-
14955
- // src/create-post-tool.ts
14956
15079
  var IMAGE_MIME_TYPES2 = {
14957
15080
  ".jpg": "image/jpeg",
14958
15081
  ".jpeg": "image/jpeg",
@@ -15160,126 +15283,6 @@ function registerGroupContextHook(api) {
15160
15283
  );
15161
15284
  }
15162
15285
 
15163
- // src/activity-hook.ts
15164
- var activeToolCounts = /* @__PURE__ */ new Map();
15165
- var lastSentAt = /* @__PURE__ */ new Map();
15166
- var pendingIdle = /* @__PURE__ */ new Map();
15167
- var DEBOUNCE_MS = 2e3;
15168
- var IDLE_DELAY_MS = 5e3;
15169
- function generateLabel(toolName, params) {
15170
- switch (toolName) {
15171
- case "exec":
15172
- case "bash":
15173
- case "Bash": {
15174
- const cmd = typeof params?.command === "string" ? params.command : "";
15175
- const first = cmd.split(/[&&||;|]/)[0].trim();
15176
- const word = first.split(/\s+/)[0] || "";
15177
- if (!word) return "Running command...";
15178
- const truncated = word.length > 50 ? word.slice(0, 50) + "\u2026" : word;
15179
- return `Running ${truncated}...`;
15180
- }
15181
- case "read":
15182
- case "Read":
15183
- return "Reading files...";
15184
- case "write":
15185
- case "Write":
15186
- case "edit":
15187
- case "Edit":
15188
- return "Writing code...";
15189
- case "web_search":
15190
- case "WebSearch":
15191
- return "Searching the web...";
15192
- case "web_fetch":
15193
- case "WebFetch":
15194
- return "Fetching page...";
15195
- case "grep":
15196
- case "Grep":
15197
- case "glob":
15198
- case "Glob":
15199
- return "Searching codebase...";
15200
- case "Task":
15201
- return "Running sub-agent...";
15202
- default:
15203
- return "Working...";
15204
- }
15205
- }
15206
- function registerActivityHook(api) {
15207
- api.on(
15208
- "before_tool_call",
15209
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15210
- (_event, ctx) => {
15211
- const sessionKey = ctx.sessionKey;
15212
- const groupId = extractGroupIdFromSessionKey(sessionKey);
15213
- if (!groupId) return;
15214
- const key = sessionKey;
15215
- const prev = activeToolCounts.get(key) ?? 0;
15216
- activeToolCounts.set(key, prev + 1);
15217
- const pendingTimer = pendingIdle.get(key);
15218
- if (pendingTimer) {
15219
- clearTimeout(pendingTimer);
15220
- pendingIdle.delete(key);
15221
- }
15222
- if (prev === 0) {
15223
- const now = Date.now();
15224
- const last = lastSentAt.get(key) ?? 0;
15225
- if (now - last < DEBOUNCE_MS) return;
15226
- lastSentAt.set(key, now);
15227
- const config = api.runtime?.config ?? api.config;
15228
- const agentId = extractAgentIdFromSessionKey(sessionKey);
15229
- const accountId = resolveAccountId(config, agentId);
15230
- const client = clients.get(accountId);
15231
- const accountCfg = accounts.get(accountId);
15232
- if (!client || !accountCfg?.botIdentityId) return;
15233
- const toolName = ctx.toolName ?? ctx.tool ?? "";
15234
- const label = generateLabel(toolName, ctx.params ?? ctx.input);
15235
- client.sendActivity(groupId, {
15236
- identityId: accountCfg.botIdentityId,
15237
- state: "working",
15238
- tool: toolName || void 0,
15239
- label
15240
- }).catch((err) => {
15241
- console.warn(`[quiubo] activity-hook working failed: ${err}`);
15242
- });
15243
- }
15244
- },
15245
- { name: "quiubo-activity-before" }
15246
- );
15247
- api.on(
15248
- "after_tool_call",
15249
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15250
- (_event, ctx) => {
15251
- const sessionKey = ctx.sessionKey;
15252
- const groupId = extractGroupIdFromSessionKey(sessionKey);
15253
- if (!groupId) return;
15254
- const key = sessionKey;
15255
- const prev = activeToolCounts.get(key) ?? 0;
15256
- const next = Math.max(0, prev - 1);
15257
- activeToolCounts.set(key, next);
15258
- if (next === 0) {
15259
- const idleTimer = setTimeout(() => {
15260
- pendingIdle.delete(key);
15261
- lastSentAt.delete(key);
15262
- if ((activeToolCounts.get(key) ?? 0) > 0) return;
15263
- const config = api.runtime?.config ?? api.config;
15264
- const agentId = extractAgentIdFromSessionKey(sessionKey);
15265
- const accountId = resolveAccountId(config, agentId);
15266
- const client = clients.get(accountId);
15267
- const accountCfg = accounts.get(accountId);
15268
- if (!client || !accountCfg?.botIdentityId) return;
15269
- client.sendActivity(groupId, {
15270
- identityId: accountCfg.botIdentityId,
15271
- state: "idle"
15272
- }).catch((err) => {
15273
- console.warn(`[quiubo] activity-hook idle failed: ${err}`);
15274
- });
15275
- }, IDLE_DELAY_MS);
15276
- pendingIdle.set(key, idleTimer);
15277
- }
15278
- },
15279
- { name: "quiubo-activity-after" }
15280
- );
15281
- }
15282
-
15283
15286
  // src/polling-gateway.ts
15284
15287
  var PollingGateway = class {
15285
15288
  client;