#!/usr/bin/env node import { google } from 'googleapis'; import minimist from 'minimist'; import { getAuthClient, parseAccountArg } from './auth/auth-utils.js'; import { logAction } from './action-logger.js'; async function updateEvent(args) { // Validate required args if (!args.id && !args.eventId) { throw new Error('Missing required argument: --id or --eventId (event ID)'); } // Get authenticated client for specified account (or default) const accountId = parseAccountArg(args); const oauth2Client = await getAuthClient(accountId); const calendar = google.calendar({ version: 'v3', auth: oauth2Client }); const eventId = args.id || args.eventId; const calendarId = args.calendar || 'primary'; // Build update object with only provided fields const updates = {}; if (args.summary || args.title) { updates.summary = args.summary || args.title; } if (args.description || args.desc) { updates.description = args.description || args.desc; } if (args.location || args.loc) { updates.location = args.location || args.loc; } // Handle time updates if (args.start || args.end) { const timezone = args.timezone || args.tz || 'America/Los_Angeles'; if (args.start) { updates.start = { dateTime: args.start, timeZone: timezone }; } if (args.end) { updates.end = { dateTime: args.end, timeZone: timezone }; } } // Handle attendees update if (args.attendees) { updates.attendees = args.attendees.split(',').map(email => ({ email: email.trim() })); } // Handle adding attendees (preserves existing) if (args.addAttendees) { // First get current event to preserve existing attendees const current = await calendar.events.get({ calendarId, eventId }); const existingAttendees = current.data.attendees || []; const newAttendees = args.addAttendees.split(',').map(email => ({ email: email.trim() })); updates.attendees = [...existingAttendees, ...newAttendees]; } // Handle removing attendees if (args.removeAttendees) { const current = await calendar.events.get({ calendarId, eventId }); const existingAttendees = current.data.attendees || []; const toRemove = args.removeAttendees.split(',').map(e => e.trim().toLowerCase()); updates.attendees = existingAttendees.filter( att => !toRemove.includes(att.email.toLowerCase()) ); } // Optional color if (args.colorId) { updates.colorId = args.colorId; } // Optional visibility if (args.visibility) { updates.visibility = args.visibility; } // Optional status (confirmed, tentative, cancelled) if (args.status) { updates.status = args.status; } // Check if any updates were provided if (Object.keys(updates).length === 0) { throw new Error('No update fields provided. Use --summary, --description, --location, --start, --end, --attendees, etc.'); } // Use patch for partial updates (more efficient) const result = await calendar.events.patch({ calendarId, eventId, resource: updates }); return { success: true, eventId: result.data.id, htmlLink: result.data.htmlLink, summary: result.data.summary, start: result.data.start, end: result.data.end, location: result.data.location, attendees: result.data.attendees, updated: result.data.updated }; } // Main execution const args = minimist(process.argv.slice(2)); const startTime = Date.now(); updateEvent(args) .then(result => { // Log the action logAction('update_event', args, result, { account: args.account || 'default', duration: Date.now() - startTime }); console.log(JSON.stringify(result, null, 2)); }) .catch(error => { const errorResult = { success: false, error: error.message }; // Log the failed action logAction('update_event', args, errorResult, { account: args.account || 'default', duration: Date.now() - startTime, failed: true }); console.error(JSON.stringify(errorResult, null, 2)); process.exit(1); });