@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,66 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
-
3
- /**
4
- * Proves Design Decision 2:
5
- * JSON.stringify(args) produces a valid JS expression for any args value,
6
- * including apostrophes, quotes, backslashes, newlines, and unicode.
7
- *
8
- * We test the injection logic directly without hitting the bridge or OmniFocus.
9
- */
10
-
11
- const TRICKY_ARGS = {
12
- name: "Finn's \"birthday\" 🎯",
13
- note: "line1\nline2\ttabbed",
14
- path: "Work ▸ Clients ▸ Acme",
15
- backslash: "C:\\Users\\test",
16
- unicode: "\u2603 snowman \u0000 null",
17
- };
18
-
19
- function injectArgs(template: string, args: unknown): string {
20
- return template.replace("__ARGS__", JSON.stringify(args));
21
- }
22
-
23
- describe("argument injection safety", () => {
24
- it("produces valid JavaScript for tricky string values", () => {
25
- const template = "(() => { const args = __ARGS__; return args; })()";
26
- const injected = injectArgs(template, TRICKY_ARGS);
27
- // new Function wraps the body in a function; we eval the IIFE directly
28
- let result: unknown;
29
- expect(() => {
30
- result = new Function(`return ${injected}`)();
31
- }).not.toThrow();
32
- expect(result).toEqual(TRICKY_ARGS);
33
- });
34
-
35
- it("recovers apostrophes exactly", () => {
36
- const template = "(() => { const args = __ARGS__; return args; })()";
37
- const args = { name: "it's a test's value" };
38
- const injected = injectArgs(template, args);
39
- const result = new Function(`return ${injected}`)() as typeof args;
40
- expect(result.name).toBe("it's a test's value");
41
- });
42
-
43
- it("recovers double quotes exactly", () => {
44
- const template = "(() => { const args = __ARGS__; return args; })()";
45
- const args = { name: 'She said "hello"' };
46
- const injected = injectArgs(template, args);
47
- const result = new Function(`return ${injected}`)() as typeof args;
48
- expect(result.name).toBe('She said "hello"');
49
- });
50
-
51
- it("recovers newlines exactly", () => {
52
- const template = "(() => { const args = __ARGS__; return args; })()";
53
- const args = { note: "line1\nline2\nline3" };
54
- const injected = injectArgs(template, args);
55
- const result = new Function(`return ${injected}`)() as typeof args;
56
- expect(result.note).toBe("line1\nline2\nline3");
57
- });
58
-
59
- it("recovers unicode exactly", () => {
60
- const template = "(() => { const args = __ARGS__; return args; })()";
61
- const args = { symbol: "▸ ★ 🎉" };
62
- const injected = injectArgs(template, args);
63
- const result = new Function(`return ${injected}`)() as typeof args;
64
- expect(result.symbol).toBe("▸ ★ 🎉");
65
- });
66
- });
@@ -1,71 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { parseResultLine, ExecutionError } from "../../src/runtime/resultProtocol.js";
3
-
4
- describe("parseResultLine", () => {
5
- it("parses a well-formed success envelope", () => {
6
- const stdout = JSON.stringify({ ok: true, data: { id: "abc" } });
7
- const result = parseResultLine(stdout);
8
- expect(result.ok).toBe(true);
9
- if (result.ok) {
10
- expect(result.data).toEqual({ id: "abc" });
11
- }
12
- });
13
-
14
- it("parses a well-formed error envelope", () => {
15
- const stdout = JSON.stringify({
16
- ok: false,
17
- error: { name: "NotFoundError", message: "Not found", stack: "..." },
18
- });
19
- const result = parseResultLine(stdout);
20
- expect(result.ok).toBe(false);
21
- if (!result.ok) {
22
- expect(result.error.name).toBe("NotFoundError");
23
- expect(result.error.message).toBe("Not found");
24
- }
25
- });
26
-
27
- it("selects first parseable JSON line when preceded by chatter", () => {
28
- const stdout =
29
- "osascript warning: something\nnot json at all\n" +
30
- JSON.stringify({ ok: true, data: [1, 2, 3] }) +
31
- "\n";
32
- const result = parseResultLine(stdout);
33
- expect(result.ok).toBe(true);
34
- if (result.ok) {
35
- expect(result.data).toEqual([1, 2, 3]);
36
- }
37
- });
38
-
39
- it("throws on empty stdout", () => {
40
- expect(() => parseResultLine("")).toThrow(/No valid JSON result envelope/);
41
- });
42
-
43
- it("throws on non-envelope JSON", () => {
44
- expect(() => parseResultLine('{"foo":"bar"}')).toThrow(/not a valid result envelope/);
45
- });
46
-
47
- it("throws on malformed-only stdout with no parseable lines", () => {
48
- expect(() => parseResultLine("not json\nalso not json\n")).toThrow(
49
- /No valid JSON result envelope/
50
- );
51
- });
52
- });
53
-
54
- describe("ExecutionError", () => {
55
- it("carries name, message, and stack from the error detail", () => {
56
- const err = new ExecutionError({
57
- name: "TypeError",
58
- message: "cannot read property",
59
- stack: "TypeError: cannot...\n at line 1",
60
- });
61
- expect(err.message).toBe("cannot read property");
62
- expect(err.errorName).toBe("TypeError");
63
- expect(err.remoteStack).toContain("TypeError:");
64
- expect(err.name).toBe("ExecutionError");
65
- });
66
-
67
- it("works without a stack field", () => {
68
- const err = new ExecutionError({ name: "Error", message: "boom" });
69
- expect(err.remoteStack).toBeUndefined();
70
- });
71
- });
@@ -1,38 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { CreateFolderInput, EditFolderInput } from "../../src/schemas/index.js";
3
-
4
- describe("CreateFolderInput schema", () => {
5
- it("accepts name only (top-level)", () => {
6
- expect(() => CreateFolderInput.parse({ name: "My Folder" })).not.toThrow();
7
- });
8
-
9
- it("accepts name with parentFolderId", () => {
10
- expect(() =>
11
- CreateFolderInput.parse({ name: "Nested", parentFolderId: "abc123" })
12
- ).not.toThrow();
13
- });
14
-
15
- it("rejects missing name", () => {
16
- expect(() => CreateFolderInput.parse({})).toThrow();
17
- });
18
-
19
- it("rejects empty name", () => {
20
- expect(() => CreateFolderInput.parse({ name: "" })).toThrow();
21
- });
22
- });
23
-
24
- describe("EditFolderInput schema", () => {
25
- it("accepts id and name", () => {
26
- expect(() =>
27
- EditFolderInput.parse({ id: "abc123", name: "Renamed" })
28
- ).not.toThrow();
29
- });
30
-
31
- it("rejects missing id", () => {
32
- expect(() => EditFolderInput.parse({ name: "Renamed" })).toThrow();
33
- });
34
-
35
- it("rejects empty name", () => {
36
- expect(() => EditFolderInput.parse({ id: "abc123", name: "" })).toThrow();
37
- });
38
- });
@@ -1,115 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { CreateProjectInput, EditProjectInput, ReviewIntervalInput } from "../../src/schemas/index.js";
3
-
4
- describe("ReviewIntervalInput schema", () => {
5
- it("accepts valid steps and unit", () => {
6
- expect(() =>
7
- ReviewIntervalInput.parse({ steps: 2, unit: "weeks" })
8
- ).not.toThrow();
9
- });
10
-
11
- it("rejects invalid unit", () => {
12
- expect(() =>
13
- ReviewIntervalInput.parse({ steps: 2, unit: "fortnights" })
14
- ).toThrow();
15
- });
16
-
17
- it("rejects non-positive steps", () => {
18
- expect(() =>
19
- ReviewIntervalInput.parse({ steps: 0, unit: "weeks" })
20
- ).toThrow();
21
- });
22
- });
23
-
24
- describe("CreateProjectInput schema", () => {
25
- it("accepts name only (top-level)", () => {
26
- expect(() => CreateProjectInput.parse({ name: "My Project" })).not.toThrow();
27
- });
28
-
29
- it("accepts name with folderId", () => {
30
- expect(() =>
31
- CreateProjectInput.parse({ name: "My Project", folderId: "abc123" })
32
- ).not.toThrow();
33
- });
34
-
35
- it("accepts valid type enum values", () => {
36
- for (const type of ["parallel", "sequential", "singleActions"] as const) {
37
- expect(() =>
38
- CreateProjectInput.parse({ name: "P", type })
39
- ).not.toThrow();
40
- }
41
- });
42
-
43
- it("rejects invalid type", () => {
44
- expect(() =>
45
- CreateProjectInput.parse({ name: "P", type: "waterfall" })
46
- ).toThrow();
47
- });
48
-
49
- it("accepts valid status values", () => {
50
- for (const status of ["active", "onHold"] as const) {
51
- expect(() =>
52
- CreateProjectInput.parse({ name: "P", status })
53
- ).not.toThrow();
54
- }
55
- });
56
-
57
- it("accepts reviewInterval", () => {
58
- expect(() =>
59
- CreateProjectInput.parse({
60
- name: "P",
61
- reviewInterval: { steps: 1, unit: "months" },
62
- })
63
- ).not.toThrow();
64
- });
65
-
66
- it("rejects missing name", () => {
67
- expect(() => CreateProjectInput.parse({})).toThrow();
68
- });
69
-
70
- it("rejects empty name", () => {
71
- expect(() => CreateProjectInput.parse({ name: "" })).toThrow();
72
- });
73
- });
74
-
75
- describe("EditProjectInput schema", () => {
76
- it("accepts id with a single field", () => {
77
- expect(() =>
78
- EditProjectInput.parse({ id: "abc123", status: "onHold" })
79
- ).not.toThrow();
80
- });
81
-
82
- it("accepts null deferDate to clear the field", () => {
83
- expect(() =>
84
- EditProjectInput.parse({ id: "abc123", deferDate: null })
85
- ).not.toThrow();
86
- });
87
-
88
- it("accepts null dueDate", () => {
89
- expect(() =>
90
- EditProjectInput.parse({ id: "abc123", dueDate: null })
91
- ).not.toThrow();
92
- });
93
-
94
- it("accepts structured reviewInterval", () => {
95
- expect(() =>
96
- EditProjectInput.parse({
97
- id: "abc123",
98
- reviewInterval: { steps: 2, unit: "weeks" },
99
- })
100
- ).not.toThrow();
101
- });
102
-
103
- it("rejects invalid reviewInterval unit", () => {
104
- expect(() =>
105
- EditProjectInput.parse({
106
- id: "abc123",
107
- reviewInterval: { steps: 2, unit: "fortnights" },
108
- })
109
- ).toThrow();
110
- });
111
-
112
- it("rejects missing id", () => {
113
- expect(() => EditProjectInput.parse({ name: "Updated" })).toThrow();
114
- });
115
- });
@@ -1,87 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { CreateTaskInput, EditTaskInput } from "../../src/schemas/index.js";
3
-
4
- describe("CreateTaskInput schema", () => {
5
- it("accepts name only (inbox placement)", () => {
6
- expect(() => CreateTaskInput.parse({ name: "Buy milk" })).not.toThrow();
7
- });
8
-
9
- it("accepts name with projectId", () => {
10
- expect(() =>
11
- CreateTaskInput.parse({ name: "Write tests", projectId: "abc123" })
12
- ).not.toThrow();
13
- });
14
-
15
- it("accepts name with parentTaskId", () => {
16
- expect(() =>
17
- CreateTaskInput.parse({ name: "Review PR", parentTaskId: "xyz789" })
18
- ).not.toThrow();
19
- });
20
-
21
- it("accepts all optional fields", () => {
22
- expect(() =>
23
- CreateTaskInput.parse({
24
- name: "Full task",
25
- note: "some note",
26
- flagged: true,
27
- deferDate: "2026-04-10T00:00:00.000Z",
28
- dueDate: "2026-04-15T00:00:00.000Z",
29
- estimatedMinutes: 30,
30
- projectId: "proj1",
31
- tagIds: ["tag1", "tag2"],
32
- })
33
- ).not.toThrow();
34
- });
35
-
36
- it("rejects both projectId and parentTaskId", () => {
37
- expect(() =>
38
- CreateTaskInput.parse({
39
- name: "Ambiguous",
40
- projectId: "proj1",
41
- parentTaskId: "task1",
42
- })
43
- ).toThrow();
44
- });
45
-
46
- it("rejects missing name", () => {
47
- expect(() => CreateTaskInput.parse({})).toThrow();
48
- });
49
-
50
- it("rejects empty name", () => {
51
- expect(() => CreateTaskInput.parse({ name: "" })).toThrow();
52
- });
53
- });
54
-
55
- describe("EditTaskInput schema", () => {
56
- it("accepts id with a single field", () => {
57
- expect(() =>
58
- EditTaskInput.parse({ id: "abc123", flagged: true })
59
- ).not.toThrow();
60
- });
61
-
62
- it("accepts null deferDate to clear the field", () => {
63
- expect(() =>
64
- EditTaskInput.parse({ id: "abc123", deferDate: null })
65
- ).not.toThrow();
66
- });
67
-
68
- it("accepts null dueDate", () => {
69
- expect(() =>
70
- EditTaskInput.parse({ id: "abc123", dueDate: null })
71
- ).not.toThrow();
72
- });
73
-
74
- it("accepts null estimatedMinutes", () => {
75
- expect(() =>
76
- EditTaskInput.parse({ id: "abc123", estimatedMinutes: null })
77
- ).not.toThrow();
78
- });
79
-
80
- it("rejects missing id", () => {
81
- expect(() => EditTaskInput.parse({ name: "Updated" })).toThrow();
82
- });
83
-
84
- it("rejects empty id", () => {
85
- expect(() => EditTaskInput.parse({ id: "", name: "Updated" })).toThrow();
86
- });
87
- });
@@ -1,64 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { CreateTagInput, EditTagInput } from "../../src/schemas/index.js";
3
-
4
- describe("CreateTagInput schema", () => {
5
- it("accepts name only (top-level)", () => {
6
- expect(() => CreateTagInput.parse({ name: "Waiting" })).not.toThrow();
7
- });
8
-
9
- it("accepts name with parentTagId", () => {
10
- expect(() =>
11
- CreateTagInput.parse({ name: "Email", parentTagId: "abc123" })
12
- ).not.toThrow();
13
- });
14
-
15
- it("rejects missing name", () => {
16
- expect(() => CreateTagInput.parse({})).toThrow();
17
- });
18
-
19
- it("rejects empty name", () => {
20
- expect(() => CreateTagInput.parse({ name: "" })).toThrow();
21
- });
22
- });
23
-
24
- describe("EditTagInput schema", () => {
25
- it("accepts id with name only", () => {
26
- expect(() =>
27
- EditTagInput.parse({ id: "abc123", name: "Renamed" })
28
- ).not.toThrow();
29
- });
30
-
31
- it("accepts id with status only", () => {
32
- expect(() =>
33
- EditTagInput.parse({ id: "abc123", status: "onHold" })
34
- ).not.toThrow();
35
- });
36
-
37
- it("accepts id with both name and status", () => {
38
- expect(() =>
39
- EditTagInput.parse({ id: "abc123", name: "New", status: "active" })
40
- ).not.toThrow();
41
- });
42
-
43
- it("accepts all valid status values", () => {
44
- for (const status of ["active", "onHold", "dropped"] as const) {
45
- expect(() =>
46
- EditTagInput.parse({ id: "abc123", status })
47
- ).not.toThrow();
48
- }
49
- });
50
-
51
- it("rejects neither name nor status (refine)", () => {
52
- expect(() => EditTagInput.parse({ id: "abc123" })).toThrow();
53
- });
54
-
55
- it("rejects invalid status enum", () => {
56
- expect(() =>
57
- EditTagInput.parse({ id: "abc123", status: "paused" })
58
- ).toThrow();
59
- });
60
-
61
- it("rejects missing id", () => {
62
- expect(() => EditTagInput.parse({ name: "X" })).toThrow();
63
- });
64
- });
@@ -1,42 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { ListFoldersFilter, ListTagsFilter } from "../../src/schemas/index.js";
3
-
4
- describe("ListFoldersFilter schema", () => {
5
- it("accepts empty filter object", () => {
6
- expect(() => ListFoldersFilter.parse({})).not.toThrow();
7
- });
8
-
9
- it("accepts status 'active'", () => {
10
- expect(() => ListFoldersFilter.parse({ status: "active" })).not.toThrow();
11
- });
12
-
13
- it("accepts status 'dropped'", () => {
14
- expect(() => ListFoldersFilter.parse({ status: "dropped" })).not.toThrow();
15
- });
16
-
17
- it("rejects invalid status value", () => {
18
- expect(() => ListFoldersFilter.parse({ status: "pending" })).toThrow();
19
- });
20
- });
21
-
22
- describe("ListTagsFilter schema", () => {
23
- it("accepts empty filter object", () => {
24
- expect(() => ListTagsFilter.parse({})).not.toThrow();
25
- });
26
-
27
- it("accepts status 'active'", () => {
28
- expect(() => ListTagsFilter.parse({ status: "active" })).not.toThrow();
29
- });
30
-
31
- it("accepts status 'onHold'", () => {
32
- expect(() => ListTagsFilter.parse({ status: "onHold" })).not.toThrow();
33
- });
34
-
35
- it("accepts status 'dropped'", () => {
36
- expect(() => ListTagsFilter.parse({ status: "dropped" })).not.toThrow();
37
- });
38
-
39
- it("rejects invalid status value", () => {
40
- expect(() => ListTagsFilter.parse({ status: "unknown" })).toThrow();
41
- });
42
- });
@@ -1,44 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { ListProjectsFilter } from "../../src/schemas/index.js";
3
-
4
- describe("ListProjectsFilter schema", () => {
5
- it("accepts empty filter object", () => {
6
- expect(() => ListProjectsFilter.parse({})).not.toThrow();
7
- });
8
-
9
- it("accepts status array", () => {
10
- expect(() =>
11
- ListProjectsFilter.parse({ status: ["active", "onHold"] })
12
- ).not.toThrow();
13
- });
14
-
15
- it("accepts folderId", () => {
16
- expect(() =>
17
- ListProjectsFilter.parse({ folderId: "folder123" })
18
- ).not.toThrow();
19
- });
20
-
21
- it("accepts flagged: true", () => {
22
- expect(() =>
23
- ListProjectsFilter.parse({ flagged: true })
24
- ).not.toThrow();
25
- });
26
-
27
- it("accepts all fields together", () => {
28
- expect(() =>
29
- ListProjectsFilter.parse({ status: ["active"], folderId: "f1", flagged: true })
30
- ).not.toThrow();
31
- });
32
-
33
- it("rejects invalid status enum in array", () => {
34
- expect(() =>
35
- ListProjectsFilter.parse({ status: ["active", "flying"] })
36
- ).toThrow();
37
- });
38
-
39
- it("rejects flagged: false (must be literal true or absent)", () => {
40
- expect(() =>
41
- ListProjectsFilter.parse({ flagged: false })
42
- ).toThrow();
43
- });
44
- });
@@ -1,60 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { MoveTaskInput, MoveProjectInput } from "../../src/schemas/index.js";
3
-
4
- describe("MoveTaskInput schema", () => {
5
- it("accepts projectId only", () => {
6
- expect(() =>
7
- MoveTaskInput.parse({ id: "t1", projectId: "p1" })
8
- ).not.toThrow();
9
- });
10
-
11
- it("accepts parentTaskId only", () => {
12
- expect(() =>
13
- MoveTaskInput.parse({ id: "t1", parentTaskId: "t2" })
14
- ).not.toThrow();
15
- });
16
-
17
- it("rejects both projectId and parentTaskId", () => {
18
- expect(() =>
19
- MoveTaskInput.parse({ id: "t1", projectId: "p1", parentTaskId: "t2" })
20
- ).toThrow();
21
- });
22
-
23
- it("rejects neither projectId nor parentTaskId", () => {
24
- expect(() =>
25
- MoveTaskInput.parse({ id: "t1" })
26
- ).toThrow();
27
- });
28
-
29
- it("rejects missing id", () => {
30
- expect(() =>
31
- MoveTaskInput.parse({ projectId: "p1" })
32
- ).toThrow();
33
- });
34
- });
35
-
36
- describe("MoveProjectInput schema", () => {
37
- it("accepts folderId as string", () => {
38
- expect(() =>
39
- MoveProjectInput.parse({ id: "p1", folderId: "f1" })
40
- ).not.toThrow();
41
- });
42
-
43
- it("accepts folderId as null", () => {
44
- expect(() =>
45
- MoveProjectInput.parse({ id: "p1", folderId: null })
46
- ).not.toThrow();
47
- });
48
-
49
- it("rejects missing id", () => {
50
- expect(() =>
51
- MoveProjectInput.parse({ folderId: "f1" })
52
- ).toThrow();
53
- });
54
-
55
- it("rejects missing folderId (undefined not same as null)", () => {
56
- expect(() =>
57
- MoveProjectInput.parse({ id: "p1" })
58
- ).toThrow();
59
- });
60
- });