@openclaw/googlechat 2026.6.1 → 2026.6.2-beta.1

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,7 +1,7 @@
1
1
  import { c as resolveGoogleChatAccount, o as listEnabledGoogleChatAccounts } from "./channel-base-DpPD0ef1.js";
2
2
  import { P as getGoogleChatRuntime } from "./runtime-api-BbVoWRxq.js";
3
3
  import { c as sendGoogleChatMessage, o as listGoogleChatReactions, r as deleteGoogleChatReaction, t as createGoogleChatReaction, u as uploadGoogleChatAttachment } from "./api-DPvlxpWa.js";
4
- import { n as resolveGoogleChatOutboundSpace } from "./channel-DxHy0I-n.js";
4
+ import { d as resolveGoogleChatOutboundSpace } from "./channel.adapters-LlD3wKl5.js";
5
5
  import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
6
6
  import { createActionGate, jsonResult, readPositiveIntegerParam, readReactionParams, readStringParam } from "openclaw/plugin-sdk/channel-actions";
7
7
  import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { a as googlechatSetupAdapter, i as googlechatSetupWizard } from "./channel-base-DpPD0ef1.js";
2
- import { t as googlechatPlugin } from "./channel-DxHy0I-n.js";
2
+ import { t as googlechatPlugin } from "./channel-AbgtAg3y.js";
3
3
  export { googlechatPlugin, googlechatSetupAdapter, googlechatSetupWizard };
@@ -0,0 +1,258 @@
1
+ import { c as resolveGoogleChatAccount, n as createGoogleChatPluginBase, s as listGoogleChatAccountIds, t as GOOGLECHAT_CHANNEL_ID } from "./channel-base-DpPD0ef1.js";
2
+ import { a as buildChannelConfigSchema, r as GoogleChatConfigSchema, t as DEFAULT_ACCOUNT_ID } from "./runtime-api-BbVoWRxq.js";
3
+ import { a as googlechatPairingTextAdapter, c as isGoogleChatSpaceTarget, i as googlechatOutboundAdapter, l as isGoogleChatUserTarget, n as googlechatGroupsAdapter, o as googlechatSecurityAdapter, r as googlechatMessageAdapter, s as googlechatThreadingAdapter, t as googlechatDirectoryAdapter, u as normalizeGoogleChatTarget } from "./channel.adapters-LlD3wKl5.js";
4
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BcEqUZ4j.js";
5
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-lCMHqumt.js";
6
+ import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
7
+ import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
8
+ import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
9
+ import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
10
+ import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
11
+ import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
12
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
13
+ import { createAccountStatusSink, runPassiveAccountLifecycle } from "openclaw/plugin-sdk/channel-outbound";
14
+ import { createDangerousNameMatchingMutableAllowlistWarningCollector } from "openclaw/plugin-sdk/channel-policy";
15
+ //#region extensions/googlechat/src/approval-auth.ts
16
+ function normalizeGoogleChatApproverId(value) {
17
+ const normalized = normalizeGoogleChatTarget(String(value));
18
+ if (!normalized || !isGoogleChatUserTarget(normalized)) return;
19
+ const suffix = normalizeLowercaseStringOrEmpty(normalized.slice(6));
20
+ if (!suffix || suffix.includes("@")) return;
21
+ return `users/${suffix}`;
22
+ }
23
+ const googleChatApprovalAuth = createResolvedApproverActionAuthAdapter({
24
+ channelLabel: "Google Chat",
25
+ resolveApprovers: ({ cfg, accountId }) => {
26
+ const account = resolveGoogleChatAccount({
27
+ cfg,
28
+ accountId
29
+ }).config;
30
+ return resolveApprovalApprovers({
31
+ allowFrom: account.dm?.allowFrom,
32
+ defaultTo: account.defaultTo,
33
+ normalizeApprover: normalizeGoogleChatApproverId
34
+ });
35
+ },
36
+ normalizeSenderId: (value) => normalizeGoogleChatApproverId(value)
37
+ });
38
+ //#endregion
39
+ //#region extensions/googlechat/src/doctor.ts
40
+ function asObjectRecord(value) {
41
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
42
+ }
43
+ function isGoogleChatMutableAllowEntry(raw) {
44
+ const text = raw.trim();
45
+ if (!text || text === "*") return false;
46
+ const withoutPrefix = text.replace(/^(googlechat|google-chat|gchat):/i, "").trim();
47
+ if (!withoutPrefix) return false;
48
+ return withoutPrefix.replace(/^users\//i, "").includes("@");
49
+ }
50
+ const collectGoogleChatMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
51
+ channel: "googlechat",
52
+ detector: isGoogleChatMutableAllowEntry,
53
+ collectLists: (scope) => {
54
+ const lists = [{
55
+ pathLabel: `${scope.prefix}.groupAllowFrom`,
56
+ list: scope.account.groupAllowFrom
57
+ }];
58
+ const dm = asObjectRecord(scope.account.dm);
59
+ if (dm) lists.push({
60
+ pathLabel: `${scope.prefix}.dm.allowFrom`,
61
+ list: dm.allowFrom
62
+ });
63
+ const groups = asObjectRecord(scope.account.groups);
64
+ if (groups) for (const [groupKey, groupRaw] of Object.entries(groups)) {
65
+ const group = asObjectRecord(groupRaw);
66
+ if (!group) continue;
67
+ lists.push({
68
+ pathLabel: `${scope.prefix}.groups.${groupKey}.users`,
69
+ list: group.users
70
+ });
71
+ }
72
+ return lists;
73
+ }
74
+ });
75
+ //#endregion
76
+ //#region extensions/googlechat/src/gateway.ts
77
+ const loadGoogleChatChannelRuntime$1 = createLazyRuntimeNamedExport(() => import("./channel.runtime-C4eLDKR3.js"), "googleChatChannelRuntime");
78
+ async function startGoogleChatGatewayAccount(ctx) {
79
+ const account = ctx.account;
80
+ const statusSink = createAccountStatusSink({
81
+ accountId: account.accountId,
82
+ setStatus: ctx.setStatus
83
+ });
84
+ ctx.log?.info?.(`[${account.accountId}] starting Google Chat webhook`);
85
+ const { resolveGoogleChatWebhookPath, startGoogleChatMonitor } = await loadGoogleChatChannelRuntime$1();
86
+ statusSink({
87
+ running: true,
88
+ lastStartAt: Date.now(),
89
+ webhookPath: resolveGoogleChatWebhookPath({ account }),
90
+ audienceType: account.config.audienceType,
91
+ audience: account.config.audience
92
+ });
93
+ await runPassiveAccountLifecycle({
94
+ abortSignal: ctx.abortSignal,
95
+ start: async () => await startGoogleChatMonitor({
96
+ account,
97
+ config: ctx.cfg,
98
+ runtime: ctx.runtime,
99
+ abortSignal: ctx.abortSignal,
100
+ webhookPath: account.config.webhookPath,
101
+ webhookUrl: account.config.webhookUrl,
102
+ statusSink
103
+ }),
104
+ stop: async (unregister) => {
105
+ unregister?.();
106
+ },
107
+ onStop: async () => {
108
+ statusSink({
109
+ running: false,
110
+ lastStopAt: Date.now()
111
+ });
112
+ }
113
+ });
114
+ }
115
+ //#endregion
116
+ //#region extensions/googlechat/src/channel.ts
117
+ const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-C4eLDKR3.js"), "googleChatChannelRuntime");
118
+ const googlechatActions = {
119
+ describeMessageTool: ({ cfg, accountId }) => {
120
+ const accounts = accountId ? [resolveGoogleChatAccount({
121
+ cfg,
122
+ accountId
123
+ })].filter((account) => account.enabled && account.credentialSource !== "none") : listGoogleChatAccountIds(cfg).map((id) => resolveGoogleChatAccount({
124
+ cfg,
125
+ accountId: id
126
+ })).filter((account) => account.enabled && account.credentialSource !== "none");
127
+ if (accounts.length === 0) return null;
128
+ const actions = new Set(["send", "upload-file"]);
129
+ if (accounts.some((account) => account.config.actions?.reactions !== false)) {
130
+ actions.add("react");
131
+ actions.add("reactions");
132
+ }
133
+ return { actions: Array.from(actions) };
134
+ },
135
+ extractToolSend: ({ args }) => extractToolSend(args, "sendMessage"),
136
+ handleAction: async (ctx) => {
137
+ const { googlechatMessageActions } = await import("./actions-DisAY2Ac.js");
138
+ if (!googlechatMessageActions.handleAction) throw new Error("Google Chat actions are not available.");
139
+ return await googlechatMessageActions.handleAction(ctx);
140
+ }
141
+ };
142
+ const googlechatPlugin = createChatChannelPlugin({
143
+ base: {
144
+ ...createGoogleChatPluginBase({ configSchema: buildChannelConfigSchema(GoogleChatConfigSchema) }),
145
+ approvalCapability: googleChatApprovalAuth,
146
+ secrets: {
147
+ secretTargetRegistryEntries,
148
+ collectRuntimeConfigAssignments
149
+ },
150
+ groups: googlechatGroupsAdapter,
151
+ messaging: {
152
+ targetPrefixes: [
153
+ "googlechat",
154
+ "google-chat",
155
+ "gchat"
156
+ ],
157
+ normalizeTarget: normalizeGoogleChatTarget,
158
+ targetResolver: {
159
+ looksLikeId: (raw, normalized) => {
160
+ const value = normalized ?? raw.trim();
161
+ return isGoogleChatSpaceTarget(value) || isGoogleChatUserTarget(value);
162
+ },
163
+ hint: "<spaces/{space}|users/{user}>"
164
+ }
165
+ },
166
+ directory: googlechatDirectoryAdapter,
167
+ message: googlechatMessageAdapter,
168
+ resolver: { resolveTargets: async ({ inputs, kind }) => {
169
+ return inputs.map((input) => {
170
+ const normalized = normalizeGoogleChatTarget(input);
171
+ if (!normalized) return {
172
+ input,
173
+ resolved: false,
174
+ note: "empty target"
175
+ };
176
+ if (kind === "user" && isGoogleChatUserTarget(normalized)) return {
177
+ input,
178
+ resolved: true,
179
+ id: normalized
180
+ };
181
+ if (kind === "group" && isGoogleChatSpaceTarget(normalized)) return {
182
+ input,
183
+ resolved: true,
184
+ id: normalized
185
+ };
186
+ return {
187
+ input,
188
+ resolved: false,
189
+ note: "use spaces/{space} or users/{user}"
190
+ };
191
+ });
192
+ } },
193
+ actions: googlechatActions,
194
+ doctor: {
195
+ dmAllowFromMode: "nestedOnly",
196
+ groupModel: "route",
197
+ groupAllowFromFallbackToAllowFrom: false,
198
+ warnOnEmptyGroupSenderAllowlist: false,
199
+ legacyConfigRules,
200
+ normalizeCompatibilityConfig,
201
+ collectMutableAllowlistWarnings: collectGoogleChatMutableAllowlistWarnings
202
+ },
203
+ status: createComputedAccountStatusAdapter({
204
+ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
205
+ collectStatusIssues: (accounts) => accounts.flatMap((entry) => {
206
+ const accountId = entry.accountId ?? DEFAULT_ACCOUNT_ID;
207
+ const enabled = entry.enabled !== false;
208
+ const configured = entry.configured === true;
209
+ if (!enabled || !configured) return [];
210
+ const issues = [];
211
+ if (!entry.audience) issues.push({
212
+ channel: GOOGLECHAT_CHANNEL_ID,
213
+ accountId,
214
+ kind: "config",
215
+ message: "Google Chat audience is missing (set channels.googlechat.audience).",
216
+ fix: "Set channels.googlechat.audienceType and channels.googlechat.audience."
217
+ });
218
+ if (!entry.audienceType) issues.push({
219
+ channel: GOOGLECHAT_CHANNEL_ID,
220
+ accountId,
221
+ kind: "config",
222
+ message: "Google Chat audienceType is missing (app-url or project-number).",
223
+ fix: "Set channels.googlechat.audienceType and channels.googlechat.audience."
224
+ });
225
+ return issues;
226
+ }),
227
+ buildChannelSummary: ({ snapshot }) => buildPassiveProbedChannelStatusSummary(snapshot, {
228
+ credentialSource: snapshot.credentialSource ?? "none",
229
+ audienceType: snapshot.audienceType ?? null,
230
+ audience: snapshot.audience ?? null,
231
+ webhookPath: snapshot.webhookPath ?? null,
232
+ webhookUrl: snapshot.webhookUrl ?? null
233
+ }),
234
+ probeAccount: async ({ account }) => (await loadGoogleChatChannelRuntime()).probeGoogleChat(account),
235
+ resolveAccountSnapshot: ({ account }) => ({
236
+ accountId: account.accountId,
237
+ name: account.name,
238
+ enabled: account.enabled,
239
+ configured: account.credentialSource !== "none",
240
+ extra: {
241
+ credentialSource: account.credentialSource,
242
+ audienceType: account.config.audienceType,
243
+ audience: account.config.audience,
244
+ webhookPath: account.config.webhookPath,
245
+ webhookUrl: account.config.webhookUrl,
246
+ dmPolicy: account.config.dm?.policy ?? "pairing"
247
+ }
248
+ })
249
+ }),
250
+ gateway: { startAccount: startGoogleChatGatewayAccount }
251
+ },
252
+ pairing: { text: googlechatPairingTextAdapter },
253
+ security: googlechatSecurityAdapter,
254
+ threading: googlechatThreadingAdapter,
255
+ outbound: googlechatOutboundAdapter
256
+ });
257
+ //#endregion
258
+ export { googlechatPlugin as t };
@@ -1,2 +1,2 @@
1
- import { t as googlechatPlugin } from "./channel-DxHy0I-n.js";
1
+ import { t as googlechatPlugin } from "./channel-AbgtAg3y.js";
2
2
  export { googlechatPlugin };
@@ -0,0 +1,280 @@
1
+ import { c as resolveGoogleChatAccount, r as formatGoogleChatAllowFromEntry } from "./channel-base-DpPD0ef1.js";
2
+ import { T as resolveChannelMediaMaxBytes, _ as missingTargetError, g as loadOutboundMediaFromUrl, i as PAIRING_APPROVED_MESSAGE, o as chunkTextForOutbound, x as readRemoteMediaBuffer } from "./runtime-api-BbVoWRxq.js";
3
+ import { a as findGoogleChatDirectMessage } from "./api-DPvlxpWa.js";
4
+ import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
5
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
+ import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
7
+ import { adaptScopedAccountAccessor } from "openclaw/plugin-sdk/channel-config-helpers";
8
+ import { composeAccountWarningCollectors, createAllowlistProviderOpenWarningCollector, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
9
+ import { createChannelDirectoryAdapter, listResolvedDirectoryGroupEntriesFromMapKeys, listResolvedDirectoryUserEntriesFromAllowFrom } from "openclaw/plugin-sdk/directory-runtime";
10
+ //#region extensions/googlechat/src/targets.ts
11
+ function normalizeGoogleChatTarget(raw) {
12
+ const trimmed = raw?.trim();
13
+ if (!trimmed) return;
14
+ const normalized = trimmed.replace(/^(googlechat|google-chat|gchat):/i, "").replace(/^user:(users\/)?/i, "users/").replace(/^space:(spaces\/)?/i, "spaces/");
15
+ if (isGoogleChatUserTarget(normalized)) {
16
+ const suffix = normalized.slice(6);
17
+ return suffix.includes("@") ? `users/${normalizeLowercaseStringOrEmpty(suffix)}` : normalized;
18
+ }
19
+ if (isGoogleChatSpaceTarget(normalized)) return normalized;
20
+ if (normalized.includes("@")) return `users/${normalizeLowercaseStringOrEmpty(normalized)}`;
21
+ return normalized;
22
+ }
23
+ function isGoogleChatUserTarget(value) {
24
+ return normalizeLowercaseStringOrEmpty(value).startsWith("users/");
25
+ }
26
+ function isGoogleChatSpaceTarget(value) {
27
+ return normalizeLowercaseStringOrEmpty(value).startsWith("spaces/");
28
+ }
29
+ function stripMessageSuffix(target) {
30
+ const index = target.indexOf("/messages/");
31
+ if (index === -1) return target;
32
+ return target.slice(0, index);
33
+ }
34
+ async function resolveGoogleChatOutboundSpace(params) {
35
+ const normalized = normalizeGoogleChatTarget(params.target);
36
+ if (!normalized) throw new Error("Missing Google Chat target.");
37
+ const base = stripMessageSuffix(normalized);
38
+ if (isGoogleChatSpaceTarget(base)) return base;
39
+ if (isGoogleChatUserTarget(base)) {
40
+ const dm = await findGoogleChatDirectMessage({
41
+ account: params.account,
42
+ userName: base
43
+ });
44
+ if (!dm?.name) throw new Error(`No Google Chat DM found for ${base}`);
45
+ return dm.name;
46
+ }
47
+ return base;
48
+ }
49
+ //#endregion
50
+ //#region extensions/googlechat/src/group-policy.ts
51
+ function resolveGoogleChatGroupRequireMention(params) {
52
+ return resolveChannelGroupRequireMention({
53
+ cfg: params.cfg,
54
+ channel: "googlechat",
55
+ groupId: params.groupId,
56
+ accountId: params.accountId
57
+ });
58
+ }
59
+ //#endregion
60
+ //#region extensions/googlechat/src/channel.adapters.ts
61
+ const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-C4eLDKR3.js"), "googleChatChannelRuntime");
62
+ function createGoogleChatSendReceipt(params) {
63
+ const messageId = params.messageId?.trim();
64
+ return createMessageReceiptFromOutboundResults({
65
+ results: messageId ? [{
66
+ channel: "googlechat",
67
+ messageId,
68
+ chatId: params.chatId,
69
+ conversationId: params.chatId
70
+ }] : [],
71
+ threadId: params.chatId,
72
+ kind: params.kind
73
+ });
74
+ }
75
+ const formatAllowFromEntry = formatGoogleChatAllowFromEntry;
76
+ const collectGoogleChatSecurityWarnings = composeAccountWarningCollectors(createAllowlistProviderOpenWarningCollector({
77
+ providerConfigPresent: (cfg) => cfg.channels?.googlechat !== void 0,
78
+ resolveGroupPolicy: (account) => account.config.groupPolicy,
79
+ buildOpenWarning: {
80
+ surface: "Google Chat spaces",
81
+ openBehavior: "allows any space to trigger (mention-gated)",
82
+ remediation: "Set channels.googlechat.groupPolicy=\"allowlist\" and configure channels.googlechat.groups"
83
+ }
84
+ }), (account) => account.config.dm?.policy === "open" && "- Google Chat DMs are open to anyone. Set channels.googlechat.dm.policy=\"pairing\" or \"allowlist\".");
85
+ const googlechatGroupsAdapter = { resolveRequireMention: resolveGoogleChatGroupRequireMention };
86
+ const googlechatDirectoryAdapter = createChannelDirectoryAdapter({
87
+ listPeers: async (params) => listResolvedDirectoryUserEntriesFromAllowFrom({
88
+ ...params,
89
+ resolveAccount: adaptScopedAccountAccessor(resolveGoogleChatAccount),
90
+ resolveAllowFrom: (account) => account.config.dm?.allowFrom,
91
+ normalizeId: (entry) => normalizeGoogleChatTarget(entry) ?? entry
92
+ }),
93
+ listGroups: async (params) => listResolvedDirectoryGroupEntriesFromMapKeys({
94
+ ...params,
95
+ resolveAccount: adaptScopedAccountAccessor(resolveGoogleChatAccount),
96
+ resolveGroups: (account) => account.config.groups
97
+ })
98
+ });
99
+ const googlechatSecurityAdapter = {
100
+ dm: {
101
+ channelKey: "googlechat",
102
+ resolvePolicy: (account) => account.config.dm?.policy,
103
+ resolveAllowFrom: (account) => account.config.dm?.allowFrom,
104
+ allowFromPathSuffix: "dm.",
105
+ normalizeEntry: (raw) => formatAllowFromEntry(raw)
106
+ },
107
+ collectWarnings: collectGoogleChatSecurityWarnings
108
+ };
109
+ const googlechatThreadingAdapter = {
110
+ scopedAccountReplyToMode: {
111
+ resolveAccount: (cfg, accountId) => resolveGoogleChatAccount({
112
+ cfg,
113
+ accountId
114
+ }),
115
+ resolveReplyToMode: (account, _chatType) => account.config.replyToMode,
116
+ fallback: "off"
117
+ },
118
+ buildToolContext: ({ cfg, accountId, context, hasRepliedRef }) => {
119
+ const currentChannelId = normalizeGoogleChatTarget(context.To);
120
+ const replyToId = normalizeOptionalString(context.ReplyToIdFull) ?? normalizeOptionalString(context.ReplyToId);
121
+ return {
122
+ currentChannelId,
123
+ currentMessageId: replyToId,
124
+ currentThreadTs: replyToId,
125
+ replyToMode: resolveGoogleChatAccount({
126
+ cfg,
127
+ accountId
128
+ }).config.replyToMode,
129
+ hasRepliedRef
130
+ };
131
+ }
132
+ };
133
+ const googlechatPairingTextAdapter = {
134
+ idLabel: "googlechatUserId",
135
+ message: PAIRING_APPROVED_MESSAGE,
136
+ normalizeAllowEntry: (entry) => formatAllowFromEntry(entry),
137
+ notify: async ({ cfg, id, message, accountId }) => {
138
+ const account = resolveGoogleChatAccount({
139
+ cfg,
140
+ accountId
141
+ });
142
+ if (account.credentialSource === "none") return;
143
+ const user = normalizeGoogleChatTarget(id) ?? id;
144
+ const space = await resolveGoogleChatOutboundSpace({
145
+ account,
146
+ target: isGoogleChatUserTarget(user) ? user : `users/${user}`
147
+ });
148
+ const { sendGoogleChatMessage } = await loadGoogleChatChannelRuntime();
149
+ await sendGoogleChatMessage({
150
+ account,
151
+ space,
152
+ text: message
153
+ });
154
+ }
155
+ };
156
+ const googlechatOutboundAdapter = {
157
+ base: {
158
+ deliveryMode: "direct",
159
+ chunker: chunkTextForOutbound,
160
+ chunkerMode: "markdown",
161
+ textChunkLimit: 4e3,
162
+ sanitizeText: ({ text }) => sanitizeForPlainText(text),
163
+ resolveTarget: ({ to }) => {
164
+ const trimmed = normalizeOptionalString(to) ?? "";
165
+ if (trimmed) {
166
+ const normalized = normalizeGoogleChatTarget(trimmed);
167
+ if (!normalized) return {
168
+ ok: false,
169
+ error: missingTargetError("Google Chat", "<spaces/{space}|users/{user}>")
170
+ };
171
+ return {
172
+ ok: true,
173
+ to: normalized
174
+ };
175
+ }
176
+ return {
177
+ ok: false,
178
+ error: missingTargetError("Google Chat", "<spaces/{space}|users/{user}>")
179
+ };
180
+ }
181
+ },
182
+ attachedResults: {
183
+ channel: "googlechat",
184
+ sendText: async ({ cfg, to, text, accountId, replyToId, threadId }) => {
185
+ const account = resolveGoogleChatAccount({
186
+ cfg,
187
+ accountId
188
+ });
189
+ const space = await resolveGoogleChatOutboundSpace({
190
+ account,
191
+ target: to
192
+ });
193
+ const thread = typeof threadId === "number" ? String(threadId) : threadId ?? replyToId ?? void 0;
194
+ const { sendGoogleChatMessage } = await loadGoogleChatChannelRuntime();
195
+ const messageId = (await sendGoogleChatMessage({
196
+ account,
197
+ space,
198
+ text,
199
+ thread
200
+ }))?.messageName ?? "";
201
+ return {
202
+ messageId,
203
+ chatId: space,
204
+ receipt: createGoogleChatSendReceipt({
205
+ messageId,
206
+ chatId: space,
207
+ kind: "text"
208
+ })
209
+ };
210
+ },
211
+ sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, accountId, replyToId, threadId }) => {
212
+ if (!mediaUrl) throw new Error("Google Chat mediaUrl is required.");
213
+ const account = resolveGoogleChatAccount({
214
+ cfg,
215
+ accountId
216
+ });
217
+ const space = await resolveGoogleChatOutboundSpace({
218
+ account,
219
+ target: to
220
+ });
221
+ const thread = typeof threadId === "number" ? String(threadId) : threadId ?? replyToId ?? void 0;
222
+ const effectiveMaxBytes = resolveChannelMediaMaxBytes({
223
+ cfg,
224
+ resolveChannelLimitMb: ({ cfg: cfgLocal, accountId: accountIdLocal }) => (cfgLocal.channels?.googlechat)?.accounts?.[accountIdLocal]?.mediaMaxMb ?? (cfgLocal.channels?.googlechat)?.mediaMaxMb,
225
+ accountId
226
+ }) ?? (account.config.mediaMaxMb ?? 20) * 1024 * 1024;
227
+ const loaded = /^https?:\/\//i.test(mediaUrl) ? await readRemoteMediaBuffer({
228
+ url: mediaUrl,
229
+ maxBytes: effectiveMaxBytes
230
+ }) : await loadOutboundMediaFromUrl(mediaUrl, {
231
+ maxBytes: effectiveMaxBytes,
232
+ mediaAccess,
233
+ mediaLocalRoots,
234
+ mediaReadFile
235
+ });
236
+ const { sendGoogleChatMessage, uploadGoogleChatAttachment } = await loadGoogleChatChannelRuntime();
237
+ const upload = await uploadGoogleChatAttachment({
238
+ account,
239
+ space,
240
+ filename: loaded.fileName ?? "attachment",
241
+ buffer: loaded.buffer,
242
+ contentType: loaded.contentType
243
+ });
244
+ const messageId = (await sendGoogleChatMessage({
245
+ account,
246
+ space,
247
+ text,
248
+ thread,
249
+ attachments: upload.attachmentUploadToken ? [{
250
+ attachmentUploadToken: upload.attachmentUploadToken,
251
+ contentName: loaded.fileName
252
+ }] : void 0
253
+ }))?.messageName ?? "";
254
+ return {
255
+ messageId,
256
+ chatId: space,
257
+ receipt: createGoogleChatSendReceipt({
258
+ messageId,
259
+ chatId: space,
260
+ kind: "media"
261
+ })
262
+ };
263
+ }
264
+ }
265
+ };
266
+ const googlechatMessageAdapter = defineChannelMessageAdapter({
267
+ id: "googlechat",
268
+ durableFinal: { capabilities: {
269
+ text: true,
270
+ media: true,
271
+ thread: true,
272
+ messageSendingHooks: true
273
+ } },
274
+ send: {
275
+ text: googlechatOutboundAdapter.attachedResults.sendText,
276
+ media: googlechatOutboundAdapter.attachedResults.sendMedia
277
+ }
278
+ });
279
+ //#endregion
280
+ export { googlechatPairingTextAdapter as a, isGoogleChatSpaceTarget as c, resolveGoogleChatOutboundSpace as d, googlechatOutboundAdapter as i, isGoogleChatUserTarget as l, googlechatGroupsAdapter as n, googlechatSecurityAdapter as o, googlechatMessageAdapter as r, googlechatThreadingAdapter as s, googlechatDirectoryAdapter as t, normalizeGoogleChatTarget as u };
@@ -0,0 +1,8 @@
1
+ import { t as googlechatDirectoryAdapter } from "./channel.adapters-LlD3wKl5.js";
2
+ //#region extensions/googlechat/directory-contract-api.ts
3
+ const googlechatDirectoryContractPlugin = {
4
+ id: "googlechat",
5
+ directory: googlechatDirectoryAdapter
6
+ };
7
+ //#endregion
8
+ export { googlechatDirectoryContractPlugin };
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@openclaw/googlechat",
3
- "version": "2026.6.1",
3
+ "version": "2026.6.2-beta.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/googlechat",
9
- "version": "2026.6.1",
9
+ "version": "2026.6.2-beta.1",
10
10
  "dependencies": {
11
11
  "gaxios": "7.1.4",
12
12
  "google-auth-library": "10.6.2",
13
13
  "zod": "4.4.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.6.1"
16
+ "openclaw": ">=2026.6.2-beta.1"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/googlechat",
3
- "version": "2026.6.1",
3
+ "version": "2026.6.2-beta.1",
4
4
  "description": "OpenClaw Google Chat channel plugin for spaces and direct messages.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,7 @@
13
13
  "zod": "4.4.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.6.1"
16
+ "openclaw": ">=2026.6.2-beta.1"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
@@ -71,10 +71,10 @@
71
71
  "minHostVersion": ">=2026.4.10"
72
72
  },
73
73
  "compat": {
74
- "pluginApi": ">=2026.6.1"
74
+ "pluginApi": ">=2026.6.2-beta.1"
75
75
  },
76
76
  "build": {
77
- "openclawVersion": "2026.6.1"
77
+ "openclawVersion": "2026.6.2-beta.1"
78
78
  },
79
79
  "release": {
80
80
  "publishToClawHub": true,
@@ -1,530 +0,0 @@
1
- import { c as resolveGoogleChatAccount, n as createGoogleChatPluginBase, r as formatGoogleChatAllowFromEntry, s as listGoogleChatAccountIds, t as GOOGLECHAT_CHANNEL_ID } from "./channel-base-DpPD0ef1.js";
2
- import { T as resolveChannelMediaMaxBytes, _ as missingTargetError, a as buildChannelConfigSchema, g as loadOutboundMediaFromUrl, i as PAIRING_APPROVED_MESSAGE, o as chunkTextForOutbound, r as GoogleChatConfigSchema, t as DEFAULT_ACCOUNT_ID, x as readRemoteMediaBuffer } from "./runtime-api-BbVoWRxq.js";
3
- import { a as findGoogleChatDirectMessage } from "./api-DPvlxpWa.js";
4
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BcEqUZ4j.js";
5
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-lCMHqumt.js";
6
- import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
7
- import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
8
- import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
9
- import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
10
- import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
11
- import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
12
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
- import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
14
- import { adaptScopedAccountAccessor } from "openclaw/plugin-sdk/channel-config-helpers";
15
- import { composeAccountWarningCollectors, createAllowlistProviderOpenWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
16
- import { createChannelDirectoryAdapter, listResolvedDirectoryGroupEntriesFromMapKeys, listResolvedDirectoryUserEntriesFromAllowFrom } from "openclaw/plugin-sdk/directory-runtime";
17
- //#region extensions/googlechat/src/targets.ts
18
- function normalizeGoogleChatTarget(raw) {
19
- const trimmed = raw?.trim();
20
- if (!trimmed) return;
21
- const normalized = trimmed.replace(/^(googlechat|google-chat|gchat):/i, "").replace(/^user:(users\/)?/i, "users/").replace(/^space:(spaces\/)?/i, "spaces/");
22
- if (isGoogleChatUserTarget(normalized)) {
23
- const suffix = normalized.slice(6);
24
- return suffix.includes("@") ? `users/${normalizeLowercaseStringOrEmpty(suffix)}` : normalized;
25
- }
26
- if (isGoogleChatSpaceTarget(normalized)) return normalized;
27
- if (normalized.includes("@")) return `users/${normalizeLowercaseStringOrEmpty(normalized)}`;
28
- return normalized;
29
- }
30
- function isGoogleChatUserTarget(value) {
31
- return normalizeLowercaseStringOrEmpty(value).startsWith("users/");
32
- }
33
- function isGoogleChatSpaceTarget(value) {
34
- return normalizeLowercaseStringOrEmpty(value).startsWith("spaces/");
35
- }
36
- function stripMessageSuffix(target) {
37
- const index = target.indexOf("/messages/");
38
- if (index === -1) return target;
39
- return target.slice(0, index);
40
- }
41
- async function resolveGoogleChatOutboundSpace(params) {
42
- const normalized = normalizeGoogleChatTarget(params.target);
43
- if (!normalized) throw new Error("Missing Google Chat target.");
44
- const base = stripMessageSuffix(normalized);
45
- if (isGoogleChatSpaceTarget(base)) return base;
46
- if (isGoogleChatUserTarget(base)) {
47
- const dm = await findGoogleChatDirectMessage({
48
- account: params.account,
49
- userName: base
50
- });
51
- if (!dm?.name) throw new Error(`No Google Chat DM found for ${base}`);
52
- return dm.name;
53
- }
54
- return base;
55
- }
56
- //#endregion
57
- //#region extensions/googlechat/src/approval-auth.ts
58
- function normalizeGoogleChatApproverId(value) {
59
- const normalized = normalizeGoogleChatTarget(String(value));
60
- if (!normalized || !isGoogleChatUserTarget(normalized)) return;
61
- const suffix = normalizeLowercaseStringOrEmpty(normalized.slice(6));
62
- if (!suffix || suffix.includes("@")) return;
63
- return `users/${suffix}`;
64
- }
65
- const googleChatApprovalAuth = createResolvedApproverActionAuthAdapter({
66
- channelLabel: "Google Chat",
67
- resolveApprovers: ({ cfg, accountId }) => {
68
- const account = resolveGoogleChatAccount({
69
- cfg,
70
- accountId
71
- }).config;
72
- return resolveApprovalApprovers({
73
- allowFrom: account.dm?.allowFrom,
74
- defaultTo: account.defaultTo,
75
- normalizeApprover: normalizeGoogleChatApproverId
76
- });
77
- },
78
- normalizeSenderId: (value) => normalizeGoogleChatApproverId(value)
79
- });
80
- //#endregion
81
- //#region extensions/googlechat/src/group-policy.ts
82
- function resolveGoogleChatGroupRequireMention(params) {
83
- return resolveChannelGroupRequireMention({
84
- cfg: params.cfg,
85
- channel: "googlechat",
86
- groupId: params.groupId,
87
- accountId: params.accountId
88
- });
89
- }
90
- //#endregion
91
- //#region extensions/googlechat/src/channel.adapters.ts
92
- const loadGoogleChatChannelRuntime$2 = createLazyRuntimeNamedExport(() => import("./channel.runtime-C4eLDKR3.js"), "googleChatChannelRuntime");
93
- function createGoogleChatSendReceipt(params) {
94
- const messageId = params.messageId?.trim();
95
- return createMessageReceiptFromOutboundResults({
96
- results: messageId ? [{
97
- channel: "googlechat",
98
- messageId,
99
- chatId: params.chatId,
100
- conversationId: params.chatId
101
- }] : [],
102
- threadId: params.chatId,
103
- kind: params.kind
104
- });
105
- }
106
- const formatAllowFromEntry = formatGoogleChatAllowFromEntry;
107
- const collectGoogleChatSecurityWarnings = composeAccountWarningCollectors(createAllowlistProviderOpenWarningCollector({
108
- providerConfigPresent: (cfg) => cfg.channels?.googlechat !== void 0,
109
- resolveGroupPolicy: (account) => account.config.groupPolicy,
110
- buildOpenWarning: {
111
- surface: "Google Chat spaces",
112
- openBehavior: "allows any space to trigger (mention-gated)",
113
- remediation: "Set channels.googlechat.groupPolicy=\"allowlist\" and configure channels.googlechat.groups"
114
- }
115
- }), (account) => account.config.dm?.policy === "open" && "- Google Chat DMs are open to anyone. Set channels.googlechat.dm.policy=\"pairing\" or \"allowlist\".");
116
- const googlechatGroupsAdapter = { resolveRequireMention: resolveGoogleChatGroupRequireMention };
117
- const googlechatDirectoryAdapter = createChannelDirectoryAdapter({
118
- listPeers: async (params) => listResolvedDirectoryUserEntriesFromAllowFrom({
119
- ...params,
120
- resolveAccount: adaptScopedAccountAccessor(resolveGoogleChatAccount),
121
- resolveAllowFrom: (account) => account.config.dm?.allowFrom,
122
- normalizeId: (entry) => normalizeGoogleChatTarget(entry) ?? entry
123
- }),
124
- listGroups: async (params) => listResolvedDirectoryGroupEntriesFromMapKeys({
125
- ...params,
126
- resolveAccount: adaptScopedAccountAccessor(resolveGoogleChatAccount),
127
- resolveGroups: (account) => account.config.groups
128
- })
129
- });
130
- const googlechatSecurityAdapter = {
131
- dm: {
132
- channelKey: "googlechat",
133
- resolvePolicy: (account) => account.config.dm?.policy,
134
- resolveAllowFrom: (account) => account.config.dm?.allowFrom,
135
- allowFromPathSuffix: "dm.",
136
- normalizeEntry: (raw) => formatAllowFromEntry(raw)
137
- },
138
- collectWarnings: collectGoogleChatSecurityWarnings
139
- };
140
- const googlechatThreadingAdapter = {
141
- scopedAccountReplyToMode: {
142
- resolveAccount: (cfg, accountId) => resolveGoogleChatAccount({
143
- cfg,
144
- accountId
145
- }),
146
- resolveReplyToMode: (account, _chatType) => account.config.replyToMode,
147
- fallback: "off"
148
- },
149
- buildToolContext: ({ cfg, accountId, context, hasRepliedRef }) => {
150
- const currentChannelId = normalizeGoogleChatTarget(context.To);
151
- const replyToId = normalizeOptionalString(context.ReplyToIdFull) ?? normalizeOptionalString(context.ReplyToId);
152
- return {
153
- currentChannelId,
154
- currentMessageId: replyToId,
155
- currentThreadTs: replyToId,
156
- replyToMode: resolveGoogleChatAccount({
157
- cfg,
158
- accountId
159
- }).config.replyToMode,
160
- hasRepliedRef
161
- };
162
- }
163
- };
164
- const googlechatPairingTextAdapter = {
165
- idLabel: "googlechatUserId",
166
- message: PAIRING_APPROVED_MESSAGE,
167
- normalizeAllowEntry: (entry) => formatAllowFromEntry(entry),
168
- notify: async ({ cfg, id, message, accountId }) => {
169
- const account = resolveGoogleChatAccount({
170
- cfg,
171
- accountId
172
- });
173
- if (account.credentialSource === "none") return;
174
- const user = normalizeGoogleChatTarget(id) ?? id;
175
- const space = await resolveGoogleChatOutboundSpace({
176
- account,
177
- target: isGoogleChatUserTarget(user) ? user : `users/${user}`
178
- });
179
- const { sendGoogleChatMessage } = await loadGoogleChatChannelRuntime$2();
180
- await sendGoogleChatMessage({
181
- account,
182
- space,
183
- text: message
184
- });
185
- }
186
- };
187
- const googlechatOutboundAdapter = {
188
- base: {
189
- deliveryMode: "direct",
190
- chunker: chunkTextForOutbound,
191
- chunkerMode: "markdown",
192
- textChunkLimit: 4e3,
193
- sanitizeText: ({ text }) => sanitizeForPlainText(text),
194
- resolveTarget: ({ to }) => {
195
- const trimmed = normalizeOptionalString(to) ?? "";
196
- if (trimmed) {
197
- const normalized = normalizeGoogleChatTarget(trimmed);
198
- if (!normalized) return {
199
- ok: false,
200
- error: missingTargetError("Google Chat", "<spaces/{space}|users/{user}>")
201
- };
202
- return {
203
- ok: true,
204
- to: normalized
205
- };
206
- }
207
- return {
208
- ok: false,
209
- error: missingTargetError("Google Chat", "<spaces/{space}|users/{user}>")
210
- };
211
- }
212
- },
213
- attachedResults: {
214
- channel: "googlechat",
215
- sendText: async ({ cfg, to, text, accountId, replyToId, threadId }) => {
216
- const account = resolveGoogleChatAccount({
217
- cfg,
218
- accountId
219
- });
220
- const space = await resolveGoogleChatOutboundSpace({
221
- account,
222
- target: to
223
- });
224
- const thread = typeof threadId === "number" ? String(threadId) : threadId ?? replyToId ?? void 0;
225
- const { sendGoogleChatMessage } = await loadGoogleChatChannelRuntime$2();
226
- const messageId = (await sendGoogleChatMessage({
227
- account,
228
- space,
229
- text,
230
- thread
231
- }))?.messageName ?? "";
232
- return {
233
- messageId,
234
- chatId: space,
235
- receipt: createGoogleChatSendReceipt({
236
- messageId,
237
- chatId: space,
238
- kind: "text"
239
- })
240
- };
241
- },
242
- sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, accountId, replyToId, threadId }) => {
243
- if (!mediaUrl) throw new Error("Google Chat mediaUrl is required.");
244
- const account = resolveGoogleChatAccount({
245
- cfg,
246
- accountId
247
- });
248
- const space = await resolveGoogleChatOutboundSpace({
249
- account,
250
- target: to
251
- });
252
- const thread = typeof threadId === "number" ? String(threadId) : threadId ?? replyToId ?? void 0;
253
- const effectiveMaxBytes = resolveChannelMediaMaxBytes({
254
- cfg,
255
- resolveChannelLimitMb: ({ cfg: cfgLocal, accountId: accountIdLocal }) => (cfgLocal.channels?.googlechat)?.accounts?.[accountIdLocal]?.mediaMaxMb ?? (cfgLocal.channels?.googlechat)?.mediaMaxMb,
256
- accountId
257
- }) ?? (account.config.mediaMaxMb ?? 20) * 1024 * 1024;
258
- const loaded = /^https?:\/\//i.test(mediaUrl) ? await readRemoteMediaBuffer({
259
- url: mediaUrl,
260
- maxBytes: effectiveMaxBytes
261
- }) : await loadOutboundMediaFromUrl(mediaUrl, {
262
- maxBytes: effectiveMaxBytes,
263
- mediaAccess,
264
- mediaLocalRoots,
265
- mediaReadFile
266
- });
267
- const { sendGoogleChatMessage, uploadGoogleChatAttachment } = await loadGoogleChatChannelRuntime$2();
268
- const upload = await uploadGoogleChatAttachment({
269
- account,
270
- space,
271
- filename: loaded.fileName ?? "attachment",
272
- buffer: loaded.buffer,
273
- contentType: loaded.contentType
274
- });
275
- const messageId = (await sendGoogleChatMessage({
276
- account,
277
- space,
278
- text,
279
- thread,
280
- attachments: upload.attachmentUploadToken ? [{
281
- attachmentUploadToken: upload.attachmentUploadToken,
282
- contentName: loaded.fileName
283
- }] : void 0
284
- }))?.messageName ?? "";
285
- return {
286
- messageId,
287
- chatId: space,
288
- receipt: createGoogleChatSendReceipt({
289
- messageId,
290
- chatId: space,
291
- kind: "media"
292
- })
293
- };
294
- }
295
- }
296
- };
297
- const googlechatMessageAdapter = defineChannelMessageAdapter({
298
- id: "googlechat",
299
- durableFinal: { capabilities: {
300
- text: true,
301
- media: true,
302
- thread: true,
303
- messageSendingHooks: true
304
- } },
305
- send: {
306
- text: googlechatOutboundAdapter.attachedResults.sendText,
307
- media: googlechatOutboundAdapter.attachedResults.sendMedia
308
- }
309
- });
310
- //#endregion
311
- //#region extensions/googlechat/src/doctor.ts
312
- function asObjectRecord(value) {
313
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
314
- }
315
- function isGoogleChatMutableAllowEntry(raw) {
316
- const text = raw.trim();
317
- if (!text || text === "*") return false;
318
- const withoutPrefix = text.replace(/^(googlechat|google-chat|gchat):/i, "").trim();
319
- if (!withoutPrefix) return false;
320
- return withoutPrefix.replace(/^users\//i, "").includes("@");
321
- }
322
- const collectGoogleChatMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
323
- channel: "googlechat",
324
- detector: isGoogleChatMutableAllowEntry,
325
- collectLists: (scope) => {
326
- const lists = [{
327
- pathLabel: `${scope.prefix}.groupAllowFrom`,
328
- list: scope.account.groupAllowFrom
329
- }];
330
- const dm = asObjectRecord(scope.account.dm);
331
- if (dm) lists.push({
332
- pathLabel: `${scope.prefix}.dm.allowFrom`,
333
- list: dm.allowFrom
334
- });
335
- const groups = asObjectRecord(scope.account.groups);
336
- if (groups) for (const [groupKey, groupRaw] of Object.entries(groups)) {
337
- const group = asObjectRecord(groupRaw);
338
- if (!group) continue;
339
- lists.push({
340
- pathLabel: `${scope.prefix}.groups.${groupKey}.users`,
341
- list: group.users
342
- });
343
- }
344
- return lists;
345
- }
346
- });
347
- //#endregion
348
- //#region extensions/googlechat/src/gateway.ts
349
- const loadGoogleChatChannelRuntime$1 = createLazyRuntimeNamedExport(() => import("./channel.runtime-C4eLDKR3.js"), "googleChatChannelRuntime");
350
- async function startGoogleChatGatewayAccount(ctx) {
351
- const account = ctx.account;
352
- const statusSink = createAccountStatusSink({
353
- accountId: account.accountId,
354
- setStatus: ctx.setStatus
355
- });
356
- ctx.log?.info?.(`[${account.accountId}] starting Google Chat webhook`);
357
- const { resolveGoogleChatWebhookPath, startGoogleChatMonitor } = await loadGoogleChatChannelRuntime$1();
358
- statusSink({
359
- running: true,
360
- lastStartAt: Date.now(),
361
- webhookPath: resolveGoogleChatWebhookPath({ account }),
362
- audienceType: account.config.audienceType,
363
- audience: account.config.audience
364
- });
365
- await runPassiveAccountLifecycle({
366
- abortSignal: ctx.abortSignal,
367
- start: async () => await startGoogleChatMonitor({
368
- account,
369
- config: ctx.cfg,
370
- runtime: ctx.runtime,
371
- abortSignal: ctx.abortSignal,
372
- webhookPath: account.config.webhookPath,
373
- webhookUrl: account.config.webhookUrl,
374
- statusSink
375
- }),
376
- stop: async (unregister) => {
377
- unregister?.();
378
- },
379
- onStop: async () => {
380
- statusSink({
381
- running: false,
382
- lastStopAt: Date.now()
383
- });
384
- }
385
- });
386
- }
387
- //#endregion
388
- //#region extensions/googlechat/src/channel.ts
389
- const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-C4eLDKR3.js"), "googleChatChannelRuntime");
390
- const googlechatActions = {
391
- describeMessageTool: ({ cfg, accountId }) => {
392
- const accounts = accountId ? [resolveGoogleChatAccount({
393
- cfg,
394
- accountId
395
- })].filter((account) => account.enabled && account.credentialSource !== "none") : listGoogleChatAccountIds(cfg).map((id) => resolveGoogleChatAccount({
396
- cfg,
397
- accountId: id
398
- })).filter((account) => account.enabled && account.credentialSource !== "none");
399
- if (accounts.length === 0) return null;
400
- const actions = new Set(["send", "upload-file"]);
401
- if (accounts.some((account) => account.config.actions?.reactions !== false)) {
402
- actions.add("react");
403
- actions.add("reactions");
404
- }
405
- return { actions: Array.from(actions) };
406
- },
407
- extractToolSend: ({ args }) => extractToolSend(args, "sendMessage"),
408
- handleAction: async (ctx) => {
409
- const { googlechatMessageActions } = await import("./actions-B4gjETr3.js");
410
- if (!googlechatMessageActions.handleAction) throw new Error("Google Chat actions are not available.");
411
- return await googlechatMessageActions.handleAction(ctx);
412
- }
413
- };
414
- const googlechatPlugin = createChatChannelPlugin({
415
- base: {
416
- ...createGoogleChatPluginBase({ configSchema: buildChannelConfigSchema(GoogleChatConfigSchema) }),
417
- approvalCapability: googleChatApprovalAuth,
418
- secrets: {
419
- secretTargetRegistryEntries,
420
- collectRuntimeConfigAssignments
421
- },
422
- groups: googlechatGroupsAdapter,
423
- messaging: {
424
- targetPrefixes: [
425
- "googlechat",
426
- "google-chat",
427
- "gchat"
428
- ],
429
- normalizeTarget: normalizeGoogleChatTarget,
430
- targetResolver: {
431
- looksLikeId: (raw, normalized) => {
432
- const value = normalized ?? raw.trim();
433
- return isGoogleChatSpaceTarget(value) || isGoogleChatUserTarget(value);
434
- },
435
- hint: "<spaces/{space}|users/{user}>"
436
- }
437
- },
438
- directory: googlechatDirectoryAdapter,
439
- message: googlechatMessageAdapter,
440
- resolver: { resolveTargets: async ({ inputs, kind }) => {
441
- return inputs.map((input) => {
442
- const normalized = normalizeGoogleChatTarget(input);
443
- if (!normalized) return {
444
- input,
445
- resolved: false,
446
- note: "empty target"
447
- };
448
- if (kind === "user" && isGoogleChatUserTarget(normalized)) return {
449
- input,
450
- resolved: true,
451
- id: normalized
452
- };
453
- if (kind === "group" && isGoogleChatSpaceTarget(normalized)) return {
454
- input,
455
- resolved: true,
456
- id: normalized
457
- };
458
- return {
459
- input,
460
- resolved: false,
461
- note: "use spaces/{space} or users/{user}"
462
- };
463
- });
464
- } },
465
- actions: googlechatActions,
466
- doctor: {
467
- dmAllowFromMode: "nestedOnly",
468
- groupModel: "route",
469
- groupAllowFromFallbackToAllowFrom: false,
470
- warnOnEmptyGroupSenderAllowlist: false,
471
- legacyConfigRules,
472
- normalizeCompatibilityConfig,
473
- collectMutableAllowlistWarnings: collectGoogleChatMutableAllowlistWarnings
474
- },
475
- status: createComputedAccountStatusAdapter({
476
- defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
477
- collectStatusIssues: (accounts) => accounts.flatMap((entry) => {
478
- const accountId = entry.accountId ?? DEFAULT_ACCOUNT_ID;
479
- const enabled = entry.enabled !== false;
480
- const configured = entry.configured === true;
481
- if (!enabled || !configured) return [];
482
- const issues = [];
483
- if (!entry.audience) issues.push({
484
- channel: GOOGLECHAT_CHANNEL_ID,
485
- accountId,
486
- kind: "config",
487
- message: "Google Chat audience is missing (set channels.googlechat.audience).",
488
- fix: "Set channels.googlechat.audienceType and channels.googlechat.audience."
489
- });
490
- if (!entry.audienceType) issues.push({
491
- channel: GOOGLECHAT_CHANNEL_ID,
492
- accountId,
493
- kind: "config",
494
- message: "Google Chat audienceType is missing (app-url or project-number).",
495
- fix: "Set channels.googlechat.audienceType and channels.googlechat.audience."
496
- });
497
- return issues;
498
- }),
499
- buildChannelSummary: ({ snapshot }) => buildPassiveProbedChannelStatusSummary(snapshot, {
500
- credentialSource: snapshot.credentialSource ?? "none",
501
- audienceType: snapshot.audienceType ?? null,
502
- audience: snapshot.audience ?? null,
503
- webhookPath: snapshot.webhookPath ?? null,
504
- webhookUrl: snapshot.webhookUrl ?? null
505
- }),
506
- probeAccount: async ({ account }) => (await loadGoogleChatChannelRuntime()).probeGoogleChat(account),
507
- resolveAccountSnapshot: ({ account }) => ({
508
- accountId: account.accountId,
509
- name: account.name,
510
- enabled: account.enabled,
511
- configured: account.credentialSource !== "none",
512
- extra: {
513
- credentialSource: account.credentialSource,
514
- audienceType: account.config.audienceType,
515
- audience: account.config.audience,
516
- webhookPath: account.config.webhookPath,
517
- webhookUrl: account.config.webhookUrl,
518
- dmPolicy: account.config.dm?.policy ?? "pairing"
519
- }
520
- })
521
- }),
522
- gateway: { startAccount: startGoogleChatGatewayAccount }
523
- },
524
- pairing: { text: googlechatPairingTextAdapter },
525
- security: googlechatSecurityAdapter,
526
- threading: googlechatThreadingAdapter,
527
- outbound: googlechatOutboundAdapter
528
- });
529
- //#endregion
530
- export { resolveGoogleChatOutboundSpace as n, googlechatPlugin as t };