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

244 lines (212 loc) 8.29 kB
// OmniJS执行器 - 通过JXA直接执行OmniJS代码 import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); /** * 执行OmniJS代码的正确方法 * 通过JXA直接执行OmniJS,能够获取返回值 */ export class OmniJSExecutor { /** * 执行OmniJS代码并获取返回值 * @param script - 纯OmniJS代码字符串 * @param timeout - 超时时间(毫秒) * @returns Promise<any> - 执行结果 */ static async execute(script, timeout = 10000) { try { console.log('[OmniJSExecutor] 开始执行OmniJS代码...'); // 转义脚本中的特殊字符 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 }); if (stderr) { console.error('[OmniJSExecutor] 执行错误:', stderr); throw new Error(`JXA执行错误: ${stderr}`); } console.log('[OmniJSExecutor] 原始输出:', stdout); // 解析返回结果 try { const result = JSON.parse(stdout); console.log('[OmniJSExecutor] 执行成功,结果:', result); return result; } catch (parseError) { // 如果不是JSON,直接返回字符串 console.log('[OmniJSExecutor] 返回非JSON结果:', stdout); return stdout.trim(); } } catch (error) { console.error('[OmniJSExecutor] 执行失败:', error); throw new Error(`OmniJS执行失败: ${error}`); } } } /** * 透视访问专用的OmniJS执行器 */ export class PerspectiveOmniJSExecutor { /** * 获取透视任务的正确方法 */ static async getPerspectiveTasks(perspectiveName, options = {}) { const { hideCompleted = true, limit = 0 } = options; const script = ` (() => { try { console.log("开始获取透视: ${perspectiveName}"); // 使用正确的document全局变量 const doc = document; // 使用正确的API查找透视 let targetPerspective = null; try { // 方法1: 直接通过名称查找 targetPerspective = Perspective.Custom.byName("${perspectiveName}"); console.log("通过byName找到透视"); } catch (byNameError) { console.log(\`byName失败: \${byNameError.message}\`); // 方法2: 遍历所有自定义透视 try { const allCustomPerspectives = Perspective.Custom.all; for (let perspective of allCustomPerspectives) { if (perspective.name === "${perspectiveName}") { targetPerspective = perspective; console.log("通过遍历找到透视"); break; } } } catch (allError) { console.log(\`遍历失败: \${allError.message}\`); } } if (!targetPerspective) { return { success: false, error: "未找到透视: ${perspectiveName}" }; } console.log("成功找到透视"); // 切换透视 let window = doc.windows[0]; if (!window) { return { success: false, error: "没有可用窗口" }; } window.perspective = targetPerspective; console.log("切换透视成功"); // 计数任务 let taskCount = 0; let projectCount = 0; let tasks = []; function collectTasks(node) { try { const obj = node.object; if (obj instanceof Task) { const completed = obj.completed; const dropped = obj.dropped; // 应用hideCompleted筛选 if (${hideCompleted} && (completed || dropped)) { return; } taskCount++; // 收集任务信息 const taskData = { id: obj.id.primaryKey, name: obj.name, completed: completed, dropped: dropped, flagged: obj.flagged, projectName: obj.containingProject ? obj.containingProject.name : null }; tasks.push(taskData); // 应用limit限制 if (${limit} > 0 && tasks.length >= ${limit}) { return false; } } else if (obj instanceof Project) { projectCount++; } // 递归处理子节点 if (node.children && node.children.length > 0) { for (let child of node.children) { if (collectTasks(child) === false) { return false; } } } } catch (nodeError) { console.log(\`节点处理错误: \${nodeError.message}\`); } } const rootNode = window.content.rootNode; collectTasks(rootNode); const result = { success: true, perspectiveName: "${perspectiveName}", taskCount: taskCount, projectCount: projectCount, tasks: tasks }; console.log(\`透视 "\${perspectiveName}" 包含 \${taskCount} 个任务\`); return result; } catch (error) { return { success: false, error: error.toString() }; } })() `; // 执行OmniJS脚本 return await OmniJSExecutor.execute(script); } /** * 测试透视查找功能 */ static async testPerspectiveAccess(perspectiveName) { const script = ` (() => { try { console.log("测试透视访问:", "${perspectiveName}"); // 查找透视 let targetPerspective = null; try { targetPerspective = Perspective.Custom.byName("${perspectiveName}"); console.log("找到透视:", targetPerspective.name); } catch (error) { console.log("byName失败:", error.message); // 列出所有自定义透视 const allCustomPerspectives = Perspective.Custom.all; const perspectiveNames = allCustomPerspectives.map(p => p.name); return JSON.stringify({ success: false, error: \`未找到透视 "${perspectiveName}"\`, availablePerspectives: perspectiveNames }); } // 获取透视信息 const perspectiveInfo = { name: targetPerspective.name, hasRules: !!targetPerspective.archivedFilterRules, rulesCount: targetPerspective.archivedFilterRules?.length || 0 }; return JSON.stringify({ success: true, perspectiveInfo: perspectiveInfo }); } catch (error) { return JSON.stringify({ success: false, error: error.toString() }); } })() `; return await OmniJSExecutor.execute(script); } }