mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-22 06:41:46 +00:00
chore: apply prettier on the entire project
This commit is contained in:
+407
-360
@@ -1,398 +1,445 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
|
||||
import { z } from 'zod';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { isDemoUser, getCurrentUser } from '../../services/authService';
|
||||
import {
|
||||
getOwnPlan, getActivePlan, getActivePlanId, getPlanData,
|
||||
updatePlan, setUserColor,
|
||||
sendInvite as sendVacayInvite, acceptInvite, declineInvite, cancelInvite, dissolvePlan,
|
||||
getOwnPlan,
|
||||
getActivePlan,
|
||||
getActivePlanId,
|
||||
getPlanData,
|
||||
updatePlan,
|
||||
setUserColor,
|
||||
sendInvite as sendVacayInvite,
|
||||
acceptInvite,
|
||||
declineInvite,
|
||||
cancelInvite,
|
||||
dissolvePlan,
|
||||
getAvailableUsers,
|
||||
listYears, addYear, deleteYear,
|
||||
getEntries as getVacayEntries, toggleEntry, toggleCompanyHoliday,
|
||||
getStats as getVacayStats, updateStats as updateVacayStats,
|
||||
addHolidayCalendar, updateHolidayCalendar, deleteHolidayCalendar,
|
||||
getCountries as getHolidayCountries, getHolidays,
|
||||
listYears,
|
||||
addYear,
|
||||
deleteYear,
|
||||
getEntries as getVacayEntries,
|
||||
toggleEntry,
|
||||
toggleCompanyHoliday,
|
||||
getStats as getVacayStats,
|
||||
updateStats as updateVacayStats,
|
||||
addHolidayCalendar,
|
||||
updateHolidayCalendar,
|
||||
deleteHolidayCalendar,
|
||||
getCountries as getHolidayCountries,
|
||||
getHolidays,
|
||||
} from '../../services/vacayService';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import {
|
||||
TOOL_ANNOTATIONS_READONLY, TOOL_ANNOTATIONS_WRITE,
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
import {
|
||||
TOOL_ANNOTATIONS_READONLY,
|
||||
TOOL_ANNOTATIONS_WRITE,
|
||||
TOOL_ANNOTATIONS_DELETE,
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied,
|
||||
ok,
|
||||
} from './_shared';
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
export function registerVacayTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'vacay');
|
||||
const W = canWrite(scopes, 'vacay');
|
||||
|
||||
if (isAddonEnabled(ADDON_IDS.VACAY)) {
|
||||
if (R) server.registerTool(
|
||||
'get_vacay_plan',
|
||||
{
|
||||
description: "Get the current user's active vacation plan (own or joined).",
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async () => {
|
||||
const plan = getPlanData(userId);
|
||||
return ok({ plan });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'update_vacay_plan',
|
||||
{
|
||||
description: 'Update vacation plan settings (weekends blocking, holidays, carry-over).',
|
||||
inputSchema: {
|
||||
block_weekends: z.boolean().optional(),
|
||||
holidays_enabled: z.boolean().optional(),
|
||||
holidays_region: z.string().nullable().optional(),
|
||||
company_holidays_enabled: z.boolean().optional(),
|
||||
carry_over_enabled: z.boolean().optional(),
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'get_vacay_plan',
|
||||
{
|
||||
description: "Get the current user's active vacation plan (own or joined).",
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ block_weekends, holidays_enabled, holidays_region, company_holidays_enabled, carry_over_enabled }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
await updatePlan(planId, { block_weekends, holidays_enabled, holidays_region, company_holidays_enabled, carry_over_enabled }, undefined);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'set_vacay_color',
|
||||
{
|
||||
description: "Set the current user's color in the vacation plan calendar.",
|
||||
inputSchema: {
|
||||
color: z.string().describe('Hex color e.g. #6366f1'),
|
||||
async () => {
|
||||
const plan = getPlanData(userId);
|
||||
return ok({ plan });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ color }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
setUserColor(userId, planId, color, undefined);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (R) server.registerTool(
|
||||
'get_available_vacay_users',
|
||||
{
|
||||
description: 'List users who can be invited to the current vacation plan.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async () => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const users = getAvailableUsers(userId, planId);
|
||||
return ok({ users });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'send_vacay_invite',
|
||||
{
|
||||
description: 'Invite a user to join the vacation plan by their user ID.',
|
||||
inputSchema: {
|
||||
targetUserId: z.number().int().positive(),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'update_vacay_plan',
|
||||
{
|
||||
description: 'Update vacation plan settings (weekends blocking, holidays, carry-over).',
|
||||
inputSchema: {
|
||||
block_weekends: z.boolean().optional(),
|
||||
holidays_enabled: z.boolean().optional(),
|
||||
holidays_region: z.string().nullable().optional(),
|
||||
company_holidays_enabled: z.boolean().optional(),
|
||||
carry_over_enabled: z.boolean().optional(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ targetUserId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const me = getCurrentUser(userId);
|
||||
if (!me) return { content: [{ type: 'text' as const, text: 'User not found.' }], isError: true };
|
||||
const result = sendVacayInvite(planId, userId, me.username, me.email, targetUserId);
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'accept_vacay_invite',
|
||||
{
|
||||
description: 'Accept a pending invitation to join another user\'s vacation plan.',
|
||||
inputSchema: {
|
||||
planId: z.number().int().positive(),
|
||||
async ({ block_weekends, holidays_enabled, holidays_region, company_holidays_enabled, carry_over_enabled }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
await updatePlan(
|
||||
planId,
|
||||
{ block_weekends, holidays_enabled, holidays_region, company_holidays_enabled, carry_over_enabled },
|
||||
undefined,
|
||||
);
|
||||
return ok({ success: true });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ planId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const result = acceptInvite(userId, planId, undefined);
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'decline_vacay_invite',
|
||||
{
|
||||
description: 'Decline a pending vacation plan invitation.',
|
||||
inputSchema: {
|
||||
planId: z.number().int().positive(),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'set_vacay_color',
|
||||
{
|
||||
description: "Set the current user's color in the vacation plan calendar.",
|
||||
inputSchema: {
|
||||
color: z.string().describe('Hex color e.g. #6366f1'),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ planId }) => {
|
||||
declineInvite(userId, planId, undefined);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'cancel_vacay_invite',
|
||||
{
|
||||
description: 'Cancel an outgoing invitation (owner cancels invite they sent).',
|
||||
inputSchema: {
|
||||
targetUserId: z.number().int().positive(),
|
||||
async ({ color }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
setUserColor(userId, planId, color, undefined);
|
||||
return ok({ success: true });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ targetUserId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
cancelInvite(planId, targetUserId);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'dissolve_vacay_plan',
|
||||
{
|
||||
description: 'Dissolve the shared plan — all members are removed and everyone returns to their own individual plan.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_DELETE,
|
||||
},
|
||||
async () => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
dissolvePlan(userId, undefined);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
|
||||
if (R) server.registerTool(
|
||||
'list_vacay_years',
|
||||
{
|
||||
description: 'List calendar years tracked in the current vacation plan.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async () => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const years = listYears(planId);
|
||||
return ok({ years });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'add_vacay_year',
|
||||
{
|
||||
description: 'Add a calendar year to the vacation plan.',
|
||||
inputSchema: {
|
||||
year: z.number().int().min(2000).max(2100),
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'get_available_vacay_users',
|
||||
{
|
||||
description: 'List users who can be invited to the current vacation plan.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ year }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const years = addYear(planId, year, undefined);
|
||||
return ok({ years });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'delete_vacay_year',
|
||||
{
|
||||
description: 'Remove a calendar year from the vacation plan.',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
async () => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const users = getAvailableUsers(userId, planId);
|
||||
return ok({ users });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_DELETE,
|
||||
},
|
||||
async ({ year }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const years = deleteYear(planId, year, undefined);
|
||||
return ok({ years });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (R) server.registerTool(
|
||||
'get_vacay_entries',
|
||||
{
|
||||
description: 'Get all vacation day entries for a plan and year.',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'send_vacay_invite',
|
||||
{
|
||||
description: 'Invite a user to join the vacation plan by their user ID.',
|
||||
inputSchema: {
|
||||
targetUserId: z.number().int().positive(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async ({ year }) => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const entries = getVacayEntries(planId, String(year));
|
||||
return ok({ entries });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'toggle_vacay_entry',
|
||||
{
|
||||
description: 'Toggle a day on or off as a vacation day for the current user.',
|
||||
inputSchema: {
|
||||
date: z.string().describe('ISO date YYYY-MM-DD'),
|
||||
async ({ targetUserId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const me = getCurrentUser(userId);
|
||||
if (!me) return { content: [{ type: 'text' as const, text: 'User not found.' }], isError: true };
|
||||
const result = sendVacayInvite(planId, userId, me.username, me.email, targetUserId);
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ success: true });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ date }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const result = toggleEntry(userId, planId, date, undefined);
|
||||
return ok(result);
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'toggle_company_holiday',
|
||||
{
|
||||
description: 'Toggle a date as a company holiday for the whole plan.',
|
||||
inputSchema: {
|
||||
date: z.string(),
|
||||
note: z.string().optional(),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'accept_vacay_invite',
|
||||
{
|
||||
description: "Accept a pending invitation to join another user's vacation plan.",
|
||||
inputSchema: {
|
||||
planId: z.number().int().positive(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ date, note }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const result = toggleCompanyHoliday(planId, date, note, undefined);
|
||||
return ok(result);
|
||||
}
|
||||
);
|
||||
|
||||
if (R) server.registerTool(
|
||||
'get_vacay_stats',
|
||||
{
|
||||
description: 'Get vacation statistics for a specific year (days used, remaining, carried over).',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
async ({ planId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const result = acceptInvite(userId, planId, undefined);
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ success: true });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async ({ year }) => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const stats = getVacayStats(planId, year);
|
||||
return ok({ stats });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'update_vacay_stats',
|
||||
{
|
||||
description: 'Update the vacation day allowance for a specific user and year.',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
vacationDays: z.number().int().min(0),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'decline_vacay_invite',
|
||||
{
|
||||
description: 'Decline a pending vacation plan invitation.',
|
||||
inputSchema: {
|
||||
planId: z.number().int().positive(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ year, vacationDays }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
updateVacayStats(userId, planId, year, vacationDays, undefined);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'add_holiday_calendar',
|
||||
{
|
||||
description: 'Add a public holiday calendar (by region code) to the vacation plan.',
|
||||
inputSchema: {
|
||||
region: z.string().describe('Country/region code e.g. US, GB, DE'),
|
||||
label: z.string().nullable().optional(),
|
||||
color: z.string().optional(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
async ({ planId }) => {
|
||||
declineInvite(userId, planId, undefined);
|
||||
return ok({ success: true });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ region, label, color, sortOrder }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const calendar = addHolidayCalendar(planId, region, label ?? null, color, sortOrder, undefined);
|
||||
return ok({ calendar });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'update_holiday_calendar',
|
||||
{
|
||||
description: 'Update label or color for a holiday calendar.',
|
||||
inputSchema: {
|
||||
calendarId: z.number().int().positive(),
|
||||
label: z.string().nullable().optional(),
|
||||
color: z.string().optional(),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'cancel_vacay_invite',
|
||||
{
|
||||
description: 'Cancel an outgoing invitation (owner cancels invite they sent).',
|
||||
inputSchema: {
|
||||
targetUserId: z.number().int().positive(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ calendarId, label, color }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const cal = updateHolidayCalendar(calendarId, planId, { label, color }, undefined);
|
||||
if (!cal) return { content: [{ type: 'text' as const, text: 'Holiday calendar not found.' }], isError: true };
|
||||
return ok({ calendar: cal });
|
||||
}
|
||||
);
|
||||
|
||||
if (W) server.registerTool(
|
||||
'delete_holiday_calendar',
|
||||
{
|
||||
description: 'Remove a holiday calendar from the vacation plan.',
|
||||
inputSchema: {
|
||||
calendarId: z.number().int().positive(),
|
||||
async ({ targetUserId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
cancelInvite(planId, targetUserId);
|
||||
return ok({ success: true });
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_DELETE,
|
||||
},
|
||||
async ({ calendarId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
deleteHolidayCalendar(calendarId, planId, undefined);
|
||||
return ok({ success: true });
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
if (R) server.registerTool(
|
||||
'list_holiday_countries',
|
||||
{
|
||||
description: 'List countries available for public holiday calendars.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async () => {
|
||||
const result = await getHolidayCountries();
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ countries: result.data });
|
||||
}
|
||||
);
|
||||
|
||||
if (R) server.registerTool(
|
||||
'list_holidays',
|
||||
{
|
||||
description: 'List public holidays for a country and year.',
|
||||
inputSchema: {
|
||||
country: z.string().describe('ISO 3166-1 alpha-2 code'),
|
||||
year: z.number().int(),
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'dissolve_vacay_plan',
|
||||
{
|
||||
description:
|
||||
'Dissolve the shared plan — all members are removed and everyone returns to their own individual plan.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_DELETE,
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async ({ country, year }) => {
|
||||
const result = await getHolidays(String(year), country);
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ holidays: result.data });
|
||||
}
|
||||
);
|
||||
async () => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
dissolvePlan(userId, undefined);
|
||||
return ok({ success: true });
|
||||
},
|
||||
);
|
||||
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'list_vacay_years',
|
||||
{
|
||||
description: 'List calendar years tracked in the current vacation plan.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async () => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const years = listYears(planId);
|
||||
return ok({ years });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'add_vacay_year',
|
||||
{
|
||||
description: 'Add a calendar year to the vacation plan.',
|
||||
inputSchema: {
|
||||
year: z.number().int().min(2000).max(2100),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ year }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const years = addYear(planId, year, undefined);
|
||||
return ok({ years });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'delete_vacay_year',
|
||||
{
|
||||
description: 'Remove a calendar year from the vacation plan.',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_DELETE,
|
||||
},
|
||||
async ({ year }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const years = deleteYear(planId, year, undefined);
|
||||
return ok({ years });
|
||||
},
|
||||
);
|
||||
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'get_vacay_entries',
|
||||
{
|
||||
description: 'Get all vacation day entries for a plan and year.',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async ({ year }) => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const entries = getVacayEntries(planId, String(year));
|
||||
return ok({ entries });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'toggle_vacay_entry',
|
||||
{
|
||||
description: 'Toggle a day on or off as a vacation day for the current user.',
|
||||
inputSchema: {
|
||||
date: z.string().describe('ISO date YYYY-MM-DD'),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ date }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const result = toggleEntry(userId, planId, date, undefined);
|
||||
return ok(result);
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'toggle_company_holiday',
|
||||
{
|
||||
description: 'Toggle a date as a company holiday for the whole plan.',
|
||||
inputSchema: {
|
||||
date: z.string(),
|
||||
note: z.string().optional(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ date, note }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const result = toggleCompanyHoliday(planId, date, note, undefined);
|
||||
return ok(result);
|
||||
},
|
||||
);
|
||||
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'get_vacay_stats',
|
||||
{
|
||||
description: 'Get vacation statistics for a specific year (days used, remaining, carried over).',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async ({ year }) => {
|
||||
const planId = getActivePlanId(userId);
|
||||
const stats = getVacayStats(planId, year);
|
||||
return ok({ stats });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'update_vacay_stats',
|
||||
{
|
||||
description: 'Update the vacation day allowance for a specific user and year.',
|
||||
inputSchema: {
|
||||
year: z.number().int(),
|
||||
vacationDays: z.number().int().min(0),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ year, vacationDays }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
updateVacayStats(userId, planId, year, vacationDays, undefined);
|
||||
return ok({ success: true });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'add_holiday_calendar',
|
||||
{
|
||||
description: 'Add a public holiday calendar (by region code) to the vacation plan.',
|
||||
inputSchema: {
|
||||
region: z.string().describe('Country/region code e.g. US, GB, DE'),
|
||||
label: z.string().nullable().optional(),
|
||||
color: z.string().optional(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
},
|
||||
async ({ region, label, color, sortOrder }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const calendar = addHolidayCalendar(planId, region, label ?? null, color, sortOrder, undefined);
|
||||
return ok({ calendar });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'update_holiday_calendar',
|
||||
{
|
||||
description: 'Update label or color for a holiday calendar.',
|
||||
inputSchema: {
|
||||
calendarId: z.number().int().positive(),
|
||||
label: z.string().nullable().optional(),
|
||||
color: z.string().optional(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
},
|
||||
async ({ calendarId, label, color }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
const cal = updateHolidayCalendar(calendarId, planId, { label, color }, undefined);
|
||||
if (!cal) return { content: [{ type: 'text' as const, text: 'Holiday calendar not found.' }], isError: true };
|
||||
return ok({ calendar: cal });
|
||||
},
|
||||
);
|
||||
|
||||
if (W)
|
||||
server.registerTool(
|
||||
'delete_holiday_calendar',
|
||||
{
|
||||
description: 'Remove a holiday calendar from the vacation plan.',
|
||||
inputSchema: {
|
||||
calendarId: z.number().int().positive(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_DELETE,
|
||||
},
|
||||
async ({ calendarId }) => {
|
||||
if (isDemoUser(userId)) return demoDenied();
|
||||
const planId = getActivePlanId(userId);
|
||||
deleteHolidayCalendar(calendarId, planId, undefined);
|
||||
return ok({ success: true });
|
||||
},
|
||||
);
|
||||
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'list_holiday_countries',
|
||||
{
|
||||
description: 'List countries available for public holiday calendars.',
|
||||
inputSchema: {},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async () => {
|
||||
const result = await getHolidayCountries();
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ countries: result.data });
|
||||
},
|
||||
);
|
||||
|
||||
if (R)
|
||||
server.registerTool(
|
||||
'list_holidays',
|
||||
{
|
||||
description: 'List public holidays for a country and year.',
|
||||
inputSchema: {
|
||||
country: z.string().describe('ISO 3166-1 alpha-2 code'),
|
||||
year: z.number().int(),
|
||||
},
|
||||
annotations: TOOL_ANNOTATIONS_READONLY,
|
||||
},
|
||||
async ({ country, year }) => {
|
||||
const result = await getHolidays(String(year), country);
|
||||
if (result.error) return { content: [{ type: 'text' as const, text: result.error }], isError: true };
|
||||
return ok({ holidays: result.data });
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user