@clawling/clawchat-plugin-openclaw 2026.7.1 → 2026.7.2
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/src/config.js +23 -1
- package/dist/src/runtime.js +21 -6
- package/package.json +1 -1
- package/src/config.ts +28 -1
- package/src/runtime.ts +24 -7
package/dist/src/config.js
CHANGED
|
@@ -207,6 +207,28 @@ function decodeJwtStringClaim(token, claim) {
|
|
|
207
207
|
return "";
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Resolve the bot-account userId, validated against the token's `sub` claim.
|
|
212
|
+
*
|
|
213
|
+
* The WS session authenticates with the access token, so the backend binds the
|
|
214
|
+
* session to the token's `sub` — that IS the bot's user id for this session.
|
|
215
|
+
* Unlike ownerUserId (explicit config wins over the `oid` claim), a configured
|
|
216
|
+
* userId that disagrees with `sub` is always wrong for the session this token
|
|
217
|
+
* creates, and it silently breaks self-echo detection: with the OWNER's id
|
|
218
|
+
* here, every owner message is dropped as the bot's own echo (2026-07-02
|
|
219
|
+
* clawnest incident — a provisioner wrote the owner id into the config). Token
|
|
220
|
+
* wins; the mismatch is logged. Also derives userId from `sub` when nothing is
|
|
221
|
+
* configured, mirroring the `oid` fallback above.
|
|
222
|
+
*/
|
|
223
|
+
function resolveUserId(token, configured) {
|
|
224
|
+
const tokenSub = decodeJwtStringClaim(token, "sub");
|
|
225
|
+
if (!tokenSub)
|
|
226
|
+
return configured;
|
|
227
|
+
if (configured && configured !== tokenSub) {
|
|
228
|
+
console.warn(`clawchat userId mismatch: configured ${configured} does not equal the access token's sub claim ${tokenSub}; using the token value. A misconfigured userId (e.g. the owner's id) breaks self-echo detection and mention gating — fix the channel userId / CLAWCHAT_USER_ID.`);
|
|
229
|
+
}
|
|
230
|
+
return tokenSub;
|
|
231
|
+
}
|
|
210
232
|
function readGroupMode(value) {
|
|
211
233
|
return value === "mention" ? "mention" : "all";
|
|
212
234
|
}
|
|
@@ -312,7 +334,7 @@ export function resolveOpenclawClawlingAccount(cfg, env = process.env) {
|
|
|
312
334
|
const mediaBaseUrl = readOptionalString(channel.mediaBaseUrl) || readEnvString(env, CLAWCHAT_MEDIA_BASE_URL_ENV);
|
|
313
335
|
const token = readOptionalString(channel.token) || readEnvString(env, CLAWCHAT_TOKEN_ENV);
|
|
314
336
|
const agentId = readOptionalString(channel.agentId) || readEnvString(env, CLAWCHAT_AGENT_ID_ENV);
|
|
315
|
-
const userId = readOptionalString(channel.userId) || readEnvString(env, CLAWCHAT_USER_ID_ENV);
|
|
337
|
+
const userId = resolveUserId(token, readOptionalString(channel.userId) || readEnvString(env, CLAWCHAT_USER_ID_ENV));
|
|
316
338
|
const ownerUserId = readOptionalString(channel.ownerUserId) ||
|
|
317
339
|
readEnvString(env, CLAWCHAT_OWNER_USER_ID_ENV) ||
|
|
318
340
|
// Fall back to the access token's `oid` (owner) claim. A provisioner may
|
package/dist/src/runtime.js
CHANGED
|
@@ -1771,14 +1771,29 @@ export async function startOpenclawClawlingGateway(params) {
|
|
|
1771
1771
|
catch (err) {
|
|
1772
1772
|
log?.info?.(`[${accountId}] clawchat-plugin-openclaw skill-update: bundled skills dir not resolvable (using managed-only current): ${err instanceof Error ? err.message : String(err)}`);
|
|
1773
1773
|
}
|
|
1774
|
-
|
|
1774
|
+
// A usr_... id is not a valid chat_id — member-backend rejects it with
|
|
1775
|
+
// "invalid conversation id" and msghub never acks the send. Proactive owner
|
|
1776
|
+
// messages must be addressed to the direct conversation recorded at
|
|
1777
|
+
// activation (parity with the hermes adapter's _owner_direct_chat_id).
|
|
1778
|
+
const resolveOwnerDirectConversationId = () => {
|
|
1775
1779
|
const ownerUserId = account.ownerUserId?.trim();
|
|
1776
1780
|
if (!ownerUserId)
|
|
1781
|
+
return null;
|
|
1782
|
+
const conversationId = store
|
|
1783
|
+
?.getActivationConversation?.({ platform: "openclaw", accountId })
|
|
1784
|
+
?.conversationId?.trim();
|
|
1785
|
+
return conversationId || null;
|
|
1786
|
+
};
|
|
1787
|
+
const sendOwnerSkillMessage = async (text) => {
|
|
1788
|
+
const conversationId = resolveOwnerDirectConversationId();
|
|
1789
|
+
if (!conversationId) {
|
|
1790
|
+
log?.info?.(`[${accountId}] clawchat-plugin-openclaw skill-update owner message skipped: no activation conversation recorded`);
|
|
1777
1791
|
return;
|
|
1792
|
+
}
|
|
1778
1793
|
await sendOpenclawClawlingText({
|
|
1779
1794
|
client,
|
|
1780
1795
|
account,
|
|
1781
|
-
to: { chatId:
|
|
1796
|
+
to: { chatId: conversationId, chatType: "direct" },
|
|
1782
1797
|
text,
|
|
1783
1798
|
log,
|
|
1784
1799
|
});
|
|
@@ -2408,16 +2423,16 @@ export async function startOpenclawClawlingGateway(params) {
|
|
|
2408
2423
|
},
|
|
2409
2424
|
});
|
|
2410
2425
|
const forwardGroupApprovalSlashToOwner = async (turn) => {
|
|
2411
|
-
const
|
|
2412
|
-
if (!
|
|
2413
|
-
log?.error?.(`[${accountId}] clawchat-plugin-openclaw group approval command suppressed reason=
|
|
2426
|
+
const ownerConversationId = resolveOwnerDirectConversationId();
|
|
2427
|
+
if (!ownerConversationId) {
|
|
2428
|
+
log?.error?.(`[${accountId}] clawchat-plugin-openclaw group approval command suppressed reason=missing_owner_conversation chat_id=${turn.peer.id} msg=${turn.messageId}`);
|
|
2414
2429
|
return "skipped";
|
|
2415
2430
|
}
|
|
2416
2431
|
try {
|
|
2417
2432
|
await sendOpenclawClawlingText({
|
|
2418
2433
|
client,
|
|
2419
2434
|
account,
|
|
2420
|
-
to: { chatId:
|
|
2435
|
+
to: { chatId: ownerConversationId, chatType: "direct" },
|
|
2421
2436
|
text: groupOwnerAttentionText(turn.peer.id, turn.rawBody),
|
|
2422
2437
|
log,
|
|
2423
2438
|
});
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -332,6 +332,30 @@ function decodeJwtStringClaim(token: string, claim: string): string {
|
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Resolve the bot-account userId, validated against the token's `sub` claim.
|
|
337
|
+
*
|
|
338
|
+
* The WS session authenticates with the access token, so the backend binds the
|
|
339
|
+
* session to the token's `sub` — that IS the bot's user id for this session.
|
|
340
|
+
* Unlike ownerUserId (explicit config wins over the `oid` claim), a configured
|
|
341
|
+
* userId that disagrees with `sub` is always wrong for the session this token
|
|
342
|
+
* creates, and it silently breaks self-echo detection: with the OWNER's id
|
|
343
|
+
* here, every owner message is dropped as the bot's own echo (2026-07-02
|
|
344
|
+
* clawnest incident — a provisioner wrote the owner id into the config). Token
|
|
345
|
+
* wins; the mismatch is logged. Also derives userId from `sub` when nothing is
|
|
346
|
+
* configured, mirroring the `oid` fallback above.
|
|
347
|
+
*/
|
|
348
|
+
function resolveUserId(token: string, configured: string): string {
|
|
349
|
+
const tokenSub = decodeJwtStringClaim(token, "sub");
|
|
350
|
+
if (!tokenSub) return configured;
|
|
351
|
+
if (configured && configured !== tokenSub) {
|
|
352
|
+
console.warn(
|
|
353
|
+
`clawchat userId mismatch: configured ${configured} does not equal the access token's sub claim ${tokenSub}; using the token value. A misconfigured userId (e.g. the owner's id) breaks self-echo detection and mention gating — fix the channel userId / CLAWCHAT_USER_ID.`,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
return tokenSub;
|
|
357
|
+
}
|
|
358
|
+
|
|
335
359
|
function readGroupMode(value: unknown): GroupMode {
|
|
336
360
|
return value === "mention" ? "mention" : "all";
|
|
337
361
|
}
|
|
@@ -465,7 +489,10 @@ export function resolveOpenclawClawlingAccount(
|
|
|
465
489
|
readOptionalString(channel.mediaBaseUrl) || readEnvString(env, CLAWCHAT_MEDIA_BASE_URL_ENV);
|
|
466
490
|
const token = readOptionalString(channel.token) || readEnvString(env, CLAWCHAT_TOKEN_ENV);
|
|
467
491
|
const agentId = readOptionalString(channel.agentId) || readEnvString(env, CLAWCHAT_AGENT_ID_ENV);
|
|
468
|
-
const userId =
|
|
492
|
+
const userId = resolveUserId(
|
|
493
|
+
token,
|
|
494
|
+
readOptionalString(channel.userId) || readEnvString(env, CLAWCHAT_USER_ID_ENV),
|
|
495
|
+
);
|
|
469
496
|
const ownerUserId =
|
|
470
497
|
readOptionalString(channel.ownerUserId) ||
|
|
471
498
|
readEnvString(env, CLAWCHAT_OWNER_USER_ID_ENV) ||
|
package/src/runtime.ts
CHANGED
|
@@ -2166,13 +2166,30 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
|
|
|
2166
2166
|
}`,
|
|
2167
2167
|
);
|
|
2168
2168
|
}
|
|
2169
|
-
|
|
2169
|
+
// A usr_... id is not a valid chat_id — member-backend rejects it with
|
|
2170
|
+
// "invalid conversation id" and msghub never acks the send. Proactive owner
|
|
2171
|
+
// messages must be addressed to the direct conversation recorded at
|
|
2172
|
+
// activation (parity with the hermes adapter's _owner_direct_chat_id).
|
|
2173
|
+
const resolveOwnerDirectConversationId = (): string | null => {
|
|
2170
2174
|
const ownerUserId = account.ownerUserId?.trim();
|
|
2171
|
-
if (!ownerUserId) return;
|
|
2175
|
+
if (!ownerUserId) return null;
|
|
2176
|
+
const conversationId = store
|
|
2177
|
+
?.getActivationConversation?.({ platform: "openclaw", accountId })
|
|
2178
|
+
?.conversationId?.trim();
|
|
2179
|
+
return conversationId || null;
|
|
2180
|
+
};
|
|
2181
|
+
const sendOwnerSkillMessage = async (text: string): Promise<void> => {
|
|
2182
|
+
const conversationId = resolveOwnerDirectConversationId();
|
|
2183
|
+
if (!conversationId) {
|
|
2184
|
+
log?.info?.(
|
|
2185
|
+
`[${accountId}] clawchat-plugin-openclaw skill-update owner message skipped: no activation conversation recorded`,
|
|
2186
|
+
);
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2172
2189
|
await sendOpenclawClawlingText({
|
|
2173
2190
|
client,
|
|
2174
2191
|
account,
|
|
2175
|
-
to: { chatId:
|
|
2192
|
+
to: { chatId: conversationId, chatType: "direct" },
|
|
2176
2193
|
text,
|
|
2177
2194
|
log,
|
|
2178
2195
|
});
|
|
@@ -2886,10 +2903,10 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
|
|
|
2886
2903
|
});
|
|
2887
2904
|
|
|
2888
2905
|
const forwardGroupApprovalSlashToOwner = async (turn: IngestTurnParams): Promise<IngestTurnResult> => {
|
|
2889
|
-
const
|
|
2890
|
-
if (!
|
|
2906
|
+
const ownerConversationId = resolveOwnerDirectConversationId();
|
|
2907
|
+
if (!ownerConversationId) {
|
|
2891
2908
|
log?.error?.(
|
|
2892
|
-
`[${accountId}] clawchat-plugin-openclaw group approval command suppressed reason=
|
|
2909
|
+
`[${accountId}] clawchat-plugin-openclaw group approval command suppressed reason=missing_owner_conversation chat_id=${turn.peer.id} msg=${turn.messageId}`,
|
|
2893
2910
|
);
|
|
2894
2911
|
return "skipped";
|
|
2895
2912
|
}
|
|
@@ -2897,7 +2914,7 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
|
|
|
2897
2914
|
await sendOpenclawClawlingText({
|
|
2898
2915
|
client,
|
|
2899
2916
|
account,
|
|
2900
|
-
to: { chatId:
|
|
2917
|
+
to: { chatId: ownerConversationId, chatType: "direct" },
|
|
2901
2918
|
text: groupOwnerAttentionText(turn.peer.id, turn.rawBody),
|
|
2902
2919
|
log,
|
|
2903
2920
|
});
|