@openclaw/googlechat 2026.7.1 → 2026.7.2-beta.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.
@@ -1,15 +1,73 @@
1
- import { A as readGoogleChatApprovalActionToken, C as verifyGoogleChatRequest, D as completeGoogleChatApprovalCardBinding, E as claimGoogleChatApprovalCardBinding, N as releaseGoogleChatApprovalCardBinding, S as uploadGoogleChatAttachment, _ as downloadGoogleChatMedia, b as sendGoogleChatMessage, c as isGoogleChatGroupSpace, h as deleteGoogleChatMessage, k as getGoogleChatApprovalCardBinding, x as updateGoogleChatMessage, y as probeGoogleChat } from "./channel.adapters-FEj7zUjh.js";
2
- import { E as resolveDefaultGroupPolicy, M as warnMissingProviderGroupPolicyFallbackOnce, O as resolveInboundRouteEnvelopeBuilderWithRuntime, P as getGoogleChatRuntime, k as resolveWebhookPath, m as isDangerousNameMatchingEnabled, n as GROUP_POLICY_BLOCKED_LABEL, u as createChannelPairingController, w as resolveAllowlistProviderRuntimeGroupPolicy } from "./runtime-api-BbVoWRxq.js";
3
- import { n as googleChatApprovalAuth } from "./approval-auth-C_BVZZFA.js";
1
+ import { A as releaseGoogleChatApprovalCardBinding, C as claimGoogleChatApprovalCardBinding, D as readGoogleChatApprovalActionToken, E as getGoogleChatApprovalCardBinding, _ as probeGoogleChat, b as verifyGoogleChatRequest, c as buildGoogleChatGroupPolicyScope, g as downloadGoogleChatMedia, h as deleteGoogleChatMessage, l as isGoogleChatGroupSpace, v as sendGoogleChatMessage, w as completeGoogleChatApprovalCardBinding, y as updateGoogleChatMessage } from "./channel.adapters-Dhy4lV4f.js";
2
+ import { C as resolveInboundRouteEnvelopeBuilderWithRuntime, D as warnMissingProviderGroupPolicyFallbackOnce, b as resolveAllowlistProviderRuntimeGroupPolicy, c as createChannelPairingController, f as isDangerousNameMatchingEnabled, k as getGoogleChatRuntime, n as GROUP_POLICY_BLOCKED_LABEL, w as resolveWebhookPath, x as resolveDefaultGroupPolicy } from "./runtime-api-1v-DgldF.js";
3
+ import { n as googleChatApprovalAuth } from "./approval-auth-B2m8ckdj.js";
4
4
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
6
6
  import { recordChannelBotPairLoopAndCheckSuppression } from "openclaw/plugin-sdk/channel-inbound";
7
7
  import { WEBHOOK_RATE_LIMIT_DEFAULTS, createFixedWindowRateLimiter, normalizeWebhookPath, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
8
8
  import { registerWebhookTargetWithPluginRoute, resolveWebhookTargetWithAuthOrReject, withResolvedWebhookRequestPipeline } from "openclaw/plugin-sdk/webhook-targets";
9
- import { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject } from "openclaw/plugin-sdk/webhook-request-guards";
9
+ import { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject, runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
10
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
10
11
  import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
11
12
  import { channelIngressRoutes, createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
12
- import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
13
+ import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
14
+ //#region extensions/googlechat/src/approval-terminal-card.ts
15
+ const GOOGLECHAT_APPROVAL_CARD_ID = "openclaw-approval";
16
+ const MAX_TEXT_PARAGRAPH_CHARS = 1800;
17
+ function escapeGoogleChatText(text) {
18
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19
+ }
20
+ function truncateText(text) {
21
+ return text.length <= MAX_TEXT_PARAGRAPH_CHARS ? text : `${truncateUtf16Safe(text, MAX_TEXT_PARAGRAPH_CHARS - 3)}...`;
22
+ }
23
+ function formatApprovalId(value) {
24
+ return JSON.stringify(value).slice(1, -1);
25
+ }
26
+ function formatCanonicalOutcome(approval) {
27
+ switch (approval.status) {
28
+ case "allowed": return approval.decision === "allow-always" ? "Allowed always" : "Allowed once";
29
+ case "denied": return "Denied";
30
+ case "expired": return "Expired";
31
+ case "cancelled": return "Cancelled";
32
+ }
33
+ return "Unavailable";
34
+ }
35
+ function buildSubjectSection(presentation) {
36
+ if (presentation.kind === "exec") return {
37
+ header: "Command",
38
+ widgets: [{ textParagraph: { text: escapeGoogleChatText(truncateText(presentation.commandPreview ?? presentation.commandText)) } }]
39
+ };
40
+ const description = presentation.description.trim();
41
+ return {
42
+ header: "Request",
43
+ widgets: [{ textParagraph: { text: truncateText(`<b>${escapeGoogleChatText(presentation.title)}</b>${description ? `<br>${escapeGoogleChatText(description)}` : ""}`) } }]
44
+ };
45
+ }
46
+ /** Render the canonical first-answer result without retaining any actionable buttons. */
47
+ function buildGoogleChatCanonicalApprovalTerminalCards(result) {
48
+ const { approval } = result;
49
+ const kindLabel = approval.presentation.kind === "plugin" ? "Plugin" : "Exec";
50
+ const detailLines = [
51
+ `<b>Approval ID:</b> ${escapeGoogleChatText(formatApprovalId(approval.id))}`,
52
+ `<b>Status:</b> ${escapeGoogleChatText(approval.status)}`,
53
+ ...approval.status === "allowed" || approval.status === "denied" ? [`<b>Decision:</b> ${escapeGoogleChatText(approval.decision)}`] : [],
54
+ `<b>Reason:</b> ${escapeGoogleChatText(approval.reason)}`
55
+ ];
56
+ return [{
57
+ cardId: GOOGLECHAT_APPROVAL_CARD_ID,
58
+ card: {
59
+ header: {
60
+ title: `${kindLabel} Approval: ${formatCanonicalOutcome(approval)}`,
61
+ subtitle: result.applied ? "Resolved by this action" : "Already resolved"
62
+ },
63
+ sections: [buildSubjectSection(approval.presentation), {
64
+ header: "Details",
65
+ widgets: [{ textParagraph: { text: truncateText(detailLines.join("<br>")) } }]
66
+ }]
67
+ }
68
+ }];
69
+ }
70
+ //#endregion
13
71
  //#region extensions/googlechat/src/approval-card-click.ts
14
72
  function logIgnored(target, message) {
15
73
  target.runtime.log?.(`[${target.account.accountId}] googlechat approval ignored: ${message}`);
@@ -60,21 +118,29 @@ async function maybeHandleGoogleChatApprovalCardClick(params) {
60
118
  return true;
61
119
  }
62
120
  const consumed = claim.binding;
121
+ let result;
63
122
  try {
64
- await resolveApprovalOverGateway({
123
+ result = await resolveApprovalOverGateway({
65
124
  cfg: params.target.config,
66
125
  approvalId: consumed.approvalId,
126
+ approvalKind: consumed.approvalKind,
67
127
  decision: consumed.decision,
68
128
  senderId: actor,
69
- allowPluginFallback: consumed.approvalKind === "exec",
70
129
  clientDisplayName: `Google Chat approval (${actor?.trim() || "unknown"})`
71
130
  });
131
+ await updateGoogleChatMessage({
132
+ account: params.target.account,
133
+ messageName: consumed.messageName,
134
+ cardsV2: buildGoogleChatCanonicalApprovalTerminalCards(result)
135
+ });
72
136
  } catch (error) {
73
137
  releaseGoogleChatApprovalCardBinding(token);
74
138
  throw error;
75
139
  }
76
140
  completeGoogleChatApprovalCardBinding(token);
77
- params.target.runtime.log?.(`[${params.target.account.accountId}] googlechat approval resolved id=${consumed.approvalId} decision=${consumed.decision} sender=${actor || "unknown"}`);
141
+ const outcome = result.applied ? "resolved" : "already resolved";
142
+ const decision = "decision" in result.approval ? result.approval.decision : "none";
143
+ params.target.runtime.log?.(`[${params.target.account.accountId}] googlechat approval ${outcome} id=${consumed.approvalId} status=${result.approval.status} decision=${decision} sender=${actor || "unknown"}`);
78
144
  return true;
79
145
  }
80
146
  //#endregion
@@ -112,7 +178,7 @@ const googleChatIngressIdentity = defineStableChannelIngressIdentity({
112
178
  isWildcardEntry: (entry) => normalizeEntryValue(entry) === "*",
113
179
  resolveEntryId: ({ entryIndex, fieldKey }) => fieldKey === "stableId" ? `entry-${entryIndex + 1}:user` : `entry-${entryIndex + 1}:${fieldKey}`
114
180
  });
115
- function resolveGroupConfig(params) {
181
+ function resolveGoogleChatGroupConfig(params) {
116
182
  const { groupId, groupName, groups } = params;
117
183
  const entries = groups ?? {};
118
184
  const keys = Object.keys(entries);
@@ -121,14 +187,21 @@ function resolveGroupConfig(params) {
121
187
  allowlistConfigured: false,
122
188
  deprecatedNameMatch: false
123
189
  };
124
- const entry = entries[groupId];
190
+ const { "*": fallback, ...scopes } = entries;
191
+ const scope = buildGoogleChatGroupPolicyScope({
192
+ tree: {
193
+ defaults: fallback,
194
+ scopes
195
+ },
196
+ groupId
197
+ });
198
+ const entry = scope.matchKey ? entries[scope.matchKey] : void 0;
125
199
  const normalizedGroupName = normalizeLowercaseStringOrEmpty(groupName ?? "");
126
200
  const deprecatedNameMatch = !entry && Boolean(groupName && keys.some((key) => {
127
201
  const trimmed = key.trim();
128
202
  if (!trimmed || trimmed === "*" || /^spaces\//i.test(trimmed)) return false;
129
203
  return trimmed === groupName || normalizeLowercaseStringOrEmpty(trimmed) === normalizedGroupName;
130
204
  }));
131
- const fallback = entries["*"];
132
205
  return {
133
206
  entry: deprecatedNameMatch ? void 0 : entry ?? fallback,
134
207
  allowlistConfigured: true,
@@ -191,7 +264,7 @@ async function applyGoogleChatInboundAccessPolicy(params) {
191
264
  log: logVerbose
192
265
  });
193
266
  warnMutableGroupKeysConfigured(logVerbose, account.config.groups ?? void 0);
194
- const groupConfigResolved = resolveGroupConfig({
267
+ const groupConfigResolved = resolveGoogleChatGroupConfig({
195
268
  groupId: spaceId,
196
269
  groupName: space.displayName ?? null,
197
270
  groups: account.config.groups ?? void 0
@@ -357,49 +430,50 @@ async function applyGoogleChatInboundAccessPolicy(params) {
357
430
  //#endregion
358
431
  //#region extensions/googlechat/src/monitor-durable.ts
359
432
  function resolveGoogleChatDurableReplyOptions(params) {
360
- if (params.infoKind !== "final" || params.typingMessageName) return false;
433
+ if (params.infoKind !== "final" || params.hasTypingMessage) return false;
361
434
  const threadId = params.payload.replyToId?.trim() || void 0;
435
+ if (!threadId) return {
436
+ to: params.spaceId,
437
+ replyToId: null
438
+ };
362
439
  return {
363
440
  to: params.spaceId,
364
- ...threadId ? {
365
- replyToId: threadId,
366
- threadId
367
- } : {}
441
+ replyToId: threadId,
442
+ threadId
368
443
  };
369
444
  }
370
445
  //#endregion
371
446
  //#region extensions/googlechat/src/monitor-reply-delivery.ts
372
447
  async function deliverGoogleChatReply(params) {
373
448
  const { payload, account, spaceId, runtime, core, config, statusSink } = params;
374
- let typingMessageName = params.typingMessageName;
449
+ let typingMessage = params.typingMessage;
450
+ const replyThreadName = payload.replyToId?.trim() || void 0;
451
+ const typingMessageThreadName = typingMessage?.thread?.trim() || void 0;
375
452
  const reply = resolveSendableOutboundReplyParts(payload);
376
- const mediaCount = reply.mediaCount;
377
- const hasMedia = reply.hasMedia;
378
453
  const text = reply.text;
379
454
  let firstTextChunk = true;
380
- let suppressCaption = false;
381
- if (hasMedia && typingMessageName) try {
382
- await deleteGoogleChatMessage({
383
- account,
384
- messageName: typingMessageName
385
- });
386
- typingMessageName = void 0;
387
- } catch (err) {
388
- runtime.error?.(`Google Chat typing cleanup failed: ${String(err)}`);
389
- if (typingMessageName) {
390
- const fallbackText = reply.hasText ? text : mediaCount > 1 ? "Sent attachments." : "Sent attachment.";
391
- try {
392
- await updateGoogleChatMessage({
393
- account,
394
- messageName: typingMessageName,
395
- text: fallbackText
396
- });
397
- suppressCaption = Boolean(text.trim());
398
- } catch (updateErr) {
399
- runtime.error?.(`Google Chat typing update failed: ${String(updateErr)}`);
400
- typingMessageName = void 0;
401
- }
455
+ if (typingMessage && typingMessageThreadName !== replyThreadName) {
456
+ try {
457
+ await deleteGoogleChatMessage({
458
+ account,
459
+ messageName: typingMessage.name
460
+ });
461
+ } catch (err) {
462
+ runtime.error?.(`Google Chat typing cleanup failed: ${String(err)}`);
402
463
  }
464
+ typingMessage = void 0;
465
+ }
466
+ if (reply.hasMedia) runtime.error?.("Google Chat outbound attachments require user OAuth and are not supported by this service-account channel; sending text fallback only.");
467
+ if (reply.hasMedia && !reply.hasText) {
468
+ try {
469
+ if (typingMessage) await deleteGoogleChatMessage({
470
+ account,
471
+ messageName: typingMessage.name
472
+ });
473
+ } catch (err) {
474
+ runtime.error?.(`Google Chat typing cleanup failed: ${String(err)}`);
475
+ }
476
+ throw new Error("Google Chat outbound attachments require user OAuth and no text fallback is available.");
403
477
  }
404
478
  const chunkLimit = account.config.textChunkLimit ?? 4e3;
405
479
  const chunkMode = core.channel.text.resolveChunkMode(config, "googlechat", account.accountId);
@@ -408,78 +482,36 @@ async function deliverGoogleChatReply(params) {
408
482
  account,
409
483
  space: spaceId,
410
484
  text: chunk,
411
- thread: payload.replyToId
485
+ thread: replyThreadName
412
486
  });
413
487
  };
414
- await deliverTextOrMediaReply({
415
- payload,
416
- text: suppressCaption ? "" : reply.text,
417
- chunkText: (value) => core.channel.text.chunkMarkdownTextWithMode(value, chunkLimit, chunkMode),
418
- sendText: async (chunk) => {
419
- try {
420
- if (firstTextChunk && typingMessageName) await updateGoogleChatMessage({
421
- account,
422
- messageName: typingMessageName,
423
- text: chunk
424
- });
425
- else await sendTextMessage(chunk);
426
- firstTextChunk = false;
427
- statusSink?.({ lastOutboundAt: Date.now() });
428
- } catch (err) {
429
- runtime.error?.(`Google Chat message send failed: ${String(err)}`);
430
- if (firstTextChunk && typingMessageName) {
431
- typingMessageName = void 0;
432
- try {
433
- await sendTextMessage(chunk);
434
- statusSink?.({ lastOutboundAt: Date.now() });
435
- } catch (fallbackErr) {
436
- runtime.error?.(`Google Chat message fallback send failed: ${String(fallbackErr)}`);
437
- } finally {
438
- firstTextChunk = false;
439
- }
488
+ const chunks = core.channel.text.chunkMarkdownTextWithMode(text, chunkLimit, chunkMode);
489
+ for (const chunk of chunks) {
490
+ if (!chunk) continue;
491
+ try {
492
+ if (firstTextChunk && typingMessage) await updateGoogleChatMessage({
493
+ account,
494
+ messageName: typingMessage.name,
495
+ text: chunk
496
+ });
497
+ else await sendTextMessage(chunk);
498
+ firstTextChunk = false;
499
+ statusSink?.({ lastOutboundAt: Date.now() });
500
+ } catch (err) {
501
+ runtime.error?.(`Google Chat message send failed: ${String(err)}`);
502
+ if (firstTextChunk && typingMessage) {
503
+ typingMessage = void 0;
504
+ try {
505
+ await sendTextMessage(chunk);
506
+ statusSink?.({ lastOutboundAt: Date.now() });
507
+ } catch (fallbackErr) {
508
+ runtime.error?.(`Google Chat message fallback send failed: ${String(fallbackErr)}`);
509
+ } finally {
510
+ firstTextChunk = false;
440
511
  }
441
512
  }
442
- },
443
- sendMedia: async ({ mediaUrl, caption }) => {
444
- try {
445
- const loaded = await core.channel.media.readRemoteMediaBuffer({
446
- url: mediaUrl,
447
- maxBytes: (account.config.mediaMaxMb ?? 20) * 1024 * 1024
448
- });
449
- const upload = await uploadAttachmentForReply({
450
- account,
451
- spaceId,
452
- buffer: loaded.buffer,
453
- contentType: loaded.contentType,
454
- filename: loaded.fileName ?? "attachment"
455
- });
456
- if (!upload.attachmentUploadToken) throw new Error("missing attachment upload token");
457
- await sendGoogleChatMessage({
458
- account,
459
- space: spaceId,
460
- text: caption,
461
- thread: payload.replyToId,
462
- attachments: [{
463
- attachmentUploadToken: upload.attachmentUploadToken,
464
- contentName: loaded.fileName
465
- }]
466
- });
467
- statusSink?.({ lastOutboundAt: Date.now() });
468
- } catch (err) {
469
- runtime.error?.(`Google Chat attachment send failed: ${String(err)}`);
470
- }
471
513
  }
472
- });
473
- }
474
- async function uploadAttachmentForReply(params) {
475
- const { account, spaceId, buffer, contentType, filename } = params;
476
- return await uploadGoogleChatAttachment({
477
- account,
478
- space: spaceId,
479
- filename,
480
- buffer,
481
- contentType
482
- });
514
+ }
483
515
  }
484
516
  //#endregion
485
517
  //#region extensions/googlechat/src/monitor-webhook.ts
@@ -688,7 +720,7 @@ function createGoogleChatWebhookRequestHandler(params) {
688
720
  }
689
721
  const dispatchTarget = selectedTarget;
690
722
  dispatchTarget.statusSink?.({ lastInboundAt: Date.now() });
691
- params.processEvent(parsedEvent, dispatchTarget).catch((err) => {
723
+ runDetachedWebhookWork(() => params.processEvent(parsedEvent, dispatchTarget)).catch((err) => {
692
724
  dispatchTarget.runtime.error?.(`[${dispatchTarget.account.accountId}] Google Chat webhook failed: ${String(err)}`);
693
725
  });
694
726
  res.statusCode = 200;
@@ -893,8 +925,8 @@ async function processMessageWithPipeline(params) {
893
925
  });
894
926
  let mediaPath;
895
927
  let mediaType;
896
- if (attachments.length > 0) {
897
- const first = attachments[0];
928
+ const first = attachments.at(0);
929
+ if (first) {
898
930
  const attachmentData = await downloadAttachment(first, account, mediaMaxMb, core);
899
931
  if (attachmentData) {
900
932
  mediaPath = attachmentData.path;
@@ -964,9 +996,10 @@ async function processMessageWithPipeline(params) {
964
996
  runtime.error?.(`[${account.accountId}] typingIndicator="reaction" requires user OAuth (not supported with service account). Falling back to "message" mode.`);
965
997
  typingIndicator = "message";
966
998
  }
967
- let typingMessageName;
999
+ let typingMessage;
1000
+ const typingMessageThreadName = account.config.replyToMode && account.config.replyToMode !== "off" ? replyThreadName : void 0;
968
1001
  if (typingIndicator === "message") try {
969
- typingMessageName = (await sendGoogleChatMessage({
1002
+ const result = await sendGoogleChatMessage({
970
1003
  account,
971
1004
  space: spaceId,
972
1005
  text: `_${resolveBotDisplayName({
@@ -974,8 +1007,12 @@ async function processMessageWithPipeline(params) {
974
1007
  agentId: route.agentId,
975
1008
  config
976
1009
  })} is typing..._`,
977
- thread: replyThreadName
978
- }))?.messageName;
1010
+ thread: typingMessageThreadName
1011
+ });
1012
+ if (result?.messageName) typingMessage = {
1013
+ name: result.messageName,
1014
+ thread: typingMessageThreadName
1015
+ };
979
1016
  } catch (err) {
980
1017
  runtime.error?.(`Failed sending typing message: ${String(err)}`);
981
1018
  }
@@ -1007,7 +1044,7 @@ async function processMessageWithPipeline(params) {
1007
1044
  payload,
1008
1045
  infoKind: info.kind,
1009
1046
  spaceId,
1010
- typingMessageName
1047
+ hasTypingMessage: Boolean(typingMessage)
1011
1048
  }),
1012
1049
  deliver: async (payload) => {
1013
1050
  await deliverGoogleChatReply({
@@ -1018,9 +1055,9 @@ async function processMessageWithPipeline(params) {
1018
1055
  core,
1019
1056
  config,
1020
1057
  statusSink,
1021
- typingMessageName
1058
+ typingMessage
1022
1059
  });
1023
- typingMessageName = void 0;
1060
+ typingMessage = void 0;
1024
1061
  },
1025
1062
  onDelivered: () => {
1026
1063
  statusSink?.({ lastOutboundAt: Date.now() });
@@ -1102,7 +1139,6 @@ function resolveGoogleChatWebhookPath(params) {
1102
1139
  const googleChatChannelRuntime = {
1103
1140
  probeGoogleChat,
1104
1141
  sendGoogleChatMessage,
1105
- uploadGoogleChatAttachment,
1106
1142
  resolveGoogleChatWebhookPath,
1107
1143
  startGoogleChatMonitor
1108
1144
  };
@@ -0,0 +1,3 @@
1
+ import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
2
+ import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
3
+ export { buildChannelConfigSchema as n, GoogleChatConfigSchema as t };
@@ -1,4 +1,4 @@
1
- import { t as googlechatDirectoryAdapter } from "./channel.adapters-FEj7zUjh.js";
1
+ import { t as googlechatDirectoryAdapter } from "./channel.adapters-Dhy4lV4f.js";
2
2
  //#region extensions/googlechat/directory-contract-api.ts
3
3
  const googlechatDirectoryContractPlugin = {
4
4
  id: "googlechat",
@@ -1,5 +1,13 @@
1
- import { asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor";
1
+ import { asObjectRecord, defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
2
2
  //#region extensions/googlechat/src/doctor-contract.ts
3
+ const streamingAliasMigration = defineChannelAliasMigration({
4
+ channelId: "googlechat",
5
+ streaming: {
6
+ defaultMode: "partial",
7
+ deliveryOnly: true
8
+ },
9
+ accountStreamingReplacesRoot: true
10
+ });
3
11
  function hasLegacyGoogleChatStreamMode(value) {
4
12
  return asObjectRecord(value)?.streamMode !== void 0;
5
13
  }
@@ -90,9 +98,10 @@ const legacyConfigRules = [
90
98
  ],
91
99
  message: "channels.googlechat.accounts.<id>.groups.<id>.allow is legacy; use channels.googlechat.accounts.<id>.groups.<id>.enabled instead. Run \"openclaw doctor --fix\".",
92
100
  match: (value) => hasLegacyAccountAliases(value, hasLegacyGoogleChatGroupAllowAlias)
93
- }
101
+ },
102
+ ...streamingAliasMigration.legacyConfigRules
94
103
  ];
95
- function normalizeCompatibilityConfig({ cfg }) {
104
+ function normalizeRetiredGoogleChatKeys(cfg) {
96
105
  const rawEntry = asObjectRecord(cfg.channels?.googlechat);
97
106
  if (!rawEntry) return {
98
107
  config: cfg,
@@ -147,5 +156,12 @@ function normalizeCompatibilityConfig({ cfg }) {
147
156
  changes
148
157
  };
149
158
  }
159
+ function normalizeCompatibilityConfig({ cfg }) {
160
+ const retired = normalizeRetiredGoogleChatKeys(cfg);
161
+ return streamingAliasMigration.normalizeChannelConfig({
162
+ cfg: retired.config,
163
+ changes: retired.changes
164
+ });
165
+ }
150
166
  //#endregion
151
167
  export { normalizeCompatibilityConfig as n, legacyConfigRules as t };
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BcEqUZ4j.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-CvhD0eoX.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -1,18 +1,15 @@
1
+ import "./config-api-CsD0IFxF.js";
1
2
  import { extractToolSend as extractToolSend$1 } from "openclaw/plugin-sdk/tool-send";
2
- import { readRemoteMediaBuffer, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
3
3
  import { fetchWithSsrFGuard as fetchWithSsrFGuard$1 } from "openclaw/plugin-sdk/ssrf-runtime";
4
4
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
5
- import { createActionGate as createActionGate$1, jsonResult as jsonResult$1, readNumberParam, readReactionParams as readReactionParams$1, readStringParam as readStringParam$1 } from "openclaw/plugin-sdk/channel-actions";
6
- import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
5
+ import { createActionGate, jsonResult as jsonResult$1, readNumberParam, readReactionParams, readStringParam as readStringParam$1 } from "openclaw/plugin-sdk/channel-actions";
7
6
  import { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
8
7
  import { createAccountStatusSink as createAccountStatusSink$1, createChannelMessageReplyPipeline, runPassiveAccountLifecycle as runPassiveAccountLifecycle$1 } from "openclaw/plugin-sdk/channel-outbound";
9
8
  import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
10
9
  import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
11
10
  import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
12
- import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
13
11
  import { GROUP_POLICY_BLOCKED_LABEL, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
14
12
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
15
- import { loadOutboundMediaFromUrl as loadOutboundMediaFromUrl$1 } from "openclaw/plugin-sdk/outbound-media";
16
13
  import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
17
14
  import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
18
15
  import { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
@@ -25,4 +22,4 @@ const { setRuntime: setGoogleChatRuntime, getRuntime: getGoogleChatRuntime } = c
25
22
  errorMessage: "Google Chat runtime not initialized"
26
23
  });
27
24
  //#endregion
28
- export { resolveWebhookTargetWithAuthOrReject$1 as A, registerWebhookTargetWithPluginRoute$1 as C, resolveInboundMentionDecision as D, resolveDefaultGroupPolicy as E, setGoogleChatRuntime as F, warnMissingProviderGroupPolicyFallbackOnce as M, withResolvedWebhookRequestPipeline$1 as N, resolveInboundRouteEnvelopeBuilderWithRuntime as O, getGoogleChatRuntime as P, readStringParam$1 as S, resolveChannelMediaMaxBytes as T, missingTargetError as _, buildChannelConfigSchema as a, readReactionParams$1 as b, createActionGate$1 as c, createWebhookInFlightLimiter$1 as d, extractToolSend$1 as f, loadOutboundMediaFromUrl$1 as g, jsonResult$1 as h, PAIRING_APPROVED_MESSAGE as i, runPassiveAccountLifecycle$1 as j, resolveWebhookPath as k, createChannelMessageReplyPipeline as l, isDangerousNameMatchingEnabled as m, GROUP_POLICY_BLOCKED_LABEL as n, chunkTextForOutbound as o, fetchWithSsrFGuard$1 as p, GoogleChatConfigSchema as r, createAccountStatusSink$1 as s, DEFAULT_ACCOUNT_ID as t, createChannelPairingController as u, readJsonWebhookBodyOrReject$1 as v, resolveAllowlistProviderRuntimeGroupPolicy as w, readRemoteMediaBuffer as x, readNumberParam as y };
25
+ export { setGoogleChatRuntime as A, resolveInboundRouteEnvelopeBuilderWithRuntime as C, warnMissingProviderGroupPolicyFallbackOnce as D, runPassiveAccountLifecycle$1 as E, withResolvedWebhookRequestPipeline$1 as O, resolveInboundMentionDecision as S, resolveWebhookTargetWithAuthOrReject$1 as T, readReactionParams as _, createAccountStatusSink$1 as a, resolveAllowlistProviderRuntimeGroupPolicy as b, createChannelPairingController as c, fetchWithSsrFGuard$1 as d, isDangerousNameMatchingEnabled as f, readNumberParam as g, readJsonWebhookBodyOrReject$1 as h, chunkTextForOutbound as i, getGoogleChatRuntime as k, createWebhookInFlightLimiter$1 as l, missingTargetError as m, GROUP_POLICY_BLOCKED_LABEL as n, createActionGate as o, jsonResult$1 as p, PAIRING_APPROVED_MESSAGE as r, createChannelMessageReplyPipeline as s, DEFAULT_ACCOUNT_ID as t, extractToolSend$1 as u, readStringParam$1 as v, resolveWebhookPath as w, resolveDefaultGroupPolicy as x, registerWebhookTargetWithPluginRoute$1 as y };
@@ -1,2 +1,3 @@
1
- import { A as resolveWebhookTargetWithAuthOrReject, C as registerWebhookTargetWithPluginRoute, D as resolveInboundMentionDecision, E as resolveDefaultGroupPolicy, F as setGoogleChatRuntime, M as warnMissingProviderGroupPolicyFallbackOnce, N as withResolvedWebhookRequestPipeline, O as resolveInboundRouteEnvelopeBuilderWithRuntime, S as readStringParam, T as resolveChannelMediaMaxBytes, _ as missingTargetError, a as buildChannelConfigSchema, b as readReactionParams, c as createActionGate, d as createWebhookInFlightLimiter, f as extractToolSend, g as loadOutboundMediaFromUrl, h as jsonResult, i as PAIRING_APPROVED_MESSAGE, j as runPassiveAccountLifecycle, k as resolveWebhookPath, l as createChannelMessageReplyPipeline, m as isDangerousNameMatchingEnabled, n as GROUP_POLICY_BLOCKED_LABEL, o as chunkTextForOutbound, p as fetchWithSsrFGuard, r as GoogleChatConfigSchema, s as createAccountStatusSink, t as DEFAULT_ACCOUNT_ID, u as createChannelPairingController, v as readJsonWebhookBodyOrReject, w as resolveAllowlistProviderRuntimeGroupPolicy, x as readRemoteMediaBuffer, y as readNumberParam } from "./runtime-api-BbVoWRxq.js";
2
- export { DEFAULT_ACCOUNT_ID, GROUP_POLICY_BLOCKED_LABEL, GoogleChatConfigSchema, PAIRING_APPROVED_MESSAGE, buildChannelConfigSchema, chunkTextForOutbound, createAccountStatusSink, createActionGate, createChannelMessageReplyPipeline, createChannelPairingController, createWebhookInFlightLimiter, extractToolSend, fetchWithSsrFGuard, isDangerousNameMatchingEnabled, jsonResult, loadOutboundMediaFromUrl, missingTargetError, readJsonWebhookBodyOrReject, readNumberParam, readReactionParams, readRemoteMediaBuffer, readStringParam, registerWebhookTargetWithPluginRoute, resolveAllowlistProviderRuntimeGroupPolicy, resolveChannelMediaMaxBytes, resolveDefaultGroupPolicy, resolveInboundMentionDecision, resolveInboundRouteEnvelopeBuilderWithRuntime, resolveWebhookPath, resolveWebhookTargetWithAuthOrReject, runPassiveAccountLifecycle, setGoogleChatRuntime, warnMissingProviderGroupPolicyFallbackOnce, withResolvedWebhookRequestPipeline };
1
+ import { n as buildChannelConfigSchema, t as GoogleChatConfigSchema } from "./config-api-CsD0IFxF.js";
2
+ import { A as setGoogleChatRuntime, C as resolveInboundRouteEnvelopeBuilderWithRuntime, D as warnMissingProviderGroupPolicyFallbackOnce, E as runPassiveAccountLifecycle, O as withResolvedWebhookRequestPipeline, S as resolveInboundMentionDecision, T as resolveWebhookTargetWithAuthOrReject, _ as readReactionParams, a as createAccountStatusSink, b as resolveAllowlistProviderRuntimeGroupPolicy, c as createChannelPairingController, d as fetchWithSsrFGuard, f as isDangerousNameMatchingEnabled, g as readNumberParam, h as readJsonWebhookBodyOrReject, i as chunkTextForOutbound, l as createWebhookInFlightLimiter, m as missingTargetError, n as GROUP_POLICY_BLOCKED_LABEL, o as createActionGate, p as jsonResult, r as PAIRING_APPROVED_MESSAGE, s as createChannelMessageReplyPipeline, t as DEFAULT_ACCOUNT_ID, u as extractToolSend, v as readStringParam, w as resolveWebhookPath, x as resolveDefaultGroupPolicy, y as registerWebhookTargetWithPluginRoute } from "./runtime-api-1v-DgldF.js";
3
+ export { DEFAULT_ACCOUNT_ID, GROUP_POLICY_BLOCKED_LABEL, GoogleChatConfigSchema, PAIRING_APPROVED_MESSAGE, buildChannelConfigSchema, chunkTextForOutbound, createAccountStatusSink, createActionGate, createChannelMessageReplyPipeline, createChannelPairingController, createWebhookInFlightLimiter, extractToolSend, fetchWithSsrFGuard, isDangerousNameMatchingEnabled, jsonResult, missingTargetError, readJsonWebhookBodyOrReject, readNumberParam, readReactionParams, readStringParam, registerWebhookTargetWithPluginRoute, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, resolveInboundMentionDecision, resolveInboundRouteEnvelopeBuilderWithRuntime, resolveWebhookPath, resolveWebhookTargetWithAuthOrReject, runPassiveAccountLifecycle, setGoogleChatRuntime, warnMissingProviderGroupPolicyFallbackOnce, withResolvedWebhookRequestPipeline };
@@ -1,31 +1,24 @@
1
- import { getChannelSurface, hasOwnProperty, pushAssignment, pushInactiveSurfaceWarning, pushWarning, resolveChannelAccountSurface } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
1
+ import { createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty, pushAssignment, pushInactiveSurfaceWarning, pushWarning, resolveChannelAccountSurface } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
2
  import { coerceSecretRef } from "openclaw/plugin-sdk/secret-ref-runtime";
3
3
  //#region extensions/googlechat/src/secret-contract.ts
4
- const secretTargetRegistryEntries = [{
5
- id: "channels.googlechat.accounts.*.serviceAccount",
6
- targetType: "channels.googlechat.serviceAccount",
7
- targetTypeAliases: ["channels.googlechat.accounts.*.serviceAccount"],
8
- configFile: "openclaw.json",
9
- pathPattern: "channels.googlechat.accounts.*.serviceAccount",
10
- refPathPattern: "channels.googlechat.accounts.*.serviceAccountRef",
11
- secretShape: "sibling_ref",
12
- expectedResolvedValue: "string-or-object",
13
- includeInPlan: true,
14
- includeInConfigure: true,
15
- includeInAudit: true,
16
- accountIdPathSegmentIndex: 3
17
- }, {
18
- id: "channels.googlechat.serviceAccount",
19
- targetType: "channels.googlechat.serviceAccount",
20
- configFile: "openclaw.json",
21
- pathPattern: "channels.googlechat.serviceAccount",
22
- refPathPattern: "channels.googlechat.serviceAccountRef",
23
- secretShape: "sibling_ref",
24
- expectedResolvedValue: "string-or-object",
25
- includeInPlan: true,
26
- includeInConfigure: true,
27
- includeInAudit: true
28
- }];
4
+ const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
5
+ channelKey: "googlechat",
6
+ account: [{
7
+ path: "serviceAccount",
8
+ refPath: "serviceAccountRef",
9
+ targetType: "channels.googlechat.serviceAccount",
10
+ targetTypeAliases: ["channels.googlechat.accounts.*.serviceAccount"],
11
+ secretShape: "sibling_ref",
12
+ expectedResolvedValue: "string-or-object",
13
+ accountIdPathSegmentIndex: 3
14
+ }],
15
+ channel: [{
16
+ path: "serviceAccount",
17
+ refPath: "serviceAccountRef",
18
+ secretShape: "sibling_ref",
19
+ expectedResolvedValue: "string-or-object"
20
+ }]
21
+ });
29
22
  function resolveSecretInputRef(params) {
30
23
  const explicitRef = coerceSecretRef(params.refValue, params.defaults);
31
24
  const inlineRef = explicitRef ? null : coerceSecretRef(params.value, params.defaults);
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-lCMHqumt.js";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-D__4IIu_.js";
2
2
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -1,4 +1,4 @@
1
- import { n as createGoogleChatPluginBase } from "./channel-base-DJICAvKH.js";
1
+ import { n as createGoogleChatPluginBase } from "./channel-base-fY2AAQj5.js";
2
2
  //#region extensions/googlechat/src/channel.setup.ts
3
3
  const googlechatSetupPlugin = createGoogleChatPluginBase();
4
4
  //#endregion
@@ -1,19 +1,18 @@
1
1
  {
2
2
  "name": "@openclaw/googlechat",
3
- "version": "2026.7.1",
3
+ "version": "2026.7.2-beta.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/googlechat",
9
- "version": "2026.7.1",
9
+ "version": "2026.7.2-beta.2",
10
10
  "dependencies": {
11
- "gaxios": "7.1.5",
12
11
  "google-auth-library": "10.9.0",
13
12
  "zod": "4.4.3"
14
13
  },
15
14
  "peerDependencies": {
16
- "openclaw": ">=2026.7.1"
15
+ "openclaw": ">=2026.7.2-beta.2"
17
16
  },
18
17
  "peerDependenciesMeta": {
19
18
  "openclaw": {