#!/usr/bin/env node /** * Create a calendar event * * Usage: * node create-event.mjs --title "Meeting" --start "2026-02-03 14:00:00" --end "2026-02-03 15:00:00" */ import { parseArgs } from 'util'; import { createEvent, DEFAULT_CALENDAR_ID, DEFAULT_TIMEZONE } from '../lib/calendar.mjs'; import { resolveNames, getDisplayNameSync } from '../lib/employees.mjs'; const { values } = parseArgs({ options: { title: { type: 'string' }, description: { type: 'string', default: '' }, start: { type: 'string' }, end: { type: 'string' }, attendees: { type: 'string', default: '' }, 'attendee-ids': { type: 'string', default: '' }, location: { type: 'string', default: '' }, timezone: { type: 'string', default: DEFAULT_TIMEZONE }, calendar: { type: 'string', default: DEFAULT_CALENDAR_ID }, help: { type: 'boolean', short: 'h' } } }); if (values.help) { console.log(` Create a Lark calendar event Options: --title Event title (required) --description Event description --start Start time: YYYY-MM-DD HH:MM:SS (required) --end End time: YYYY-MM-DD HH:MM:SS (required) --attendees Comma-separated names (auto-resolved to user_ids) --attendee-ids Comma-separated user_ids directly --location Event location --timezone IANA timezone (default: Asia/Singapore) --calendar Calendar ID (uses default Claw calendar if omitted) -h, --help Show this help Examples: node create-event.mjs --title "Team Sync" --start "2026-02-03 10:00:00" --end "2026-02-03 10:30:00" node create-event.mjs --title "Review" --start "2026-02-03 14:00:00" --end "2026-02-03 15:00:00" --attendees "Boyang,RK,jc" `); process.exit(0); } // Validate required fields if (!values.title) { console.error('Error: --title is required'); process.exit(1); } if (!values.start) { console.error('Error: --start is required'); process.exit(1); } if (!values.end) { console.error('Error: --end is required'); process.exit(1); } // Resolve attendees let attendeeIds = []; if (values['attendee-ids']) { attendeeIds = values['attendee-ids'].split(',').map(s => s.trim()).filter(Boolean); } if (values.attendees) { const names = values.attendees.split(',').map(s => s.trim()).filter(Boolean); const { resolved, unresolved } = resolveNames(names); attendeeIds = [...new Set([...attendeeIds, ...resolved])]; if (unresolved.length > 0) { console.warn(`Warning: Could not resolve names: ${unresolved.join(', ')}`); } } async function main() { try { console.log('Creating event...'); console.log(` Title: ${values.title}`); console.log(` Start: ${values.start}`); console.log(` End: ${values.end}`); console.log(` Timezone: ${values.timezone}`); console.log(` Attendees: ${attendeeIds.map(id => getDisplayNameSync(id)).join(', ') || '(Boyang will be added automatically)'}`); if (values.location) console.log(` Location: ${values.location}`); console.log(''); const result = await createEvent({ title: values.title, description: values.description, startTime: values.start, endTime: values.end, attendeeIds, location: values.location, timezone: values.timezone, calendarId: values.calendar }); console.log('✅ Event created successfully!'); console.log(''); console.log('Event Details:'); console.log(` Event ID: ${result.event.event_id}`); console.log(` Title: ${result.event.summary}`); console.log(` Link: ${result.event.app_link || 'N/A'}`); console.log(` Attendees: ${result.attendeeNames || 'N/A'}`); // Output JSON for programmatic use if (process.env.JSON_OUTPUT) { console.log('\nJSON:'); console.log(JSON.stringify(result, null, 2)); } } catch (error) { console.error('❌ Failed to create event:', error.message); if (error.larkResponse) { console.error('Lark response:', JSON.stringify(error.larkResponse, null, 2)); } process.exit(1); } } main();