@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.
Files changed (223) hide show
  1. package/dist/schemas/shapes.d.ts +3 -33
  2. package/dist/schemas/shapes.d.ts.map +1 -1
  3. package/dist/schemas/shapes.js +3 -5
  4. package/dist/schemas/shapes.js.map +1 -1
  5. package/dist/server.js +3 -5
  6. package/dist/server.js.map +1 -1
  7. package/dist/tools/createTask.d.ts +1 -11
  8. package/dist/tools/createTask.d.ts.map +1 -1
  9. package/dist/tools/editTask.d.ts +1 -11
  10. package/dist/tools/editTask.d.ts.map +1 -1
  11. package/dist/tools/index.d.ts +2 -22
  12. package/dist/tools/index.d.ts.map +1 -1
  13. package/package.json +7 -1
  14. package/src/snippets/edit_task.js +4 -6
  15. package/.claude/commands/opsx/apply.md +0 -152
  16. package/.claude/commands/opsx/archive.md +0 -157
  17. package/.claude/commands/opsx/bulk-archive.md +0 -242
  18. package/.claude/commands/opsx/continue.md +0 -114
  19. package/.claude/commands/opsx/explore.md +0 -173
  20. package/.claude/commands/opsx/ff.md +0 -97
  21. package/.claude/commands/opsx/new.md +0 -69
  22. package/.claude/commands/opsx/onboard.md +0 -550
  23. package/.claude/commands/opsx/propose.md +0 -106
  24. package/.claude/commands/opsx/sync.md +0 -134
  25. package/.claude/commands/opsx/verify.md +0 -164
  26. package/.claude/skills/openspec-apply-change/SKILL.md +0 -156
  27. package/.claude/skills/openspec-archive-change/SKILL.md +0 -114
  28. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -246
  29. package/.claude/skills/openspec-continue-change/SKILL.md +0 -118
  30. package/.claude/skills/openspec-explore/SKILL.md +0 -288
  31. package/.claude/skills/openspec-ff-change/SKILL.md +0 -101
  32. package/.claude/skills/openspec-new-change/SKILL.md +0 -74
  33. package/.claude/skills/openspec-onboard/SKILL.md +0 -554
  34. package/.claude/skills/openspec-propose/SKILL.md +0 -110
  35. package/.claude/skills/openspec-sync-specs/SKILL.md +0 -138
  36. package/.claude/skills/openspec-verify-change/SKILL.md +0 -168
  37. package/CONTRIBUTING.md +0 -83
  38. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/.openspec.yaml +0 -2
  39. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/design.md +0 -162
  40. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/proposal.md +0 -49
  41. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/attachments/spec.md +0 -9
  42. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/batch-operations/spec.md +0 -9
  43. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/database-inspection/spec.md +0 -9
  44. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/execution-runtime/spec.md +0 -69
  45. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/folder-management/spec.md +0 -25
  46. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/forecast/spec.md +0 -9
  47. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/identity-resolution/spec.md +0 -45
  48. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/perspective-management/spec.md +0 -9
  49. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/project-management/spec.md +0 -25
  50. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/recurrence/spec.md +0 -9
  51. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/settings/spec.md +0 -9
  52. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/tag-management/spec.md +0 -25
  53. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/task-management/spec.md +0 -29
  54. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/url-automation/spec.md +0 -9
  55. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/window-state/spec.md +0 -9
  56. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/tasks.md +0 -84
  57. package/openspec/changes/archive/2026-04-09-folder-crud/.openspec.yaml +0 -2
  58. package/openspec/changes/archive/2026-04-09-folder-crud/design.md +0 -58
  59. package/openspec/changes/archive/2026-04-09-folder-crud/proposal.md +0 -28
  60. package/openspec/changes/archive/2026-04-09-folder-crud/specs/folder-write/spec.md +0 -45
  61. package/openspec/changes/archive/2026-04-09-folder-crud/tasks.md +0 -41
  62. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/.openspec.yaml +0 -2
  63. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/design.md +0 -38
  64. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/proposal.md +0 -30
  65. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/specs/folder-management/spec.md +0 -21
  66. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/specs/tag-management/spec.md +0 -21
  67. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/tasks.md +0 -35
  68. package/openspec/changes/archive/2026-04-09-move-operations/.openspec.yaml +0 -2
  69. package/openspec/changes/archive/2026-04-09-move-operations/design.md +0 -43
  70. package/openspec/changes/archive/2026-04-09-move-operations/proposal.md +0 -25
  71. package/openspec/changes/archive/2026-04-09-move-operations/specs/move-operations/spec.md +0 -41
  72. package/openspec/changes/archive/2026-04-09-move-operations/tasks.md +0 -40
  73. package/openspec/changes/archive/2026-04-09-project-crud/.openspec.yaml +0 -2
  74. package/openspec/changes/archive/2026-04-09-project-crud/design.md +0 -60
  75. package/openspec/changes/archive/2026-04-09-project-crud/proposal.md +0 -29
  76. package/openspec/changes/archive/2026-04-09-project-crud/specs/project-write/spec.md +0 -74
  77. package/openspec/changes/archive/2026-04-09-project-crud/tasks.md +0 -48
  78. package/openspec/changes/archive/2026-04-09-project-filtering/.openspec.yaml +0 -2
  79. package/openspec/changes/archive/2026-04-09-project-filtering/design.md +0 -52
  80. package/openspec/changes/archive/2026-04-09-project-filtering/proposal.md +0 -26
  81. package/openspec/changes/archive/2026-04-09-project-filtering/specs/project-filtering/spec.md +0 -66
  82. package/openspec/changes/archive/2026-04-09-project-filtering/specs/project-management/spec.md +0 -13
  83. package/openspec/changes/archive/2026-04-09-project-filtering/tasks.md +0 -41
  84. package/openspec/changes/archive/2026-04-09-tag-crud/.openspec.yaml +0 -2
  85. package/openspec/changes/archive/2026-04-09-tag-crud/design.md +0 -45
  86. package/openspec/changes/archive/2026-04-09-tag-crud/proposal.md +0 -28
  87. package/openspec/changes/archive/2026-04-09-tag-crud/specs/tag-write/spec.md +0 -49
  88. package/openspec/changes/archive/2026-04-09-tag-crud/tasks.md +0 -41
  89. package/openspec/changes/archive/2026-04-09-task-crud/.openspec.yaml +0 -2
  90. package/openspec/changes/archive/2026-04-09-task-crud/design.md +0 -62
  91. package/openspec/changes/archive/2026-04-09-task-crud/proposal.md +0 -29
  92. package/openspec/changes/archive/2026-04-09-task-crud/specs/task-management/spec.md +0 -17
  93. package/openspec/changes/archive/2026-04-09-task-crud/specs/task-write/spec.md +0 -89
  94. package/openspec/changes/archive/2026-04-09-task-crud/tasks.md +0 -55
  95. package/openspec/changes/archive/2026-04-09-task-filtering/.openspec.yaml +0 -2
  96. package/openspec/changes/archive/2026-04-09-task-filtering/design.md +0 -61
  97. package/openspec/changes/archive/2026-04-09-task-filtering/proposal.md +0 -26
  98. package/openspec/changes/archive/2026-04-09-task-filtering/specs/task-filtering/spec.md +0 -63
  99. package/openspec/changes/archive/2026-04-09-task-filtering/specs/task-management/spec.md +0 -17
  100. package/openspec/changes/archive/2026-04-09-task-filtering/tasks.md +0 -42
  101. package/openspec/changes/archive/2026-04-10-planned-date/.openspec.yaml +0 -2
  102. package/openspec/changes/archive/2026-04-10-planned-date/design.md +0 -27
  103. package/openspec/changes/archive/2026-04-10-planned-date/proposal.md +0 -29
  104. package/openspec/changes/archive/2026-04-10-planned-date/specs/task-management/spec.md +0 -29
  105. package/openspec/changes/archive/2026-04-10-planned-date/specs/task-write/spec.md +0 -69
  106. package/openspec/changes/archive/2026-04-10-planned-date/tasks.md +0 -26
  107. package/openspec/changes/archive/2026-04-10-task-recurrence/.openspec.yaml +0 -2
  108. package/openspec/changes/archive/2026-04-10-task-recurrence/design.md +0 -81
  109. package/openspec/changes/archive/2026-04-10-task-recurrence/proposal.md +0 -28
  110. package/openspec/changes/archive/2026-04-10-task-recurrence/specs/recurrence/spec.md +0 -47
  111. package/openspec/changes/archive/2026-04-10-task-recurrence/specs/task-management/spec.md +0 -25
  112. package/openspec/changes/archive/2026-04-10-task-recurrence/specs/task-write/spec.md +0 -61
  113. package/openspec/changes/archive/2026-04-10-task-recurrence/tasks.md +0 -39
  114. package/openspec/config.yaml +0 -20
  115. package/openspec/specs/attachments/spec.md +0 -15
  116. package/openspec/specs/batch-operations/spec.md +0 -15
  117. package/openspec/specs/database-inspection/spec.md +0 -15
  118. package/openspec/specs/execution-runtime/spec.md +0 -75
  119. package/openspec/specs/folder-management/spec.md +0 -39
  120. package/openspec/specs/folder-write/spec.md +0 -45
  121. package/openspec/specs/forecast/spec.md +0 -15
  122. package/openspec/specs/identity-resolution/spec.md +0 -51
  123. package/openspec/specs/move-operations/spec.md +0 -41
  124. package/openspec/specs/perspective-management/spec.md +0 -15
  125. package/openspec/specs/project-filtering/spec.md +0 -72
  126. package/openspec/specs/project-management/spec.md +0 -31
  127. package/openspec/specs/project-write/spec.md +0 -79
  128. package/openspec/specs/recurrence/spec.md +0 -51
  129. package/openspec/specs/settings/spec.md +0 -15
  130. package/openspec/specs/tag-management/spec.md +0 -39
  131. package/openspec/specs/tag-write/spec.md +0 -49
  132. package/openspec/specs/task-filtering/spec.md +0 -63
  133. package/openspec/specs/task-management/spec.md +0 -51
  134. package/openspec/specs/task-write/spec.md +0 -115
  135. package/openspec/specs/url-automation/spec.md +0 -15
  136. package/openspec/specs/window-state/spec.md +0 -15
  137. package/scripts/cleanup-fixtures.ts +0 -89
  138. package/server.json +0 -21
  139. package/src/runtime/bridge.ts +0 -97
  140. package/src/runtime/index.ts +0 -4
  141. package/src/runtime/jxaShim.ts +0 -55
  142. package/src/runtime/resultProtocol.ts +0 -62
  143. package/src/runtime/snippetLoader.ts +0 -79
  144. package/src/schemas/enums.ts +0 -32
  145. package/src/schemas/index.ts +0 -38
  146. package/src/schemas/shapes.ts +0 -267
  147. package/src/server.ts +0 -58
  148. package/src/tools/completeProject.ts +0 -21
  149. package/src/tools/completeTask.ts +0 -23
  150. package/src/tools/createFolder.ts +0 -20
  151. package/src/tools/createProject.ts +0 -20
  152. package/src/tools/createTag.ts +0 -20
  153. package/src/tools/createTask.ts +0 -20
  154. package/src/tools/deleteFolder.ts +0 -24
  155. package/src/tools/deleteProject.ts +0 -24
  156. package/src/tools/deleteTag.ts +0 -24
  157. package/src/tools/deleteTask.ts +0 -26
  158. package/src/tools/dropProject.ts +0 -21
  159. package/src/tools/dropTask.ts +0 -23
  160. package/src/tools/editFolder.ts +0 -19
  161. package/src/tools/editProject.ts +0 -20
  162. package/src/tools/editTag.ts +0 -20
  163. package/src/tools/editTask.ts +0 -20
  164. package/src/tools/getFolder.ts +0 -24
  165. package/src/tools/getProject.ts +0 -24
  166. package/src/tools/getTag.ts +0 -24
  167. package/src/tools/getTask.ts +0 -24
  168. package/src/tools/index.ts +0 -85
  169. package/src/tools/listFolders.ts +0 -32
  170. package/src/tools/listProjects.ts +0 -32
  171. package/src/tools/listTags.ts +0 -32
  172. package/src/tools/listTasks.ts +0 -56
  173. package/src/tools/moveProject.ts +0 -20
  174. package/src/tools/moveTask.ts +0 -20
  175. package/src/tools/resolveName.ts +0 -37
  176. package/test/integration/.gitkeep +0 -0
  177. package/test/integration/completeProject.int.test.ts +0 -25
  178. package/test/integration/completeTask.int.test.ts +0 -30
  179. package/test/integration/createFolder.int.test.ts +0 -50
  180. package/test/integration/createProject.int.test.ts +0 -49
  181. package/test/integration/createTag.int.test.ts +0 -52
  182. package/test/integration/createTask.int.test.ts +0 -55
  183. package/test/integration/deleteFolder.int.test.ts +0 -64
  184. package/test/integration/deleteProject.int.test.ts +0 -31
  185. package/test/integration/deleteTag.int.test.ts +0 -61
  186. package/test/integration/deleteTask.int.test.ts +0 -36
  187. package/test/integration/dropProject.int.test.ts +0 -24
  188. package/test/integration/dropTask.int.test.ts +0 -29
  189. package/test/integration/editFolder.int.test.ts +0 -43
  190. package/test/integration/editProject.int.test.ts +0 -39
  191. package/test/integration/editTag.int.test.ts +0 -43
  192. package/test/integration/editTask.int.test.ts +0 -56
  193. package/test/integration/fixtures.ts +0 -219
  194. package/test/integration/getTask.int.test.ts +0 -64
  195. package/test/integration/listFoldersFiltered.int.test.ts +0 -98
  196. package/test/integration/listProjects.int.test.ts +0 -73
  197. package/test/integration/listProjectsFiltered.int.test.ts +0 -96
  198. package/test/integration/listTagsFiltered.int.test.ts +0 -54
  199. package/test/integration/listTasksFiltered.int.test.ts +0 -141
  200. package/test/integration/moveProject.int.test.ts +0 -57
  201. package/test/integration/moveTask.int.test.ts +0 -61
  202. package/test/integration/plannedDate.int.test.ts +0 -72
  203. package/test/integration/preflight.ts +0 -60
  204. package/test/integration/resolveName.int.test.ts +0 -86
  205. package/test/integration/taskRecurrence.int.test.ts +0 -106
  206. package/test/unit/.gitkeep +0 -0
  207. package/test/unit/bridge.injection.test.ts +0 -66
  208. package/test/unit/resultProtocol.test.ts +0 -71
  209. package/test/unit/schemas.createFolder.test.ts +0 -38
  210. package/test/unit/schemas.createProject.test.ts +0 -115
  211. package/test/unit/schemas.createTask.test.ts +0 -87
  212. package/test/unit/schemas.editTag.test.ts +0 -64
  213. package/test/unit/schemas.folderTagFiltering.test.ts +0 -42
  214. package/test/unit/schemas.listProjects.test.ts +0 -44
  215. package/test/unit/schemas.moveOperations.test.ts +0 -60
  216. package/test/unit/schemas.recurrence.test.ts +0 -120
  217. package/test/unit/schemas.test.ts +0 -126
  218. package/test/unit/snippetLoader.test.ts +0 -56
  219. package/test/unit/tools.deleteTask.test.ts +0 -19
  220. package/test/unit/tools.listTasks.test.ts +0 -126
  221. package/tsconfig.json +0 -19
  222. package/vitest.config.ts +0 -8
  223. package/vitest.integration.config.ts +0 -18
@@ -1,37 +0,0 @@
1
- import { z } from "zod";
2
- import { runSnippet } from "../runtime/index.js";
3
- import { EntityType, ResolveCandidate } from "../schemas/index.js";
4
-
5
- export const resolveNameSchema = z.object({
6
- type: EntityType.describe(
7
- "The entity type to search: task, project, folder, tag, or perspective"
8
- ),
9
- query: z.string().min(1).describe("Exact name to search for"),
10
- scope: z
11
- .string()
12
- .optional()
13
- .describe(
14
- 'Optional path prefix to narrow results, e.g. "Work ▸ Clients"'
15
- ),
16
- });
17
-
18
- export type ResolveNameInput = z.infer<typeof resolveNameSchema>;
19
-
20
- export async function resolveNameHandler(
21
- input: ResolveNameInput
22
- ): Promise<z.infer<typeof ResolveCandidate>[]> {
23
- const raw = await runSnippet("resolve_name", {
24
- type: input.type,
25
- query: input.query,
26
- scope: input.scope ?? null,
27
- });
28
- return z.array(ResolveCandidate).parse(raw);
29
- }
30
-
31
- export const resolveNameTool = {
32
- name: "resolve_name",
33
- description:
34
- "Resolve an entity name to its stable ID(s). Returns ALL matches — never silently picks one. If multiple candidates are returned, ask the user or caller to disambiguate using the path field before proceeding with a write operation.",
35
- inputSchema: resolveNameSchema,
36
- handler: resolveNameHandler,
37
- } as const;
File without changes
@@ -1,25 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { ProjectDetail } from "../../src/schemas/index.js";
5
-
6
- describe("complete_project (integration)", () => {
7
- let fixture: TestFixture;
8
- let projectId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- projectId = await createTestProject(fixture.folderId, "CompleteProject Test Project");
13
- });
14
-
15
- afterAll(async () => {
16
- await cleanupTestFolder(fixture.folderId);
17
- });
18
-
19
- it("marks project complete and returns status done", async () => {
20
- const raw = await runSnippet("complete_project", { id: projectId });
21
- const project = ProjectDetail.parse(raw);
22
- expect(project.status).toBe("done");
23
- expect(project.completionDate).not.toBeNull();
24
- });
25
- });
@@ -1,30 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { TaskDetail } from "../../src/schemas/index.js";
5
-
6
- describe("complete_task (integration)", () => {
7
- let fixture: TestFixture;
8
- let taskId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- const projectId = await createTestProject(fixture.folderId, "CompleteTask Test Project");
13
- const taskRaw = await runSnippet("create_task", {
14
- name: "Task to complete",
15
- projectId,
16
- });
17
- taskId = TaskDetail.parse(taskRaw).id;
18
- });
19
-
20
- afterAll(async () => {
21
- await cleanupTestFolder(fixture.folderId);
22
- });
23
-
24
- it("marks task complete and returns status complete", async () => {
25
- const raw = await runSnippet("complete_task", { id: taskId });
26
- const task = TaskDetail.parse(raw);
27
- expect(task.status).toBe("complete");
28
- expect(task.completionDate).not.toBeNull();
29
- });
30
- });
@@ -1,50 +0,0 @@
1
- import { describe, it, expect, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { cleanupTestFolder } from "./fixtures.js";
4
- import { FolderDetail } from "../../src/schemas/index.js";
5
-
6
- describe("create_folder (integration)", () => {
7
- const createdFolderIds: string[] = [];
8
-
9
- afterAll(async () => {
10
- for (const id of createdFolderIds) {
11
- await cleanupTestFolder(id);
12
- }
13
- });
14
-
15
- it("creates a top-level folder and returns stable id", async () => {
16
- const name = `__mcp_test_folder_${Date.now()}__`;
17
- const raw = await runSnippet("create_folder", { name });
18
- const folder = FolderDetail.parse(raw);
19
- expect(folder.id).toBeTruthy();
20
- expect(folder.name).toBe(name);
21
- expect(folder.parentId).toBeNull();
22
- expect(folder.path).toBe(name);
23
- createdFolderIds.push(folder.id);
24
- });
25
-
26
- it("creates a nested folder with correct path and parentId", async () => {
27
- const parentName = `__mcp_test_parent_${Date.now()}__`;
28
- const parentRaw = await runSnippet("create_folder", { name: parentName });
29
- const parent = FolderDetail.parse(parentRaw);
30
- createdFolderIds.push(parent.id);
31
-
32
- const childRaw = await runSnippet("create_folder", {
33
- name: "Child",
34
- parentFolderId: parent.id,
35
- });
36
- const child = FolderDetail.parse(childRaw);
37
- expect(child.parentId).toBe(parent.id);
38
- expect(child.path).toContain(parentName);
39
- expect(child.path).toContain("Child");
40
- });
41
-
42
- it("returns not-found error for invalid parentFolderId", async () => {
43
- await expect(
44
- runSnippet("create_folder", { name: "X", parentFolderId: "nonexistent-id-xyz" })
45
- ).rejects.toSatisfy((e: unknown) => {
46
- const err = e as Record<string, unknown>;
47
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
48
- });
49
- });
50
- });
@@ -1,49 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, type TestFixture } from "./fixtures.js";
4
- import { ProjectDetail } from "../../src/schemas/index.js";
5
-
6
- describe("create_project (integration)", () => {
7
- let fixture: TestFixture;
8
-
9
- beforeAll(async () => {
10
- fixture = await createTestFolder();
11
- });
12
-
13
- afterAll(async () => {
14
- await cleanupTestFolder(fixture.folderId);
15
- });
16
-
17
- it("creates a top-level project and returns stable id", async () => {
18
- const name = `__mcp_test_proj_${Date.now()}__`;
19
- const raw = await runSnippet("create_project", { name });
20
- const project = ProjectDetail.parse(raw);
21
- expect(project.id).toBeTruthy();
22
- expect(project.name).toBe(name);
23
- expect(project.folderPath).toBe("");
24
- expect(project.type).toBe("parallel");
25
- // Clean up the top-level project
26
- await runSnippet("delete_project", { id: project.id });
27
- });
28
-
29
- it("creates project inside a folder and sets folderPath", async () => {
30
- const raw = await runSnippet("create_project", {
31
- name: "Folder Project Test",
32
- folderId: fixture.folderId,
33
- });
34
- const project = ProjectDetail.parse(raw);
35
- expect(project.id).toBeTruthy();
36
- expect(project.folderPath).toBeTruthy();
37
- expect(project.type).toBe("parallel");
38
- });
39
-
40
- it("creates sequential project and returns type sequential", async () => {
41
- const raw = await runSnippet("create_project", {
42
- name: "Sequential Project Test",
43
- folderId: fixture.folderId,
44
- type: "sequential",
45
- });
46
- const project = ProjectDetail.parse(raw);
47
- expect(project.type).toBe("sequential");
48
- });
49
- });
@@ -1,52 +0,0 @@
1
- import { describe, it, expect, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { deleteTestTag } from "./fixtures.js";
4
- import { TagDetail } from "../../src/schemas/index.js";
5
-
6
- describe("create_tag (integration)", () => {
7
- const createdTagIds: string[] = [];
8
-
9
- afterAll(async () => {
10
- for (const id of createdTagIds) {
11
- await deleteTestTag(id);
12
- }
13
- });
14
-
15
- it("creates a top-level tag and returns stable id", async () => {
16
- const name = `__mcp_test_tag_${Date.now()}__`;
17
- const raw = await runSnippet("create_tag", { name });
18
- const tag = TagDetail.parse(raw);
19
- expect(tag.id).toBeTruthy();
20
- expect(tag.name).toBe(name);
21
- expect(tag.parentId).toBeNull();
22
- expect(tag.path).toBe(name);
23
- createdTagIds.push(tag.id);
24
- });
25
-
26
- it("creates a child tag with correct path and parentId", async () => {
27
- const parentName = `__mcp_test_parent_tag_${Date.now()}__`;
28
- const parentRaw = await runSnippet("create_tag", { name: parentName });
29
- const parent = TagDetail.parse(parentRaw);
30
- createdTagIds.push(parent.id);
31
-
32
- const childRaw = await runSnippet("create_tag", {
33
- name: "Child",
34
- parentTagId: parent.id,
35
- });
36
- const child = TagDetail.parse(childRaw);
37
- expect(child.parentId).toBe(parent.id);
38
- expect(child.path).toContain(parentName);
39
- expect(child.path).toContain("Child");
40
- // Parent should now list child
41
- expect(parent.childTagIds).not.toContain(child.id); // stale parent object; child is real
42
- });
43
-
44
- it("returns not-found error for invalid parentTagId", async () => {
45
- await expect(
46
- runSnippet("create_tag", { name: "X", parentTagId: "nonexistent-id-xyz" })
47
- ).rejects.toSatisfy((e: unknown) => {
48
- const err = e as Record<string, unknown>;
49
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
50
- });
51
- });
52
- });
@@ -1,55 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { TaskDetail } from "../../src/schemas/index.js";
5
-
6
- describe("create_task (integration)", () => {
7
- let fixture: TestFixture;
8
- let projectId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- projectId = await createTestProject(fixture.folderId, "CreateTask Test Project");
13
- });
14
-
15
- afterAll(async () => {
16
- await cleanupTestFolder(fixture.folderId);
17
- });
18
-
19
- it("creates an inbox task and returns a stable id", async () => {
20
- const raw = await runSnippet("create_task", { name: "Inbox task test" });
21
- const task = TaskDetail.parse(raw);
22
- expect(task.id).toBeTruthy();
23
- expect(task.name).toBe("Inbox task test");
24
- expect(task.containerType).toBe("inbox");
25
- // Clean up inbox task
26
- await runSnippet("delete_task", { id: task.id });
27
- });
28
-
29
- it("creates a task in a project and sets containerId", async () => {
30
- const raw = await runSnippet("create_task", {
31
- name: "Project task test",
32
- projectId,
33
- });
34
- const task = TaskDetail.parse(raw);
35
- expect(task.id).toBeTruthy();
36
- expect(task.name).toBe("Project task test");
37
- expect(task.containerId).toBe(projectId);
38
- expect(task.containerType).toBe("project");
39
- });
40
-
41
- it("creates a subtask and sets parentTaskId", async () => {
42
- const parentRaw = await runSnippet("create_task", {
43
- name: "Parent task",
44
- projectId,
45
- });
46
- const parent = TaskDetail.parse(parentRaw);
47
-
48
- const childRaw = await runSnippet("create_task", {
49
- name: "Child task",
50
- parentTaskId: parent.id,
51
- });
52
- const child = TaskDetail.parse(childRaw);
53
- expect(child.parentTaskId).toBe(parent.id);
54
- });
55
- });
@@ -1,64 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { FolderDetail } from "../../src/schemas/index.js";
5
-
6
- describe("delete_folder (integration)", () => {
7
- let fixture: TestFixture;
8
-
9
- beforeAll(async () => {
10
- fixture = await createTestFolder();
11
- });
12
-
13
- afterAll(async () => {
14
- // Best-effort cleanup — the folder may already be deleted by the test
15
- try { await cleanupTestFolder(fixture.folderId); } catch (_) {}
16
- });
17
-
18
- it("deletes folder with child project and get_folder returns not-found afterwards", async () => {
19
- // Create a nested folder with a project inside the fixture
20
- const childRaw = await runSnippet("create_folder", {
21
- name: "ToDelete",
22
- parentFolderId: fixture.folderId,
23
- });
24
- const childFolder = FolderDetail.parse(childRaw);
25
- await createTestProject(childFolder.id, "Project inside folder");
26
-
27
- // Delete the child folder
28
- await runSnippet("delete_folder", { id: childFolder.id });
29
-
30
- // get_folder should return not-found
31
- await expect(
32
- runSnippet("get_folder", { id: childFolder.id })
33
- ).rejects.toSatisfy((e: unknown) => {
34
- const err = e as Record<string, unknown>;
35
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
36
- });
37
- });
38
-
39
- it("deletes an empty folder", async () => {
40
- const raw = await runSnippet("create_folder", {
41
- name: "EmptyToDelete",
42
- parentFolderId: fixture.folderId,
43
- });
44
- const folder = FolderDetail.parse(raw);
45
-
46
- await runSnippet("delete_folder", { id: folder.id });
47
-
48
- await expect(
49
- runSnippet("get_folder", { id: folder.id })
50
- ).rejects.toSatisfy((e: unknown) => {
51
- const err = e as Record<string, unknown>;
52
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
53
- });
54
- });
55
-
56
- it("returns not-found error for invalid id", async () => {
57
- await expect(
58
- runSnippet("delete_folder", { id: "nonexistent-id-xyz" })
59
- ).rejects.toSatisfy((e: unknown) => {
60
- const err = e as Record<string, unknown>;
61
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
62
- });
63
- });
64
- });
@@ -1,31 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { ProjectDetail } from "../../src/schemas/index.js";
5
-
6
- describe("delete_project (integration)", () => {
7
- let fixture: TestFixture;
8
- let projectId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- projectId = await createTestProject(fixture.folderId, "DeleteProject Test Project");
13
- });
14
-
15
- afterAll(async () => {
16
- await cleanupTestFolder(fixture.folderId);
17
- });
18
-
19
- it("deletes the project and get_project returns not-found afterwards", async () => {
20
- await runSnippet("delete_project", { id: projectId });
21
-
22
- await expect(
23
- runSnippet("get_project", { id: projectId })
24
- ).rejects.toSatisfy(
25
- (e: unknown) => {
26
- const err = e as Record<string, unknown>;
27
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
28
- }
29
- );
30
- });
31
- });
@@ -1,61 +0,0 @@
1
- import { describe, it, expect, beforeAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestTag } from "./fixtures.js";
4
- import { TagDetail } from "../../src/schemas/index.js";
5
-
6
- describe("delete_tag (integration)", () => {
7
- let tagId: string;
8
- let parentTagId: string;
9
-
10
- beforeAll(async () => {
11
- tagId = await createTestTag(`__mcp_test_del_tag_${Date.now()}__`);
12
- parentTagId = await createTestTag(`__mcp_test_del_parent_${Date.now()}__`);
13
- });
14
-
15
- it("deletes a tag and get_tag returns not-found afterwards", async () => {
16
- await runSnippet("delete_tag", { id: tagId });
17
-
18
- await expect(
19
- runSnippet("get_tag", { id: tagId })
20
- ).rejects.toSatisfy((e: unknown) => {
21
- const err = e as Record<string, unknown>;
22
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
23
- });
24
- });
25
-
26
- it("deletes parent tag and child tags are also gone", async () => {
27
- // Create a child tag under parentTagId
28
- const childRaw = await runSnippet("create_tag", {
29
- name: "ChildToDelete",
30
- parentTagId,
31
- });
32
- const child = TagDetail.parse(childRaw);
33
-
34
- // Delete the parent
35
- await runSnippet("delete_tag", { id: parentTagId });
36
-
37
- // Both parent and child should be gone
38
- await expect(
39
- runSnippet("get_tag", { id: parentTagId })
40
- ).rejects.toSatisfy((e: unknown) => {
41
- const err = e as Record<string, unknown>;
42
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
43
- });
44
-
45
- await expect(
46
- runSnippet("get_tag", { id: child.id })
47
- ).rejects.toSatisfy((e: unknown) => {
48
- const err = e as Record<string, unknown>;
49
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
50
- });
51
- });
52
-
53
- it("returns not-found error for invalid id", async () => {
54
- await expect(
55
- runSnippet("delete_tag", { id: "nonexistent-id-xyz" })
56
- ).rejects.toSatisfy((e: unknown) => {
57
- const err = e as Record<string, unknown>;
58
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
59
- });
60
- });
61
- });
@@ -1,36 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { TaskDetail } from "../../src/schemas/index.js";
5
-
6
- describe("delete_task (integration)", () => {
7
- let fixture: TestFixture;
8
- let taskId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- const projectId = await createTestProject(fixture.folderId, "DeleteTask Test Project");
13
- const taskRaw = await runSnippet("create_task", {
14
- name: "Task to delete",
15
- projectId,
16
- });
17
- taskId = TaskDetail.parse(taskRaw).id;
18
- });
19
-
20
- afterAll(async () => {
21
- await cleanupTestFolder(fixture.folderId);
22
- });
23
-
24
- it("deletes the task and get_task returns not-found afterwards", async () => {
25
- await runSnippet("delete_task", { id: taskId });
26
-
27
- await expect(
28
- runSnippet("get_task", { id: taskId })
29
- ).rejects.toSatisfy(
30
- (e: unknown) => {
31
- const err = e as Record<string, unknown>;
32
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
33
- }
34
- );
35
- });
36
- });
@@ -1,24 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { ProjectDetail } from "../../src/schemas/index.js";
5
-
6
- describe("drop_project (integration)", () => {
7
- let fixture: TestFixture;
8
- let projectId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- projectId = await createTestProject(fixture.folderId, "DropProject Test Project");
13
- });
14
-
15
- afterAll(async () => {
16
- await cleanupTestFolder(fixture.folderId);
17
- });
18
-
19
- it("marks project dropped and returns status dropped", async () => {
20
- const raw = await runSnippet("drop_project", { id: projectId });
21
- const project = ProjectDetail.parse(raw);
22
- expect(project.status).toBe("dropped");
23
- });
24
- });
@@ -1,29 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { TaskDetail } from "../../src/schemas/index.js";
5
-
6
- describe("drop_task (integration)", () => {
7
- let fixture: TestFixture;
8
- let taskId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- const projectId = await createTestProject(fixture.folderId, "DropTask Test Project");
13
- const taskRaw = await runSnippet("create_task", {
14
- name: "Task to drop",
15
- projectId,
16
- });
17
- taskId = TaskDetail.parse(taskRaw).id;
18
- });
19
-
20
- afterAll(async () => {
21
- await cleanupTestFolder(fixture.folderId);
22
- });
23
-
24
- it("marks task dropped and returns status dropped", async () => {
25
- const raw = await runSnippet("drop_task", { id: taskId });
26
- const task = TaskDetail.parse(raw);
27
- expect(task.status).toBe("dropped");
28
- });
29
- });
@@ -1,43 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, type TestFixture } from "./fixtures.js";
4
- import { FolderDetail } from "../../src/schemas/index.js";
5
-
6
- describe("edit_folder (integration)", () => {
7
- let fixture: TestFixture;
8
- let childFolderId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- // Create a child folder to rename
13
- const raw = await runSnippet("create_folder", {
14
- name: "Original Name",
15
- parentFolderId: fixture.folderId,
16
- });
17
- const folder = FolderDetail.parse(raw);
18
- childFolderId = folder.id;
19
- });
20
-
21
- afterAll(async () => {
22
- await cleanupTestFolder(fixture.folderId);
23
- });
24
-
25
- it("renames a folder and returns updated name and path", async () => {
26
- const raw = await runSnippet("edit_folder", {
27
- id: childFolderId,
28
- name: "Renamed Folder",
29
- });
30
- const folder = FolderDetail.parse(raw);
31
- expect(folder.name).toBe("Renamed Folder");
32
- expect(folder.path).toContain("Renamed Folder");
33
- });
34
-
35
- it("returns not-found error for invalid id", async () => {
36
- await expect(
37
- runSnippet("edit_folder", { id: "nonexistent-id-xyz", name: "X" })
38
- ).rejects.toSatisfy((e: unknown) => {
39
- const err = e as Record<string, unknown>;
40
- return err.name === "ExecutionError" && err.errorName === "NotFoundError";
41
- });
42
- });
43
- });
@@ -1,39 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { runSnippet } from "../../src/runtime/bridge.js";
3
- import { createTestFolder, cleanupTestFolder, createTestProject, type TestFixture } from "./fixtures.js";
4
- import { ProjectDetail } from "../../src/schemas/index.js";
5
-
6
- describe("edit_project (integration)", () => {
7
- let fixture: TestFixture;
8
- let projectId: string;
9
-
10
- beforeAll(async () => {
11
- fixture = await createTestFolder();
12
- projectId = await createTestProject(fixture.folderId, "EditProject Test Project");
13
- });
14
-
15
- afterAll(async () => {
16
- await cleanupTestFolder(fixture.folderId);
17
- });
18
-
19
- it("edits name only; other fields unchanged", async () => {
20
- const raw = await runSnippet("edit_project", { id: projectId, name: "Updated name" });
21
- const project = ProjectDetail.parse(raw);
22
- expect(project.name).toBe("Updated name");
23
- });
24
-
25
- it("sets status to onHold", async () => {
26
- const raw = await runSnippet("edit_project", { id: projectId, status: "onHold" });
27
- const project = ProjectDetail.parse(raw);
28
- expect(project.status).toBe("onHold");
29
- });
30
-
31
- it("sets review interval", async () => {
32
- const raw = await runSnippet("edit_project", {
33
- id: projectId,
34
- reviewInterval: { steps: 2, unit: "weeks" },
35
- });
36
- const project = ProjectDetail.parse(raw);
37
- expect(project.reviewInterval).toBeTruthy();
38
- });
39
- });