gnosys-mcp 0.1.0

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +297 -0
  3. package/dist/cli.d.ts +7 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +927 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.d.ts +8 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +1092 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/lib/bootstrap.d.ts +56 -0
  12. package/dist/lib/bootstrap.d.ts.map +1 -0
  13. package/dist/lib/bootstrap.js +163 -0
  14. package/dist/lib/bootstrap.js.map +1 -0
  15. package/dist/lib/history.d.ts +39 -0
  16. package/dist/lib/history.d.ts.map +1 -0
  17. package/dist/lib/history.js +86 -0
  18. package/dist/lib/history.js.map +1 -0
  19. package/dist/lib/ingest.d.ts +47 -0
  20. package/dist/lib/ingest.d.ts.map +1 -0
  21. package/dist/lib/ingest.js +134 -0
  22. package/dist/lib/ingest.js.map +1 -0
  23. package/dist/lib/lensing.d.ts +35 -0
  24. package/dist/lib/lensing.d.ts.map +1 -0
  25. package/dist/lib/lensing.js +85 -0
  26. package/dist/lib/lensing.js.map +1 -0
  27. package/dist/lib/resolver.d.ts +84 -0
  28. package/dist/lib/resolver.d.ts.map +1 -0
  29. package/dist/lib/resolver.js +269 -0
  30. package/dist/lib/resolver.js.map +1 -0
  31. package/dist/lib/search.d.ts +50 -0
  32. package/dist/lib/search.d.ts.map +1 -0
  33. package/dist/lib/search.js +166 -0
  34. package/dist/lib/search.js.map +1 -0
  35. package/dist/lib/store.d.ts +67 -0
  36. package/dist/lib/store.d.ts.map +1 -0
  37. package/dist/lib/store.js +168 -0
  38. package/dist/lib/store.js.map +1 -0
  39. package/dist/lib/tags.d.ts +26 -0
  40. package/dist/lib/tags.d.ts.map +1 -0
  41. package/dist/lib/tags.js +109 -0
  42. package/dist/lib/tags.js.map +1 -0
  43. package/dist/lib/timeline.d.ts +34 -0
  44. package/dist/lib/timeline.d.ts.map +1 -0
  45. package/dist/lib/timeline.js +116 -0
  46. package/dist/lib/timeline.js.map +1 -0
  47. package/dist/lib/wikilinks.d.ts +63 -0
  48. package/dist/lib/wikilinks.d.ts.map +1 -0
  49. package/dist/lib/wikilinks.js +146 -0
  50. package/dist/lib/wikilinks.js.map +1 -0
  51. package/dist/test/bootstrap.test.d.ts +2 -0
  52. package/dist/test/bootstrap.test.d.ts.map +1 -0
  53. package/dist/test/bootstrap.test.js +208 -0
  54. package/dist/test/bootstrap.test.js.map +1 -0
  55. package/dist/test/history.test.d.ts +2 -0
  56. package/dist/test/history.test.d.ts.map +1 -0
  57. package/dist/test/history.test.js +141 -0
  58. package/dist/test/history.test.js.map +1 -0
  59. package/dist/test/ingest.test.d.ts +2 -0
  60. package/dist/test/ingest.test.d.ts.map +1 -0
  61. package/dist/test/ingest.test.js +132 -0
  62. package/dist/test/ingest.test.js.map +1 -0
  63. package/dist/test/lensing.test.d.ts +2 -0
  64. package/dist/test/lensing.test.d.ts.map +1 -0
  65. package/dist/test/lensing.test.js +154 -0
  66. package/dist/test/lensing.test.js.map +1 -0
  67. package/dist/test/search.test.d.ts +2 -0
  68. package/dist/test/search.test.d.ts.map +1 -0
  69. package/dist/test/search.test.js +129 -0
  70. package/dist/test/search.test.js.map +1 -0
  71. package/dist/test/store.test.d.ts +2 -0
  72. package/dist/test/store.test.d.ts.map +1 -0
  73. package/dist/test/store.test.js +152 -0
  74. package/dist/test/store.test.js.map +1 -0
  75. package/dist/test/tags.test.d.ts +2 -0
  76. package/dist/test/tags.test.d.ts.map +1 -0
  77. package/dist/test/tags.test.js +81 -0
  78. package/dist/test/tags.test.js.map +1 -0
  79. package/dist/test/timeline.test.d.ts +2 -0
  80. package/dist/test/timeline.test.d.ts.map +1 -0
  81. package/dist/test/timeline.test.js +127 -0
  82. package/dist/test/timeline.test.js.map +1 -0
  83. package/dist/test/wikilinks.test.d.ts +2 -0
  84. package/dist/test/wikilinks.test.d.ts.map +1 -0
  85. package/dist/test/wikilinks.test.js +178 -0
  86. package/dist/test/wikilinks.test.js.map +1 -0
  87. package/package.json +56 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Tests for GnosysStore — core read/write operations on atomic memory files.
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
5
+ import fs from "fs/promises";
6
+ import path from "path";
7
+ import os from "os";
8
+ import { GnosysStore } from "../lib/store.js";
9
+ let tmpDir;
10
+ let store;
11
+ function makeFrontmatter(overrides = {}) {
12
+ return {
13
+ id: "test-001",
14
+ title: "Test Memory",
15
+ category: "decisions",
16
+ tags: { domain: ["testing"], type: ["decision"] },
17
+ relevance: "test unit testing vitest store",
18
+ author: "human",
19
+ authority: "declared",
20
+ confidence: 0.9,
21
+ created: "2026-03-06",
22
+ modified: "2026-03-06",
23
+ last_reviewed: "2026-03-06",
24
+ status: "active",
25
+ supersedes: null,
26
+ ...overrides,
27
+ };
28
+ }
29
+ beforeEach(async () => {
30
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "gnosys-test-"));
31
+ store = new GnosysStore(tmpDir);
32
+ await store.init();
33
+ });
34
+ afterEach(async () => {
35
+ await fs.rm(tmpDir, { recursive: true, force: true });
36
+ });
37
+ describe("GnosysStore", () => {
38
+ describe("init", () => {
39
+ it("creates .gnosys internal directory", async () => {
40
+ const stat = await fs.stat(path.join(tmpDir, ".gnosys"));
41
+ expect(stat.isDirectory()).toBe(true);
42
+ });
43
+ });
44
+ describe("writeMemory + readMemory", () => {
45
+ it("writes and reads a memory with correct frontmatter", async () => {
46
+ const fm = makeFrontmatter();
47
+ const content = "# Test Memory\n\nThis is test content.";
48
+ const relPath = await store.writeMemory("decisions", "test.md", fm, content);
49
+ expect(relPath).toBe("decisions/test.md");
50
+ const memory = await store.readMemory(relPath);
51
+ expect(memory).not.toBeNull();
52
+ expect(memory.frontmatter.id).toBe("test-001");
53
+ expect(memory.frontmatter.title).toBe("Test Memory");
54
+ expect(memory.frontmatter.relevance).toBe("test unit testing vitest store");
55
+ expect(memory.frontmatter.status).toBe("active");
56
+ expect(memory.content).toContain("This is test content.");
57
+ });
58
+ it("returns null for non-existent memory", async () => {
59
+ const memory = await store.readMemory("nope/doesnt-exist.md");
60
+ expect(memory).toBeNull();
61
+ });
62
+ it("returns null for files without id frontmatter", async () => {
63
+ const filePath = path.join(tmpDir, "no-id.md");
64
+ await fs.writeFile(filePath, "---\ntitle: No ID\n---\nContent", "utf-8");
65
+ const memory = await store.readMemory("no-id.md");
66
+ expect(memory).toBeNull();
67
+ });
68
+ });
69
+ describe("getAllMemories", () => {
70
+ it("returns all valid memories, ignores non-memory files", async () => {
71
+ // Write two valid memories
72
+ await store.writeMemory("decisions", "a.md", makeFrontmatter({ id: "deci-001", title: "Decision A" }), "# Decision A\n\nContent A");
73
+ await store.writeMemory("concepts", "b.md", makeFrontmatter({ id: "conc-001", title: "Concept B", category: "concepts" }), "# Concept B\n\nContent B");
74
+ // Write a non-memory file (no id)
75
+ await fs.mkdir(path.join(tmpDir, "misc"), { recursive: true });
76
+ await fs.writeFile(path.join(tmpDir, "misc", "random.md"), "---\ntitle: Random\n---\nNot a memory", "utf-8");
77
+ const memories = await store.getAllMemories();
78
+ expect(memories.length).toBe(2);
79
+ const titles = memories.map((m) => m.frontmatter.title).sort();
80
+ expect(titles).toEqual(["Concept B", "Decision A"]);
81
+ });
82
+ it("ignores CHANGELOG.md and MANIFEST.md", async () => {
83
+ await fs.writeFile(path.join(tmpDir, "CHANGELOG.md"), "---\nid: skip\n---\nShould be ignored", "utf-8");
84
+ await store.writeMemory("decisions", "real.md", makeFrontmatter(), "# Real\n\nContent");
85
+ const memories = await store.getAllMemories();
86
+ expect(memories.length).toBe(1);
87
+ expect(memories[0].frontmatter.title).toBe("Test Memory");
88
+ });
89
+ });
90
+ describe("updateMemory", () => {
91
+ it("updates frontmatter fields and preserves content", async () => {
92
+ await store.writeMemory("decisions", "update-test.md", makeFrontmatter(), "# Test\n\nOriginal content");
93
+ const updated = await store.updateMemory("decisions/update-test.md", {
94
+ title: "Updated Title",
95
+ confidence: 0.5,
96
+ status: "archived",
97
+ });
98
+ expect(updated).not.toBeNull();
99
+ expect(updated.frontmatter.title).toBe("Updated Title");
100
+ expect(updated.frontmatter.confidence).toBe(0.5);
101
+ expect(updated.frontmatter.status).toBe("archived");
102
+ expect(updated.content).toContain("Original content");
103
+ // modified should be updated to today
104
+ expect(updated.frontmatter.modified).toBe(new Date().toISOString().split("T")[0]);
105
+ });
106
+ it("can replace content", async () => {
107
+ await store.writeMemory("decisions", "content-test.md", makeFrontmatter(), "# Old\n\nOld content");
108
+ const updated = await store.updateMemory("decisions/content-test.md", {}, "# New\n\nNew content");
109
+ expect(updated).not.toBeNull();
110
+ expect(updated.content).toContain("New content");
111
+ expect(updated.content).not.toContain("Old content");
112
+ });
113
+ it("returns null for non-existent memory", async () => {
114
+ const result = await store.updateMemory("nope.md", { title: "X" });
115
+ expect(result).toBeNull();
116
+ });
117
+ });
118
+ describe("getCategories", () => {
119
+ it("returns only directories, excludes hidden and node_modules", async () => {
120
+ await fs.mkdir(path.join(tmpDir, "decisions"), { recursive: true });
121
+ await fs.mkdir(path.join(tmpDir, "concepts"), { recursive: true });
122
+ // .gnosys already exists from init
123
+ const cats = await store.getCategories();
124
+ expect(cats).toContain("decisions");
125
+ expect(cats).toContain("concepts");
126
+ expect(cats).not.toContain(".gnosys");
127
+ });
128
+ });
129
+ describe("generateId", () => {
130
+ it("generates sequential IDs with category prefix", async () => {
131
+ const id1 = await store.generateId("decisions");
132
+ expect(id1).toBe("deci-001");
133
+ await store.writeMemory("decisions", "first.md", makeFrontmatter({ id: id1 }), "# First\n\nContent");
134
+ const id2 = await store.generateId("decisions");
135
+ expect(id2).toBe("deci-002");
136
+ });
137
+ });
138
+ describe("supersession fields", () => {
139
+ it("writes and reads supersedes/superseded_by fields", async () => {
140
+ const fm = makeFrontmatter({
141
+ id: "deci-002",
142
+ supersedes: "deci-001",
143
+ superseded_by: null,
144
+ });
145
+ await store.writeMemory("decisions", "v2.md", fm, "# V2\n\nNew version");
146
+ const memory = await store.readMemory("decisions/v2.md");
147
+ expect(memory.frontmatter.supersedes).toBe("deci-001");
148
+ expect(memory.frontmatter.superseded_by).toBeNull();
149
+ });
150
+ });
151
+ });
152
+ //# sourceMappingURL=store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.test.js","sourceRoot":"","sources":["../../src/test/store.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tags.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.test.d.ts","sourceRoot":"","sources":["../../src/test/tags.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Tests for GnosysTagRegistry — tag management and validation.
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
5
+ import fs from "fs/promises";
6
+ import path from "path";
7
+ import os from "os";
8
+ import { GnosysTagRegistry } from "../lib/tags.js";
9
+ let tmpDir;
10
+ let registry;
11
+ beforeEach(async () => {
12
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "gnosys-tags-test-"));
13
+ // GnosysTagRegistry expects tags at .gnosys/tags.json inside the store
14
+ const gnosysDir = path.join(tmpDir, ".gnosys");
15
+ await fs.mkdir(gnosysDir, { recursive: true });
16
+ const defaultTags = {
17
+ domain: ["architecture", "auth", "testing"],
18
+ type: ["decision", "concept"],
19
+ concern: ["dx", "scalability"],
20
+ };
21
+ await fs.writeFile(path.join(gnosysDir, "tags.json"), JSON.stringify(defaultTags, null, 2), "utf-8");
22
+ registry = new GnosysTagRegistry(tmpDir);
23
+ await registry.load();
24
+ });
25
+ afterEach(async () => {
26
+ await fs.rm(tmpDir, { recursive: true, force: true });
27
+ });
28
+ describe("GnosysTagRegistry", () => {
29
+ describe("load + getRegistry", () => {
30
+ it("loads tags from tags.json", () => {
31
+ const reg = registry.getRegistry();
32
+ expect(reg.domain).toContain("auth");
33
+ expect(reg.type).toContain("decision");
34
+ expect(reg.concern).toContain("dx");
35
+ });
36
+ });
37
+ describe("hasTag", () => {
38
+ it("finds existing tags", () => {
39
+ expect(registry.hasTag("auth")).toBe(true);
40
+ expect(registry.hasTag("architecture")).toBe(true);
41
+ });
42
+ it("returns false for non-existent tags", () => {
43
+ expect(registry.hasTag("nonexistent-tag-xyz")).toBe(false);
44
+ });
45
+ });
46
+ describe("addTag", () => {
47
+ it("adds a new tag to an existing category", async () => {
48
+ const added = await registry.addTag("domain", "frontend");
49
+ expect(added).toBe(true);
50
+ expect(registry.hasTag("frontend")).toBe(true);
51
+ // Verify it was persisted to disk at .gnosys/tags.json
52
+ const raw = await fs.readFile(path.join(tmpDir, ".gnosys", "tags.json"), "utf-8");
53
+ const parsed = JSON.parse(raw);
54
+ expect(parsed.domain).toContain("frontend");
55
+ });
56
+ it("adds a tag to a new category", async () => {
57
+ const added = await registry.addTag("status_tag", "stable");
58
+ expect(added).toBe(true);
59
+ expect(registry.hasTag("stable")).toBe(true);
60
+ });
61
+ it("returns false if tag already exists", async () => {
62
+ const added = await registry.addTag("domain", "auth");
63
+ expect(added).toBe(false);
64
+ });
65
+ });
66
+ describe("edge cases", () => {
67
+ it("falls back to DEFAULT_REGISTRY when tags.json is missing", async () => {
68
+ // GnosysTagRegistry falls back to a built-in default when no file exists
69
+ const emptyDir = await fs.mkdtemp(path.join(os.tmpdir(), "gnosys-tags-empty-"));
70
+ const emptyRegistry = new GnosysTagRegistry(emptyDir);
71
+ await emptyRegistry.load();
72
+ const reg = emptyRegistry.getRegistry();
73
+ // Default registry has 4 categories: domain, type, concern, status_tag
74
+ expect(Object.keys(reg).length).toBe(4);
75
+ expect(reg.domain).toBeDefined();
76
+ expect(reg.domain.length).toBeGreaterThan(0);
77
+ await fs.rm(emptyDir, { recursive: true, force: true });
78
+ });
79
+ });
80
+ });
81
+ //# sourceMappingURL=tags.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.test.js","sourceRoot":"","sources":["../../src/test/tags.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=timeline.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.test.d.ts","sourceRoot":"","sources":["../../src/test/timeline.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { groupByPeriod, computeStats } from "../lib/timeline.js";
3
+ function makeMem(overrides = {}) {
4
+ const frontmatter = {
5
+ id: "test-001",
6
+ title: "Test",
7
+ category: "decisions",
8
+ tags: { domain: ["testing"] },
9
+ relevance: "test",
10
+ author: "human",
11
+ authority: "declared",
12
+ confidence: 0.8,
13
+ created: "2026-02-15",
14
+ modified: "2026-02-15",
15
+ status: "active",
16
+ supersedes: null,
17
+ ...overrides,
18
+ };
19
+ return {
20
+ frontmatter,
21
+ content: "# Test",
22
+ filePath: `/tmp/${frontmatter.id}.md`,
23
+ relativePath: `${frontmatter.category}/${frontmatter.id}.md`,
24
+ };
25
+ }
26
+ const memories = [
27
+ makeMem({ id: "d1", title: "Jan Decision", category: "decisions", created: "2026-01-10", modified: "2026-01-15", confidence: 0.9, author: "human" }),
28
+ makeMem({ id: "d2", title: "Jan Concept", category: "concepts", created: "2026-01-20", modified: "2026-02-01", confidence: 0.7, author: "ai" }),
29
+ makeMem({ id: "d3", title: "Feb Decision", category: "decisions", created: "2026-02-05", modified: "2026-02-05", confidence: 0.85, author: "human+ai" }),
30
+ makeMem({ id: "d4", title: "Feb Arch", category: "architecture", created: "2026-02-15", modified: "2026-03-01", confidence: 0.6, author: "ai", status: "superseded" }),
31
+ makeMem({ id: "d5", title: "Mar Decision", category: "decisions", created: "2026-03-01", modified: "2026-03-06", confidence: 0.95, author: "human", authority: "observed" }),
32
+ ];
33
+ describe("groupByPeriod", () => {
34
+ it("groups by month", () => {
35
+ const result = groupByPeriod(memories, "month");
36
+ expect(result).toHaveLength(3); // Jan, Feb, Mar
37
+ const jan = result.find((e) => e.period === "2026-01");
38
+ expect(jan?.created).toBe(2);
39
+ const feb = result.find((e) => e.period === "2026-02");
40
+ expect(feb?.created).toBe(2);
41
+ const mar = result.find((e) => e.period === "2026-03");
42
+ expect(mar?.created).toBe(1);
43
+ });
44
+ it("groups by year", () => {
45
+ const result = groupByPeriod(memories, "year");
46
+ expect(result).toHaveLength(1);
47
+ expect(result[0].period).toBe("2026");
48
+ expect(result[0].created).toBe(5);
49
+ });
50
+ it("groups by day", () => {
51
+ const result = groupByPeriod(memories, "day");
52
+ // Each memory has a unique created date
53
+ expect(result.length).toBeGreaterThanOrEqual(5);
54
+ });
55
+ it("groups by week", () => {
56
+ const result = groupByPeriod(memories, "week");
57
+ // Should have multiple weeks
58
+ expect(result.length).toBeGreaterThan(1);
59
+ // Each entry should have W## format
60
+ for (const entry of result) {
61
+ expect(entry.period).toMatch(/^\d{4}-W\d{2}$/);
62
+ }
63
+ });
64
+ it("returns entries sorted chronologically", () => {
65
+ const result = groupByPeriod(memories, "month");
66
+ for (let i = 1; i < result.length; i++) {
67
+ expect(result[i].period > result[i - 1].period).toBe(true);
68
+ }
69
+ });
70
+ it("tracks modified separately from created", () => {
71
+ const result = groupByPeriod(memories, "month");
72
+ // d2 created Jan, modified Feb → Feb should have modified count
73
+ const feb = result.find((e) => e.period === "2026-02");
74
+ expect(feb?.modified).toBeGreaterThanOrEqual(1);
75
+ });
76
+ it("includes titles for created memories", () => {
77
+ const result = groupByPeriod(memories, "month");
78
+ const jan = result.find((e) => e.period === "2026-01");
79
+ expect(jan?.titles).toContain("Jan Decision");
80
+ expect(jan?.titles).toContain("Jan Concept");
81
+ });
82
+ it("handles empty array", () => {
83
+ const result = groupByPeriod([], "month");
84
+ expect(result).toHaveLength(0);
85
+ });
86
+ });
87
+ describe("computeStats", () => {
88
+ it("computes total count", () => {
89
+ const stats = computeStats(memories);
90
+ expect(stats.totalCount).toBe(5);
91
+ });
92
+ it("counts by category", () => {
93
+ const stats = computeStats(memories);
94
+ expect(stats.byCategory.decisions).toBe(3);
95
+ expect(stats.byCategory.concepts).toBe(1);
96
+ expect(stats.byCategory.architecture).toBe(1);
97
+ });
98
+ it("counts by status", () => {
99
+ const stats = computeStats(memories);
100
+ expect(stats.byStatus.active).toBe(4);
101
+ expect(stats.byStatus.superseded).toBe(1);
102
+ });
103
+ it("counts by author", () => {
104
+ const stats = computeStats(memories);
105
+ expect(stats.byAuthor.human).toBe(2);
106
+ expect(stats.byAuthor.ai).toBe(2);
107
+ expect(stats.byAuthor["human+ai"]).toBe(1);
108
+ });
109
+ it("computes average confidence", () => {
110
+ const stats = computeStats(memories);
111
+ // (0.9 + 0.7 + 0.85 + 0.6 + 0.95) / 5 = 0.8
112
+ expect(stats.averageConfidence).toBe(0.8);
113
+ });
114
+ it("finds oldest and newest dates", () => {
115
+ const stats = computeStats(memories);
116
+ expect(stats.oldestCreated).toBe("2026-01-10");
117
+ expect(stats.newestCreated).toBe("2026-03-01");
118
+ expect(stats.lastModified).toBe("2026-03-06");
119
+ });
120
+ it("handles empty array", () => {
121
+ const stats = computeStats([]);
122
+ expect(stats.totalCount).toBe(0);
123
+ expect(stats.averageConfidence).toBe(0);
124
+ expect(stats.oldestCreated).toBeNull();
125
+ });
126
+ });
127
+ //# sourceMappingURL=timeline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.test.js","sourceRoot":"","sources":["../../src/test/timeline.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wikilinks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikilinks.test.d.ts","sourceRoot":"","sources":["../../src/test/wikilinks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,178 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { extractLinks, resolveLink, buildLinkGraph, getBacklinks, getOutgoingLinks, formatGraphSummary, } from "../lib/wikilinks.js";
3
+ function makeMem(overrides = {}) {
4
+ const { content: body, ...fmOverrides } = overrides;
5
+ const frontmatter = {
6
+ id: "test-001",
7
+ title: "Test Memory",
8
+ category: "decisions",
9
+ tags: { domain: ["testing"] },
10
+ relevance: "test",
11
+ author: "human",
12
+ authority: "declared",
13
+ confidence: 0.8,
14
+ created: "2026-02-15",
15
+ modified: "2026-02-15",
16
+ status: "active",
17
+ supersedes: null,
18
+ ...fmOverrides,
19
+ };
20
+ return {
21
+ frontmatter,
22
+ content: body ?? "# Test",
23
+ filePath: `/tmp/${frontmatter.category}/${frontmatter.id}.md`,
24
+ relativePath: `${frontmatter.category}/${frontmatter.id}.md`,
25
+ };
26
+ }
27
+ const memories = [
28
+ makeMem({
29
+ id: "auth-decision",
30
+ title: "Auth Decision",
31
+ category: "decisions",
32
+ content: "# Auth Decision\n\nWe chose JWT. See [[DB Choice]] and [[architecture/three-layers]].",
33
+ }),
34
+ makeMem({
35
+ id: "db-choice",
36
+ title: "DB Choice",
37
+ category: "decisions",
38
+ content: "# DB Choice\n\nPostgres. Related to [[Auth Decision|our auth approach]].",
39
+ }),
40
+ makeMem({
41
+ id: "three-layers",
42
+ title: "Three Layers",
43
+ category: "architecture",
44
+ content: "# Three Layers\n\nPresentation, domain, data.",
45
+ }),
46
+ makeMem({
47
+ id: "frontend-guide",
48
+ title: "Frontend Guide",
49
+ category: "conventions",
50
+ content: "# Frontend Guide\n\nSee [[Nonexistent Memory]] and [[Auth Decision]].",
51
+ }),
52
+ ];
53
+ describe("extractLinks", () => {
54
+ it("extracts simple wikilinks", () => {
55
+ const links = extractLinks(memories[0]);
56
+ expect(links).toHaveLength(2);
57
+ expect(links[0].target).toBe("DB Choice");
58
+ expect(links[0].displayText).toBeNull();
59
+ expect(links[1].target).toBe("architecture/three-layers");
60
+ });
61
+ it("extracts wikilinks with display text", () => {
62
+ const links = extractLinks(memories[1]);
63
+ expect(links).toHaveLength(1);
64
+ expect(links[0].target).toBe("Auth Decision");
65
+ expect(links[0].displayText).toBe("our auth approach");
66
+ });
67
+ it("returns empty array for content with no links", () => {
68
+ const links = extractLinks(memories[2]);
69
+ expect(links).toHaveLength(0);
70
+ });
71
+ it("includes source info", () => {
72
+ const links = extractLinks(memories[0]);
73
+ expect(links[0].sourcePath).toBe("decisions/auth-decision.md");
74
+ expect(links[0].sourceTitle).toBe("Auth Decision");
75
+ });
76
+ });
77
+ describe("resolveLink", () => {
78
+ it("resolves by title (case-insensitive)", () => {
79
+ const result = resolveLink("DB Choice", memories);
80
+ expect(result?.frontmatter.id).toBe("db-choice");
81
+ });
82
+ it("resolves by title case-insensitively", () => {
83
+ const result = resolveLink("db choice", memories);
84
+ expect(result?.frontmatter.id).toBe("db-choice");
85
+ });
86
+ it("resolves by relative path", () => {
87
+ const result = resolveLink("architecture/three-layers.md", memories);
88
+ expect(result?.frontmatter.id).toBe("three-layers");
89
+ });
90
+ it("resolves by filename without extension", () => {
91
+ const result = resolveLink("three-layers", memories);
92
+ expect(result?.frontmatter.id).toBe("three-layers");
93
+ });
94
+ it("resolves by id", () => {
95
+ const result = resolveLink("auth-decision", memories);
96
+ expect(result?.frontmatter.id).toBe("auth-decision");
97
+ });
98
+ it("returns null for non-existent target", () => {
99
+ const result = resolveLink("Nonexistent Memory", memories);
100
+ expect(result).toBeNull();
101
+ });
102
+ });
103
+ describe("buildLinkGraph", () => {
104
+ it("builds graph with correct link counts", () => {
105
+ const graph = buildLinkGraph(memories);
106
+ expect(graph.totalLinks).toBe(5); // 2 + 1 + 0 + 2
107
+ });
108
+ it("tracks outgoing links", () => {
109
+ const graph = buildLinkGraph(memories);
110
+ const authNode = graph.nodes.get("decisions/auth-decision.md");
111
+ expect(authNode?.outgoing).toHaveLength(2);
112
+ });
113
+ it("tracks backlinks (incoming)", () => {
114
+ const graph = buildLinkGraph(memories);
115
+ // Auth Decision is linked to by DB Choice and Frontend Guide
116
+ const authNode = graph.nodes.get("decisions/auth-decision.md");
117
+ expect(authNode?.incoming).toHaveLength(2);
118
+ const sources = authNode?.incoming.map((l) => l.sourceTitle);
119
+ expect(sources).toContain("DB Choice");
120
+ expect(sources).toContain("Frontend Guide");
121
+ });
122
+ it("identifies orphaned links", () => {
123
+ const graph = buildLinkGraph(memories);
124
+ expect(graph.orphanedLinks).toHaveLength(1);
125
+ expect(graph.orphanedLinks[0].target).toBe("Nonexistent Memory");
126
+ expect(graph.orphanedLinks[0].sourceTitle).toBe("Frontend Guide");
127
+ });
128
+ it("handles memories with no links", () => {
129
+ const graph = buildLinkGraph(memories);
130
+ const layersNode = graph.nodes.get("architecture/three-layers.md");
131
+ expect(layersNode?.outgoing).toHaveLength(0);
132
+ // But it has incoming from Auth Decision
133
+ expect(layersNode?.incoming).toHaveLength(1);
134
+ });
135
+ it("handles empty memory list", () => {
136
+ const graph = buildLinkGraph([]);
137
+ expect(graph.totalLinks).toBe(0);
138
+ expect(graph.orphanedLinks).toHaveLength(0);
139
+ expect(graph.nodes.size).toBe(0);
140
+ });
141
+ });
142
+ describe("getBacklinks", () => {
143
+ it("returns backlinks for a target", () => {
144
+ const backlinks = getBacklinks(memories, "decisions/auth-decision.md");
145
+ expect(backlinks).toHaveLength(2);
146
+ });
147
+ it("returns empty for memory with no backlinks", () => {
148
+ const backlinks = getBacklinks(memories, "conventions/frontend-guide.md");
149
+ expect(backlinks).toHaveLength(0);
150
+ });
151
+ });
152
+ describe("getOutgoingLinks", () => {
153
+ it("returns outgoing links for a source", () => {
154
+ const outgoing = getOutgoingLinks(memories, "decisions/auth-decision.md");
155
+ expect(outgoing).toHaveLength(2);
156
+ });
157
+ it("returns empty for memory with no outgoing links", () => {
158
+ const outgoing = getOutgoingLinks(memories, "architecture/three-layers.md");
159
+ expect(outgoing).toHaveLength(0);
160
+ });
161
+ });
162
+ describe("formatGraphSummary", () => {
163
+ it("produces a readable summary", () => {
164
+ const graph = buildLinkGraph(memories);
165
+ const summary = formatGraphSummary(graph);
166
+ expect(summary).toContain("5 total links");
167
+ expect(summary).toContain("1 orphaned");
168
+ expect(summary).toContain("Auth Decision");
169
+ expect(summary).toContain("Nonexistent Memory");
170
+ });
171
+ it("handles empty graph", () => {
172
+ const graph = buildLinkGraph([]);
173
+ const summary = formatGraphSummary(graph);
174
+ expect(summary).toContain("0 total links");
175
+ expect(summary).toContain("No cross-references found");
176
+ });
177
+ });
178
+ //# sourceMappingURL=wikilinks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wikilinks.test.js","sourceRoot":"","sources":["../../src/test/wikilinks.test.ts"],"names":[],"mappings":"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"}