/**
* handlers/reminderHandlers.ts
* Handlers for reminder task operations
*/
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
import type { RemindersToolArgs } from '../../types/index.js';
import { handleAsyncOperation } from '../../utils/errorHandling.js';
import { formatMultilineNotes } from '../../utils/helpers.js';
import { reminderRepository } from '../../utils/reminderRepository.js';
import {
CreateReminderSchema,
DeleteReminderSchema,
ReadRemindersSchema,
UpdateReminderSchema,
} from '../../validation/schemas.js';
import {
extractAndValidateArgs,
formatDeleteMessage,
formatListMarkdown,
formatSuccessMessage,
} from './shared.js';
/**
* Formats a reminder object as markdown list items
*/
const formatReminderMarkdown = (reminder: {
title: string;
isCompleted: boolean;
list?: string;
id?: string;
notes?: string;
dueDate?: string;
url?: string;
}): string[] => {
const lines: string[] = [];
const checkbox = reminder.isCompleted ? '[x]' : '[ ]';
lines.push(`- ${checkbox} ${reminder.title}`);
if (reminder.list) lines.push(` - List: ${reminder.list}`);
if (reminder.id) lines.push(` - ID: ${reminder.id}`);
if (reminder.notes)
lines.push(` - Notes: ${formatMultilineNotes(reminder.notes)}`);
if (reminder.dueDate) lines.push(` - Due: ${reminder.dueDate}`);
if (reminder.url) lines.push(` - URL: ${reminder.url}`);
return lines;
};
export const handleCreateReminder = async (
args: RemindersToolArgs,
): Promise<CallToolResult> => {
return handleAsyncOperation(async () => {
const validatedArgs = extractAndValidateArgs(args, CreateReminderSchema);
const reminder = await reminderRepository.createReminder({
title: validatedArgs.title,
notes: validatedArgs.note,
url: validatedArgs.url,
list: validatedArgs.targetList,
dueDate: validatedArgs.dueDate,
});
return formatSuccessMessage(
'created',
'reminder',
reminder.title,
reminder.id,
);
}, 'create reminder');
};
export const handleUpdateReminder = async (
args: RemindersToolArgs,
): Promise<CallToolResult> => {
return handleAsyncOperation(async () => {
const validatedArgs = extractAndValidateArgs(args, UpdateReminderSchema);
const reminder = await reminderRepository.updateReminder({
id: validatedArgs.id,
newTitle: validatedArgs.title,
notes: validatedArgs.note,
url: validatedArgs.url,
isCompleted: validatedArgs.completed,
list: validatedArgs.targetList,
dueDate: validatedArgs.dueDate,
});
return formatSuccessMessage(
'updated',
'reminder',
reminder.title,
reminder.id,
);
}, 'update reminder');
};
export const handleDeleteReminder = async (
args: RemindersToolArgs,
): Promise<CallToolResult> => {
return handleAsyncOperation(async () => {
const validatedArgs = extractAndValidateArgs(args, DeleteReminderSchema);
await reminderRepository.deleteReminder(validatedArgs.id);
return formatDeleteMessage('reminder', validatedArgs.id, {
useQuotes: false,
useIdPrefix: true,
usePeriod: false,
});
}, 'delete reminder');
};
export const handleReadReminders = async (
args: RemindersToolArgs,
): Promise<CallToolResult> => {
return handleAsyncOperation(async () => {
const validatedArgs = extractAndValidateArgs(args, ReadRemindersSchema);
// Check if id is provided in args (before validation)
// because id might be filtered out by schema validation if it's optional
if (args.id) {
const reminder = await reminderRepository.findReminderById(args.id);
const markdownLines: string[] = [
'### Reminder',
'',
...formatReminderMarkdown(reminder),
];
return markdownLines.join('\n');
}
// Otherwise, return all matching reminders
const reminders = await reminderRepository.findReminders({
list: validatedArgs.filterList,
showCompleted: validatedArgs.showCompleted,
search: validatedArgs.search,
dueWithin: validatedArgs.dueWithin,
});
return formatListMarkdown(
'Reminders',
reminders,
formatReminderMarkdown,
'No reminders found matching the criteria.',
);
}, 'read reminders');
};