@gopherine/obsidian-mcp 0.1.1

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/CHANGELOG.md +60 -0
  2. package/LICENSE +661 -0
  3. package/README.md +235 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +805 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/brainstorm.d.ts +9 -0
  8. package/dist/commands/brainstorm.js +37 -0
  9. package/dist/commands/brainstorm.js.map +1 -0
  10. package/dist/commands/brainstorm.test.d.ts +1 -0
  11. package/dist/commands/brainstorm.test.js +110 -0
  12. package/dist/commands/brainstorm.test.js.map +1 -0
  13. package/dist/commands/context.d.ts +18 -0
  14. package/dist/commands/context.js +88 -0
  15. package/dist/commands/context.js.map +1 -0
  16. package/dist/commands/context.test.d.ts +1 -0
  17. package/dist/commands/context.test.js +230 -0
  18. package/dist/commands/context.test.js.map +1 -0
  19. package/dist/commands/decide.d.ts +12 -0
  20. package/dist/commands/decide.js +40 -0
  21. package/dist/commands/decide.js.map +1 -0
  22. package/dist/commands/decide.test.d.ts +1 -0
  23. package/dist/commands/decide.test.js +109 -0
  24. package/dist/commands/decide.test.js.map +1 -0
  25. package/dist/commands/graph.d.ts +15 -0
  26. package/dist/commands/graph.js +89 -0
  27. package/dist/commands/graph.js.map +1 -0
  28. package/dist/commands/graph.test.d.ts +1 -0
  29. package/dist/commands/graph.test.js +215 -0
  30. package/dist/commands/graph.test.js.map +1 -0
  31. package/dist/commands/init.d.ts +11 -0
  32. package/dist/commands/init.js +256 -0
  33. package/dist/commands/init.js.map +1 -0
  34. package/dist/commands/learn.d.ts +25 -0
  35. package/dist/commands/learn.js +92 -0
  36. package/dist/commands/learn.js.map +1 -0
  37. package/dist/commands/learn.test.d.ts +1 -0
  38. package/dist/commands/learn.test.js +241 -0
  39. package/dist/commands/learn.test.js.map +1 -0
  40. package/dist/commands/prune.d.ts +58 -0
  41. package/dist/commands/prune.js +246 -0
  42. package/dist/commands/prune.js.map +1 -0
  43. package/dist/commands/read.d.ts +8 -0
  44. package/dist/commands/read.js +7 -0
  45. package/dist/commands/read.js.map +1 -0
  46. package/dist/commands/read.test.d.ts +1 -0
  47. package/dist/commands/read.test.js +48 -0
  48. package/dist/commands/read.test.js.map +1 -0
  49. package/dist/commands/resume.d.ts +20 -0
  50. package/dist/commands/resume.js +138 -0
  51. package/dist/commands/resume.js.map +1 -0
  52. package/dist/commands/resume.test.d.ts +1 -0
  53. package/dist/commands/resume.test.js +243 -0
  54. package/dist/commands/resume.test.js.map +1 -0
  55. package/dist/commands/search.d.ts +8 -0
  56. package/dist/commands/search.js +25 -0
  57. package/dist/commands/search.js.map +1 -0
  58. package/dist/commands/search.test.d.ts +1 -0
  59. package/dist/commands/search.test.js +61 -0
  60. package/dist/commands/search.test.js.map +1 -0
  61. package/dist/commands/session.d.ts +22 -0
  62. package/dist/commands/session.js +79 -0
  63. package/dist/commands/session.js.map +1 -0
  64. package/dist/commands/session.test.d.ts +1 -0
  65. package/dist/commands/session.test.js +185 -0
  66. package/dist/commands/session.test.js.map +1 -0
  67. package/dist/commands/skill/index.d.ts +30 -0
  68. package/dist/commands/skill/index.js +61 -0
  69. package/dist/commands/skill/index.js.map +1 -0
  70. package/dist/commands/skill/index.test.d.ts +1 -0
  71. package/dist/commands/skill/index.test.js +137 -0
  72. package/dist/commands/skill/index.test.js.map +1 -0
  73. package/dist/commands/skill/install.d.ts +14 -0
  74. package/dist/commands/skill/install.js +107 -0
  75. package/dist/commands/skill/install.js.map +1 -0
  76. package/dist/commands/skill/install.test.d.ts +1 -0
  77. package/dist/commands/skill/install.test.js +225 -0
  78. package/dist/commands/skill/install.test.js.map +1 -0
  79. package/dist/commands/skill/list.d.ts +6 -0
  80. package/dist/commands/skill/list.js +5 -0
  81. package/dist/commands/skill/list.js.map +1 -0
  82. package/dist/commands/skill/list.test.d.ts +1 -0
  83. package/dist/commands/skill/list.test.js +101 -0
  84. package/dist/commands/skill/list.test.js.map +1 -0
  85. package/dist/commands/skill/schema.d.ts +27 -0
  86. package/dist/commands/skill/schema.js +55 -0
  87. package/dist/commands/skill/schema.js.map +1 -0
  88. package/dist/commands/skill/schema.test.d.ts +1 -0
  89. package/dist/commands/skill/schema.test.js +142 -0
  90. package/dist/commands/skill/schema.test.js.map +1 -0
  91. package/dist/commands/skill/validate.d.ts +10 -0
  92. package/dist/commands/skill/validate.js +39 -0
  93. package/dist/commands/skill/validate.js.map +1 -0
  94. package/dist/commands/skill/validate.test.d.ts +1 -0
  95. package/dist/commands/skill/validate.test.js +171 -0
  96. package/dist/commands/skill/validate.test.js.map +1 -0
  97. package/dist/commands/task.d.ts +34 -0
  98. package/dist/commands/task.js +160 -0
  99. package/dist/commands/task.js.map +1 -0
  100. package/dist/commands/task.test.d.ts +1 -0
  101. package/dist/commands/task.test.js +395 -0
  102. package/dist/commands/task.test.js.map +1 -0
  103. package/dist/commands/todo.d.ts +15 -0
  104. package/dist/commands/todo.js +99 -0
  105. package/dist/commands/todo.js.map +1 -0
  106. package/dist/commands/todo.test.d.ts +1 -0
  107. package/dist/commands/todo.test.js +324 -0
  108. package/dist/commands/todo.test.js.map +1 -0
  109. package/dist/commands/write.d.ts +12 -0
  110. package/dist/commands/write.js +40 -0
  111. package/dist/commands/write.js.map +1 -0
  112. package/dist/commands/write.test.d.ts +1 -0
  113. package/dist/commands/write.test.js +79 -0
  114. package/dist/commands/write.test.js.map +1 -0
  115. package/dist/config.d.ts +15 -0
  116. package/dist/config.js +48 -0
  117. package/dist/config.js.map +1 -0
  118. package/dist/config.test.d.ts +1 -0
  119. package/dist/config.test.js +147 -0
  120. package/dist/config.test.js.map +1 -0
  121. package/dist/core/executor.d.ts +11 -0
  122. package/dist/core/executor.js +42 -0
  123. package/dist/core/executor.js.map +1 -0
  124. package/dist/core/executor.test.d.ts +1 -0
  125. package/dist/core/executor.test.js +206 -0
  126. package/dist/core/executor.test.js.map +1 -0
  127. package/dist/core/middleware/error-handler.d.ts +2 -0
  128. package/dist/core/middleware/error-handler.js +29 -0
  129. package/dist/core/middleware/error-handler.js.map +1 -0
  130. package/dist/core/middleware/index.d.ts +2 -0
  131. package/dist/core/middleware/index.js +3 -0
  132. package/dist/core/middleware/index.js.map +1 -0
  133. package/dist/core/middleware/logging.d.ts +2 -0
  134. package/dist/core/middleware/logging.js +18 -0
  135. package/dist/core/middleware/logging.js.map +1 -0
  136. package/dist/core/registry.d.ts +12 -0
  137. package/dist/core/registry.js +407 -0
  138. package/dist/core/registry.js.map +1 -0
  139. package/dist/core/registry.test.d.ts +1 -0
  140. package/dist/core/registry.test.js +162 -0
  141. package/dist/core/registry.test.js.map +1 -0
  142. package/dist/core/types.d.ts +38 -0
  143. package/dist/core/types.js +2 -0
  144. package/dist/core/types.js.map +1 -0
  145. package/dist/integration/coordination.test.d.ts +1 -0
  146. package/dist/integration/coordination.test.js +286 -0
  147. package/dist/integration/coordination.test.js.map +1 -0
  148. package/dist/integration/project-artifacts.test.d.ts +1 -0
  149. package/dist/integration/project-artifacts.test.js +275 -0
  150. package/dist/integration/project-artifacts.test.js.map +1 -0
  151. package/dist/integration/registry-graph.test.d.ts +1 -0
  152. package/dist/integration/registry-graph.test.js +157 -0
  153. package/dist/integration/registry-graph.test.js.map +1 -0
  154. package/dist/integration/vault-lifecycle.test.d.ts +1 -0
  155. package/dist/integration/vault-lifecycle.test.js +183 -0
  156. package/dist/integration/vault-lifecycle.test.js.map +1 -0
  157. package/dist/lib/auto-number.d.ts +10 -0
  158. package/dist/lib/auto-number.js +33 -0
  159. package/dist/lib/auto-number.js.map +1 -0
  160. package/dist/lib/auto-number.test.d.ts +1 -0
  161. package/dist/lib/auto-number.test.js +88 -0
  162. package/dist/lib/auto-number.test.js.map +1 -0
  163. package/dist/lib/escape-regex.d.ts +4 -0
  164. package/dist/lib/escape-regex.js +7 -0
  165. package/dist/lib/escape-regex.js.map +1 -0
  166. package/dist/lib/escape-regex.test.d.ts +1 -0
  167. package/dist/lib/escape-regex.test.js +27 -0
  168. package/dist/lib/escape-regex.test.js.map +1 -0
  169. package/dist/lib/frontmatter.d.ts +34 -0
  170. package/dist/lib/frontmatter.js +74 -0
  171. package/dist/lib/frontmatter.js.map +1 -0
  172. package/dist/lib/frontmatter.test.d.ts +1 -0
  173. package/dist/lib/frontmatter.test.js +192 -0
  174. package/dist/lib/frontmatter.test.js.map +1 -0
  175. package/dist/lib/project-detector.d.ts +12 -0
  176. package/dist/lib/project-detector.js +123 -0
  177. package/dist/lib/project-detector.js.map +1 -0
  178. package/dist/lib/project-detector.test.d.ts +1 -0
  179. package/dist/lib/project-detector.test.js +117 -0
  180. package/dist/lib/project-detector.test.js.map +1 -0
  181. package/dist/lib/safe-external-path.d.ts +10 -0
  182. package/dist/lib/safe-external-path.js +46 -0
  183. package/dist/lib/safe-external-path.js.map +1 -0
  184. package/dist/lib/safe-external-path.test.d.ts +1 -0
  185. package/dist/lib/safe-external-path.test.js +99 -0
  186. package/dist/lib/safe-external-path.test.js.map +1 -0
  187. package/dist/lib/search-engine.d.ts +19 -0
  188. package/dist/lib/search-engine.js +157 -0
  189. package/dist/lib/search-engine.js.map +1 -0
  190. package/dist/lib/search-engine.test.d.ts +1 -0
  191. package/dist/lib/search-engine.test.js +120 -0
  192. package/dist/lib/search-engine.test.js.map +1 -0
  193. package/dist/lib/session-registry.d.ts +59 -0
  194. package/dist/lib/session-registry.js +230 -0
  195. package/dist/lib/session-registry.js.map +1 -0
  196. package/dist/lib/session-registry.test.d.ts +1 -0
  197. package/dist/lib/session-registry.test.js +199 -0
  198. package/dist/lib/session-registry.test.js.map +1 -0
  199. package/dist/lib/skill-registry.d.ts +13 -0
  200. package/dist/lib/skill-registry.js +76 -0
  201. package/dist/lib/skill-registry.js.map +1 -0
  202. package/dist/lib/token-estimator.d.ts +19 -0
  203. package/dist/lib/token-estimator.js +58 -0
  204. package/dist/lib/token-estimator.js.map +1 -0
  205. package/dist/lib/token-estimator.test.d.ts +1 -0
  206. package/dist/lib/token-estimator.test.js +65 -0
  207. package/dist/lib/token-estimator.test.js.map +1 -0
  208. package/dist/lib/vault-fs.d.ts +39 -0
  209. package/dist/lib/vault-fs.js +183 -0
  210. package/dist/lib/vault-fs.js.map +1 -0
  211. package/dist/lib/vault-fs.test.d.ts +1 -0
  212. package/dist/lib/vault-fs.test.js +210 -0
  213. package/dist/lib/vault-fs.test.js.map +1 -0
  214. package/dist/mcp-server.d.ts +2 -0
  215. package/dist/mcp-server.js +385 -0
  216. package/dist/mcp-server.js.map +1 -0
  217. package/dist/test-helpers.d.ts +20 -0
  218. package/dist/test-helpers.js +46 -0
  219. package/dist/test-helpers.js.map +1 -0
  220. package/dist/test-helpers.test.d.ts +1 -0
  221. package/dist/test-helpers.test.js +90 -0
  222. package/dist/test-helpers.test.js.map +1 -0
  223. package/package.json +72 -0
@@ -0,0 +1,157 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir } from "fs/promises";
3
+ import { join } from "path";
4
+ import { createTestContext } from "../test-helpers.js";
5
+ import { createRegistry } from "../core/registry.js";
6
+ import { graphRelatedCommand, graphCrossProjectCommand } from "../commands/graph.js";
7
+ describe("integration > command registry", () => {
8
+ let ctx;
9
+ let vaultRoot;
10
+ let cleanup;
11
+ beforeEach(async () => {
12
+ const tc = await createTestContext({ project: "my-project" });
13
+ ctx = tc.ctx;
14
+ vaultRoot = tc.vaultRoot;
15
+ cleanup = tc.cleanup;
16
+ await mkdir(join(vaultRoot, "projects/my-project/tasks"), { recursive: true });
17
+ await mkdir(join(vaultRoot, "projects/my-project/decisions"), { recursive: true });
18
+ });
19
+ afterEach(async () => {
20
+ await cleanup();
21
+ });
22
+ describe("registry dispatch", () => {
23
+ it("registry execute vault_read calls readCommand and returns content", async () => {
24
+ await ctx.vaultFs.write("test.md", "# Hello\n\nSome content");
25
+ const registry = createRegistry();
26
+ const result = await registry.execute("vault_read", { path: "test.md" }, ctx);
27
+ expect(typeof result).toBe("string");
28
+ expect(result).toContain("Hello");
29
+ });
30
+ it("registry execute vault_write calls writeCommand and writes file", async () => {
31
+ const registry = createRegistry();
32
+ await registry.execute("vault_write", { path: "new-file.md", content: "# Written", mode: "overwrite" }, ctx);
33
+ const content = await ctx.vaultFs.read("new-file.md");
34
+ expect(content).toContain("Written");
35
+ });
36
+ it("registry execute vault_task add creates a task via the registry", async () => {
37
+ const registry = createRegistry();
38
+ const result = await registry.execute("vault_task", { action: "add", title: "Test task", project: "my-project" }, ctx);
39
+ expect(result).toBeDefined();
40
+ const taskList = await registry.execute("vault_task", { action: "list", project: "my-project" }, ctx);
41
+ expect(JSON.stringify(taskList)).toContain("Test task");
42
+ });
43
+ it("registry execute vault_decide creates an ADR via the registry", async () => {
44
+ const registry = createRegistry();
45
+ const result = await registry.execute("vault_decide", { title: "Use TypeScript", context: "Need types", decision: "Use TS", project: "my-project" }, ctx);
46
+ expect(result).toBeDefined();
47
+ const files = await ctx.vaultFs.list("projects/my-project/decisions");
48
+ expect(files.length).toBe(1);
49
+ const content = await ctx.vaultFs.read(files[0]);
50
+ expect(content).toContain("Use TypeScript");
51
+ });
52
+ it("registry execute with adaptArgs converts snake_case to camelCase", async () => {
53
+ const registry = createRegistry();
54
+ const addResult = await registry.execute("vault_task", { action: "add", title: "Snake test", project: "my-project" }, ctx);
55
+ const taskId = addResult.task_id;
56
+ expect(taskId).toMatch(/^task-\d+$/);
57
+ await registry.execute("vault_task", { action: "update", task_id: taskId, status: "done", project: "my-project" }, ctx);
58
+ const listResult = await registry.execute("vault_task", { action: "list", project: "my-project" }, ctx);
59
+ expect(JSON.stringify(listResult)).toContain("done");
60
+ });
61
+ it("registry getToolDefinitions returns all tool definitions", () => {
62
+ const registry = createRegistry();
63
+ const defs = registry.getToolDefinitions();
64
+ expect(defs.length).toBeGreaterThanOrEqual(15);
65
+ const names = defs.map((d) => d.name);
66
+ expect(names).toContain("vault_read");
67
+ expect(names).toContain("vault_write");
68
+ expect(names).toContain("vault_search");
69
+ expect(names).toContain("vault_task");
70
+ expect(names).toContain("vault_decide");
71
+ expect(names).toContain("vault_learn");
72
+ expect(names).toContain("vault_session");
73
+ expect(names).toContain("vault_brainstorm");
74
+ expect(names).toContain("vault_prune");
75
+ expect(names).toContain("vault_stats");
76
+ expect(names).toContain("vault_resume");
77
+ expect(names).toContain("vault_deprecate");
78
+ expect(names).toContain("vault_project_context");
79
+ expect(names).toContain("vault_init");
80
+ expect(names).toContain("vault_todo");
81
+ });
82
+ });
83
+ });
84
+ describe("integration > graph commands", () => {
85
+ let ctx;
86
+ let vaultRoot;
87
+ let cleanup;
88
+ beforeEach(async () => {
89
+ const tc = await createTestContext({ project: "my-project" });
90
+ ctx = tc.ctx;
91
+ vaultRoot = tc.vaultRoot;
92
+ cleanup = tc.cleanup;
93
+ await mkdir(join(vaultRoot, "projects/my-project"), { recursive: true });
94
+ });
95
+ afterEach(async () => {
96
+ await cleanup();
97
+ });
98
+ describe("graph related", () => {
99
+ it("graphRelated finds outgoing wikilinks from a note", async () => {
100
+ await ctx.vaultFs.write("projects/my-project/note-a.md", "# Note A\n\nSee [[projects/my-project/note-b]] and [[projects/my-project/note-c|C Alias]]");
101
+ await ctx.vaultFs.write("projects/my-project/note-b.md", "# Note B");
102
+ await ctx.vaultFs.write("projects/my-project/note-c.md", "# Note C");
103
+ const result = await graphRelatedCommand({ path: "projects/my-project/note-a.md" }, ctx);
104
+ expect(result.outgoing).toContain("projects/my-project/note-b");
105
+ expect(result.outgoing).toContain("projects/my-project/note-c");
106
+ });
107
+ it("graphRelated finds backlinks to a note", async () => {
108
+ await ctx.vaultFs.write("projects/my-project/note-a.md", "# Note A\n\nSee [[projects/my-project/note-b]]");
109
+ await ctx.vaultFs.write("projects/my-project/note-b.md", "# Note B\n\nLinks to [[projects/my-project/note-a]]");
110
+ const result = await graphRelatedCommand({ path: "projects/my-project/note-a.md" }, ctx);
111
+ expect(result.backlinks).toContain("projects/my-project/note-b.md");
112
+ });
113
+ it("graphRelated with hops > 1 follows linked notes", async () => {
114
+ await ctx.vaultFs.write("projects/my-project/a.md", "# A\n\n[[projects/my-project/b]]");
115
+ await ctx.vaultFs.write("projects/my-project/b.md", "# B\n\n[[projects/my-project/c]]");
116
+ await ctx.vaultFs.write("projects/my-project/c.md", "# C");
117
+ const result = await graphRelatedCommand({ path: "projects/my-project/a.md", hops: 2 }, ctx);
118
+ expect(result.outgoing).toContain("projects/my-project/b");
119
+ expect(result.outgoing).toContain("projects/my-project/c");
120
+ });
121
+ it("graphRelated on note with no links returns empty arrays", async () => {
122
+ await ctx.vaultFs.write("projects/my-project/isolated.md", "# Isolated\n\nNo links here.");
123
+ const result = await graphRelatedCommand({ path: "projects/my-project/isolated.md" }, ctx);
124
+ expect(result.outgoing).toEqual([]);
125
+ expect(result.backlinks).toEqual([]);
126
+ });
127
+ });
128
+ describe("graph cross-project", () => {
129
+ it("graphCrossProject searches across multiple project directories", async () => {
130
+ const projectMap = { projects: { "proj-a": "/tmp/a", "proj-b": "/tmp/b" } };
131
+ await ctx.vaultFs.write("project-map.json", JSON.stringify(projectMap));
132
+ await mkdir(join(vaultRoot, "projects/proj-a"), { recursive: true });
133
+ await mkdir(join(vaultRoot, "projects/proj-b"), { recursive: true });
134
+ await ctx.vaultFs.write("projects/proj-a/note.md", "# Note A\n\nDatabase connection handling");
135
+ await ctx.vaultFs.write("projects/proj-b/note.md", "# Note B\n\nDatabase migration scripts");
136
+ const result = await graphCrossProjectCommand({ query: "Database" }, ctx);
137
+ expect(typeof result).toBe("object");
138
+ const projects = Object.keys(result);
139
+ expect(projects.length).toBeGreaterThanOrEqual(1);
140
+ });
141
+ it("graphCrossProject respects limit parameter", async () => {
142
+ for (let i = 0; i < 30; i++) {
143
+ await ctx.vaultFs.write(`projects/my-project/bulk-${i}.md`, `# Note ${i}\n\nSearchable content here`);
144
+ }
145
+ const result = await graphCrossProjectCommand({ query: "Searchable", limit: 5 }, ctx);
146
+ const totalResults = Object.values(result).flat().length;
147
+ expect(totalResults).toBeLessThanOrEqual(5);
148
+ });
149
+ it("graphCrossProject returns empty for no matches", async () => {
150
+ await ctx.vaultFs.write("projects/my-project/existing.md", "# Existing\n\nSome content");
151
+ const result = await graphCrossProjectCommand({ query: "xyznonexistent123" }, ctx);
152
+ expect(typeof result).toBe("object");
153
+ expect(Object.values(result).flat().length).toBe(0);
154
+ });
155
+ });
156
+ });
157
+ //# sourceMappingURL=registry-graph.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-graph.test.js","sourceRoot":"","sources":["../../src/integration/registry-graph.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErF,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,IAAI,GAAyD,CAAC;IAC9D,IAAI,SAAiB,CAAC;IACtB,IAAI,OAA4B,CAAC;IAEjC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QAC9D,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;QACb,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC;QACzB,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;QACrB,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,2BAA2B,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,+BAA+B,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,yBAAyB,CAAC,CAAC;YAC9D,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC;YAC9E,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;YAC/E,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;YAClC,MAAM,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;YAC7G,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACtD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;YAC/E,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;YACvH,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;YACtG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;YAC7E,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CACnC,cAAc,EACd,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,EAC7F,GAAG,CACJ,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YACtE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;YAChF,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;YAC3H,MAAM,MAAM,GAAI,SAAiC,CAAC,OAAO,CAAC;YAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAErC,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;YACxH,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;YACxG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,kBAAkB,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;YACjD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,IAAI,GAAyD,CAAC;IAC9D,IAAI,SAAiB,CAAC;IACtB,IAAI,OAA4B,CAAC;IAEjC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QAC9D,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;QACb,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC;QACzB,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;QACrB,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,2FAA2F,CAAC,CAAC;YACtJ,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,UAAU,CAAC,CAAC;YACrE,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,UAAU,CAAC,CAAC;YAErE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,+BAA+B,EAAE,EAAE,GAAG,CAAC,CAAC;YACzF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;YAChE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,gDAAgD,CAAC,CAAC;YAC3G,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,qDAAqD,CAAC,CAAC;YAEhH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,+BAA+B,EAAE,EAAE,GAAG,CAAC,CAAC;YACzF,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,kCAAkC,CAAC,CAAC;YACxF,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,kCAAkC,CAAC,CAAC;YACxF,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAE3D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC7F,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;YAC3D,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACvE,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,8BAA8B,CAAC,CAAC;YAE3F,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,iCAAiC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC3F,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;YAC9E,MAAM,UAAU,GAAG,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC;YAC5E,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YACxE,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAErE,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,0CAA0C,CAAC,CAAC;YAC/F,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,wCAAwC,CAAC,CAAC;YAE7F,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC;YAC1E,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,KAAK,EAAE,UAAU,CAAC,6BAA6B,CAAC,CAAC;YACxG,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACtF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;YACzD,MAAM,CAAC,YAAY,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,4BAA4B,CAAC,CAAC;YAEzF,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;YACnF,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir } from "fs/promises";
3
+ import { join } from "path";
4
+ import { createTestContext } from "../test-helpers.js";
5
+ import { readCommand, listCommand } from "../commands/read.js";
6
+ import { writeCommand } from "../commands/write.js";
7
+ import { searchCommand } from "../commands/search.js";
8
+ import { contextCommand } from "../commands/context.js";
9
+ import { decideCommand } from "../commands/decide.js";
10
+ import { taskCommand } from "../commands/task.js";
11
+ import { learnCommand } from "../commands/learn.js";
12
+ import { parseFrontmatter } from "../lib/frontmatter.js";
13
+ describe("integration > vault lifecycle", () => {
14
+ let ctx;
15
+ let vaultRoot;
16
+ let cleanup;
17
+ beforeEach(async () => {
18
+ const tc = await createTestContext({ project: "my-project" });
19
+ ctx = tc.ctx;
20
+ vaultRoot = tc.vaultRoot;
21
+ cleanup = tc.cleanup;
22
+ await mkdir(join(vaultRoot, "projects/my-project/decisions"), { recursive: true });
23
+ await mkdir(join(vaultRoot, "projects/my-project/tasks"), { recursive: true });
24
+ await mkdir(join(vaultRoot, "projects/my-project/learnings"), { recursive: true });
25
+ });
26
+ afterEach(async () => {
27
+ await cleanup();
28
+ });
29
+ describe("read + write round-trip", () => {
30
+ it("write then read returns the same content", async () => {
31
+ await writeCommand({ path: "projects/my-project/context.md", content: "# Hello\n\nWorld" }, ctx);
32
+ const result = await readCommand({ path: "projects/my-project/context.md" }, ctx);
33
+ expect(result).toContain("# Hello");
34
+ expect(result).toContain("World");
35
+ });
36
+ it("write with append mode appends to existing file", async () => {
37
+ await writeCommand({ path: "projects/my-project/context.md", content: "First line" }, ctx);
38
+ await writeCommand({ path: "projects/my-project/context.md", content: "Second line", mode: "append" }, ctx);
39
+ const result = await readCommand({ path: "projects/my-project/context.md" }, ctx);
40
+ expect(result).toContain("First line");
41
+ expect(result).toContain("Second line");
42
+ expect(result.indexOf("Second line")).toBeGreaterThan(result.indexOf("First line"));
43
+ });
44
+ it("write with prepend mode prepends before existing body", async () => {
45
+ await writeCommand({ path: "projects/my-project/context.md", content: "Original body" }, ctx);
46
+ await writeCommand({ path: "projects/my-project/context.md", content: "New section", mode: "prepend" }, ctx);
47
+ const result = await readCommand({ path: "projects/my-project/context.md" }, ctx);
48
+ expect(result).toContain("New section");
49
+ expect(result).toContain("Original body");
50
+ expect(result.indexOf("New section")).toBeLessThan(result.indexOf("Original body"));
51
+ });
52
+ it("write with overwrite mode replaces entire file", async () => {
53
+ await writeCommand({ path: "projects/my-project/context.md", content: "Old content" }, ctx);
54
+ await writeCommand({ path: "projects/my-project/context.md", content: "New content", mode: "overwrite" }, ctx);
55
+ const result = await readCommand({ path: "projects/my-project/context.md" }, ctx);
56
+ expect(result).toContain("New content");
57
+ expect(result).not.toContain("Old content");
58
+ });
59
+ it("write with frontmatter creates valid YAML frontmatter", async () => {
60
+ await writeCommand({ path: "projects/my-project/context.md", content: "# Context\n\nSome info", frontmatter: { type: "context", project: "my-project" } }, ctx);
61
+ const result = await readCommand({ path: "projects/my-project/context.md" }, ctx);
62
+ const { data, content } = parseFrontmatter(result);
63
+ expect(data.type).toBe("context");
64
+ expect(data.project).toBe("my-project");
65
+ expect(content).toContain("# Context");
66
+ });
67
+ it("list returns directory contents at depth 1 and 2", async () => {
68
+ await writeCommand({ path: "projects/my-project/note1.md", content: "a" }, ctx);
69
+ await writeCommand({ path: "projects/my-project/sub/note2.md", content: "b" }, ctx);
70
+ const depth1 = await listCommand({ path: "projects/my-project", depth: 1 }, ctx);
71
+ expect(depth1).toContain("projects/my-project/note1.md");
72
+ expect(depth1.some((f) => f.includes("note2.md"))).toBe(false);
73
+ const depth2 = await listCommand({ path: "projects/my-project", depth: 2 }, ctx);
74
+ expect(depth2).toContain("projects/my-project/note1.md");
75
+ expect(depth2.some((f) => f.includes("note2.md"))).toBe(true);
76
+ });
77
+ });
78
+ describe("search", () => {
79
+ it("text search finds written content across files", async () => {
80
+ await writeCommand({ path: "projects/my-project/a.md", content: "unique-needle-alpha" }, ctx);
81
+ await writeCommand({ path: "projects/my-project/b.md", content: "unique-needle-beta" }, ctx);
82
+ const results = await searchCommand({ query: "unique-needle" }, ctx);
83
+ expect(results.length).toBeGreaterThanOrEqual(2);
84
+ const paths = results.map((r) => r.path);
85
+ expect(paths.some((p) => p.includes("a.md"))).toBe(true);
86
+ expect(paths.some((p) => p.includes("b.md"))).toBe(true);
87
+ });
88
+ it("structured search filters by frontmatter fields", async () => {
89
+ await writeCommand({ path: "projects/my-project/s1.md", content: "doc", frontmatter: { type: "adr", project: "my-project" } }, ctx);
90
+ await writeCommand({ path: "projects/my-project/s2.md", content: "doc", frontmatter: { type: "task", project: "my-project" } }, ctx);
91
+ const results = await searchCommand({ query: "type:adr project:my-project", structured: true }, ctx);
92
+ expect(results.length).toBeGreaterThanOrEqual(1);
93
+ for (const r of results) {
94
+ expect(r.path).toContain("s1.md");
95
+ }
96
+ });
97
+ it("search with project path filter narrows results", async () => {
98
+ await writeCommand({ path: "projects/my-project/x.md", content: "pfx-target" }, ctx);
99
+ await writeCommand({ path: "other/note.md", content: "pfx-target" }, ctx);
100
+ const results = await searchCommand({ query: "pfx-target", project: "my-project" }, ctx);
101
+ expect(results.length).toBeGreaterThanOrEqual(1);
102
+ for (const r of results) {
103
+ expect(r.path).toContain("my-project");
104
+ }
105
+ expect(results.some((r) => r.path.includes("other/"))).toBe(false);
106
+ });
107
+ it("search returns empty for no matches", async () => {
108
+ await writeCommand({ path: "projects/my-project/z.md", content: "existing content" }, ctx);
109
+ const results = await searchCommand({ query: "zzz-nonexistent-xyzzy" }, ctx);
110
+ expect(results).toHaveLength(0);
111
+ });
112
+ });
113
+ describe("context", () => {
114
+ it("context command returns project context after writing context.md", async () => {
115
+ await writeCommand({ path: "projects/my-project/context.md", content: "# Overview\n\n## Architecture\n\nUses TypeScript", frontmatter: { type: "context" } }, ctx);
116
+ const result = await contextCommand({ project: "my-project" }, ctx);
117
+ expect(result.project_slug).toBe("my-project");
118
+ expect(result.context_md).toContain("Overview");
119
+ expect(result.sections).toContain("Architecture");
120
+ });
121
+ it("context with detailLevel full returns untruncated content", async () => {
122
+ const longContent = "A".repeat(5000);
123
+ await writeCommand({ path: "projects/my-project/context.md", content: longContent, frontmatter: { type: "context" } }, ctx);
124
+ const result = await contextCommand({ project: "my-project", detailLevel: "full" }, ctx);
125
+ expect(result.truncated).toBe(false);
126
+ expect(result.context_md).toContain(longContent.trim());
127
+ });
128
+ it("context with detailLevel summary truncates to token budget", async () => {
129
+ const longContent = "word ".repeat(3000);
130
+ await writeCommand({ path: "projects/my-project/context.md", content: longContent, frontmatter: { type: "context" } }, ctx);
131
+ const result = await contextCommand({ project: "my-project", detailLevel: "summary", maxTokens: 100 }, ctx);
132
+ expect(result.truncated).toBe(true);
133
+ expect(result.token_estimate).toBeLessThanOrEqual(150);
134
+ });
135
+ });
136
+ describe("cross-command flow", () => {
137
+ it("write ADR via decide, then search finds it by content", async () => {
138
+ const decision = await decideCommand({
139
+ title: "Use TypeScript",
140
+ context: "Need type safety",
141
+ decision: "We chose TypeScript",
142
+ project: "my-project",
143
+ }, ctx);
144
+ expect(decision.decision_number).toBe(1);
145
+ expect(decision.path).toContain("decisions");
146
+ const results = await searchCommand({ query: "TypeScript", project: "my-project" }, ctx);
147
+ expect(results.length).toBeGreaterThanOrEqual(1);
148
+ const paths = results.map((r) => r.path);
149
+ expect(paths.some((p) => p.includes(decision.path))).toBe(true);
150
+ });
151
+ it("write task via task, then read retrieves it", async () => {
152
+ const taskResult = await taskCommand({
153
+ action: "add",
154
+ title: "Implement feature X",
155
+ project: "my-project",
156
+ }, ctx);
157
+ expect(taskResult.task_id).toBe("task-001");
158
+ expect(taskResult.path).toBeDefined();
159
+ const content = await readCommand({ path: taskResult.path }, ctx);
160
+ expect(content).toContain("Implement feature X");
161
+ const { data } = parseFrontmatter(content);
162
+ expect(data.type).toBe("task");
163
+ expect(data.status).toBe("backlog");
164
+ });
165
+ it("write learning, then context includes learning count", async () => {
166
+ await learnCommand({
167
+ action: "add",
168
+ title: "Vault is fast",
169
+ discovery: "File operations complete in under 1ms",
170
+ project: "my-project",
171
+ }, ctx);
172
+ await learnCommand({
173
+ action: "add",
174
+ title: "Frontmatter matters",
175
+ discovery: "YAML frontmatter enables structured search",
176
+ project: "my-project",
177
+ }, ctx);
178
+ const result = await contextCommand({ project: "my-project" }, ctx);
179
+ expect(result.learning_count).toBe(2);
180
+ });
181
+ });
182
+ });
183
+ //# sourceMappingURL=vault-lifecycle.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-lifecycle.test.js","sourceRoot":"","sources":["../../src/integration/vault-lifecycle.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { VaultFS } from "./vault-fs.js";
2
+ /**
3
+ * Find the next auto-increment number for files in a directory.
4
+ * Scans existing files matching NNN-*.md pattern.
5
+ */
6
+ export declare function getNextNumber(vaultFs: VaultFS, dirPath: string): Promise<number>;
7
+ /**
8
+ * Generate a filename slug from a title.
9
+ */
10
+ export declare function slugify(title: string): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Find the next auto-increment number for files in a directory.
3
+ * Scans existing files matching NNN-*.md pattern.
4
+ */
5
+ export async function getNextNumber(vaultFs, dirPath) {
6
+ let nextNumber = 1;
7
+ try {
8
+ const files = await vaultFs.list(dirPath, 1);
9
+ for (const file of files) {
10
+ const match = file.match(/(\d+)-/);
11
+ if (match) {
12
+ const num = parseInt(match[1], 10);
13
+ if (num >= nextNumber)
14
+ nextNumber = num + 1;
15
+ }
16
+ }
17
+ }
18
+ catch {
19
+ // Directory doesn't exist yet, start at 1
20
+ }
21
+ return nextNumber;
22
+ }
23
+ /**
24
+ * Generate a filename slug from a title.
25
+ */
26
+ export function slugify(title) {
27
+ const result = title
28
+ .toLowerCase()
29
+ .replace(/[^a-z0-9_]+/g, "-")
30
+ .replace(/^-|-$/g, "");
31
+ return result || "untitled";
32
+ }
33
+ //# sourceMappingURL=auto-number.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-number.js","sourceRoot":"","sources":["../../src/lib/auto-number.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB,EAAE,OAAe;IACnE,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnC,IAAI,GAAG,IAAI,UAAU;oBAAE,UAAU,GAAG,GAAG,GAAG,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;IAC5C,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,MAAM,GAAG,KAAK;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzB,OAAO,MAAM,IAAI,UAAU,CAAC;AAC9B,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir, rm } from "fs/promises";
3
+ import { tmpdir } from "os";
4
+ import { join } from "path";
5
+ import { getNextNumber, slugify } from "./auto-number.js";
6
+ import { VaultFS } from "./vault-fs.js";
7
+ describe("auto-number", () => {
8
+ let vaultRoot;
9
+ let vaultFs;
10
+ beforeEach(async () => {
11
+ vaultRoot = join(tmpdir(), `autonumber-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
12
+ await mkdir(vaultRoot, { recursive: true });
13
+ vaultFs = new VaultFS(vaultRoot);
14
+ });
15
+ afterEach(async () => {
16
+ await rm(vaultRoot, { recursive: true, force: true });
17
+ });
18
+ describe("getNextNumber", () => {
19
+ it("returns 1 for empty directory", async () => {
20
+ await mkdir(join(vaultRoot, "empty"), { recursive: true });
21
+ const result = await getNextNumber(vaultFs, "empty");
22
+ expect(result).toBe(1);
23
+ });
24
+ it("returns 1 for non-existent directory", async () => {
25
+ const result = await getNextNumber(vaultFs, "nonexistent");
26
+ expect(result).toBe(1);
27
+ });
28
+ it("returns next number after existing files", async () => {
29
+ await vaultFs.write("decisions/.keep", "");
30
+ await vaultFs.write("decisions/001-first.md", "");
31
+ await vaultFs.write("decisions/002-second.md", "");
32
+ const result = await getNextNumber(vaultFs, "decisions");
33
+ expect(result).toBe(3);
34
+ });
35
+ it("handles gaps in numbering", async () => {
36
+ await vaultFs.write("tasks/.keep", "");
37
+ await vaultFs.write("tasks/001-first.md", "");
38
+ await vaultFs.write("tasks/005-fifth.md", "");
39
+ const result = await getNextNumber(vaultFs, "tasks");
40
+ expect(result).toBe(6);
41
+ });
42
+ it("ignores files without number prefix", async () => {
43
+ await vaultFs.write("mixed/.keep", "");
44
+ await vaultFs.write("mixed/001-numbered.md", "");
45
+ await vaultFs.write("mixed/unnumbered.md", "");
46
+ await vaultFs.write("mixed/README.md", "");
47
+ const result = await getNextNumber(vaultFs, "mixed");
48
+ expect(result).toBe(2);
49
+ });
50
+ it("handles single digit numbers", async () => {
51
+ await vaultFs.write("single/.keep", "");
52
+ await vaultFs.write("single/1-first.md", "");
53
+ await vaultFs.write("single/5-fifth.md", "");
54
+ const result = await getNextNumber(vaultFs, "single");
55
+ expect(result).toBe(6);
56
+ });
57
+ it("handles three digit numbers", async () => {
58
+ await vaultFs.write("triple/.keep", "");
59
+ await vaultFs.write("triple/099-late.md", "");
60
+ await vaultFs.write("triple/100-hundred.md", "");
61
+ const result = await getNextNumber(vaultFs, "triple");
62
+ expect(result).toBe(101);
63
+ });
64
+ });
65
+ describe("slugify", () => {
66
+ const cases = [
67
+ { name: "simple title", input: "Hello World", expected: "hello-world" },
68
+ { name: "spaces become dashes", input: "multiple spaces", expected: "multiple-spaces" },
69
+ { name: "special chars removed", input: "Hello! @World# $Test%", expected: "hello-world-test" },
70
+ { name: "uppercase to lowercase", input: "UPPERCASE TITLE", expected: "uppercase-title" },
71
+ { name: "mixed case", input: "MixedCase Title", expected: "mixedcase-title" },
72
+ { name: "numbers preserved", input: "Task 123 Test", expected: "task-123-test" },
73
+ { name: "dashes at start removed", input: "-start with dash", expected: "start-with-dash" },
74
+ { name: "dashes at end removed", input: "end with dash-", expected: "end-with-dash" },
75
+ { name: "multiple dashes collapsed", input: "a---b", expected: "a-b" },
76
+ { name: "empty string", input: "", expected: "untitled" },
77
+ { name: "only special chars", input: "!@#$%", expected: "untitled" },
78
+ { name: "underscore preserved", input: "hello_world", expected: "hello_world" },
79
+ { name: "dots removed", input: "file.name.md", expected: "file-name-md" },
80
+ ];
81
+ for (const c of cases) {
82
+ it(c.name, () => {
83
+ expect(slugify(c.input)).toBe(c.expected);
84
+ });
85
+ }
86
+ });
87
+ });
88
+ //# sourceMappingURL=auto-number.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-number.test.js","sourceRoot":"","sources":["../../src/lib/auto-number.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Escape a string for use in a regex pattern.
3
+ */
4
+ export declare function escapeRegex(str: string): string;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Escape a string for use in a regex pattern.
3
+ */
4
+ export function escapeRegex(str) {
5
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6
+ }
7
+ //# sourceMappingURL=escape-regex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape-regex.js","sourceRoot":"","sources":["../../src/lib/escape-regex.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { escapeRegex } from "./escape-regex.js";
3
+ describe("escapeRegex", () => {
4
+ const cases = [
5
+ { name: "empty string", input: "", expected: "" },
6
+ { name: "normal string", input: "hello", expected: "hello" },
7
+ { name: "dot", input: "a.b", expected: "a\\.b" },
8
+ { name: "asterisk", input: "a*b", expected: "a\\*b" },
9
+ { name: "plus", input: "a+b", expected: "a\\+b" },
10
+ { name: "question", input: "a?b", expected: "a\\?b" },
11
+ { name: "caret", input: "a^b", expected: "a\\^b" },
12
+ { name: "dollar", input: "a$b", expected: "a\\$b" },
13
+ { name: "braces", input: "a{b}", expected: "a\\{b\\}" },
14
+ { name: "parentheses", input: "a(b)", expected: "a\\(b\\)" },
15
+ { name: "pipe", input: "a|b", expected: "a\\|b" },
16
+ { name: "brackets", input: "a[b]", expected: "a\\[b\\]" },
17
+ { name: "backslash", input: "a\\b", expected: "a\\\\b" },
18
+ { name: "multiple special chars", input: "a.b*c+d?e^f$g{h}i(j)j|k[l]m\\n", expected: "a\\.b\\*c\\+d\\?e\\^f\\$g\\{h\\}i\\(j\\)j\\|k\\[l\\]m\\\\n" },
19
+ { name: "regex pattern", input: ".*+?^${}()|[]\\", expected: "\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\|\\[\\]\\\\" },
20
+ ];
21
+ for (const c of cases) {
22
+ it(c.name, () => {
23
+ expect(escapeRegex(c.input)).toBe(c.expected);
24
+ });
25
+ }
26
+ });
27
+ //# sourceMappingURL=escape-regex.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape-regex.test.js","sourceRoot":"","sources":["../../src/lib/escape-regex.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,MAAM,KAAK,GAAG;QACZ,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjD,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE;QAC5D,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QAChD,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACrD,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACjD,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACrD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QAClD,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACnD,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE;QACvD,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE;QAC5D,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACjD,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE;QACzD,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE;QACxD,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,gCAAgC,EAAE,QAAQ,EAAE,4DAA4D,EAAE;QACnJ,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,6CAA6C,EAAE;KAC7G,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE;YACd,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC"}