omnifocus-mcp
Version:
Model Context Protocol (MCP) server that integrates with OmniFocus for AI assistant interaction
105 lines (96 loc) • 3.79 kB
JavaScript
import { executeOmniFocusScript } from '../utils/scriptExecution.js';
import { getCacheManager } from '../utils/cacheManager.js';
import { dumpDatabase as originalDumpDatabase } from './dumpDatabase.js';
/**
* Optimized version of dumpDatabase that uses caching
* Falls back to original implementation if caching fails
*/
export async function dumpDatabaseOptimized(options) {
const cacheManager = getCacheManager({
ttlSeconds: 300, // 5 minute cache
useChecksum: true // Validate with database checksum
});
const cacheKey = options?.cacheKey || 'full-dump';
// Check if we should force a refresh
if (!options?.forceRefresh) {
const cached = await cacheManager.get(cacheKey);
if (cached) {
cacheManager.trackHit();
console.log(`Cache hit for ${cacheKey}. Stats:`, cacheManager.getStats());
return cached;
}
}
cacheManager.trackMiss();
console.log(`Cache miss for ${cacheKey}. Fetching fresh data...`);
// Fetch fresh data using the original implementation
const freshData = await originalDumpDatabase();
// Store in cache for next time
await cacheManager.set(cacheKey, freshData);
return freshData;
}
/**
* Get just database statistics without full dump
* Much more efficient for overview information
*/
export async function getDatabaseStats() {
const script = `
(() => {
try {
// Calculate statistics without fetching full data
const allTasks = flattenedTasks;
const activeTasks = allTasks.filter(task =>
task.taskStatus !== Task.Status.Completed &&
task.taskStatus !== Task.Status.Dropped
);
const allProjects = flattenedProjects;
const activeProjects = allProjects.filter(project =>
project.status === Project.Status.Active
);
// Count specific task statuses
const overdueCount = activeTasks.filter(task =>
task.taskStatus === Task.Status.Overdue
).length;
const nextActionCount = activeTasks.filter(task =>
task.taskStatus === Task.Status.Next
).length;
const flaggedCount = activeTasks.filter(task => task.flagged).length;
const inboxCount = activeTasks.filter(task => task.inInbox).length;
// Get latest modification time (OmniJS property is "modified",
// not the AppleScript name "modificationDate")
let lastModified = new Date(0);
allTasks.forEach(task => {
if (task.modified && task.modified > lastModified) {
lastModified = task.modified;
}
});
return JSON.stringify({
taskCount: allTasks.length,
activeTaskCount: activeTasks.length,
projectCount: allProjects.length,
activeProjectCount: activeProjects.length,
folderCount: flattenedFolders.length,
tagCount: flattenedTags.filter(tag => tag.active).length,
overdueCount: overdueCount,
nextActionCount: nextActionCount,
flaggedCount: flaggedCount,
inboxCount: inboxCount,
lastModified: formatDate(lastModified)
});
} catch (error) {
return JSON.stringify({
error: "Failed to get database stats: " + error.toString()
});
}
})();
`;
// Write script to temp file and execute
const fs = await import('fs');
const tempFile = `/tmp/omnifocus_stats_${crypto.randomUUID()}.js`;
fs.writeFileSync(tempFile, script);
const result = await executeOmniFocusScript(tempFile);
fs.unlinkSync(tempFile);
if (result.error) {
throw new Error(result.error);
}
return result;
}