mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
feat(google-meet): add export manifests and tool parity
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { PassThrough, Writable } from "node:stream";
|
||||
import type { RealtimeVoiceProviderPlugin } from "openclaw/plugin-sdk/realtime-voice";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
@@ -363,6 +366,7 @@ describe("google-meet plugin", () => {
|
||||
"calendar_events",
|
||||
"artifacts",
|
||||
"attendance",
|
||||
"export",
|
||||
"recover_current_tab",
|
||||
"leave",
|
||||
"speak",
|
||||
@@ -890,6 +894,50 @@ describe("google-meet plugin", () => {
|
||||
expect(result.details.attendance).toEqual([expect.objectContaining({ displayName: "Alice" })]);
|
||||
});
|
||||
|
||||
it("writes export bundles through the tool", async () => {
|
||||
stubMeetArtifactsApi();
|
||||
const tempDir = mkdtempSync(path.join(tmpdir(), "openclaw-google-meet-tool-export-"));
|
||||
const { tools } = setup();
|
||||
const tool = tools[0] as {
|
||||
execute: (
|
||||
id: string,
|
||||
params: unknown,
|
||||
) => Promise<{ details: { files?: string[]; zipFile?: string } }>;
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await tool.execute("id", {
|
||||
action: "export",
|
||||
accessToken: "token",
|
||||
expiresAt: Date.now() + 120_000,
|
||||
conferenceRecord: "rec-1",
|
||||
includeDocumentBodies: true,
|
||||
outputDir: tempDir,
|
||||
zip: true,
|
||||
});
|
||||
|
||||
expect(result.details.files).toEqual(
|
||||
expect.arrayContaining([path.join(tempDir, "manifest.json")]),
|
||||
);
|
||||
expect(result.details.zipFile).toBe(`${tempDir}.zip`);
|
||||
const manifest = JSON.parse(readFileSync(path.join(tempDir, "manifest.json"), "utf8"));
|
||||
expect(manifest).toMatchObject({
|
||||
request: {
|
||||
conferenceRecord: "rec-1",
|
||||
includeDocumentBodies: true,
|
||||
},
|
||||
counts: {
|
||||
attendanceRows: 1,
|
||||
warnings: 0,
|
||||
},
|
||||
files: expect.arrayContaining(["summary.md", "manifest.json"]),
|
||||
});
|
||||
} finally {
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
rmSync(`${tempDir}.zip`, { force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("reports the latest conference record through the tool", async () => {
|
||||
stubMeetArtifactsApi();
|
||||
const { tools } = setup();
|
||||
|
||||
@@ -154,6 +154,7 @@ const GoogleMeetToolSchema = Type.Object({
|
||||
"calendar_events",
|
||||
"artifacts",
|
||||
"attendance",
|
||||
"export",
|
||||
"recover_current_tab",
|
||||
"leave",
|
||||
"speak",
|
||||
@@ -205,13 +206,15 @@ const GoogleMeetToolSchema = Type.Object({
|
||||
includeDocumentBodies: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"For artifacts, export linked transcript and smart-note Google Docs text through Drive.",
|
||||
"For artifacts/export, export linked transcript and smart-note Google Docs text through Drive.",
|
||||
}),
|
||||
),
|
||||
outputDir: Type.Optional(Type.String({ description: "For export, output directory" })),
|
||||
zip: Type.Optional(Type.Boolean({ description: "For export, also write a .zip archive" })),
|
||||
includeAllConferenceRecords: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"For artifacts or attendance with meeting input, fetch all conference records instead of only the latest.",
|
||||
"For artifacts, attendance, or export with meeting input, fetch all conference records instead of only the latest.",
|
||||
}),
|
||||
),
|
||||
mergeDuplicateParticipants: Type.Optional(
|
||||
@@ -374,6 +377,73 @@ async function resolveArtifactQueryFromParams(
|
||||
};
|
||||
}
|
||||
|
||||
async function exportGoogleMeetBundleFromParams(
|
||||
config: GoogleMeetConfig,
|
||||
raw: Record<string, unknown>,
|
||||
) {
|
||||
const resolved = await resolveArtifactQueryFromParams(config, raw);
|
||||
const [artifacts, attendance] = await Promise.all([
|
||||
fetchGoogleMeetArtifacts({
|
||||
accessToken: resolved.token.accessToken,
|
||||
meeting: resolved.meeting,
|
||||
conferenceRecord: resolved.conferenceRecord,
|
||||
pageSize: resolved.pageSize,
|
||||
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
||||
includeDocumentBodies: resolved.includeDocumentBodies,
|
||||
allConferenceRecords: resolved.allConferenceRecords,
|
||||
}),
|
||||
fetchGoogleMeetAttendance({
|
||||
accessToken: resolved.token.accessToken,
|
||||
meeting: resolved.meeting,
|
||||
conferenceRecord: resolved.conferenceRecord,
|
||||
pageSize: resolved.pageSize,
|
||||
allConferenceRecords: resolved.allConferenceRecords,
|
||||
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
||||
lateAfterMinutes: resolved.lateAfterMinutes,
|
||||
earlyBeforeMinutes: resolved.earlyBeforeMinutes,
|
||||
}),
|
||||
]);
|
||||
const { writeMeetExportBundle } = await import("./src/cli.js");
|
||||
const calendarId = normalizeOptionalString(raw.calendarId);
|
||||
const request = {
|
||||
...(resolved.meeting ? { meeting: resolved.meeting } : {}),
|
||||
...(resolved.conferenceRecord ? { conferenceRecord: resolved.conferenceRecord } : {}),
|
||||
...(resolved.calendarEvent?.event.id
|
||||
? { calendarEventId: resolved.calendarEvent.event.id }
|
||||
: {}),
|
||||
...(resolved.calendarEvent?.event.summary
|
||||
? { calendarEventSummary: resolved.calendarEvent.event.summary }
|
||||
: {}),
|
||||
...(calendarId ? { calendarId } : {}),
|
||||
...(resolved.pageSize !== undefined ? { pageSize: resolved.pageSize } : {}),
|
||||
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
||||
includeDocumentBodies: resolved.includeDocumentBodies,
|
||||
allConferenceRecords: resolved.allConferenceRecords,
|
||||
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
||||
...(resolved.lateAfterMinutes !== undefined
|
||||
? { lateAfterMinutes: resolved.lateAfterMinutes }
|
||||
: {}),
|
||||
...(resolved.earlyBeforeMinutes !== undefined
|
||||
? { earlyBeforeMinutes: resolved.earlyBeforeMinutes }
|
||||
: {}),
|
||||
};
|
||||
const outputDir = normalizeOptionalString(raw.outputDir) ?? normalizeOptionalString(raw.output);
|
||||
const bundle = await writeMeetExportBundle({
|
||||
...(outputDir ? { outputDir } : {}),
|
||||
artifacts,
|
||||
attendance,
|
||||
zip: raw.zip === true,
|
||||
request,
|
||||
tokenSource: resolved.token.refreshed ? "refresh-token" : "cached-access-token",
|
||||
...(resolved.calendarEvent ? { calendarEvent: resolved.calendarEvent } : {}),
|
||||
});
|
||||
return {
|
||||
...bundle,
|
||||
...(resolved.calendarEvent ? { calendarEvent: resolved.calendarEvent } : {}),
|
||||
tokenSource: resolved.token.refreshed ? "refresh-token" : "cached-access-token",
|
||||
};
|
||||
}
|
||||
|
||||
export default definePluginEntry({
|
||||
id: "google-meet",
|
||||
name: "Google Meet",
|
||||
@@ -579,6 +649,17 @@ export default definePluginEntry({
|
||||
},
|
||||
);
|
||||
|
||||
api.registerGatewayMethod(
|
||||
"googlemeet.export",
|
||||
async ({ params, respond }: GatewayRequestHandlerOptions) => {
|
||||
try {
|
||||
respond(true, await exportGoogleMeetBundleFromParams(config, asParamRecord(params)));
|
||||
} catch (err) {
|
||||
sendError(respond, err);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
api.registerGatewayMethod(
|
||||
"googlemeet.leave",
|
||||
async ({ params, respond }: GatewayRequestHandlerOptions) => {
|
||||
@@ -767,6 +848,9 @@ export default definePluginEntry({
|
||||
}),
|
||||
);
|
||||
}
|
||||
case "export": {
|
||||
return json(await exportGoogleMeetBundleFromParams(config, raw));
|
||||
}
|
||||
case "leave": {
|
||||
const rt = await ensureRuntime();
|
||||
const sessionId = normalizeOptionalString(raw.sessionId);
|
||||
|
||||
@@ -55,7 +55,7 @@ function requestUrl(input: RequestInfo | URL): URL {
|
||||
return new URL(input.url);
|
||||
}
|
||||
|
||||
function stubMeetArtifactsApi() {
|
||||
function stubMeetArtifactsApi(options: { failSmartNoteDocumentBody?: boolean } = {}) {
|
||||
vi.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(async (input: RequestInfo | URL) => {
|
||||
@@ -173,6 +173,9 @@ function stubMeetArtifactsApi() {
|
||||
});
|
||||
}
|
||||
if (url.pathname === "/drive/v3/files/notes-1/export") {
|
||||
if (options.failSmartNoteDocumentBody) {
|
||||
return new Response("insufficientPermissions", { status: 403 });
|
||||
}
|
||||
return new Response("Smart note document body.", {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
@@ -516,6 +519,26 @@ describe("google-meet CLI", () => {
|
||||
expect(readFileSync(path.join(tempDir, "transcript.md"), "utf8")).toContain(
|
||||
"Transcript document body.",
|
||||
);
|
||||
const manifest = JSON.parse(readFileSync(path.join(tempDir, "manifest.json"), "utf8"));
|
||||
expect(manifest).toMatchObject({
|
||||
request: {
|
||||
conferenceRecord: "rec-1",
|
||||
includeDocumentBodies: true,
|
||||
},
|
||||
tokenSource: "cached-access-token",
|
||||
counts: {
|
||||
attendanceRows: 1,
|
||||
warnings: 0,
|
||||
},
|
||||
files: expect.arrayContaining([
|
||||
"summary.md",
|
||||
"attendance.csv",
|
||||
"transcript.md",
|
||||
"artifacts.json",
|
||||
"attendance.json",
|
||||
"manifest.json",
|
||||
]),
|
||||
});
|
||||
expect(JSON.parse(readFileSync(path.join(tempDir, "artifacts.json"), "utf8"))).toMatchObject({
|
||||
conferenceRecords: [{ name: "conferenceRecords/rec-1" }],
|
||||
artifacts: [{ transcripts: [{ documentText: "Transcript document body." }] }],
|
||||
@@ -528,6 +551,49 @@ describe("google-meet CLI", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("includes artifact warnings in export summaries and manifests", async () => {
|
||||
stubMeetArtifactsApi({ failSmartNoteDocumentBody: true });
|
||||
const stdout = captureStdout();
|
||||
const tempDir = mkdtempSync(path.join(tmpdir(), "openclaw-google-meet-export-warning-"));
|
||||
|
||||
try {
|
||||
await setupCli({}).parseAsync(
|
||||
[
|
||||
"googlemeet",
|
||||
"export",
|
||||
"--access-token",
|
||||
"token",
|
||||
"--expires-at",
|
||||
String(Date.now() + 120_000),
|
||||
"--conference-record",
|
||||
"rec-1",
|
||||
"--include-doc-bodies",
|
||||
"--output",
|
||||
tempDir,
|
||||
"--json",
|
||||
],
|
||||
{ from: "user" },
|
||||
);
|
||||
const summary = readFileSync(path.join(tempDir, "summary.md"), "utf8");
|
||||
expect(summary).toContain("### Warnings");
|
||||
expect(summary).toContain("Document body warning");
|
||||
const manifest = JSON.parse(readFileSync(path.join(tempDir, "manifest.json"), "utf8"));
|
||||
expect(manifest).toMatchObject({
|
||||
counts: { warnings: 1 },
|
||||
warnings: [
|
||||
{
|
||||
type: "smart_note_document_body",
|
||||
conferenceRecord: "conferenceRecords/rec-1",
|
||||
resource: "conferenceRecords/rec-1/smartNotes/sn1",
|
||||
},
|
||||
],
|
||||
});
|
||||
} finally {
|
||||
stdout.restore();
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("prints human-readable session doctor output", async () => {
|
||||
const stdout = captureStdout();
|
||||
try {
|
||||
|
||||
@@ -75,6 +75,57 @@ type MeetArtifactOptions = ResolveSpaceOptions & {
|
||||
output?: string;
|
||||
};
|
||||
|
||||
export type GoogleMeetExportRequest = {
|
||||
meeting?: string;
|
||||
conferenceRecord?: string;
|
||||
calendarEventId?: string;
|
||||
calendarEventSummary?: string;
|
||||
calendarId?: string;
|
||||
pageSize?: number;
|
||||
includeTranscriptEntries?: boolean;
|
||||
includeDocumentBodies?: boolean;
|
||||
allConferenceRecords?: boolean;
|
||||
mergeDuplicateParticipants?: boolean;
|
||||
lateAfterMinutes?: number;
|
||||
earlyBeforeMinutes?: number;
|
||||
};
|
||||
|
||||
export type GoogleMeetExportWarning = {
|
||||
type:
|
||||
| "smart_notes"
|
||||
| "transcript_entries"
|
||||
| "transcript_document_body"
|
||||
| "smart_note_document_body";
|
||||
conferenceRecord: string;
|
||||
resource?: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type GoogleMeetExportManifest = {
|
||||
generatedAt: string;
|
||||
request?: GoogleMeetExportRequest;
|
||||
tokenSource?: "cached-access-token" | "refresh-token";
|
||||
calendarEvent?: GoogleMeetCalendarLookupResult;
|
||||
inputs: {
|
||||
artifacts?: string;
|
||||
attendance?: string;
|
||||
};
|
||||
counts: {
|
||||
conferenceRecords: number;
|
||||
artifacts: number;
|
||||
attendanceRows: number;
|
||||
recordings: number;
|
||||
transcripts: number;
|
||||
transcriptEntries: number;
|
||||
smartNotes: number;
|
||||
warnings: number;
|
||||
};
|
||||
conferenceRecords: string[];
|
||||
files: string[];
|
||||
zipFile?: string;
|
||||
warnings: GoogleMeetExportWarning[];
|
||||
};
|
||||
|
||||
type SetupOptions = {
|
||||
json?: boolean;
|
||||
};
|
||||
@@ -601,6 +652,9 @@ function writeArtifactsSummary(result: GoogleMeetArtifactsResult): void {
|
||||
}
|
||||
for (const transcript of entry.transcripts) {
|
||||
writeStdoutLine("- transcript: %s", transcript.name);
|
||||
if (transcript.documentTextError) {
|
||||
writeStdoutLine("- transcript document body warning: %s", transcript.documentTextError);
|
||||
}
|
||||
}
|
||||
for (const transcriptEntries of entry.transcriptEntries) {
|
||||
if (transcriptEntries.entriesError) {
|
||||
@@ -613,6 +667,9 @@ function writeArtifactsSummary(result: GoogleMeetArtifactsResult): void {
|
||||
}
|
||||
for (const smartNote of entry.smartNotes) {
|
||||
writeStdoutLine("- smart note: %s", smartNote.name);
|
||||
if (smartNote.documentTextError) {
|
||||
writeStdoutLine("- smart note document body warning: %s", smartNote.documentTextError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -735,6 +792,18 @@ function renderArtifactsMarkdown(result: GoogleMeetArtifactsResult): string {
|
||||
)}`,
|
||||
);
|
||||
pushMarkdownLine(lines, `Smart notes: ${entry.smartNotes.length}`);
|
||||
const warnings = collectGoogleMeetArtifactWarnings({
|
||||
conferenceRecords: [entry.conferenceRecord],
|
||||
artifacts: [entry],
|
||||
});
|
||||
if (warnings.length > 0) {
|
||||
pushMarkdownLine(lines);
|
||||
pushMarkdownLine(lines, "### Warnings");
|
||||
for (const warning of warnings) {
|
||||
const resource = warning.resource ? `${warning.resource}: ` : "";
|
||||
pushMarkdownLine(lines, `- ${resource}${warning.message}`);
|
||||
}
|
||||
}
|
||||
if (entry.recordings.length > 0) {
|
||||
pushMarkdownLine(lines);
|
||||
pushMarkdownLine(lines, "### Recordings");
|
||||
@@ -935,6 +1004,107 @@ function renderTranscriptMarkdown(result: GoogleMeetArtifactsResult): string {
|
||||
return `${lines.join("\n")}\n`;
|
||||
}
|
||||
|
||||
export function collectGoogleMeetArtifactWarnings(
|
||||
result: GoogleMeetArtifactsResult,
|
||||
): GoogleMeetExportWarning[] {
|
||||
const warnings: GoogleMeetExportWarning[] = [];
|
||||
for (const entry of result.artifacts) {
|
||||
const conferenceRecord = entry.conferenceRecord.name;
|
||||
if (entry.smartNotesError) {
|
||||
warnings.push({
|
||||
type: "smart_notes",
|
||||
conferenceRecord,
|
||||
message: entry.smartNotesError,
|
||||
});
|
||||
}
|
||||
for (const transcriptEntries of entry.transcriptEntries) {
|
||||
if (transcriptEntries.entriesError) {
|
||||
warnings.push({
|
||||
type: "transcript_entries",
|
||||
conferenceRecord,
|
||||
resource: transcriptEntries.transcript,
|
||||
message: transcriptEntries.entriesError,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const transcript of entry.transcripts) {
|
||||
if (transcript.documentTextError) {
|
||||
warnings.push({
|
||||
type: "transcript_document_body",
|
||||
conferenceRecord,
|
||||
resource: transcript.name,
|
||||
message: transcript.documentTextError,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const smartNote of entry.smartNotes) {
|
||||
if (smartNote.documentTextError) {
|
||||
warnings.push({
|
||||
type: "smart_note_document_body",
|
||||
conferenceRecord,
|
||||
resource: smartNote.name,
|
||||
message: smartNote.documentTextError,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function buildGoogleMeetExportManifest(params: {
|
||||
artifacts: GoogleMeetArtifactsResult;
|
||||
attendance: GoogleMeetAttendanceResult;
|
||||
files: string[];
|
||||
request?: GoogleMeetExportRequest;
|
||||
tokenSource?: "cached-access-token" | "refresh-token";
|
||||
calendarEvent?: GoogleMeetCalendarLookupResult;
|
||||
zipFile?: string;
|
||||
}): GoogleMeetExportManifest {
|
||||
const transcriptEntryCount = params.artifacts.artifacts.reduce(
|
||||
(count, entry) =>
|
||||
count +
|
||||
entry.transcriptEntries.reduce(
|
||||
(entryCount, transcript) => entryCount + transcript.entries.length,
|
||||
0,
|
||||
),
|
||||
0,
|
||||
);
|
||||
const warnings = collectGoogleMeetArtifactWarnings(params.artifacts);
|
||||
return {
|
||||
generatedAt: new Date().toISOString(),
|
||||
...(params.request ? { request: params.request } : {}),
|
||||
...(params.tokenSource ? { tokenSource: params.tokenSource } : {}),
|
||||
...(params.calendarEvent ? { calendarEvent: params.calendarEvent } : {}),
|
||||
inputs: {
|
||||
...(params.artifacts.input ? { artifacts: params.artifacts.input } : {}),
|
||||
...(params.attendance.input ? { attendance: params.attendance.input } : {}),
|
||||
},
|
||||
counts: {
|
||||
conferenceRecords: params.artifacts.conferenceRecords.length,
|
||||
artifacts: params.artifacts.artifacts.length,
|
||||
attendanceRows: params.attendance.attendance.length,
|
||||
recordings: params.artifacts.artifacts.reduce(
|
||||
(count, entry) => count + entry.recordings.length,
|
||||
0,
|
||||
),
|
||||
transcripts: params.artifacts.artifacts.reduce(
|
||||
(count, entry) => count + entry.transcripts.length,
|
||||
0,
|
||||
),
|
||||
transcriptEntries: transcriptEntryCount,
|
||||
smartNotes: params.artifacts.artifacts.reduce(
|
||||
(count, entry) => count + entry.smartNotes.length,
|
||||
0,
|
||||
),
|
||||
warnings: warnings.length,
|
||||
},
|
||||
conferenceRecords: params.artifacts.conferenceRecords.map((record) => record.name),
|
||||
files: params.files,
|
||||
...(params.zipFile ? { zipFile: params.zipFile } : {}),
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
|
||||
function defaultExportDirectory(): string {
|
||||
return `google-meet-export-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
||||
}
|
||||
@@ -1021,14 +1191,26 @@ function buildZipArchive(files: Array<{ name: string; content: string }>): Buffe
|
||||
return Buffer.concat([...localParts, centralDirectory, end]);
|
||||
}
|
||||
|
||||
async function writeMeetExportBundle(params: {
|
||||
export async function writeMeetExportBundle(params: {
|
||||
outputDir?: string;
|
||||
artifacts: GoogleMeetArtifactsResult;
|
||||
attendance: GoogleMeetAttendanceResult;
|
||||
zip?: boolean;
|
||||
request?: GoogleMeetExportRequest;
|
||||
tokenSource?: "cached-access-token" | "refresh-token";
|
||||
calendarEvent?: GoogleMeetCalendarLookupResult;
|
||||
}): Promise<{ outputDir: string; files: string[]; zipFile?: string }> {
|
||||
const outputDir = params.outputDir?.trim() || defaultExportDirectory();
|
||||
await mkdir(outputDir, { recursive: true });
|
||||
const zipFile = params.zip ? `${outputDir.replace(/\/$/, "")}.zip` : undefined;
|
||||
const fileNames = [
|
||||
"summary.md",
|
||||
"attendance.csv",
|
||||
"transcript.md",
|
||||
"artifacts.json",
|
||||
"attendance.json",
|
||||
"manifest.json",
|
||||
];
|
||||
const files = [
|
||||
{
|
||||
name: "summary.md",
|
||||
@@ -1038,6 +1220,22 @@ async function writeMeetExportBundle(params: {
|
||||
{ name: "transcript.md", content: renderTranscriptMarkdown(params.artifacts) },
|
||||
{ name: "artifacts.json", content: `${JSON.stringify(params.artifacts, null, 2)}\n` },
|
||||
{ name: "attendance.json", content: `${JSON.stringify(params.attendance, null, 2)}\n` },
|
||||
{
|
||||
name: "manifest.json",
|
||||
content: `${JSON.stringify(
|
||||
buildGoogleMeetExportManifest({
|
||||
artifacts: params.artifacts,
|
||||
attendance: params.attendance,
|
||||
files: fileNames,
|
||||
...(params.request ? { request: params.request } : {}),
|
||||
...(params.tokenSource ? { tokenSource: params.tokenSource } : {}),
|
||||
...(params.calendarEvent ? { calendarEvent: params.calendarEvent } : {}),
|
||||
...(zipFile ? { zipFile } : {}),
|
||||
}),
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
},
|
||||
];
|
||||
for (const file of files) {
|
||||
await writeFile(path.join(outputDir, file.name), file.content, "utf8");
|
||||
@@ -1046,8 +1244,7 @@ async function writeMeetExportBundle(params: {
|
||||
outputDir,
|
||||
files: files.map((file) => path.join(outputDir, file.name)),
|
||||
};
|
||||
if (params.zip) {
|
||||
const zipFile = `${outputDir.replace(/\/$/, "")}.zip`;
|
||||
if (zipFile) {
|
||||
await writeFile(zipFile, buildZipArchive(files));
|
||||
result.zipFile = zipFile;
|
||||
}
|
||||
@@ -1648,11 +1845,37 @@ export function registerGoogleMeetCli(params: {
|
||||
lateAfterMinutes: resolved.lateAfterMinutes,
|
||||
earlyBeforeMinutes: resolved.earlyBeforeMinutes,
|
||||
});
|
||||
const resolvedMeeting = meetingResult.meeting ?? resolved.meeting;
|
||||
const request: GoogleMeetExportRequest = {
|
||||
...(resolvedMeeting ? { meeting: resolvedMeeting } : {}),
|
||||
...(resolved.conferenceRecord ? { conferenceRecord: resolved.conferenceRecord } : {}),
|
||||
...(meetingResult.calendarEvent?.event.id
|
||||
? { calendarEventId: meetingResult.calendarEvent.event.id }
|
||||
: {}),
|
||||
...(meetingResult.calendarEvent?.event.summary
|
||||
? { calendarEventSummary: meetingResult.calendarEvent.event.summary }
|
||||
: {}),
|
||||
...(options.calendar ? { calendarId: options.calendar } : {}),
|
||||
...(resolved.pageSize !== undefined ? { pageSize: resolved.pageSize } : {}),
|
||||
includeTranscriptEntries: resolved.includeTranscriptEntries,
|
||||
includeDocumentBodies: resolved.includeDocumentBodies,
|
||||
allConferenceRecords: resolved.allConferenceRecords,
|
||||
mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
|
||||
...(resolved.lateAfterMinutes !== undefined
|
||||
? { lateAfterMinutes: resolved.lateAfterMinutes }
|
||||
: {}),
|
||||
...(resolved.earlyBeforeMinutes !== undefined
|
||||
? { earlyBeforeMinutes: resolved.earlyBeforeMinutes }
|
||||
: {}),
|
||||
};
|
||||
const bundle = await writeMeetExportBundle({
|
||||
outputDir: options.output,
|
||||
artifacts,
|
||||
attendance,
|
||||
zip: Boolean(options.zip),
|
||||
request,
|
||||
tokenSource: token.refreshed ? "refresh-token" : "cached-access-token",
|
||||
...(meetingResult.calendarEvent ? { calendarEvent: meetingResult.calendarEvent } : {}),
|
||||
});
|
||||
const payload = {
|
||||
...bundle,
|
||||
|
||||
Reference in New Issue
Block a user