@openclaw/google-meet 2026.5.28 → 2026.5.30-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,5 +1,6 @@
1
1
  import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
2
2
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
3
+ import { addTimerTimeoutGraceMs } from "openclaw/plugin-sdk/number-runtime";
3
4
  import { sleep } from "openclaw/plugin-sdk/runtime-env";
4
5
  //#region extensions/google-meet/src/google-api-errors.ts
5
6
  const REAUTH_HINT = "Re-run `openclaw googlemeet auth login` and store the refreshed oauth block.";
@@ -711,7 +712,7 @@ async function callBrowserProxyOnNode(params) {
711
712
  body: params.body,
712
713
  timeoutMs: params.timeoutMs
713
714
  },
714
- timeoutMs: params.timeoutMs + 5e3
715
+ timeoutMs: addTimerTimeoutGraceMs(params.timeoutMs) ?? 1
715
716
  }));
716
717
  }
717
718
  function asBrowserTabs(result) {
@@ -1,15 +1,21 @@
1
- import { d as createGoogleMeetSpace, f as endGoogleMeetActiveConference, g as fetchLatestGoogleMeetConferenceRecord, h as fetchGoogleMeetSpace, m as fetchGoogleMeetAttendance, p as fetchGoogleMeetArtifacts, u as buildGoogleMeetPreflightReport } from "./chrome-create-B3zyjf5f.js";
2
- import { n as findGoogleMeetCalendarEvent, r as listGoogleMeetCalendarEvents, t as buildGoogleMeetCalendarDayWindow } from "./calendar-IxWkFtfn.js";
3
- import { buildGoogleMeetAuthUrl, createGoogleMeetOAuthState, createGoogleMeetPkce, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-B3tz8JcD.js";
4
- import { hasCreateSpaceConfigInput, resolveCreateSpaceConfig } from "./create-OMWgK9on.js";
1
+ import { d as createGoogleMeetSpace, f as endGoogleMeetActiveConference, g as fetchLatestGoogleMeetConferenceRecord, h as fetchGoogleMeetSpace, m as fetchGoogleMeetAttendance, p as fetchGoogleMeetArtifacts, u as buildGoogleMeetPreflightReport } from "./chrome-create-By4DuikO.js";
2
+ import { a as buildGoogleMeetCalendarDayWindow, i as resolveGoogleMeetGatewayOperationTimeoutMs, o as findGoogleMeetCalendarEvent, s as listGoogleMeetCalendarEvents } from "./config-HmaADLv3.js";
3
+ import { buildGoogleMeetAuthUrl, createGoogleMeetOAuthState, createGoogleMeetPkce, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth--J53aI66.js";
4
+ import { hasCreateSpaceConfigInput, resolveCreateSpaceConfig } from "./create-BzkoPzD2.js";
5
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
6
  import { callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
7
+ import { clampTimerTimeoutMs, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
7
8
  import path from "node:path";
8
9
  import { mkdir, writeFile } from "node:fs/promises";
9
10
  import { createInterface } from "node:readline/promises";
10
11
  import { format } from "node:util";
11
- import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
12
12
  //#region extensions/google-meet/src/cli.ts
13
+ const testing = {
14
+ parsePositiveNumber,
15
+ resolveGoogleMeetGatewayOperationTimeoutMs,
16
+ resolveGoogleMeetGatewayTimeoutMs,
17
+ resolveGoogleMeetOAuthCallbackTimeoutMs
18
+ };
13
19
  const GOOGLE_MEET_GATEWAY_DEFAULT_TIMEOUT_MS = 5e3;
14
20
  const PLAIN_DECIMAL_NUMBER_RE = /^\d+(?:\.\d+)?$/;
15
21
  function writeStdoutJson(value) {
@@ -65,6 +71,12 @@ function parsePositiveNumber(value, label) {
65
71
  if (!Number.isFinite(parsed) || parsed <= 0) throw new Error(`${label} must be a positive number`);
66
72
  return parsed;
67
73
  }
74
+ function resolveGoogleMeetGatewayTimeoutMs(timeoutMs) {
75
+ return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) ? clampTimerTimeoutMs(Math.ceil(timeoutMs)) ?? 1 : GOOGLE_MEET_GATEWAY_DEFAULT_TIMEOUT_MS;
76
+ }
77
+ function resolveGoogleMeetOAuthCallbackTimeoutMs(timeoutSec) {
78
+ return clampTimerTimeoutMs((parsePositiveNumber(timeoutSec, "timeout-sec") ?? 300) * 1e3) ?? 3e5;
79
+ }
68
80
  function parsePositiveIntegerOption(value, label) {
69
81
  if (value === void 0) return;
70
82
  const parsed = parseStrictPositiveInteger(value);
@@ -73,7 +85,7 @@ function parsePositiveIntegerOption(value, label) {
73
85
  }
74
86
  async function callGoogleMeetGateway(params) {
75
87
  try {
76
- const timeoutMs = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) ? Math.max(1, Math.ceil(params.timeoutMs)) : GOOGLE_MEET_GATEWAY_DEFAULT_TIMEOUT_MS;
88
+ const timeoutMs = resolveGoogleMeetGatewayTimeoutMs(params.timeoutMs);
77
89
  return {
78
90
  ok: true,
79
91
  payload: await params.callGateway(params.method, {
@@ -89,9 +101,6 @@ async function callGoogleMeetGateway(params) {
89
101
  throw err;
90
102
  }
91
103
  }
92
- function resolveGoogleMeetGatewayOperationTimeoutMs(config) {
93
- return Math.max(6e4, config.chrome.joinTimeoutMs + 3e4, config.voiceCall.requestTimeoutMs + 1e4);
94
- }
95
104
  function formatDuration(value) {
96
105
  if (value === void 0) return "n/a";
97
106
  const totalSeconds = Math.round(value / 1e3);
@@ -857,7 +866,7 @@ function registerGoogleMeetCli(params) {
857
866
  code: await waitForGoogleMeetAuthCode({
858
867
  state,
859
868
  manual: Boolean(options.manual),
860
- timeoutMs: (parsePositiveNumber(options.timeoutSec, "timeout-sec") ?? 300) * 1e3,
869
+ timeoutMs: resolveGoogleMeetOAuthCallbackTimeoutMs(options.timeoutSec),
861
870
  authUrl,
862
871
  promptInput,
863
872
  writeLine: (message) => writeStdoutLine("%s", message)
@@ -1397,4 +1406,4 @@ function registerGoogleMeetCli(params) {
1397
1406
  });
1398
1407
  }
1399
1408
  //#endregion
1400
- export { buildGoogleMeetExportManifest, googleMeetExportFileNames, registerGoogleMeetCli, writeMeetExportBundle };
1409
+ export { buildGoogleMeetExportManifest, googleMeetExportFileNames, registerGoogleMeetCli, testing, writeMeetExportBundle };
@@ -0,0 +1,464 @@
1
+ import { _ as googleApiError } from "./chrome-create-By4DuikO.js";
2
+ import { asRecord, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
4
+ import { addTimerTimeoutGraceMs } from "openclaw/plugin-sdk/number-runtime";
5
+ import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, resolveRealtimeVoiceAgentConsultToolPolicy } from "openclaw/plugin-sdk/realtime-voice";
6
+ //#region extensions/google-meet/src/calendar.ts
7
+ const GOOGLE_CALENDAR_API_BASE_URL = "https://www.googleapis.com/calendar/v3";
8
+ const GOOGLE_CALENDAR_API_HOST = "www.googleapis.com";
9
+ const GOOGLE_MEET_URL_HOST = "meet.google.com";
10
+ const GOOGLE_CALENDAR_EVENTS_SCOPE = "https://www.googleapis.com/auth/calendar.events.readonly";
11
+ function appendQuery(url, query) {
12
+ const parsed = new URL(url);
13
+ for (const [key, value] of Object.entries(query)) if (value !== void 0) parsed.searchParams.set(key, String(value));
14
+ return parsed.toString();
15
+ }
16
+ function isGoogleMeetUri(value) {
17
+ if (!value?.trim()) return false;
18
+ try {
19
+ return new URL(value).hostname === GOOGLE_MEET_URL_HOST;
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+ function extractGoogleMeetUriFromText(value) {
25
+ return (value?.match(/https:\/\/meet\.google\.com\/[a-z0-9-]+/i))?.[0];
26
+ }
27
+ function extractGoogleMeetUriFromCalendarEvent(event) {
28
+ if (isGoogleMeetUri(event.hangoutLink)) return event.hangoutLink;
29
+ const entryPoints = event.conferenceData?.entryPoints ?? [];
30
+ const videoEntry = entryPoints.find((entry) => entry.entryPointType === "video" && isGoogleMeetUri(entry.uri));
31
+ if (videoEntry?.uri) return videoEntry.uri;
32
+ const meetEntry = entryPoints.find((entry) => isGoogleMeetUri(entry.uri));
33
+ if (meetEntry?.uri) return meetEntry.uri;
34
+ return extractGoogleMeetUriFromText(event.location) ?? extractGoogleMeetUriFromText(event.description);
35
+ }
36
+ function buildGoogleMeetCalendarDayWindow(now = /* @__PURE__ */ new Date()) {
37
+ const start = new Date(now);
38
+ start.setHours(0, 0, 0, 0);
39
+ const end = new Date(start);
40
+ end.setDate(start.getDate() + 1);
41
+ return {
42
+ timeMin: start.toISOString(),
43
+ timeMax: end.toISOString()
44
+ };
45
+ }
46
+ function parseCalendarEventTime(value) {
47
+ const raw = value?.dateTime ?? value?.date;
48
+ if (!raw) return;
49
+ const parsed = Date.parse(raw);
50
+ return Number.isFinite(parsed) ? parsed : void 0;
51
+ }
52
+ function rankCalendarEvent(event, nowMs) {
53
+ const startMs = parseCalendarEventTime(event.start) ?? Number.POSITIVE_INFINITY;
54
+ const endMs = parseCalendarEventTime(event.end) ?? startMs;
55
+ if (startMs <= nowMs && endMs >= nowMs) return 0;
56
+ if (startMs > nowMs) return startMs - nowMs;
57
+ return nowMs - startMs + 720 * 60 * 60 * 1e3;
58
+ }
59
+ function chooseBestMeetCalendarEvent(events, now) {
60
+ const nowMs = now.getTime();
61
+ let selected;
62
+ let selectedRank = Number.POSITIVE_INFINITY;
63
+ for (const event of events) {
64
+ if (event.status === "cancelled" || !extractGoogleMeetUriFromCalendarEvent(event)) continue;
65
+ const rank = rankCalendarEvent(event, nowMs);
66
+ if (!selected || rank < selectedRank) {
67
+ selected = event;
68
+ selectedRank = rank;
69
+ }
70
+ }
71
+ return selected;
72
+ }
73
+ async function fetchGoogleCalendarEvents(params) {
74
+ const calendarId = params.calendarId?.trim() || "primary";
75
+ const now = params.now ?? /* @__PURE__ */ new Date();
76
+ const defaultTimeMax = new Date(now);
77
+ defaultTimeMax.setDate(defaultTimeMax.getDate() + 7);
78
+ const { response, release } = await fetchWithSsrFGuard({
79
+ url: appendQuery(`${GOOGLE_CALENDAR_API_BASE_URL}/calendars/${encodeURIComponent(calendarId)}/events`, {
80
+ maxResults: params.maxResults ?? 50,
81
+ orderBy: "startTime",
82
+ q: params.eventQuery?.trim() || void 0,
83
+ showDeleted: false,
84
+ singleEvents: true,
85
+ timeMin: params.timeMin ?? now.toISOString(),
86
+ timeMax: params.timeMax ?? defaultTimeMax.toISOString()
87
+ }),
88
+ init: { headers: {
89
+ Authorization: `Bearer ${params.accessToken}`,
90
+ Accept: "application/json"
91
+ } },
92
+ policy: { allowedHostnames: [GOOGLE_CALENDAR_API_HOST] },
93
+ auditContext: "google-meet.calendar.events.list"
94
+ });
95
+ try {
96
+ if (!response.ok) throw await googleApiError({
97
+ response,
98
+ detail: await response.text(),
99
+ prefix: "Google Calendar events.list",
100
+ scopes: [GOOGLE_CALENDAR_EVENTS_SCOPE]
101
+ });
102
+ const payload = await response.json();
103
+ if (payload.items !== void 0 && !Array.isArray(payload.items)) throw new Error("Google Calendar events.list response had non-array items");
104
+ return {
105
+ calendarId,
106
+ events: payload.items ?? [],
107
+ now
108
+ };
109
+ } finally {
110
+ await release();
111
+ }
112
+ }
113
+ async function listGoogleMeetCalendarEvents(params) {
114
+ const { calendarId, events, now } = await fetchGoogleCalendarEvents(params);
115
+ const best = chooseBestMeetCalendarEvent(events, now);
116
+ return {
117
+ calendarId,
118
+ events: events.map((event) => {
119
+ const meetingUri = extractGoogleMeetUriFromCalendarEvent(event);
120
+ return meetingUri ? {
121
+ event,
122
+ meetingUri,
123
+ selected: event === best
124
+ } : void 0;
125
+ }).filter((event) => Boolean(event))
126
+ };
127
+ }
128
+ async function findGoogleMeetCalendarEvent(params) {
129
+ const result = await listGoogleMeetCalendarEvents(params);
130
+ const selected = result.events.find((event) => event.selected) ?? result.events[0];
131
+ if (!selected) throw new Error("No Google Calendar event with a Google Meet link matched the query");
132
+ return {
133
+ calendarId: result.calendarId,
134
+ event: selected.event,
135
+ meetingUri: selected.meetingUri
136
+ };
137
+ }
138
+ //#endregion
139
+ //#region extensions/google-meet/src/config.ts
140
+ function resolveGoogleMeetGatewayOperationTimeoutMs(config) {
141
+ return Math.max(6e4, addTimerTimeoutGraceMs(config.chrome.joinTimeoutMs, 3e4) ?? 1, addTimerTimeoutGraceMs(config.voiceCall.requestTimeoutMs, 1e4) ?? 1);
142
+ }
143
+ const SOX_DEFAULT_BUFFER_BYTES = 8192;
144
+ const SOX_MIN_BUFFER_BYTES = 17;
145
+ const DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES = SOX_DEFAULT_BUFFER_BYTES / 2;
146
+ const PLAIN_DECIMAL_NUMBER_RE = /^\d+(?:\.\d+)?$/;
147
+ function withSoxBuffer(command, bufferBytes) {
148
+ return [
149
+ command[0] ?? "sox",
150
+ "-q",
151
+ "--buffer",
152
+ String(bufferBytes),
153
+ ...command.slice(2)
154
+ ];
155
+ }
156
+ const DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE = [
157
+ "sox",
158
+ "-q",
159
+ "-t",
160
+ "coreaudio",
161
+ "BlackHole 2ch",
162
+ "-t",
163
+ "raw",
164
+ "-r",
165
+ "24000",
166
+ "-c",
167
+ "1",
168
+ "-e",
169
+ "signed-integer",
170
+ "-b",
171
+ "16",
172
+ "-L",
173
+ "-"
174
+ ];
175
+ const DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE = [
176
+ "sox",
177
+ "-q",
178
+ "-t",
179
+ "raw",
180
+ "-r",
181
+ "24000",
182
+ "-c",
183
+ "1",
184
+ "-e",
185
+ "signed-integer",
186
+ "-b",
187
+ "16",
188
+ "-L",
189
+ "-",
190
+ "-t",
191
+ "coreaudio",
192
+ "BlackHole 2ch"
193
+ ];
194
+ const LEGACY_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE = [
195
+ "rec",
196
+ "-q",
197
+ "-t",
198
+ "raw",
199
+ "-r",
200
+ "8000",
201
+ "-c",
202
+ "1",
203
+ "-e",
204
+ "mu-law",
205
+ "-b",
206
+ "8",
207
+ "-"
208
+ ];
209
+ const LEGACY_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE = [
210
+ "play",
211
+ "-q",
212
+ "-t",
213
+ "raw",
214
+ "-r",
215
+ "8000",
216
+ "-c",
217
+ "1",
218
+ "-e",
219
+ "mu-law",
220
+ "-b",
221
+ "8",
222
+ "-"
223
+ ];
224
+ const DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND = withSoxBuffer(DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE, DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES);
225
+ const DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND = withSoxBuffer(DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE, DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES);
226
+ const DEFAULT_GOOGLE_MEET_CHROME_AUDIO_FORMAT = "pcm16-24khz";
227
+ const DEFAULT_GOOGLE_MEET_BARGE_IN_RMS_THRESHOLD = 650;
228
+ const DEFAULT_GOOGLE_MEET_BARGE_IN_PEAK_THRESHOLD = 2500;
229
+ const DEFAULT_GOOGLE_MEET_BARGE_IN_COOLDOWN_MS = 900;
230
+ const DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS = `You are joining a private Google Meet as an OpenClaw voice transport. Keep spoken replies brief and natural. In agent mode, wait for OpenClaw consult results and speak them exactly. In bidi mode, answer directly and call ${REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME} for deeper reasoning, current information, or tools.`;
231
+ const DEFAULT_GOOGLE_MEET_REALTIME_INTRO_MESSAGE = "Say exactly: I'm here and listening.";
232
+ const DEFAULT_GOOGLE_MEET_CONFIG = {
233
+ enabled: true,
234
+ defaults: {},
235
+ preview: { enrollmentAcknowledged: false },
236
+ defaultTransport: "chrome",
237
+ defaultMode: "agent",
238
+ chrome: {
239
+ audioBackend: "blackhole-2ch",
240
+ audioFormat: DEFAULT_GOOGLE_MEET_CHROME_AUDIO_FORMAT,
241
+ audioBufferBytes: DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES,
242
+ launch: true,
243
+ guestName: "OpenClaw Agent",
244
+ reuseExistingTab: true,
245
+ autoJoin: true,
246
+ joinTimeoutMs: 3e4,
247
+ waitForInCallMs: 2e4,
248
+ audioInputCommand: [...DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND],
249
+ audioOutputCommand: [...DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND],
250
+ bargeInRmsThreshold: DEFAULT_GOOGLE_MEET_BARGE_IN_RMS_THRESHOLD,
251
+ bargeInPeakThreshold: DEFAULT_GOOGLE_MEET_BARGE_IN_PEAK_THRESHOLD,
252
+ bargeInCooldownMs: DEFAULT_GOOGLE_MEET_BARGE_IN_COOLDOWN_MS
253
+ },
254
+ chromeNode: {},
255
+ twilio: {},
256
+ voiceCall: {
257
+ enabled: true,
258
+ requestTimeoutMs: 3e4,
259
+ dtmfDelayMs: 12e3,
260
+ postDtmfSpeechDelayMs: 5e3
261
+ },
262
+ realtime: {
263
+ strategy: "agent",
264
+ provider: "openai",
265
+ transcriptionProvider: "openai",
266
+ instructions: DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS,
267
+ introMessage: DEFAULT_GOOGLE_MEET_REALTIME_INTRO_MESSAGE,
268
+ toolPolicy: "safe-read-only",
269
+ providers: {}
270
+ },
271
+ oauth: {},
272
+ auth: { provider: "google-oauth" }
273
+ };
274
+ const GOOGLE_MEET_CLIENT_ID_KEYS = ["OPENCLAW_GOOGLE_MEET_CLIENT_ID", "GOOGLE_MEET_CLIENT_ID"];
275
+ const GOOGLE_MEET_CLIENT_SECRET_KEYS = ["OPENCLAW_GOOGLE_MEET_CLIENT_SECRET", "GOOGLE_MEET_CLIENT_SECRET"];
276
+ const GOOGLE_MEET_REFRESH_TOKEN_KEYS = ["OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN", "GOOGLE_MEET_REFRESH_TOKEN"];
277
+ const GOOGLE_MEET_ACCESS_TOKEN_KEYS = ["OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN", "GOOGLE_MEET_ACCESS_TOKEN"];
278
+ const GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT_KEYS = ["OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT", "GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT"];
279
+ const GOOGLE_MEET_DEFAULT_MEETING_KEYS = ["OPENCLAW_GOOGLE_MEET_DEFAULT_MEETING", "GOOGLE_MEET_DEFAULT_MEETING"];
280
+ const GOOGLE_MEET_PREVIEW_ACK_KEYS = ["OPENCLAW_GOOGLE_MEET_PREVIEW_ACK", "GOOGLE_MEET_PREVIEW_ACK"];
281
+ function resolveBoolean(value, fallback) {
282
+ return typeof value === "boolean" ? value : fallback;
283
+ }
284
+ function resolveNumber(value, fallback) {
285
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
286
+ }
287
+ function resolveOptionalNumber(value) {
288
+ if (typeof value === "number" && Number.isFinite(value)) return value;
289
+ if (typeof value === "string" && value.trim()) {
290
+ const trimmed = value.trim();
291
+ const parsed = PLAIN_DECIMAL_NUMBER_RE.test(trimmed) ? Number(trimmed) : NaN;
292
+ return Number.isFinite(parsed) ? parsed : void 0;
293
+ }
294
+ }
295
+ function readEnvString(env, keys) {
296
+ for (const key of keys) {
297
+ const value = normalizeOptionalString(env[key]);
298
+ if (value) return value;
299
+ }
300
+ }
301
+ function normalizeStringAllowEmpty(value) {
302
+ return typeof value === "string" ? value.trim() : void 0;
303
+ }
304
+ function readEnvBoolean(env, keys) {
305
+ const normalized = normalizeOptionalLowercaseString(readEnvString(env, keys));
306
+ if (!normalized) return;
307
+ if ([
308
+ "1",
309
+ "true",
310
+ "yes",
311
+ "on"
312
+ ].includes(normalized)) return true;
313
+ if ([
314
+ "0",
315
+ "false",
316
+ "no",
317
+ "off"
318
+ ].includes(normalized)) return false;
319
+ }
320
+ function readEnvNumber(env, keys) {
321
+ return resolveOptionalNumber(readEnvString(env, keys));
322
+ }
323
+ function resolveStringArray(value) {
324
+ return normalizeOptionalTrimmedStringList(value);
325
+ }
326
+ function resolveProvidersConfig(value) {
327
+ const raw = asRecord(value);
328
+ const providers = {};
329
+ for (const [key, entry] of Object.entries(raw)) {
330
+ const providerId = normalizeOptionalLowercaseString(key);
331
+ if (!providerId) continue;
332
+ providers[providerId] = asRecord(entry);
333
+ }
334
+ return providers;
335
+ }
336
+ function resolveTransport(value, fallback) {
337
+ const normalized = normalizeOptionalLowercaseString(value);
338
+ return normalized === "chrome" || normalized === "chrome-node" || normalized === "twilio" ? normalized : fallback;
339
+ }
340
+ function resolveMode(value, fallback) {
341
+ const normalized = normalizeOptionalLowercaseString(value);
342
+ if (normalized === "realtime") return "agent";
343
+ return normalized === "agent" || normalized === "bidi" || normalized === "transcribe" ? normalized : fallback;
344
+ }
345
+ function resolveRealtimeStrategy(value, fallback) {
346
+ const normalized = normalizeOptionalLowercaseString(value);
347
+ return normalized === "agent" || normalized === "bidi" ? normalized : fallback;
348
+ }
349
+ function resolveChromeAudioFormat(value) {
350
+ switch (normalizeOptionalString(value)?.toLowerCase().replaceAll("_", "-")) {
351
+ case "pcm16-24khz":
352
+ case "pcm16-24k":
353
+ case "pcm24":
354
+ case "pcm": return "pcm16-24khz";
355
+ case "g711-ulaw-8khz":
356
+ case "g711-ulaw-8k":
357
+ case "g711-ulaw":
358
+ case "mulaw":
359
+ case "mu-law": return "g711-ulaw-8khz";
360
+ default: return;
361
+ }
362
+ }
363
+ function resolveAudioBufferBytes(value, fallback) {
364
+ const number = resolveNumber(value, fallback);
365
+ if (!Number.isFinite(number) || number <= 0) return fallback;
366
+ return Math.max(SOX_MIN_BUFFER_BYTES, Math.trunc(number));
367
+ }
368
+ function defaultAudioInputCommand(format, bufferBytes) {
369
+ return withSoxBuffer(format === "g711-ulaw-8khz" ? LEGACY_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE : DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE, bufferBytes);
370
+ }
371
+ function defaultAudioOutputCommand(format, bufferBytes) {
372
+ return withSoxBuffer(format === "g711-ulaw-8khz" ? LEGACY_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE : DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE, bufferBytes);
373
+ }
374
+ function resolveGoogleMeetConfig(input) {
375
+ return resolveGoogleMeetConfigWithEnv(input);
376
+ }
377
+ function resolveGoogleMeetConfigWithEnv(input, env = process.env) {
378
+ const raw = asRecord(input);
379
+ const defaults = asRecord(raw.defaults);
380
+ const preview = asRecord(raw.preview);
381
+ const chrome = asRecord(raw.chrome);
382
+ const configuredAudioInputCommand = resolveStringArray(chrome.audioInputCommand);
383
+ const configuredAudioOutputCommand = resolveStringArray(chrome.audioOutputCommand);
384
+ const hasCustomAudioCommand = configuredAudioInputCommand !== void 0 || configuredAudioOutputCommand !== void 0;
385
+ const audioFormat = resolveChromeAudioFormat(chrome.audioFormat) ?? (hasCustomAudioCommand ? "g711-ulaw-8khz" : DEFAULT_GOOGLE_MEET_CONFIG.chrome.audioFormat);
386
+ const audioBufferBytes = resolveAudioBufferBytes(chrome.audioBufferBytes, DEFAULT_GOOGLE_MEET_CONFIG.chrome.audioBufferBytes);
387
+ const chromeNode = asRecord(raw.chromeNode);
388
+ const twilio = asRecord(raw.twilio);
389
+ const voiceCall = asRecord(raw.voiceCall);
390
+ const realtime = asRecord(raw.realtime);
391
+ const realtimeProvider = normalizeOptionalString(realtime.provider);
392
+ const resolvedRealtimeProvider = realtimeProvider ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.provider;
393
+ const oauth = asRecord(raw.oauth);
394
+ const auth = asRecord(raw.auth);
395
+ return {
396
+ enabled: resolveBoolean(raw.enabled, DEFAULT_GOOGLE_MEET_CONFIG.enabled),
397
+ defaults: { meeting: normalizeOptionalString(defaults.meeting) ?? readEnvString(env, GOOGLE_MEET_DEFAULT_MEETING_KEYS) },
398
+ preview: { enrollmentAcknowledged: resolveBoolean(preview.enrollmentAcknowledged, readEnvBoolean(env, GOOGLE_MEET_PREVIEW_ACK_KEYS) ?? DEFAULT_GOOGLE_MEET_CONFIG.preview.enrollmentAcknowledged) },
399
+ defaultTransport: resolveTransport(raw.defaultTransport, DEFAULT_GOOGLE_MEET_CONFIG.defaultTransport),
400
+ defaultMode: resolveMode(raw.defaultMode, DEFAULT_GOOGLE_MEET_CONFIG.defaultMode),
401
+ chrome: {
402
+ audioBackend: "blackhole-2ch",
403
+ audioFormat,
404
+ audioBufferBytes,
405
+ launch: resolveBoolean(chrome.launch, DEFAULT_GOOGLE_MEET_CONFIG.chrome.launch),
406
+ browserProfile: normalizeOptionalString(chrome.browserProfile),
407
+ guestName: normalizeOptionalString(chrome.guestName) ?? DEFAULT_GOOGLE_MEET_CONFIG.chrome.guestName,
408
+ reuseExistingTab: resolveBoolean(chrome.reuseExistingTab, DEFAULT_GOOGLE_MEET_CONFIG.chrome.reuseExistingTab),
409
+ autoJoin: resolveBoolean(chrome.autoJoin, DEFAULT_GOOGLE_MEET_CONFIG.chrome.autoJoin),
410
+ joinTimeoutMs: resolveNumber(chrome.joinTimeoutMs, DEFAULT_GOOGLE_MEET_CONFIG.chrome.joinTimeoutMs),
411
+ waitForInCallMs: resolveNumber(chrome.waitForInCallMs, DEFAULT_GOOGLE_MEET_CONFIG.chrome.waitForInCallMs),
412
+ audioInputCommand: configuredAudioInputCommand ?? defaultAudioInputCommand(audioFormat, audioBufferBytes),
413
+ audioOutputCommand: configuredAudioOutputCommand ?? defaultAudioOutputCommand(audioFormat, audioBufferBytes),
414
+ bargeInInputCommand: resolveStringArray(chrome.bargeInInputCommand),
415
+ bargeInRmsThreshold: resolveNumber(chrome.bargeInRmsThreshold, DEFAULT_GOOGLE_MEET_CONFIG.chrome.bargeInRmsThreshold),
416
+ bargeInPeakThreshold: resolveNumber(chrome.bargeInPeakThreshold, DEFAULT_GOOGLE_MEET_CONFIG.chrome.bargeInPeakThreshold),
417
+ bargeInCooldownMs: resolveNumber(chrome.bargeInCooldownMs, DEFAULT_GOOGLE_MEET_CONFIG.chrome.bargeInCooldownMs),
418
+ audioBridgeCommand: resolveStringArray(chrome.audioBridgeCommand),
419
+ audioBridgeHealthCommand: resolveStringArray(chrome.audioBridgeHealthCommand)
420
+ },
421
+ chromeNode: { node: normalizeOptionalString(chromeNode.node) },
422
+ twilio: {
423
+ defaultDialInNumber: normalizeOptionalString(twilio.defaultDialInNumber),
424
+ defaultPin: normalizeOptionalString(twilio.defaultPin),
425
+ defaultDtmfSequence: normalizeOptionalString(twilio.defaultDtmfSequence)
426
+ },
427
+ voiceCall: {
428
+ enabled: resolveBoolean(voiceCall.enabled, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.enabled),
429
+ gatewayUrl: normalizeOptionalString(voiceCall.gatewayUrl),
430
+ token: normalizeOptionalString(voiceCall.token),
431
+ requestTimeoutMs: resolveNumber(voiceCall.requestTimeoutMs, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.requestTimeoutMs),
432
+ dtmfDelayMs: resolveNumber(voiceCall.dtmfDelayMs, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.dtmfDelayMs),
433
+ postDtmfSpeechDelayMs: resolveNumber(voiceCall.postDtmfSpeechDelayMs, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.postDtmfSpeechDelayMs),
434
+ introMessage: normalizeOptionalString(voiceCall.introMessage)
435
+ },
436
+ realtime: {
437
+ strategy: resolveRealtimeStrategy(realtime.strategy, DEFAULT_GOOGLE_MEET_CONFIG.realtime.strategy),
438
+ provider: resolvedRealtimeProvider,
439
+ transcriptionProvider: normalizeOptionalString(realtime.transcriptionProvider) ?? (realtimeProvider && realtimeProvider !== "google" ? resolvedRealtimeProvider : DEFAULT_GOOGLE_MEET_CONFIG.realtime.transcriptionProvider),
440
+ voiceProvider: normalizeOptionalString(realtime.voiceProvider),
441
+ model: normalizeOptionalString(realtime.model) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.model,
442
+ instructions: normalizeOptionalString(realtime.instructions) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.instructions,
443
+ introMessage: normalizeStringAllowEmpty(realtime.introMessage) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.introMessage,
444
+ agentId: normalizeOptionalString(realtime.agentId),
445
+ toolPolicy: resolveRealtimeVoiceAgentConsultToolPolicy(realtime.toolPolicy, DEFAULT_GOOGLE_MEET_CONFIG.realtime.toolPolicy),
446
+ providers: resolveProvidersConfig(realtime.providers)
447
+ },
448
+ oauth: {
449
+ clientId: normalizeOptionalString(oauth.clientId) ?? normalizeOptionalString(auth.clientId) ?? readEnvString(env, GOOGLE_MEET_CLIENT_ID_KEYS),
450
+ clientSecret: normalizeOptionalString(oauth.clientSecret) ?? normalizeOptionalString(auth.clientSecret) ?? readEnvString(env, GOOGLE_MEET_CLIENT_SECRET_KEYS),
451
+ refreshToken: normalizeOptionalString(oauth.refreshToken) ?? readEnvString(env, GOOGLE_MEET_REFRESH_TOKEN_KEYS),
452
+ accessToken: normalizeOptionalString(oauth.accessToken) ?? readEnvString(env, GOOGLE_MEET_ACCESS_TOKEN_KEYS),
453
+ expiresAt: resolveOptionalNumber(oauth.expiresAt) ?? readEnvNumber(env, GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT_KEYS)
454
+ },
455
+ auth: {
456
+ provider: "google-oauth",
457
+ clientId: normalizeOptionalString(auth.clientId),
458
+ clientSecret: normalizeOptionalString(auth.clientSecret),
459
+ tokenPath: normalizeOptionalString(auth.tokenPath)
460
+ }
461
+ };
462
+ }
463
+ //#endregion
464
+ export { buildGoogleMeetCalendarDayWindow as a, resolveGoogleMeetGatewayOperationTimeoutMs as i, DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND as n, findGoogleMeetCalendarEvent as o, resolveGoogleMeetConfig as r, listGoogleMeetCalendarEvents as s, DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND as t };
@@ -1,5 +1,5 @@
1
- import { d as createGoogleMeetSpace, t as createMeetWithBrowserProxyOnNode } from "./chrome-create-B3zyjf5f.js";
2
- import { resolveGoogleMeetAccessToken } from "./oauth-B3tz8JcD.js";
1
+ import { d as createGoogleMeetSpace, t as createMeetWithBrowserProxyOnNode } from "./chrome-create-By4DuikO.js";
2
+ import { resolveGoogleMeetAccessToken } from "./oauth--J53aI66.js";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  //#region extensions/google-meet/src/create.ts
5
5
  function normalizeTransport(value) {