@openclaw/google-meet 2026.9.7 → 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.
- package/dist/.setup/{chrome-create-wuAK5Pnq.mjs → chrome-create-Bh1L33pr.mjs} +20 -57
- package/dist/.setup/{cli-DVDq0TFu.mjs → cli-Bfm5LpNM.mjs} +63 -143
- package/dist/.setup/{cli-export-D4IM6KLJ.mjs → cli-export-BOebaVFW.mjs} +52 -57
- package/dist/.setup/{create-UrHOmnWb.mjs → create-DyYbmN11.mjs} +3 -3
- package/dist/.setup/google-api-DEZ9mWx7.mjs +50 -0
- package/dist/.setup/{google-meet-platform-adapter-gosgbMIM.mjs → google-meet-platform-adapter-CKXMbP3X.mjs} +1 -1
- package/dist/.setup/{node-host-Tr7Mx3da.mjs → node-host-CyFclhO_.mjs} +1 -1
- package/dist/.setup/{node-invoke-policy-Dd3krTYV.mjs → node-invoke-policy-BnX3PaH7.mjs} +3 -4
- package/dist/.setup/{oauth-BoyruWcS.mjs → oauth-XgdPFWEJ.mjs} +1 -1
- package/dist/.setup/{plugin-helpers-CdQ_YNA7.mjs → plugin-helpers-D1OyyzEZ.mjs} +85 -201
- package/dist/.setup/{plugin-registration-aCEuCerg.mjs → plugin-registration-BP83dqMw.mjs} +23 -31
- package/dist/.setup/{runtime-BdiF53A2.mjs → runtime-DQgxZ2Na.mjs} +16 -67
- package/dist/index.js +4 -4
- package/package.json +4 -4
|
@@ -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
|
|
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
|
|
201
|
+
await callBrowserProxyOnNode({
|
|
241
202
|
runtime: params.runtime,
|
|
242
203
|
nodeId,
|
|
243
|
-
|
|
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-
|
|
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
|
|
4
|
-
import { buildGoogleMeetAuthUrl, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-
|
|
5
|
-
import { n as hasCreateSpaceConfigInput, r as resolveCreateSpaceConfig } from "./create-
|
|
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(
|
|
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 =
|
|
49
|
-
else if (!options.format || options.format === "summary") text = `${
|
|
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(
|
|
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 =
|
|
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 = `${
|
|
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(
|
|
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
|
|
201
|
-
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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(
|
|
258
|
+
url: resolveMeetingInput(context.config, url),
|
|
279
259
|
transport: parseGoogleMeetBrowserTransport(options.transport),
|
|
280
260
|
timeoutMs: parsePositiveNumber(options.timeoutMs, "timeout-ms")
|
|
281
261
|
};
|
|
282
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
390
|
+
const token = await resolveGoogleMeetTokenFromParams(context.config, resolveCliParams(options));
|
|
470
391
|
const result = await endGoogleMeetActiveConference({
|
|
471
392
|
accessToken: token.accessToken,
|
|
472
|
-
meeting: resolveMeetingInput(
|
|
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(
|
|
491
|
-
const { space, token } = await resolveSpaceFromParams(
|
|
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(
|
|
508
|
-
const { space, token } = await resolveSpaceFromParams(
|
|
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:
|
|
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(
|
|
458
|
+
const token = await resolveGoogleMeetTokenFromParams(context.config, raw);
|
|
539
459
|
if (!options.today && !options.event?.trim()) {
|
|
540
|
-
const meeting = options.meeting?.trim() ||
|
|
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:
|
|
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")
|
|
569
|
-
const token = await resolveGoogleMeetTokenFromParams(
|
|
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,
|