diff --git a/workspace-server/src/index.ts b/workspace-server/src/index.ts index 674d678..f4066cb 100644 --- a/workspace-server/src/index.ts +++ b/workspace-server/src/index.ts @@ -532,6 +532,29 @@ async function main() { driveService.downloadFile, ); + server.registerTool( + 'drive.copy', + { + description: + 'Copies a file in Google Drive. Useful for creating documents from templates. Returns the new file ID and URL.', + inputSchema: { + fileId: z + .string() + .describe( + 'The ID of the file to copy. Can be extracted from a Google Drive URL.', + ), + name: z.string().describe('The name for the new copied file.'), + folderId: z + .string() + .optional() + .describe( + 'Optional folder ID to place the copy in. If not specified, the copy is placed in the same location as the original.', + ), + }, + }, + driveService.copyFile, + ); + server.registerTool( 'drive.moveFile', { diff --git a/workspace-server/src/services/DriveService.ts b/workspace-server/src/services/DriveService.ts index 8561b61..1b051b8 100644 --- a/workspace-server/src/services/DriveService.ts +++ b/workspace-server/src/services/DriveService.ts @@ -98,6 +98,7 @@ export class DriveService { ); try { const drive = await this.getDriveClient(); + const id = extractDocumentId(fileId); const fileMetadata: drive_v3.Schema$File = { name: name, mimeType: 'application/vnd.google-apps.folder', @@ -157,6 +158,7 @@ export class DriveService { sharedWithMe?: boolean; }) => { const drive = await this.getDriveClient(); + const id = extractDocumentId(fileId); let q = query; let isProcessed = false; @@ -209,7 +211,7 @@ export class DriveService { logToFile(`Extracted File ID from URL: ${fileId}, using files.get`); try { const res = await drive.files.get({ - fileId: fileId, + fileId: id, fields: 'id, name, modifiedTime, viewedByMeTime, mimeType, parents', supportsAllDrives: true, @@ -361,6 +363,7 @@ export class DriveService { try { const drive = await this.getDriveClient(); const id = extractDocumentId(fileId); + const id = extractDocumentId(fileId); const file = await drive.files.update({ fileId: id, @@ -398,6 +401,7 @@ export class DriveService { try { const drive = await this.getDriveClient(); const id = extractDocumentId(fileId); + const id = extractDocumentId(fileId); const file = await drive.files.update({ fileId: id, @@ -428,6 +432,7 @@ export class DriveService { try { const drive = await this.getDriveClient(); const id = extractDocumentId(fileId); + const id = extractDocumentId(fileId); const res = await drive.comments.list({ fileId: id, fields: @@ -467,6 +472,7 @@ export class DriveService { try { const drive = await this.getDriveClient(); const id = extractDocumentId(fileId); + const id = extractDocumentId(fileId); let targetFolderId = folderId; @@ -531,6 +537,56 @@ export class DriveService { } }; + public copyFile = async ({ + fileId, + name, + folderId, + }: { + fileId: string; + name: string; + folderId?: string; + }) => { + logToFile( + `Copying Drive file ${fileId} with new name: ${name}${folderId ? ` to folder: ${folderId}` : ''}`, + ); + try { + const drive = await this.getDriveClient(); + const id = extractDocumentId(fileId); + + const requestBody: drive_v3.Schema$File = { name }; + if (folderId) { + requestBody.parents = [folderId]; + } + + const copy = await drive.files.copy({ + fileId: id, + requestBody: requestBody, + fields: 'id, name, mimeType, webViewLink', + supportsAllDrives: true, + }); + + logToFile( + `Successfully copied file: ${copy.data.name} (${copy.data.id})`, + ); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify({ + id: copy.data.id, + name: copy.data.name, + mimeType: copy.data.mimeType, + webViewLink: copy.data.webViewLink, + }), + }, + ], + }; + } catch (error) { + return this.handleError('drive.copyFile', error); + } + }; + public downloadFile = async ({ fileId, localPath, @@ -542,6 +598,7 @@ export class DriveService { try { const drive = await this.getDriveClient(); const id = extractDocumentId(fileId); + const id = extractDocumentId(fileId); // 1. Check if it's a Google Doc (special handling required, export instead of download) const metadata = await drive.files.get({