@scardis/omnifocus-mcp 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schemas/shapes.d.ts +3 -33
- package/dist/schemas/shapes.d.ts.map +1 -1
- package/dist/schemas/shapes.js +3 -5
- package/dist/schemas/shapes.js.map +1 -1
- package/dist/server.js +3 -5
- package/dist/server.js.map +1 -1
- package/dist/tools/createTask.d.ts +1 -11
- package/dist/tools/createTask.d.ts.map +1 -1
- package/dist/tools/editTask.d.ts +1 -11
- package/dist/tools/editTask.d.ts.map +1 -1
- package/dist/tools/index.d.ts +2 -22
- package/dist/tools/index.d.ts.map +1 -1
- package/package.json +7 -1
- package/src/snippets/edit_task.js +4 -6
- package/.claude/commands/opsx/apply.md +0 -152
- package/.claude/commands/opsx/archive.md +0 -157
- package/.claude/commands/opsx/bulk-archive.md +0 -242
- package/.claude/commands/opsx/continue.md +0 -114
- package/.claude/commands/opsx/explore.md +0 -173
- package/.claude/commands/opsx/ff.md +0 -97
- package/.claude/commands/opsx/new.md +0 -69
- package/.claude/commands/opsx/onboard.md +0 -550
- package/.claude/commands/opsx/propose.md +0 -106
- package/.claude/commands/opsx/sync.md +0 -134
- package/.claude/commands/opsx/verify.md +0 -164
- package/.claude/skills/openspec-apply-change/SKILL.md +0 -156
- package/.claude/skills/openspec-archive-change/SKILL.md +0 -114
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -246
- package/.claude/skills/openspec-continue-change/SKILL.md +0 -118
- package/.claude/skills/openspec-explore/SKILL.md +0 -288
- package/.claude/skills/openspec-ff-change/SKILL.md +0 -101
- package/.claude/skills/openspec-new-change/SKILL.md +0 -74
- package/.claude/skills/openspec-onboard/SKILL.md +0 -554
- package/.claude/skills/openspec-propose/SKILL.md +0 -110
- package/.claude/skills/openspec-sync-specs/SKILL.md +0 -138
- package/.claude/skills/openspec-verify-change/SKILL.md +0 -168
- package/CONTRIBUTING.md +0 -83
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/design.md +0 -162
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/proposal.md +0 -49
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/attachments/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/batch-operations/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/database-inspection/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/execution-runtime/spec.md +0 -69
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/folder-management/spec.md +0 -25
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/forecast/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/identity-resolution/spec.md +0 -45
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/perspective-management/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/project-management/spec.md +0 -25
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/recurrence/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/settings/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/tag-management/spec.md +0 -25
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/task-management/spec.md +0 -29
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/url-automation/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/window-state/spec.md +0 -9
- package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/tasks.md +0 -84
- package/openspec/changes/archive/2026-04-09-folder-crud/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-folder-crud/design.md +0 -58
- package/openspec/changes/archive/2026-04-09-folder-crud/proposal.md +0 -28
- package/openspec/changes/archive/2026-04-09-folder-crud/specs/folder-write/spec.md +0 -45
- package/openspec/changes/archive/2026-04-09-folder-crud/tasks.md +0 -41
- package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/design.md +0 -38
- package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/proposal.md +0 -30
- package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/specs/folder-management/spec.md +0 -21
- package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/specs/tag-management/spec.md +0 -21
- package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/tasks.md +0 -35
- package/openspec/changes/archive/2026-04-09-move-operations/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-move-operations/design.md +0 -43
- package/openspec/changes/archive/2026-04-09-move-operations/proposal.md +0 -25
- package/openspec/changes/archive/2026-04-09-move-operations/specs/move-operations/spec.md +0 -41
- package/openspec/changes/archive/2026-04-09-move-operations/tasks.md +0 -40
- package/openspec/changes/archive/2026-04-09-project-crud/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-project-crud/design.md +0 -60
- package/openspec/changes/archive/2026-04-09-project-crud/proposal.md +0 -29
- package/openspec/changes/archive/2026-04-09-project-crud/specs/project-write/spec.md +0 -74
- package/openspec/changes/archive/2026-04-09-project-crud/tasks.md +0 -48
- package/openspec/changes/archive/2026-04-09-project-filtering/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-project-filtering/design.md +0 -52
- package/openspec/changes/archive/2026-04-09-project-filtering/proposal.md +0 -26
- package/openspec/changes/archive/2026-04-09-project-filtering/specs/project-filtering/spec.md +0 -66
- package/openspec/changes/archive/2026-04-09-project-filtering/specs/project-management/spec.md +0 -13
- package/openspec/changes/archive/2026-04-09-project-filtering/tasks.md +0 -41
- package/openspec/changes/archive/2026-04-09-tag-crud/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-tag-crud/design.md +0 -45
- package/openspec/changes/archive/2026-04-09-tag-crud/proposal.md +0 -28
- package/openspec/changes/archive/2026-04-09-tag-crud/specs/tag-write/spec.md +0 -49
- package/openspec/changes/archive/2026-04-09-tag-crud/tasks.md +0 -41
- package/openspec/changes/archive/2026-04-09-task-crud/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-task-crud/design.md +0 -62
- package/openspec/changes/archive/2026-04-09-task-crud/proposal.md +0 -29
- package/openspec/changes/archive/2026-04-09-task-crud/specs/task-management/spec.md +0 -17
- package/openspec/changes/archive/2026-04-09-task-crud/specs/task-write/spec.md +0 -89
- package/openspec/changes/archive/2026-04-09-task-crud/tasks.md +0 -55
- package/openspec/changes/archive/2026-04-09-task-filtering/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-09-task-filtering/design.md +0 -61
- package/openspec/changes/archive/2026-04-09-task-filtering/proposal.md +0 -26
- package/openspec/changes/archive/2026-04-09-task-filtering/specs/task-filtering/spec.md +0 -63
- package/openspec/changes/archive/2026-04-09-task-filtering/specs/task-management/spec.md +0 -17
- package/openspec/changes/archive/2026-04-09-task-filtering/tasks.md +0 -42
- package/openspec/changes/archive/2026-04-10-planned-date/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-10-planned-date/design.md +0 -27
- package/openspec/changes/archive/2026-04-10-planned-date/proposal.md +0 -29
- package/openspec/changes/archive/2026-04-10-planned-date/specs/task-management/spec.md +0 -29
- package/openspec/changes/archive/2026-04-10-planned-date/specs/task-write/spec.md +0 -69
- package/openspec/changes/archive/2026-04-10-planned-date/tasks.md +0 -26
- package/openspec/changes/archive/2026-04-10-task-recurrence/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-10-task-recurrence/design.md +0 -81
- package/openspec/changes/archive/2026-04-10-task-recurrence/proposal.md +0 -28
- package/openspec/changes/archive/2026-04-10-task-recurrence/specs/recurrence/spec.md +0 -47
- package/openspec/changes/archive/2026-04-10-task-recurrence/specs/task-management/spec.md +0 -25
- package/openspec/changes/archive/2026-04-10-task-recurrence/specs/task-write/spec.md +0 -61
- package/openspec/changes/archive/2026-04-10-task-recurrence/tasks.md +0 -39
- package/openspec/config.yaml +0 -20
- package/openspec/specs/attachments/spec.md +0 -15
- package/openspec/specs/batch-operations/spec.md +0 -15
- package/openspec/specs/database-inspection/spec.md +0 -15
- package/openspec/specs/execution-runtime/spec.md +0 -75
- package/openspec/specs/folder-management/spec.md +0 -39
- package/openspec/specs/folder-write/spec.md +0 -45
- package/openspec/specs/forecast/spec.md +0 -15
- package/openspec/specs/identity-resolution/spec.md +0 -51
- package/openspec/specs/move-operations/spec.md +0 -41
- package/openspec/specs/perspective-management/spec.md +0 -15
- package/openspec/specs/project-filtering/spec.md +0 -72
- package/openspec/specs/project-management/spec.md +0 -31
- package/openspec/specs/project-write/spec.md +0 -79
- package/openspec/specs/recurrence/spec.md +0 -51
- package/openspec/specs/settings/spec.md +0 -15
- package/openspec/specs/tag-management/spec.md +0 -39
- package/openspec/specs/tag-write/spec.md +0 -49
- package/openspec/specs/task-filtering/spec.md +0 -63
- package/openspec/specs/task-management/spec.md +0 -51
- package/openspec/specs/task-write/spec.md +0 -115
- package/openspec/specs/url-automation/spec.md +0 -15
- package/openspec/specs/window-state/spec.md +0 -15
- package/scripts/cleanup-fixtures.ts +0 -89
- package/server.json +0 -21
- package/src/runtime/bridge.ts +0 -97
- package/src/runtime/index.ts +0 -4
- package/src/runtime/jxaShim.ts +0 -55
- package/src/runtime/resultProtocol.ts +0 -62
- package/src/runtime/snippetLoader.ts +0 -79
- package/src/schemas/enums.ts +0 -32
- package/src/schemas/index.ts +0 -38
- package/src/schemas/shapes.ts +0 -267
- package/src/server.ts +0 -58
- package/src/tools/completeProject.ts +0 -21
- package/src/tools/completeTask.ts +0 -23
- package/src/tools/createFolder.ts +0 -20
- package/src/tools/createProject.ts +0 -20
- package/src/tools/createTag.ts +0 -20
- package/src/tools/createTask.ts +0 -20
- package/src/tools/deleteFolder.ts +0 -24
- package/src/tools/deleteProject.ts +0 -24
- package/src/tools/deleteTag.ts +0 -24
- package/src/tools/deleteTask.ts +0 -26
- package/src/tools/dropProject.ts +0 -21
- package/src/tools/dropTask.ts +0 -23
- package/src/tools/editFolder.ts +0 -19
- package/src/tools/editProject.ts +0 -20
- package/src/tools/editTag.ts +0 -20
- package/src/tools/editTask.ts +0 -20
- package/src/tools/getFolder.ts +0 -24
- package/src/tools/getProject.ts +0 -24
- package/src/tools/getTag.ts +0 -24
- package/src/tools/getTask.ts +0 -24
- package/src/tools/index.ts +0 -85
- package/src/tools/listFolders.ts +0 -32
- package/src/tools/listProjects.ts +0 -32
- package/src/tools/listTags.ts +0 -32
- package/src/tools/listTasks.ts +0 -56
- package/src/tools/moveProject.ts +0 -20
- package/src/tools/moveTask.ts +0 -20
- package/src/tools/resolveName.ts +0 -37
- package/test/integration/.gitkeep +0 -0
- package/test/integration/completeProject.int.test.ts +0 -25
- package/test/integration/completeTask.int.test.ts +0 -30
- package/test/integration/createFolder.int.test.ts +0 -50
- package/test/integration/createProject.int.test.ts +0 -49
- package/test/integration/createTag.int.test.ts +0 -52
- package/test/integration/createTask.int.test.ts +0 -55
- package/test/integration/deleteFolder.int.test.ts +0 -64
- package/test/integration/deleteProject.int.test.ts +0 -31
- package/test/integration/deleteTag.int.test.ts +0 -61
- package/test/integration/deleteTask.int.test.ts +0 -36
- package/test/integration/dropProject.int.test.ts +0 -24
- package/test/integration/dropTask.int.test.ts +0 -29
- package/test/integration/editFolder.int.test.ts +0 -43
- package/test/integration/editProject.int.test.ts +0 -39
- package/test/integration/editTag.int.test.ts +0 -43
- package/test/integration/editTask.int.test.ts +0 -56
- package/test/integration/fixtures.ts +0 -219
- package/test/integration/getTask.int.test.ts +0 -64
- package/test/integration/listFoldersFiltered.int.test.ts +0 -98
- package/test/integration/listProjects.int.test.ts +0 -73
- package/test/integration/listProjectsFiltered.int.test.ts +0 -96
- package/test/integration/listTagsFiltered.int.test.ts +0 -54
- package/test/integration/listTasksFiltered.int.test.ts +0 -141
- package/test/integration/moveProject.int.test.ts +0 -57
- package/test/integration/moveTask.int.test.ts +0 -61
- package/test/integration/plannedDate.int.test.ts +0 -72
- package/test/integration/preflight.ts +0 -60
- package/test/integration/resolveName.int.test.ts +0 -86
- package/test/integration/taskRecurrence.int.test.ts +0 -106
- package/test/unit/.gitkeep +0 -0
- package/test/unit/bridge.injection.test.ts +0 -66
- package/test/unit/resultProtocol.test.ts +0 -71
- package/test/unit/schemas.createFolder.test.ts +0 -38
- package/test/unit/schemas.createProject.test.ts +0 -115
- package/test/unit/schemas.createTask.test.ts +0 -87
- package/test/unit/schemas.editTag.test.ts +0 -64
- package/test/unit/schemas.folderTagFiltering.test.ts +0 -42
- package/test/unit/schemas.listProjects.test.ts +0 -44
- package/test/unit/schemas.moveOperations.test.ts +0 -60
- package/test/unit/schemas.recurrence.test.ts +0 -120
- package/test/unit/schemas.test.ts +0 -126
- package/test/unit/snippetLoader.test.ts +0 -56
- package/test/unit/tools.deleteTask.test.ts +0 -19
- package/test/unit/tools.listTasks.test.ts +0 -126
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -8
- package/vitest.integration.config.ts +0 -18
package/src/runtime/jxaShim.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JXA wrapper template. The `__SNIPPET__` placeholder is replaced with the
|
|
3
|
-
* OmniJS snippet to execute. The resulting script is passed to
|
|
4
|
-
* `osascript -l JavaScript` via stdin.
|
|
5
|
-
*
|
|
6
|
-
* This shim:
|
|
7
|
-
* - Calls Application('OmniFocus').evaluateJavascript() with the snippet
|
|
8
|
-
* - Wraps in try/catch
|
|
9
|
-
* - Prints exactly one line of JSON: {ok, data} | {ok: false, error: {...}}
|
|
10
|
-
*
|
|
11
|
-
* The JXA scripting dictionary is used ONLY for evaluateJavascript.
|
|
12
|
-
* No other scripting-dictionary domain methods are invoked here.
|
|
13
|
-
*/
|
|
14
|
-
export const JXA_SHIM_TEMPLATE = `
|
|
15
|
-
(function() {
|
|
16
|
-
var snippet = __SNIPPET__;
|
|
17
|
-
var app = Application('OmniFocus');
|
|
18
|
-
app.includeStandardAdditions = true;
|
|
19
|
-
try {
|
|
20
|
-
var result = app.evaluateJavascript(snippet);
|
|
21
|
-
// result is already a JSON string produced by the snippet
|
|
22
|
-
$.NSFileHandle.fileHandleWithStandardOutput.writeData(
|
|
23
|
-
$.NSString.alloc.initWithString(result + '\\n')
|
|
24
|
-
.dataUsingEncoding($.NSUTF8StringEncoding)
|
|
25
|
-
);
|
|
26
|
-
} catch(e) {
|
|
27
|
-
var errName = e.name || 'Error';
|
|
28
|
-
var errMsg = e.message || String(e);
|
|
29
|
-
// OmniJS wraps thrown errors; the original name is embedded in the message
|
|
30
|
-
// as "SomeName: original message". Recover it when the name is generic.
|
|
31
|
-
var nameMatch = errMsg.match(/^([A-Z]\\w*Error): ([\\s\\S]*)$/);
|
|
32
|
-
if (nameMatch) { errName = nameMatch[1]; errMsg = nameMatch[2]; }
|
|
33
|
-
var err = JSON.stringify({
|
|
34
|
-
ok: false,
|
|
35
|
-
error: {
|
|
36
|
-
name: errName,
|
|
37
|
-
message: errMsg
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
$.NSFileHandle.fileHandleWithStandardOutput.writeData(
|
|
41
|
-
$.NSString.alloc.initWithString(err + '\\n')
|
|
42
|
-
.dataUsingEncoding($.NSUTF8StringEncoding)
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
})();
|
|
46
|
-
`;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Build the complete JXA script to pass to osascript.
|
|
50
|
-
* The snippet is embedded as a JS string literal via JSON.stringify,
|
|
51
|
-
* so it is safe to contain any characters including quotes, backslashes, etc.
|
|
52
|
-
*/
|
|
53
|
-
export function buildJxaScript(snippet: string): string {
|
|
54
|
-
return JXA_SHIM_TEMPLATE.replace("__SNIPPET__", JSON.stringify(snippet));
|
|
55
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
const ErrorDetail = z.object({
|
|
4
|
-
name: z.string(),
|
|
5
|
-
message: z.string(),
|
|
6
|
-
stack: z.string().optional(),
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
const SuccessEnvelope = z.object({
|
|
10
|
-
ok: z.literal(true),
|
|
11
|
-
data: z.unknown(),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
const ErrorEnvelope = z.object({
|
|
15
|
-
ok: z.literal(false),
|
|
16
|
-
error: ErrorDetail,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const Envelope = z.discriminatedUnion("ok", [SuccessEnvelope, ErrorEnvelope]);
|
|
20
|
-
|
|
21
|
-
export type ResultEnvelope = z.infer<typeof Envelope>;
|
|
22
|
-
|
|
23
|
-
export class ExecutionError extends Error {
|
|
24
|
-
readonly errorName: string;
|
|
25
|
-
readonly remoteStack?: string;
|
|
26
|
-
|
|
27
|
-
constructor(detail: z.infer<typeof ErrorDetail>) {
|
|
28
|
-
super(detail.message);
|
|
29
|
-
this.name = "ExecutionError";
|
|
30
|
-
this.errorName = detail.name;
|
|
31
|
-
this.remoteStack = detail.stack;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Scans stdout for the first JSON-parseable line and validates it as a result
|
|
37
|
-
* envelope. Ignores any preceding non-JSON chatter (e.g. osascript warnings).
|
|
38
|
-
*/
|
|
39
|
-
export function parseResultLine(stdout: string): ResultEnvelope {
|
|
40
|
-
const lines = stdout.split("\n");
|
|
41
|
-
for (const line of lines) {
|
|
42
|
-
const trimmed = line.trim();
|
|
43
|
-
if (!trimmed) continue;
|
|
44
|
-
let parsed: unknown;
|
|
45
|
-
try {
|
|
46
|
-
parsed = JSON.parse(trimmed);
|
|
47
|
-
} catch {
|
|
48
|
-
continue; // not JSON, skip
|
|
49
|
-
}
|
|
50
|
-
const result = Envelope.safeParse(parsed);
|
|
51
|
-
if (result.success) {
|
|
52
|
-
return result.data;
|
|
53
|
-
}
|
|
54
|
-
// Parsed as JSON but not a valid envelope — this is a protocol error
|
|
55
|
-
throw new Error(
|
|
56
|
-
`Bridge returned JSON that is not a valid result envelope: ${trimmed}`
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
throw new Error(
|
|
60
|
-
`No valid JSON result envelope found in osascript output:\n${stdout}`
|
|
61
|
-
);
|
|
62
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import { join, dirname } from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
|
|
5
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const SNIPPETS_DIR = join(__dirname, "..", "snippets");
|
|
7
|
-
|
|
8
|
-
// Allowlist of valid snippet names. Adding a new snippet requires an explicit
|
|
9
|
-
// entry here, which prevents path-traversal attacks if a snippet name ever
|
|
10
|
-
// reaches this loader from a dynamic source.
|
|
11
|
-
const ALLOWED_SNIPPETS = new Set([
|
|
12
|
-
"get_folder",
|
|
13
|
-
"get_project",
|
|
14
|
-
"get_tag",
|
|
15
|
-
"get_task",
|
|
16
|
-
"list_folders",
|
|
17
|
-
"list_projects",
|
|
18
|
-
"list_tags",
|
|
19
|
-
"list_tasks",
|
|
20
|
-
"resolve_name",
|
|
21
|
-
"create_task",
|
|
22
|
-
"edit_task",
|
|
23
|
-
"complete_task",
|
|
24
|
-
"drop_task",
|
|
25
|
-
"delete_task",
|
|
26
|
-
"create_project",
|
|
27
|
-
"edit_project",
|
|
28
|
-
"complete_project",
|
|
29
|
-
"drop_project",
|
|
30
|
-
"delete_project",
|
|
31
|
-
"create_folder",
|
|
32
|
-
"edit_folder",
|
|
33
|
-
"delete_folder",
|
|
34
|
-
"create_tag",
|
|
35
|
-
"edit_tag",
|
|
36
|
-
"delete_tag",
|
|
37
|
-
"move_task",
|
|
38
|
-
"move_project",
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const cache = new Map<string, string>();
|
|
42
|
-
|
|
43
|
-
export function loadSnippet(name: string): string {
|
|
44
|
-
if (!ALLOWED_SNIPPETS.has(name)) {
|
|
45
|
-
throw new Error(`Unknown snippet: "${name}"`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (cache.has(name)) {
|
|
49
|
-
return cache.get(name)!;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const filePath = join(SNIPPETS_DIR, `${name}.js`);
|
|
53
|
-
let content: string;
|
|
54
|
-
try {
|
|
55
|
-
content = readFileSync(filePath, "utf-8");
|
|
56
|
-
} catch {
|
|
57
|
-
throw new Error(`Snippet "${name}" could not be loaded`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const matches = content.split("__ARGS__").length - 1;
|
|
61
|
-
if (matches === 0) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`Snippet "${name}" contains no __ARGS__ placeholder. Every snippet must have exactly one.`
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
if (matches > 1) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
`Snippet "${name}" contains ${matches} __ARGS__ placeholders. Exactly one is required.`
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
cache.set(name, content);
|
|
73
|
-
return content;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** For testing: clear the in-memory cache. */
|
|
77
|
-
export function clearSnippetCache(): void {
|
|
78
|
-
cache.clear();
|
|
79
|
-
}
|
package/src/schemas/enums.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const IdSchema = z.string().min(1, "ID must be a non-empty string");
|
|
4
|
-
|
|
5
|
-
export const EntityType = z.enum([
|
|
6
|
-
"task",
|
|
7
|
-
"project",
|
|
8
|
-
"folder",
|
|
9
|
-
"tag",
|
|
10
|
-
"perspective",
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
export const ProjectType = z.enum(["parallel", "sequential", "singleActions"]);
|
|
14
|
-
|
|
15
|
-
export const ProjectStatus = z.enum(["active", "onHold", "done", "dropped"]);
|
|
16
|
-
|
|
17
|
-
export const TaskStatus = z.enum([
|
|
18
|
-
"available",
|
|
19
|
-
"incomplete",
|
|
20
|
-
"completedByChildren",
|
|
21
|
-
"complete",
|
|
22
|
-
"dropped",
|
|
23
|
-
"dueSoon",
|
|
24
|
-
"overdue",
|
|
25
|
-
"flagged",
|
|
26
|
-
"blocked",
|
|
27
|
-
"next",
|
|
28
|
-
]);
|
|
29
|
-
|
|
30
|
-
export const TagStatus = z.enum(["active", "onHold", "dropped"]);
|
|
31
|
-
|
|
32
|
-
export const FolderStatus = z.enum(["active", "dropped"]);
|
package/src/schemas/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
IdSchema,
|
|
3
|
-
EntityType,
|
|
4
|
-
ProjectType,
|
|
5
|
-
ProjectStatus,
|
|
6
|
-
TaskStatus,
|
|
7
|
-
TagStatus,
|
|
8
|
-
FolderStatus,
|
|
9
|
-
} from "./enums.js";
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
RepetitionRuleInput,
|
|
13
|
-
RepetitionRuleDetail,
|
|
14
|
-
TaskSummary,
|
|
15
|
-
ListTasksFilter,
|
|
16
|
-
TaskDetail,
|
|
17
|
-
CreateTaskInput,
|
|
18
|
-
EditTaskInput,
|
|
19
|
-
MoveTaskInput,
|
|
20
|
-
ReviewIntervalInput,
|
|
21
|
-
CreateProjectInput,
|
|
22
|
-
EditProjectInput,
|
|
23
|
-
MoveProjectInput,
|
|
24
|
-
ListProjectsFilter,
|
|
25
|
-
ProjectSummary,
|
|
26
|
-
ProjectDetail,
|
|
27
|
-
ListFoldersFilter,
|
|
28
|
-
CreateFolderInput,
|
|
29
|
-
EditFolderInput,
|
|
30
|
-
FolderSummary,
|
|
31
|
-
FolderDetail,
|
|
32
|
-
ListTagsFilter,
|
|
33
|
-
CreateTagInput,
|
|
34
|
-
EditTagInput,
|
|
35
|
-
TagSummary,
|
|
36
|
-
TagDetail,
|
|
37
|
-
ResolveCandidate,
|
|
38
|
-
} from "./shapes.js";
|
package/src/schemas/shapes.ts
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
IdSchema,
|
|
4
|
-
ProjectType,
|
|
5
|
-
ProjectStatus,
|
|
6
|
-
TaskStatus,
|
|
7
|
-
TagStatus,
|
|
8
|
-
FolderStatus,
|
|
9
|
-
EntityType,
|
|
10
|
-
} from "./enums.js";
|
|
11
|
-
|
|
12
|
-
// ─── Recurrence ──────────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
const RepetitionFrequency = z.enum(["daily", "weekly", "monthly", "yearly"]);
|
|
15
|
-
const RepetitionMethod = z.enum(["fixed", "dueDate", "start"]);
|
|
16
|
-
const DayOfWeek = z.enum(["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]);
|
|
17
|
-
|
|
18
|
-
export const RepetitionRuleInput = z
|
|
19
|
-
.object({
|
|
20
|
-
frequency: RepetitionFrequency,
|
|
21
|
-
interval: z.number().int().positive().default(1),
|
|
22
|
-
daysOfWeek: z.array(DayOfWeek).optional(),
|
|
23
|
-
method: RepetitionMethod,
|
|
24
|
-
})
|
|
25
|
-
.refine(
|
|
26
|
-
(d) => d.daysOfWeek === undefined || d.frequency === "weekly",
|
|
27
|
-
{ message: "daysOfWeek is only valid when frequency is 'weekly'" }
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
export const RepetitionRuleDetail = z.object({
|
|
31
|
-
frequency: RepetitionFrequency,
|
|
32
|
-
interval: z.number(),
|
|
33
|
-
daysOfWeek: z.array(DayOfWeek).optional(),
|
|
34
|
-
method: RepetitionMethod,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// ─── Task ────────────────────────────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
export const TaskSummary = z.object({
|
|
40
|
-
id: IdSchema,
|
|
41
|
-
name: z.string(),
|
|
42
|
-
status: TaskStatus,
|
|
43
|
-
flagged: z.boolean(),
|
|
44
|
-
containerId: IdSchema.nullable(),
|
|
45
|
-
containerType: z.enum(["project", "inbox", "task"]).nullable(),
|
|
46
|
-
dueDate: z.string().datetime().nullable(),
|
|
47
|
-
tagIds: z.array(IdSchema),
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export const ListTasksFilter = z.object({
|
|
51
|
-
flagged: z.literal(true).optional(),
|
|
52
|
-
status: z.array(TaskStatus).optional(),
|
|
53
|
-
tagId: IdSchema.optional(),
|
|
54
|
-
dueBeforeDate: z.string().datetime().optional(),
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
export const TaskDetail = z.object({
|
|
58
|
-
id: IdSchema,
|
|
59
|
-
name: z.string(),
|
|
60
|
-
note: z.string(),
|
|
61
|
-
status: TaskStatus,
|
|
62
|
-
flagged: z.boolean(),
|
|
63
|
-
deferDate: z.string().datetime().nullable(),
|
|
64
|
-
plannedDate: z.string().datetime().nullable(),
|
|
65
|
-
dueDate: z.string().datetime().nullable(),
|
|
66
|
-
completionDate: z.string().datetime().nullable(),
|
|
67
|
-
estimatedMinutes: z.number().nullable(),
|
|
68
|
-
containerId: IdSchema.nullable(),
|
|
69
|
-
containerType: z.enum(["project", "inbox", "task"]).nullable(),
|
|
70
|
-
tagIds: z.array(IdSchema),
|
|
71
|
-
parentTaskId: IdSchema.nullable(),
|
|
72
|
-
repetitionRule: RepetitionRuleDetail.nullable(),
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
export const CreateTaskInput = z
|
|
76
|
-
.object({
|
|
77
|
-
name: z.string().min(1),
|
|
78
|
-
note: z.string().optional(),
|
|
79
|
-
flagged: z.boolean().optional(),
|
|
80
|
-
deferDate: z.string().datetime().optional(),
|
|
81
|
-
plannedDate: z.string().datetime().optional(),
|
|
82
|
-
dueDate: z.string().datetime().optional(),
|
|
83
|
-
estimatedMinutes: z.number().int().positive().optional(),
|
|
84
|
-
projectId: IdSchema.optional(),
|
|
85
|
-
parentTaskId: IdSchema.optional(),
|
|
86
|
-
tagIds: z.array(IdSchema).optional(),
|
|
87
|
-
repetitionRule: RepetitionRuleInput.optional(),
|
|
88
|
-
})
|
|
89
|
-
.refine((d) => !(d.projectId && d.parentTaskId), {
|
|
90
|
-
message: "Provide projectId or parentTaskId, not both",
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
export const EditTaskInput = z.object({
|
|
94
|
-
id: IdSchema,
|
|
95
|
-
name: z.string().min(1).optional(),
|
|
96
|
-
note: z.string().optional(),
|
|
97
|
-
flagged: z.boolean().optional(),
|
|
98
|
-
deferDate: z.string().datetime().nullable().optional(),
|
|
99
|
-
plannedDate: z.string().datetime().nullable().optional(),
|
|
100
|
-
dueDate: z.string().datetime().nullable().optional(),
|
|
101
|
-
estimatedMinutes: z.number().int().positive().nullable().optional(),
|
|
102
|
-
tagIds: z.array(IdSchema).optional(),
|
|
103
|
-
repetitionRule: RepetitionRuleInput.nullable().optional(),
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// ─── Project ─────────────────────────────────────────────────────────────────
|
|
107
|
-
|
|
108
|
-
export const ReviewIntervalInput = z.object({
|
|
109
|
-
steps: z.number().int().positive(),
|
|
110
|
-
unit: z.enum(["days", "weeks", "months", "years"]),
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
export const CreateProjectInput = z.object({
|
|
114
|
-
name: z.string().min(1),
|
|
115
|
-
folderId: IdSchema.optional(),
|
|
116
|
-
note: z.string().optional(),
|
|
117
|
-
type: ProjectType.optional(),
|
|
118
|
-
status: z.enum(["active", "onHold"]).optional(),
|
|
119
|
-
flagged: z.boolean().optional(),
|
|
120
|
-
deferDate: z.string().datetime().optional(),
|
|
121
|
-
dueDate: z.string().datetime().optional(),
|
|
122
|
-
reviewInterval: ReviewIntervalInput.optional(),
|
|
123
|
-
tagIds: z.array(IdSchema).optional(),
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
export const EditProjectInput = z.object({
|
|
127
|
-
id: IdSchema,
|
|
128
|
-
name: z.string().min(1).optional(),
|
|
129
|
-
note: z.string().optional(),
|
|
130
|
-
type: ProjectType.optional(),
|
|
131
|
-
status: z.enum(["active", "onHold"]).optional(),
|
|
132
|
-
flagged: z.boolean().optional(),
|
|
133
|
-
deferDate: z.string().datetime().nullable().optional(),
|
|
134
|
-
dueDate: z.string().datetime().nullable().optional(),
|
|
135
|
-
reviewInterval: ReviewIntervalInput.optional(),
|
|
136
|
-
tagIds: z.array(IdSchema).optional(),
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
export const MoveTaskInput = z
|
|
140
|
-
.object({
|
|
141
|
-
id: IdSchema,
|
|
142
|
-
projectId: IdSchema.optional(),
|
|
143
|
-
parentTaskId: IdSchema.optional(),
|
|
144
|
-
})
|
|
145
|
-
.refine(
|
|
146
|
-
(d) => (d.projectId !== undefined) !== (d.parentTaskId !== undefined),
|
|
147
|
-
{ message: "Exactly one of projectId or parentTaskId must be provided" }
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
export const MoveProjectInput = z.object({
|
|
151
|
-
id: IdSchema,
|
|
152
|
-
folderId: IdSchema.nullable(),
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
export const ListFoldersFilter = z.object({
|
|
156
|
-
status: FolderStatus.optional(),
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
export const ListTagsFilter = z.object({
|
|
160
|
-
status: TagStatus.optional(),
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
export const ListProjectsFilter = z.object({
|
|
164
|
-
status: z.array(ProjectStatus).optional(),
|
|
165
|
-
folderId: IdSchema.optional(),
|
|
166
|
-
flagged: z.literal(true).optional(),
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
export const ProjectSummary = z.object({
|
|
170
|
-
id: IdSchema,
|
|
171
|
-
name: z.string(),
|
|
172
|
-
folderPath: z.string(),
|
|
173
|
-
folderId: IdSchema.nullable(),
|
|
174
|
-
status: ProjectStatus,
|
|
175
|
-
type: ProjectType,
|
|
176
|
-
flagged: z.boolean(),
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
export const ProjectDetail = z.object({
|
|
180
|
-
id: IdSchema,
|
|
181
|
-
name: z.string(),
|
|
182
|
-
note: z.string(),
|
|
183
|
-
folderPath: z.string(),
|
|
184
|
-
status: ProjectStatus,
|
|
185
|
-
type: ProjectType,
|
|
186
|
-
flagged: z.boolean(),
|
|
187
|
-
deferDate: z.string().datetime().nullable(),
|
|
188
|
-
dueDate: z.string().datetime().nullable(),
|
|
189
|
-
completionDate: z.string().datetime().nullable(),
|
|
190
|
-
reviewInterval: z.string().nullable(),
|
|
191
|
-
nextReviewDate: z.string().datetime().nullable(),
|
|
192
|
-
lastReviewDate: z.string().datetime().nullable(),
|
|
193
|
-
tagIds: z.array(IdSchema),
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
export const CreateFolderInput = z.object({
|
|
197
|
-
name: z.string().min(1),
|
|
198
|
-
parentFolderId: IdSchema.optional(),
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
export const EditFolderInput = z.object({
|
|
202
|
-
id: IdSchema,
|
|
203
|
-
name: z.string().min(1),
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// ─── Folder ──────────────────────────────────────────────────────────────────
|
|
207
|
-
|
|
208
|
-
export const FolderSummary = z.object({
|
|
209
|
-
id: IdSchema,
|
|
210
|
-
name: z.string(),
|
|
211
|
-
path: z.string(),
|
|
212
|
-
parentId: IdSchema.nullable(),
|
|
213
|
-
status: FolderStatus,
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
export const FolderDetail = z.object({
|
|
217
|
-
id: IdSchema,
|
|
218
|
-
name: z.string(),
|
|
219
|
-
path: z.string(),
|
|
220
|
-
parentId: IdSchema.nullable(),
|
|
221
|
-
status: FolderStatus,
|
|
222
|
-
childFolderIds: z.array(IdSchema),
|
|
223
|
-
projectIds: z.array(IdSchema),
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
export const CreateTagInput = z.object({
|
|
227
|
-
name: z.string().min(1),
|
|
228
|
-
parentTagId: IdSchema.optional(),
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
export const EditTagInput = z
|
|
232
|
-
.object({
|
|
233
|
-
id: IdSchema,
|
|
234
|
-
name: z.string().min(1).optional(),
|
|
235
|
-
status: TagStatus.optional(),
|
|
236
|
-
})
|
|
237
|
-
.refine((d) => d.name !== undefined || d.status !== undefined, {
|
|
238
|
-
message: "Provide at least one of name or status",
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
// ─── Tag ─────────────────────────────────────────────────────────────────────
|
|
242
|
-
|
|
243
|
-
export const TagSummary = z.object({
|
|
244
|
-
id: IdSchema,
|
|
245
|
-
name: z.string(),
|
|
246
|
-
path: z.string(),
|
|
247
|
-
parentId: IdSchema.nullable(),
|
|
248
|
-
status: TagStatus,
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
export const TagDetail = z.object({
|
|
252
|
-
id: IdSchema,
|
|
253
|
-
name: z.string(),
|
|
254
|
-
path: z.string(),
|
|
255
|
-
parentId: IdSchema.nullable(),
|
|
256
|
-
status: TagStatus,
|
|
257
|
-
childTagIds: z.array(IdSchema),
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
// ─── Resolution ──────────────────────────────────────────────────────────────
|
|
261
|
-
|
|
262
|
-
export const ResolveCandidate = z.object({
|
|
263
|
-
id: IdSchema,
|
|
264
|
-
name: z.string(),
|
|
265
|
-
path: z.string(),
|
|
266
|
-
type: EntityType,
|
|
267
|
-
});
|
package/src/server.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
import { allTools } from "./tools/index.js";
|
|
5
|
-
|
|
6
|
-
const server = new McpServer({
|
|
7
|
-
name: "omnifocus-mcp",
|
|
8
|
-
version: "0.1.0",
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
for (const tool of allTools) {
|
|
12
|
-
// Extract the shape from the zod object schema for registerTool.
|
|
13
|
-
// .refine() wraps in ZodEffects which has no .shape; unwrap via ._def.schema first.
|
|
14
|
-
const baseSchema =
|
|
15
|
-
tool.inputSchema instanceof z.ZodEffects
|
|
16
|
-
? (tool.inputSchema._def.schema as z.AnyZodObject)
|
|
17
|
-
: (tool.inputSchema as z.AnyZodObject);
|
|
18
|
-
const inputShape = baseSchema.shape;
|
|
19
|
-
|
|
20
|
-
server.registerTool(
|
|
21
|
-
tool.name,
|
|
22
|
-
{
|
|
23
|
-
description: tool.description,
|
|
24
|
-
inputSchema: inputShape,
|
|
25
|
-
},
|
|
26
|
-
async (args: Record<string, unknown>) => {
|
|
27
|
-
try {
|
|
28
|
-
// Validate input (already parsed by MCP SDK, re-parse for our shape)
|
|
29
|
-
const input = tool.inputSchema.parse(args);
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
-
const result = await (tool.handler as (input: any) => Promise<unknown>)(input);
|
|
32
|
-
return {
|
|
33
|
-
content: [
|
|
34
|
-
{
|
|
35
|
-
type: "text" as const,
|
|
36
|
-
text: JSON.stringify(result, null, 2),
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
};
|
|
40
|
-
} catch (err) {
|
|
41
|
-
const message =
|
|
42
|
-
err instanceof Error ? err.message : String(err);
|
|
43
|
-
return {
|
|
44
|
-
content: [
|
|
45
|
-
{
|
|
46
|
-
type: "text" as const,
|
|
47
|
-
text: `Error: ${message}`,
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
isError: true,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const transport = new StdioServerTransport();
|
|
58
|
-
await server.connect(transport);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { runSnippet } from "../runtime/index.js";
|
|
3
|
-
import { IdSchema, ProjectDetail } from "../schemas/index.js";
|
|
4
|
-
|
|
5
|
-
const CompleteProjectInput = z.object({
|
|
6
|
-
id: IdSchema.describe("The project's id.primaryKey"),
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
export async function completeProjectHandler(
|
|
10
|
-
input: z.infer<typeof CompleteProjectInput>
|
|
11
|
-
): Promise<z.infer<typeof ProjectDetail>> {
|
|
12
|
-
const raw = await runSnippet("complete_project", { id: input.id });
|
|
13
|
-
return ProjectDetail.parse(raw);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const completeProjectTool = {
|
|
17
|
-
name: "complete_project",
|
|
18
|
-
description: "Mark a project as done (complete). Returns the updated project detail.",
|
|
19
|
-
inputSchema: CompleteProjectInput,
|
|
20
|
-
handler: completeProjectHandler,
|
|
21
|
-
} as const;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { runSnippet } from "../runtime/index.js";
|
|
3
|
-
import { IdSchema, TaskDetail } from "../schemas/index.js";
|
|
4
|
-
|
|
5
|
-
const completeTaskSchema = z.object({
|
|
6
|
-
id: IdSchema.describe("The task's id.primaryKey"),
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
export type CompleteTaskInput = z.infer<typeof completeTaskSchema>;
|
|
10
|
-
|
|
11
|
-
export async function completeTaskHandler(
|
|
12
|
-
input: CompleteTaskInput
|
|
13
|
-
): Promise<z.infer<typeof TaskDetail>> {
|
|
14
|
-
const raw = await runSnippet("complete_task", { id: input.id });
|
|
15
|
-
return TaskDetail.parse(raw);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const completeTaskTool = {
|
|
19
|
-
name: "complete_task",
|
|
20
|
-
description: "Mark a task complete by its stable ID. Returns the updated task detail.",
|
|
21
|
-
inputSchema: completeTaskSchema,
|
|
22
|
-
handler: completeTaskHandler,
|
|
23
|
-
} as const;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { runSnippet } from "../runtime/index.js";
|
|
3
|
-
import { CreateFolderInput, FolderDetail } from "../schemas/index.js";
|
|
4
|
-
|
|
5
|
-
export type CreateFolderInputType = z.infer<typeof CreateFolderInput>;
|
|
6
|
-
|
|
7
|
-
export async function createFolderHandler(
|
|
8
|
-
input: CreateFolderInputType
|
|
9
|
-
): Promise<z.infer<typeof FolderDetail>> {
|
|
10
|
-
const raw = await runSnippet("create_folder", input);
|
|
11
|
-
return FolderDetail.parse(raw);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const createFolderTool = {
|
|
15
|
-
name: "create_folder",
|
|
16
|
-
description:
|
|
17
|
-
"Create a new OmniFocus folder. Omit parentFolderId to create at the top level; provide parentFolderId to nest it inside an existing folder.",
|
|
18
|
-
inputSchema: CreateFolderInput,
|
|
19
|
-
handler: createFolderHandler,
|
|
20
|
-
} as const;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { runSnippet } from "../runtime/index.js";
|
|
3
|
-
import { CreateProjectInput, ProjectDetail } from "../schemas/index.js";
|
|
4
|
-
|
|
5
|
-
export type CreateProjectInputType = z.infer<typeof CreateProjectInput>;
|
|
6
|
-
|
|
7
|
-
export async function createProjectHandler(
|
|
8
|
-
input: CreateProjectInputType
|
|
9
|
-
): Promise<z.infer<typeof ProjectDetail>> {
|
|
10
|
-
const raw = await runSnippet("create_project", input);
|
|
11
|
-
return ProjectDetail.parse(raw);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const createProjectTool = {
|
|
15
|
-
name: "create_project",
|
|
16
|
-
description:
|
|
17
|
-
"Create a new OmniFocus project. Omit folderId to create at the top level; provide folderId to place it inside a folder. Optionally set type (parallel/sequential/singleActions), status (active/onHold), review interval, and tags.",
|
|
18
|
-
inputSchema: CreateProjectInput,
|
|
19
|
-
handler: createProjectHandler,
|
|
20
|
-
} as const;
|