UNPKG

omnifocus-mcp-enhanced

Version:

🚀 NEW: Native Custom Perspective Access! Enhanced MCP server with OmniFocus custom perspective support, hierarchical task display, AI-optimized tool selection, and comprehensive task management

166 lines (146 loc) 6.34 kB
// 正确的透视执行器 - 基于用户提供的工作代码实现 import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); /** * 透视任务获取器 * 基于用户提供的正确代码实现,直接切换透视并从内容树收集任务 */ export class CorrectPerspectiveExecutor { /** * 获取透视任务的正确方法 * 基于用户提供的工作代码,直接切换透视并从内容树收集任务 */ static async getPerspectiveTasks(perspectiveName, options = {}) { const { hideCompleted = true, limit = 0 } = options; const script = ` (() => { try { console.log("开始获取透视: ${perspectiveName}"); // 获取自定义透视 let perspective = Perspective.Custom.byName("${perspectiveName}"); if (!perspective) { return { success: false, error: "未找到透视: ${perspectiveName}" }; } console.log("成功找到透视:", perspective.name); // 切换到目标透视 document.windows[0].perspective = perspective; // 用于存储所有任务,key为任务ID let taskMap = {}; // 遍历内容树,收集任务信息(含层级关系) let rootNode = document.windows[0].content.rootNode; function collectTasks(node, parentId) { if (node.object && node.object instanceof Task) { let t = node.object; let id = t.id.primaryKey; // 应用 hideCompleted 筛选 if (${hideCompleted} && (t.completed || t.dropped)) { return; } // 记录任务信息 taskMap[id] = { id: id, name: t.name, note: t.note, project: t.project ? t.project.name : null, tags: t.tags ? t.tags.map(tag => tag.name) : [], dueDate: t.dueDate ? t.dueDate.toISOString() : null, deferDate: t.deferDate ? t.deferDate.toISOString() : null, completed: t.completed, dropped: t.dropped, flagged: t.flagged, estimatedMinutes: t.estimatedMinutes, repetitionRule: t.repetitionRule ? t.repetitionRule.toString() : null, parent: parentId, // 父任务ID children: [], // 子任务ID列表,后面补充 creationDate: t.added ? t.added.toISOString() : null, completionDate: t.completionDate ? t.completionDate.toISOString() : null }; // 递归收集子任务 node.children.forEach(childNode => { if (childNode.object && childNode.object instanceof Task) { let childId = childNode.object.id.primaryKey; taskMap[id].children.push(childId); collectTasks(childNode, id); } else { collectTasks(childNode, id); } }); } else { // 不是任务节点,递归子节点 node.children.forEach(childNode => collectTasks(childNode, parentId)); } } // 开始收集任务 rootNode.children.forEach(node => collectTasks(node, null)); // 转换为数组格式(保持向后兼容) let tasks = Object.values(taskMap); // 应用 limit 限制 if (${limit} > 0 && tasks.length > ${limit}) { tasks = tasks.slice(0, ${limit}); } console.log("透视 '" + perspective.name + "' 收集到 " + tasks.length + " 个任务"); const result = { success: true, perspectiveName: "${perspectiveName}", taskCount: tasks.length, tasks: tasks, taskMap: taskMap, // 包含层级关系的完整数据 totalTasks: tasks.length }; return result; } catch (error) { console.log("透视获取失败:", error); return { success: false, error: error.toString() }; } })() `; try { console.log('[CorrectPerspectiveExecutor] 开始执行透视查询...'); // 转义脚本中的特殊字符 const escapedScript = script.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$'); // 使用JXA直接执行OmniJS const jxaScript = ` function run() { try { const app = Application('OmniFocus'); app.includeStandardAdditions = true; // 执行OmniJS代码并获取结果 const result = app.evaluateJavascript(\`${escapedScript}\`); return result; } catch (e) { return JSON.stringify({ error: e.message }); } } `; // 执行JXA脚本 const { stdout, stderr } = await execAsync(`osascript -l JavaScript -e '${jxaScript}'`, { timeout: 10000 }); if (stderr) { console.error('[CorrectPerspectiveExecutor] 执行错误:', stderr); throw new Error(`JXA执行错误: ${stderr}`); } console.log('[CorrectPerspectiveExecutor] 原始输出:', stdout); // 解析返回结果 try { const result = JSON.parse(stdout); console.log('[CorrectPerspectiveExecutor] 执行成功,结果:', result); return result; } catch (parseError) { // 如果不是JSON,直接返回字符串 console.log('[CorrectPerspectiveExecutor] 返回非JSON结果:', stdout); return stdout.trim(); } } catch (error) { console.error('[CorrectPerspectiveExecutor] 执行失败:', error); throw new Error(`透视查询失败: ${error}`); } } }