@clawling/clawchat-plugin-openclaw 2026.6.16-1 → 2026.6.16-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.
@@ -185,6 +185,27 @@ function readOptionalString(value) {
185
185
  function readEnvString(env, key) {
186
186
  return readOptionalString(env[key]);
187
187
  }
188
+ /**
189
+ * Decode a string claim from a JWT access token's payload (no signature
190
+ * verification — this is for self-identifying claims the backend already signed,
191
+ * e.g. `oid` owner id). Returns "" on any malformed input.
192
+ */
193
+ function decodeJwtStringClaim(token, claim) {
194
+ if (typeof token !== "string")
195
+ return "";
196
+ const segments = token.split(".");
197
+ if (segments.length < 2 || !segments[1])
198
+ return "";
199
+ try {
200
+ const json = Buffer.from(segments[1], "base64url").toString("utf8");
201
+ const parsed = JSON.parse(json);
202
+ const value = parsed?.[claim];
203
+ return typeof value === "string" ? value.trim() : "";
204
+ }
205
+ catch {
206
+ return "";
207
+ }
208
+ }
188
209
  function readGroupMode(value) {
189
210
  return value === "mention" ? "mention" : "all";
190
211
  }
@@ -291,7 +312,13 @@ export function resolveOpenclawClawlingAccount(cfg, env = process.env) {
291
312
  const token = readOptionalString(channel.token) || readEnvString(env, CLAWCHAT_TOKEN_ENV);
292
313
  const agentId = readOptionalString(channel.agentId) || readEnvString(env, CLAWCHAT_AGENT_ID_ENV);
293
314
  const userId = readOptionalString(channel.userId) || readEnvString(env, CLAWCHAT_USER_ID_ENV);
294
- const ownerUserId = readOptionalString(channel.ownerUserId) || readEnvString(env, CLAWCHAT_OWNER_USER_ID_ENV);
315
+ const ownerUserId = readOptionalString(channel.ownerUserId) ||
316
+ readEnvString(env, CLAWCHAT_OWNER_USER_ID_ENV) ||
317
+ // Fall back to the access token's `oid` (owner) claim. A provisioner may
318
+ // inject token + userId but omit ownerUserId; without it the connect gate
319
+ // (hasOpenclawClawlingConnectCredentials) never passes and the plugin sits
320
+ // in the wait-for-activation loop. The owner is always carried in the token.
321
+ decodeJwtStringClaim(token, "oid");
295
322
  const enabled = typeof channel.enabled === "boolean" ? channel.enabled : true;
296
323
  const outputVisibility = readOutputVisibility(channel.outputVisibility);
297
324
  const chats = readChats(channel.chats);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawling/clawchat-plugin-openclaw",
3
- "version": "2026.6.16-1",
3
+ "version": "2026.6.16-2",
4
4
  "description": "OpenClaw ClawChat channel plugin",
5
5
  "license": "MIT",
6
6
  "files": [
package/src/config.ts CHANGED
@@ -309,6 +309,25 @@ function readEnvString(env: Record<string, string | undefined>, key: string): st
309
309
  return readOptionalString(env[key]);
310
310
  }
311
311
 
312
+ /**
313
+ * Decode a string claim from a JWT access token's payload (no signature
314
+ * verification — this is for self-identifying claims the backend already signed,
315
+ * e.g. `oid` owner id). Returns "" on any malformed input.
316
+ */
317
+ function decodeJwtStringClaim(token: string, claim: string): string {
318
+ if (typeof token !== "string") return "";
319
+ const segments = token.split(".");
320
+ if (segments.length < 2 || !segments[1]) return "";
321
+ try {
322
+ const json = Buffer.from(segments[1], "base64url").toString("utf8");
323
+ const parsed = JSON.parse(json) as Record<string, unknown>;
324
+ const value = parsed?.[claim];
325
+ return typeof value === "string" ? value.trim() : "";
326
+ } catch {
327
+ return "";
328
+ }
329
+ }
330
+
312
331
  function readGroupMode(value: unknown): GroupMode {
313
332
  return value === "mention" ? "mention" : "all";
314
333
  }
@@ -444,7 +463,13 @@ export function resolveOpenclawClawlingAccount(
444
463
  const agentId = readOptionalString(channel.agentId) || readEnvString(env, CLAWCHAT_AGENT_ID_ENV);
445
464
  const userId = readOptionalString(channel.userId) || readEnvString(env, CLAWCHAT_USER_ID_ENV);
446
465
  const ownerUserId =
447
- readOptionalString(channel.ownerUserId) || readEnvString(env, CLAWCHAT_OWNER_USER_ID_ENV);
466
+ readOptionalString(channel.ownerUserId) ||
467
+ readEnvString(env, CLAWCHAT_OWNER_USER_ID_ENV) ||
468
+ // Fall back to the access token's `oid` (owner) claim. A provisioner may
469
+ // inject token + userId but omit ownerUserId; without it the connect gate
470
+ // (hasOpenclawClawlingConnectCredentials) never passes and the plugin sits
471
+ // in the wait-for-activation loop. The owner is always carried in the token.
472
+ decodeJwtStringClaim(token, "oid");
448
473
  const enabled = typeof channel.enabled === "boolean" ? channel.enabled : true;
449
474
  const outputVisibility = readOutputVisibility(channel.outputVisibility);
450
475
  const chats = readChats(channel.chats);