diff --git a/src/tools/event-crud-tools.ts b/src/tools/event-crud-tools.ts index 1cdda63..76a75fd 100644 --- a/src/tools/event-crud-tools.ts +++ b/src/tools/event-crud-tools.ts @@ -26,6 +26,10 @@ export const CreateEventInputSchema = z.object({ note: z.string().optional().describe('Event notes/description'), location: z.string().optional().describe('Event location'), url: z.string().optional().describe('Related URL'), + checklist: z.array(z.object({ + checked: z.boolean().default(false).describe('Whether the checklist item is checked'), + title: z.string().min(1).describe('Checklist item title'), + })).optional().describe('Checklist items to attach to the event'), }); export function createCreateEventTool(apiClient: TimeTreeAPIClient) { @@ -35,7 +39,8 @@ export function createCreateEventTool(apiClient: TimeTreeAPIClient) { 'Create a new event in a TimeTree calendar. Requires CSRF token (automatically managed). ' + 'Returns the created event with UUID. ' + 'Label colors (label_id 1-10): 1=Emerald green, 2=Modern cyan, 3=Deep sky blue, 4=Pastel brown, ' + - '5=Midnight black, 6=Apple red, 7=French rose, 8=Coral pink, 9=Bright orange, 10=Soft violet.', + '5=Midnight black, 6=Apple red, 7=French rose, 8=Coral pink, 9=Bright orange, 10=Soft violet. ' + + 'Supports attaching checklist items.', inputSchema: { type: 'object', properties: { @@ -94,6 +99,18 @@ export function createCreateEventTool(apiClient: TimeTreeAPIClient) { type: 'string', description: 'Related URL', }, + checklist: { + type: 'array', + description: 'Checklist items to attach to the event', + items: { + type: 'object', + properties: { + checked: { type: 'boolean', description: 'Whether the item is checked' }, + title: { type: 'string', description: 'Checklist item title' }, + }, + required: ['title'], + }, + }, }, required: ['calendar_id', 'title', 'start_at', 'end_at'], }, @@ -117,6 +134,9 @@ export function createCreateEventTool(apiClient: TimeTreeAPIClient) { recurrences: [], alerts: [], file_uuids: [], + attachment: input.checklist + ? { checklist: input.checklist, virtual_user_attendees: [] } + : undefined, }); // Format event for output @@ -135,6 +155,7 @@ export function createCreateEventTool(apiClient: TimeTreeAPIClient) { note: event.note || null, url: event.url || null, category: event.category || null, + checklist: event.attachment?.checklist || null, created_at: event.created_at ? new Date(event.created_at).toISOString() : null, updated_at: event.updated_at ? new Date(event.updated_at).toISOString() : null, }; @@ -257,6 +278,10 @@ export const UpdateEventInputSchema = z.object({ note: z.string().optional().describe('New event notes'), location: z.string().optional().describe('New event location'), url: z.string().optional().describe('New related URL'), + checklist: z.array(z.object({ + checked: z.boolean().default(false).describe('Whether the checklist item is checked'), + title: z.string().min(1).describe('Checklist item title'), + })).optional().describe('Replace the event checklist items'), }); export function createUpdateEventTool(apiClient: TimeTreeAPIClient) { @@ -266,7 +291,8 @@ export function createUpdateEventTool(apiClient: TimeTreeAPIClient) { 'Update an existing event in a TimeTree calendar. Only provide the fields you want to change. ' + 'Requires CSRF token (automatically managed). Returns the updated event. ' + 'Label colors (label_id 1-10): 1=Emerald green, 2=Modern cyan, 3=Deep sky blue, 4=Pastel brown, ' + - '5=Midnight black, 6=Apple red, 7=French rose, 8=Coral pink, 9=Bright orange, 10=Soft violet.', + '5=Midnight black, 6=Apple red, 7=French rose, 8=Coral pink, 9=Bright orange, 10=Soft violet. ' + + 'Supports attaching checklist items.', inputSchema: { type: 'object', properties: { @@ -326,6 +352,18 @@ export function createUpdateEventTool(apiClient: TimeTreeAPIClient) { type: 'string', description: 'New related URL', }, + checklist: { + type: 'array', + description: 'Replace the event checklist items. Use [] to clear the checklist.', + items: { + type: 'object', + properties: { + checked: { type: 'boolean', description: 'Whether the item is checked' }, + title: { type: 'string', description: 'Checklist item title' }, + }, + required: ['title'], + }, + }, }, required: ['calendar_id', 'event_uuid'], }, @@ -352,6 +390,11 @@ export function createUpdateEventTool(apiClient: TimeTreeAPIClient) { note: input.note, location: input.location, url: input.url, + attachment: input.checklist === undefined + ? undefined + : input.checklist.length === 0 + ? null + : { checklist: input.checklist }, } ); @@ -371,6 +414,7 @@ export function createUpdateEventTool(apiClient: TimeTreeAPIClient) { note: event.note || null, url: event.url || null, category: event.category || null, + checklist: event.attachment?.checklist || null, updated_at: event.updated_at ? new Date(event.updated_at).toISOString() : null, }; diff --git a/src/tools/event-tools.ts b/src/tools/event-tools.ts index 329053b..567e429 100644 --- a/src/tools/event-tools.ts +++ b/src/tools/event-tools.ts @@ -104,6 +104,7 @@ export function createGetEventsTool(apiClient: TimeTreeAPIClient) { updated_at: event.updated_at ? new Date(event.updated_at).toISOString() : null, has_alerts: event.alerts && event.alerts.length > 0, has_recurrence: event.recurrences && event.recurrences.length > 0, + checklist: event.attachment?.checklist || null, })); const result = { @@ -256,6 +257,7 @@ export function createGetUpdatedEventsTool(apiClient: TimeTreeAPIClient) { updated_at: event.updated_at ? new Date(event.updated_at).toISOString() : null, has_alerts: event.alerts && event.alerts.length > 0, has_recurrence: event.recurrences && event.recurrences.length > 0, + checklist: event.attachment?.checklist || null, })); const result = { diff --git a/src/types/timetree.ts b/src/types/timetree.ts index 37856c9..2b95bbf 100644 --- a/src/types/timetree.ts +++ b/src/types/timetree.ts @@ -54,6 +54,12 @@ export const EventSchema = z.object({ attendees: z.array(z.number()).optional(), recurrences: z.array(z.any()).optional(), alerts: z.array(z.any()).optional(), + attachment: z.object({ + checklist: z.array(z.object({ + checked: z.boolean().default(false), + title: z.string().min(1), + }).passthrough()).default([]), + }).passthrough().optional().nullable(), created_at: z.number().optional(), updated_at: z.number().optional(), // Allow additional fields but ignore them @@ -110,7 +116,11 @@ export const CreateEventInputSchema = z.object({ alerts: z.array(z.any()).default([]), file_uuids: z.array(z.string()).default([]), attachment: z.object({ - url: z.string().url(), + url: z.string().url().optional(), + checklist: z.array(z.object({ + checked: z.boolean().default(false), + title: z.string().min(1), + }).passthrough()).default([]), virtual_user_attendees: z.array(z.any()).default([]), }).optional(), }).passthrough(); @@ -138,9 +148,13 @@ export const UpdateEventInputSchema = z.object({ alerts: z.array(z.any()).optional(), file_uuids: z.array(z.string()).optional(), attachment: z.object({ - url: z.string().url(), + url: z.string().url().optional(), + checklist: z.array(z.object({ + checked: z.boolean().default(false), + title: z.string().min(1), + }).passthrough()).optional(), virtual_user_attendees: z.array(z.any()).optional(), - }).optional(), + }).optional().nullable(), }).passthrough(); export type UpdateEventInput = z.infer; @@ -183,6 +197,10 @@ export const CreateEventToolInputSchema = z.object({ note: z.string().optional(), location: z.string().optional(), url: z.string().optional(), + checklist: z.array(z.object({ + checked: z.boolean().default(false), + title: z.string().min(1), + }).passthrough()).optional(), }).passthrough(); export type CreateEventToolInput = z.infer; @@ -204,6 +222,10 @@ export const UpdateEventToolInputSchema = z.object({ note: z.string().optional(), location: z.string().optional(), url: z.string().optional(), + checklist: z.array(z.object({ + checked: z.boolean().default(false), + title: z.string().min(1), + }).passthrough()).optional(), }).passthrough(); export type UpdateEventToolInput = z.infer;