We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Thinh-nguyen-03/virtual-assistant-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
import { DateTime, Duration } from 'luxon';
export function parseWorkHours(start, end, tz) {
const today = DateTime.now().setZone(tz);
const startTime = today.set({
hour: parseInt(start.split(':')[0] || '0'),
minute: parseInt(start.split(':')[1] || '0'),
second: 0,
millisecond: 0
});
const endTime = today.set({
hour: parseInt(end.split(':')[0] || '0'),
minute: parseInt(end.split(':')[1] || '0'),
second: 0,
millisecond: 0
});
return { start: startTime, end: endTime };
}
export function isWorkday(date, workDays) {
const dayName = date.toFormat('ccc');
return workDays.includes(dayName);
}
export function clampToWorkHours(dateTime, config) {
const workHours = parseWorkHours(config.workHoursStart, config.workHoursEnd, config.defaultTz);
if (!isWorkday(dateTime, config.workDays)) {
let nextWorkday = dateTime.plus({ days: 1 });
while (!isWorkday(nextWorkday, config.workDays)) {
nextWorkday = nextWorkday.plus({ days: 1 });
}
return nextWorkday.set({
hour: workHours.start.hour,
minute: workHours.start.minute,
second: 0,
millisecond: 0
});
}
const startOfDay = dateTime.set({
hour: workHours.start.hour,
minute: workHours.start.minute,
second: 0,
millisecond: 0
});
const endOfDay = dateTime.set({
hour: workHours.end.hour,
minute: workHours.end.minute,
second: 0,
millisecond: 0
});
if (dateTime < startOfDay) {
return startOfDay;
}
if (dateTime > endOfDay) {
let nextWorkday = dateTime.plus({ days: 1 });
while (!isWorkday(nextWorkday, config.workDays)) {
nextWorkday = nextWorkday.plus({ days: 1 });
}
return nextWorkday.set({
hour: workHours.start.hour,
minute: workHours.start.minute,
second: 0,
millisecond: 0
});
}
return dateTime;
}
export function parseIsoWithTz(isoString, tz) {
return DateTime.fromISO(isoString, { zone: tz });
}
export function toIsoString(dateTime) {
return dateTime.toISO();
}
export function getNextWorkdayStart(config, fromDate) {
const baseDate = fromDate || DateTime.now().setZone(config.defaultTz);
const workHours = parseWorkHours(config.workHoursStart, config.workHoursEnd, config.defaultTz);
let nextWorkday = baseDate.plus({ days: 1 });
while (!isWorkday(nextWorkday, config.workDays)) {
nextWorkday = nextWorkday.plus({ days: 1 });
}
return nextWorkday.set({
hour: workHours.start.hour,
minute: workHours.start.minute,
second: 0,
millisecond: 0
});
}
export function isWithinWorkHours(start, end, config) {
if (!isWorkday(start, config.workDays) || !isWorkday(end, config.workDays)) {
return false;
}
const workHours = parseWorkHours(config.workHoursStart, config.workHoursEnd, config.defaultTz);
const startTime = start.set({
year: workHours.start.year,
month: workHours.start.month,
day: workHours.start.day
});
const endTime = end.set({
year: workHours.end.year,
month: workHours.end.month,
day: workHours.end.day
});
return start >= workHours.start && end <= workHours.end;
}
export function generateWorkHourSlots(windowStart, windowEnd, durationMinutes, config) {
const slots = [];
const duration = Duration.fromObject({ minutes: durationMinutes });
let current = windowStart;
while (current.plus(duration) <= windowEnd) {
const slotEnd = current.plus(duration);
if (isWithinWorkHours(current, slotEnd, config)) {
slots.push({
start_iso: toIsoString(current),
end_iso: toIsoString(slotEnd)
});
}
current = current.plus({ minutes: 15 });
}
return slots;
}
export function parseRelativeTime(input, tz, now) {
const referenceDate = now || DateTime.now().setZone(tz);
const lowerInput = input.toLowerCase().trim();
let didAssumeDate = false;
let didAssumeDuration = false;
let start;
let end;
if (lowerInput.includes('next')) {
const dayMatch = lowerInput.match(/next\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday|mon|tue|wed|thu|fri|sat|sun)/i);
if (dayMatch && dayMatch[1]) {
const targetDay = dayMatch[1].toLowerCase();
const dayMap = {
'monday': 1, 'mon': 1,
'tuesday': 2, 'tue': 2,
'wednesday': 3, 'wed': 3,
'thursday': 4, 'thu': 4,
'friday': 5, 'fri': 5,
'saturday': 6, 'sat': 6,
'sunday': 7, 'sun': 7
};
const targetDayNum = dayMap[targetDay];
let nextDay = referenceDate.plus({ days: 1 });
while (nextDay.weekday !== targetDayNum) {
nextDay = nextDay.plus({ days: 1 });
}
const timeMatch = lowerInput.match(/(\d{1,2}):?(\d{2})?\s*(am|pm)?/i);
if (timeMatch) {
let hour = parseInt(timeMatch[1] || '0');
const minute = timeMatch[2] ? parseInt(timeMatch[2]) : 0;
const period = timeMatch[3]?.toLowerCase();
if (period === 'pm' && hour < 12)
hour += 12;
if (period === 'am' && hour === 12)
hour = 0;
start = nextDay.set({ hour, minute, second: 0, millisecond: 0 });
}
else {
start = nextDay.set({ hour: 9, minute: 0, second: 0, millisecond: 0 });
didAssumeDate = true;
}
end = start.plus({ minutes: 30 });
didAssumeDuration = true;
}
}
else if (lowerInput.match(/^\d{1,2}:?\d{0,2}\s*(am|pm)?$/i)) {
const timeMatch = lowerInput.match(/(\d{1,2}):?(\d{2})?\s*(am|pm)?/i);
if (timeMatch) {
let hour = parseInt(timeMatch[1] || '0');
const minute = timeMatch[2] ? parseInt(timeMatch[2]) : 0;
const period = timeMatch[3]?.toLowerCase();
if (period === 'pm' && hour < 12)
hour += 12;
if (period === 'am' && hour === 12)
hour = 0;
start = referenceDate.set({ hour, minute, second: 0, millisecond: 0 });
end = start.plus({ minutes: 30 });
didAssumeDuration = true;
}
else {
throw new Error('Invalid time format');
}
}
else if (lowerInput.includes('tomorrow')) {
const tomorrow = referenceDate.plus({ days: 1 });
const timeMatch = lowerInput.match(/(\d{1,2}):?(\d{2})?\s*(am|pm)?/i);
if (timeMatch) {
let hour = parseInt(timeMatch[1] || '0');
const minute = timeMatch[2] ? parseInt(timeMatch[2]) : 0;
const period = timeMatch[3]?.toLowerCase();
if (period === 'pm' && hour < 12)
hour += 12;
if (period === 'am' && hour === 12)
hour = 0;
start = tomorrow.set({ hour, minute, second: 0, millisecond: 0 });
}
else {
start = tomorrow.set({ hour: 9, minute: 0, second: 0, millisecond: 0 });
didAssumeDate = true;
}
end = start.plus({ minutes: 30 });
didAssumeDuration = true;
}
else {
throw new Error('Unable to parse time expression');
}
return { start, end, didAssumeDate, didAssumeDuration };
}
export function validateDuration(start, end, minMinutes = 15, maxMinutes = 480) {
const duration = end.diff(start, 'minutes').minutes;
return duration >= minMinutes && duration <= maxMinutes;
}
//# sourceMappingURL=time.js.map