@openclaw/google-meet 2026.9.8 → 2026.10.1-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.
@@ -94,25 +94,6 @@ function isGoogleMeetCreateTab(tab) {
94
94
  if (/^https:\/\/meet\.google\.com\/(?:new|[a-z]{3}-[a-z]{4}-[a-z]{3})(?:$|[/?#])/i.test(url)) return true;
95
95
  return url.startsWith("https://accounts.google.com/") && /sign in|google accounts|meet/i.test(tab.title ?? "");
96
96
  }
97
- async function findGoogleMeetCreateTab(params) {
98
- return asMeetingBrowserTabs(await callBrowserProxyOnNode({
99
- runtime: params.runtime,
100
- nodeId: params.nodeId,
101
- method: "GET",
102
- path: "/tabs",
103
- timeoutMs: params.timeoutMs
104
- })).find(isGoogleMeetCreateTab);
105
- }
106
- async function focusBrowserTab(params) {
107
- await callBrowserProxyOnNode({
108
- runtime: params.runtime,
109
- nodeId: params.nodeId,
110
- method: "POST",
111
- path: "/tabs/focus",
112
- body: { targetId: params.targetId },
113
- timeoutMs: params.timeoutMs
114
- });
115
- }
116
97
  function readBrowserManualAction(value) {
117
98
  const action = asRecord(value);
118
99
  return typeof action.reason === "string" && typeof action.message === "string" ? {
@@ -136,8 +117,13 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
136
117
  const meetUrlPattern = /^https:\\/\\/meet\\.google\\.com\\/[a-z]{3}-[a-z]{4}-[a-z]{3}(?:$|[/?#])/i;
137
118
  const text = (node) => (node?.innerText || node?.textContent || "").trim();
138
119
  const current = () => location.href;
139
- const manualActionFor = (reason, message) => ({ reason, message });
140
120
  const notes = [];
121
+ const manualActionFor = (reason, message, browserUrl = current()) => ({
122
+ manualAction: { reason, message },
123
+ browserUrl,
124
+ browserTitle: document.title,
125
+ notes,
126
+ });
141
127
  const findButton = (pattern) =>
142
128
  [...document.querySelectorAll("button")].find((button) => {
143
129
  const label = [
@@ -159,12 +145,7 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
159
145
  return true;
160
146
  };
161
147
  if (!current().startsWith("https://meet.google.com/")) {
162
- return {
163
- manualAction: manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry meeting creation."),
164
- browserUrl: current(),
165
- browserTitle: document.title,
166
- notes,
167
- };
148
+ return manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry meeting creation.");
168
149
  }
169
150
  const href = current();
170
151
  if (meetUrlPattern.test(href)) {
@@ -173,10 +154,8 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
173
154
  return { meetingUri: href.split(/[?#]/)[0], browserUrl: href, browserTitle: document.title, notes };
174
155
  }
175
156
  const pageText = text(document.body);
176
- if (clickButton(/\\buse microphone\\b/i, "Accepted Meet microphone prompt with browser automation.")) {
177
- return { browserUrl: href, browserTitle: document.title, notes, retryAfterMs: 1000 };
178
- }
179
157
  if (
158
+ clickButton(/\\buse microphone\\b/i, "Accepted Meet microphone prompt with browser automation.") ||
180
159
  clickButton(
181
160
  /continue without microphone/i,
182
161
  "Continued through Meet microphone prompt with browser automation.",
@@ -185,36 +164,16 @@ const CREATE_MEET_FROM_BROWSER_SCRIPT = `async () => {
185
164
  return { browserUrl: href, browserTitle: document.title, notes, retryAfterMs: 1000 };
186
165
  }
187
166
  if (/do you want people to hear you in the meeting/i.test(pageText)) {
188
- return {
189
- manualAction: manualActionFor("meet-audio-choice-required", "Meet is showing the microphone choice. Click Use microphone in the OpenClaw browser profile, then retry meeting creation."),
190
- browserUrl: href,
191
- browserTitle: document.title,
192
- notes,
193
- };
167
+ return manualActionFor("meet-audio-choice-required", "Meet is showing the microphone choice. Click Use microphone in the OpenClaw browser profile, then retry meeting creation.", href);
194
168
  }
195
169
  if (/allow.*(microphone|camera)|blocked.*(microphone|camera)|permission.*(microphone|camera)/i.test(pageText)) {
196
- return {
197
- manualAction: manualActionFor("meet-permission-required", "Allow microphone/camera permissions for Meet in the OpenClaw browser profile, then retry meeting creation."),
198
- browserUrl: href,
199
- browserTitle: document.title,
200
- notes,
201
- };
170
+ return manualActionFor("meet-permission-required", "Allow microphone/camera permissions for Meet in the OpenClaw browser profile, then retry meeting creation.", href);
202
171
  }
203
172
  if (/couldn't create|unable to create/i.test(pageText)) {
204
- return {
205
- manualAction: manualActionFor("browser-control-unavailable", "Resolve the Google Meet page prompt in the OpenClaw browser profile, then retry meeting creation."),
206
- browserUrl: href,
207
- browserTitle: document.title,
208
- notes,
209
- };
173
+ return manualActionFor("browser-control-unavailable", "Resolve the Google Meet page prompt in the OpenClaw browser profile, then retry meeting creation.", href);
210
174
  }
211
175
  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)) {
212
- return {
213
- manualAction: manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry meeting creation."),
214
- browserUrl: href,
215
- browserTitle: document.title,
216
- notes,
217
- };
176
+ return manualActionFor("google-login-required", "Sign in to Google in the OpenClaw browser profile, then retry meeting creation.", href);
218
177
  }
219
178
  return {
220
179
  retryAfterMs: 500,
@@ -231,16 +190,20 @@ async function createMeetWithBrowserProxyOnNode(params) {
231
190
  const timeoutMs = Math.max(GOOGLE_MEET_BROWSER_CREATE_TIMEOUT_MS, params.config.chrome.joinTimeoutMs);
232
191
  const stepTimeoutMs = Math.min(timeoutMs, GOOGLE_MEET_BROWSER_STEP_TIMEOUT_MS);
233
192
  let openedByPlugin = false;
234
- let tab = await findGoogleMeetCreateTab({
193
+ let tab = asMeetingBrowserTabs(await callBrowserProxyOnNode({
235
194
  runtime: params.runtime,
236
195
  nodeId,
196
+ method: "GET",
197
+ path: "/tabs",
237
198
  timeoutMs: stepTimeoutMs
238
- });
199
+ })).find(isGoogleMeetCreateTab);
239
200
  if (tab?.targetId) {
240
- await focusBrowserTab({
201
+ await callBrowserProxyOnNode({
241
202
  runtime: params.runtime,
242
203
  nodeId,
243
- targetId: tab.targetId,
204
+ method: "POST",
205
+ path: "/tabs/focus",
206
+ body: { targetId: tab.targetId },
244
207
  timeoutMs: stepTimeoutMs
245
208
  });
246
209
  const reusedUrl = tab.url ?? "";
@@ -1,8 +1,8 @@
1
- import { a as resolveArtifactQueryFromParams, c as resolveSpaceFromParams, d as endGoogleMeetActiveConference, f as fetchGoogleMeetSpace, h as listGoogleMeetCalendarEvents, l as buildGoogleMeetPreflightReport, m as buildGoogleMeetCalendarDayWindow, n as fetchResolvedGoogleMeetArtifacts, o as resolveGoogleMeetTokenFromParams, p as fetchLatestGoogleMeetConferenceRecord, r as fetchResolvedGoogleMeetAttendance, s as resolveMeetingFromParams, t as buildGoogleMeetExportRequest, u as createGoogleMeetSpace } from "./plugin-helpers-CdQ_YNA7.mjs";
1
+ import { a as resolveArtifactQueryFromParams, c as resolveSpaceFromParams, d as endGoogleMeetActiveConference, f as fetchGoogleMeetSpace, h as listGoogleMeetCalendarEvents, l as buildGoogleMeetPreflightReport, m as buildGoogleMeetCalendarDayWindow, n as fetchResolvedGoogleMeetArtifacts, o as resolveGoogleMeetTokenFromParams, p as fetchLatestGoogleMeetConferenceRecord, r as fetchResolvedGoogleMeetAttendance, s as resolveMeetingFromParams, t as buildGoogleMeetExportRequest, u as createGoogleMeetSpace } from "./plugin-helpers-D1OyyzEZ.mjs";
2
2
  import { i as resolveGoogleMeetGatewayOperationTimeoutMs } from "./config-BXGAMntj.mjs";
3
- import { C as writeSetupStatus, S as writeRecoverCurrentTabResult, T as writeStdoutLine, _ as promptInput, a as renderAttendanceCsv, b as writeDoctorStatus, c as writeCalendarEventsSummary, d as parseGoogleMeetBrowserTransport, f as parseGoogleMeetMode, g as parsePositiveNumber, h as parsePositiveIntegerOption, i as renderArtifactsSummary, l as writeLatestConferenceRecordSummary, m as parseOptionalNumber, n as exportGoogleMeetBundle, o as renderAttendanceMarkdown, p as parseGoogleMeetTransport, r as renderArtifactsMarkdown, s as renderAttendanceSummary, u as callGoogleMeetGateway, v as resolveGoogleMeetOAuthCallbackTimeoutMs, w as writeStdoutJson, x as writeLeaveResult, y as writeCliOutput } from "./cli-export-D4IM6KLJ.mjs";
4
- import { buildGoogleMeetAuthUrl, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-BoyruWcS.mjs";
5
- import { n as hasCreateSpaceConfigInput, r as resolveCreateSpaceConfig } from "./create-UrHOmnWb.mjs";
3
+ import { C as writeStdoutJson, S as writeSetupStatus, _ as resolveGoogleMeetOAuthCallbackTimeoutMs, a as renderAttendanceCsv, b as writeLeaveResult, c as callGoogleMeetGateway, d as parseGoogleMeetTransport, f as parseOptionalNumber, g as resolveCliJoinRequest, h as promptInput, i as renderAttendance, l as parseGoogleMeetBrowserTransport, m as parsePositiveNumber, n as exportGoogleMeetBundle, o as writeCalendarEventsSummary, p as parsePositiveIntegerOption, r as renderArtifacts, s as writeLatestConferenceRecordSummary, u as parseGoogleMeetMode, v as writeCliOutput, w as writeStdoutLine, x as writeRecoverCurrentTabResult, y as writeDoctorStatus } from "./cli-export-BOebaVFW.mjs";
4
+ import { buildGoogleMeetAuthUrl, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-XgdPFWEJ.mjs";
5
+ import { n as hasCreateSpaceConfigInput, r as resolveCreateSpaceConfig } from "./create-DyYbmN11.mjs";
6
6
  import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
7
7
  import { callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
8
8
  import { generateHexPkceVerifierChallenge } from "openclaw/plugin-sdk/provider-auth";
@@ -20,6 +20,15 @@ function addGoogleMeetCalendarOptions(command) {
20
20
  function addGoogleMeetArtifactOptions(command) {
21
21
  return addGoogleMeetOAuthOptions(addGoogleMeetCalendarOptions(addGoogleMeetMeetingOption(command).option("--conference-record <name>", "Conference record name or id"))).option("--page-size <n>", "Max resources per Meet API page").option("--all-conference-records", "Fetch every conference record for --meeting");
22
22
  }
23
+ async function callGoogleMeetRuntime(context, method, payload, local, timeoutMs) {
24
+ const delegated = await callGoogleMeetGateway({
25
+ callGateway: context.callGateway,
26
+ method,
27
+ payload,
28
+ timeoutMs
29
+ });
30
+ return delegated.ok ? delegated.payload : local(await context.ensureRuntime());
31
+ }
23
32
  //#endregion
24
33
  //#region extensions/google-meet/src/cli-artifact-commands.ts
25
34
  async function resolveCliArtifactQuery(context, options) {
@@ -34,10 +43,9 @@ function resolveTokenSource(refreshed) {
34
43
  return refreshed ? "refresh-token" : "cached-access-token";
35
44
  }
36
45
  function registerGoogleMeetArtifactCommands(context) {
37
- const params = context;
38
46
  const { root } = context;
39
47
  addGoogleMeetArtifactOptions(root.command("artifacts").description("List Meet conference records and available participant/artifact metadata")).option("--no-transcript-entries", "Skip structured transcript entry lookup").option("--include-doc-bodies", "Export linked transcript and smart-note Google Docs text").option("--format <format>", "Output format: summary or markdown", "summary").option("--output <path>", "Write output to a file instead of stdout").option("--json", "Print JSON output", false).action(async (options) => {
40
- const resolved = await resolveCliArtifactQuery(params, options);
48
+ const resolved = await resolveCliArtifactQuery(context, options);
41
49
  const result = await fetchResolvedGoogleMeetArtifacts(resolved);
42
50
  const tokenSource = resolveTokenSource(resolved.token.refreshed);
43
51
  let text;
@@ -45,13 +53,13 @@ function registerGoogleMeetArtifactCommands(context) {
45
53
  ...result,
46
54
  tokenSource
47
55
  }, null, 2);
48
- else if (options.format === "markdown") text = renderArtifactsMarkdown(result);
49
- else if (!options.format || options.format === "summary") text = `${renderArtifactsSummary(result)}token source: ${tokenSource}\n`;
56
+ else if (options.format === "markdown") text = renderArtifacts(result, "markdown");
57
+ else if (!options.format || options.format === "summary") text = `${renderArtifacts(result, "summary")}token source: ${tokenSource}\n`;
50
58
  else throw new Error("Unsupported format. Expected summary or markdown.");
51
59
  await writeCliOutput(options, text);
52
60
  });
53
61
  addGoogleMeetArtifactOptions(root.command("attendance").description("List Meet participants and participant sessions")).option("--no-merge-duplicates", "Keep duplicate participant resources as separate rows").option("--late-after-minutes <n>", "Mark participants late after this many minutes", "5").option("--early-before-minutes <n>", "Mark early leavers before this many minutes", "5").option("--format <format>", "Output format: summary, markdown, or csv", "summary").option("--output <path>", "Write output to a file instead of stdout").option("--json", "Print JSON output", false).action(async (options) => {
54
- const resolved = await resolveCliArtifactQuery(params, options);
62
+ const resolved = await resolveCliArtifactQuery(context, options);
55
63
  const result = await fetchResolvedGoogleMeetAttendance(resolved);
56
64
  const tokenSource = resolveTokenSource(resolved.token.refreshed);
57
65
  let text;
@@ -59,14 +67,14 @@ function registerGoogleMeetArtifactCommands(context) {
59
67
  ...result,
60
68
  tokenSource
61
69
  }, null, 2);
62
- else if (options.format === "markdown") text = renderAttendanceMarkdown(result);
70
+ else if (options.format === "markdown") text = renderAttendance(result, "markdown");
63
71
  else if (options.format === "csv") text = renderAttendanceCsv(result);
64
- else if (!options.format || options.format === "summary") text = `${renderAttendanceSummary(result)}token source: ${tokenSource}\n`;
72
+ else if (!options.format || options.format === "summary") text = `${renderAttendance(result, "summary")}token source: ${tokenSource}\n`;
65
73
  else throw new Error("Unsupported format. Expected summary, markdown, or csv.");
66
74
  await writeCliOutput(options, text);
67
75
  });
68
76
  addGoogleMeetArtifactOptions(root.command("export").description("Write Meet artifacts, attendance, transcript, and raw JSON into a folder")).option("--no-transcript-entries", "Skip structured transcript entry lookup").option("--include-doc-bodies", "Export linked transcript and smart-note Google Docs text").option("--no-merge-duplicates", "Keep duplicate participant resources as separate rows").option("--late-after-minutes <n>", "Mark participants late after this many minutes", "5").option("--early-before-minutes <n>", "Mark early leavers before this many minutes", "5").option("--output <dir>", "Output directory").option("--zip", "Also write a portable .zip archive").option("--dry-run", "Fetch export data and print the manifest without writing files", false).option("--json", "Print JSON output", false).action(async (options) => {
69
- const resolved = await resolveCliArtifactQuery(params, options);
77
+ const resolved = await resolveCliArtifactQuery(context, options);
70
78
  const artifacts = await fetchResolvedGoogleMeetArtifacts(resolved);
71
79
  const attendance = await fetchResolvedGoogleMeetAttendance(resolved);
72
80
  const payload = await exportGoogleMeetBundle({
@@ -197,11 +205,10 @@ function writeOAuthDoctorReport(report) {
197
205
  for (const check of report.checks) writeStdoutLine("[%s] %s: %s", check.ok ? "ok" : "fail", check.id, check.message);
198
206
  }
199
207
  function registerGoogleMeetDoctorCommand(context) {
200
- const params = context;
201
- const { root, callGateway } = context;
202
- root.command("doctor").description("Show human-readable Meet session/browser/realtime health").argument("[session-id]", "Meet session ID").option("--oauth", "Verify Google Meet OAuth token refresh without printing secrets", false).option("--meeting <value>", "Also verify spaces.get for a Meet URL, code, or spaces/{id}").option("--create-space", "Also verify spaces.create by creating a throwaway Meet space", false).option("--access-token <token>", "Access token override").option("--refresh-token <token>", "Refresh token override").option("--client-id <id>", "OAuth client id override").option("--client-secret <secret>", "OAuth client secret override").option("--expires-at <ms>", "Cached access token expiry as unix epoch milliseconds").option("--json", "Print JSON output", false).action(async (sessionId, options) => {
208
+ const { root } = context;
209
+ addGoogleMeetOAuthOptions(root.command("doctor").description("Show human-readable Meet session/browser/realtime health").argument("[session-id]", "Meet session ID").option("--oauth", "Verify Google Meet OAuth token refresh without printing secrets", false).option("--meeting <value>", "Also verify spaces.get for a Meet URL, code, or spaces/{id}").option("--create-space", "Also verify spaces.create by creating a throwaway Meet space", false)).option("--json", "Print JSON output", false).action(async (sessionId, options) => {
203
210
  if (options.oauth) {
204
- const report = await buildOAuthDoctorReport(params.config, options);
211
+ const report = await buildOAuthDoctorReport(context.config, options);
205
212
  if (options.json) {
206
213
  writeStdoutJson(report);
207
214
  return;
@@ -209,14 +216,7 @@ function registerGoogleMeetDoctorCommand(context) {
209
216
  writeOAuthDoctorReport(report);
210
217
  return;
211
218
  }
212
- const delegated = await callGoogleMeetGateway({
213
- callGateway,
214
- method: "googlemeet.status",
215
- payload: { sessionId }
216
- });
217
- let status;
218
- if (delegated.ok) status = delegated.payload;
219
- else status = await (await params.ensureRuntime()).status(sessionId);
219
+ const status = await callGoogleMeetRuntime(context, "googlemeet.status", { sessionId }, (rt) => rt.status(sessionId));
220
220
  if (options.json) {
221
221
  writeStdoutJson(status);
222
222
  return;
@@ -227,18 +227,9 @@ function registerGoogleMeetDoctorCommand(context) {
227
227
  //#endregion
228
228
  //#region extensions/google-meet/src/cli-runtime-commands.ts
229
229
  function registerGoogleMeetProbeCommands(context) {
230
- const params = context;
231
230
  const { root, callGateway, operationTimeoutMs, resolveMeetingInput } = context;
232
231
  root.command("join").argument("[url]", "Explicit https://meet.google.com/... URL").option("--transport <transport>", "Transport: chrome, chrome-node, or twilio").option("--mode <mode>", "Mode: agent, bidi, or transcribe").option("--message <text>", "Realtime speech to trigger after join").option("--dial-in-number <phone>", "Meet dial-in number for Twilio transport").option("--pin <pin>", "Meet phone PIN; # is appended if omitted").option("--dtmf-sequence <sequence>", "Explicit Twilio DTMF sequence").action(async (url, options) => {
233
- const payload = {
234
- url: resolveMeetingInput(params.config, url),
235
- transport: parseGoogleMeetTransport(options.transport),
236
- mode: parseGoogleMeetMode(options.mode),
237
- message: options.message,
238
- dialInNumber: options.dialInNumber,
239
- pin: options.pin,
240
- dtmfSequence: options.dtmfSequence
241
- };
232
+ const payload = resolveCliJoinRequest(resolveMeetingInput(context.config, url), options);
242
233
  const delegated = await callGoogleMeetGateway({
243
234
  callGateway,
244
235
  method: "googlemeet.join",
@@ -250,77 +241,39 @@ function registerGoogleMeetProbeCommands(context) {
250
241
  writeStdoutJson(result.session ?? delegated.payload);
251
242
  return;
252
243
  }
253
- const result = await (await params.ensureRuntime()).join(payload);
244
+ const result = await (await context.ensureRuntime()).join(payload);
254
245
  writeStdoutJson(result.session);
255
246
  });
256
247
  root.command("test-speech").argument("[url]", "Explicit https://meet.google.com/... URL").option("--transport <transport>", "Transport: chrome, chrome-node, or twilio").option("--mode <mode>", "Mode: agent, bidi, or transcribe").option("--message <text>", "Realtime speech to trigger", "Say exactly: Google Meet speech test complete.").action(async (url, options) => {
257
248
  const payload = {
258
- url: resolveMeetingInput(params.config, url),
249
+ url: resolveMeetingInput(context.config, url),
259
250
  transport: parseGoogleMeetTransport(options.transport),
260
251
  mode: parseGoogleMeetMode(options.mode),
261
252
  message: options.message
262
253
  };
263
- const delegated = await callGoogleMeetGateway({
264
- callGateway,
265
- method: "googlemeet.testSpeech",
266
- payload,
267
- timeoutMs: operationTimeoutMs
268
- });
269
- if (delegated.ok) {
270
- writeStdoutJson(delegated.payload);
271
- return;
272
- }
273
- const rt = await params.ensureRuntime();
274
- writeStdoutJson(await rt.testSpeech(payload));
254
+ writeStdoutJson(await callGoogleMeetRuntime(context, "googlemeet.testSpeech", payload, (rt) => rt.testSpeech(payload), operationTimeoutMs));
275
255
  });
276
256
  root.command("test-listen").argument("[url]", "Explicit https://meet.google.com/... URL").option("--transport <transport>", "Transport: chrome or chrome-node").option("--timeout-ms <ms>", "How long to wait for fresh captions/transcript movement").action(async (url, options) => {
277
257
  const payload = {
278
- url: resolveMeetingInput(params.config, url),
258
+ url: resolveMeetingInput(context.config, url),
279
259
  transport: parseGoogleMeetBrowserTransport(options.transport),
280
260
  timeoutMs: parsePositiveNumber(options.timeoutMs, "timeout-ms")
281
261
  };
282
- const delegated = await callGoogleMeetGateway({
283
- callGateway,
284
- method: "googlemeet.testListen",
285
- payload,
286
- timeoutMs: operationTimeoutMs
287
- });
288
- if (delegated.ok) {
289
- writeStdoutJson(delegated.payload);
290
- return;
291
- }
292
- const rt = await params.ensureRuntime();
293
- writeStdoutJson(await rt.testListen(payload));
262
+ writeStdoutJson(await callGoogleMeetRuntime(context, "googlemeet.testListen", payload, (rt) => rt.testListen(payload), operationTimeoutMs));
294
263
  });
295
264
  }
296
265
  function registerGoogleMeetSessionCommands(context) {
297
- const params = context;
298
- const { root, callGateway } = context;
266
+ const { root } = context;
299
267
  root.command("status").argument("[session-id]", "Meet session ID").option("--json", "Print JSON output", false).action(async (sessionId) => {
300
- const delegated = await callGoogleMeetGateway({
301
- callGateway,
302
- method: "googlemeet.status",
303
- payload: { sessionId }
304
- });
305
- if (delegated.ok) {
306
- writeStdoutJson(delegated.payload);
307
- return;
308
- }
309
- const rt = await params.ensureRuntime();
310
- writeStdoutJson(await rt.status(sessionId));
268
+ writeStdoutJson(await callGoogleMeetRuntime(context, "googlemeet.status", { sessionId }, (rt) => rt.status(sessionId)));
311
269
  });
312
270
  root.command("transcript").description("Print the bounded caption transcript for a Meet session").argument("<session-id>", "Meet session ID").option("--since <index>", "Resume from the previous response's nextIndex").option("--json", "Print JSON output", false).action(async (sessionId, options) => {
313
271
  const sinceIndex = parseStrictNonNegativeInteger(options.since);
314
272
  if (options.since !== void 0 && sinceIndex === void 0) throw new Error("--since must be a non-negative safe integer");
315
- const delegated = await callGoogleMeetGateway({
316
- callGateway,
317
- method: "googlemeet.transcript",
318
- payload: {
319
- sessionId,
320
- ...sinceIndex === void 0 ? {} : { sinceIndex }
321
- }
322
- });
323
- const result = delegated.ok ? delegated.payload : await (await params.ensureRuntime()).transcript(sessionId, sinceIndex === void 0 ? {} : { sinceIndex });
273
+ const result = await callGoogleMeetRuntime(context, "googlemeet.transcript", {
274
+ sessionId,
275
+ ...sinceIndex === void 0 ? {} : { sinceIndex }
276
+ }, (rt) => rt.transcript(sessionId, sinceIndex === void 0 ? {} : { sinceIndex }));
324
277
  if (!result.found) throw new Error("session not found");
325
278
  if (options.json) {
326
279
  writeStdoutJson(result);
@@ -333,10 +286,9 @@ function registerGoogleMeetSessionCommands(context) {
333
286
  });
334
287
  }
335
288
  function registerGoogleMeetLifecycleCommands(context) {
336
- const params = context;
337
- const { root, callGateway } = context;
289
+ const { root } = context;
338
290
  root.command("recover-tab").description("Focus and inspect an existing Google Meet tab").argument("[url]", "Optional Meet URL to match").option("--transport <transport>", "Transport to inspect: chrome or chrome-node").option("--json", "Print JSON output", false).action(async (url, options) => {
339
- const result = await (await params.ensureRuntime()).recoverCurrentTab({
291
+ const result = await (await context.ensureRuntime()).recoverCurrentTab({
340
292
  url,
341
293
  transport: parseGoogleMeetBrowserTransport(options.transport)
342
294
  });
@@ -347,38 +299,24 @@ function registerGoogleMeetLifecycleCommands(context) {
347
299
  writeRecoverCurrentTabResult(result);
348
300
  });
349
301
  root.command("setup").description("Show Google Meet transport setup status").option("--transport <transport>", "Transport to check: chrome, chrome-node, or twilio").option("--mode <mode>", "Mode to check: agent, bidi, or transcribe").option("--json", "Print JSON output", false).action(async (options) => {
350
- const status = await (await params.ensureRuntime()).setupStatus({
302
+ const status = await (await context.ensureRuntime()).setupStatus({
351
303
  transport: parseGoogleMeetTransport(options.transport),
352
304
  mode: parseGoogleMeetMode(options.mode)
353
305
  });
354
- if (options.json) {
355
- writeStdoutJson(status);
356
- if (!status.ok) process.exitCode = 1;
357
- return;
358
- }
359
- writeSetupStatus(status);
306
+ if (options.json) writeStdoutJson(status);
307
+ else writeSetupStatus(status);
360
308
  if (!status.ok) process.exitCode = 1;
361
309
  });
362
310
  root.command("leave").argument("<session-id>", "Meet session ID").action(async (sessionId) => {
363
- const delegated = await callGoogleMeetGateway({
364
- callGateway,
365
- method: "googlemeet.leave",
366
- payload: { sessionId }
367
- });
368
- const result = delegated.ok ? delegated.payload : await (await params.ensureRuntime()).leave(sessionId);
311
+ const result = await callGoogleMeetRuntime(context, "googlemeet.leave", { sessionId }, (rt) => rt.leave(sessionId));
369
312
  if (!result.found) throw new Error("session not found");
370
313
  writeLeaveResult(sessionId, result);
371
314
  });
372
315
  root.command("speak").argument("<session-id>", "Meet session ID").argument("[message]", "Realtime instructions to speak now").action(async (sessionId, message) => {
373
- const delegated = await callGoogleMeetGateway({
374
- callGateway,
375
- method: "googlemeet.speak",
376
- payload: {
377
- sessionId,
378
- message
379
- }
380
- });
381
- const result = delegated.ok ? delegated.payload : await (await params.ensureRuntime()).speak(sessionId, message);
316
+ const result = await callGoogleMeetRuntime(context, "googlemeet.speak", {
317
+ sessionId,
318
+ message
319
+ }, (rt) => rt.speak(sessionId, message));
382
320
  if (!result.found) throw new Error("session not found");
383
321
  if (!result.spoken) throw new Error(result.session?.chrome?.health?.speechBlockedMessage ?? "session has no active realtime audio bridge");
384
322
  writeStdoutLine("speaking on %s", sessionId);
@@ -401,7 +339,6 @@ function writeGoogleMeetCreateOutput(payload, json) {
401
339
  writeStdoutLine(joinedSessionId ? "joined: %s" : "joined: no (run `openclaw googlemeet join %s`)", joinedSessionId ?? payload.meetingUri);
402
340
  }
403
341
  function registerGoogleMeetCreateCommands(context) {
404
- const params = context;
405
342
  const { root, callGateway, operationTimeoutMs, hasCreateOAuth, resolveMeetingInput, resolveCliParams } = context;
406
343
  addGoogleMeetOAuthOptions(root.command("create").description("Create a new Google Meet space and print its meeting URL")).option("--access-type <type>", "Google Meet SpaceConfig accessType for API create: OPEN, TRUSTED, or RESTRICTED").option("--entry-point-access <type>", "Google Meet SpaceConfig entryPointAccess for API create: ALL or CREATOR_APP_ONLY").option("--no-join", "Only create the meeting URL; do not join it").option("--transport <transport>", "Join transport: chrome, chrome-node, or twilio").option("--mode <mode>", "Join mode: agent, bidi, or transcribe").option("--message <text>", "Realtime speech to trigger after join").option("--dial-in-number <phone>", "Meet dial-in number for Twilio transport").option("--pin <pin>", "Meet phone PIN; # is appended if omitted").option("--dtmf-sequence <sequence>", "Explicit Twilio DTMF sequence").option("--json", "Print JSON output", false).action(async (options) => {
407
344
  if (options.join !== false) {
@@ -417,19 +354,11 @@ function registerGoogleMeetCreateCommands(context) {
417
354
  return;
418
355
  }
419
356
  }
420
- if (!hasCreateOAuth(params.config, options)) {
357
+ if (!hasCreateOAuth(context.config, options)) {
421
358
  if (hasCreateSpaceConfigInput(options)) throw new Error("Google Meet access policy options require OAuth/API room creation. Configure Google Meet OAuth or remove --access-type/--entry-point-access.");
422
- const rt = await params.ensureRuntime();
359
+ const rt = await context.ensureRuntime();
423
360
  const result = await rt.createViaBrowser();
424
- const join = options.join !== false ? await rt.join({
425
- url: result.meetingUri,
426
- transport: parseGoogleMeetTransport(options.transport),
427
- mode: parseGoogleMeetMode(options.mode),
428
- message: options.message,
429
- dialInNumber: options.dialInNumber,
430
- pin: options.pin,
431
- dtmfSequence: options.dtmfSequence
432
- }) : void 0;
361
+ const join = options.join !== false ? await rt.join(resolveCliJoinRequest(result.meetingUri, options)) : void 0;
433
362
  writeGoogleMeetCreateOutput({
434
363
  source: result.source,
435
364
  meetingUri: result.meetingUri,
@@ -444,20 +373,12 @@ function registerGoogleMeetCreateCommands(context) {
444
373
  }, options.json);
445
374
  return;
446
375
  }
447
- const token = await resolveGoogleMeetTokenFromParams(params.config, resolveCliParams(options));
376
+ const token = await resolveGoogleMeetTokenFromParams(context.config, resolveCliParams(options));
448
377
  const result = await createGoogleMeetSpace({
449
378
  accessToken: token.accessToken,
450
379
  config: resolveCreateSpaceConfig(options)
451
380
  });
452
- const join = options.join !== false ? await (await params.ensureRuntime()).join({
453
- url: result.meetingUri,
454
- transport: parseGoogleMeetTransport(options.transport),
455
- mode: parseGoogleMeetMode(options.mode),
456
- message: options.message,
457
- dialInNumber: options.dialInNumber,
458
- pin: options.pin,
459
- dtmfSequence: options.dtmfSequence
460
- }) : void 0;
381
+ const join = options.join !== false ? await (await context.ensureRuntime()).join(resolveCliJoinRequest(result.meetingUri, options)) : void 0;
461
382
  writeGoogleMeetCreateOutput({
462
383
  ...result,
463
384
  tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
@@ -466,10 +387,10 @@ function registerGoogleMeetCreateCommands(context) {
466
387
  }, options.json);
467
388
  });
468
389
  addGoogleMeetOAuthOptions(root.command("end-active-conference").description("End the active conference for a Google Meet space").argument("[meeting]", "Meet URL, meeting code, or spaces/{id}")).option("--json", "Print JSON output", false).action(async (meeting, options) => {
469
- const token = await resolveGoogleMeetTokenFromParams(params.config, resolveCliParams(options));
390
+ const token = await resolveGoogleMeetTokenFromParams(context.config, resolveCliParams(options));
470
391
  const result = await endGoogleMeetActiveConference({
471
392
  accessToken: token.accessToken,
472
- meeting: resolveMeetingInput(params.config, meeting ?? options.meeting)
393
+ meeting: resolveMeetingInput(context.config, meeting ?? options.meeting)
473
394
  });
474
395
  if (options.json) {
475
396
  writeStdoutJson({
@@ -484,11 +405,10 @@ function registerGoogleMeetCreateCommands(context) {
484
405
  });
485
406
  }
486
407
  function registerGoogleMeetApiCommands(context) {
487
- const params = context;
488
408
  const { root, resolveCliParams, resolveMeetingInput } = context;
489
409
  addGoogleMeetOAuthOptions(addGoogleMeetMeetingOption(root.command("resolve-space").description("Resolve a Meet URL, meeting code, or spaces/{id} to its canonical space"))).option("--json", "Print JSON output", false).action(async (options) => {
490
- const meeting = resolveMeetingInput(params.config, options.meeting);
491
- const { space, token } = await resolveSpaceFromParams(params.config, {
410
+ const meeting = resolveMeetingInput(context.config, options.meeting);
411
+ const { space, token } = await resolveSpaceFromParams(context.config, {
492
412
  ...resolveCliParams(options),
493
413
  meeting
494
414
  });
@@ -504,15 +424,15 @@ function registerGoogleMeetApiCommands(context) {
504
424
  writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
505
425
  });
506
426
  addGoogleMeetOAuthOptions(addGoogleMeetMeetingOption(root.command("preflight").description("Validate OAuth + meeting resolution prerequisites for Meet media work"))).option("--json", "Print JSON output", false).action(async (options) => {
507
- const meeting = resolveMeetingInput(params.config, options.meeting);
508
- const { space, token } = await resolveSpaceFromParams(params.config, {
427
+ const meeting = resolveMeetingInput(context.config, options.meeting);
428
+ const { space, token } = await resolveSpaceFromParams(context.config, {
509
429
  ...resolveCliParams(options),
510
430
  meeting
511
431
  });
512
432
  const report = buildGoogleMeetPreflightReport({
513
433
  input: meeting,
514
434
  space,
515
- previewAcknowledged: params.config.preview.enrollmentAcknowledged,
435
+ previewAcknowledged: context.config.preview.enrollmentAcknowledged,
516
436
  tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
517
437
  });
518
438
  if (options.json) {
@@ -535,14 +455,14 @@ function registerGoogleMeetApiCommands(context) {
535
455
  });
536
456
  addGoogleMeetOAuthOptions(addGoogleMeetCalendarOptions(addGoogleMeetMeetingOption(root.command("latest").description("Find the latest Meet conference record for a meeting")))).option("--json", "Print JSON output", false).action(async (options) => {
537
457
  const raw = resolveCliParams(options);
538
- const token = await resolveGoogleMeetTokenFromParams(params.config, raw);
458
+ const token = await resolveGoogleMeetTokenFromParams(context.config, raw);
539
459
  if (!options.today && !options.event?.trim()) {
540
- const meeting = options.meeting?.trim() || params.config.defaults.meeting;
460
+ const meeting = options.meeting?.trim() || context.config.defaults.meeting;
541
461
  if (!meeting) throw new Error("Meeting input is required. Pass --meeting, --today, --event, or configure defaults.meeting.");
542
462
  raw.meeting = meeting;
543
463
  }
544
464
  const resolved = await resolveMeetingFromParams({
545
- config: params.config,
465
+ config: context.config,
546
466
  raw,
547
467
  accessToken: token.accessToken
548
468
  });
@@ -565,8 +485,8 @@ function registerGoogleMeetApiCommands(context) {
565
485
  writeLatestConferenceRecordSummary(result);
566
486
  writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
567
487
  });
568
- root.command("calendar-events").description("Preview Calendar events with Google Meet links").option("--today", "Find Meet links on today's calendar").option("--event <query>", "Find matching calendar events with Meet links").option("--calendar <id>", "Calendar id for lookup", "primary").option("--access-token <token>", "Access token override").option("--refresh-token <token>", "Refresh token override").option("--client-id <id>", "OAuth client id override").option("--client-secret <secret>", "OAuth client secret override").option("--expires-at <ms>", "Cached access token expiry as unix epoch milliseconds").option("--json", "Print JSON output", false).action(async (options) => {
569
- const token = await resolveGoogleMeetTokenFromParams(params.config, resolveCliParams(options));
488
+ addGoogleMeetOAuthOptions(root.command("calendar-events").description("Preview Calendar events with Google Meet links").option("--today", "Find Meet links on today's calendar").option("--event <query>", "Find matching calendar events with Meet links").option("--calendar <id>", "Calendar id for lookup", "primary")).option("--json", "Print JSON output", false).action(async (options) => {
489
+ const token = await resolveGoogleMeetTokenFromParams(context.config, resolveCliParams(options));
570
490
  const window = options.today ? buildGoogleMeetCalendarDayWindow() : {};
571
491
  const result = await listGoogleMeetCalendarEvents({
572
492
  accessToken: token.accessToken,