@openclaw/google-meet 2026.7.2-beta.4 → 2026.7.2-beta.5

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.
@@ -687,8 +687,7 @@ const GOOGLE_MEET_BROWSER_NAVIGATION_RETRY_MS = 1e3;
687
687
  const GOOGLE_MEET_BROWSER_POLL_MS = 500;
688
688
  var GoogleMeetBrowserManualActionError = class extends Error {
689
689
  constructor(payload) {
690
- const prefix = payload.manualActionReason ? `${payload.manualActionReason}: ` : "";
691
- super(`${prefix}${payload.manualActionMessage}`);
690
+ super(`${payload.manualAction.reason}: ${payload.manualAction.message}`);
692
691
  this.name = "GoogleMeetBrowserManualActionError";
693
692
  this.payload = {
694
693
  source: "browser",
@@ -738,6 +737,14 @@ async function focusBrowserTab(params) {
738
737
  function readStringArray(value) {
739
738
  return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : void 0;
740
739
  }
740
+ function readBrowserManualAction(value) {
741
+ if (!value || typeof value !== "object") return;
742
+ const action = value;
743
+ return typeof action.reason === "string" && typeof action.message === "string" ? {
744
+ reason: action.reason,
745
+ message: action.message
746
+ } : void 0;
747
+ }
741
748
  function readBrowserCreateResult(result) {
742
749
  const record = result && typeof result === "object" ? result : {};
743
750
  const nested = record.result && typeof record.result === "object" ? record.result : record;
@@ -745,8 +752,7 @@ function readBrowserCreateResult(result) {
745
752
  meetingUri: typeof nested.meetingUri === "string" ? nested.meetingUri : void 0,
746
753
  browserUrl: typeof nested.browserUrl === "string" ? nested.browserUrl : void 0,
747
754
  browserTitle: typeof nested.browserTitle === "string" ? nested.browserTitle : void 0,
748
- manualAction: typeof nested.manualAction === "string" ? nested.manualAction : void 0,
749
- manualActionReason: typeof nested.manualActionReason === "string" ? nested.manualActionReason : void 0,
755
+ manualAction: readBrowserManualAction(nested.manualAction),
750
756
  notes: readStringArray(nested.notes),
751
757
  retryAfterMs: typeof nested.retryAfterMs === "number" && Number.isFinite(nested.retryAfterMs) ? nested.retryAfterMs : void 0
752
758
  };
@@ -755,6 +761,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
755
761
  const meetUrlPattern = /^https:\\/\\/meet\\.google\\.com\\/[a-z]{3}-[a-z]{4}-[a-z]{3}(?:$|[/?#])/i;
756
762
  const text = (node) => (node?.innerText || node?.textContent || "").trim();
757
763
  const current = () => location.href;
764
+ const manualActionFor = (reason, message) => ({ reason, message });
758
765
  const notes = [];
759
766
  const findButton = (pattern) =>
760
767
  [...document.querySelectorAll("button")].find((button) => {
@@ -778,8 +785,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
778
785
  };
779
786
  if (!current().startsWith("https://meet.google.com/")) {
780
787
  return {
781
- manualActionReason: "google-login-required",
782
- manualAction: "Sign in to Google in the OpenClaw browser profile, then retry meeting creation.",
788
+ manualAction: manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry meeting creation."),
783
789
  browserUrl: current(),
784
790
  browserTitle: document.title,
785
791
  notes,
@@ -805,8 +811,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
805
811
  }
806
812
  if (/do you want people to hear you in the meeting/i.test(pageText)) {
807
813
  return {
808
- manualActionReason: "meet-audio-choice-required",
809
- manualAction: "Meet is showing the microphone choice. Click Use microphone in the OpenClaw browser profile, then retry meeting creation.",
814
+ manualAction: manualActionFor("meet-audio-choice-required", "Meet is showing the microphone choice. Click Use microphone in the OpenClaw browser profile, then retry meeting creation."),
810
815
  browserUrl: href,
811
816
  browserTitle: document.title,
812
817
  notes,
@@ -814,8 +819,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
814
819
  }
815
820
  if (/allow.*(microphone|camera)|blocked.*(microphone|camera)|permission.*(microphone|camera)/i.test(pageText)) {
816
821
  return {
817
- manualActionReason: "meet-permission-required",
818
- manualAction: "Allow microphone/camera permissions for Meet in the OpenClaw browser profile, then retry meeting creation.",
822
+ manualAction: manualActionFor("meet-permission-required", "Allow microphone/camera permissions for Meet in the OpenClaw browser profile, then retry meeting creation."),
819
823
  browserUrl: href,
820
824
  browserTitle: document.title,
821
825
  notes,
@@ -823,7 +827,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
823
827
  }
824
828
  if (/couldn't create|unable to create/i.test(pageText)) {
825
829
  return {
826
- manualAction: "Resolve the Google Meet page prompt in the OpenClaw browser profile, then retry meeting creation.",
830
+ manualAction: manualActionFor("browser-control-unavailable", "Resolve the Google Meet page prompt in the OpenClaw browser profile, then retry meeting creation."),
827
831
  browserUrl: href,
828
832
  browserTitle: document.title,
829
833
  notes,
@@ -831,8 +835,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
831
835
  }
832
836
  if (location.hostname.toLowerCase() === "accounts.google.com" || /use your google account|to continue to google meet|choose an account|sign in to (join|continue)/i.test(pageText)) {
833
837
  return {
834
- manualActionReason: "google-login-required",
835
- manualAction: "Sign in to Google in the OpenClaw browser profile, then retry meeting creation.",
838
+ manualAction: manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry meeting creation."),
836
839
  browserUrl: href,
837
840
  browserTitle: document.title,
838
841
  notes,
@@ -921,9 +924,7 @@ async function createMeetWithBrowserProxyOnNode(params) {
921
924
  notes: [...notes]
922
925
  };
923
926
  if (result.manualAction) throw new GoogleMeetBrowserManualActionError({
924
- manualActionRequired: true,
925
- manualActionReason: result.manualActionReason,
926
- manualActionMessage: result.manualAction,
927
+ manualAction: result.manualAction,
927
928
  browser: {
928
929
  nodeId,
929
930
  targetId,
@@ -938,7 +939,7 @@ async function createMeetWithBrowserProxyOnNode(params) {
938
939
  if (!isBrowserNavigationInterruption(error)) throw error;
939
940
  await sleep(GOOGLE_MEET_BROWSER_NAVIGATION_RETRY_MS);
940
941
  }
941
- throw new Error(lastResult?.manualAction ?? `Google Meet did not return a meeting URL from the browser create flow before timeout.${lastError ? ` Last browser automation error: ${formatBrowserAutomationError(lastError)}` : ""}`);
942
+ throw new Error(lastResult?.manualAction?.message ?? `Google Meet did not return a meeting URL from the browser create flow before timeout.${lastError ? ` Last browser automation error: ${formatBrowserAutomationError(lastError)}` : ""}`);
942
943
  }
943
944
  //#endregion
944
945
  export { endGoogleMeetActiveConference as _, isRecoverableMeetTab as a, readMeetAuthUser as c, resolveChromeNodeInfo as d, GOOGLE_MEET_NODE_COMMAND as f, createGoogleMeetSpace as g, fetchGoogleMeetAttendance as h, isEnglishMeetTab as i, callBrowserProxyOnNode as l, fetchGoogleMeetArtifacts as m, isGoogleMeetBrowserManualActionError as n, isSameMeetUrlForReuse as o, buildGoogleMeetPreflightReport as p, forceMeetEnglishUi as r, normalizeMeetUrlForReuse as s, createMeetWithBrowserProxyOnNode as t, resolveChromeNode as u, fetchGoogleMeetSpace as v, fetchLatestGoogleMeetConferenceRecord as y };
@@ -1,6 +1,6 @@
1
- import { n as hasCreateSpaceConfigInput, r as resolveCreateSpaceConfig } from "./create-CNAkrEju.js";
1
+ import { n as hasCreateSpaceConfigInput, r as resolveCreateSpaceConfig } from "./create-af1MDlus.js";
2
2
  import { a as buildGoogleMeetCalendarDayWindow, i as resolveGoogleMeetGatewayOperationTimeoutMs, o as findGoogleMeetCalendarEvent, s as listGoogleMeetCalendarEvents } from "./config-BcaS1BDr.js";
3
- import { _ as endGoogleMeetActiveConference, g as createGoogleMeetSpace, h as fetchGoogleMeetAttendance, m as fetchGoogleMeetArtifacts, p as buildGoogleMeetPreflightReport, v as fetchGoogleMeetSpace, y as fetchLatestGoogleMeetConferenceRecord } from "./chrome-create-DkWXFsK2.js";
3
+ import { _ as endGoogleMeetActiveConference, g as createGoogleMeetSpace, h as fetchGoogleMeetAttendance, m as fetchGoogleMeetArtifacts, p as buildGoogleMeetPreflightReport, v as fetchGoogleMeetSpace, y as fetchLatestGoogleMeetConferenceRecord } from "./chrome-create-DMKruRFW.js";
4
4
  import { buildGoogleMeetAuthUrl, createGoogleMeetOAuthState, createGoogleMeetPkce, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-DOfMKlGp.js";
5
5
  import { callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
6
6
  import { clampTimerTimeoutMs, parseStrictNonNegativeInteger, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
@@ -143,10 +143,10 @@ function writeDoctorStatus(status) {
143
143
  writeStdoutLine("captioning: %s", formatBoolean(health?.captioning));
144
144
  writeStdoutLine("transcript lines: %s", health?.transcriptLines ?? 0);
145
145
  writeStdoutLine("last caption: %s", formatOptional(health?.lastCaptionAt));
146
- writeStdoutLine("manual action: %s", formatBoolean(health?.manualActionRequired));
147
- if (health?.manualActionRequired) {
148
- writeStdoutLine("manual reason: %s", formatOptional(health.manualActionReason));
149
- writeStdoutLine("manual message: %s", formatOptional(health.manualActionMessage));
146
+ writeStdoutLine("manual action: %s", formatBoolean(Boolean(health?.manualAction)));
147
+ if (health?.manualAction) {
148
+ writeStdoutLine("manual reason: %s", formatOptional(health.manualAction.reason));
149
+ writeStdoutLine("manual message: %s", formatOptional(health.manualAction.message));
150
150
  }
151
151
  writeStdoutLine("speech ready: %s", formatBoolean(health?.speechReady));
152
152
  if (health?.speechReady === false) {
@@ -0,0 +1,13 @@
1
+ import { t as GOOGLE_MEET_CLI_DESCRIPTOR } from "./cli-output-mode-BwH_6tH8.js";
2
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
3
+ //#region extensions/google-meet/cli-metadata.ts
4
+ var cli_metadata_default = definePluginEntry({
5
+ id: "google-meet",
6
+ name: "Google Meet",
7
+ description: "Google Meet CLI metadata",
8
+ register(api) {
9
+ api.registerCli(() => {}, { descriptors: [GOOGLE_MEET_CLI_DESCRIPTOR] });
10
+ }
11
+ });
12
+ //#endregion
13
+ export { cli_metadata_default as default };
@@ -0,0 +1,28 @@
1
+ import { getRootOptionAwareCommandPath } from "openclaw/plugin-sdk/cli-argv";
2
+ //#region extensions/google-meet/src/cli-output-mode.ts
3
+ const DEFAULT_JSON_COMMANDS = /* @__PURE__ */ new Set([
4
+ "join",
5
+ "status",
6
+ "test-listen",
7
+ "test-speech"
8
+ ]);
9
+ function hasOption(argv, flag) {
10
+ for (const arg of argv.slice(2)) {
11
+ if (arg === "--") return false;
12
+ if (arg === flag || arg.startsWith(`${flag}=`)) return true;
13
+ }
14
+ return false;
15
+ }
16
+ /** Runtime probe commands emit JSON without requiring the shared `--json` option. */
17
+ function isGoogleMeetMachineOutput(params) {
18
+ const [, command] = getRootOptionAwareCommandPath(params.argv, 2);
19
+ return DEFAULT_JSON_COMMANDS.has(command ?? "") || command === "export" && hasOption(params.argv, "--dry-run");
20
+ }
21
+ const GOOGLE_MEET_CLI_DESCRIPTOR = {
22
+ name: "googlemeet",
23
+ description: "Join and manage Google Meet calls",
24
+ hasSubcommands: true,
25
+ machineOutput: isGoogleMeetMachineOutput
26
+ };
27
+ //#endregion
28
+ export { GOOGLE_MEET_CLI_DESCRIPTOR as t };
@@ -1,4 +1,4 @@
1
- import { g as createGoogleMeetSpace, t as createMeetWithBrowserProxyOnNode } from "./chrome-create-DkWXFsK2.js";
1
+ import { g as createGoogleMeetSpace, t as createMeetWithBrowserProxyOnNode } from "./chrome-create-DMKruRFW.js";
2
2
  import { resolveGoogleMeetAccessToken } from "./oauth-DOfMKlGp.js";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  //#region \0rolldown/runtime.js
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { a as buildGoogleMeetCalendarDayWindow, c as normalizeMeetUrl, i as resolveGoogleMeetGatewayOperationTimeoutMs, n as DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND, o as findGoogleMeetCalendarEvent, r as resolveGoogleMeetConfig, s as listGoogleMeetCalendarEvents, t as DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND } from "./config-BcaS1BDr.js";
2
- import { _ as endGoogleMeetActiveConference, a as isRecoverableMeetTab, c as readMeetAuthUser, d as resolveChromeNodeInfo, f as GOOGLE_MEET_NODE_COMMAND, h as fetchGoogleMeetAttendance, i as isEnglishMeetTab, l as callBrowserProxyOnNode, m as fetchGoogleMeetArtifacts, n as isGoogleMeetBrowserManualActionError, o as isSameMeetUrlForReuse, p as buildGoogleMeetPreflightReport, r as forceMeetEnglishUi, s as normalizeMeetUrlForReuse, t as createMeetWithBrowserProxyOnNode, u as resolveChromeNode, v as fetchGoogleMeetSpace, y as fetchLatestGoogleMeetConferenceRecord } from "./chrome-create-DkWXFsK2.js";
2
+ import { t as GOOGLE_MEET_CLI_DESCRIPTOR } from "./cli-output-mode-BwH_6tH8.js";
3
+ import { _ as endGoogleMeetActiveConference, a as isRecoverableMeetTab, c as readMeetAuthUser, d as resolveChromeNodeInfo, f as GOOGLE_MEET_NODE_COMMAND, h as fetchGoogleMeetAttendance, i as isEnglishMeetTab, l as callBrowserProxyOnNode, m as fetchGoogleMeetArtifacts, n as isGoogleMeetBrowserManualActionError, o as isSameMeetUrlForReuse, p as buildGoogleMeetPreflightReport, r as forceMeetEnglishUi, s as normalizeMeetUrlForReuse, t as createMeetWithBrowserProxyOnNode, u as resolveChromeNode, v as fetchGoogleMeetSpace, y as fetchLatestGoogleMeetConferenceRecord } from "./chrome-create-DMKruRFW.js";
3
4
  import { optionalPositiveIntegerSchema, readPositiveIntegerParam } from "openclaw/plugin-sdk/channel-actions";
4
5
  import { ErrorCodes, GatewayClient, callGatewayFromCli, errorShape, startGatewayClientWhenEventLoopReady } from "openclaw/plugin-sdk/gateway-runtime";
5
6
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
@@ -9,10 +10,9 @@ import { jsonResult } from "openclaw/plugin-sdk/tool-results";
9
10
  import { createMeetingTranscriptSourceProvider, resolveTranscriptsConfig } from "openclaw/plugin-sdk/transcripts";
10
11
  import { isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
11
12
  import { spawnSync } from "node:child_process";
12
- import { MeetingSessionRuntime, addMeetingSetupCheck, createLocalMeetingRealtimeAudioTransport, createMeetingBrowserNodeInvokePolicy, createMeetingNodeHost, createMeetingRealtimeEngineBindings, createMeetingSession, createMeetingSetupStatus, createMeetingVoiceCallGateway, createNodeMeetingRealtimeAudioTransport, endMeetingVoiceCallGatewayCall, getMeetingVoiceCallGatewayCall, isMeetingVoiceCallMissingError, joinMeetingViaVoiceCallGateway, leaveMeetingWithBrowser, openMeetingWithBrowser, readMeetingTranscriptWithBrowser, recoverMeetingBrowserTab, resolveLocalMeetingBrowserRequest, speakMeetingViaVoiceCallGateway, startMeetingAgentRealtimeEngine, startMeetingRealtimeEngine } from "openclaw/plugin-sdk/meeting-runtime";
13
+ import { MeetingPlatformAdapter, MeetingSessionRuntime, addMeetingSetupCheck, createLocalMeetingRealtimeAudioTransport, createMeetingBrowserNodeInvokePolicy, createMeetingNodeHost, createMeetingRealtimeEngineBindings, createMeetingSession, createMeetingSetupStatus, createMeetingVoiceCallGateway, createNodeMeetingRealtimeAudioTransport, endMeetingVoiceCallGatewayCall, getMeetingVoiceCallGatewayCall, isMeetingVoiceCallMissingError, joinMeetingViaVoiceCallGateway, leaveMeetingWithBrowser, openMeetingWithBrowser, readMeetingTranscriptWithBrowser, recoverMeetingBrowserTab, resolveLocalMeetingBrowserRequest, speakMeetingViaVoiceCallGateway, startMeetingAgentRealtimeEngine, startMeetingRealtimeEngine } from "openclaw/plugin-sdk/meeting-runtime";
13
14
  import { addTimerTimeoutGraceMs } from "openclaw/plugin-sdk/number-runtime";
14
15
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
15
- import { sleep } from "openclaw/plugin-sdk/runtime-env";
16
16
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
17
17
  import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
18
18
  import fs from "node:fs";
@@ -33,6 +33,7 @@ const GOOGLE_MEET_CAPTION_SETTLE_MS = 1e3;
33
33
  function meetStatusScript(params) {
34
34
  return `async () => {
35
35
  const text = (node) => (node?.innerText || node?.textContent || "").trim();
36
+ const manualActionFor = (reason, message) => ({ reason, message });
36
37
  const allowMicrophone = ${JSON.stringify(params.allowMicrophone)};
37
38
  const captionSessionId = ${JSON.stringify(params.captionSessionId)};
38
39
  const captureCaptions = ${JSON.stringify(params.captureCaptions)};
@@ -331,27 +332,17 @@ function meetStatusScript(params) {
331
332
  const leaveReason = !inCall && /you left the meeting|you.?ve left the meeting|removed from the meeting|you were removed|call ended|meeting ended/i.test(pageText)
332
333
  ? pageText.match(/you left the meeting|you.?ve left the meeting|removed from the meeting|you were removed|call ended|meeting ended/i)?.[0]
333
334
  : undefined;
334
- let manualActionReason;
335
- let manualActionMessage;
335
+ let manualAction;
336
336
  if (!inCall && (host === "accounts.google.com" || /use your google account|to continue to google meet|choose an account|sign in to (join|continue)/i.test(pageText))) {
337
- manualActionReason = "google-login-required";
338
- manualActionMessage = "Sign in to Google in the OpenClaw browser profile, then retry the Meet join.";
337
+ manualAction = manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry the Meet join.");
339
338
  } else if (!inCall && joinElsewhere) {
340
- manualActionReason = "meet-session-conflict";
341
- manualActionMessage = "Meet is already active in another tab or device. Leave that session or reuse an English-pinned tab before retrying.";
339
+ manualAction = manualActionFor("meet-session-conflict", "Meet is already active in another tab or device. Leave that session or reuse an English-pinned tab before retrying.");
342
340
  } else if (!inCall && /asking to be let in|you.?ll join when someone lets you in|waiting to be let in|ask to join/i.test(pageText)) {
343
- manualActionReason = "meet-admission-required";
344
- manualActionMessage = "Admit the OpenClaw browser participant in Google Meet, then retry speech.";
341
+ manualAction = manualActionFor("meet-admission-required", "Admit the OpenClaw browser participant in Google Meet, then retry speech.");
345
342
  } else if (permissionNeeded) {
346
- manualActionReason = "meet-permission-required";
347
- manualActionMessage = allowMicrophone
348
- ? "Allow microphone/camera/speaker permissions for Meet in the OpenClaw browser profile, then retry."
349
- : "Join without microphone/camera permissions in the OpenClaw browser profile, then retry.";
343
+ manualAction = manualActionFor("meet-permission-required", allowMicrophone ? "Allow microphone/camera/speaker permissions for Meet in the OpenClaw browser profile, then retry." : "Join without microphone/camera permissions in the OpenClaw browser profile, then retry.");
350
344
  } else if (!inCall && (allowMicrophone ? !microphoneChoice : !noMicrophoneChoice) && /do you want people to hear you in the meeting/i.test(pageText)) {
351
- manualActionReason = "meet-audio-choice-required";
352
- manualActionMessage = allowMicrophone
353
- ? "Meet is showing the microphone choice. Click Use microphone in the OpenClaw browser profile, then retry."
354
- : "Meet is showing the microphone choice. Choose the no-microphone option in the OpenClaw browser profile, then retry.";
345
+ manualAction = manualActionFor("meet-audio-choice-required", allowMicrophone ? "Meet is showing the microphone choice. Click Use microphone in the OpenClaw browser profile, then retry." : "Meet is showing the microphone choice. Choose the no-microphone option in the OpenClaw browser profile, then retry.");
355
346
  }
356
347
  return JSON.stringify({
357
348
  clickedJoin: Boolean(join),
@@ -370,9 +361,7 @@ function meetStatusScript(params) {
370
361
  audioOutputRouted,
371
362
  audioOutputDeviceLabel,
372
363
  audioOutputRouteError,
373
- manualActionRequired: Boolean(manualActionReason),
374
- manualActionReason,
375
- manualActionMessage,
364
+ manualAction,
376
365
  title: document.title,
377
366
  url: pageUrl,
378
367
  notes
@@ -519,42 +508,6 @@ function prefixDtmfWait(sequence, delayMs) {
519
508
  }
520
509
  //#endregion
521
510
  //#region extensions/google-meet/src/transports/google-meet-platform-adapter.ts
522
- function isGoogleMeetTalkBackMode$1(mode) {
523
- return mode === "agent" || mode === "bidi";
524
- }
525
- function parseMeetBrowserStatus(result) {
526
- const raw = (result && typeof result === "object" ? result : {}).result;
527
- if (typeof raw !== "string" || !raw.trim()) return;
528
- let parsed;
529
- try {
530
- parsed = JSON.parse(raw);
531
- } catch {
532
- throw new Error("Google Meet browser status JSON is malformed.");
533
- }
534
- return {
535
- inCall: parsed.inCall,
536
- micMuted: parsed.micMuted,
537
- lobbyWaiting: parsed.lobbyWaiting,
538
- leaveReason: parsed.leaveReason,
539
- captioning: parsed.captioning,
540
- captionsEnabledAttempted: parsed.captionsEnabledAttempted,
541
- transcriptLines: parsed.transcriptLines,
542
- lastCaptionAt: parsed.lastCaptionAt,
543
- lastCaptionSpeaker: parsed.lastCaptionSpeaker,
544
- lastCaptionText: parsed.lastCaptionText,
545
- recentTranscript: parsed.recentTranscript,
546
- audioOutputRouted: parsed.audioOutputRouted,
547
- audioOutputDeviceLabel: parsed.audioOutputDeviceLabel,
548
- audioOutputRouteError: parsed.audioOutputRouteError,
549
- manualActionRequired: parsed.manualActionRequired,
550
- manualActionReason: parsed.manualActionReason,
551
- manualActionMessage: parsed.manualActionMessage,
552
- browserUrl: parsed.url,
553
- browserTitle: parsed.title,
554
- status: "browser-control",
555
- notes: Array.isArray(parsed.notes) ? parsed.notes.filter((note) => typeof note === "string") : void 0
556
- };
557
- }
558
511
  function parsePermissionGrantNotes(result) {
559
512
  const record = result && typeof result === "object" ? result : {};
560
513
  const unsupportedPermissions = Array.isArray(record.unsupportedPermissions) ? record.unsupportedPermissions.filter((value) => typeof value === "string") : [];
@@ -562,63 +515,19 @@ function parsePermissionGrantNotes(result) {
562
515
  if (unsupportedPermissions.includes("speakerSelection")) notes.push("Chrome did not accept the optional Meet speaker-selection permission.");
563
516
  return notes;
564
517
  }
565
- function parseMeetTranscriptSnapshot(result) {
566
- const raw = (result && typeof result === "object" ? result : {}).result;
567
- if (typeof raw !== "string" || !raw.trim()) return {
568
- droppedLines: 0,
569
- lines: []
570
- };
571
- let parsed;
572
- try {
573
- parsed = JSON.parse(raw);
574
- } catch {
575
- throw new Error("Google Meet transcript JSON is malformed.");
576
- }
577
- if (!parsed || typeof parsed !== "object") throw new Error("Google Meet transcript payload is invalid.");
578
- const payload = parsed;
579
- const droppedLines = typeof payload.droppedLines === "number" && Number.isSafeInteger(payload.droppedLines) ? Math.max(0, payload.droppedLines) : 0;
580
- const lines = Array.isArray(payload.lines) ? payload.lines.flatMap((value) => {
581
- if (!value || typeof value !== "object") return [];
582
- const line = value;
583
- if (typeof line.text !== "string" || !line.text.trim()) return [];
584
- return [{
585
- ...typeof line.at === "string" ? { at: line.at } : {},
586
- ...typeof line.speaker === "string" ? { speaker: line.speaker } : {},
587
- text: line.text
588
- }];
589
- }) : [];
590
- return {
591
- droppedLines,
592
- ...typeof payload.epoch === "string" ? { epoch: payload.epoch } : {},
593
- lines,
594
- ...typeof payload.urlMatched === "boolean" ? { urlMatched: payload.urlMatched } : {},
595
- ...typeof payload.sessionMatched === "boolean" ? { sessionMatched: payload.sessionMatched } : {}
596
- };
597
- }
598
- function parseMeetLeaveResult(result) {
599
- const raw = (result && typeof result === "object" ? result : {}).result;
600
- if (typeof raw !== "string" || !raw.trim()) return { departed: false };
601
- try {
602
- const parsed = JSON.parse(raw);
603
- const leaveAction = parsed.leaveAction === "leave" || parsed.leaveAction === "confirm" ? parsed.leaveAction : void 0;
604
- return {
605
- departed: parsed.departed === true,
606
- ...leaveAction ? { leaveAction } : {},
607
- ...typeof parsed.urlMatched === "boolean" ? { urlMatched: parsed.urlMatched } : {}
608
- };
609
- } catch {
610
- return { departed: false };
611
- }
612
- }
613
- function classifyMeetManualAction(health) {
614
- if (!health.manualActionRequired || !health.manualActionReason || !health.manualActionMessage) return;
615
- return {
616
- category: health.manualActionReason === "google-login-required" ? "login-required" : health.manualActionReason === "meet-admission-required" ? "admission-required" : health.manualActionReason === "meet-permission-required" ? "permission-required" : health.manualActionReason === "meet-audio-choice-required" ? "audio-choice-required" : health.manualActionReason === "meet-locale-required" ? "locale-required" : health.manualActionReason === "meet-session-conflict" ? "session-conflict" : health.manualActionReason === "browser-control-unavailable" ? "browser-control-unavailable" : "custom",
617
- reason: health.manualActionReason,
618
- message: health.manualActionMessage
619
- };
518
+ const manualActionCategories = /* @__PURE__ */ new Map([
519
+ ["browser-control-unavailable", "browser-control-unavailable"],
520
+ ["google-login-required", "login-required"],
521
+ ["meet-admission-required", "admission-required"],
522
+ ["meet-audio-choice-required", "audio-choice-required"],
523
+ ["meet-locale-required", "locale-required"],
524
+ ["meet-permission-required", "permission-required"],
525
+ ["meet-session-conflict", "session-conflict"]
526
+ ]);
527
+ function classifyManualActionReason(reason) {
528
+ return manualActionCategories.get(reason) ?? "custom";
620
529
  }
621
- const GOOGLE_MEET_PLATFORM_ADAPTER = {
530
+ const GOOGLE_MEET_PLATFORM_ADAPTER = MeetingPlatformAdapter.create({
622
531
  id: "google-meet",
623
532
  displayName: "Google Meet",
624
533
  browserLabel: "Meet",
@@ -661,28 +570,24 @@ const GOOGLE_MEET_PLATFORM_ADAPTER = {
661
570
  }
662
571
  },
663
572
  browser: {
664
- allowsMicrophone: isGoogleMeetTalkBackMode$1,
573
+ allowsMicrophone: MeetingPlatformAdapter.isTalkBackMode,
665
574
  buildStatusJoinScript: (params) => meetStatusScript({
666
- allowMicrophone: isGoogleMeetTalkBackMode$1(params.mode),
575
+ allowMicrophone: MeetingPlatformAdapter.isTalkBackMode(params.mode),
667
576
  autoJoin: params.autoJoin,
668
577
  captionSessionId: params.meetingSessionId || void 0,
669
578
  captureCaptions: params.captureCaptions,
670
579
  guestName: params.guestName,
671
580
  readOnly: params.readOnly
672
581
  }),
673
- parseStatus: parseMeetBrowserStatus,
674
- classifyManualAction: classifyMeetManualAction,
675
582
  browserControlUnavailable: () => ({
676
583
  category: "browser-control-unavailable",
677
584
  reason: "browser-control-unavailable",
678
585
  message: "Open the OpenClaw browser profile, finish Google Meet login, admission, or permission prompts, then retry."
679
586
  }),
680
587
  buildLeaveScript: meetLeaveScript,
681
- parseLeaveResult: parseMeetLeaveResult,
682
588
  captions: {
683
589
  enabled: (_mode) => true,
684
- buildTranscriptScript: ({ finalize, meetingSessionId, meetingUrl }) => meetTranscriptScript(meetingUrl, meetingSessionId, finalize),
685
- parseTranscript: parseMeetTranscriptSnapshot
590
+ buildTranscriptScript: ({ finalize, meetingSessionId, meetingUrl }) => meetTranscriptScript(meetingUrl, meetingSessionId, finalize)
686
591
  },
687
592
  permissions: ({ allowMicrophone }) => allowMicrophone ? {
688
593
  origin: "https://meet.google.com",
@@ -708,8 +613,16 @@ const GOOGLE_MEET_PLATFORM_ADAPTER = {
708
613
  pin,
709
614
  dtmfSequence: params.dtmfSequence || params.defaultDtmfSequence ? rawDtmfSequence : prefixDtmfWait(rawDtmfSequence, params.dtmfDelayMs)
710
615
  };
711
- } }
712
- };
616
+ } },
617
+ parsing: {
618
+ classifyManualActionReason,
619
+ displayName: "Meet",
620
+ invalidTranscriptMessage: "Google Meet transcript payload is invalid.",
621
+ malformedStatusMessage: "Google Meet browser status JSON is malformed.",
622
+ malformedTranscriptMessage: "Google Meet transcript JSON is malformed.",
623
+ statusFields: (parsed) => ({ leaveReason: typeof parsed.leaveReason === "string" ? parsed.leaveReason : void 0 })
624
+ }
625
+ });
713
626
  //#endregion
714
627
  //#region extensions/google-meet/src/node-host.ts
715
628
  function assertBlackHoleAvailable(timeoutMs) {
@@ -779,131 +692,30 @@ function createGoogleMeetChromeNodeInvokePolicy(config) {
779
692
  }
780
693
  //#endregion
781
694
  //#region extensions/google-meet/src/runtime-probes.ts
782
- function resolveMode$1(request, config) {
783
- return request.mode === "realtime" ? "agent" : request.mode ?? config.defaultMode;
784
- }
785
695
  function resolveProbeTimeoutMs(input, fallback) {
786
696
  if (input === void 0) return Math.min(Math.max(fallback, 1), 12e4);
787
697
  if (!Number.isFinite(input) || input <= 0) throw new Error("timeoutMs must be a positive number");
788
698
  return Math.min(Math.trunc(input), 12e4);
789
699
  }
790
- async function testGoogleMeetSpeech(context, request) {
791
- if (request.mode === "transcribe") throw new Error("test_speech requires mode: agent or bidi; use join mode: transcribe for observe-only sessions.");
792
- const requestedMode = request.mode ? resolveMode$1(request, context.config) : void 0;
793
- const mode = requestedMode === "agent" || requestedMode === "bidi" ? requestedMode : context.config.defaultMode === "agent" || context.config.defaultMode === "bidi" ? context.config.defaultMode : "agent";
794
- const resolved = {
795
- url: normalizeMeetUrl(request.url),
796
- transport: request.transport ?? context.config.defaultTransport,
797
- mode,
798
- agentId: context.resolveAgentId(request)
799
- };
800
- const beforeSessions = context.list();
801
- const before = new Set(beforeSessions.map((session) => session.id));
802
- const existing = beforeSessions.find((session) => context.isReusable(session, resolved));
803
- const existingBaseline = {
804
- outputBytes: existing?.chrome?.health?.lastOutputBytes ?? 0,
805
- outputGeneration: existing?.chrome?.health?.outputGeneration ?? 0
806
- };
807
- const result = await context.join({
808
- ...request,
809
- ...resolved,
810
- message: request.message ?? "Say exactly: Google Meet speech test complete."
811
- });
812
- const baseline = existing?.id === result.session.id ? existingBaseline : {
813
- outputBytes: 0,
814
- outputGeneration: 0
815
- };
816
- let health = result.session.chrome?.health;
817
- const verified = () => (health?.lastOutputBytes ?? 0) > baseline.outputBytes && (health?.outputGeneration ?? 0) > baseline.outputGeneration && health?.verifiedOutputGeneration === health?.outputGeneration;
818
- const shouldWait = result.spoken === true && health?.manualActionRequired !== true && context.hasHealthHandle(result.session.id);
819
- if (shouldWait && !verified()) {
820
- const deadline = Date.now() + Math.min(context.config.chrome.joinTimeoutMs, 5e3);
821
- while (Date.now() < deadline) {
822
- await sleep(100);
823
- context.refreshHealth(result.session.id);
824
- health = result.session.chrome?.health;
825
- if (verified()) break;
826
- }
827
- }
828
- const speechOutputVerified = verified();
829
- return {
830
- createdSession: !before.has(result.session.id),
831
- inCall: health?.inCall,
832
- manualActionRequired: health?.manualActionRequired,
833
- manualActionReason: health?.manualActionReason,
834
- manualActionMessage: health?.manualActionMessage,
835
- spoken: result.spoken ?? false,
836
- speechOutputVerified,
837
- speechOutputTimedOut: shouldWait && !speechOutputVerified,
838
- speechReady: health?.speechReady,
839
- speechBlockedReason: health?.speechBlockedReason,
840
- speechBlockedMessage: health?.speechBlockedMessage,
841
- audioOutputActive: health?.audioOutputActive,
842
- lastOutputBytes: health?.lastOutputBytes,
843
- outputLoopbackSignalBytes: health?.outputLoopbackSignalBytes,
844
- lastOutputLoopbackAt: health?.lastOutputLoopbackAt,
845
- lastOutputLoopbackCorrelation: health?.lastOutputLoopbackCorrelation,
846
- lastOutputLoopbackRms: health?.lastOutputLoopbackRms,
847
- lastOutputLoopbackPeak: health?.lastOutputLoopbackPeak,
848
- outputGeneration: health?.outputGeneration,
849
- verifiedOutputGeneration: health?.verifiedOutputGeneration,
850
- session: result.session
851
- };
852
- }
853
- async function testGoogleMeetListening(context, request) {
854
- const requestedMode = request.mode ? resolveMode$1(request, context.config) : void 0;
855
- if (requestedMode === "agent" || requestedMode === "bidi") throw new Error("test_listen requires mode: transcribe; use test_speech for talk-back sessions.");
856
- const resolved = {
857
- url: normalizeMeetUrl(request.url),
858
- transport: request.transport ?? context.config.defaultTransport,
859
- mode: "transcribe",
860
- agentId: context.resolveAgentId(request)
861
- };
862
- if (resolved.transport === "twilio") throw new Error("test_listen supports chrome or chrome-node transports");
863
- const beforeSessions = context.list();
864
- const before = new Set(beforeSessions.map((session) => session.id));
865
- const existing = beforeSessions.find((session) => context.isReusable(session, resolved));
866
- const start = {
867
- lines: existing?.chrome?.health?.transcriptLines ?? 0,
868
- at: existing?.chrome?.health?.lastCaptionAt,
869
- text: existing?.chrome?.health?.lastCaptionText
870
- };
871
- const result = await context.join({
872
- ...request,
873
- ...resolved,
874
- message: void 0
875
- });
876
- let health = result.session.chrome?.health;
877
- const advanced = () => (health?.transcriptLines ?? 0) > (existing?.id === result.session.id ? start.lines : 0) || Boolean(health?.lastCaptionAt && health.lastCaptionAt !== start.at) || Boolean(health?.lastCaptionText && health.lastCaptionText !== start.text);
878
- const shouldWait = health?.manualActionRequired !== true && Boolean((result.session.transport === "chrome" || result.session.transport === "chrome-node") && result.session.chrome?.launched);
879
- if (shouldWait && !advanced()) {
880
- const deadline = Date.now() + resolveProbeTimeoutMs(request.timeoutMs, context.config.chrome.joinTimeoutMs);
881
- while (Date.now() < deadline) {
882
- await sleep(250);
883
- await context.refreshCaptionHealth(result.session);
884
- health = result.session.chrome?.health;
885
- if (health?.manualActionRequired || advanced()) break;
886
- }
887
- }
888
- const listenVerified = advanced();
889
- return {
890
- createdSession: !before.has(result.session.id),
891
- inCall: health?.inCall,
892
- manualActionRequired: health?.manualActionRequired,
893
- manualActionReason: health?.manualActionReason,
894
- manualActionMessage: health?.manualActionMessage,
895
- listenVerified,
896
- listenTimedOut: shouldWait && !listenVerified && health?.manualActionRequired !== true,
897
- captioning: health?.captioning,
898
- captionsEnabledAttempted: health?.captionsEnabledAttempted,
899
- transcriptLines: health?.transcriptLines,
900
- lastCaptionAt: health?.lastCaptionAt,
901
- lastCaptionSpeaker: health?.lastCaptionSpeaker,
902
- lastCaptionText: health?.lastCaptionText,
903
- recentTranscript: health?.recentTranscript,
904
- session: result.session
905
- };
906
- }
700
+ const probes = MeetingPlatformAdapter.createRuntimeProbes({
701
+ defaultSpeechMessage: "Say exactly: Google Meet speech test complete.",
702
+ invalidRequest: (message) => new Error(message),
703
+ resolveTimeoutMs: resolveProbeTimeoutMs,
704
+ shouldWaitForListening: (session) => Boolean((session.transport === "chrome" || session.transport === "chrome-node") && session.chrome?.launched),
705
+ talkBackMode: MeetingPlatformAdapter.isTalkBackMode,
706
+ normalizeUrl: normalizeMeetUrl,
707
+ resolveRequestMode: (mode) => mode === "realtime" ? "agent" : mode,
708
+ defaultTransport: (config) => config.defaultTransport,
709
+ validateListeningTransport: (transport) => {
710
+ if (transport === "twilio") throw new Error("test_listen supports chrome or chrome-node transports");
711
+ },
712
+ resolveSpeechTimeoutMs: (_request, config) => Math.min(config.chrome.joinTimeoutMs, 5e3),
713
+ refreshCaptionHealth: async (context, session) => await context.refreshCaptionHealth(session),
714
+ speechModeError: "test_speech requires mode: agent or bidi; use join mode: transcribe for observe-only sessions.",
715
+ listeningModeError: "test_listen requires mode: transcribe; use test_speech for talk-back sessions."
716
+ });
717
+ const testGoogleMeetListening = probes.testListening;
718
+ const testGoogleMeetSpeech = probes.testSpeech;
907
719
  //#endregion
908
720
  //#region extensions/google-meet/src/runtime-session.ts
909
721
  function resolveTransport(input, config) {
@@ -980,7 +792,7 @@ function getGoogleMeetSetupStatus(config, options) {
980
792
  const fullConfig = asRecord(options?.fullConfig);
981
793
  const mode = options?.mode ?? config.defaultMode;
982
794
  const transport = options?.transport ?? config.defaultTransport;
983
- const needsChromeRealtimeAudio = (mode === "agent" || mode === "bidi") && (transport === "chrome" || transport === "chrome-node");
795
+ const needsChromeRealtimeAudio = MeetingPlatformAdapter.isTalkBackMode(mode) && (transport === "chrome" || transport === "chrome-node");
984
796
  const pluginEntries = asRecord(asRecord(fullConfig.plugins).entries);
985
797
  const pluginAllow = asRecord(fullConfig.plugins).allow;
986
798
  const voiceCallEntry = asRecord(pluginEntries["voice-call"]);
@@ -1091,7 +903,7 @@ async function assertBlackHole2chAvailable(params) {
1091
903
  }
1092
904
  async function launchChromeMeet(params) {
1093
905
  const checkRealtimeAudioPrerequisites = async () => {
1094
- if (!isGoogleMeetTalkBackMode$1(params.mode)) return;
906
+ if (!MeetingPlatformAdapter.isTalkBackMode(params.mode)) return;
1095
907
  await assertBlackHole2chAvailable({
1096
908
  runtime: params.runtime,
1097
909
  timeoutMs: Math.min(params.config.chrome.joinTimeoutMs, 1e4)
@@ -1102,7 +914,7 @@ async function launchChromeMeet(params) {
1102
914
  }
1103
915
  };
1104
916
  const startRealtimeAudioBridge = async () => {
1105
- if (!isGoogleMeetTalkBackMode$1(params.mode)) return;
917
+ if (!MeetingPlatformAdapter.isTalkBackMode(params.mode)) return;
1106
918
  if (params.config.chrome.audioBridgeCommand) {
1107
919
  if (params.mode === "agent") throw new Error("Chrome agent mode requires chrome.audioInputCommand and chrome.audioOutputCommand so OpenClaw can run STT and regular TTS directly.");
1108
920
  const bridge = await params.runtime.system.runCommandWithTimeout(params.config.chrome.audioBridgeCommand, { timeoutMs: params.config.chrome.joinTimeoutMs });
@@ -1174,7 +986,7 @@ async function launchChromeMeet(params) {
1174
986
  url: params.url
1175
987
  }
1176
988
  });
1177
- const audioBridge = isGoogleMeetTalkBackMode$1(params.mode) && result.browser?.inCall === true && result.browser.micMuted === false && result.browser.manualActionRequired !== true ? await startRealtimeAudioBridge() : void 0;
989
+ const audioBridge = MeetingPlatformAdapter.isTalkBackMode(params.mode) && result.browser?.inCall === true && result.browser.micMuted === false && result.browser.manualAction === void 0 ? await startRealtimeAudioBridge() : void 0;
1178
990
  return {
1179
991
  ...result,
1180
992
  audioBridge
@@ -1346,7 +1158,7 @@ async function launchChromeMeetOnNode(params) {
1346
1158
  meetingSessionId: params.meetingSessionId,
1347
1159
  url: params.url
1348
1160
  });
1349
- if (params.config.chrome.launch && isGoogleMeetTalkBackMode$1(params.mode) && (browserControl.browser?.inCall !== true || browserControl.browser.micMuted !== false || browserControl.browser.manualActionRequired === true)) return {
1161
+ if (params.config.chrome.launch && MeetingPlatformAdapter.isTalkBackMode(params.mode) && (browserControl.browser?.inCall !== true || browserControl.browser.micMuted !== false || browserControl.browser.manualAction)) return {
1350
1162
  nodeId,
1351
1163
  launched: browserControl.launched,
1352
1164
  browser: browserControl.browser,
@@ -1636,7 +1448,6 @@ var GoogleMeetRuntime = class {
1636
1448
  speech: {
1637
1449
  audioBridgeUnavailable: "Realtime speech requires an active Chrome audio bridge.",
1638
1450
  browserUnverified: "Google Meet browser state has not been verified yet.",
1639
- manualActionFallback: "Resolve the Google Meet browser prompt before asking OpenClaw to speak.",
1640
1451
  microphoneMuted: "Turn on the OpenClaw Google Meet microphone before asking OpenClaw to speak.",
1641
1452
  microphoneMutedReason: "meet-microphone-muted",
1642
1453
  notInCall: "Google Meet has not reported that the browser participant is in the call.",
@@ -1659,7 +1470,7 @@ var GoogleMeetRuntime = class {
1659
1470
  }),
1660
1471
  resolveSpeechInstructions: (request) => request.message ?? params.config.realtime.introMessage,
1661
1472
  isBrowserTransport,
1662
- isTalkBackMode: isGoogleMeetTalkBackMode$1,
1473
+ isTalkBackMode: (mode) => MeetingPlatformAdapter.isTalkBackMode(mode),
1663
1474
  isTranscribeMode: (mode) => mode === "transcribe",
1664
1475
  sameMeetingUrl: (left, right) => adapter.urls.isSameMeeting(left, right),
1665
1476
  normalizeMeetingUrlForReuse: (url) => adapter.urls.normalizeForReuse(url),
@@ -1809,7 +1620,7 @@ var GoogleMeetRuntime = class {
1809
1620
  };
1810
1621
  const handles = this.#attachChromeAudioBridge(session, result.audioBridge);
1811
1622
  if (handles) context.attachRuntimeHandles(session, handles);
1812
- session.notes.push(result.audioBridge ? session.transport === "chrome-node" ? "Chrome node transport joins as the signed-in Google profile on the selected node and routes realtime audio through the node bridge." : "Chrome transport joins as the signed-in Google profile and routes realtime audio through the configured bridge." : isGoogleMeetTalkBackMode$1(session.mode) ? "Chrome transport joins as the signed-in Google profile and expects BlackHole 2ch audio routing." : "Chrome transport joins as the signed-in Google profile without starting the realtime audio bridge.");
1623
+ session.notes.push(result.audioBridge ? session.transport === "chrome-node" ? "Chrome node transport joins as the signed-in Google profile on the selected node and routes realtime audio through the node bridge." : "Chrome transport joins as the signed-in Google profile and routes realtime audio through the configured bridge." : MeetingPlatformAdapter.isTalkBackMode(session.mode) ? "Chrome transport joins as the signed-in Google profile and expects BlackHole 2ch audio routing." : "Chrome transport joins as the signed-in Google profile without starting the realtime audio bridge.");
1813
1624
  this.#sessions.refreshSpeechReadiness(session);
1814
1625
  return {};
1815
1626
  }
@@ -1835,7 +1646,7 @@ var GoogleMeetRuntime = class {
1835
1646
  ...request.requesterSessionKey ? { requesterSessionKey: request.requesterSessionKey } : {},
1836
1647
  agentId: delegatedAgentId,
1837
1648
  sessionKey: delegatedAgentId ? `agent:${delegatedAgentId}:google-meet:${session.id}` : `voice:google-meet:${session.id}`,
1838
- message: isGoogleMeetTalkBackMode$1(session.mode) ? request.message ?? this.params.config.voiceCall.introMessage ?? this.params.config.realtime.introMessage : void 0
1649
+ message: MeetingPlatformAdapter.isTalkBackMode(session.mode) ? request.message ?? this.params.config.voiceCall.introMessage ?? this.params.config.realtime.introMessage : void 0
1839
1650
  }) : void 0;
1840
1651
  session.twilio = {
1841
1652
  dialInNumber,
@@ -1867,7 +1678,7 @@ var GoogleMeetRuntime = class {
1867
1678
  } : void 0;
1868
1679
  }
1869
1680
  async #ensureChromeRealtimeBridge(session) {
1870
- if (!isGoogleMeetTalkBackMode$1(session.mode) || !isBrowserTransport(session.transport) || session.state !== "active" || !session.chrome || session.chrome.audioBridge || session.chrome.health?.inCall !== true || session.chrome.health.micMuted !== false || session.chrome.health.manualActionRequired === true) return;
1681
+ if (!MeetingPlatformAdapter.isTalkBackMode(session.mode) || !isBrowserTransport(session.transport) || session.state !== "active" || !session.chrome || session.chrome.audioBridge || session.chrome.health?.inCall !== true || session.chrome.health.micMuted !== false || session.chrome.health.manualAction) return;
1871
1682
  const config = withSessionAgentConfig(this.params.config, session.agentId);
1872
1683
  const recoveryConfig = {
1873
1684
  ...config,
@@ -2059,8 +1870,8 @@ var GoogleMeetRuntime = class {
2059
1870
  };
2060
1871
  //#endregion
2061
1872
  //#region extensions/google-meet/src/plugin-helpers.ts
2062
- const loadGoogleMeetCreateModule = createLazyRuntimeModule(() => import("./create-CNAkrEju.js").then((n) => n.t));
2063
- const loadGoogleMeetCliModule = createLazyRuntimeModule(() => import("./cli-CksOXL4n.js"));
1873
+ const loadGoogleMeetCreateModule = createLazyRuntimeModule(() => import("./create-af1MDlus.js").then((n) => n.t));
1874
+ const loadGoogleMeetCliModule = createLazyRuntimeModule(() => import("./cli-GeuAaEIy.js"));
2064
1875
  function asParamRecord(params) {
2065
1876
  return params && typeof params === "object" && !Array.isArray(params) ? params : {};
2066
1877
  }
@@ -2071,9 +1882,6 @@ function normalizeMode(value) {
2071
1882
  if (value === "realtime") return "agent";
2072
1883
  return value === "agent" || value === "bidi" || value === "transcribe" ? value : void 0;
2073
1884
  }
2074
- function isGoogleMeetTalkBackMode(mode) {
2075
- return mode === "agent" || mode === "bidi";
2076
- }
2077
1885
  function resolveMeetingInput(config, value) {
2078
1886
  const meeting = normalizeOptionalString(value) ?? config.defaults.meeting;
2079
1887
  if (!meeting) throw new Error("Meeting input is required");
@@ -2112,7 +1920,7 @@ function isGoogleMeetAgentToolActionUnsupportedOnHost(params) {
2112
1920
  if (action !== "join" && action !== "test_speech" && !(action === "create" && shouldJoinCreatedMeet(params.raw))) return false;
2113
1921
  const transport = normalizeTransport(params.raw.transport) ?? params.config.defaultTransport;
2114
1922
  const mode = action === "test_speech" ? "agent" : normalizeMode(params.raw.mode) ?? params.config.defaultMode;
2115
- return transport === "chrome" && isGoogleMeetTalkBackMode(mode);
1923
+ return transport === "chrome" && MeetingPlatformAdapter.isTalkBackMode(mode);
2116
1924
  }
2117
1925
  function assertGoogleMeetAgentToolActionSupported(params) {
2118
1926
  if (!isGoogleMeetAgentToolActionUnsupportedOnHost(params)) return;
@@ -3016,11 +2824,7 @@ var google_meet_default = definePluginEntry({
3016
2824
  });
3017
2825
  }, {
3018
2826
  commands: ["googlemeet"],
3019
- descriptors: [{
3020
- name: "googlemeet",
3021
- description: "Join and manage Google Meet calls",
3022
- hasSubcommands: true
3023
- }]
2827
+ descriptors: [GOOGLE_MEET_CLI_DESCRIPTOR]
3024
2828
  });
3025
2829
  }
3026
2830
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/google-meet",
3
- "version": "2026.7.2-beta.4",
3
+ "version": "2026.7.2-beta.5",
4
4
  "description": "OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,7 @@
13
13
  "typebox": "1.3.6"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.7.2-beta.4"
16
+ "openclaw": ">=2026.7.2-beta.5"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
@@ -30,10 +30,10 @@
30
30
  "minHostVersion": ">=2026.4.20"
31
31
  },
32
32
  "compat": {
33
- "pluginApi": ">=2026.7.2-beta.4"
33
+ "pluginApi": ">=2026.7.2-beta.5"
34
34
  },
35
35
  "build": {
36
- "openclawVersion": "2026.7.2-beta.4"
36
+ "openclawVersion": "2026.7.2-beta.5"
37
37
  },
38
38
  "release": {
39
39
  "publishToClawHub": true,
@@ -46,7 +46,6 @@
46
46
  "files": [
47
47
  "dist/**",
48
48
  "openclaw.plugin.json",
49
- "npm-shrinkwrap.json",
50
49
  "README.md"
51
50
  ],
52
51
  "bundledDependencies": [
@@ -1,157 +0,0 @@
1
- {
2
- "name": "@openclaw/google-meet",
3
- "version": "2026.7.2-beta.4",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "@openclaw/google-meet",
9
- "version": "2026.7.2-beta.4",
10
- "dependencies": {
11
- "jszip": "3.10.1",
12
- "pretty-ms": "9.3.0",
13
- "typebox": "1.3.6"
14
- },
15
- "peerDependencies": {
16
- "openclaw": ">=2026.7.2-beta.4"
17
- },
18
- "peerDependenciesMeta": {
19
- "openclaw": {
20
- "optional": true
21
- }
22
- }
23
- },
24
- "node_modules/core-util-is": {
25
- "version": "1.0.3",
26
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
27
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
28
- "license": "MIT"
29
- },
30
- "node_modules/immediate": {
31
- "version": "3.0.6",
32
- "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
33
- "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
34
- "license": "MIT"
35
- },
36
- "node_modules/inherits": {
37
- "version": "2.0.4",
38
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
39
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
40
- "license": "ISC"
41
- },
42
- "node_modules/isarray": {
43
- "version": "1.0.0",
44
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
45
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
46
- "license": "MIT"
47
- },
48
- "node_modules/jszip": {
49
- "version": "3.10.1",
50
- "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
51
- "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
52
- "license": "(MIT OR GPL-3.0-or-later)",
53
- "dependencies": {
54
- "lie": "~3.3.0",
55
- "pako": "~1.0.2",
56
- "readable-stream": "~2.3.6",
57
- "setimmediate": "^1.0.5"
58
- }
59
- },
60
- "node_modules/lie": {
61
- "version": "3.3.0",
62
- "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
63
- "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
64
- "license": "MIT",
65
- "dependencies": {
66
- "immediate": "~3.0.5"
67
- }
68
- },
69
- "node_modules/pako": {
70
- "version": "1.0.11",
71
- "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
72
- "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
73
- "license": "(MIT AND Zlib)"
74
- },
75
- "node_modules/parse-ms": {
76
- "version": "4.0.0",
77
- "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
78
- "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
79
- "license": "MIT",
80
- "engines": {
81
- "node": ">=18"
82
- },
83
- "funding": {
84
- "url": "https://github.com/sponsors/sindresorhus"
85
- }
86
- },
87
- "node_modules/pretty-ms": {
88
- "version": "9.3.0",
89
- "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",
90
- "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==",
91
- "license": "MIT",
92
- "dependencies": {
93
- "parse-ms": "^4.0.0"
94
- },
95
- "engines": {
96
- "node": ">=18"
97
- },
98
- "funding": {
99
- "url": "https://github.com/sponsors/sindresorhus"
100
- }
101
- },
102
- "node_modules/process-nextick-args": {
103
- "version": "2.0.1",
104
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
105
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
106
- "license": "MIT"
107
- },
108
- "node_modules/readable-stream": {
109
- "version": "2.3.8",
110
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
111
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
112
- "license": "MIT",
113
- "dependencies": {
114
- "core-util-is": "~1.0.0",
115
- "inherits": "~2.0.3",
116
- "isarray": "~1.0.0",
117
- "process-nextick-args": "~2.0.0",
118
- "safe-buffer": "~5.1.1",
119
- "string_decoder": "~1.1.1",
120
- "util-deprecate": "~1.0.1"
121
- }
122
- },
123
- "node_modules/safe-buffer": {
124
- "version": "5.1.2",
125
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
126
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
127
- "license": "MIT"
128
- },
129
- "node_modules/setimmediate": {
130
- "version": "1.0.5",
131
- "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
132
- "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
133
- "license": "MIT"
134
- },
135
- "node_modules/string_decoder": {
136
- "version": "1.1.1",
137
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
138
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
139
- "license": "MIT",
140
- "dependencies": {
141
- "safe-buffer": "~5.1.0"
142
- }
143
- },
144
- "node_modules/typebox": {
145
- "version": "1.3.6",
146
- "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.6.tgz",
147
- "integrity": "sha512-Sc8RA0NCMEFmApHNU9ZMzqcpQj46She44J8ffpLM/bdhLNUZKq7DJumcLcsFx1gRmDfQPgCgOmFFJ7rcnfWNyA==",
148
- "license": "MIT"
149
- },
150
- "node_modules/util-deprecate": {
151
- "version": "1.0.2",
152
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
153
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
154
- "license": "MIT"
155
- }
156
- }
157
- }