@openclaw/google-meet 2026.7.2-beta.7 → 2026.7.33
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/{chrome-create-DMKruRFW.js → .setup/chrome-create-CFNlY-qH.mjs} +153 -132
- package/dist/{cli-DCcRyaMf.js → .setup/cli-DfOl5mwt.mjs} +707 -716
- package/dist/{config-BcaS1BDr.js → .setup/config-DeJhjNWQ.mjs} +95 -76
- package/dist/{create-af1MDlus.js → .setup/create-BVsTTJt1.mjs} +3 -21
- package/dist/{google-api-errors-CDUYkIcK.js → .setup/google-api-errors-BDYXfKRa.mjs} +1 -1
- package/dist/{oauth-DOfMKlGp.js → .setup/oauth-CtVbvmvR.mjs} +4 -3
- package/dist/doctor-contract-api.js +3 -1
- package/dist/index.js +3868 -1818
- package/node_modules/{jszip/node_modules/setimmediate/LICENSE.txt → commander/LICENSE} +10 -8
- package/node_modules/commander/Readme.md +1172 -0
- package/node_modules/commander/index.js +21 -0
- package/node_modules/commander/lib/argument.js +147 -0
- package/node_modules/commander/lib/command.js +2790 -0
- package/node_modules/commander/lib/error.js +36 -0
- package/node_modules/commander/lib/help.js +731 -0
- package/node_modules/commander/lib/option.js +377 -0
- package/node_modules/commander/lib/suggestSimilar.js +99 -0
- package/node_modules/commander/package-support.json +19 -0
- package/node_modules/commander/package.json +64 -0
- package/node_modules/commander/typings/index.d.ts +1113 -0
- package/node_modules/typebox/build/compile/validator.d.mts +4 -1
- package/node_modules/typebox/build/guard/guard.d.mts +1 -1
- package/node_modules/typebox/build/guard/guard.mjs +2 -5
- package/node_modules/typebox/build/guard/string.mjs +4 -16
- package/node_modules/typebox/build/schema/engine/_functions.mjs +15 -34
- package/node_modules/typebox/build/type/action/readonly_object.d.mts +0 -5
- package/node_modules/typebox/build/type/action/readonly_object.mjs +0 -8
- package/node_modules/typebox/build/typebox.d.mts +1 -1
- package/node_modules/typebox/build/typebox.mjs +1 -1
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +32 -29
- package/openclaw.plugin.json +3 -4
- package/package.json +7 -9
- package/dist/cli-metadata.js +0 -13
- package/dist/cli-output-mode-BwH_6tH8.js +0 -28
- package/node_modules/jszip/.codeclimate.yml +0 -16
- package/node_modules/jszip/.editorconfig +0 -8
- package/node_modules/jszip/.eslintrc.js +0 -43
- package/node_modules/jszip/.github/workflows/pr.yaml +0 -58
- package/node_modules/jszip/.jekyll-metadata +0 -0
- package/node_modules/jszip/.travis.yml +0 -17
- package/node_modules/jszip/CHANGES.md +0 -204
- package/node_modules/jszip/LICENSE.markdown +0 -651
- package/node_modules/jszip/README.markdown +0 -33
- package/node_modules/jszip/deps.js +0 -37
- package/node_modules/jszip/dist/jszip.js +0 -11577
- package/node_modules/jszip/dist/jszip.min.js +0 -13
- package/node_modules/jszip/graph.svg +0 -601
- package/node_modules/jszip/index.d.ts +0 -330
- package/node_modules/jszip/lib/base64.js +0 -106
- package/node_modules/jszip/lib/compressedObject.js +0 -74
- package/node_modules/jszip/lib/compressions.js +0 -14
- package/node_modules/jszip/lib/crc32.js +0 -77
- package/node_modules/jszip/lib/defaults.js +0 -11
- package/node_modules/jszip/lib/external.js +0 -18
- package/node_modules/jszip/lib/flate.js +0 -85
- package/node_modules/jszip/lib/generate/ZipFileWorker.js +0 -539
- package/node_modules/jszip/lib/generate/index.js +0 -57
- package/node_modules/jszip/lib/index.js +0 -55
- package/node_modules/jszip/lib/license_header.js +0 -11
- package/node_modules/jszip/lib/load.js +0 -88
- package/node_modules/jszip/lib/nodejs/NodejsStreamInputAdapter.js +0 -74
- package/node_modules/jszip/lib/nodejs/NodejsStreamOutputAdapter.js +0 -42
- package/node_modules/jszip/lib/nodejsUtils.js +0 -57
- package/node_modules/jszip/lib/object.js +0 -384
- package/node_modules/jszip/lib/readable-stream-browser.js +0 -10
- package/node_modules/jszip/lib/reader/ArrayReader.js +0 -57
- package/node_modules/jszip/lib/reader/DataReader.js +0 -116
- package/node_modules/jszip/lib/reader/NodeBufferReader.js +0 -19
- package/node_modules/jszip/lib/reader/StringReader.js +0 -38
- package/node_modules/jszip/lib/reader/Uint8ArrayReader.js +0 -22
- package/node_modules/jszip/lib/reader/readerFor.js +0 -28
- package/node_modules/jszip/lib/signature.js +0 -7
- package/node_modules/jszip/lib/stream/ConvertWorker.js +0 -26
- package/node_modules/jszip/lib/stream/Crc32Probe.js +0 -24
- package/node_modules/jszip/lib/stream/DataLengthProbe.js +0 -29
- package/node_modules/jszip/lib/stream/DataWorker.js +0 -116
- package/node_modules/jszip/lib/stream/GenericWorker.js +0 -263
- package/node_modules/jszip/lib/stream/StreamHelper.js +0 -214
- package/node_modules/jszip/lib/support.js +0 -38
- package/node_modules/jszip/lib/utf8.js +0 -275
- package/node_modules/jszip/lib/utils.js +0 -501
- package/node_modules/jszip/lib/zipEntries.js +0 -261
- package/node_modules/jszip/lib/zipEntry.js +0 -293
- package/node_modules/jszip/lib/zipObject.js +0 -133
- package/node_modules/jszip/node_modules/core-util-is/LICENSE +0 -19
- package/node_modules/jszip/node_modules/core-util-is/README.md +0 -3
- package/node_modules/jszip/node_modules/core-util-is/lib/util.js +0 -107
- package/node_modules/jszip/node_modules/core-util-is/package.json +0 -38
- package/node_modules/jszip/node_modules/immediate/LICENSE.txt +0 -20
- package/node_modules/jszip/node_modules/immediate/README.md +0 -93
- package/node_modules/jszip/node_modules/immediate/dist/immediate.js +0 -75
- package/node_modules/jszip/node_modules/immediate/dist/immediate.min.js +0 -1
- package/node_modules/jszip/node_modules/immediate/lib/browser.js +0 -69
- package/node_modules/jszip/node_modules/immediate/lib/index.js +0 -73
- package/node_modules/jszip/node_modules/immediate/package.json +0 -42
- package/node_modules/jszip/node_modules/inherits/LICENSE +0 -16
- package/node_modules/jszip/node_modules/inherits/README.md +0 -42
- package/node_modules/jszip/node_modules/inherits/inherits.js +0 -9
- package/node_modules/jszip/node_modules/inherits/inherits_browser.js +0 -27
- package/node_modules/jszip/node_modules/inherits/package.json +0 -29
- package/node_modules/jszip/node_modules/isarray/.npmignore +0 -1
- package/node_modules/jszip/node_modules/isarray/.travis.yml +0 -4
- package/node_modules/jszip/node_modules/isarray/Makefile +0 -6
- package/node_modules/jszip/node_modules/isarray/README.md +0 -60
- package/node_modules/jszip/node_modules/isarray/component.json +0 -19
- package/node_modules/jszip/node_modules/isarray/index.js +0 -5
- package/node_modules/jszip/node_modules/isarray/package.json +0 -45
- package/node_modules/jszip/node_modules/isarray/test.js +0 -20
- package/node_modules/jszip/node_modules/lie/README.md +0 -62
- package/node_modules/jszip/node_modules/lie/dist/lie.js +0 -350
- package/node_modules/jszip/node_modules/lie/dist/lie.min.js +0 -1
- package/node_modules/jszip/node_modules/lie/dist/lie.polyfill.js +0 -358
- package/node_modules/jszip/node_modules/lie/dist/lie.polyfill.min.js +0 -1
- package/node_modules/jszip/node_modules/lie/lib/browser.js +0 -273
- package/node_modules/jszip/node_modules/lie/lib/index.js +0 -298
- package/node_modules/jszip/node_modules/lie/license.md +0 -7
- package/node_modules/jszip/node_modules/lie/lie.d.ts +0 -244
- package/node_modules/jszip/node_modules/lie/package.json +0 -69
- package/node_modules/jszip/node_modules/lie/polyfill.js +0 -4
- package/node_modules/jszip/node_modules/pako/CHANGELOG.md +0 -164
- package/node_modules/jszip/node_modules/pako/LICENSE +0 -21
- package/node_modules/jszip/node_modules/pako/README.md +0 -191
- package/node_modules/jszip/node_modules/pako/dist/pako.js +0 -6818
- package/node_modules/jszip/node_modules/pako/dist/pako.min.js +0 -1
- package/node_modules/jszip/node_modules/pako/dist/pako_deflate.js +0 -3997
- package/node_modules/jszip/node_modules/pako/dist/pako_deflate.min.js +0 -1
- package/node_modules/jszip/node_modules/pako/dist/pako_inflate.js +0 -3300
- package/node_modules/jszip/node_modules/pako/dist/pako_inflate.min.js +0 -1
- package/node_modules/jszip/node_modules/pako/index.js +0 -14
- package/node_modules/jszip/node_modules/pako/lib/deflate.js +0 -400
- package/node_modules/jszip/node_modules/pako/lib/inflate.js +0 -423
- package/node_modules/jszip/node_modules/pako/lib/utils/common.js +0 -105
- package/node_modules/jszip/node_modules/pako/lib/utils/strings.js +0 -187
- package/node_modules/jszip/node_modules/pako/lib/zlib/README +0 -59
- package/node_modules/jszip/node_modules/pako/lib/zlib/adler32.js +0 -51
- package/node_modules/jszip/node_modules/pako/lib/zlib/constants.js +0 -68
- package/node_modules/jszip/node_modules/pako/lib/zlib/crc32.js +0 -59
- package/node_modules/jszip/node_modules/pako/lib/zlib/deflate.js +0 -1874
- package/node_modules/jszip/node_modules/pako/lib/zlib/gzheader.js +0 -58
- package/node_modules/jszip/node_modules/pako/lib/zlib/inffast.js +0 -345
- package/node_modules/jszip/node_modules/pako/lib/zlib/inflate.js +0 -1556
- package/node_modules/jszip/node_modules/pako/lib/zlib/inftrees.js +0 -343
- package/node_modules/jszip/node_modules/pako/lib/zlib/messages.js +0 -32
- package/node_modules/jszip/node_modules/pako/lib/zlib/trees.js +0 -1222
- package/node_modules/jszip/node_modules/pako/lib/zlib/zstream.js +0 -47
- package/node_modules/jszip/node_modules/pako/package.json +0 -44
- package/node_modules/jszip/node_modules/process-nextick-args/index.js +0 -45
- package/node_modules/jszip/node_modules/process-nextick-args/license.md +0 -19
- package/node_modules/jszip/node_modules/process-nextick-args/package.json +0 -25
- package/node_modules/jszip/node_modules/process-nextick-args/readme.md +0 -18
- package/node_modules/jszip/node_modules/readable-stream/.travis.yml +0 -34
- package/node_modules/jszip/node_modules/readable-stream/CONTRIBUTING.md +0 -38
- package/node_modules/jszip/node_modules/readable-stream/GOVERNANCE.md +0 -136
- package/node_modules/jszip/node_modules/readable-stream/LICENSE +0 -47
- package/node_modules/jszip/node_modules/readable-stream/README.md +0 -58
- package/node_modules/jszip/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md +0 -60
- package/node_modules/jszip/node_modules/readable-stream/duplex-browser.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/duplex.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/lib/_stream_duplex.js +0 -131
- package/node_modules/jszip/node_modules/readable-stream/lib/_stream_passthrough.js +0 -47
- package/node_modules/jszip/node_modules/readable-stream/lib/_stream_readable.js +0 -1019
- package/node_modules/jszip/node_modules/readable-stream/lib/_stream_transform.js +0 -214
- package/node_modules/jszip/node_modules/readable-stream/lib/_stream_writable.js +0 -685
- package/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/BufferList.js +0 -78
- package/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/destroy.js +0 -84
- package/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/stream-browser.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/stream.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/package.json +0 -52
- package/node_modules/jszip/node_modules/readable-stream/passthrough.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/readable-browser.js +0 -7
- package/node_modules/jszip/node_modules/readable-stream/readable.js +0 -19
- package/node_modules/jszip/node_modules/readable-stream/transform.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/writable-browser.js +0 -1
- package/node_modules/jszip/node_modules/readable-stream/writable.js +0 -8
- package/node_modules/jszip/node_modules/safe-buffer/LICENSE +0 -21
- package/node_modules/jszip/node_modules/safe-buffer/README.md +0 -584
- package/node_modules/jszip/node_modules/safe-buffer/index.d.ts +0 -187
- package/node_modules/jszip/node_modules/safe-buffer/index.js +0 -62
- package/node_modules/jszip/node_modules/safe-buffer/package.json +0 -37
- package/node_modules/jszip/node_modules/setimmediate/package.json +0 -30
- package/node_modules/jszip/node_modules/setimmediate/setImmediate.js +0 -186
- package/node_modules/jszip/node_modules/string_decoder/.travis.yml +0 -50
- package/node_modules/jszip/node_modules/string_decoder/LICENSE +0 -48
- package/node_modules/jszip/node_modules/string_decoder/README.md +0 -47
- package/node_modules/jszip/node_modules/string_decoder/lib/string_decoder.js +0 -296
- package/node_modules/jszip/node_modules/string_decoder/package.json +0 -31
- package/node_modules/jszip/node_modules/util-deprecate/History.md +0 -16
- package/node_modules/jszip/node_modules/util-deprecate/LICENSE +0 -24
- package/node_modules/jszip/node_modules/util-deprecate/README.md +0 -53
- package/node_modules/jszip/node_modules/util-deprecate/browser.js +0 -67
- package/node_modules/jszip/node_modules/util-deprecate/node.js +0 -6
- package/node_modules/jszip/node_modules/util-deprecate/package.json +0 -27
- package/node_modules/jszip/package.json +0 -67
- package/node_modules/jszip/sponsors.md +0 -21
- package/node_modules/jszip/tsconfig.json +0 -101
- package/node_modules/jszip/vendor/FileSaver.js +0 -247
- package/node_modules/pretty-ms/index.d.ts +0 -157
- package/node_modules/pretty-ms/index.js +0 -149
- package/node_modules/pretty-ms/license +0 -9
- package/node_modules/pretty-ms/node_modules/parse-ms/index.d.ts +0 -30
- package/node_modules/pretty-ms/node_modules/parse-ms/index.js +0 -45
- package/node_modules/pretty-ms/node_modules/parse-ms/license +0 -9
- package/node_modules/pretty-ms/node_modules/parse-ms/package.json +0 -47
- package/node_modules/pretty-ms/node_modules/parse-ms/readme.md +0 -46
- package/node_modules/pretty-ms/package.json +0 -55
- package/node_modules/pretty-ms/readme.md +0 -179
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
|
|
6
|
-
import { clampTimerTimeoutMs, parseStrictNonNegativeInteger, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
1
|
+
import { a as buildGoogleMeetCalendarDayWindow, i as resolveGoogleMeetGatewayOperationTimeoutMs, o as findGoogleMeetCalendarEvent, s as listGoogleMeetCalendarEvents } from "./config-DeJhjNWQ.mjs";
|
|
2
|
+
import { _ as fetchLatestGoogleMeetConferenceRecord, d as buildGoogleMeetPreflightReport, f as createGoogleMeetSpace, g as fetchGoogleMeetSpace, h as fetchGoogleMeetAttendance, m as fetchGoogleMeetArtifacts, p as endGoogleMeetActiveConference } from "./chrome-create-CFNlY-qH.mjs";
|
|
3
|
+
import { buildGoogleMeetAuthUrl, createGoogleMeetOAuthState, createGoogleMeetPkce, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-CtVbvmvR.mjs";
|
|
4
|
+
import { hasCreateSpaceConfigInput, resolveCreateSpaceConfig } from "./create-BVsTTJt1.mjs";
|
|
7
5
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
6
|
+
import { callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
|
|
7
|
+
import { clampTimerTimeoutMs, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
10
|
-
import JSZip from "jszip";
|
|
11
10
|
import { createInterface } from "node:readline/promises";
|
|
12
11
|
import { format } from "node:util";
|
|
13
|
-
|
|
14
|
-
//#region extensions/google-meet/src/cli-shared.ts
|
|
12
|
+
//#region extensions/google-meet/src/cli.ts
|
|
15
13
|
const testing = {
|
|
16
14
|
parsePositiveNumber,
|
|
17
15
|
resolveGoogleMeetGatewayOperationTimeoutMs,
|
|
@@ -105,7 +103,11 @@ async function callGoogleMeetGateway(params) {
|
|
|
105
103
|
}
|
|
106
104
|
function formatDuration(value) {
|
|
107
105
|
if (value === void 0) return "n/a";
|
|
108
|
-
|
|
106
|
+
const totalSeconds = Math.round(value / 1e3);
|
|
107
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
108
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
109
|
+
const seconds = totalSeconds % 60;
|
|
110
|
+
return hours > 0 ? `${hours}h ${minutes.toString().padStart(2, "0")}m` : `${minutes}m ${seconds.toString().padStart(2, "0")}s`;
|
|
109
111
|
}
|
|
110
112
|
function writeDoctorStatus(status) {
|
|
111
113
|
if (!status.found) {
|
|
@@ -143,10 +145,10 @@ function writeDoctorStatus(status) {
|
|
|
143
145
|
writeStdoutLine("captioning: %s", formatBoolean(health?.captioning));
|
|
144
146
|
writeStdoutLine("transcript lines: %s", health?.transcriptLines ?? 0);
|
|
145
147
|
writeStdoutLine("last caption: %s", formatOptional(health?.lastCaptionAt));
|
|
146
|
-
writeStdoutLine("manual action: %s", formatBoolean(
|
|
147
|
-
if (health?.
|
|
148
|
-
writeStdoutLine("manual reason: %s", formatOptional(health.
|
|
149
|
-
writeStdoutLine("manual message: %s", formatOptional(health.
|
|
148
|
+
writeStdoutLine("manual action: %s", formatBoolean(health?.manualActionRequired));
|
|
149
|
+
if (health?.manualActionRequired) {
|
|
150
|
+
writeStdoutLine("manual reason: %s", formatOptional(health.manualActionReason));
|
|
151
|
+
writeStdoutLine("manual message: %s", formatOptional(health.manualActionMessage));
|
|
150
152
|
}
|
|
151
153
|
writeStdoutLine("speech ready: %s", formatBoolean(health?.speechReady));
|
|
152
154
|
if (health?.speechReady === false) {
|
|
@@ -175,6 +177,112 @@ function writeDoctorStatus(status) {
|
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
179
|
}
|
|
180
|
+
function sanitizeOAuthErrorMessage(error) {
|
|
181
|
+
return (error instanceof Error ? error.message : String(error)).replace(/(access_token["'=:\s]+)[^"',\s&]+/gi, "$1[redacted]").replace(/(refresh_token["'=:\s]+)[^"',\s&]+/gi, "$1[redacted]").replace(/(client_secret["'=:\s]+)[^"',\s&]+/gi, "$1[redacted]");
|
|
182
|
+
}
|
|
183
|
+
async function buildOAuthDoctorReport(config, options) {
|
|
184
|
+
const clientId = options.clientId?.trim() || config.oauth.clientId;
|
|
185
|
+
const clientSecret = options.clientSecret?.trim() || config.oauth.clientSecret;
|
|
186
|
+
const refreshToken = options.refreshToken?.trim() || config.oauth.refreshToken;
|
|
187
|
+
const accessToken = options.accessToken?.trim() || config.oauth.accessToken;
|
|
188
|
+
const expiresAt = parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt;
|
|
189
|
+
const checks = [];
|
|
190
|
+
const hasRefreshConfig = Boolean(clientId && refreshToken);
|
|
191
|
+
if (!hasRefreshConfig && !Boolean(accessToken)) {
|
|
192
|
+
checks.push({
|
|
193
|
+
id: "oauth-config",
|
|
194
|
+
ok: false,
|
|
195
|
+
message: "Missing Google Meet OAuth credentials. Configure oauth.clientId and oauth.refreshToken, or pass --client-id and --refresh-token."
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
configured: false,
|
|
200
|
+
checks
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
checks.push({
|
|
204
|
+
id: "oauth-config",
|
|
205
|
+
ok: true,
|
|
206
|
+
message: hasRefreshConfig ? "Google Meet OAuth refresh credentials are configured" : "Google Meet cached access token is configured"
|
|
207
|
+
});
|
|
208
|
+
let token;
|
|
209
|
+
try {
|
|
210
|
+
token = await resolveGoogleMeetAccessToken({
|
|
211
|
+
clientId,
|
|
212
|
+
clientSecret,
|
|
213
|
+
refreshToken,
|
|
214
|
+
accessToken,
|
|
215
|
+
expiresAt
|
|
216
|
+
});
|
|
217
|
+
checks.push({
|
|
218
|
+
id: "oauth-token",
|
|
219
|
+
ok: true,
|
|
220
|
+
message: token.refreshed ? "Refresh token minted an access token" : "Cached access token is still valid"
|
|
221
|
+
});
|
|
222
|
+
} catch (error) {
|
|
223
|
+
checks.push({
|
|
224
|
+
id: "oauth-token",
|
|
225
|
+
ok: false,
|
|
226
|
+
message: sanitizeOAuthErrorMessage(error)
|
|
227
|
+
});
|
|
228
|
+
return {
|
|
229
|
+
ok: false,
|
|
230
|
+
configured: true,
|
|
231
|
+
checks
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const report = {
|
|
235
|
+
ok: true,
|
|
236
|
+
configured: true,
|
|
237
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
238
|
+
expiresAt: token.expiresAt,
|
|
239
|
+
checks
|
|
240
|
+
};
|
|
241
|
+
const meeting = options.meeting?.trim();
|
|
242
|
+
if (meeting) try {
|
|
243
|
+
const space = await fetchGoogleMeetSpace({
|
|
244
|
+
accessToken: token.accessToken,
|
|
245
|
+
meeting
|
|
246
|
+
});
|
|
247
|
+
checks.push({
|
|
248
|
+
id: "meet-spaces-get",
|
|
249
|
+
ok: true,
|
|
250
|
+
message: `Resolved ${space.name}`
|
|
251
|
+
});
|
|
252
|
+
report.meetingUri = space.meetingUri;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
checks.push({
|
|
255
|
+
id: "meet-spaces-get",
|
|
256
|
+
ok: false,
|
|
257
|
+
message: sanitizeOAuthErrorMessage(error)
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
if (options.createSpace) try {
|
|
261
|
+
const created = await createGoogleMeetSpace({ accessToken: token.accessToken });
|
|
262
|
+
checks.push({
|
|
263
|
+
id: "meet-spaces-create",
|
|
264
|
+
ok: true,
|
|
265
|
+
message: `Created ${created.space.name}`
|
|
266
|
+
});
|
|
267
|
+
report.createdSpace = created.space.name;
|
|
268
|
+
report.meetingUri = created.meetingUri;
|
|
269
|
+
} catch (error) {
|
|
270
|
+
checks.push({
|
|
271
|
+
id: "meet-spaces-create",
|
|
272
|
+
ok: false,
|
|
273
|
+
message: sanitizeOAuthErrorMessage(error)
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
report.ok = checks.every((check) => check.ok);
|
|
277
|
+
return report;
|
|
278
|
+
}
|
|
279
|
+
function writeOAuthDoctorReport(report) {
|
|
280
|
+
writeStdoutLine("Google Meet OAuth: %s", report.ok ? "OK" : "needs attention");
|
|
281
|
+
writeStdoutLine("configured: %s", report.configured ? "yes" : "no");
|
|
282
|
+
if (report.tokenSource) writeStdoutLine("token source: %s", report.tokenSource);
|
|
283
|
+
if (report.meetingUri) writeStdoutLine("meeting uri: %s", report.meetingUri);
|
|
284
|
+
for (const check of report.checks) writeStdoutLine("[%s] %s: %s", check.ok ? "ok" : "fail", check.id, check.message);
|
|
285
|
+
}
|
|
178
286
|
function writeRecoverCurrentTabResult(result) {
|
|
179
287
|
writeStdoutLine("Google Meet current tab: %s", result.found ? "found" : "not found");
|
|
180
288
|
writeStdoutLine("transport: %s", result.transport);
|
|
@@ -208,15 +316,88 @@ function writeRecoverCurrentTabResult(result) {
|
|
|
208
316
|
}
|
|
209
317
|
});
|
|
210
318
|
}
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
319
|
+
function resolveMeetingInput(config, value) {
|
|
320
|
+
const meeting = value?.trim() || config.defaults.meeting;
|
|
321
|
+
if (!meeting) throw new Error("Meeting input is required. Pass a URL/meeting code or configure defaults.meeting.");
|
|
322
|
+
return meeting;
|
|
323
|
+
}
|
|
324
|
+
function resolveOAuthTokenOptions(config, options) {
|
|
325
|
+
return {
|
|
326
|
+
clientId: options.clientId?.trim() || config.oauth.clientId,
|
|
327
|
+
clientSecret: options.clientSecret?.trim() || config.oauth.clientSecret,
|
|
328
|
+
refreshToken: options.refreshToken?.trim() || config.oauth.refreshToken,
|
|
329
|
+
accessToken: options.accessToken?.trim() || config.oauth.accessToken,
|
|
330
|
+
expiresAt: parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function resolveTokenOptions(config, options) {
|
|
334
|
+
return {
|
|
335
|
+
meeting: resolveMeetingInput(config, options.meeting),
|
|
336
|
+
...resolveOAuthTokenOptions(config, options)
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function hasCalendarLookupOptions(options) {
|
|
340
|
+
return Boolean(options.today || options.event?.trim());
|
|
341
|
+
}
|
|
342
|
+
async function resolveCalendarMeetingInput(params) {
|
|
343
|
+
if (!hasCalendarLookupOptions(params.options)) return {};
|
|
344
|
+
const window = params.options.today ? buildGoogleMeetCalendarDayWindow() : {};
|
|
345
|
+
const calendarEvent = await findGoogleMeetCalendarEvent({
|
|
346
|
+
accessToken: params.accessToken,
|
|
347
|
+
calendarId: params.options.calendar,
|
|
348
|
+
eventQuery: params.options.event,
|
|
349
|
+
...window
|
|
350
|
+
});
|
|
351
|
+
return {
|
|
352
|
+
meeting: calendarEvent.meetingUri,
|
|
353
|
+
calendarEvent
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
async function resolveMeetingForToken(params) {
|
|
357
|
+
const calendarMeeting = await resolveCalendarMeetingInput({
|
|
358
|
+
accessToken: params.accessToken,
|
|
359
|
+
options: params.options
|
|
360
|
+
});
|
|
361
|
+
const meeting = calendarMeeting.meeting ?? params.configuredMeeting ?? params.config.defaults.meeting;
|
|
362
|
+
if (!meeting) throw new Error("Meeting input is required. Pass --meeting, --today, --event, or configure defaults.meeting.");
|
|
363
|
+
return calendarMeeting.calendarEvent ? {
|
|
364
|
+
meeting,
|
|
365
|
+
calendarEvent: calendarMeeting.calendarEvent
|
|
366
|
+
} : { meeting };
|
|
367
|
+
}
|
|
368
|
+
function resolveCreateTokenOptions(config, options) {
|
|
369
|
+
return {
|
|
370
|
+
clientId: options.clientId?.trim() || config.oauth.clientId,
|
|
371
|
+
clientSecret: options.clientSecret?.trim() || config.oauth.clientSecret,
|
|
372
|
+
refreshToken: options.refreshToken?.trim() || config.oauth.refreshToken,
|
|
373
|
+
accessToken: options.accessToken?.trim() || config.oauth.accessToken,
|
|
374
|
+
expiresAt: parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function resolveArtifactTokenOptions(config, options) {
|
|
378
|
+
const meeting = options.meeting?.trim() || config.defaults.meeting;
|
|
379
|
+
const conferenceRecord = options.conferenceRecord?.trim();
|
|
380
|
+
if (!meeting && !conferenceRecord && !hasCalendarLookupOptions(options)) throw new Error("Meeting input or conference record is required. Pass --meeting, --today, --event, --conference-record, or configure defaults.meeting.");
|
|
381
|
+
return {
|
|
382
|
+
meeting,
|
|
383
|
+
conferenceRecord,
|
|
384
|
+
clientId: options.clientId?.trim() || config.oauth.clientId,
|
|
385
|
+
clientSecret: options.clientSecret?.trim() || config.oauth.clientSecret,
|
|
386
|
+
refreshToken: options.refreshToken?.trim() || config.oauth.refreshToken,
|
|
387
|
+
accessToken: options.accessToken?.trim() || config.oauth.accessToken,
|
|
388
|
+
expiresAt: parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt,
|
|
389
|
+
pageSize: parsePositiveIntegerOption(options.pageSize, "page-size"),
|
|
390
|
+
includeTranscriptEntries: options.transcriptEntries !== false,
|
|
391
|
+
allConferenceRecords: Boolean(options.allConferenceRecords),
|
|
392
|
+
includeDocumentBodies: Boolean(options.includeDocBodies),
|
|
393
|
+
mergeDuplicateParticipants: options.mergeDuplicates !== false,
|
|
394
|
+
lateAfterMinutes: parseOptionalNumber(options.lateAfterMinutes),
|
|
395
|
+
earlyBeforeMinutes: parseOptionalNumber(options.earlyBeforeMinutes)
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
function hasCreateOAuth(config, options) {
|
|
399
|
+
return Boolean(options.accessToken?.trim() || options.refreshToken?.trim() || config.oauth.accessToken || config.oauth.refreshToken);
|
|
217
400
|
}
|
|
218
|
-
//#endregion
|
|
219
|
-
//#region extensions/google-meet/src/cli-export.ts
|
|
220
401
|
function writeArtifactsSummary(result) {
|
|
221
402
|
if (result.input) writeStdoutLine("input: %s", result.input);
|
|
222
403
|
if (result.space) writeStdoutLine("space: %s", result.space.name);
|
|
@@ -392,12 +573,9 @@ function renderAttendanceMarkdown(result) {
|
|
|
392
573
|
}
|
|
393
574
|
return `${lines.join("\n")}\n`;
|
|
394
575
|
}
|
|
395
|
-
function neutralizeSpreadsheetFormulaCell(text) {
|
|
396
|
-
return /^[ \t\r\n]*[=+\-@\uFF0B\uFF0D\uFF1D\uFF20]/u.test(text) || /^[\t\r\n]/.test(text) ? `'${text}` : text;
|
|
397
|
-
}
|
|
398
576
|
function csvCell(value) {
|
|
399
|
-
const
|
|
400
|
-
return /[",\
|
|
577
|
+
const text = value === void 0 || value === null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
|
|
578
|
+
return /[",\n]/.test(text) ? `"${text.replaceAll("\"", "\"\"")}"` : text;
|
|
401
579
|
}
|
|
402
580
|
function renderAttendanceCsv(result) {
|
|
403
581
|
const rows = [[
|
|
@@ -543,6 +721,81 @@ function googleMeetExportFileNames() {
|
|
|
543
721
|
function defaultExportDirectory() {
|
|
544
722
|
return `google-meet-export-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
545
723
|
}
|
|
724
|
+
const CRC32_TABLE = new Uint32Array(Array.from({ length: 256 }, (_, index) => {
|
|
725
|
+
let value = index;
|
|
726
|
+
for (let bit = 0; bit < 8; bit += 1) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
|
|
727
|
+
return value >>> 0;
|
|
728
|
+
}));
|
|
729
|
+
function crc32(buffer) {
|
|
730
|
+
let value = 4294967295;
|
|
731
|
+
for (const byte of buffer) value = CRC32_TABLE[(value ^ byte) & 255] ^ value >>> 8;
|
|
732
|
+
return (value ^ 4294967295) >>> 0;
|
|
733
|
+
}
|
|
734
|
+
function dosDateTime(date = /* @__PURE__ */ new Date()) {
|
|
735
|
+
return {
|
|
736
|
+
time: date.getHours() << 11 | date.getMinutes() << 5 | Math.floor(date.getSeconds() / 2),
|
|
737
|
+
date: date.getFullYear() - 1980 << 9 | date.getMonth() + 1 << 5 | date.getDate()
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function buildZipArchive(files) {
|
|
741
|
+
const localParts = [];
|
|
742
|
+
const centralParts = [];
|
|
743
|
+
let offset = 0;
|
|
744
|
+
const stamp = dosDateTime();
|
|
745
|
+
for (const file of files) {
|
|
746
|
+
const name = Buffer.from(file.name, "utf8");
|
|
747
|
+
const content = Buffer.from(file.content, "utf8");
|
|
748
|
+
const checksum = crc32(content);
|
|
749
|
+
const local = Buffer.alloc(30);
|
|
750
|
+
local.writeUInt32LE(67324752, 0);
|
|
751
|
+
local.writeUInt16LE(20, 4);
|
|
752
|
+
local.writeUInt16LE(0, 6);
|
|
753
|
+
local.writeUInt16LE(0, 8);
|
|
754
|
+
local.writeUInt16LE(stamp.time, 10);
|
|
755
|
+
local.writeUInt16LE(stamp.date, 12);
|
|
756
|
+
local.writeUInt32LE(checksum, 14);
|
|
757
|
+
local.writeUInt32LE(content.length, 18);
|
|
758
|
+
local.writeUInt32LE(content.length, 22);
|
|
759
|
+
local.writeUInt16LE(name.length, 26);
|
|
760
|
+
local.writeUInt16LE(0, 28);
|
|
761
|
+
localParts.push(local, name, content);
|
|
762
|
+
const central = Buffer.alloc(46);
|
|
763
|
+
central.writeUInt32LE(33639248, 0);
|
|
764
|
+
central.writeUInt16LE(20, 4);
|
|
765
|
+
central.writeUInt16LE(20, 6);
|
|
766
|
+
central.writeUInt16LE(0, 8);
|
|
767
|
+
central.writeUInt16LE(0, 10);
|
|
768
|
+
central.writeUInt16LE(stamp.time, 12);
|
|
769
|
+
central.writeUInt16LE(stamp.date, 14);
|
|
770
|
+
central.writeUInt32LE(checksum, 16);
|
|
771
|
+
central.writeUInt32LE(content.length, 20);
|
|
772
|
+
central.writeUInt32LE(content.length, 24);
|
|
773
|
+
central.writeUInt16LE(name.length, 28);
|
|
774
|
+
central.writeUInt16LE(0, 30);
|
|
775
|
+
central.writeUInt16LE(0, 32);
|
|
776
|
+
central.writeUInt16LE(0, 34);
|
|
777
|
+
central.writeUInt16LE(0, 36);
|
|
778
|
+
central.writeUInt32LE(0, 38);
|
|
779
|
+
central.writeUInt32LE(offset, 42);
|
|
780
|
+
centralParts.push(central, name);
|
|
781
|
+
offset += local.length + name.length + content.length;
|
|
782
|
+
}
|
|
783
|
+
const centralDirectory = Buffer.concat(centralParts);
|
|
784
|
+
const end = Buffer.alloc(22);
|
|
785
|
+
end.writeUInt32LE(101010256, 0);
|
|
786
|
+
end.writeUInt16LE(0, 4);
|
|
787
|
+
end.writeUInt16LE(0, 6);
|
|
788
|
+
end.writeUInt16LE(files.length, 8);
|
|
789
|
+
end.writeUInt16LE(files.length, 10);
|
|
790
|
+
end.writeUInt32LE(centralDirectory.length, 12);
|
|
791
|
+
end.writeUInt32LE(offset, 16);
|
|
792
|
+
end.writeUInt16LE(0, 20);
|
|
793
|
+
return Buffer.concat([
|
|
794
|
+
...localParts,
|
|
795
|
+
centralDirectory,
|
|
796
|
+
end
|
|
797
|
+
]);
|
|
798
|
+
}
|
|
546
799
|
async function writeMeetExportBundle(params) {
|
|
547
800
|
const outputDir = params.outputDir?.trim() || defaultExportDirectory();
|
|
548
801
|
await mkdir(outputDir, { recursive: true });
|
|
@@ -588,319 +841,163 @@ async function writeMeetExportBundle(params) {
|
|
|
588
841
|
files: files.map((file) => path.join(outputDir, file.name))
|
|
589
842
|
};
|
|
590
843
|
if (zipFile) {
|
|
591
|
-
|
|
592
|
-
for (const file of files) zip.file(file.name, file.content);
|
|
593
|
-
await writeFile(zipFile, await zip.generateAsync({ type: "nodebuffer" }));
|
|
844
|
+
await writeFile(zipFile, buildZipArchive(files));
|
|
594
845
|
result.zipFile = zipFile;
|
|
595
846
|
}
|
|
596
847
|
return result;
|
|
597
848
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
const result = await fetchGoogleMeetArtifacts({
|
|
613
|
-
accessToken: token.accessToken,
|
|
614
|
-
meeting,
|
|
615
|
-
conferenceRecord: resolved.conferenceRecord,
|
|
616
|
-
pageSize: resolved.pageSize,
|
|
617
|
-
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
|
618
|
-
allConferenceRecords: resolved.allConferenceRecords,
|
|
619
|
-
includeDocumentBodies: resolved.includeDocumentBodies
|
|
849
|
+
function registerGoogleMeetCli(params) {
|
|
850
|
+
const callGateway = params.callGatewayFromCli ?? callGatewayFromCli;
|
|
851
|
+
const operationTimeoutMs = resolveGoogleMeetGatewayOperationTimeoutMs(params.config);
|
|
852
|
+
const root = params.program.command("googlemeet").description("Google Meet participant utilities").addHelpText("after", () => `\nDocs: https://docs.openclaw.ai/plugins/google-meet\n`);
|
|
853
|
+
root.command("auth").description("Google Meet OAuth helpers").command("login").description("Run a PKCE OAuth flow and print refresh-token JSON to store in plugin config").option("--client-id <id>", "OAuth client id override").option("--client-secret <secret>", "OAuth client secret override").option("--manual", "Use copy/paste callback flow instead of localhost callback").option("--json", "Print the token payload as JSON", false).option("--timeout-sec <n>", "Local callback timeout in seconds", "300").action(async (options) => {
|
|
854
|
+
const clientId = options.clientId?.trim() || params.config.oauth.clientId;
|
|
855
|
+
const clientSecret = options.clientSecret?.trim() || params.config.oauth.clientSecret;
|
|
856
|
+
if (!clientId) throw new Error("Missing Google Meet OAuth client id. Configure oauth.clientId or pass --client-id.");
|
|
857
|
+
const { verifier, challenge } = createGoogleMeetPkce();
|
|
858
|
+
const state = createGoogleMeetOAuthState();
|
|
859
|
+
const authUrl = buildGoogleMeetAuthUrl({
|
|
860
|
+
clientId,
|
|
861
|
+
challenge,
|
|
862
|
+
state
|
|
620
863
|
});
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
if (options.format === "markdown") {
|
|
629
|
-
await writeCliOutput(options, renderArtifactsMarkdown(result));
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
if (options.format && options.format !== "summary") throw new Error("Unsupported format. Expected summary or markdown.");
|
|
633
|
-
writeArtifactsSummary(result);
|
|
634
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
635
|
-
});
|
|
636
|
-
root.command("attendance").description("List Meet participants and participant sessions").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").option("--conference-record <name>", "Conference record name or id").option("--today", "Find a Meet link on today's calendar").option("--event <query>", "Find a matching calendar event with a Meet link").option("--calendar <id>", "Calendar id for --today or --event", "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("--page-size <n>", "Max resources per Meet API page").option("--all-conference-records", "Fetch every conference record for --meeting").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) => {
|
|
637
|
-
const resolved = resolveArtifactTokenOptions(params.config, options);
|
|
638
|
-
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
639
|
-
const meeting = resolved.conferenceRecord ? resolved.meeting : (await resolveMeetingForToken({
|
|
640
|
-
config: params.config,
|
|
641
|
-
options,
|
|
642
|
-
accessToken: token.accessToken,
|
|
643
|
-
configuredMeeting: resolved.meeting
|
|
644
|
-
})).meeting;
|
|
645
|
-
const result = await fetchGoogleMeetAttendance({
|
|
646
|
-
accessToken: token.accessToken,
|
|
647
|
-
meeting,
|
|
648
|
-
conferenceRecord: resolved.conferenceRecord,
|
|
649
|
-
pageSize: resolved.pageSize,
|
|
650
|
-
allConferenceRecords: resolved.allConferenceRecords,
|
|
651
|
-
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
|
652
|
-
lateAfterMinutes: resolved.lateAfterMinutes,
|
|
653
|
-
earlyBeforeMinutes: resolved.earlyBeforeMinutes
|
|
864
|
+
const code = await waitForGoogleMeetAuthCode({
|
|
865
|
+
state,
|
|
866
|
+
manual: Boolean(options.manual),
|
|
867
|
+
timeoutMs: resolveGoogleMeetOAuthCallbackTimeoutMs(options.timeoutSec),
|
|
868
|
+
authUrl,
|
|
869
|
+
promptInput,
|
|
870
|
+
writeLine: (message) => writeStdoutLine("%s", message)
|
|
654
871
|
});
|
|
655
|
-
|
|
656
|
-
await writeCliOutput(options, JSON.stringify({
|
|
657
|
-
...result,
|
|
658
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
659
|
-
}, null, 2));
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
if (options.format === "markdown") {
|
|
663
|
-
await writeCliOutput(options, renderAttendanceMarkdown(result));
|
|
664
|
-
return;
|
|
665
|
-
}
|
|
666
|
-
if (options.format === "csv") {
|
|
667
|
-
await writeCliOutput(options, renderAttendanceCsv(result));
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
if (options.format && options.format !== "summary") throw new Error("Unsupported format. Expected summary, markdown, or csv.");
|
|
671
|
-
writeAttendanceSummary(result);
|
|
672
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
673
|
-
});
|
|
674
|
-
root.command("export").description("Write Meet artifacts, attendance, transcript, and raw JSON into a folder").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").option("--conference-record <name>", "Conference record name or id").option("--today", "Find a Meet link on today's calendar").option("--event <query>", "Find a matching calendar event with a Meet link").option("--calendar <id>", "Calendar id for --today or --event", "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("--page-size <n>", "Max resources per Meet API page").option("--all-conference-records", "Fetch every conference record for --meeting").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) => {
|
|
675
|
-
const resolved = resolveArtifactTokenOptions(params.config, options);
|
|
676
|
-
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
677
|
-
const meetingResult = resolved.conferenceRecord ? { meeting: resolved.meeting } : await resolveMeetingForToken({
|
|
678
|
-
config: params.config,
|
|
679
|
-
options,
|
|
680
|
-
accessToken: token.accessToken,
|
|
681
|
-
configuredMeeting: resolved.meeting
|
|
682
|
-
});
|
|
683
|
-
const artifacts = await fetchGoogleMeetArtifacts({
|
|
684
|
-
accessToken: token.accessToken,
|
|
685
|
-
meeting: meetingResult.meeting,
|
|
686
|
-
conferenceRecord: resolved.conferenceRecord,
|
|
687
|
-
pageSize: resolved.pageSize,
|
|
688
|
-
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
|
689
|
-
allConferenceRecords: resolved.allConferenceRecords,
|
|
690
|
-
includeDocumentBodies: resolved.includeDocumentBodies
|
|
691
|
-
});
|
|
692
|
-
const attendance = await fetchGoogleMeetAttendance({
|
|
693
|
-
accessToken: token.accessToken,
|
|
694
|
-
meeting: meetingResult.meeting,
|
|
695
|
-
conferenceRecord: resolved.conferenceRecord,
|
|
696
|
-
pageSize: resolved.pageSize,
|
|
697
|
-
allConferenceRecords: resolved.allConferenceRecords,
|
|
698
|
-
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
|
699
|
-
lateAfterMinutes: resolved.lateAfterMinutes,
|
|
700
|
-
earlyBeforeMinutes: resolved.earlyBeforeMinutes
|
|
701
|
-
});
|
|
702
|
-
const resolvedMeeting = meetingResult.meeting ?? resolved.meeting;
|
|
703
|
-
const request = {
|
|
704
|
-
...resolvedMeeting ? { meeting: resolvedMeeting } : {},
|
|
705
|
-
...resolved.conferenceRecord ? { conferenceRecord: resolved.conferenceRecord } : {},
|
|
706
|
-
...meetingResult.calendarEvent?.event.id ? { calendarEventId: meetingResult.calendarEvent.event.id } : {},
|
|
707
|
-
...meetingResult.calendarEvent?.event.summary ? { calendarEventSummary: meetingResult.calendarEvent.event.summary } : {},
|
|
708
|
-
...options.calendar ? { calendarId: options.calendar } : {},
|
|
709
|
-
...resolved.pageSize !== void 0 ? { pageSize: resolved.pageSize } : {},
|
|
710
|
-
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
|
711
|
-
includeDocumentBodies: resolved.includeDocumentBodies,
|
|
712
|
-
allConferenceRecords: resolved.allConferenceRecords,
|
|
713
|
-
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
|
714
|
-
...resolved.lateAfterMinutes !== void 0 ? { lateAfterMinutes: resolved.lateAfterMinutes } : {},
|
|
715
|
-
...resolved.earlyBeforeMinutes !== void 0 ? { earlyBeforeMinutes: resolved.earlyBeforeMinutes } : {}
|
|
716
|
-
};
|
|
717
|
-
if (options.dryRun) {
|
|
718
|
-
writeStdoutJson({
|
|
719
|
-
dryRun: true,
|
|
720
|
-
manifest: buildGoogleMeetExportManifest({
|
|
721
|
-
artifacts,
|
|
722
|
-
attendance,
|
|
723
|
-
files: googleMeetExportFileNames(),
|
|
724
|
-
request,
|
|
725
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
726
|
-
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {}
|
|
727
|
-
}),
|
|
728
|
-
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {},
|
|
729
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
730
|
-
});
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
const bundle = await writeMeetExportBundle({
|
|
734
|
-
outputDir: options.output,
|
|
735
|
-
artifacts,
|
|
736
|
-
attendance,
|
|
737
|
-
zip: Boolean(options.zip),
|
|
738
|
-
request,
|
|
739
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
740
|
-
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {}
|
|
741
|
-
});
|
|
742
|
-
const payload = {
|
|
743
|
-
...bundle,
|
|
744
|
-
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {},
|
|
745
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
746
|
-
};
|
|
747
|
-
if (options.json) {
|
|
748
|
-
writeStdoutJson(payload);
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
writeStdoutLine("export: %s", bundle.outputDir);
|
|
752
|
-
for (const file of bundle.files) writeStdoutLine("- %s", file);
|
|
753
|
-
if (bundle.zipFile) writeStdoutLine("zip: %s", bundle.zipFile);
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
//#endregion
|
|
757
|
-
//#region extensions/google-meet/src/cli-doctor.ts
|
|
758
|
-
function sanitizeOAuthErrorMessage(error) {
|
|
759
|
-
return (error instanceof Error ? error.message : String(error)).replace(/(access_token["'=:\s]+)[^"',\s&]+/gi, "$1[redacted]").replace(/(refresh_token["'=:\s]+)[^"',\s&]+/gi, "$1[redacted]").replace(/(client_secret["'=:\s]+)[^"',\s&]+/gi, "$1[redacted]");
|
|
760
|
-
}
|
|
761
|
-
async function buildOAuthDoctorReport(config, options) {
|
|
762
|
-
const clientId = options.clientId?.trim() || config.oauth.clientId;
|
|
763
|
-
const clientSecret = options.clientSecret?.trim() || config.oauth.clientSecret;
|
|
764
|
-
const refreshToken = options.refreshToken?.trim() || config.oauth.refreshToken;
|
|
765
|
-
const accessToken = options.accessToken?.trim() || config.oauth.accessToken;
|
|
766
|
-
const expiresAt = parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt;
|
|
767
|
-
const checks = [];
|
|
768
|
-
const hasRefreshConfig = Boolean(clientId && refreshToken);
|
|
769
|
-
if (!hasRefreshConfig && !Boolean(accessToken)) {
|
|
770
|
-
checks.push({
|
|
771
|
-
id: "oauth-config",
|
|
772
|
-
ok: false,
|
|
773
|
-
message: "Missing Google Meet OAuth credentials. Configure oauth.clientId and oauth.refreshToken, or pass --client-id and --refresh-token."
|
|
774
|
-
});
|
|
775
|
-
return {
|
|
776
|
-
ok: false,
|
|
777
|
-
configured: false,
|
|
778
|
-
checks
|
|
779
|
-
};
|
|
780
|
-
}
|
|
781
|
-
checks.push({
|
|
782
|
-
id: "oauth-config",
|
|
783
|
-
ok: true,
|
|
784
|
-
message: hasRefreshConfig ? "Google Meet OAuth refresh credentials are configured" : "Google Meet cached access token is configured"
|
|
785
|
-
});
|
|
786
|
-
let token;
|
|
787
|
-
try {
|
|
788
|
-
token = await resolveGoogleMeetAccessToken({
|
|
872
|
+
const tokens = await exchangeGoogleMeetAuthCode({
|
|
789
873
|
clientId,
|
|
790
874
|
clientSecret,
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
expiresAt
|
|
794
|
-
});
|
|
795
|
-
checks.push({
|
|
796
|
-
id: "oauth-token",
|
|
797
|
-
ok: true,
|
|
798
|
-
message: token.refreshed ? "Refresh token minted an access token" : "Cached access token is still valid"
|
|
799
|
-
});
|
|
800
|
-
} catch (error) {
|
|
801
|
-
checks.push({
|
|
802
|
-
id: "oauth-token",
|
|
803
|
-
ok: false,
|
|
804
|
-
message: sanitizeOAuthErrorMessage(error)
|
|
875
|
+
code,
|
|
876
|
+
verifier
|
|
805
877
|
});
|
|
806
|
-
return
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
878
|
+
if (!tokens.refreshToken) throw new Error("Google OAuth did not return a refresh token. Re-run the flow with consent and offline access.");
|
|
879
|
+
const payload = {
|
|
880
|
+
oauth: {
|
|
881
|
+
clientId,
|
|
882
|
+
...clientSecret ? { clientSecret } : {},
|
|
883
|
+
refreshToken: tokens.refreshToken,
|
|
884
|
+
accessToken: tokens.accessToken,
|
|
885
|
+
expiresAt: tokens.expiresAt
|
|
886
|
+
},
|
|
887
|
+
scope: tokens.scope,
|
|
888
|
+
tokenType: tokens.tokenType
|
|
810
889
|
};
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
if (options.createSpace) try {
|
|
839
|
-
const created = await createGoogleMeetSpace({ accessToken: token.accessToken });
|
|
840
|
-
checks.push({
|
|
841
|
-
id: "meet-spaces-create",
|
|
842
|
-
ok: true,
|
|
843
|
-
message: `Created ${created.space.name}`
|
|
844
|
-
});
|
|
845
|
-
report.createdSpace = created.space.name;
|
|
846
|
-
report.meetingUri = created.meetingUri;
|
|
847
|
-
} catch (error) {
|
|
848
|
-
checks.push({
|
|
849
|
-
id: "meet-spaces-create",
|
|
850
|
-
ok: false,
|
|
851
|
-
message: sanitizeOAuthErrorMessage(error)
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
report.ok = checks.every((check) => check.ok);
|
|
855
|
-
return report;
|
|
856
|
-
}
|
|
857
|
-
function writeOAuthDoctorReport(report) {
|
|
858
|
-
writeStdoutLine("Google Meet OAuth: %s", report.ok ? "OK" : "needs attention");
|
|
859
|
-
writeStdoutLine("configured: %s", report.configured ? "yes" : "no");
|
|
860
|
-
if (report.tokenSource) writeStdoutLine("token source: %s", report.tokenSource);
|
|
861
|
-
if (report.meetingUri) writeStdoutLine("meeting uri: %s", report.meetingUri);
|
|
862
|
-
for (const check of report.checks) writeStdoutLine("[%s] %s: %s", check.ok ? "ok" : "fail", check.id, check.message);
|
|
863
|
-
}
|
|
864
|
-
function registerGoogleMeetDoctorCommand(context) {
|
|
865
|
-
const params = context;
|
|
866
|
-
const { root, callGateway } = context;
|
|
867
|
-
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) => {
|
|
868
|
-
if (options.oauth) {
|
|
869
|
-
const report = await buildOAuthDoctorReport(params.config, options);
|
|
870
|
-
if (options.json) {
|
|
871
|
-
writeStdoutJson(report);
|
|
890
|
+
if (!options.json) writeStdoutLine("Paste this into plugins.entries.google-meet.config:");
|
|
891
|
+
writeStdoutJson(payload);
|
|
892
|
+
});
|
|
893
|
+
root.command("create").description("Create a new Google Meet space and print its meeting URL").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("--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) => {
|
|
894
|
+
if (options.join !== false) {
|
|
895
|
+
const delegated = await callGoogleMeetGateway({
|
|
896
|
+
callGateway,
|
|
897
|
+
method: "googlemeet.create",
|
|
898
|
+
payload: { ...options },
|
|
899
|
+
timeoutMs: operationTimeoutMs
|
|
900
|
+
});
|
|
901
|
+
if (delegated.ok) {
|
|
902
|
+
const payload = delegated.payload;
|
|
903
|
+
if (options.json) {
|
|
904
|
+
writeStdoutJson(payload);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
writeStdoutLine("meeting uri: %s", payload.meetingUri);
|
|
908
|
+
if (payload.space?.name) writeStdoutLine("space: %s", payload.space.name);
|
|
909
|
+
if (payload.space?.meetingCode) writeStdoutLine("meeting code: %s", payload.space.meetingCode);
|
|
910
|
+
if (payload.source) writeStdoutLine("source: %s", payload.source);
|
|
911
|
+
if (payload.browser?.nodeId) writeStdoutLine("node: %s", payload.browser.nodeId);
|
|
912
|
+
if (payload.tokenSource) writeStdoutLine("token source: %s", payload.tokenSource);
|
|
913
|
+
if (payload.joined && payload.join?.session?.id) writeStdoutLine("joined: %s", payload.join.session.id);
|
|
914
|
+
else writeStdoutLine("joined: no (run `openclaw googlemeet join %s`)", payload.meetingUri);
|
|
872
915
|
return;
|
|
873
916
|
}
|
|
874
|
-
writeOAuthDoctorReport(report);
|
|
875
|
-
return;
|
|
876
917
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
918
|
+
if (!hasCreateOAuth(params.config, options)) {
|
|
919
|
+
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.");
|
|
920
|
+
const rt = await params.ensureRuntime();
|
|
921
|
+
const result = await rt.createViaBrowser();
|
|
922
|
+
const join = options.join !== false ? await rt.join({
|
|
923
|
+
url: result.meetingUri,
|
|
924
|
+
transport: options.transport,
|
|
925
|
+
mode: options.mode,
|
|
926
|
+
message: options.message,
|
|
927
|
+
dialInNumber: options.dialInNumber,
|
|
928
|
+
pin: options.pin,
|
|
929
|
+
dtmfSequence: options.dtmfSequence
|
|
930
|
+
}) : void 0;
|
|
931
|
+
const payload = {
|
|
932
|
+
source: result.source,
|
|
933
|
+
meetingUri: result.meetingUri,
|
|
934
|
+
joined: Boolean(join),
|
|
935
|
+
...join ? { join } : {},
|
|
936
|
+
browser: {
|
|
937
|
+
nodeId: result.nodeId,
|
|
938
|
+
targetId: result.targetId,
|
|
939
|
+
browserUrl: result.browserUrl,
|
|
940
|
+
browserTitle: result.browserTitle
|
|
941
|
+
}
|
|
942
|
+
};
|
|
884
943
|
if (options.json) {
|
|
885
|
-
writeStdoutJson(
|
|
944
|
+
writeStdoutJson(payload);
|
|
886
945
|
return;
|
|
887
946
|
}
|
|
888
|
-
|
|
947
|
+
writeStdoutLine("meeting uri: %s", result.meetingUri);
|
|
948
|
+
writeStdoutLine("source: browser");
|
|
949
|
+
writeStdoutLine("node: %s", result.nodeId);
|
|
950
|
+
if (join) writeStdoutLine("joined: %s", join.session.id);
|
|
951
|
+
else writeStdoutLine("joined: no (run `openclaw googlemeet join %s`)", result.meetingUri);
|
|
889
952
|
return;
|
|
890
953
|
}
|
|
891
|
-
const
|
|
954
|
+
const token = await resolveGoogleMeetAccessToken(resolveCreateTokenOptions(params.config, options));
|
|
955
|
+
const result = await createGoogleMeetSpace({
|
|
956
|
+
accessToken: token.accessToken,
|
|
957
|
+
config: resolveCreateSpaceConfig(options)
|
|
958
|
+
});
|
|
959
|
+
const join = options.join !== false ? await (await params.ensureRuntime()).join({
|
|
960
|
+
url: result.meetingUri,
|
|
961
|
+
transport: options.transport,
|
|
962
|
+
mode: options.mode,
|
|
963
|
+
message: options.message,
|
|
964
|
+
dialInNumber: options.dialInNumber,
|
|
965
|
+
pin: options.pin,
|
|
966
|
+
dtmfSequence: options.dtmfSequence
|
|
967
|
+
}) : void 0;
|
|
892
968
|
if (options.json) {
|
|
893
|
-
writeStdoutJson(
|
|
969
|
+
writeStdoutJson({
|
|
970
|
+
...result,
|
|
971
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
972
|
+
joined: Boolean(join),
|
|
973
|
+
...join ? { join } : {}
|
|
974
|
+
});
|
|
894
975
|
return;
|
|
895
976
|
}
|
|
896
|
-
|
|
977
|
+
writeStdoutLine("meeting uri: %s", result.meetingUri);
|
|
978
|
+
writeStdoutLine("space: %s", result.space.name);
|
|
979
|
+
if (result.space.meetingCode) writeStdoutLine("meeting code: %s", result.space.meetingCode);
|
|
980
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
981
|
+
if (join) writeStdoutLine("joined: %s", join.session.id);
|
|
982
|
+
else writeStdoutLine("joined: no (run `openclaw googlemeet join %s`)", result.meetingUri);
|
|
983
|
+
});
|
|
984
|
+
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("--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 (meeting, options) => {
|
|
985
|
+
const token = await resolveGoogleMeetAccessToken(resolveOAuthTokenOptions(params.config, options));
|
|
986
|
+
const result = await endGoogleMeetActiveConference({
|
|
987
|
+
accessToken: token.accessToken,
|
|
988
|
+
meeting: resolveMeetingInput(params.config, meeting ?? options.meeting)
|
|
989
|
+
});
|
|
990
|
+
if (options.json) {
|
|
991
|
+
writeStdoutJson({
|
|
992
|
+
...result,
|
|
993
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
994
|
+
});
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
writeStdoutLine("space: %s", result.space);
|
|
998
|
+
writeStdoutLine("ended: yes");
|
|
999
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
897
1000
|
});
|
|
898
|
-
}
|
|
899
|
-
//#endregion
|
|
900
|
-
//#region extensions/google-meet/src/cli-runtime-commands.ts
|
|
901
|
-
function registerGoogleMeetProbeCommands(context) {
|
|
902
|
-
const params = context;
|
|
903
|
-
const { root, callGateway, operationTimeoutMs, resolveMeetingInput } = context;
|
|
904
1001
|
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) => {
|
|
905
1002
|
const payload = {
|
|
906
1003
|
url: resolveMeetingInput(params.config, url),
|
|
@@ -961,460 +1058,354 @@ function registerGoogleMeetProbeCommands(context) {
|
|
|
961
1058
|
}
|
|
962
1059
|
writeStdoutJson(await (await params.ensureRuntime()).testListen(payload));
|
|
963
1060
|
});
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
callGateway,
|
|
971
|
-
method: "googlemeet.status",
|
|
972
|
-
payload: { sessionId }
|
|
1061
|
+
root.command("resolve-space").description("Resolve a Meet URL, meeting code, or spaces/{id} to its canonical space").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").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) => {
|
|
1062
|
+
const resolved = resolveTokenOptions(params.config, options);
|
|
1063
|
+
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
1064
|
+
const space = await fetchGoogleMeetSpace({
|
|
1065
|
+
accessToken: token.accessToken,
|
|
1066
|
+
meeting: resolved.meeting
|
|
973
1067
|
});
|
|
974
|
-
if (
|
|
975
|
-
writeStdoutJson(
|
|
1068
|
+
if (options.json) {
|
|
1069
|
+
writeStdoutJson(space);
|
|
976
1070
|
return;
|
|
977
1071
|
}
|
|
978
|
-
|
|
1072
|
+
writeStdoutLine("input: %s", resolved.meeting);
|
|
1073
|
+
writeStdoutLine("space: %s", space.name);
|
|
1074
|
+
if (space.meetingCode) writeStdoutLine("meeting code: %s", space.meetingCode);
|
|
1075
|
+
if (space.meetingUri) writeStdoutLine("meeting uri: %s", space.meetingUri);
|
|
1076
|
+
writeStdoutLine("active conference: %s", space.activeConference ? "yes" : "no");
|
|
1077
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
979
1078
|
});
|
|
980
|
-
root.command("
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
const
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1079
|
+
root.command("preflight").description("Validate OAuth + meeting resolution prerequisites for Meet media work").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").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) => {
|
|
1080
|
+
const resolved = resolveTokenOptions(params.config, options);
|
|
1081
|
+
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
1082
|
+
const space = await fetchGoogleMeetSpace({
|
|
1083
|
+
accessToken: token.accessToken,
|
|
1084
|
+
meeting: resolved.meeting
|
|
1085
|
+
});
|
|
1086
|
+
const report = buildGoogleMeetPreflightReport({
|
|
1087
|
+
input: resolved.meeting,
|
|
1088
|
+
space,
|
|
1089
|
+
previewAcknowledged: params.config.preview.enrollmentAcknowledged,
|
|
1090
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
990
1091
|
});
|
|
991
|
-
const result = delegated.ok ? delegated.payload : await (await params.ensureRuntime()).transcript(sessionId, sinceIndex === void 0 ? {} : { sinceIndex });
|
|
992
|
-
if (!result.found) throw new Error("session not found");
|
|
993
1092
|
if (options.json) {
|
|
994
|
-
writeStdoutJson(
|
|
1093
|
+
writeStdoutJson(report);
|
|
995
1094
|
return;
|
|
996
1095
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
writeStdoutLine("
|
|
1096
|
+
writeStdoutLine("input: %s", report.input);
|
|
1097
|
+
writeStdoutLine("resolved space: %s", report.resolvedSpaceName);
|
|
1098
|
+
if (report.meetingCode) writeStdoutLine("meeting code: %s", report.meetingCode);
|
|
1099
|
+
if (report.meetingUri) writeStdoutLine("meeting uri: %s", report.meetingUri);
|
|
1100
|
+
writeStdoutLine("active conference: %s", report.hasActiveConference ? "yes" : "no");
|
|
1101
|
+
writeStdoutLine("preview acknowledged: %s", report.previewAcknowledged ? "yes" : "no");
|
|
1102
|
+
writeStdoutLine("token source: %s", report.tokenSource);
|
|
1103
|
+
if (report.blockers.length === 0) {
|
|
1104
|
+
writeStdoutLine("blockers: none");
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
writeStdoutLine("blockers:");
|
|
1108
|
+
for (const blocker of report.blockers) writeStdoutLine("- %s", blocker);
|
|
1001
1109
|
});
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1110
|
+
root.command("latest").description("Find the latest Meet conference record for a meeting").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").option("--today", "Find a Meet link on today's calendar").option("--event <query>", "Find a matching calendar event with a Meet link").option("--calendar <id>", "Calendar id for --today or --event", "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) => {
|
|
1111
|
+
const token = await resolveGoogleMeetAccessToken(resolveOAuthTokenOptions(params.config, options));
|
|
1112
|
+
const resolved = await resolveMeetingForToken({
|
|
1113
|
+
config: params.config,
|
|
1114
|
+
options,
|
|
1115
|
+
accessToken: token.accessToken,
|
|
1116
|
+
configuredMeeting: options.meeting?.trim()
|
|
1117
|
+
});
|
|
1118
|
+
const result = await fetchLatestGoogleMeetConferenceRecord({
|
|
1119
|
+
accessToken: token.accessToken,
|
|
1120
|
+
meeting: resolved.meeting
|
|
1121
|
+
});
|
|
1122
|
+
if (options.json) {
|
|
1123
|
+
writeStdoutJson({
|
|
1124
|
+
...result,
|
|
1125
|
+
...resolved.calendarEvent ? { calendarEvent: resolved.calendarEvent } : {},
|
|
1126
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1127
|
+
});
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
if (resolved.calendarEvent) {
|
|
1131
|
+
writeStdoutLine("calendar event: %s", resolved.calendarEvent.event.summary ?? "untitled");
|
|
1132
|
+
writeStdoutLine("calendar meet: %s", resolved.calendarEvent.meetingUri);
|
|
1133
|
+
}
|
|
1134
|
+
writeLatestConferenceRecordSummary(result);
|
|
1135
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1136
|
+
});
|
|
1137
|
+
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) => {
|
|
1138
|
+
const token = await resolveGoogleMeetAccessToken(resolveOAuthTokenOptions(params.config, options));
|
|
1139
|
+
const window = options.today ? buildGoogleMeetCalendarDayWindow() : {};
|
|
1140
|
+
const result = await listGoogleMeetCalendarEvents({
|
|
1141
|
+
accessToken: token.accessToken,
|
|
1142
|
+
calendarId: options.calendar,
|
|
1143
|
+
eventQuery: options.event,
|
|
1144
|
+
...window
|
|
1145
|
+
});
|
|
1146
|
+
const payload = {
|
|
1147
|
+
...result,
|
|
1148
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1149
|
+
};
|
|
1150
|
+
if (options.json) {
|
|
1151
|
+
writeStdoutJson(payload);
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
writeCalendarEventsSummary(result);
|
|
1155
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1156
|
+
});
|
|
1157
|
+
root.command("artifacts").description("List Meet conference records and available participant/artifact metadata").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").option("--conference-record <name>", "Conference record name or id").option("--today", "Find a Meet link on today's calendar").option("--event <query>", "Find a matching calendar event with a Meet link").option("--calendar <id>", "Calendar id for --today or --event", "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("--page-size <n>", "Max resources per Meet API page").option("--all-conference-records", "Fetch every conference record for --meeting").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) => {
|
|
1158
|
+
const resolved = resolveArtifactTokenOptions(params.config, options);
|
|
1159
|
+
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
1160
|
+
const meeting = resolved.conferenceRecord ? resolved.meeting : (await resolveMeetingForToken({
|
|
1161
|
+
config: params.config,
|
|
1162
|
+
options,
|
|
1163
|
+
accessToken: token.accessToken,
|
|
1164
|
+
configuredMeeting: resolved.meeting
|
|
1165
|
+
})).meeting;
|
|
1166
|
+
const result = await fetchGoogleMeetArtifacts({
|
|
1167
|
+
accessToken: token.accessToken,
|
|
1168
|
+
meeting,
|
|
1169
|
+
conferenceRecord: resolved.conferenceRecord,
|
|
1170
|
+
pageSize: resolved.pageSize,
|
|
1171
|
+
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
|
1172
|
+
allConferenceRecords: resolved.allConferenceRecords,
|
|
1173
|
+
includeDocumentBodies: resolved.includeDocumentBodies
|
|
1010
1174
|
});
|
|
1011
1175
|
if (options.json) {
|
|
1012
|
-
|
|
1176
|
+
await writeCliOutput(options, JSON.stringify({
|
|
1177
|
+
...result,
|
|
1178
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1179
|
+
}, null, 2));
|
|
1013
1180
|
return;
|
|
1014
1181
|
}
|
|
1015
|
-
|
|
1182
|
+
if (options.format === "markdown") {
|
|
1183
|
+
await writeCliOutput(options, renderArtifactsMarkdown(result));
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
if (options.format && options.format !== "summary") throw new Error("Unsupported format. Expected summary or markdown.");
|
|
1187
|
+
writeArtifactsSummary(result);
|
|
1188
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1016
1189
|
});
|
|
1017
|
-
root.command("
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1190
|
+
root.command("attendance").description("List Meet participants and participant sessions").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").option("--conference-record <name>", "Conference record name or id").option("--today", "Find a Meet link on today's calendar").option("--event <query>", "Find a matching calendar event with a Meet link").option("--calendar <id>", "Calendar id for --today or --event", "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("--page-size <n>", "Max resources per Meet API page").option("--all-conference-records", "Fetch every conference record for --meeting").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) => {
|
|
1191
|
+
const resolved = resolveArtifactTokenOptions(params.config, options);
|
|
1192
|
+
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
1193
|
+
const meeting = resolved.conferenceRecord ? resolved.meeting : (await resolveMeetingForToken({
|
|
1194
|
+
config: params.config,
|
|
1195
|
+
options,
|
|
1196
|
+
accessToken: token.accessToken,
|
|
1197
|
+
configuredMeeting: resolved.meeting
|
|
1198
|
+
})).meeting;
|
|
1199
|
+
const result = await fetchGoogleMeetAttendance({
|
|
1200
|
+
accessToken: token.accessToken,
|
|
1201
|
+
meeting,
|
|
1202
|
+
conferenceRecord: resolved.conferenceRecord,
|
|
1203
|
+
pageSize: resolved.pageSize,
|
|
1204
|
+
allConferenceRecords: resolved.allConferenceRecords,
|
|
1205
|
+
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
|
1206
|
+
lateAfterMinutes: resolved.lateAfterMinutes,
|
|
1207
|
+
earlyBeforeMinutes: resolved.earlyBeforeMinutes
|
|
1021
1208
|
});
|
|
1022
1209
|
if (options.json) {
|
|
1023
|
-
|
|
1210
|
+
await writeCliOutput(options, JSON.stringify({
|
|
1211
|
+
...result,
|
|
1212
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1213
|
+
}, null, 2));
|
|
1024
1214
|
return;
|
|
1025
1215
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
root.command("leave").argument("<session-id>", "Meet session ID").action(async (sessionId) => {
|
|
1029
|
-
const delegated = await callGoogleMeetGateway({
|
|
1030
|
-
callGateway,
|
|
1031
|
-
method: "googlemeet.leave",
|
|
1032
|
-
payload: { sessionId }
|
|
1033
|
-
});
|
|
1034
|
-
if (delegated.ok) {
|
|
1035
|
-
const result = delegated.payload;
|
|
1036
|
-
if (!result.found) throw new Error("session not found");
|
|
1037
|
-
writeLeaveResult(sessionId, result);
|
|
1216
|
+
if (options.format === "markdown") {
|
|
1217
|
+
await writeCliOutput(options, renderAttendanceMarkdown(result));
|
|
1038
1218
|
return;
|
|
1039
1219
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
writeLeaveResult(sessionId, result);
|
|
1043
|
-
});
|
|
1044
|
-
root.command("speak").argument("<session-id>", "Meet session ID").argument("[message]", "Realtime instructions to speak now").action(async (sessionId, message) => {
|
|
1045
|
-
const delegated = await callGoogleMeetGateway({
|
|
1046
|
-
callGateway,
|
|
1047
|
-
method: "googlemeet.speak",
|
|
1048
|
-
payload: {
|
|
1049
|
-
sessionId,
|
|
1050
|
-
message
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
if (delegated.ok) {
|
|
1054
|
-
const result = delegated.payload;
|
|
1055
|
-
if (!result.found) throw new Error("session not found");
|
|
1056
|
-
if (!result.spoken) throw new Error(result.session?.chrome?.health?.speechBlockedMessage ?? "session has no active realtime audio bridge");
|
|
1057
|
-
writeStdoutLine("speaking on %s", sessionId);
|
|
1220
|
+
if (options.format === "csv") {
|
|
1221
|
+
await writeCliOutput(options, renderAttendanceCsv(result));
|
|
1058
1222
|
return;
|
|
1059
1223
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
writeStdoutLine("speaking on %s", sessionId);
|
|
1224
|
+
if (options.format && options.format !== "summary") throw new Error("Unsupported format. Expected summary, markdown, or csv.");
|
|
1225
|
+
writeAttendanceSummary(result);
|
|
1226
|
+
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1064
1227
|
});
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1228
|
+
root.command("export").description("Write Meet artifacts, attendance, transcript, and raw JSON into a folder").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").option("--conference-record <name>", "Conference record name or id").option("--today", "Find a Meet link on today's calendar").option("--event <query>", "Find a matching calendar event with a Meet link").option("--calendar <id>", "Calendar id for --today or --event", "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("--page-size <n>", "Max resources per Meet API page").option("--all-conference-records", "Fetch every conference record for --meeting").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) => {
|
|
1229
|
+
const resolved = resolveArtifactTokenOptions(params.config, options);
|
|
1230
|
+
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
1231
|
+
const meetingResult = resolved.conferenceRecord ? { meeting: resolved.meeting } : await resolveMeetingForToken({
|
|
1232
|
+
config: params.config,
|
|
1233
|
+
options,
|
|
1234
|
+
accessToken: token.accessToken,
|
|
1235
|
+
configuredMeeting: resolved.meeting
|
|
1236
|
+
});
|
|
1237
|
+
const artifacts = await fetchGoogleMeetArtifacts({
|
|
1238
|
+
accessToken: token.accessToken,
|
|
1239
|
+
meeting: meetingResult.meeting,
|
|
1240
|
+
conferenceRecord: resolved.conferenceRecord,
|
|
1241
|
+
pageSize: resolved.pageSize,
|
|
1242
|
+
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
|
1243
|
+
allConferenceRecords: resolved.allConferenceRecords,
|
|
1244
|
+
includeDocumentBodies: resolved.includeDocumentBodies
|
|
1245
|
+
});
|
|
1246
|
+
const attendance = await fetchGoogleMeetAttendance({
|
|
1247
|
+
accessToken: token.accessToken,
|
|
1248
|
+
meeting: meetingResult.meeting,
|
|
1249
|
+
conferenceRecord: resolved.conferenceRecord,
|
|
1250
|
+
pageSize: resolved.pageSize,
|
|
1251
|
+
allConferenceRecords: resolved.allConferenceRecords,
|
|
1252
|
+
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
|
1253
|
+
lateAfterMinutes: resolved.lateAfterMinutes,
|
|
1254
|
+
earlyBeforeMinutes: resolved.earlyBeforeMinutes
|
|
1255
|
+
});
|
|
1256
|
+
const resolvedMeeting = meetingResult.meeting ?? resolved.meeting;
|
|
1257
|
+
const request = {
|
|
1258
|
+
...resolvedMeeting ? { meeting: resolvedMeeting } : {},
|
|
1259
|
+
...resolved.conferenceRecord ? { conferenceRecord: resolved.conferenceRecord } : {},
|
|
1260
|
+
...meetingResult.calendarEvent?.event.id ? { calendarEventId: meetingResult.calendarEvent.event.id } : {},
|
|
1261
|
+
...meetingResult.calendarEvent?.event.summary ? { calendarEventSummary: meetingResult.calendarEvent.event.summary } : {},
|
|
1262
|
+
...options.calendar ? { calendarId: options.calendar } : {},
|
|
1263
|
+
...resolved.pageSize !== void 0 ? { pageSize: resolved.pageSize } : {},
|
|
1264
|
+
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
|
1265
|
+
includeDocumentBodies: resolved.includeDocumentBodies,
|
|
1266
|
+
allConferenceRecords: resolved.allConferenceRecords,
|
|
1267
|
+
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
|
1268
|
+
...resolved.lateAfterMinutes !== void 0 ? { lateAfterMinutes: resolved.lateAfterMinutes } : {},
|
|
1269
|
+
...resolved.earlyBeforeMinutes !== void 0 ? { earlyBeforeMinutes: resolved.earlyBeforeMinutes } : {}
|
|
1270
|
+
};
|
|
1271
|
+
if (options.dryRun) {
|
|
1272
|
+
writeStdoutJson({
|
|
1273
|
+
dryRun: true,
|
|
1274
|
+
manifest: buildGoogleMeetExportManifest({
|
|
1275
|
+
artifacts,
|
|
1276
|
+
attendance,
|
|
1277
|
+
files: googleMeetExportFileNames(),
|
|
1278
|
+
request,
|
|
1279
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
1280
|
+
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {}
|
|
1281
|
+
}),
|
|
1282
|
+
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {},
|
|
1283
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1078
1284
|
});
|
|
1079
|
-
if (delegated.ok) {
|
|
1080
|
-
const payload = delegated.payload;
|
|
1081
|
-
if (options.json) {
|
|
1082
|
-
writeStdoutJson(payload);
|
|
1083
|
-
return;
|
|
1084
|
-
}
|
|
1085
|
-
writeStdoutLine("meeting uri: %s", payload.meetingUri);
|
|
1086
|
-
if (payload.space?.name) writeStdoutLine("space: %s", payload.space.name);
|
|
1087
|
-
if (payload.space?.meetingCode) writeStdoutLine("meeting code: %s", payload.space.meetingCode);
|
|
1088
|
-
if (payload.source) writeStdoutLine("source: %s", payload.source);
|
|
1089
|
-
if (payload.browser?.nodeId) writeStdoutLine("node: %s", payload.browser.nodeId);
|
|
1090
|
-
if (payload.tokenSource) writeStdoutLine("token source: %s", payload.tokenSource);
|
|
1091
|
-
if (payload.joined && payload.join?.session?.id) writeStdoutLine("joined: %s", payload.join.session.id);
|
|
1092
|
-
else writeStdoutLine("joined: no (run `openclaw googlemeet join %s`)", payload.meetingUri);
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
if (!hasCreateOAuth(params.config, options)) {
|
|
1097
|
-
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.");
|
|
1098
|
-
const rt = await params.ensureRuntime();
|
|
1099
|
-
const result = await rt.createViaBrowser();
|
|
1100
|
-
const join = options.join !== false ? await rt.join({
|
|
1101
|
-
url: result.meetingUri,
|
|
1102
|
-
transport: options.transport,
|
|
1103
|
-
mode: options.mode,
|
|
1104
|
-
message: options.message,
|
|
1105
|
-
dialInNumber: options.dialInNumber,
|
|
1106
|
-
pin: options.pin,
|
|
1107
|
-
dtmfSequence: options.dtmfSequence
|
|
1108
|
-
}) : void 0;
|
|
1109
|
-
const payload = {
|
|
1110
|
-
source: result.source,
|
|
1111
|
-
meetingUri: result.meetingUri,
|
|
1112
|
-
joined: Boolean(join),
|
|
1113
|
-
...join ? { join } : {},
|
|
1114
|
-
browser: {
|
|
1115
|
-
nodeId: result.nodeId,
|
|
1116
|
-
targetId: result.targetId,
|
|
1117
|
-
browserUrl: result.browserUrl,
|
|
1118
|
-
browserTitle: result.browserTitle
|
|
1119
|
-
}
|
|
1120
|
-
};
|
|
1121
|
-
if (options.json) {
|
|
1122
|
-
writeStdoutJson(payload);
|
|
1123
|
-
return;
|
|
1124
|
-
}
|
|
1125
|
-
writeStdoutLine("meeting uri: %s", result.meetingUri);
|
|
1126
|
-
writeStdoutLine("source: browser");
|
|
1127
|
-
writeStdoutLine("node: %s", result.nodeId);
|
|
1128
|
-
if (join) writeStdoutLine("joined: %s", join.session.id);
|
|
1129
|
-
else writeStdoutLine("joined: no (run `openclaw googlemeet join %s`)", result.meetingUri);
|
|
1130
1285
|
return;
|
|
1131
1286
|
}
|
|
1132
|
-
const
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1287
|
+
const bundle = await writeMeetExportBundle({
|
|
1288
|
+
outputDir: options.output,
|
|
1289
|
+
artifacts,
|
|
1290
|
+
attendance,
|
|
1291
|
+
zip: Boolean(options.zip),
|
|
1292
|
+
request,
|
|
1293
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
1294
|
+
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {}
|
|
1136
1295
|
});
|
|
1137
|
-
const
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
dialInNumber: options.dialInNumber,
|
|
1143
|
-
pin: options.pin,
|
|
1144
|
-
dtmfSequence: options.dtmfSequence
|
|
1145
|
-
}) : void 0;
|
|
1296
|
+
const payload = {
|
|
1297
|
+
...bundle,
|
|
1298
|
+
...meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {},
|
|
1299
|
+
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1300
|
+
};
|
|
1146
1301
|
if (options.json) {
|
|
1147
|
-
writeStdoutJson(
|
|
1148
|
-
...result,
|
|
1149
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
|
1150
|
-
joined: Boolean(join),
|
|
1151
|
-
...join ? { join } : {}
|
|
1152
|
-
});
|
|
1302
|
+
writeStdoutJson(payload);
|
|
1153
1303
|
return;
|
|
1154
1304
|
}
|
|
1155
|
-
writeStdoutLine("
|
|
1156
|
-
writeStdoutLine("
|
|
1157
|
-
if (
|
|
1158
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1159
|
-
if (join) writeStdoutLine("joined: %s", join.session.id);
|
|
1160
|
-
else writeStdoutLine("joined: no (run `openclaw googlemeet join %s`)", result.meetingUri);
|
|
1305
|
+
writeStdoutLine("export: %s", bundle.outputDir);
|
|
1306
|
+
for (const file of bundle.files) writeStdoutLine("- %s", file);
|
|
1307
|
+
if (bundle.zipFile) writeStdoutLine("zip: %s", bundle.zipFile);
|
|
1161
1308
|
});
|
|
1162
|
-
root.command("
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1309
|
+
root.command("status").argument("[session-id]", "Meet session ID").option("--json", "Print JSON output", false).action(async (sessionId) => {
|
|
1310
|
+
const delegated = await callGoogleMeetGateway({
|
|
1311
|
+
callGateway,
|
|
1312
|
+
method: "googlemeet.status",
|
|
1313
|
+
payload: { sessionId }
|
|
1167
1314
|
});
|
|
1168
|
-
if (
|
|
1169
|
-
writeStdoutJson(
|
|
1170
|
-
...result,
|
|
1171
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1172
|
-
});
|
|
1315
|
+
if (delegated.ok) {
|
|
1316
|
+
writeStdoutJson(delegated.payload);
|
|
1173
1317
|
return;
|
|
1174
1318
|
}
|
|
1175
|
-
|
|
1176
|
-
writeStdoutLine("ended: yes");
|
|
1177
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1319
|
+
writeStdoutJson(await (await params.ensureRuntime()).status(sessionId));
|
|
1178
1320
|
});
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
accessToken: token.accessToken,
|
|
1188
|
-
meeting: resolved.meeting
|
|
1189
|
-
});
|
|
1190
|
-
if (options.json) {
|
|
1191
|
-
writeStdoutJson(space);
|
|
1321
|
+
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) => {
|
|
1322
|
+
if (options.oauth) {
|
|
1323
|
+
const report = await buildOAuthDoctorReport(params.config, options);
|
|
1324
|
+
if (options.json) {
|
|
1325
|
+
writeStdoutJson(report);
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
writeOAuthDoctorReport(report);
|
|
1192
1329
|
return;
|
|
1193
1330
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
writeStdoutLine("active conference: %s", space.activeConference ? "yes" : "no");
|
|
1199
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1200
|
-
});
|
|
1201
|
-
root.command("preflight").description("Validate OAuth + meeting resolution prerequisites for Meet media work").option("--meeting <value>", "Meet URL, meeting code, or spaces/{id}").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) => {
|
|
1202
|
-
const resolved = resolveTokenOptions(params.config, options);
|
|
1203
|
-
const token = await resolveGoogleMeetAccessToken(resolved);
|
|
1204
|
-
const space = await fetchGoogleMeetSpace({
|
|
1205
|
-
accessToken: token.accessToken,
|
|
1206
|
-
meeting: resolved.meeting
|
|
1207
|
-
});
|
|
1208
|
-
const report = buildGoogleMeetPreflightReport({
|
|
1209
|
-
input: resolved.meeting,
|
|
1210
|
-
space,
|
|
1211
|
-
previewAcknowledged: params.config.preview.enrollmentAcknowledged,
|
|
1212
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1331
|
+
const delegated = await callGoogleMeetGateway({
|
|
1332
|
+
callGateway,
|
|
1333
|
+
method: "googlemeet.status",
|
|
1334
|
+
payload: { sessionId }
|
|
1213
1335
|
});
|
|
1214
|
-
if (
|
|
1215
|
-
|
|
1336
|
+
if (delegated.ok) {
|
|
1337
|
+
const status = delegated.payload;
|
|
1338
|
+
if (options.json) {
|
|
1339
|
+
writeStdoutJson(status);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
writeDoctorStatus(status);
|
|
1216
1343
|
return;
|
|
1217
1344
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
if (report.meetingUri) writeStdoutLine("meeting uri: %s", report.meetingUri);
|
|
1222
|
-
writeStdoutLine("active conference: %s", report.hasActiveConference ? "yes" : "no");
|
|
1223
|
-
writeStdoutLine("preview acknowledged: %s", report.previewAcknowledged ? "yes" : "no");
|
|
1224
|
-
writeStdoutLine("token source: %s", report.tokenSource);
|
|
1225
|
-
if (report.blockers.length === 0) {
|
|
1226
|
-
writeStdoutLine("blockers: none");
|
|
1345
|
+
const status = await (await params.ensureRuntime()).status(sessionId);
|
|
1346
|
+
if (options.json) {
|
|
1347
|
+
writeStdoutJson(status);
|
|
1227
1348
|
return;
|
|
1228
1349
|
}
|
|
1229
|
-
|
|
1230
|
-
for (const blocker of report.blockers) writeStdoutLine("- %s", blocker);
|
|
1350
|
+
writeDoctorStatus(status);
|
|
1231
1351
|
});
|
|
1232
|
-
root.command("
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
options,
|
|
1237
|
-
accessToken: token.accessToken,
|
|
1238
|
-
configuredMeeting: options.meeting?.trim()
|
|
1239
|
-
});
|
|
1240
|
-
const result = await fetchLatestGoogleMeetConferenceRecord({
|
|
1241
|
-
accessToken: token.accessToken,
|
|
1242
|
-
meeting: resolved.meeting
|
|
1352
|
+
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) => {
|
|
1353
|
+
const result = await (await params.ensureRuntime()).recoverCurrentTab({
|
|
1354
|
+
url,
|
|
1355
|
+
transport: options.transport
|
|
1243
1356
|
});
|
|
1244
1357
|
if (options.json) {
|
|
1245
|
-
writeStdoutJson(
|
|
1246
|
-
...result,
|
|
1247
|
-
...resolved.calendarEvent ? { calendarEvent: resolved.calendarEvent } : {},
|
|
1248
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1249
|
-
});
|
|
1358
|
+
writeStdoutJson(result);
|
|
1250
1359
|
return;
|
|
1251
1360
|
}
|
|
1252
|
-
|
|
1253
|
-
writeStdoutLine("calendar event: %s", resolved.calendarEvent.event.summary ?? "untitled");
|
|
1254
|
-
writeStdoutLine("calendar meet: %s", resolved.calendarEvent.meetingUri);
|
|
1255
|
-
}
|
|
1256
|
-
writeLatestConferenceRecordSummary(result);
|
|
1257
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1361
|
+
writeRecoverCurrentTabResult(result);
|
|
1258
1362
|
});
|
|
1259
|
-
root.command("
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
accessToken: token.accessToken,
|
|
1264
|
-
calendarId: options.calendar,
|
|
1265
|
-
eventQuery: options.event,
|
|
1266
|
-
...window
|
|
1363
|
+
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) => {
|
|
1364
|
+
const status = await (await params.ensureRuntime()).setupStatus({
|
|
1365
|
+
transport: options.transport,
|
|
1366
|
+
mode: options.mode
|
|
1267
1367
|
});
|
|
1268
|
-
const payload = {
|
|
1269
|
-
...result,
|
|
1270
|
-
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token"
|
|
1271
|
-
};
|
|
1272
1368
|
if (options.json) {
|
|
1273
|
-
writeStdoutJson(
|
|
1369
|
+
writeStdoutJson(status);
|
|
1274
1370
|
return;
|
|
1275
1371
|
}
|
|
1276
|
-
|
|
1277
|
-
writeStdoutLine("token source: %s", token.refreshed ? "refresh-token" : "cached-access-token");
|
|
1278
|
-
});
|
|
1279
|
-
}
|
|
1280
|
-
//#endregion
|
|
1281
|
-
//#region extensions/google-meet/src/cli.ts
|
|
1282
|
-
function resolveMeetingInput(config, value) {
|
|
1283
|
-
const meeting = value?.trim() || config.defaults.meeting;
|
|
1284
|
-
if (!meeting) throw new Error("Meeting input is required. Pass a URL/meeting code or configure defaults.meeting.");
|
|
1285
|
-
return meeting;
|
|
1286
|
-
}
|
|
1287
|
-
function resolveOAuthTokenOptions(config, options) {
|
|
1288
|
-
return {
|
|
1289
|
-
clientId: options.clientId?.trim() || config.oauth.clientId,
|
|
1290
|
-
clientSecret: options.clientSecret?.trim() || config.oauth.clientSecret,
|
|
1291
|
-
refreshToken: options.refreshToken?.trim() || config.oauth.refreshToken,
|
|
1292
|
-
accessToken: options.accessToken?.trim() || config.oauth.accessToken,
|
|
1293
|
-
expiresAt: parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt
|
|
1294
|
-
};
|
|
1295
|
-
}
|
|
1296
|
-
function resolveTokenOptions(config, options) {
|
|
1297
|
-
return {
|
|
1298
|
-
meeting: resolveMeetingInput(config, options.meeting),
|
|
1299
|
-
...resolveOAuthTokenOptions(config, options)
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
function hasCalendarLookupOptions(options) {
|
|
1303
|
-
return Boolean(options.today || options.event?.trim());
|
|
1304
|
-
}
|
|
1305
|
-
async function resolveCalendarMeetingInput(params) {
|
|
1306
|
-
if (!hasCalendarLookupOptions(params.options)) return {};
|
|
1307
|
-
const window = params.options.today ? buildGoogleMeetCalendarDayWindow() : {};
|
|
1308
|
-
const calendarEvent = await findGoogleMeetCalendarEvent({
|
|
1309
|
-
accessToken: params.accessToken,
|
|
1310
|
-
calendarId: params.options.calendar,
|
|
1311
|
-
eventQuery: params.options.event,
|
|
1312
|
-
...window
|
|
1313
|
-
});
|
|
1314
|
-
return {
|
|
1315
|
-
meeting: calendarEvent.meetingUri,
|
|
1316
|
-
calendarEvent
|
|
1317
|
-
};
|
|
1318
|
-
}
|
|
1319
|
-
async function resolveMeetingForToken(params) {
|
|
1320
|
-
const calendarMeeting = await resolveCalendarMeetingInput({
|
|
1321
|
-
accessToken: params.accessToken,
|
|
1322
|
-
options: params.options
|
|
1372
|
+
writeSetupStatus(status);
|
|
1323
1373
|
});
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
} : { meeting };
|
|
1330
|
-
}
|
|
1331
|
-
function resolveArtifactTokenOptions(config, options) {
|
|
1332
|
-
const meeting = options.meeting?.trim() || config.defaults.meeting;
|
|
1333
|
-
const conferenceRecord = options.conferenceRecord?.trim();
|
|
1334
|
-
if (!meeting && !conferenceRecord && !hasCalendarLookupOptions(options)) throw new Error("Meeting input or conference record is required. Pass --meeting, --today, --event, --conference-record, or configure defaults.meeting.");
|
|
1335
|
-
return {
|
|
1336
|
-
meeting,
|
|
1337
|
-
conferenceRecord,
|
|
1338
|
-
clientId: options.clientId?.trim() || config.oauth.clientId,
|
|
1339
|
-
clientSecret: options.clientSecret?.trim() || config.oauth.clientSecret,
|
|
1340
|
-
refreshToken: options.refreshToken?.trim() || config.oauth.refreshToken,
|
|
1341
|
-
accessToken: options.accessToken?.trim() || config.oauth.accessToken,
|
|
1342
|
-
expiresAt: parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt,
|
|
1343
|
-
pageSize: parsePositiveIntegerOption(options.pageSize, "page-size"),
|
|
1344
|
-
includeTranscriptEntries: options.transcriptEntries !== false,
|
|
1345
|
-
allConferenceRecords: Boolean(options.allConferenceRecords),
|
|
1346
|
-
includeDocumentBodies: Boolean(options.includeDocBodies),
|
|
1347
|
-
mergeDuplicateParticipants: options.mergeDuplicates !== false,
|
|
1348
|
-
lateAfterMinutes: parseOptionalNumber(options.lateAfterMinutes),
|
|
1349
|
-
earlyBeforeMinutes: parseOptionalNumber(options.earlyBeforeMinutes)
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
function hasCreateOAuth(config, options) {
|
|
1353
|
-
return Boolean(options.accessToken?.trim() || options.refreshToken?.trim() || config.oauth.accessToken || config.oauth.refreshToken);
|
|
1354
|
-
}
|
|
1355
|
-
function registerGoogleMeetCli(params) {
|
|
1356
|
-
const callGateway = params.callGatewayFromCli ?? callGatewayFromCli;
|
|
1357
|
-
const operationTimeoutMs = resolveGoogleMeetGatewayOperationTimeoutMs(params.config);
|
|
1358
|
-
const root = params.program.command("googlemeet").description("Google Meet participant utilities").addHelpText("after", () => `\nDocs: https://docs.openclaw.ai/plugins/google-meet\n`);
|
|
1359
|
-
root.command("auth").description("Google Meet OAuth helpers").command("login").description("Run a PKCE OAuth flow and print refresh-token JSON to store in plugin config").option("--client-id <id>", "OAuth client id override").option("--client-secret <secret>", "OAuth client secret override").option("--manual", "Use copy/paste callback flow instead of localhost callback").option("--json", "Print the token payload as JSON", false).option("--timeout-sec <n>", "Local callback timeout in seconds", "300").action(async (options) => {
|
|
1360
|
-
const clientId = options.clientId?.trim() || params.config.oauth.clientId;
|
|
1361
|
-
const clientSecret = options.clientSecret?.trim() || params.config.oauth.clientSecret;
|
|
1362
|
-
if (!clientId) throw new Error("Missing Google Meet OAuth client id. Configure oauth.clientId or pass --client-id.");
|
|
1363
|
-
const { verifier, challenge } = createGoogleMeetPkce();
|
|
1364
|
-
const state = createGoogleMeetOAuthState();
|
|
1365
|
-
const authUrl = buildGoogleMeetAuthUrl({
|
|
1366
|
-
clientId,
|
|
1367
|
-
challenge,
|
|
1368
|
-
state
|
|
1374
|
+
root.command("leave").argument("<session-id>", "Meet session ID").action(async (sessionId) => {
|
|
1375
|
+
const delegated = await callGoogleMeetGateway({
|
|
1376
|
+
callGateway,
|
|
1377
|
+
method: "googlemeet.leave",
|
|
1378
|
+
payload: { sessionId }
|
|
1369
1379
|
});
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1380
|
+
if (delegated.ok) {
|
|
1381
|
+
if (!delegated.payload.found) throw new Error("session not found");
|
|
1382
|
+
writeStdoutLine("left %s", sessionId);
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
if (!(await (await params.ensureRuntime()).leave(sessionId)).found) throw new Error("session not found");
|
|
1386
|
+
writeStdoutLine("left %s", sessionId);
|
|
1387
|
+
});
|
|
1388
|
+
root.command("speak").argument("<session-id>", "Meet session ID").argument("[message]", "Realtime instructions to speak now").action(async (sessionId, message) => {
|
|
1389
|
+
const delegated = await callGoogleMeetGateway({
|
|
1390
|
+
callGateway,
|
|
1391
|
+
method: "googlemeet.speak",
|
|
1392
|
+
payload: {
|
|
1393
|
+
sessionId,
|
|
1394
|
+
message
|
|
1395
|
+
}
|
|
1382
1396
|
});
|
|
1383
|
-
if (
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
};
|
|
1395
|
-
if (!options.json) writeStdoutLine("Paste this into plugins.entries.google-meet.config:");
|
|
1396
|
-
writeStdoutJson(payload);
|
|
1397
|
+
if (delegated.ok) {
|
|
1398
|
+
const result = delegated.payload;
|
|
1399
|
+
if (!result.found) throw new Error("session not found");
|
|
1400
|
+
if (!result.spoken) throw new Error(result.session?.chrome?.health?.speechBlockedMessage ?? "session has no active realtime audio bridge");
|
|
1401
|
+
writeStdoutLine("speaking on %s", sessionId);
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
const result = await (await params.ensureRuntime()).speak(sessionId, message);
|
|
1405
|
+
if (!result.found) throw new Error("session not found");
|
|
1406
|
+
if (!result.spoken) throw new Error(result.session?.chrome?.health?.speechBlockedMessage ?? "session has no active realtime audio bridge");
|
|
1407
|
+
writeStdoutLine("speaking on %s", sessionId);
|
|
1397
1408
|
});
|
|
1398
|
-
const context = {
|
|
1399
|
-
root,
|
|
1400
|
-
config: params.config,
|
|
1401
|
-
ensureRuntime: params.ensureRuntime,
|
|
1402
|
-
callGateway,
|
|
1403
|
-
operationTimeoutMs,
|
|
1404
|
-
resolveMeetingInput,
|
|
1405
|
-
resolveOAuthTokenOptions,
|
|
1406
|
-
resolveTokenOptions,
|
|
1407
|
-
resolveMeetingForToken,
|
|
1408
|
-
resolveArtifactTokenOptions,
|
|
1409
|
-
hasCreateOAuth
|
|
1410
|
-
};
|
|
1411
|
-
registerGoogleMeetCreateCommands(context);
|
|
1412
|
-
registerGoogleMeetProbeCommands(context);
|
|
1413
|
-
registerGoogleMeetApiCommands(context);
|
|
1414
|
-
registerGoogleMeetArtifactCommands(context);
|
|
1415
|
-
registerGoogleMeetSessionCommands(context);
|
|
1416
|
-
registerGoogleMeetDoctorCommand(context);
|
|
1417
|
-
registerGoogleMeetLifecycleCommands(context);
|
|
1418
1409
|
}
|
|
1419
1410
|
//#endregion
|
|
1420
1411
|
export { buildGoogleMeetExportManifest, googleMeetExportFileNames, registerGoogleMeetCli, testing, writeMeetExportBundle };
|