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
220 lines (189 loc) • 6.85 kB
JavaScript
// JXA兼容的透视访问 - 基于验证过的逻辑但用JXA语法
(() => {
try {
// 参数会被自动注入
let perspectiveName = null;
let hideCompleted = true;
let limit = 0; // 0表示无限制
console.log(`JXA方式获取透视: ${perspectiveName}`);
// 使用JXA方式访问OmniFocus
const app = Application('OmniFocus');
const doc = app.defaultDocument;
// Helper functions
function formatDate(date) {
if (!date) return null;
return date.toISOString();
}
// 1. 查找透视 - 使用JXA方式
let targetPerspective = null;
// 尝试在自定义透视中查找
try {
const customPerspectives = doc.customPerspectives;
// 先尝试byName方法
try {
targetPerspective = customPerspectives.byName(perspectiveName);
if (targetPerspective && targetPerspective.name() === perspectiveName) {
console.log(`通过byName找到透视: ${perspectiveName}`);
} else {
targetPerspective = null;
}
} catch (byNameError) {
console.log(`byName方法失败: ${byNameError.message}`);
targetPerspective = null;
}
// 如果byName失败,尝试遍历
if (!targetPerspective) {
// 使用验证过的逻辑:不直接遍历,而是使用索引访问
for (let i = 0; i < 50; i++) { // 限制搜索范围
try {
const perspective = customPerspectives[i];
if (perspective && perspective.name() === perspectiveName) {
targetPerspective = perspective;
console.log(`通过索引${i}找到透视: ${perspectiveName}`);
break;
}
} catch (indexError) {
// 索引超出范围,停止搜索
break;
}
}
}
} catch (customError) {
console.log(`自定义透视访问失败: ${customError.message}`);
}
// 如果还没找到,尝试内置透视
if (!targetPerspective) {
try {
const builtInPerspectives = doc.builtInPerspectives;
for (let i = 0; i < 20; i++) {
try {
const perspective = builtInPerspectives[i];
if (perspective && perspective.name() === perspectiveName) {
targetPerspective = perspective;
console.log(`在内置透视中找到: ${perspectiveName}`);
break;
}
} catch (builtInIndexError) {
break;
}
}
} catch (builtInError) {
console.log(`内置透视访问失败: ${builtInError.message}`);
}
}
if (!targetPerspective) {
return JSON.stringify({
success: false,
error: `透视 "${perspectiveName}" 未找到`
});
}
console.log(`成功找到透视: ${perspectiveName}`);
// 2. 切换到透视 - 关键:使用正确的方法
const windows = doc.windows;
if (windows.length === 0) {
return JSON.stringify({
success: false,
error: "没有可用窗口"
});
}
const window = windows[0];
console.log("使用第一个窗口");
// 切换透视
window.perspective = targetPerspective;
console.log(`已切换到透视: ${perspectiveName}`);
// 3. 获取透视内容 - 使用验证过的方法
const tasks = [];
try {
const content = window.content;
if (!content || !content.rootNode) {
return JSON.stringify({
success: false,
error: "无法获取窗口内容"
});
}
const rootNode = content.rootNode;
console.log("获取根节点成功");
// 获取所有后代节点
const allNodes = rootNode.descendantNodes;
console.log(`总节点数: ${allNodes.length}`);
// 遍历所有节点,寻找任务
for (let i = 0; i < allNodes.length; i++) {
try {
const node = allNodes[i];
const obj = node.object();
if (obj && obj.class && obj.class() === 'task') {
const completed = obj.completed();
const dropped = obj.dropped();
// 应用hideCompleted筛选
if (hideCompleted && (completed || dropped)) {
continue;
}
const taskData = {
id: obj.id(),
name: obj.name(),
note: obj.note() || "",
completed: completed,
dropped: dropped,
flagged: obj.flagged(),
dueDate: obj.dueDate() ? formatDate(obj.dueDate()) : null,
deferDate: obj.deferDate() ? formatDate(obj.deferDate()) : null,
completedDate: obj.completionDate() ? formatDate(obj.completionDate()) : null,
estimatedMinutes: obj.estimatedMinutes() || 0,
projectName: null,
tags: [],
containingProjectInfo: null,
parentTaskInfo: null
};
// 尝试获取项目信息
try {
if (obj.containingProject && obj.containingProject()) {
const project = obj.containingProject();
taskData.projectName = project.name();
taskData.containingProjectInfo = {
name: project.name(),
id: project.id(),
status: "active status"
};
}
} catch (projError) {
// 忽略项目信息获取错误
}
tasks.push(taskData);
// 应用限制
if (limit > 0 && tasks.length >= limit) {
break;
}
}
} catch (nodeError) {
// 忽略单个节点错误,继续处理其他节点
}
}
} catch (contentError) {
console.log(`获取内容失败: ${contentError.message}`);
return JSON.stringify({
success: false,
error: `获取透视内容失败: ${contentError.message}`
});
}
const result = {
success: true,
perspectiveInfo: {
name: perspectiveName,
rulesCount: 1,
aggregation: "perspective_native"
},
tasks: tasks,
isReal: true,
apiVersion: "JXA兼容的透视访问"
};
console.log(`JXA方式获取透视 "${perspectiveName}" 返回 ${tasks.length} 个任务`);
return JSON.stringify(result);
} catch (error) {
console.log(`JXA透视访问失败: ${error.message}`);
return JSON.stringify({
success: false,
error: `JXA透视访问失败: ${error.message}`,
apiVersion: "JXA兼容的透视访问"
});
}
})();