Section Writer Skills
Comprehensive skill library for section writing and content generation tasks.
Table of Contents
Core Utilities
Get Current Datetime
Returns current date and time as ISO string.
function get_current_datetime() {
return new Date().toISOString();
}
Get User ID
Extract user ID from context for API authentication.
function getUserId(context) {
return context.user?.id || context.auth?.userId || 'default-user';
}
Task Management
Get Current User Tasks
Fetch all tasks for authenticated user with optional filters.
async function get_current_user_tasks(params = {}) {
const { status = "all", sort, search_text } = params;
const queryParams = new URLSearchParams();
if (status !== "all") queryParams.append('status', status);
if (sort) queryParams.append('sort', sort);
if (search_text) queryParams.append('search_text', search_text);
const userId = getUserId(this.context || {});
const query = queryParams.toString();
const url = `${BASE_URL}/api/${userId}/tasks${query ? '?' + query : ''}`;
const response = await fetch(url);
if (!response.ok) throw new Error(`Failed to fetch tasks: ${response.statusText}`);
return await response.json();
}
Create New Task
Create a new task with title, description, due date, priority, and recurrence.
async function create_new_task(params) {
const { title, description, due_date, priority = "medium", recurrence } = params;
const userId = getUserId(this.context || {});
const url = `${BASE_URL}/api/${userId}/tasks`;
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, description, due_date, priority, recurrence })
});
if (!response.ok) throw new Error(`Failed to create task: ${response.statusText}`);
return await response.json();
}
Update Existing Task
Fully or partially update a task.
async function update_existing_task(params) {
const { task_id, data } = params;
const userId = getUserId(this.context || {});
const url = `${BASE_URL}/api/${userId}/tasks/${task_id}`;
const response = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) throw new Error(`Failed to update task: ${response.statusText}`);
return await response.json();
}
Toggle Task Completion
Mark a task as completed or incomplete.
async function toggle_task_completion(params) {
const { task_id, completed } = params;
const userId = getUserId(this.context || {});
const url = `${BASE_URL}/api/${userId}/tasks/${task_id}/complete`;
const response = await fetch(url, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ completed })
});
if (!response.ok) throw new Error(`Failed to toggle task: ${response.statusText}`);
return await response.json();
}
Search Tasks by Keyword
Find tasks matching a keyword or phrase.
async function search_tasks_by_keyword(params) {
return get_current_user_tasks({ search_text: params.query });
}
Content Generation
Parse Natural Language Task
Parse free-text input into structured task data.
async function parse_natural_language_task(input) {
const result = {
title: null,
description: null,
due_date: null,
priority: 'medium',
recurrence: null
};
const text = input.toLowerCase();
// Priority keywords mapping
const priorityKeywords = {
high: ['urgent', 'asap', 'important', 'critical', 'immediately', 'right now', 'today'],
low: ['whenever', 'low priority', 'sometime', 'maybe', 'eventually', 'not important']
};
// Detect priority
for (const [priority, keywords] of Object.entries(priorityKeywords)) {
if (keywords.some(kw => text.includes(kw))) {
result.priority = priority;
break;
}
}
// Recurrence patterns
const recurrencePatterns = [
{ pattern: /\b(daily|every day)\b/i, value: 'daily' },
{ pattern: /\b(weekly|every week)\b/i, value: 'weekly' },
{ pattern: /\b(monthly|every month)\b/i, value: 'monthly' },
{ pattern: /\b(weekdays?)\b/i, value: 'weekdays' }
];
for (const { pattern, value } of recurrencePatterns) {
if (pattern.test(text)) {
result.recurrence = value;
break;
}
}
// Date extraction patterns
const datePatterns = [
{ pattern: /\b(today)\b/i, type: 'today' },
{ pattern: /\b(tomorrow)\b/i, type: 'tomorrow' },
{ pattern: /\b(next week)\b/i, type: 'next_week' },
{ pattern: /\b(on\s+(\w+day|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s*(\d{1,2})?)\b/i, type: 'specific' },
{ pattern: /\bby\s+(today|tomorrow|next week|this weekend|end of (week|month|day))\b/i, type: 'deadline' },
{ pattern: /\b(\d{1,2}\/\d{1,2}(\/\d{2,4})?)\b/, type: 'mmdd' },
{ pattern: /\b(\d{4}-\d{2}-\d{2})\b/, type: 'iso' }
];
const now = new Date();
for (const { pattern, type } of datePatterns) {
const match = text.match(pattern);
if (match) {
const date = new Date();
switch (type) {
case 'today':
result.due_date = date.toISOString();
break;
case 'tomorrow':
date.setDate(date.getDate() + 1);
result.due_date = date.toISOString();
break;
case 'next_week':
date.setDate(date.getDate() + 7);
result.due_date = date.toISOString();
break;
case 'specific':
try {
const parsed = new Date(match[0]);
if (!isNaN(parsed)) result.due_date = parsed.toISOString();
} catch (e) {}
break;
case 'deadline':
if (match[1].includes('today')) {
result.due_date = date.toISOString();
} else if (match[1].includes('tomorrow')) {
date.setDate(date.getDate() + 1);
result.due_date = date.toISOString();
} else if (match[1].includes('week')) {
date.setDate(date.getDate() + 7);
result.due_date = date.toISOString();
} else if (match[1].includes('month')) {
date.setMonth(date.getMonth() + 1);
result.due_date = date.toISOString();
}
break;
case 'mmdd':
try {
const parts = match[1].split('/');
const parsed = new Date();
parsed.setMonth(parseInt(parts[0]) - 1);
parsed.setDate(parseInt(parts[1]));
if (parts[2]) parsed.setYear(parseInt(parts[2]) < 100 ? 2000 + parseInt(parts[2]) : parseInt(parts[2]));
result.due_date = parsed.toISOString();
} catch (e) {}
break;
case 'iso':
result.due_date = match[1];
break;
}
break;
}
}
// Extract title
const titleIndicators = ['due', 'by', 'on', 'at', 'priority', 'recurring', 'daily', 'weekly', 'monthly'];
let titleCandidate = input;
for (const indicator of titleIndicators) {
const idx = text.indexOf(indicator + ' ');
if (idx > 0) {
titleCandidate = input.substring(0, idx).trim();
break;
}
}
// Clean up title
result.title = titleCandidate
.replace(/^(create|add|make|schedule|plan)\s+(a\s+)?(new\s+)?(task\s+)?/i, '')
.replace(/^(i need to|i should|i want to|i have to)\s+/i, '')
.trim();
result.title = result.title.replace(/^["'\-–—]\s*/, '').replace(/["'\-–—]\s*$/, '');
const titleEndIdx = input.indexOf(titleCandidate) + titleCandidate.length;
if (titleEndIdx < input.length) {
const remaining = input.substring(titleEndIdx).trim();
if (remaining.length > 5) {
result.description = remaining.replace(/^(due|by|on|at|priority|recurring)\s*:?\s*/i, '').trim();
}
}
if (!result.title || result.title.length < 2) {
result.title = input;
}
return result;
}
Suggest Task Clarification
Identify ambiguities and suggest clarification questions.
function suggest_task_clarification(parsedTask, originalInput) {
const questions = [];
if (!parsedTask.title || parsedTask.title.length < 3) {
questions.push("What should this task be called?");
}
const text = originalInput.toLowerCase();
if (parsedTask.priority === 'high' && !text.match(/urgent|asap|important|critical|immediately/i)) {
questions.push("How urgent is this task? Is it something that needs to be done right away?");
}
if (!parsedTask.due_date) {
if (text.match(/asap|urgent|immediately|right now/)) {
parsedTask.priority = 'high';
} else {
questions.push("When is this task due?");
}
}
if (parsedTask.recurrence && !text.match(/daily|weekly|monthly|every/)) {
questions.push("How often should this task repeat?");
}
return {
needs_clarification: questions.length > 0,
questions
};
}
Generate Task Summary
Create natural language summary from task list.
async function generate_task_summary(tasks) {
if (!tasks || tasks.length === 0) {
return "You have no tasks.";
}
const now = taskManager.get_current_datetime();
const today = new Date().toISOString().split('T')[0];
const completed = tasks.filter(t => t.completed);
const pending = tasks.filter(t => !t.completed);
const overdue = pending.filter(t => t.due_date && t.due_date < now);
const dueToday = pending.filter(t => t.due_date && t.due_date.startsWith(today));
const upcoming = pending.filter(t => t.due_date && t.due_date >= now && !t.due_date.startsWith(today));
const noDate = pending.filter(t => !t.due_date);
const highPriority = pending.filter(t => t.priority === 'high' || t.priority === 'urgent');
const mediumPriority = pending.filter(t => t.priority === 'medium');
const lowPriority = pending.filter(t => t.priority === 'low');
const parts = [];
if (completed.length > 0) {
parts.push(`You have ${completed.length} completed task${completed.length > 1 ? 's' : ''}.`);
}
if (pending.length > 0) {
parts.push(`You have ${pending.length} pending task${pending.length > 1 ? 's' : ''}:`);
const details = [];
if (overdue.length > 0) details.push(`${overdue.length} overdue`);
if (dueToday.length > 0) details.push(`${dueToday.length} due today`);
if (upcoming.length > 0) details.push(`${upcoming.length} upcoming`);
if (noDate.length > 0) details.push(`${noDate.length} no due date`);
if (details.length > 0) {
parts.push(details.join(', '));
}
if (highPriority.length > 0) {
parts.push(`${highPriority.length} high priority`);
}
}
return parts.join('\n');
}
Format Task List
Format tasks into readable list with status icons.
async function format_task_list(tasks, format = 'bullet') {
if (!tasks || tasks.length === 0) {
return "No tasks to display.";
}
const statusIcons = {
completed: '[x]',
pending: '[ ]',
overdue: '[!]'
};
const now = taskManager.get_current_datetime();
const today = new Date().toISOString().split('T')[0];
const lines = tasks.map((task, index) => {
let status = task.completed ? 'completed' : 'pending';
if (!task.completed && task.due_date && task.due_date < now) {
status = 'overdue';
}
const icon = statusIcons[status];
let dueInfo = '';
if (task.due_date) {
const dueDate = new Date(task.due_date);
const dueStr = dueDate.toISOString().split('T')[0];
if (dueStr === today) {
dueInfo = ' (due today)';
} else if (dueDate > new Date()) {
const diff = Math.ceil((dueDate - new Date()) / (1000 * 60 * 60 * 24));
if (diff === 1) dueInfo = ' (due tomorrow)';
else if (diff <= 7) dueInfo = ` (due in ${diff} days)`;
} else {
dueInfo = ` (due ${dueStr})`;
}
}
const priorityTag = task.priority ? ` [${task.priority}]` : '';
const title = task.title || 'Untitled task';
switch (format) {
case 'numbered':
return `${index + 1}. ${icon} ${title}${dueInfo}${priorityTag}`;
case 'simple':
return `${icon} ${title}`;
case 'bullet':
default:
return ` ${icon} ${title}${dueInfo}${priorityTag}`;
}
});
return lines.join('\n');
}
Generate Reminder Message
Create personalized reminder message with configurable tone.
function generate_reminder_message(options = {}) {
const {
overdue = [],
today = [],
upcoming = [],
tone = 'gentle'
} = options;
if (overdue.length === 0 && today.length === 0 && upcoming.length === 0) {
return "All caught up! No pending tasks.";
}
const templates = {
gentle: {
intro: "Just a friendly reminder about your tasks:",
overdue: "These are past their due date:",
today: "Due today:",
upcoming: "Coming up soon:",
outro: "Take your time!"
},
urgent: {
intro: "Action needed! Here's your task status:",
overdue: "URGENT - Overdue tasks:",
today: "Due today - don't delay:",
upcoming: "Upcoming deadlines:",
outro: "Get them done!"
},
friendly: {
intro: "Hey! Here's what's on your plate:",
overdue: "A few things slipped past their dates:",
today: "Today's to-dos:",
upcoming: "On the horizon:",
outro: "You've got this!"
}
};
const t = templates[tone] || templates.gentle;
const parts = [t.intro];
if (overdue.length > 0) {
parts.push(`\n${t.overdue}`);
overdue.forEach((task, i) => {
parts.push(` ${i + 1}. ${task.title}`);
});
}
if (today.length > 0) {
parts.push(`\n${t.today}`);
today.forEach((task, i) => {
parts.push(` ${i + 1}. ${task.title}`);
});
}
if (upcoming.length > 0) {
parts.push(`\n${t.upcoming}`);
upcoming.forEach((task, i) => {
const due = new Date(task.due_date).toLocaleDateString();
parts.push(` ${i + 1}. ${task.title} (${due})`);
});
}
parts.push(`\n${t.outro}`);
return parts.filter(p => p).join('\n');
}
Analysis & Scoring
Calculate Priority Score
Calculate priority score using multi-factor algorithm.
function calculate_priority_score(task, options = {}) {
const {
urgency_weight = 1.5,
importance_weight = 1.0
} = options;
const now = taskManager.get_current_datetime();
const priorityValues = {
urgent: 4,
high: 3,
medium: 2,
low: 1,
none: 0
};
let importanceScore = priorityValues[task.priority?.toLowerCase()] || 2;
const importantKeywords = ['important', 'urgent', 'critical', 'asap', 'deadline', 'must', 'essential'];
const title = (task.title || '').toLowerCase();
const description = (task.description || '').toLowerCase();
const text = title + ' ' + description;
let keywordBoost = 0;
for (const kw of importantKeywords) {
if (text.includes(kw)) keywordBoost += 0.5;
}
importanceScore = Math.min(importanceScore + keywordBoost, 5);
let urgencyScore = 0;
if (task.due_date && !task.completed) {
const dueDate = new Date(task.due_date);
const nowDate = new Date(now);
const diffMs = dueDate - nowDate;
const diffDays = diffMs / (1000 * 60 * 60 * 24);
if (diffDays < 0) {
urgencyScore = 10 + Math.abs(diffDays) * 0.5;
} else if (diffDays === 0) {
urgencyScore = 8;
} else if (diffDays <= 1) {
urgencyScore = 6;
} else if (diffDays <= 3) {
urgencyScore = 5;
} else if (diffDays <= 7) {
urgencyScore = 3;
} else {
urgencyScore = 1;
}
} else if (!task.due_date) {
urgencyScore = 0.5;
}
const score = (urgencyScore * urgency_weight) + (importanceScore * importance_weight);
return {
score: Math.round(score * 10) / 10,
breakdown: {
urgencyScore: Math.round(urgencyScore * 10) / 10,
importanceScore,
urgencyWeight: urgency_weight,
importanceWeight: importance_weight
}
};
}
Generate Eisenhower Matrix
Categorize tasks into four quadrants.
async function generate_eisenhower_matrix(tasks, outputFormat = 'text') {
const matrix = {
urgent_important: [],
urgent_not_important: [],
not_urgent_important: [],
not_urgent_not_important: []
};
const now = taskManager.get_current_datetime();
for (const task of tasks) {
if (task.completed) continue;
const { score, breakdown } = calculate_priority_score(task);
const isUrgent = breakdown.urgencyScore >= 5;
const isImportant = breakdown.importanceScore >= 3;
if (isUrgent && isImportant) {
matrix.urgent_important.push({ ...task, priorityScore: score });
} else if (isUrgent && !isImportant) {
matrix.urgent_not_important.push({ ...task, priorityScore: score });
} else if (!isUrgent && isImportant) {
matrix.not_urgent_important.push({ ...task, priorityScore: score });
} else {
matrix.not_urgent_not_important.push({ ...task, priorityScore: score });
}
}
if (outputFormat === 'json') {
return matrix;
}
const formatTasks = (taskList) => {
if (taskList.length === 0) return ' (none)';
return taskList
.sort((a, b) => b.priorityScore - a.priorityScore)
.map(t => ` - ${t.title} (score: ${t.priorityScore})`)
.join('\n');
};
return `
╔══════════════════════════════════════════════════════════════╗
║ EISENHOWER MATRIX ║
╠══════════════════════════════════════════════════════════════╣
║ URGENT & IMPORTANT │ NOT URGENT & IMPORTANT ║
║ (Do First) │ (Schedule) ║
║ ────────────────────────────┼──────────────────────────── ║
${formatTasks(matrix.urgent_important).padEnd(27)}│${formatTasks(matrix.not_urgent_important).padStart(28)}
╠───────────────────────────────┼───────────────────────────────╣
║ URGENT & NOT IMPORTANT │ NOT URGENT & NOT IMPORTANT ║
║ (Delegate/Schedule) │ (Eliminate/Low Priority) ║
║ ────────────────────────────┼──────────────────────────── ║
${formatTasks(matrix.urgent_not_important).padEnd(27)}│${formatTasks(matrix.not_urgent_not_important).padStart(28)}
╚══════════════════════════════════════════════════════════════╝
`.trim();
}
Task Resolution & Confirmation
Resolve Task Reference
Resolve vague task references to specific task IDs.
async function resolve_task_reference(reference, tasks) {
if (!reference || !tasks || tasks.length === 0) {
return null;
}
const refLower = reference.toLowerCase().trim();
const exactMatch = tasks.find(t =>
t.title?.toLowerCase() === refLower ||
t.title?.toLowerCase().includes(refLower)
);
if (exactMatch) return exactMatch;
const allTasks = await taskManager.get_current_user_tasks({ search_text: reference });
if (allTasks.length === 1) {
return allTasks[0];
}
if (allTasks.length > 1) {
return allTasks[0];
}
const patterns = {
first: () => tasks[0],
last: () => tasks[tasks.length - 1],
newest: () => tasks.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0],
oldest: () => tasks.sort((a, b) => new Date(a.created_at) - new Date(b.created_at))[0],
recent: () => tasks.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0],
overdue: () => {
const now = taskManager.get_current_datetime();
return tasks.find(t => !t.completed && t.due_date && t.due_date < now);
},
urgent: () => tasks.find(t => t.priority === 'high' || t.priority === 'urgent'),
completed: () => tasks.find(t => t.completed),
pending: () => tasks.find(t => !t.completed)
};
for (const [pattern, resolver] of Object.entries(patterns)) {
if (refLower.includes(pattern)) {
const result = resolver();
if (result) return result;
}
}
return null;
}
Confirm Before Update
Generate confirmation message before destructive changes.
function confirm_before_update(action, target, changes = null) {
const isArray = Array.isArray(target);
const count = isArray ? target.length : 1;
const taskTitle = isArray ? target[0]?.title : target?.title;
const actionMessages = {
delete: {
single: `Delete "${taskTitle}"? This cannot be undone.`,
multiple: `Delete ${count} tasks? This cannot be undone.`,
requires_confirm: true
},
complete: {
single: `Mark "${taskTitle}" as completed?`,
multiple: `Mark ${count} tasks as completed?`,
requires_confirm: false
},
update: {
single: `Update "${taskTitle}"?`,
multiple: `Update ${count} tasks?`,
requires_confirm: false
},
bulk: {
single: `Apply changes to ${count} task?`,
multiple: `Apply changes to ${count} tasks?`,
requires_confirm: true
}
};
const msgKey = isArray && count > 1 ? 'multiple' : 'single';
const config = actionMessages[action] || actionMessages.update;
let message = config[msgKey];
if (changes && Object.keys(changes).length > 0) {
const changeDesc = Object.entries(changes)
.map(([k, v]) => `${k}: "${v}"`)
.join(', ');
message += ` Changes: ${changeDesc}`;
}
return {
message,
requires_confirm: config.requires_confirm,
target,
changes
};
}
Scheduling & Planning
Filter Overdue Tasks
Get tasks past their due date that are not completed.
async function filter_overdue_tasks(tasks) {
const taskList = tasks || await taskManager.get_current_user_tasks();
const now = taskManager.get_current_datetime();
return taskList.filter(t =>
!t.completed &&
t.due_date &&
new Date(t.due_date) < new Date(now)
);
}
Filter Today Tasks
Get tasks due exactly today.
async function filter_today_tasks(tasks) {
const taskList = tasks || await taskManager.get_current_user_tasks();
const today = new Date().toISOString().split('T')[0];
return taskList.filter(t =>
!t.completed &&
t.due_date &&
t.due_date.startsWith(today)
);
}
Filter Upcoming Tasks
Get tasks due in the next N days.
async function filter_upcoming_tasks(days = 3, tasks) {
const taskList = tasks || await taskManager.get_current_user_tasks();
const now = new Date();
const futureDate = new Date();
futureDate.setDate(futureDate.getDate() + days);
const nowISO = now.toISOString();
const futureISO = futureDate.toISOString();
return taskList.filter(t =>
!t.completed &&
t.due_date &&
t.due_date >= nowISO &&
t.due_date <= futureISO
);
}
Get Reminder Summary
Get comprehensive categorized reminder data.
async function get_reminder_summary(tasks) {
const taskList = tasks || await taskManager.get_current_user_tasks();
const [overdue, today, upcoming] = await Promise.all([
filter_overdue_tasks(taskList),
filter_today_tasks(taskList),
filter_upcoming_tasks(7, taskList)
]);
return {
overdue,
today,
upcoming,
summary: {
overdueCount: overdue.length,
todayCount: today.length,
upcomingCount: upcoming.length,
totalPending: overdue.length + today.length + upcoming.length
}
};
}
Estimate Task Duration
Estimate task duration based on keywords and priority.
function estimate_task_duration(task, defaultDuration = 30) {
const title = (task.title || '').toLowerCase();
const description = (task.description || '').toLowerCase();
const text = title + ' ' + description;
const quickKeywords = ['quick', 'fast', 'short', 'small', 'simple', 'check', 'reply', 'send', 'call'];
const longKeywords = ['long', 'big', 'complex', ' extensive', 'detailed', 'deep', 'write report', 'create', 'build'];
const mediumKeywords = ['meeting', 'call', 'review', 'update', 'prepare'];
if (quickKeywords.some(kw => text.includes(kw))) {
return 15;
}
if (longKeywords.some(kw => text.includes(kw))) {
return 90;
}
if (mediumKeywords.some(kw => text.includes(kw))) {
return 45;
}
if (task.priority === 'high' || task.priority === 'urgent') {
return 45;
}
if (task.priority === 'low') {
return 20;
}
return defaultDuration;
}
Detect Time Conflicts
Detect overlapping time slots between scheduled tasks.
function detect_time_conflicts(scheduledTasks) {
const conflicts = [];
for (let i = 0; i < scheduledTasks.length; i++) {
for (let j = i + 1; j < scheduledTasks.length; j++) {
const a = scheduledTasks[i];
const b = scheduledTasks[j];
if (!a.startTime || !a.endTime || !b.startTime || !b.endTime) continue;
const aStart = new Date(a.startTime).getTime();
const aEnd = new Date(a.endTime).getTime();
const bStart = new Date(b.startTime).getTime();
const bEnd = new Date(b.endTime).getTime();
if (aStart < bEnd && bStart < aEnd) {
conflicts.push({
task1: a.task.title,
task2: b.task.title,
overlap: Math.min(aEnd, bEnd) - Math.max(aStart, bStart)
});
}
}
}
return conflicts;
}
Generate Daily Agenda
Create formatted daily agenda from tasks.
async function generate_daily_agenda(tasks, options = {}) {
const {
startHour = 9,
endHour = 18,
breakDuration = 15
} = options;
if (!tasks || tasks.length === 0) {
return "No tasks scheduled for today.";
}
const sortedTasks = [...tasks].sort((a, b) => {
if (a.priority === 'urgent' && b.priority !== 'urgent') return -1;
if (b.priority === 'urgent' && a.priority !== 'urgent') return 1;
if (a.priority === 'high' && b.priority !== 'high') return -1;
if (b.priority === 'high' && a.priority !== 'high') return 1;
if (a.due_date && b.due_date) {
return new Date(a.due_date) - new Date(b.due_date);
}
return 0;
});
const schedule = [];
let currentTime = new Date();
currentTime.setHours(startHour, 0, 0, 0);
const dayEnd = new Date();
dayEnd.setHours(endHour, 0, 0, 0);
for (const task of sortedTasks) {
const duration = estimate_task_duration(task);
const startTime = new Date(currentTime);
if (startTime >= dayEnd) break;
const endTime = new Date(currentTime.getTime() + duration * 60000);
if (endTime > dayEnd) {
schedule.push({
task,
startTime: startTime.toISOString(),
endTime: dayEnd.toISOString(),
duration: Math.round((dayEnd - startTime) / 60000),
truncated: true
});
break;
}
schedule.push({
task,
startTime: startTime.toISOString(),
endTime: endTime.toISOString(),
duration
});
currentTime = new Date(endTime.getTime() + breakDuration * 60000);
}
const formatTime = (isoString) => {
const date = new Date(isoString);
return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
};
const formatDuration = (mins) => {
if (mins < 60) return `${mins} min`;
const h = Math.floor(mins / 60);
const m = mins % 60;
return m > 0 ? `${h}h ${m}m` : `${h}h`;
};
const lines = ['═'.repeat(50)];
lines.push('📅 DAILY AGENDA');
lines.push('═'.repeat(50));
const periods = {
morning: { start: 6, end: 12, tasks: [] },
afternoon: { start: 12, end: 17, tasks: [] },
evening: { start: 17, end: 24, tasks: [] }
};
for (const item of schedule) {
const hour = new Date(item.startTime).getHours();
if (hour < 12) periods.morning.tasks.push(item);
else if (hour < 17) periods.afternoon.tasks.push(item);
else periods.evening.tasks.push(item);
}
const periodLabels = {
morning: '🌅 Morning',
afternoon: '☀️ Afternoon',
evening: '🌙 Evening'
};
for (const [period, data] of Object.entries(periods)) {
if (data.tasks.length > 0) {
lines.push('');
lines.push(periodLabels[period]);
lines.push('─'.repeat(30));
for (const item of data.tasks) {
const timeStr = `${formatTime(item.startTime)} - ${formatTime(item.endTime)}`;
const durationStr = formatDuration(item.duration);
const truncated = item.truncated ? ' (truncated)' : '';
lines.push(` ${timeStr}`);
lines.push(` 📌 ${item.task.title}${truncated}`);
lines.push(` ⏱️ ${durationStr}`);
lines.push('');
}
}
}
lines.push('═'.repeat(50));
const totalMins = schedule.reduce((sum, item) => sum + item.duration, 0);
lines.push(`Total: ${formatDuration(totalMins)} • ${schedule.length} tasks`);
return lines.join('\n');
}
Suggest Time Slots
Find optimal time slots for a new task.
async function suggest_time_slots(task, existingSchedule = [], options = {}) {
const { startHour = 9, endHour = 18, preferredDuration = null } = options;
const duration = preferredDuration || estimate_task_duration(task);
const slots = [];
const bookedTimes = existingSchedule
.filter(s => s.startTime && s.endTime)
.map(s => ({
start: new Date(s.startTime).getTime(),
end: new Date(s.endTime).getTime()
}))
.sort((a, b) => a.start - b.start);
let currentTime = new Date();
currentTime.setHours(startHour, 0, 0, 0);
const dayEnd = new Date();
dayEnd.setHours(endHour, 0, 0, 0);
while (currentTime.getTime() + duration * 60000 <= dayEnd.getTime()) {
const slotStart = currentTime.getTime();
const slotEnd = slotStart + duration * 60000;
const isFree = !bookedTimes.some(booked =>
slotStart < booked.end && slotEnd > booked.start
);
if (isFree) {
slots.push({
startTime: new Date(slotStart).toISOString(),
endTime: new Date(slotEnd).toISOString(),
duration,
score: calculate_slot_score(new Date(slotStart))
});
}
currentTime = new Date(currentTime.getTime() + 30 * 60000);
}
return slots.sort((a, b) => b.score - a.score).slice(0, 3);
}
function calculate_slot_score(date) {
const hour = date.getHours();
let score = 0;
if (hour >= 9 && hour <= 11) score += 3;
if (hour >= 14 && hour <= 16) score += 2;
if (hour < 9 || hour >= 17) score -= 2;
if (hour >= 12 && hour <= 13) score -= 1;
return score;
}
Module Exports
module.exports = {
// Core Utilities
get_current_datetime,
getUserId,
// Task Management
get_current_user_tasks,
create_new_task,
update_existing_task,
toggle_task_completion,
search_tasks_by_keyword,
// Content Generation
parse_natural_language_task,
suggest_task_clarification,
generate_task_summary,
format_task_list,
generate_reminder_message,
// Analysis & Scoring
calculate_priority_score,
generate_eisenhower_matrix,
// Task Resolution
resolve_task_reference,
confirm_before_update,
// Scheduling & Planning
filter_overdue_tasks,
filter_today_tasks,
filter_upcoming_tasks,
get_reminder_summary,
estimate_task_duration,
detect_time_conflicts,
generate_daily_agenda,
suggest_time_slots
};