openclaw-quiubo 2.6.49 → 2.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,sBAAsB,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACvK,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAGxB,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,eAAe,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAC;IAEjD,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE5D,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC5F;AAED,QAAA,MAAM,MAAM;;;;kBAII,iBAAiB;CAMhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,sBAAsB,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACvK,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAGxB,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,eAAe,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAC;IAEjD,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE5D,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC5F;AAED,QAAA,MAAM,MAAM;;;;kBAII,iBAAiB;CAOhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js CHANGED
@@ -9008,7 +9008,8 @@ var QuiuboApiClient = class {
9008
9008
  ...opts.ciphertext ? { ciphertext: opts.ciphertext } : { plaintext: opts.plaintext ?? "" },
9009
9009
  clientMessageId: opts.clientMessageId ?? randomUUID(),
9010
9010
  ...opts.metadata ? { metadata: opts.metadata } : {},
9011
- ...opts.attachments?.length ? { attachments: opts.attachments } : {}
9011
+ ...opts.attachments?.length ? { attachments: opts.attachments } : {},
9012
+ ...opts.replyToMessageId ? { replyToMessageId: opts.replyToMessageId } : {}
9012
9013
  });
9013
9014
  }
9014
9015
  /**
@@ -12644,6 +12645,14 @@ var RealtimeGateway = class {
12644
12645
  getBotConfig(groupId) {
12645
12646
  return this.botConfigCache.get(groupId);
12646
12647
  }
12648
+ /** Number of groups in the bot config cache */
12649
+ getGroupCount() {
12650
+ return this.botConfigCache.size;
12651
+ }
12652
+ /** All group IDs in the bot config cache */
12653
+ getGroupIds() {
12654
+ return [...this.botConfigCache.keys()];
12655
+ }
12647
12656
  /** Set the cache-miss callback */
12648
12657
  setOnCacheMiss(fn) {
12649
12658
  this.onCacheMiss = fn;
@@ -13343,6 +13352,100 @@ var AgentKeyManager = class {
13343
13352
  }
13344
13353
  };
13345
13354
 
13355
+ // src/status.ts
13356
+ var accountStatuses = /* @__PURE__ */ new Map();
13357
+ function updateAccountStatus(accountId, update) {
13358
+ const existing = accountStatuses.get(accountId) ?? {
13359
+ connected: false,
13360
+ groupCount: 0,
13361
+ activeGroups: [],
13362
+ e2ee: false
13363
+ };
13364
+ accountStatuses.set(accountId, { ...existing, ...update });
13365
+ }
13366
+ function trackLastMessage(accountId) {
13367
+ const existing = accountStatuses.get(accountId);
13368
+ if (existing) {
13369
+ existing.lastMessageAt = (/* @__PURE__ */ new Date()).toISOString();
13370
+ }
13371
+ }
13372
+ function clearAccountStatus(accountId) {
13373
+ accountStatuses.delete(accountId);
13374
+ }
13375
+ function inspectAccount(cfg, accountId) {
13376
+ const channelCfg = cfg?.channels?.quiubo?.accounts?.[accountId];
13377
+ if (!channelCfg) {
13378
+ return {
13379
+ accountId,
13380
+ enabled: false,
13381
+ configured: false
13382
+ };
13383
+ }
13384
+ const hasApiKey = Boolean(channelCfg.apiKey);
13385
+ const hasBotIdentity = Boolean(channelCfg.botIdentityId);
13386
+ const status = accountStatuses.get(accountId);
13387
+ return {
13388
+ accountId,
13389
+ enabled: channelCfg.enabled !== false && hasApiKey,
13390
+ configured: hasApiKey && hasBotIdentity,
13391
+ tokenStatus: hasApiKey ? "available" : "missing",
13392
+ botIdentityStatus: hasBotIdentity ? "available" : "missing",
13393
+ apiUrl: channelCfg.apiUrl ?? "https://api.quiubo.io",
13394
+ ...status && {
13395
+ connected: status.connected,
13396
+ groups: status.groupCount,
13397
+ e2ee: status.e2ee,
13398
+ lastMessage: status.lastMessageAt,
13399
+ uptime: status.startedAt ? formatUptime(Date.now() - new Date(status.startedAt).getTime()) : void 0
13400
+ }
13401
+ };
13402
+ }
13403
+ function registerStatusRpc(api) {
13404
+ api.registerGatewayMethod(
13405
+ "quiubo.status",
13406
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13407
+ ({ respond }) => {
13408
+ const result = { accounts: {} };
13409
+ for (const [accountId, status] of accountStatuses.entries()) {
13410
+ result.accounts[accountId] = {
13411
+ connected: status.connected,
13412
+ groups: status.groupCount,
13413
+ activeGroups: status.activeGroups,
13414
+ e2ee: status.e2ee,
13415
+ lastMessage: status.lastMessageAt,
13416
+ uptime: status.startedAt ? formatUptime(Date.now() - new Date(status.startedAt).getTime()) : void 0,
13417
+ ...status.pusherState && {
13418
+ pusher: {
13419
+ state: status.pusherState,
13420
+ channels: status.pusherChannels
13421
+ }
13422
+ }
13423
+ };
13424
+ }
13425
+ const config = api.runtime?.config ?? api.config;
13426
+ const channelAccounts = config?.channels?.quiubo?.accounts;
13427
+ if (channelAccounts) {
13428
+ for (const id of Object.keys(channelAccounts)) {
13429
+ if (!result.accounts[id]) {
13430
+ result.accounts[id] = {
13431
+ connected: false,
13432
+ configured: Boolean(channelAccounts[id]?.apiKey),
13433
+ enabled: channelAccounts[id]?.enabled !== false
13434
+ };
13435
+ }
13436
+ }
13437
+ }
13438
+ respond(true, result);
13439
+ }
13440
+ );
13441
+ }
13442
+ function formatUptime(ms) {
13443
+ const hours = Math.floor(ms / 36e5);
13444
+ const minutes = Math.floor(ms % 36e5 / 6e4);
13445
+ if (hours > 0) return `${hours}h ${minutes}m`;
13446
+ return `${minutes}m`;
13447
+ }
13448
+
13346
13449
  // src/channel.ts
13347
13450
  var KEYS_DIR = join2(process.env.HOME ?? process.env.USERPROFILE ?? "", ".openclaw", "cron");
13348
13451
  async function loadOrGenerateKeys(cfg, accountId) {
@@ -13437,6 +13540,76 @@ var loggers = /* @__PURE__ */ new Map();
13437
13540
  var CHANNEL_ID = "quiubo";
13438
13541
  var DEFAULT_API_URL = "https://api.quiubo.io";
13439
13542
  var DEFAULT_ACCOUNT_ID = "default";
13543
+ async function loadGroupIdsFromCursors(accountId) {
13544
+ const cursorsFile = join2(
13545
+ process.env.HOME ?? process.env.USERPROFILE ?? "",
13546
+ ".openclaw",
13547
+ "cron",
13548
+ `quiubo-cursors-${accountId}.json`
13549
+ );
13550
+ try {
13551
+ const raw = await readFile2(cursorsFile, "utf-8");
13552
+ const data = JSON.parse(raw);
13553
+ return Object.keys(data).filter((k) => typeof data[k] === "string" && data[k]);
13554
+ } catch {
13555
+ return [];
13556
+ }
13557
+ }
13558
+ async function notifyGroupsViaFallbackAccount(failedAccountId, failedBotIdentityId, reason, log) {
13559
+ let fallbackClient = null;
13560
+ let fallbackBotIdentityId = null;
13561
+ let fallbackAccountId = null;
13562
+ for (const [aid, client] of clients) {
13563
+ if (aid === failedAccountId) continue;
13564
+ const acct = accounts.get(aid);
13565
+ if (acct?.botIdentityId) {
13566
+ fallbackClient = client;
13567
+ fallbackBotIdentityId = acct.botIdentityId;
13568
+ fallbackAccountId = aid;
13569
+ break;
13570
+ }
13571
+ }
13572
+ if (!fallbackClient || !fallbackBotIdentityId) {
13573
+ log?.warn?.(`[${failedAccountId}] No fallback account available to notify groups about rate limit`);
13574
+ return;
13575
+ }
13576
+ log?.info?.(`[${failedAccountId}] Using fallback account "${fallbackAccountId}" to notify groups`);
13577
+ try {
13578
+ const failedGateway = gateways.get(failedAccountId);
13579
+ let groupIds = failedGateway?.getGroupIds() ?? [];
13580
+ if (groupIds.length === 0) {
13581
+ groupIds = await loadGroupIdsFromCursors(failedAccountId);
13582
+ if (groupIds.length > 0) {
13583
+ log?.info?.(`[${failedAccountId}] Loaded ${groupIds.length} group(s) from persisted cursors`);
13584
+ }
13585
+ }
13586
+ if (groupIds.length === 0) {
13587
+ log?.info?.(`[${failedAccountId}] No groups found (first-ever start) \u2014 cannot notify`);
13588
+ return;
13589
+ }
13590
+ const notifyGroups = groupIds.slice(0, 10);
13591
+ const message = `\u26A0\uFE0F **${failedAccountId}** is temporarily unavailable \u2014 ${reason}. Messages to this bot will not be delivered until the limit resets.`;
13592
+ let notified = 0;
13593
+ for (const groupId of notifyGroups) {
13594
+ try {
13595
+ await fallbackClient.sendMessage(groupId, {
13596
+ senderIdentityId: fallbackBotIdentityId,
13597
+ plaintext: message
13598
+ });
13599
+ notified++;
13600
+ log?.info?.(`[${failedAccountId}] Notified group ${groupId} via ${fallbackAccountId}`);
13601
+ } catch (sendErr) {
13602
+ const status = sendErr instanceof QuiuboApiError ? ` [${sendErr.status}]` : "";
13603
+ log?.debug?.(`[${failedAccountId}] Could not notify group ${groupId}${status} \u2014 fallback account may not be a member`);
13604
+ }
13605
+ }
13606
+ if (notified === 0) {
13607
+ log?.warn?.(`[${failedAccountId}] Could not notify any groups \u2014 fallback account "${fallbackAccountId}" is not a member of the failed account's groups`);
13608
+ }
13609
+ } catch (err) {
13610
+ log?.warn?.(`[${failedAccountId}] Failed to send rate limit notifications: ${err}`);
13611
+ }
13612
+ }
13440
13613
  function getChannelConfig(cfg) {
13441
13614
  return cfg.channels?.[CHANNEL_ID];
13442
13615
  }
@@ -13532,6 +13705,11 @@ var quiuboPlugin = {
13532
13705
  delete accts[id];
13533
13706
  return setChannelConfig(cfg, { ...channel, accounts: accts });
13534
13707
  },
13708
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13709
+ inspectAccount({ cfg, accountId }) {
13710
+ const id = accountId ?? DEFAULT_ACCOUNT_ID;
13711
+ return inspectAccount(cfg, id);
13712
+ },
13535
13713
  /**
13536
13714
  * Resolve a default delivery target for cron/announce when no --to is provided.
13537
13715
  * Scans the agent's session store for quiubo group sessions and returns the
@@ -13818,13 +13996,16 @@ var quiuboPlugin = {
13818
13996
  if (!senderId) {
13819
13997
  return { ok: false, error: "No botIdentityId configured" };
13820
13998
  }
13999
+ const rawReplyTo = ctx.replyTo ?? ctx.replyToMessageId ?? ctx.target?.raw?.replyToMessageId;
14000
+ const outboundReplyToId = typeof rawReplyTo === "string" && rawReplyTo.startsWith("quiubo-") ? rawReplyTo.slice("quiubo-".length) : typeof rawReplyTo === "string" && rawReplyTo.match(/^[0-9a-f]{8}-/i) ? rawReplyTo : void 0;
13821
14001
  try {
13822
14002
  const apiResp = await client.sendMessage(groupId, {
13823
14003
  senderIdentityId: senderId,
13824
14004
  plaintext: text,
13825
- metadata: { format: "markdown" }
14005
+ metadata: { format: "markdown" },
14006
+ ...outboundReplyToId ? { replyToMessageId: outboundReplyToId } : {}
13826
14007
  });
13827
- log?.info?.(`[${accountId}] [outbound:sendText] sent to group ${groupId} (realtime=${apiResp?.realtimeDelivered})`);
14008
+ log?.info?.(`[${accountId}] [outbound:sendText] sent to group ${groupId} (realtime=${apiResp?.realtimeDelivered}${outboundReplyToId ? `, replyTo=${outboundReplyToId}` : ""})`);
13828
14009
  return { ok: true };
13829
14010
  } catch (error) {
13830
14011
  if (error instanceof QuiuboApiError) {
@@ -14039,7 +14220,13 @@ var quiuboPlugin = {
14039
14220
  }
14040
14221
  } catch (error) {
14041
14222
  if (error instanceof QuiuboApiError) {
14042
- if (error.status === 401) {
14223
+ if (error.status === 429) {
14224
+ const isMonthlyLimit = error.body?.includes("monthly_limit");
14225
+ const reason = isMonthlyLimit ? "monthly API usage limit reached" : "rate limited";
14226
+ log?.error?.(`[${accountId}] Quiubo: [FATAL] STARTUP FAILED \u2014 ${reason} (429). ${error.body}`);
14227
+ updateAccountStatus(accountId, { connected: false });
14228
+ await notifyGroupsViaFallbackAccount(accountId, botIdentityId, reason, log);
14229
+ } else if (error.status === 401) {
14043
14230
  log?.error?.(`[${accountId}] Quiubo: [FATAL] STARTUP FAILED \u2014 API key is invalid or expired (401). Regenerate your SDK API key in the Quiubo dashboard.`);
14044
14231
  } else if (error.status === 403) {
14045
14232
  log?.error?.(`[${accountId}] Quiubo: [FATAL] STARTUP FAILED \u2014 API key lacks permissions (403). Check your SDK app tier and permissions.`);
@@ -14245,6 +14432,7 @@ var quiuboPlugin = {
14245
14432
  },
14246
14433
  onMessage: async (msg) => {
14247
14434
  log?.info?.(`[${accountId}] [delivery:onMessage] messageId=${msg.messageId} groupId=${msg.groupId} sender=${msg.senderIdentityId} text=${msg.plaintext?.slice(0, 80)}`);
14435
+ trackLastMessage(accountId);
14248
14436
  try {
14249
14437
  await routeInboundMessage({
14250
14438
  runtime: runtime2,
@@ -14361,6 +14549,14 @@ var quiuboPlugin = {
14361
14549
  await gateway.loadCursors();
14362
14550
  await gateway.start();
14363
14551
  log?.info?.(`[${accountId}] Quiubo: [OK] STARTUP COMPLETE \u2014 realtime=${pusherConfig ? "pusher" : "polling"}, agent=${resolvedAgentId ? resolvedAgentName : "none"}, e2ee=${keyManager ? "ready" : "off"}`);
14552
+ updateAccountStatus(accountId, {
14553
+ connected: true,
14554
+ groupCount: gateway.getGroupCount(),
14555
+ activeGroups: gateway.getGroupIds(),
14556
+ e2ee: !!keyManager,
14557
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
14558
+ pusherState: pusherConfig ? "connected" : void 0
14559
+ });
14364
14560
  return new Promise((resolve) => {
14365
14561
  const cleanup = () => {
14366
14562
  log?.info?.(`[${accountId}] Quiubo: gateway stopping`);
@@ -14369,6 +14565,7 @@ var quiuboPlugin = {
14369
14565
  clients.delete(accountId);
14370
14566
  accounts.delete(accountId);
14371
14567
  loggers.delete(accountId);
14568
+ clearAccountStatus(accountId);
14372
14569
  resolve();
14373
14570
  };
14374
14571
  if (abortSignal) {
@@ -14602,6 +14799,7 @@ async function routeInboundMessage(opts) {
14602
14799
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
14603
14800
  deliver: async (payload, info) => {
14604
14801
  const agentSource = info.kind === "subagent" ? "subagent" : "agent";
14802
+ const replyToMessageId = payload.replyToId?.startsWith("quiubo-") ? payload.replyToId.slice("quiubo-".length) : void 0;
14605
14803
  log?.info?.(`[${accountId}] [delivery:deliver-callback] FIRED for groupId=${groupId} (from closure), kind=${info.kind}, text=${payload.text?.length ?? 0} chars`);
14606
14804
  log?.info?.(`[${accountId}] Quiubo: deliver payload keys=${Object.keys(payload).join(",")}, mediaUrl=${payload.mediaUrl ? "yes" : "no"}, mediaUrls=${Array.isArray(payload.mediaUrls) ? payload.mediaUrls.length : "no"}, media=${Array.isArray(payload.media) ? payload.media.length : "no"}, text=${payload.text?.length ?? 0} chars`);
14607
14805
  if (Array.isArray(payload.media)) {
@@ -14669,7 +14867,8 @@ async function routeInboundMessage(opts) {
14669
14867
  senderIdentityId: botIdentityId,
14670
14868
  ...ciphertextOut ? { ciphertext: ciphertextOut } : { plaintext: payload.text || " " },
14671
14869
  metadata: { format: "markdown" },
14672
- ...nonImageAttachments.length > 0 ? { attachments: nonImageAttachments } : {}
14870
+ ...nonImageAttachments.length > 0 ? { attachments: nonImageAttachments } : {},
14871
+ ...replyToMessageId ? { replyToMessageId } : {}
14673
14872
  });
14674
14873
  if (apiResp?.realtimeDelivered === false) {
14675
14874
  log?.warn?.(`[${accountId}] Quiubo: reply persisted but Pusher delivery failed for group ${groupId} \u2014 clients will see on next poll`);
@@ -14713,17 +14912,13 @@ async function routeInboundMessage(opts) {
14713
14912
 
14714
14913
  // src/create-post-tool.ts
14715
14914
  import { readFile as readFile3 } from "fs/promises";
14716
- var IMAGE_MIME_TYPES2 = {
14717
- ".jpg": "image/jpeg",
14718
- ".jpeg": "image/jpeg",
14719
- ".png": "image/png",
14720
- ".webp": "image/webp"
14721
- };
14722
- var MAX_IMAGE_BYTES2 = 5 * 1024 * 1024;
14723
- var DEFAULT_API_URL2 = "https://api.quiubo.io";
14915
+
14916
+ // src/session-utils.ts
14724
14917
  function extractGroupIdFromSessionKey(key) {
14725
14918
  if (!key) return void 0;
14726
- const match = key.match(/quiubo:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i);
14919
+ const match = key.match(
14920
+ /quiubo:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i
14921
+ );
14727
14922
  return match?.[1];
14728
14923
  }
14729
14924
  function extractAgentIdFromSessionKey(key) {
@@ -14734,10 +14929,20 @@ function extractAgentIdFromSessionKey(key) {
14734
14929
  function resolveAccountId(config, agentId) {
14735
14930
  const bindings = config?.bindings ?? [];
14736
14931
  const matched = bindings.find(
14932
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14737
14933
  (b) => b?.match?.channel === "quiubo" && b?.agentId === agentId
14738
14934
  );
14739
14935
  return matched?.match?.accountId ?? "default";
14740
14936
  }
14937
+
14938
+ // src/create-post-tool.ts
14939
+ var IMAGE_MIME_TYPES2 = {
14940
+ ".jpg": "image/jpeg",
14941
+ ".jpeg": "image/jpeg",
14942
+ ".png": "image/png",
14943
+ ".webp": "image/webp"
14944
+ };
14945
+ var MAX_IMAGE_BYTES2 = 5 * 1024 * 1024;
14741
14946
  function jsonResult(payload) {
14742
14947
  return {
14743
14948
  content: [{ type: "text", text: JSON.stringify(payload) }],
@@ -14753,13 +14958,9 @@ function errorResult(msg) {
14753
14958
  function createQuiuboPostToolFactory(ctx) {
14754
14959
  const agentId = extractAgentIdFromSessionKey(ctx.sessionKey);
14755
14960
  const accountId = resolveAccountId(ctx.config, agentId);
14756
- const quiuboConfig = ctx.config?.channels?.quiubo;
14757
- const accountCfg = quiuboConfig?.accounts?.[accountId];
14758
- if (!accountCfg?.apiKey) return null;
14759
- const client = new QuiuboApiClient(
14760
- accountCfg.apiUrl ?? DEFAULT_API_URL2,
14761
- accountCfg.apiKey
14762
- );
14961
+ const client = clients.get(accountId);
14962
+ const accountCfg = accounts.get(accountId);
14963
+ if (!client || !accountCfg) return null;
14763
14964
  const botIdentityId = accountCfg.botIdentityId;
14764
14965
  const defaultGroupId = extractGroupIdFromSessionKey(ctx.sessionKey);
14765
14966
  return {
@@ -14850,33 +15051,13 @@ function getCached(groupId) {
14850
15051
  function setCache(groupId, data) {
14851
15052
  cache.set(groupId, { data, expiry: Date.now() + CACHE_TTL_MS });
14852
15053
  }
14853
- function extractGroupIdFromSessionKey2(key) {
14854
- if (!key) return void 0;
14855
- const match = key.match(
14856
- /quiubo:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i
14857
- );
14858
- return match?.[1];
14859
- }
14860
- function extractAgentIdFromSessionKey2(key) {
14861
- if (!key) return "main";
14862
- const match = key.match(/^agent:([^:]+):quiubo:/);
14863
- return match?.[1] ?? "main";
14864
- }
14865
- function resolveAccountId2(config, agentId) {
14866
- const bindings = config?.bindings ?? [];
14867
- const matched = bindings.find(
14868
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14869
- (b) => b?.match?.channel === "quiubo" && b?.agentId === agentId
14870
- );
14871
- return matched?.match?.accountId ?? "default";
14872
- }
14873
15054
  async function fetchGroupContext(config, sessionKey) {
14874
- const groupId = extractGroupIdFromSessionKey2(sessionKey);
15055
+ const groupId = extractGroupIdFromSessionKey(sessionKey);
14875
15056
  if (!groupId) return void 0;
14876
15057
  const cached = getCached(groupId);
14877
15058
  if (cached) return cached;
14878
- const agentId = extractAgentIdFromSessionKey2(sessionKey);
14879
- const accountId = resolveAccountId2(config, agentId);
15059
+ const agentId = extractAgentIdFromSessionKey(sessionKey);
15060
+ const accountId = resolveAccountId(config, agentId);
14880
15061
  const client = clients.get(accountId);
14881
15062
  const accountCfg = accounts.get(accountId);
14882
15063
  if (!client || !accountCfg) return void 0;
@@ -14891,10 +15072,19 @@ async function fetchGroupContext(config, sessionKey) {
14891
15072
  botIdentityIds.add(acct.botIdentityId);
14892
15073
  }
14893
15074
  }
15075
+ const channelAccounts = config?.channels?.quiubo?.accounts;
15076
+ if (channelAccounts && typeof channelAccounts === "object") {
15077
+ for (const acct of Object.values(channelAccounts)) {
15078
+ if (acct?.botIdentityId) {
15079
+ botIdentityIds.add(acct.botIdentityId);
15080
+ }
15081
+ }
15082
+ }
14894
15083
  const currentAgent = agents.find((a) => a.identityId === accountCfg.botIdentityId);
14895
15084
  const e2eeEnabled = currentAgent?.e2eeConfigured ?? false;
14896
15085
  let scopes = [];
14897
- if (currentAgent) {
15086
+ const isPartnerGroup = group.groupType === "agent_channel" || group.management === "partner";
15087
+ if (currentAgent && !isPartnerGroup) {
14898
15088
  try {
14899
15089
  const status = await client.getGroupAgent(currentAgent.id, groupId);
14900
15090
  scopes = status?.grantedScopes ?? [];
@@ -15101,6 +15291,7 @@ var plugin = {
15101
15291
  api.registerChannel({ plugin: quiuboPlugin });
15102
15292
  api.registerTool(createQuiuboPostToolFactory, { name: "quiubo_create_post" });
15103
15293
  registerGroupContextHook(api);
15294
+ registerStatusRpc(api);
15104
15295
  }
15105
15296
  };
15106
15297
  var index_default = plugin;