Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions src/tools/event-crud-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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: {
Expand Down Expand Up @@ -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'],
},
Expand All @@ -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
Expand All @@ -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,
};
Expand Down Expand Up @@ -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) {
Expand All @@ -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: {
Expand Down Expand Up @@ -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'],
},
Expand All @@ -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 },
}
);

Expand All @@ -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,
};

Expand Down
2 changes: 2 additions & 0 deletions src/tools/event-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down
28 changes: 25 additions & 3 deletions src/types/timetree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<typeof UpdateEventInputSchema>;
Expand Down Expand Up @@ -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<typeof CreateEventToolInputSchema>;
Expand All @@ -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<typeof UpdateEventToolInputSchema>;
Expand Down