@scardis/omnifocus-mcp 0.1.1 → 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 (210) hide show
  1. package/package.json +7 -1
  2. package/.claude/commands/opsx/apply.md +0 -152
  3. package/.claude/commands/opsx/archive.md +0 -157
  4. package/.claude/commands/opsx/bulk-archive.md +0 -242
  5. package/.claude/commands/opsx/continue.md +0 -114
  6. package/.claude/commands/opsx/explore.md +0 -173
  7. package/.claude/commands/opsx/ff.md +0 -97
  8. package/.claude/commands/opsx/new.md +0 -69
  9. package/.claude/commands/opsx/onboard.md +0 -550
  10. package/.claude/commands/opsx/propose.md +0 -106
  11. package/.claude/commands/opsx/sync.md +0 -134
  12. package/.claude/commands/opsx/verify.md +0 -164
  13. package/.claude/skills/openspec-apply-change/SKILL.md +0 -156
  14. package/.claude/skills/openspec-archive-change/SKILL.md +0 -114
  15. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -246
  16. package/.claude/skills/openspec-continue-change/SKILL.md +0 -118
  17. package/.claude/skills/openspec-explore/SKILL.md +0 -288
  18. package/.claude/skills/openspec-ff-change/SKILL.md +0 -101
  19. package/.claude/skills/openspec-new-change/SKILL.md +0 -74
  20. package/.claude/skills/openspec-onboard/SKILL.md +0 -554
  21. package/.claude/skills/openspec-propose/SKILL.md +0 -110
  22. package/.claude/skills/openspec-sync-specs/SKILL.md +0 -138
  23. package/.claude/skills/openspec-verify-change/SKILL.md +0 -168
  24. package/CONTRIBUTING.md +0 -83
  25. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/.openspec.yaml +0 -2
  26. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/design.md +0 -162
  27. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/proposal.md +0 -49
  28. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/attachments/spec.md +0 -9
  29. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/batch-operations/spec.md +0 -9
  30. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/database-inspection/spec.md +0 -9
  31. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/execution-runtime/spec.md +0 -69
  32. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/folder-management/spec.md +0 -25
  33. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/forecast/spec.md +0 -9
  34. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/identity-resolution/spec.md +0 -45
  35. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/perspective-management/spec.md +0 -9
  36. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/project-management/spec.md +0 -25
  37. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/recurrence/spec.md +0 -9
  38. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/settings/spec.md +0 -9
  39. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/tag-management/spec.md +0 -25
  40. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/task-management/spec.md +0 -29
  41. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/url-automation/spec.md +0 -9
  42. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/specs/window-state/spec.md +0 -9
  43. package/openspec/changes/archive/2026-04-09-bootstrap-omnifocus-mcp/tasks.md +0 -84
  44. package/openspec/changes/archive/2026-04-09-folder-crud/.openspec.yaml +0 -2
  45. package/openspec/changes/archive/2026-04-09-folder-crud/design.md +0 -58
  46. package/openspec/changes/archive/2026-04-09-folder-crud/proposal.md +0 -28
  47. package/openspec/changes/archive/2026-04-09-folder-crud/specs/folder-write/spec.md +0 -45
  48. package/openspec/changes/archive/2026-04-09-folder-crud/tasks.md +0 -41
  49. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/.openspec.yaml +0 -2
  50. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/design.md +0 -38
  51. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/proposal.md +0 -30
  52. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/specs/folder-management/spec.md +0 -21
  53. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/specs/tag-management/spec.md +0 -21
  54. package/openspec/changes/archive/2026-04-09-folder-tag-list-filtering/tasks.md +0 -35
  55. package/openspec/changes/archive/2026-04-09-move-operations/.openspec.yaml +0 -2
  56. package/openspec/changes/archive/2026-04-09-move-operations/design.md +0 -43
  57. package/openspec/changes/archive/2026-04-09-move-operations/proposal.md +0 -25
  58. package/openspec/changes/archive/2026-04-09-move-operations/specs/move-operations/spec.md +0 -41
  59. package/openspec/changes/archive/2026-04-09-move-operations/tasks.md +0 -40
  60. package/openspec/changes/archive/2026-04-09-project-crud/.openspec.yaml +0 -2
  61. package/openspec/changes/archive/2026-04-09-project-crud/design.md +0 -60
  62. package/openspec/changes/archive/2026-04-09-project-crud/proposal.md +0 -29
  63. package/openspec/changes/archive/2026-04-09-project-crud/specs/project-write/spec.md +0 -74
  64. package/openspec/changes/archive/2026-04-09-project-crud/tasks.md +0 -48
  65. package/openspec/changes/archive/2026-04-09-project-filtering/.openspec.yaml +0 -2
  66. package/openspec/changes/archive/2026-04-09-project-filtering/design.md +0 -52
  67. package/openspec/changes/archive/2026-04-09-project-filtering/proposal.md +0 -26
  68. package/openspec/changes/archive/2026-04-09-project-filtering/specs/project-filtering/spec.md +0 -66
  69. package/openspec/changes/archive/2026-04-09-project-filtering/specs/project-management/spec.md +0 -13
  70. package/openspec/changes/archive/2026-04-09-project-filtering/tasks.md +0 -41
  71. package/openspec/changes/archive/2026-04-09-tag-crud/.openspec.yaml +0 -2
  72. package/openspec/changes/archive/2026-04-09-tag-crud/design.md +0 -45
  73. package/openspec/changes/archive/2026-04-09-tag-crud/proposal.md +0 -28
  74. package/openspec/changes/archive/2026-04-09-tag-crud/specs/tag-write/spec.md +0 -49
  75. package/openspec/changes/archive/2026-04-09-tag-crud/tasks.md +0 -41
  76. package/openspec/changes/archive/2026-04-09-task-crud/.openspec.yaml +0 -2
  77. package/openspec/changes/archive/2026-04-09-task-crud/design.md +0 -62
  78. package/openspec/changes/archive/2026-04-09-task-crud/proposal.md +0 -29
  79. package/openspec/changes/archive/2026-04-09-task-crud/specs/task-management/spec.md +0 -17
  80. package/openspec/changes/archive/2026-04-09-task-crud/specs/task-write/spec.md +0 -89
  81. package/openspec/changes/archive/2026-04-09-task-crud/tasks.md +0 -55
  82. package/openspec/changes/archive/2026-04-09-task-filtering/.openspec.yaml +0 -2
  83. package/openspec/changes/archive/2026-04-09-task-filtering/design.md +0 -61
  84. package/openspec/changes/archive/2026-04-09-task-filtering/proposal.md +0 -26
  85. package/openspec/changes/archive/2026-04-09-task-filtering/specs/task-filtering/spec.md +0 -63
  86. package/openspec/changes/archive/2026-04-09-task-filtering/specs/task-management/spec.md +0 -17
  87. package/openspec/changes/archive/2026-04-09-task-filtering/tasks.md +0 -42
  88. package/openspec/changes/archive/2026-04-10-planned-date/.openspec.yaml +0 -2
  89. package/openspec/changes/archive/2026-04-10-planned-date/design.md +0 -27
  90. package/openspec/changes/archive/2026-04-10-planned-date/proposal.md +0 -29
  91. package/openspec/changes/archive/2026-04-10-planned-date/specs/task-management/spec.md +0 -29
  92. package/openspec/changes/archive/2026-04-10-planned-date/specs/task-write/spec.md +0 -69
  93. package/openspec/changes/archive/2026-04-10-planned-date/tasks.md +0 -26
  94. package/openspec/changes/archive/2026-04-10-task-recurrence/.openspec.yaml +0 -2
  95. package/openspec/changes/archive/2026-04-10-task-recurrence/design.md +0 -81
  96. package/openspec/changes/archive/2026-04-10-task-recurrence/proposal.md +0 -28
  97. package/openspec/changes/archive/2026-04-10-task-recurrence/specs/recurrence/spec.md +0 -47
  98. package/openspec/changes/archive/2026-04-10-task-recurrence/specs/task-management/spec.md +0 -25
  99. package/openspec/changes/archive/2026-04-10-task-recurrence/specs/task-write/spec.md +0 -61
  100. package/openspec/changes/archive/2026-04-10-task-recurrence/tasks.md +0 -39
  101. package/openspec/config.yaml +0 -20
  102. package/openspec/specs/attachments/spec.md +0 -15
  103. package/openspec/specs/batch-operations/spec.md +0 -15
  104. package/openspec/specs/database-inspection/spec.md +0 -15
  105. package/openspec/specs/execution-runtime/spec.md +0 -75
  106. package/openspec/specs/folder-management/spec.md +0 -39
  107. package/openspec/specs/folder-write/spec.md +0 -45
  108. package/openspec/specs/forecast/spec.md +0 -15
  109. package/openspec/specs/identity-resolution/spec.md +0 -51
  110. package/openspec/specs/move-operations/spec.md +0 -41
  111. package/openspec/specs/perspective-management/spec.md +0 -15
  112. package/openspec/specs/project-filtering/spec.md +0 -72
  113. package/openspec/specs/project-management/spec.md +0 -31
  114. package/openspec/specs/project-write/spec.md +0 -79
  115. package/openspec/specs/recurrence/spec.md +0 -51
  116. package/openspec/specs/settings/spec.md +0 -15
  117. package/openspec/specs/tag-management/spec.md +0 -39
  118. package/openspec/specs/tag-write/spec.md +0 -49
  119. package/openspec/specs/task-filtering/spec.md +0 -63
  120. package/openspec/specs/task-management/spec.md +0 -51
  121. package/openspec/specs/task-write/spec.md +0 -115
  122. package/openspec/specs/url-automation/spec.md +0 -15
  123. package/openspec/specs/window-state/spec.md +0 -15
  124. package/scripts/cleanup-fixtures.ts +0 -89
  125. package/server.json +0 -21
  126. package/src/runtime/bridge.ts +0 -97
  127. package/src/runtime/index.ts +0 -4
  128. package/src/runtime/jxaShim.ts +0 -55
  129. package/src/runtime/resultProtocol.ts +0 -62
  130. package/src/runtime/snippetLoader.ts +0 -79
  131. package/src/schemas/enums.ts +0 -32
  132. package/src/schemas/index.ts +0 -38
  133. package/src/schemas/shapes.ts +0 -263
  134. package/src/server.ts +0 -56
  135. package/src/tools/completeProject.ts +0 -21
  136. package/src/tools/completeTask.ts +0 -23
  137. package/src/tools/createFolder.ts +0 -20
  138. package/src/tools/createProject.ts +0 -20
  139. package/src/tools/createTag.ts +0 -20
  140. package/src/tools/createTask.ts +0 -20
  141. package/src/tools/deleteFolder.ts +0 -24
  142. package/src/tools/deleteProject.ts +0 -24
  143. package/src/tools/deleteTag.ts +0 -24
  144. package/src/tools/deleteTask.ts +0 -26
  145. package/src/tools/dropProject.ts +0 -21
  146. package/src/tools/dropTask.ts +0 -23
  147. package/src/tools/editFolder.ts +0 -19
  148. package/src/tools/editProject.ts +0 -20
  149. package/src/tools/editTag.ts +0 -20
  150. package/src/tools/editTask.ts +0 -20
  151. package/src/tools/getFolder.ts +0 -24
  152. package/src/tools/getProject.ts +0 -24
  153. package/src/tools/getTag.ts +0 -24
  154. package/src/tools/getTask.ts +0 -24
  155. package/src/tools/index.ts +0 -85
  156. package/src/tools/listFolders.ts +0 -32
  157. package/src/tools/listProjects.ts +0 -32
  158. package/src/tools/listTags.ts +0 -32
  159. package/src/tools/listTasks.ts +0 -56
  160. package/src/tools/moveProject.ts +0 -20
  161. package/src/tools/moveTask.ts +0 -20
  162. package/src/tools/resolveName.ts +0 -37
  163. package/test/integration/.gitkeep +0 -0
  164. package/test/integration/completeProject.int.test.ts +0 -25
  165. package/test/integration/completeTask.int.test.ts +0 -30
  166. package/test/integration/createFolder.int.test.ts +0 -50
  167. package/test/integration/createProject.int.test.ts +0 -49
  168. package/test/integration/createTag.int.test.ts +0 -52
  169. package/test/integration/createTask.int.test.ts +0 -55
  170. package/test/integration/deleteFolder.int.test.ts +0 -64
  171. package/test/integration/deleteProject.int.test.ts +0 -31
  172. package/test/integration/deleteTag.int.test.ts +0 -61
  173. package/test/integration/deleteTask.int.test.ts +0 -36
  174. package/test/integration/dropProject.int.test.ts +0 -24
  175. package/test/integration/dropTask.int.test.ts +0 -29
  176. package/test/integration/editFolder.int.test.ts +0 -43
  177. package/test/integration/editProject.int.test.ts +0 -39
  178. package/test/integration/editTag.int.test.ts +0 -43
  179. package/test/integration/editTask.int.test.ts +0 -56
  180. package/test/integration/fixtures.ts +0 -219
  181. package/test/integration/getTask.int.test.ts +0 -64
  182. package/test/integration/listFoldersFiltered.int.test.ts +0 -98
  183. package/test/integration/listProjects.int.test.ts +0 -73
  184. package/test/integration/listProjectsFiltered.int.test.ts +0 -96
  185. package/test/integration/listTagsFiltered.int.test.ts +0 -54
  186. package/test/integration/listTasksFiltered.int.test.ts +0 -141
  187. package/test/integration/moveProject.int.test.ts +0 -57
  188. package/test/integration/moveTask.int.test.ts +0 -61
  189. package/test/integration/plannedDate.int.test.ts +0 -72
  190. package/test/integration/preflight.ts +0 -60
  191. package/test/integration/resolveName.int.test.ts +0 -86
  192. package/test/integration/taskRecurrence.int.test.ts +0 -106
  193. package/test/unit/.gitkeep +0 -0
  194. package/test/unit/bridge.injection.test.ts +0 -66
  195. package/test/unit/resultProtocol.test.ts +0 -71
  196. package/test/unit/schemas.createFolder.test.ts +0 -38
  197. package/test/unit/schemas.createProject.test.ts +0 -115
  198. package/test/unit/schemas.createTask.test.ts +0 -87
  199. package/test/unit/schemas.editTag.test.ts +0 -64
  200. package/test/unit/schemas.folderTagFiltering.test.ts +0 -42
  201. package/test/unit/schemas.listProjects.test.ts +0 -44
  202. package/test/unit/schemas.moveOperations.test.ts +0 -60
  203. package/test/unit/schemas.recurrence.test.ts +0 -98
  204. package/test/unit/schemas.test.ts +0 -126
  205. package/test/unit/snippetLoader.test.ts +0 -56
  206. package/test/unit/tools.deleteTask.test.ts +0 -19
  207. package/test/unit/tools.listTasks.test.ts +0 -126
  208. package/tsconfig.json +0 -19
  209. package/vitest.config.ts +0 -8
  210. 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
- });