openclaw-quiubo 2.6.7 → 2.6.11
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
|
@@ -12470,6 +12470,11 @@ var RealtimeGateway = class {
|
|
|
12470
12470
|
pollTimer = null;
|
|
12471
12471
|
polling = false;
|
|
12472
12472
|
cursors = /* @__PURE__ */ new Map();
|
|
12473
|
+
/** Message IDs already dispatched (Pusher + poll dedup). Capped to prevent unbounded growth. */
|
|
12474
|
+
dispatched = /* @__PURE__ */ new Set();
|
|
12475
|
+
// Cached directory group IDs from listAgentGroups (refreshed every 60s)
|
|
12476
|
+
agentGroupsCache = null;
|
|
12477
|
+
AGENT_GROUPS_TTL = 6e4;
|
|
12473
12478
|
// Bot config cache (per group)
|
|
12474
12479
|
botConfigCache = /* @__PURE__ */ new Map();
|
|
12475
12480
|
// Owner takeover suppression: groupId → suppressedUntil timestamp
|
|
@@ -12503,6 +12508,13 @@ var RealtimeGateway = class {
|
|
|
12503
12508
|
setBotConfig(groupId, config) {
|
|
12504
12509
|
this.botConfigCache.set(groupId, config);
|
|
12505
12510
|
}
|
|
12511
|
+
/** Track a dispatched message ID (capped at 500 to prevent unbounded growth) */
|
|
12512
|
+
markDispatched(messageId) {
|
|
12513
|
+
this.dispatched.add(messageId);
|
|
12514
|
+
if (this.dispatched.size > 500) {
|
|
12515
|
+
this.dispatched.clear();
|
|
12516
|
+
}
|
|
12517
|
+
}
|
|
12506
12518
|
/** Get bot config for a group (for outbound scope checks) */
|
|
12507
12519
|
getBotConfig(groupId) {
|
|
12508
12520
|
return this.botConfigCache.get(groupId);
|
|
@@ -12599,12 +12611,13 @@ var RealtimeGateway = class {
|
|
|
12599
12611
|
*/
|
|
12600
12612
|
async start() {
|
|
12601
12613
|
this.stopped = false;
|
|
12614
|
+
console.log(`[gw:start] botIdentityId=${this.botIdentityId} pusher=${!!this.pusherConfig} agentId=${this.agentId}`);
|
|
12615
|
+
this.startPolling();
|
|
12616
|
+
if (this.agentId) this.startHeartbeat();
|
|
12602
12617
|
if (this.pusherConfig) {
|
|
12603
12618
|
await this.startPusher();
|
|
12604
12619
|
} else {
|
|
12605
|
-
|
|
12606
|
-
this.startPolling();
|
|
12607
|
-
if (this.agentId) this.startHeartbeat();
|
|
12620
|
+
console.log("[gw:start] No Pusher config \u2014 polling only");
|
|
12608
12621
|
}
|
|
12609
12622
|
}
|
|
12610
12623
|
/**
|
|
@@ -12638,6 +12651,7 @@ var RealtimeGateway = class {
|
|
|
12638
12651
|
// ── Pusher ──────────────────────────────────────────────────────
|
|
12639
12652
|
async startPusher() {
|
|
12640
12653
|
if (!this.pusherConfig) return;
|
|
12654
|
+
console.log(`[gw:startPusher] botIdentityId=${this.botIdentityId} key=${this.pusherConfig.key} cluster=${this.pusherConfig.cluster}`);
|
|
12641
12655
|
this.log.info?.(`[gateway] startPusher called for botIdentityId=${this.botIdentityId}`);
|
|
12642
12656
|
const { key, cluster } = this.pusherConfig;
|
|
12643
12657
|
const apiClient = this.client;
|
|
@@ -12659,12 +12673,13 @@ var RealtimeGateway = class {
|
|
|
12659
12673
|
})
|
|
12660
12674
|
});
|
|
12661
12675
|
this.pusherClient.connection.bind("state_change", (states) => {
|
|
12676
|
+
console.log(`[gw:pusher] state: ${states.previous} \u2192 ${states.current}`);
|
|
12662
12677
|
log.info?.(`Pusher state: ${states.previous} \u2192 ${states.current}`);
|
|
12663
12678
|
});
|
|
12664
12679
|
this.pusherClient.connection.bind("connected", () => {
|
|
12665
12680
|
this.pusherConnected = true;
|
|
12666
|
-
log
|
|
12667
|
-
|
|
12681
|
+
console.log("[gw:pusher] connected");
|
|
12682
|
+
log.info?.("Pusher connected (polling continues as safety net)");
|
|
12668
12683
|
if (this.agentId) this.startHeartbeat();
|
|
12669
12684
|
});
|
|
12670
12685
|
this.pusherClient.connection.bind("disconnected", () => {
|
|
@@ -12754,16 +12769,18 @@ var RealtimeGateway = class {
|
|
|
12754
12769
|
agentDisplayName: this.agentDisplayName ?? void 0,
|
|
12755
12770
|
securityMode: data.securityMode
|
|
12756
12771
|
});
|
|
12772
|
+
this.agentGroupsCache = null;
|
|
12757
12773
|
});
|
|
12758
12774
|
channel.bind("agent:group-removed", (data) => {
|
|
12759
12775
|
log.info?.(`agent:group-removed for group ${data.groupId}`);
|
|
12760
12776
|
this.botConfigCache.delete(data.groupId);
|
|
12777
|
+
this.agentGroupsCache = null;
|
|
12761
12778
|
});
|
|
12762
12779
|
channel.bind_global((eventName, data) => {
|
|
12763
|
-
|
|
12764
|
-
log.info?.(`[pusher:raw] event=${eventName} data=${JSON.stringify(data).slice(0, 300)}`);
|
|
12780
|
+
console.log(`[gw:pusher:raw] event=${eventName} data=${JSON.stringify(data).slice(0, 200)}`);
|
|
12765
12781
|
});
|
|
12766
12782
|
channel.bind("new-group-message", (data) => {
|
|
12783
|
+
console.log(`[gw:pusher:msg] messageId=${data.messageId} groupId=${data.groupId} sender=${data.senderUsername} plaintext=${!!data.plaintext} ciphertext=${!!data.ciphertext}`);
|
|
12767
12784
|
log.info?.(`Pusher event: messageId=${data.messageId} groupId=${data.groupId} sender=${data.senderUsername} plaintext=${!!data.plaintext} ciphertext=${!!data.ciphertext} botId=${this.botIdentityId}`);
|
|
12768
12785
|
if (data.senderId === this.botIdentityId) return;
|
|
12769
12786
|
this.shouldProcessMessage(data.groupId, data.senderId, {
|
|
@@ -12778,6 +12795,7 @@ var RealtimeGateway = class {
|
|
|
12778
12795
|
if (!shouldProcess) return;
|
|
12779
12796
|
if (data.plaintext) {
|
|
12780
12797
|
this.cursors.set(data.groupId, data.messageId);
|
|
12798
|
+
this.markDispatched(data.messageId);
|
|
12781
12799
|
Promise.resolve(this.onMessage({
|
|
12782
12800
|
messageId: data.messageId,
|
|
12783
12801
|
groupId: data.groupId,
|
|
@@ -12805,6 +12823,7 @@ var RealtimeGateway = class {
|
|
|
12805
12823
|
const plaintext = decryptGroupMessage(data.ciphertext, cached.key);
|
|
12806
12824
|
log.info?.(`[e2ee:pusher] group=${data.groupId} decrypted OK: ${plaintext?.length} chars \u2014 routing to onMessage`);
|
|
12807
12825
|
this.cursors.set(data.groupId, data.messageId);
|
|
12826
|
+
this.markDispatched(data.messageId);
|
|
12808
12827
|
return Promise.resolve(this.onMessage({
|
|
12809
12828
|
messageId: data.messageId,
|
|
12810
12829
|
groupId: data.groupId,
|
|
@@ -12856,6 +12875,8 @@ var RealtimeGateway = class {
|
|
|
12856
12875
|
this.log.warn?.(`Message ${messageId} has no plaintext`);
|
|
12857
12876
|
return;
|
|
12858
12877
|
}
|
|
12878
|
+
if (this.dispatched.has(msg.id)) return;
|
|
12879
|
+
this.markDispatched(msg.id);
|
|
12859
12880
|
await this.onMessage({
|
|
12860
12881
|
messageId: msg.id,
|
|
12861
12882
|
groupId,
|
|
@@ -12877,6 +12898,7 @@ var RealtimeGateway = class {
|
|
|
12877
12898
|
// ── Polling (fallback) ──────────────────────────────────────────
|
|
12878
12899
|
startPolling() {
|
|
12879
12900
|
if (this.pollTimer) return;
|
|
12901
|
+
console.log(`[gw:startPolling] botIdentityId=${this.botIdentityId} interval=${this.pollIntervalMs}ms`);
|
|
12880
12902
|
this.log.info?.(`[gateway] startPolling called for botIdentityId=${this.botIdentityId}`);
|
|
12881
12903
|
this.poll();
|
|
12882
12904
|
this.pollTimer = setInterval(() => this.poll(), this.pollIntervalMs);
|
|
@@ -12887,8 +12909,57 @@ var RealtimeGateway = class {
|
|
|
12887
12909
|
this.pollTimer = null;
|
|
12888
12910
|
}
|
|
12889
12911
|
}
|
|
12912
|
+
/**
|
|
12913
|
+
* Get directory group IDs, refreshing from API every AGENT_GROUPS_TTL ms.
|
|
12914
|
+
* Falls back to botConfigCache if the API call fails.
|
|
12915
|
+
* Pusher agent:group-added/removed events also invalidate the cache.
|
|
12916
|
+
*/
|
|
12917
|
+
async getDirectoryGroupIds() {
|
|
12918
|
+
if (!this.agentId) {
|
|
12919
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12920
|
+
for (const [gid, config] of this.botConfigCache) {
|
|
12921
|
+
if (config.source === "directory" && config.enabled) ids.add(gid);
|
|
12922
|
+
}
|
|
12923
|
+
return ids;
|
|
12924
|
+
}
|
|
12925
|
+
const now = Date.now();
|
|
12926
|
+
if (this.agentGroupsCache && now - this.agentGroupsCache.fetchedAt < this.AGENT_GROUPS_TTL) {
|
|
12927
|
+
return this.agentGroupsCache.groupIds;
|
|
12928
|
+
}
|
|
12929
|
+
try {
|
|
12930
|
+
const { groups: agentGroups } = await this.client.listAgentGroups(this.agentId);
|
|
12931
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12932
|
+
for (const ag of agentGroups) {
|
|
12933
|
+
if (ag.source === "directory" && (ag.enabled ?? true)) {
|
|
12934
|
+
ids.add(ag.groupId);
|
|
12935
|
+
if (!this.botConfigCache.has(ag.groupId)) {
|
|
12936
|
+
this.botConfigCache.set(ag.groupId, {
|
|
12937
|
+
enabled: ag.enabled ?? true,
|
|
12938
|
+
suppressionMinutes: 10,
|
|
12939
|
+
ownerIdentityId: "",
|
|
12940
|
+
groupType: ag.groupType ?? "standard",
|
|
12941
|
+
source: "directory",
|
|
12942
|
+
grantedScopes: ag.grantedScopes,
|
|
12943
|
+
agentDisplayName: ag.agentDisplayName ?? this.agentDisplayName ?? void 0,
|
|
12944
|
+
securityMode: ag.securityMode
|
|
12945
|
+
});
|
|
12946
|
+
}
|
|
12947
|
+
}
|
|
12948
|
+
}
|
|
12949
|
+
this.agentGroupsCache = { groupIds: ids, fetchedAt: now };
|
|
12950
|
+
return ids;
|
|
12951
|
+
} catch (err) {
|
|
12952
|
+
this.log.warn?.(`listAgentGroups failed: ${err}, using cache`);
|
|
12953
|
+
if (this.agentGroupsCache) return this.agentGroupsCache.groupIds;
|
|
12954
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12955
|
+
for (const [gid, config] of this.botConfigCache) {
|
|
12956
|
+
if (config.source === "directory" && config.enabled) ids.add(gid);
|
|
12957
|
+
}
|
|
12958
|
+
return ids;
|
|
12959
|
+
}
|
|
12960
|
+
}
|
|
12890
12961
|
async poll() {
|
|
12891
|
-
if (this.polling
|
|
12962
|
+
if (this.polling) return;
|
|
12892
12963
|
this.polling = true;
|
|
12893
12964
|
try {
|
|
12894
12965
|
this.clearStaleSuppression();
|
|
@@ -12906,11 +12977,9 @@ var RealtimeGateway = class {
|
|
|
12906
12977
|
}
|
|
12907
12978
|
}
|
|
12908
12979
|
const groupIds = new Set(groups.map((g) => g.id));
|
|
12909
|
-
|
|
12910
|
-
|
|
12911
|
-
|
|
12912
|
-
}
|
|
12913
|
-
}
|
|
12980
|
+
const directoryIds = await this.getDirectoryGroupIds();
|
|
12981
|
+
for (const gid of directoryIds) groupIds.add(gid);
|
|
12982
|
+
console.log(`[gw:poll] partner=${groups.length} directory=${directoryIds.size} total=${groupIds.size} groups=[${[...groupIds].join(", ")}]`);
|
|
12914
12983
|
await Promise.allSettled(
|
|
12915
12984
|
[...groupIds].map((gid) => this.pollGroup(gid))
|
|
12916
12985
|
);
|
|
@@ -12923,7 +12992,7 @@ var RealtimeGateway = class {
|
|
|
12923
12992
|
async pollGroup(groupId) {
|
|
12924
12993
|
try {
|
|
12925
12994
|
const cursor = this.cursors.get(groupId);
|
|
12926
|
-
|
|
12995
|
+
console.log(`[gw:pollGroup] group=${groupId} cursor=${cursor ?? "none"}`);
|
|
12927
12996
|
const { messages } = await this.client.listMessages(groupId, cursor);
|
|
12928
12997
|
if (messages.length === 0) return;
|
|
12929
12998
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -12947,8 +13016,17 @@ var RealtimeGateway = class {
|
|
|
12947
13016
|
}
|
|
12948
13017
|
if (!plaintext) continue;
|
|
12949
13018
|
const shouldProcess = await this.shouldProcessMessage(groupId, msg.senderIdentityId, { plaintext });
|
|
12950
|
-
if (!shouldProcess)
|
|
13019
|
+
if (!shouldProcess) {
|
|
13020
|
+
console.log(`[gw:pollGroup] skipping msg=${msg.id} in group=${groupId} (shouldProcess=false)`);
|
|
13021
|
+
continue;
|
|
13022
|
+
}
|
|
13023
|
+
if (this.dispatched.has(msg.id)) {
|
|
13024
|
+
console.log(`[gw:pollGroup] skipping msg=${msg.id} in group=${groupId} (already dispatched)`);
|
|
13025
|
+
continue;
|
|
13026
|
+
}
|
|
12951
13027
|
try {
|
|
13028
|
+
console.log(`[gw:pollGroup] dispatching msg=${msg.id} group=${groupId} text=${plaintext?.slice(0, 60)}`);
|
|
13029
|
+
this.markDispatched(msg.id);
|
|
12952
13030
|
await this.onMessage({
|
|
12953
13031
|
messageId: msg.id,
|
|
12954
13032
|
groupId,
|