@openclaw/google-meet 2026.9.6 → 2026.9.7
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/assets/icon.png +0 -0
- package/dist/.setup/{chrome-create-BZRBHJp9.mjs → chrome-create-wuAK5Pnq.mjs} +14 -19
- package/dist/.setup/{cli-CbxqjjTC.mjs → cli-DVDq0TFu.mjs} +27 -695
- package/dist/.setup/cli-export-D4IM6KLJ.mjs +632 -0
- package/dist/.setup/config-BXGAMntj.mjs +240 -0
- package/dist/.setup/{create-CG9Pgwsb.mjs → create-UrHOmnWb.mjs} +4 -17
- package/dist/.setup/{google-meet-platform-adapter-DQZ74Kd5.mjs → google-meet-platform-adapter-gosgbMIM.mjs} +337 -228
- package/dist/.setup/{google-meet-platform-constants-Bs5iAg3E.mjs → google-meet-platform-constants-CnRfrYX7.mjs} +1 -4
- package/dist/.setup/{node-host-BUrsParx.mjs → node-host-Tr7Mx3da.mjs} +3 -3
- package/dist/.setup/{node-invoke-policy-hwXq9MfV.mjs → node-invoke-policy-Dd3krTYV.mjs} +2 -2
- package/dist/.setup/{oauth-22Ey-zCb.mjs → oauth-BoyruWcS.mjs} +2 -2
- package/dist/.setup/{plugin-helpers--7X3icub.mjs → plugin-helpers-CdQ_YNA7.mjs} +147 -236
- package/dist/.setup/{plugin-registration-B3LXKV4R.mjs → plugin-registration-aCEuCerg.mjs} +34 -10
- package/dist/.setup/{runtime-BuIZ5e3V.mjs → runtime-BdiF53A2.mjs} +85 -41
- package/dist/doctor-contract-api.js +3 -6
- package/dist/index.js +48 -12
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/package.json +5 -5
- package/dist/.setup/config-C-6enWkx.mjs +0 -328
- package/dist/.setup/google-api-errors-BDYXfKRa.mjs +0 -17
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import { _ as __exportAll } from "./plugin-helpers-CdQ_YNA7.mjs";
|
|
2
|
+
import { clampTimerTimeoutMs, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
3
|
+
import fsp, { stat } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import JSZip from "jszip";
|
|
6
|
+
import { replaceFileAtomic, writeExternalFileWithinRoot } from "openclaw/plugin-sdk/security-runtime";
|
|
7
|
+
import { createInterface } from "node:readline/promises";
|
|
8
|
+
import { format } from "node:util";
|
|
9
|
+
import { isGatewayClientRequestError, isGatewayTransportError } from "openclaw/plugin-sdk/gateway-runtime";
|
|
10
|
+
import { formatDurationCompact } from "openclaw/plugin-sdk/time-runtime";
|
|
11
|
+
//#region extensions/google-meet/src/cli-shared.ts
|
|
12
|
+
const GOOGLE_MEET_GATEWAY_DEFAULT_TIMEOUT_MS = 5e3;
|
|
13
|
+
const PLAIN_DECIMAL_NUMBER_RE = /^\d+(?:\.\d+)?$/;
|
|
14
|
+
function parseGoogleMeetMode(value) {
|
|
15
|
+
if (value === void 0 || value === "agent" || value === "bidi" || value === "transcribe" || value === "realtime") return value;
|
|
16
|
+
throw new Error(`mode must be agent, bidi, transcribe, or realtime; received ${value}`);
|
|
17
|
+
}
|
|
18
|
+
function parseGoogleMeetTransport(value) {
|
|
19
|
+
if (value === void 0 || value === "chrome" || value === "chrome-node" || value === "twilio") return value;
|
|
20
|
+
throw new Error(`transport must be chrome, chrome-node, or twilio; received ${value}`);
|
|
21
|
+
}
|
|
22
|
+
function parseGoogleMeetBrowserTransport(value) {
|
|
23
|
+
const transport = parseGoogleMeetTransport(value);
|
|
24
|
+
if (transport === "twilio") throw new Error(`transport must be chrome or chrome-node; received ${value}`);
|
|
25
|
+
return transport;
|
|
26
|
+
}
|
|
27
|
+
function writeStdoutJson(value) {
|
|
28
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
29
|
+
}
|
|
30
|
+
function isGatewayUnavailableForLocalFallback(err, method) {
|
|
31
|
+
if (isGatewayTransportError(err)) return err.kind === "closed" && err.code === void 0;
|
|
32
|
+
return isGatewayClientRequestError(err) && err.message.includes(`unknown method: ${method}`);
|
|
33
|
+
}
|
|
34
|
+
function writeStdoutLine(...values) {
|
|
35
|
+
process.stdout.write(`${format(...values)}\n`);
|
|
36
|
+
}
|
|
37
|
+
async function writeCliOutput(options, text) {
|
|
38
|
+
if (options.output?.trim()) {
|
|
39
|
+
const dirMode = (await stat(path.dirname(options.output))).mode & 4095;
|
|
40
|
+
await replaceFileAtomic({
|
|
41
|
+
filePath: options.output,
|
|
42
|
+
content: text.endsWith("\n") ? text : `${text}\n`,
|
|
43
|
+
dirMode,
|
|
44
|
+
mode: 438 & ~process.umask(),
|
|
45
|
+
preserveExistingMode: true,
|
|
46
|
+
tempPrefix: ".google-meet-output",
|
|
47
|
+
syncTempFile: true,
|
|
48
|
+
syncParentDir: true,
|
|
49
|
+
throwOnCleanupError: true
|
|
50
|
+
});
|
|
51
|
+
writeStdoutLine("wrote: %s", options.output);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
process.stdout.write(text.endsWith("\n") ? text : `${text}\n`);
|
|
55
|
+
}
|
|
56
|
+
async function promptInput(message) {
|
|
57
|
+
const rl = createInterface({
|
|
58
|
+
input: process.stdin,
|
|
59
|
+
output: process.stderr
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
return await rl.question(message);
|
|
63
|
+
} finally {
|
|
64
|
+
rl.close();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseOptionalNumber(value) {
|
|
68
|
+
if (!value?.trim()) return;
|
|
69
|
+
const trimmed = value.trim();
|
|
70
|
+
const parsed = PLAIN_DECIMAL_NUMBER_RE.test(trimmed) ? Number(trimmed) : NaN;
|
|
71
|
+
if (!Number.isFinite(parsed)) throw new Error(`Expected a numeric value, received ${value}`);
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
function writeSetupStatus(status) {
|
|
75
|
+
writeStdoutLine("Google Meet setup: %s", status.ok ? "OK" : "needs attention");
|
|
76
|
+
for (const check of status.checks) writeStdoutLine("[%s] %s: %s", check.ok ? "ok" : "fail", check.id, check.message);
|
|
77
|
+
}
|
|
78
|
+
function formatBoolean(value) {
|
|
79
|
+
return typeof value === "boolean" ? value ? "yes" : "no" : "unknown";
|
|
80
|
+
}
|
|
81
|
+
function formatOptional(value) {
|
|
82
|
+
return typeof value === "string" && value.trim() ? value : "n/a";
|
|
83
|
+
}
|
|
84
|
+
function parsePositiveNumber(value, label) {
|
|
85
|
+
if (value === void 0) return;
|
|
86
|
+
const trimmed = value.trim();
|
|
87
|
+
const parsed = PLAIN_DECIMAL_NUMBER_RE.test(trimmed) ? Number(trimmed) : NaN;
|
|
88
|
+
if (!Number.isFinite(parsed) || parsed <= 0) throw new Error(`${label} must be a positive number`);
|
|
89
|
+
return parsed;
|
|
90
|
+
}
|
|
91
|
+
function resolveGoogleMeetGatewayTimeoutMs(timeoutMs) {
|
|
92
|
+
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) ? clampTimerTimeoutMs(Math.ceil(timeoutMs)) ?? 1 : GOOGLE_MEET_GATEWAY_DEFAULT_TIMEOUT_MS;
|
|
93
|
+
}
|
|
94
|
+
function resolveGoogleMeetOAuthCallbackTimeoutMs(timeoutSec) {
|
|
95
|
+
return clampTimerTimeoutMs((parsePositiveNumber(timeoutSec, "timeout-sec") ?? 300) * 1e3) ?? 3e5;
|
|
96
|
+
}
|
|
97
|
+
function parsePositiveIntegerOption(value, label) {
|
|
98
|
+
if (value === void 0) return;
|
|
99
|
+
const parsed = parseStrictPositiveInteger(value);
|
|
100
|
+
if (parsed === void 0) throw new Error(`${label} must be a positive integer`);
|
|
101
|
+
return parsed;
|
|
102
|
+
}
|
|
103
|
+
async function callGoogleMeetGateway(params) {
|
|
104
|
+
try {
|
|
105
|
+
const timeoutMs = resolveGoogleMeetGatewayTimeoutMs(params.timeoutMs);
|
|
106
|
+
return {
|
|
107
|
+
ok: true,
|
|
108
|
+
payload: await params.callGateway(params.method, {
|
|
109
|
+
json: true,
|
|
110
|
+
timeout: String(timeoutMs)
|
|
111
|
+
}, params.payload, { progress: false })
|
|
112
|
+
};
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (isGatewayUnavailableForLocalFallback(err, params.method)) return {
|
|
115
|
+
ok: false,
|
|
116
|
+
error: err
|
|
117
|
+
};
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function formatDuration(value) {
|
|
122
|
+
if (value === void 0) return "n/a";
|
|
123
|
+
const roundedMs = Math.max(0, Math.round(value / 1e3) * 1e3);
|
|
124
|
+
return formatDurationCompact(roundedMs, {
|
|
125
|
+
showYears: true,
|
|
126
|
+
spaced: true
|
|
127
|
+
}) ?? "0ms";
|
|
128
|
+
}
|
|
129
|
+
function writeDoctorStatus(status) {
|
|
130
|
+
if (!status.found) {
|
|
131
|
+
writeStdoutLine("Google Meet session: not found");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const sessions = status.session ? [status.session] : status.sessions ?? [];
|
|
135
|
+
if (sessions.length === 0) {
|
|
136
|
+
writeStdoutLine("Google Meet sessions: none");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
writeStdoutLine("Google Meet sessions: %d", sessions.length);
|
|
140
|
+
for (const session of sessions) {
|
|
141
|
+
const health = session.chrome?.health;
|
|
142
|
+
writeStdoutLine("");
|
|
143
|
+
writeStdoutLine("session: %s", session.id);
|
|
144
|
+
writeStdoutLine("url: %s", session.url);
|
|
145
|
+
writeStdoutLine("state: %s", session.state);
|
|
146
|
+
writeStdoutLine("transport: %s", session.transport);
|
|
147
|
+
writeStdoutLine("mode: %s", session.mode);
|
|
148
|
+
if (session.twilio) {
|
|
149
|
+
writeStdoutLine("twilio dial-in: %s", session.twilio.dialInNumber);
|
|
150
|
+
writeStdoutLine("voice call id: %s", formatOptional(session.twilio.voiceCallId));
|
|
151
|
+
writeStdoutLine("dtmf sent: %s", formatBoolean(session.twilio.dtmfSent));
|
|
152
|
+
writeStdoutLine("intro sent: %s", formatBoolean(session.twilio.introSent));
|
|
153
|
+
}
|
|
154
|
+
if (!session.chrome) continue;
|
|
155
|
+
writeStdoutLine("node: %s", session.chrome?.nodeId ?? "local/none");
|
|
156
|
+
writeStdoutLine("audio bridge: %s", session.chrome?.audioBridge?.type ?? "none");
|
|
157
|
+
const bridgeProvider = session.chrome?.audioBridge?.provider ?? session.realtime.transcriptionProvider ?? session.realtime.provider ?? "n/a";
|
|
158
|
+
writeStdoutLine(session.mode === "agent" ? "transcription provider: %s" : "provider: %s", bridgeProvider);
|
|
159
|
+
if (session.realtime.enabled) writeStdoutLine("talk-back mode: %s", session.realtime.strategy ?? session.mode);
|
|
160
|
+
writeStdoutLine("in call: %s", formatBoolean(health?.inCall));
|
|
161
|
+
writeStdoutLine("lobby waiting: %s", formatBoolean(health?.lobbyWaiting));
|
|
162
|
+
writeStdoutLine("captioning: %s", formatBoolean(health?.captioning));
|
|
163
|
+
writeStdoutLine("transcript lines: %s", health?.transcriptLines ?? 0);
|
|
164
|
+
writeStdoutLine("last caption: %s", formatOptional(health?.lastCaptionAt));
|
|
165
|
+
writeStdoutLine("manual action: %s", formatBoolean(Boolean(health?.manualAction)));
|
|
166
|
+
if (health?.manualAction) {
|
|
167
|
+
writeStdoutLine("manual reason: %s", formatOptional(health.manualAction.reason));
|
|
168
|
+
writeStdoutLine("manual message: %s", formatOptional(health.manualAction.message));
|
|
169
|
+
}
|
|
170
|
+
writeStdoutLine("speech ready: %s", formatBoolean(health?.speechReady));
|
|
171
|
+
if (health?.speechReady === false) {
|
|
172
|
+
writeStdoutLine("speech blocked reason: %s", formatOptional(health.speechBlockedReason));
|
|
173
|
+
writeStdoutLine("speech blocked message: %s", formatOptional(health.speechBlockedMessage));
|
|
174
|
+
}
|
|
175
|
+
writeStdoutLine("provider connected: %s", formatBoolean(health?.providerConnected));
|
|
176
|
+
writeStdoutLine("realtime ready: %s", formatBoolean(health?.realtimeReady));
|
|
177
|
+
writeStdoutLine("audio input active: %s", formatBoolean(health?.audioInputActive));
|
|
178
|
+
writeStdoutLine("audio output active: %s", formatBoolean(health?.audioOutputActive));
|
|
179
|
+
writeStdoutLine("meet output routed: %s", formatBoolean(health?.audioOutputRouted));
|
|
180
|
+
if (health?.audioOutputDeviceLabel || health?.audioOutputRouteError) {
|
|
181
|
+
writeStdoutLine("meet output device: %s", formatOptional(health.audioOutputDeviceLabel));
|
|
182
|
+
writeStdoutLine("meet output route error: %s", formatOptional(health.audioOutputRouteError));
|
|
183
|
+
}
|
|
184
|
+
writeStdoutLine("last input: %s (%s bytes)", formatOptional(health?.lastInputAt), health?.lastInputBytes ?? 0);
|
|
185
|
+
writeStdoutLine("last output: %s (%s bytes)", formatOptional(health?.lastOutputAt), health?.lastOutputBytes ?? 0);
|
|
186
|
+
writeStdoutLine("bridge closed: %s", formatBoolean(health?.bridgeClosed));
|
|
187
|
+
writeStdoutLine("browser url: %s", formatOptional(health?.browserUrl));
|
|
188
|
+
if (health?.lastCaptionText) writeStdoutLine("last caption text: %s%s", health.lastCaptionSpeaker ? `${health.lastCaptionSpeaker}: ` : "", health.lastCaptionText);
|
|
189
|
+
writeStdoutLine("realtime transcript lines: %s", health?.realtimeTranscriptLines ?? 0);
|
|
190
|
+
if (health?.lastRealtimeTranscriptText) writeStdoutLine("last realtime transcript: %s%s", health.lastRealtimeTranscriptRole ? `${health.lastRealtimeTranscriptRole}: ` : "", health.lastRealtimeTranscriptText);
|
|
191
|
+
if (health?.lastRealtimeEventType) {
|
|
192
|
+
const detail = health.lastRealtimeEventDetail ? ` ${health.lastRealtimeEventDetail}` : "";
|
|
193
|
+
writeStdoutLine("last realtime event: %s%s", health.lastRealtimeEventType, detail);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function writeRecoverCurrentTabResult(result) {
|
|
198
|
+
writeStdoutLine("Google Meet current tab: %s", result.found ? "found" : "not found");
|
|
199
|
+
writeStdoutLine("transport: %s", result.transport);
|
|
200
|
+
writeStdoutLine("node: %s", result.nodeId ?? "local/none");
|
|
201
|
+
if (result.targetId) writeStdoutLine("target: %s", result.targetId);
|
|
202
|
+
if (result.tab?.url) writeStdoutLine("tab url: %s", result.tab.url);
|
|
203
|
+
writeStdoutLine("message: %s", result.message);
|
|
204
|
+
if (result.browser) writeDoctorStatus({
|
|
205
|
+
found: true,
|
|
206
|
+
session: {
|
|
207
|
+
id: "current-tab",
|
|
208
|
+
url: result.browser.browserUrl ?? result.tab?.url ?? "unknown",
|
|
209
|
+
transport: result.transport,
|
|
210
|
+
mode: "transcribe",
|
|
211
|
+
agentId: "main",
|
|
212
|
+
state: "active",
|
|
213
|
+
createdAt: "",
|
|
214
|
+
updatedAt: "",
|
|
215
|
+
participantIdentity: result.transport === "chrome-node" ? "signed-in Google Chrome profile on a paired node" : "signed-in Google Chrome profile",
|
|
216
|
+
realtime: {
|
|
217
|
+
enabled: false,
|
|
218
|
+
toolPolicy: "safe-read-only"
|
|
219
|
+
},
|
|
220
|
+
chrome: {
|
|
221
|
+
launched: true,
|
|
222
|
+
nodeId: result.nodeId,
|
|
223
|
+
health: result.browser
|
|
224
|
+
},
|
|
225
|
+
notes: []
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function writeLeaveResult(sessionId, result) {
|
|
230
|
+
if (result.browserLeft === false) {
|
|
231
|
+
writeStdoutLine("left %s, but the browser participant may still be in the call; check session notes", sessionId);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
writeStdoutLine("left %s", sessionId);
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region extensions/google-meet/src/cli-export.ts
|
|
238
|
+
var cli_export_exports = /* @__PURE__ */ __exportAll({
|
|
239
|
+
buildGoogleMeetExportManifest: () => buildGoogleMeetExportManifest,
|
|
240
|
+
exportGoogleMeetBundle: () => exportGoogleMeetBundle,
|
|
241
|
+
googleMeetExportFileNames: () => googleMeetExportFileNames,
|
|
242
|
+
renderArtifactsMarkdown: () => renderArtifactsMarkdown,
|
|
243
|
+
renderArtifactsSummary: () => renderArtifactsSummary,
|
|
244
|
+
renderAttendanceCsv: () => renderAttendanceCsv,
|
|
245
|
+
renderAttendanceMarkdown: () => renderAttendanceMarkdown,
|
|
246
|
+
renderAttendanceSummary: () => renderAttendanceSummary,
|
|
247
|
+
writeCalendarEventsSummary: () => writeCalendarEventsSummary,
|
|
248
|
+
writeLatestConferenceRecordSummary: () => writeLatestConferenceRecordSummary,
|
|
249
|
+
writeMeetExportBundle: () => writeMeetExportBundle
|
|
250
|
+
});
|
|
251
|
+
function renderArtifactsSummary(result) {
|
|
252
|
+
const lines = [];
|
|
253
|
+
if (result.input) lines.push(`input: ${result.input}`);
|
|
254
|
+
if (result.space) lines.push(`space: ${result.space.name}`);
|
|
255
|
+
lines.push(`conference records: ${result.conferenceRecords.length}`);
|
|
256
|
+
for (const entry of result.artifacts) {
|
|
257
|
+
lines.push("");
|
|
258
|
+
lines.push(`record: ${entry.conferenceRecord.name}`);
|
|
259
|
+
lines.push(`started: ${formatOptional(entry.conferenceRecord.startTime)}`);
|
|
260
|
+
lines.push(`ended: ${formatOptional(entry.conferenceRecord.endTime)}`);
|
|
261
|
+
lines.push(`participants: ${entry.participants.length}`);
|
|
262
|
+
lines.push(`recordings: ${entry.recordings.length}`);
|
|
263
|
+
lines.push(`transcripts: ${entry.transcripts.length}`);
|
|
264
|
+
lines.push(`transcript entries: ${entry.transcriptEntries.reduce((count, transcript) => count + transcript.entries.length, 0)}`);
|
|
265
|
+
lines.push(`smart notes: ${entry.smartNotes.length}`);
|
|
266
|
+
if (entry.smartNotesError) lines.push(`smart notes warning: ${entry.smartNotesError}`);
|
|
267
|
+
for (const recording of entry.recordings) lines.push(`- recording: ${recording.name}`);
|
|
268
|
+
for (const transcript of entry.transcripts) {
|
|
269
|
+
lines.push(`- transcript: ${transcript.name}`);
|
|
270
|
+
if (transcript.documentTextError) lines.push(`- transcript document body warning: ${transcript.documentTextError}`);
|
|
271
|
+
}
|
|
272
|
+
for (const transcriptEntries of entry.transcriptEntries) if (transcriptEntries.entriesError) lines.push(`- transcript entries warning: ${transcriptEntries.transcript}: ${transcriptEntries.entriesError}`);
|
|
273
|
+
for (const smartNote of entry.smartNotes) {
|
|
274
|
+
lines.push(`- smart note: ${smartNote.name}`);
|
|
275
|
+
if (smartNote.documentTextError) lines.push(`- smart note document body warning: ${smartNote.documentTextError}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return `${lines.join("\n")}\n`;
|
|
279
|
+
}
|
|
280
|
+
function renderAttendance(result, markdown) {
|
|
281
|
+
const lines = markdown ? ["# Google Meet Attendance"] : [];
|
|
282
|
+
const field = (label, value) => {
|
|
283
|
+
lines.push(`${markdown ? label : label.toLowerCase()}: ${value}`);
|
|
284
|
+
};
|
|
285
|
+
if (result.input) field("Input", result.input);
|
|
286
|
+
if (result.space) field("Space", result.space.name);
|
|
287
|
+
if (markdown) lines.push("");
|
|
288
|
+
field("Conference records", result.conferenceRecords.length);
|
|
289
|
+
field("Attendance rows", result.attendance.length);
|
|
290
|
+
for (const row of result.attendance) {
|
|
291
|
+
const identity = row.displayName || row.user || row.participant;
|
|
292
|
+
lines.push("", markdown ? `## ${identity}` : `participant: ${identity}`);
|
|
293
|
+
field("Record", row.conferenceRecord);
|
|
294
|
+
field("Resource", row.participant);
|
|
295
|
+
field("Participants merged", row.participants?.length ?? 1);
|
|
296
|
+
field("First joined", formatOptional(row.firstJoinTime ?? row.earliestStartTime));
|
|
297
|
+
field("Last left", formatOptional(row.lastLeaveTime ?? row.latestEndTime));
|
|
298
|
+
field("Duration", formatDuration(row.durationMs));
|
|
299
|
+
field("Late", row.late ? formatDuration(row.lateByMs) : "no");
|
|
300
|
+
field("Early leave", row.earlyLeave ? formatDuration(row.earlyLeaveByMs) : "no");
|
|
301
|
+
field("Sessions", row.sessions.length);
|
|
302
|
+
for (const session of row.sessions) lines.push(`- ${session.name}: ${formatOptional(session.startTime)} -> ${formatOptional(session.endTime)}`);
|
|
303
|
+
}
|
|
304
|
+
return `${lines.join("\n")}\n`;
|
|
305
|
+
}
|
|
306
|
+
function renderAttendanceSummary(result) {
|
|
307
|
+
return renderAttendance(result, false);
|
|
308
|
+
}
|
|
309
|
+
function renderAttendanceMarkdown(result) {
|
|
310
|
+
return renderAttendance(result, true);
|
|
311
|
+
}
|
|
312
|
+
function writeLatestConferenceRecordSummary(result) {
|
|
313
|
+
writeStdoutLine("input: %s", result.input);
|
|
314
|
+
writeStdoutLine("space: %s", result.space.name);
|
|
315
|
+
if (!result.conferenceRecord) {
|
|
316
|
+
writeStdoutLine("conference record: none");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
writeStdoutLine("conference record: %s", result.conferenceRecord.name);
|
|
320
|
+
writeStdoutLine("started: %s", formatOptional(result.conferenceRecord.startTime));
|
|
321
|
+
writeStdoutLine("ended: %s", formatOptional(result.conferenceRecord.endTime));
|
|
322
|
+
}
|
|
323
|
+
function writeCalendarEventsSummary(result) {
|
|
324
|
+
writeStdoutLine("calendar: %s", result.calendarId);
|
|
325
|
+
writeStdoutLine("meet events: %d", result.events.length);
|
|
326
|
+
for (const entry of result.events) {
|
|
327
|
+
writeStdoutLine("");
|
|
328
|
+
writeStdoutLine("%s%s", entry.selected ? "* " : "- ", entry.event.summary ?? "untitled");
|
|
329
|
+
writeStdoutLine("meeting uri: %s", entry.meetingUri);
|
|
330
|
+
writeStdoutLine("starts: %s", formatOptional(entry.event.start?.dateTime ?? entry.event.start?.date));
|
|
331
|
+
writeStdoutLine("ends: %s", formatOptional(entry.event.end?.dateTime ?? entry.event.end?.date));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function participantDisplayName(entry, name) {
|
|
335
|
+
const participant = entry.participants.find((candidate) => candidate.name === name);
|
|
336
|
+
if (!participant) return name;
|
|
337
|
+
return participant.signedinUser?.displayName ?? participant.anonymousUser?.displayName ?? participant.phoneUser?.displayName ?? participant.signedinUser?.user ?? name;
|
|
338
|
+
}
|
|
339
|
+
function appendArtifactDocuments(lines, title, documents) {
|
|
340
|
+
if (documents.length === 0) return;
|
|
341
|
+
lines.push("", `### ${title}`);
|
|
342
|
+
for (const document of documents) {
|
|
343
|
+
lines.push(`- ${document.name}`);
|
|
344
|
+
if (document.documentTextError) lines.push(` - Document body warning: ${document.documentTextError}`);
|
|
345
|
+
else if (document.documentText) lines.push(` - Document body: ${document.documentText.length} chars`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function renderArtifactsMarkdown(result) {
|
|
349
|
+
const lines = ["# Google Meet Artifacts"];
|
|
350
|
+
if (result.input) lines.push(`Input: ${result.input}`);
|
|
351
|
+
if (result.space) lines.push(`Space: ${result.space.name}`);
|
|
352
|
+
lines.push("");
|
|
353
|
+
lines.push(`Conference records: ${result.conferenceRecords.length}`);
|
|
354
|
+
for (const entry of result.artifacts) {
|
|
355
|
+
lines.push("");
|
|
356
|
+
lines.push(`## ${entry.conferenceRecord.name}`);
|
|
357
|
+
lines.push(`Started: ${formatOptional(entry.conferenceRecord.startTime)}`);
|
|
358
|
+
lines.push(`Ended: ${formatOptional(entry.conferenceRecord.endTime)}`);
|
|
359
|
+
lines.push("");
|
|
360
|
+
lines.push(`Participants: ${entry.participants.length}`);
|
|
361
|
+
lines.push(`Recordings: ${entry.recordings.length}`);
|
|
362
|
+
lines.push(`Transcripts: ${entry.transcripts.length}`);
|
|
363
|
+
lines.push(`Transcript entries: ${entry.transcriptEntries.reduce((count, transcript) => count + transcript.entries.length, 0)}`);
|
|
364
|
+
lines.push(`Smart notes: ${entry.smartNotes.length}`);
|
|
365
|
+
const warnings = collectGoogleMeetArtifactWarnings({
|
|
366
|
+
conferenceRecords: [entry.conferenceRecord],
|
|
367
|
+
artifacts: [entry]
|
|
368
|
+
});
|
|
369
|
+
if (warnings.length > 0) {
|
|
370
|
+
lines.push("");
|
|
371
|
+
lines.push("### Warnings");
|
|
372
|
+
for (const warning of warnings) {
|
|
373
|
+
const resource = warning.resource ? `${warning.resource}: ` : "";
|
|
374
|
+
lines.push(`- ${resource}${warning.message}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (entry.recordings.length > 0) {
|
|
378
|
+
lines.push("");
|
|
379
|
+
lines.push("### Recordings");
|
|
380
|
+
for (const recording of entry.recordings) lines.push(`- ${recording.name}`);
|
|
381
|
+
}
|
|
382
|
+
appendArtifactDocuments(lines, "Transcripts", entry.transcripts);
|
|
383
|
+
for (const transcriptEntries of entry.transcriptEntries) {
|
|
384
|
+
lines.push("");
|
|
385
|
+
lines.push(`### Transcript Entries: ${transcriptEntries.transcript}`);
|
|
386
|
+
if (transcriptEntries.entriesError) {
|
|
387
|
+
lines.push(`Warning: ${transcriptEntries.entriesError}`);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (transcriptEntries.entries.length === 0) {
|
|
391
|
+
lines.push("_No transcript entries._");
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
for (const transcriptEntry of transcriptEntries.entries) {
|
|
395
|
+
const times = transcriptEntry.startTime || transcriptEntry.endTime ? ` (${formatOptional(transcriptEntry.startTime)} -> ${formatOptional(transcriptEntry.endTime)})` : "";
|
|
396
|
+
const speaker = transcriptEntry.participant ? `${participantDisplayName(entry, transcriptEntry.participant)}: ` : "";
|
|
397
|
+
lines.push(`- ${speaker}${transcriptEntry.text ?? ""}${times}`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
appendArtifactDocuments(lines, "Smart Notes", entry.smartNotes);
|
|
401
|
+
}
|
|
402
|
+
return `${lines.join("\n")}\n`;
|
|
403
|
+
}
|
|
404
|
+
function neutralizeSpreadsheetFormulaCell(text) {
|
|
405
|
+
return /^[ \t\r\n]*[=+\-@\uFF0B\uFF0D\uFF1D\uFF20]/u.test(text) || /^[\t\r\n]/.test(text) ? `'${text}` : text;
|
|
406
|
+
}
|
|
407
|
+
function csvCell(value) {
|
|
408
|
+
const safeText = neutralizeSpreadsheetFormulaCell(value === void 0 || value === null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value));
|
|
409
|
+
return /[",\r\n]/.test(safeText) ? `"${safeText.replaceAll("\"", "\"\"")}"` : safeText;
|
|
410
|
+
}
|
|
411
|
+
function renderAttendanceCsv(result) {
|
|
412
|
+
const rows = [[
|
|
413
|
+
"conferenceRecord",
|
|
414
|
+
"displayName",
|
|
415
|
+
"user",
|
|
416
|
+
"participants",
|
|
417
|
+
"firstJoined",
|
|
418
|
+
"lastLeft",
|
|
419
|
+
"durationMs",
|
|
420
|
+
"sessions",
|
|
421
|
+
"late",
|
|
422
|
+
"lateByMs",
|
|
423
|
+
"earlyLeave",
|
|
424
|
+
"earlyLeaveByMs"
|
|
425
|
+
]];
|
|
426
|
+
for (const row of result.attendance) rows.push([
|
|
427
|
+
row.conferenceRecord,
|
|
428
|
+
row.displayName ?? "",
|
|
429
|
+
row.user ?? "",
|
|
430
|
+
(row.participants ?? [row.participant]).join(";"),
|
|
431
|
+
row.firstJoinTime ?? row.earliestStartTime ?? "",
|
|
432
|
+
row.lastLeaveTime ?? row.latestEndTime ?? "",
|
|
433
|
+
row.durationMs ?? "",
|
|
434
|
+
row.sessions.length,
|
|
435
|
+
row.late ?? "",
|
|
436
|
+
row.lateByMs ?? "",
|
|
437
|
+
row.earlyLeave ?? "",
|
|
438
|
+
row.earlyLeaveByMs ?? ""
|
|
439
|
+
]);
|
|
440
|
+
return `${rows.map((row) => row.map(csvCell).join(",")).join("\n")}\n`;
|
|
441
|
+
}
|
|
442
|
+
function renderTranscriptMarkdown(result) {
|
|
443
|
+
const lines = ["# Google Meet Transcript"];
|
|
444
|
+
if (result.input) lines.push(`Input: ${result.input}`);
|
|
445
|
+
for (const entry of result.artifacts) {
|
|
446
|
+
lines.push("");
|
|
447
|
+
lines.push(`## ${entry.conferenceRecord.name}`);
|
|
448
|
+
if (entry.transcriptEntries.length === 0) {
|
|
449
|
+
lines.push("_No transcript entries._");
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
for (const transcriptEntries of entry.transcriptEntries) {
|
|
453
|
+
lines.push("");
|
|
454
|
+
lines.push(`### ${transcriptEntries.transcript}`);
|
|
455
|
+
if (transcriptEntries.entriesError) {
|
|
456
|
+
lines.push(`Warning: ${transcriptEntries.entriesError}`);
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
for (const transcriptEntry of transcriptEntries.entries) {
|
|
460
|
+
const speaker = transcriptEntry.participant ? participantDisplayName(entry, transcriptEntry.participant) : "unknown";
|
|
461
|
+
const time = transcriptEntry.startTime ? ` [${transcriptEntry.startTime}]` : "";
|
|
462
|
+
lines.push(`- ${speaker}${time}: ${transcriptEntry.text ?? ""}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
for (const [title, documents] of [["Transcript Document Bodies", entry.transcripts], ["Smart Note Document Bodies", entry.smartNotes]]) {
|
|
466
|
+
const bodies = documents.filter((document) => document.documentText);
|
|
467
|
+
if (bodies.length > 0) {
|
|
468
|
+
lines.push("", `### ${title}`);
|
|
469
|
+
for (const document of bodies) {
|
|
470
|
+
lines.push("", `#### ${document.name}`);
|
|
471
|
+
lines.push(document.documentText?.trim() || "_Empty document body._");
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return `${lines.join("\n")}\n`;
|
|
477
|
+
}
|
|
478
|
+
function collectGoogleMeetArtifactWarnings(result) {
|
|
479
|
+
const warnings = [];
|
|
480
|
+
for (const entry of result.artifacts) {
|
|
481
|
+
const conferenceRecord = entry.conferenceRecord.name;
|
|
482
|
+
if (entry.smartNotesError) warnings.push({
|
|
483
|
+
type: "smart_notes",
|
|
484
|
+
conferenceRecord,
|
|
485
|
+
message: entry.smartNotesError
|
|
486
|
+
});
|
|
487
|
+
for (const transcriptEntries of entry.transcriptEntries) if (transcriptEntries.entriesError) warnings.push({
|
|
488
|
+
type: "transcript_entries",
|
|
489
|
+
conferenceRecord,
|
|
490
|
+
resource: transcriptEntries.transcript,
|
|
491
|
+
message: transcriptEntries.entriesError
|
|
492
|
+
});
|
|
493
|
+
for (const [type, documents] of [["transcript_document_body", entry.transcripts], ["smart_note_document_body", entry.smartNotes]]) for (const document of documents) if (document.documentTextError) warnings.push({
|
|
494
|
+
type,
|
|
495
|
+
conferenceRecord,
|
|
496
|
+
resource: document.name,
|
|
497
|
+
message: document.documentTextError
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
return warnings;
|
|
501
|
+
}
|
|
502
|
+
function buildGoogleMeetExportManifest(params) {
|
|
503
|
+
const transcriptEntryCount = params.artifacts.artifacts.reduce((count, entry) => count + entry.transcriptEntries.reduce((entryCount, transcript) => entryCount + transcript.entries.length, 0), 0);
|
|
504
|
+
const warnings = collectGoogleMeetArtifactWarnings(params.artifacts);
|
|
505
|
+
return {
|
|
506
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
507
|
+
...params.request ? { request: params.request } : {},
|
|
508
|
+
...params.tokenSource ? { tokenSource: params.tokenSource } : {},
|
|
509
|
+
...params.calendarEvent ? { calendarEvent: params.calendarEvent } : {},
|
|
510
|
+
inputs: {
|
|
511
|
+
...params.artifacts.input ? { artifacts: params.artifacts.input } : {},
|
|
512
|
+
...params.attendance.input ? { attendance: params.attendance.input } : {}
|
|
513
|
+
},
|
|
514
|
+
counts: {
|
|
515
|
+
conferenceRecords: params.artifacts.conferenceRecords.length,
|
|
516
|
+
artifacts: params.artifacts.artifacts.length,
|
|
517
|
+
attendanceRows: params.attendance.attendance.length,
|
|
518
|
+
recordings: params.artifacts.artifacts.reduce((count, entry) => count + entry.recordings.length, 0),
|
|
519
|
+
transcripts: params.artifacts.artifacts.reduce((count, entry) => count + entry.transcripts.length, 0),
|
|
520
|
+
transcriptEntries: transcriptEntryCount,
|
|
521
|
+
smartNotes: params.artifacts.artifacts.reduce((count, entry) => count + entry.smartNotes.length, 0),
|
|
522
|
+
warnings: warnings.length
|
|
523
|
+
},
|
|
524
|
+
conferenceRecords: params.artifacts.conferenceRecords.map((record) => record.name),
|
|
525
|
+
files: params.files,
|
|
526
|
+
...params.zipFile ? { zipFile: params.zipFile } : {},
|
|
527
|
+
warnings
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function googleMeetExportFileNames() {
|
|
531
|
+
return [
|
|
532
|
+
"summary.md",
|
|
533
|
+
"attendance.csv",
|
|
534
|
+
"transcript.md",
|
|
535
|
+
"artifacts.json",
|
|
536
|
+
"attendance.json",
|
|
537
|
+
"manifest.json"
|
|
538
|
+
];
|
|
539
|
+
}
|
|
540
|
+
function defaultExportDirectory() {
|
|
541
|
+
return `google-meet-export-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
542
|
+
}
|
|
543
|
+
async function publishMeetExportFile(outputPath, content) {
|
|
544
|
+
const absolutePath = path.resolve(outputPath);
|
|
545
|
+
await writeExternalFileWithinRoot({
|
|
546
|
+
rootDir: path.dirname(absolutePath),
|
|
547
|
+
path: path.basename(absolutePath),
|
|
548
|
+
write: async (tempPath) => {
|
|
549
|
+
await fsp.writeFile(tempPath, content);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
async function writeMeetExportBundle(params) {
|
|
554
|
+
const outputDir = params.outputDir?.trim() || defaultExportDirectory();
|
|
555
|
+
await fsp.mkdir(outputDir, { recursive: true });
|
|
556
|
+
let zipOutputDir = outputDir;
|
|
557
|
+
if (params.zip) {
|
|
558
|
+
const resolvedOutputDir = path.resolve(outputDir);
|
|
559
|
+
if (resolvedOutputDir !== path.parse(resolvedOutputDir).root) zipOutputDir = outputDir.replace(path.sep === "\\" ? /[\\/]+$/ : /\/+$/, "");
|
|
560
|
+
}
|
|
561
|
+
const zipFile = params.zip ? `${zipOutputDir.replace(/\/$/, "")}.zip` : void 0;
|
|
562
|
+
const fileNames = googleMeetExportFileNames();
|
|
563
|
+
const files = [
|
|
564
|
+
{
|
|
565
|
+
name: "summary.md",
|
|
566
|
+
content: `${renderArtifactsMarkdown(params.artifacts)}\n${renderAttendanceMarkdown(params.attendance)}`
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
name: "attendance.csv",
|
|
570
|
+
content: renderAttendanceCsv(params.attendance)
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
name: "transcript.md",
|
|
574
|
+
content: renderTranscriptMarkdown(params.artifacts)
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
name: "artifacts.json",
|
|
578
|
+
content: `${JSON.stringify(params.artifacts, null, 2)}\n`
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
name: "attendance.json",
|
|
582
|
+
content: `${JSON.stringify(params.attendance, null, 2)}\n`
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
name: "manifest.json",
|
|
586
|
+
content: `${JSON.stringify(buildGoogleMeetExportManifest({
|
|
587
|
+
artifacts: params.artifacts,
|
|
588
|
+
attendance: params.attendance,
|
|
589
|
+
files: fileNames,
|
|
590
|
+
...params.request ? { request: params.request } : {},
|
|
591
|
+
...params.tokenSource ? { tokenSource: params.tokenSource } : {},
|
|
592
|
+
...params.calendarEvent ? { calendarEvent: params.calendarEvent } : {},
|
|
593
|
+
...zipFile ? { zipFile } : {}
|
|
594
|
+
}), null, 2)}\n`
|
|
595
|
+
}
|
|
596
|
+
];
|
|
597
|
+
for (const file of files) await publishMeetExportFile(path.join(outputDir, file.name), file.content);
|
|
598
|
+
const result = {
|
|
599
|
+
outputDir,
|
|
600
|
+
files: files.map((file) => path.join(outputDir, file.name))
|
|
601
|
+
};
|
|
602
|
+
if (zipFile) {
|
|
603
|
+
const zip = new JSZip();
|
|
604
|
+
for (const file of files) zip.file(file.name, file.content);
|
|
605
|
+
await publishMeetExportFile(zipFile, await zip.generateAsync({ type: "nodebuffer" }));
|
|
606
|
+
result.zipFile = zipFile;
|
|
607
|
+
}
|
|
608
|
+
return result;
|
|
609
|
+
}
|
|
610
|
+
async function exportGoogleMeetBundle(params) {
|
|
611
|
+
const metadata = {
|
|
612
|
+
...params.calendarEvent ? { calendarEvent: params.calendarEvent } : {},
|
|
613
|
+
tokenSource: params.tokenSource
|
|
614
|
+
};
|
|
615
|
+
if (params.dryRun) return {
|
|
616
|
+
dryRun: true,
|
|
617
|
+
manifest: buildGoogleMeetExportManifest({
|
|
618
|
+
artifacts: params.artifacts,
|
|
619
|
+
attendance: params.attendance,
|
|
620
|
+
files: googleMeetExportFileNames(),
|
|
621
|
+
request: params.request,
|
|
622
|
+
...metadata
|
|
623
|
+
}),
|
|
624
|
+
...metadata
|
|
625
|
+
};
|
|
626
|
+
return {
|
|
627
|
+
...await writeMeetExportBundle(params),
|
|
628
|
+
...metadata
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
//#endregion
|
|
632
|
+
export { writeSetupStatus as C, writeRecoverCurrentTabResult as S, writeStdoutLine as T, promptInput as _, renderAttendanceCsv as a, writeDoctorStatus as b, writeCalendarEventsSummary as c, parseGoogleMeetBrowserTransport as d, parseGoogleMeetMode as f, parsePositiveNumber as g, parsePositiveIntegerOption as h, renderArtifactsSummary as i, writeLatestConferenceRecordSummary as l, parseOptionalNumber as m, exportGoogleMeetBundle as n, renderAttendanceMarkdown as o, parseGoogleMeetTransport as p, renderArtifactsMarkdown as r, renderAttendanceSummary as s, cli_export_exports as t, callGoogleMeetGateway as u, resolveGoogleMeetOAuthCallbackTimeoutMs as v, writeStdoutJson as w, writeLeaveResult as x, writeCliOutput as y };
|