@vheins/local-memory-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 (196) hide show
  1. package/DASHBOARD.md +129 -0
  2. package/HYBRID_SEARCH.md +204 -0
  3. package/IMPLEMENTATION.md +159 -0
  4. package/README.md +175 -0
  5. package/dist/capabilities.d.ts +22 -0
  6. package/dist/capabilities.d.ts.map +1 -0
  7. package/dist/capabilities.js +23 -0
  8. package/dist/capabilities.js.map +1 -0
  9. package/dist/dashboard/dashboard.test.d.ts +2 -0
  10. package/dist/dashboard/dashboard.test.d.ts.map +1 -0
  11. package/dist/dashboard/dashboard.test.js +362 -0
  12. package/dist/dashboard/dashboard.test.js.map +1 -0
  13. package/dist/dashboard/public/app.js +1187 -0
  14. package/dist/dashboard/public/chart.js +0 -0
  15. package/dist/dashboard/public/index.html +967 -0
  16. package/dist/dashboard/server.d.ts +3 -0
  17. package/dist/dashboard/server.d.ts.map +1 -0
  18. package/dist/dashboard/server.js +297 -0
  19. package/dist/dashboard/server.js.map +1 -0
  20. package/dist/mcp/client.d.ts +34 -0
  21. package/dist/mcp/client.d.ts.map +1 -0
  22. package/dist/mcp/client.js +181 -0
  23. package/dist/mcp/client.js.map +1 -0
  24. package/dist/mcp/client.test.d.ts +2 -0
  25. package/dist/mcp/client.test.d.ts.map +1 -0
  26. package/dist/mcp/client.test.js +130 -0
  27. package/dist/mcp/client.test.js.map +1 -0
  28. package/dist/prompts/registry.d.ts +39 -0
  29. package/dist/prompts/registry.d.ts.map +1 -0
  30. package/dist/prompts/registry.js +90 -0
  31. package/dist/prompts/registry.js.map +1 -0
  32. package/dist/resources/index.d.ts +17 -0
  33. package/dist/resources/index.d.ts.map +1 -0
  34. package/dist/resources/index.js +100 -0
  35. package/dist/resources/index.js.map +1 -0
  36. package/dist/resources/index.test.d.ts +2 -0
  37. package/dist/resources/index.test.d.ts.map +1 -0
  38. package/dist/resources/index.test.js +96 -0
  39. package/dist/resources/index.test.js.map +1 -0
  40. package/dist/router.d.ts +4 -0
  41. package/dist/router.d.ts.map +1 -0
  42. package/dist/router.js +60 -0
  43. package/dist/router.js.map +1 -0
  44. package/dist/router.test.d.ts +2 -0
  45. package/dist/router.test.d.ts.map +1 -0
  46. package/dist/router.test.js +113 -0
  47. package/dist/router.test.js.map +1 -0
  48. package/dist/search_memory_example.d.ts +3 -0
  49. package/dist/search_memory_example.d.ts.map +1 -0
  50. package/dist/search_memory_example.js +56 -0
  51. package/dist/search_memory_example.js.map +1 -0
  52. package/dist/server.d.ts +3 -0
  53. package/dist/server.d.ts.map +1 -0
  54. package/dist/server.js +91 -0
  55. package/dist/server.js.map +1 -0
  56. package/dist/storage/sqlite.d.ts +95 -0
  57. package/dist/storage/sqlite.d.ts.map +1 -0
  58. package/dist/storage/sqlite.js +537 -0
  59. package/dist/storage/sqlite.js.map +1 -0
  60. package/dist/storage/sqlite.test.d.ts +2 -0
  61. package/dist/storage/sqlite.test.d.ts.map +1 -0
  62. package/dist/storage/sqlite.test.js +358 -0
  63. package/dist/storage/sqlite.test.js.map +1 -0
  64. package/dist/storage/vectors.stub.d.ts +12 -0
  65. package/dist/storage/vectors.stub.d.ts.map +1 -0
  66. package/dist/storage/vectors.stub.js +88 -0
  67. package/dist/storage/vectors.stub.js.map +1 -0
  68. package/dist/store_memory_example.d.ts +3 -0
  69. package/dist/store_memory_example.d.ts.map +1 -0
  70. package/dist/store_memory_example.js +69 -0
  71. package/dist/store_memory_example.js.map +1 -0
  72. package/dist/test_quotes_client.d.ts +3 -0
  73. package/dist/test_quotes_client.d.ts.map +1 -0
  74. package/dist/test_quotes_client.js +72 -0
  75. package/dist/test_quotes_client.js.map +1 -0
  76. package/dist/tools/memory.delete.d.ts +9 -0
  77. package/dist/tools/memory.delete.d.ts.map +1 -0
  78. package/dist/tools/memory.delete.js +22 -0
  79. package/dist/tools/memory.delete.js.map +1 -0
  80. package/dist/tools/memory.recap.d.ts +4 -0
  81. package/dist/tools/memory.recap.d.ts.map +1 -0
  82. package/dist/tools/memory.recap.js +42 -0
  83. package/dist/tools/memory.recap.js.map +1 -0
  84. package/dist/tools/memory.search.d.ts +5 -0
  85. package/dist/tools/memory.search.d.ts.map +1 -0
  86. package/dist/tools/memory.search.js +192 -0
  87. package/dist/tools/memory.search.js.map +1 -0
  88. package/dist/tools/memory.search.test.d.ts +2 -0
  89. package/dist/tools/memory.search.test.d.ts.map +1 -0
  90. package/dist/tools/memory.search.test.js +181 -0
  91. package/dist/tools/memory.search.test.js.map +1 -0
  92. package/dist/tools/memory.store.d.ts +5 -0
  93. package/dist/tools/memory.store.d.ts.map +1 -0
  94. package/dist/tools/memory.store.js +41 -0
  95. package/dist/tools/memory.store.js.map +1 -0
  96. package/dist/tools/memory.summarize.d.ts +4 -0
  97. package/dist/tools/memory.summarize.d.ts.map +1 -0
  98. package/dist/tools/memory.summarize.js +13 -0
  99. package/dist/tools/memory.summarize.js.map +1 -0
  100. package/dist/tools/memory.update.d.ts +5 -0
  101. package/dist/tools/memory.update.d.ts.map +1 -0
  102. package/dist/tools/memory.update.js +31 -0
  103. package/dist/tools/memory.update.js.map +1 -0
  104. package/dist/tools/schemas.d.ts +334 -0
  105. package/dist/tools/schemas.d.ts.map +1 -0
  106. package/dist/tools/schemas.js +251 -0
  107. package/dist/tools/schemas.js.map +1 -0
  108. package/dist/types.d.ts +31 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +3 -0
  111. package/dist/types.js.map +1 -0
  112. package/dist/utils/git-scope.d.ts +8 -0
  113. package/dist/utils/git-scope.d.ts.map +1 -0
  114. package/dist/utils/git-scope.js +38 -0
  115. package/dist/utils/git-scope.js.map +1 -0
  116. package/dist/utils/logger.d.ts +7 -0
  117. package/dist/utils/logger.d.ts.map +1 -0
  118. package/dist/utils/logger.js +40 -0
  119. package/dist/utils/logger.js.map +1 -0
  120. package/dist/utils/logger.test.d.ts +2 -0
  121. package/dist/utils/logger.test.d.ts.map +1 -0
  122. package/dist/utils/logger.test.js +84 -0
  123. package/dist/utils/logger.test.js.map +1 -0
  124. package/dist/utils/mcp-response.d.ts +44 -0
  125. package/dist/utils/mcp-response.d.ts.map +1 -0
  126. package/dist/utils/mcp-response.js +81 -0
  127. package/dist/utils/mcp-response.js.map +1 -0
  128. package/dist/utils/normalize.d.ts +4 -0
  129. package/dist/utils/normalize.d.ts.map +1 -0
  130. package/dist/utils/normalize.js +51 -0
  131. package/dist/utils/normalize.js.map +1 -0
  132. package/dist/utils/normalize.test.d.ts +2 -0
  133. package/dist/utils/normalize.test.d.ts.map +1 -0
  134. package/dist/utils/normalize.test.js +159 -0
  135. package/dist/utils/normalize.test.js.map +1 -0
  136. package/dist/utils/query-expander.d.ts +2 -0
  137. package/dist/utils/query-expander.d.ts.map +1 -0
  138. package/dist/utils/query-expander.js +50 -0
  139. package/dist/utils/query-expander.js.map +1 -0
  140. package/dist/utils/query-expander.test.d.ts +2 -0
  141. package/dist/utils/query-expander.test.d.ts.map +1 -0
  142. package/dist/utils/query-expander.test.js +35 -0
  143. package/dist/utils/query-expander.test.js.map +1 -0
  144. package/docs/PRD.md +199 -0
  145. package/docs/PROMPT-agent.md +139 -0
  146. package/docs/SPEC-git-scope.md +172 -0
  147. package/docs/SPEC-heuristics.md +199 -0
  148. package/docs/SPEC-server.md +243 -0
  149. package/docs/SPEC-skeleton.md +255 -0
  150. package/docs/SPEC-sqlite-schema.md +183 -0
  151. package/docs/SPEC-tool-schema.md +201 -0
  152. package/docs/SPEC-vector-search.md +198 -0
  153. package/docs/TEST-scenarios.md +179 -0
  154. package/package.json +43 -0
  155. package/scripts/update-null-titles-ai.mjs +272 -0
  156. package/scripts/update-titles-batch.mjs +71 -0
  157. package/scripts/update-titles.mjs +66 -0
  158. package/seed-data.mjs +151 -0
  159. package/src/capabilities.ts +22 -0
  160. package/src/dashboard/dashboard.test.ts +546 -0
  161. package/src/dashboard/public/app.js +1187 -0
  162. package/src/dashboard/public/chart.js +0 -0
  163. package/src/dashboard/public/index.html +967 -0
  164. package/src/dashboard/server.ts +347 -0
  165. package/src/mcp/client.test.ts +164 -0
  166. package/src/mcp/client.ts +212 -0
  167. package/src/prompts/registry.ts +89 -0
  168. package/src/resources/index.test.ts +132 -0
  169. package/src/resources/index.ts +113 -0
  170. package/src/router.test.ts +145 -0
  171. package/src/router.ts +80 -0
  172. package/src/server.ts +99 -0
  173. package/src/storage/sqlite.test.ts +504 -0
  174. package/src/storage/sqlite.ts +688 -0
  175. package/src/storage/vectors.stub.ts +101 -0
  176. package/src/tools/memory.delete.ts +37 -0
  177. package/src/tools/memory.recap.ts +61 -0
  178. package/src/tools/memory.search.test.ts +276 -0
  179. package/src/tools/memory.search.ts +244 -0
  180. package/src/tools/memory.store.ts +56 -0
  181. package/src/tools/memory.summarize.ts +23 -0
  182. package/src/tools/memory.update.ts +46 -0
  183. package/src/tools/schemas.ts +261 -0
  184. package/src/types.ts +36 -0
  185. package/src/utils/git-scope.ts +42 -0
  186. package/src/utils/logger.test.ts +125 -0
  187. package/src/utils/logger.ts +53 -0
  188. package/src/utils/mcp-response.ts +116 -0
  189. package/src/utils/normalize.test.ts +203 -0
  190. package/src/utils/normalize.ts +53 -0
  191. package/src/utils/query-expander.test.ts +40 -0
  192. package/src/utils/query-expander.ts +60 -0
  193. package/storage/.gitkeep +5 -0
  194. package/test.sh +48 -0
  195. package/tsconfig.json +21 -0
  196. package/vitest.config.ts +10 -0
@@ -0,0 +1,130 @@
1
+ // Feature: memory-mcp-optimization, Property 16: MCPClient cleanup pending requests
2
+ // Feature: memory-mcp-optimization, Property 17: MCPClient retry count
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import * as fc from "fast-check";
5
+ import { MCPClient } from "./client.js";
6
+ class TestableMCPClient extends MCPClient {
7
+ get pending() {
8
+ return this.pendingRequests;
9
+ }
10
+ injectPending(n) {
11
+ const promises = [];
12
+ for (let i = 0; i < n; i++) {
13
+ const id = 1000 + i;
14
+ const p = new Promise((resolve, reject) => {
15
+ this.pending.set(id, {
16
+ resolve,
17
+ reject,
18
+ });
19
+ });
20
+ promises.push(p);
21
+ }
22
+ return promises;
23
+ }
24
+ }
25
+ describe("Property 16: MCPClient cleanup pending requests saat stop atau timeout", () => {
26
+ it("stop() clears the pending map synchronously", () => {
27
+ const client = new TestableMCPClient();
28
+ const n = 5;
29
+ const promises = client.injectPending(n);
30
+ const rejections = promises.map((p) => p.catch(() => undefined));
31
+ client.stop();
32
+ expect(client.getPendingCount()).toBe(0);
33
+ void Promise.all(rejections);
34
+ });
35
+ it("stop() rejects all pending requests with 'Client stopped'", async () => {
36
+ const client = new TestableMCPClient();
37
+ const n = 5;
38
+ const promises = client.injectPending(n);
39
+ client.stop();
40
+ const results = await Promise.allSettled(promises);
41
+ for (const result of results) {
42
+ expect(result.status).toBe("rejected");
43
+ if (result.status === "rejected") {
44
+ expect(result.reason.message).toBe("Client stopped");
45
+ }
46
+ }
47
+ });
48
+ it("getPendingCount() returns correct count before and after stop()", () => {
49
+ const client = new TestableMCPClient();
50
+ const n = 10;
51
+ const promises = client.injectPending(n);
52
+ const rejections = promises.map((p) => p.catch(() => undefined));
53
+ expect(client.getPendingCount()).toBe(n);
54
+ client.stop();
55
+ expect(client.getPendingCount()).toBe(0);
56
+ void Promise.all(rejections);
57
+ });
58
+ it("property: for any N >= 0, after stop() pendingCount === 0", () => {
59
+ fc.assert(fc.property(fc.integer({ min: 0, max: 20 }), (n) => {
60
+ const client = new TestableMCPClient();
61
+ const promises = client.injectPending(n);
62
+ promises.forEach((p) => p.catch(() => undefined));
63
+ client.stop();
64
+ return client.getPendingCount() === 0;
65
+ }));
66
+ });
67
+ });
68
+ describe("Property 17: MCPClient retry maksimal 3 kali dengan exponential backoff", () => {
69
+ it("retries exactly 3 times (4 total attempts) on timeout before rejecting", async () => {
70
+ vi.useFakeTimers();
71
+ try {
72
+ let callOnceCount = 0;
73
+ const client = new TestableMCPClient();
74
+ client.callOnce = async (_method, _params) => {
75
+ callOnceCount++;
76
+ throw new Error("Request timeout");
77
+ };
78
+ client.process = { stdin: { write: () => true } };
79
+ const retryPromise = client.callWithRetry("test/method", {});
80
+ retryPromise.catch(() => undefined);
81
+ await vi.runAllTimersAsync();
82
+ const result = await retryPromise.catch((e) => e);
83
+ expect(result).toBeInstanceOf(Error);
84
+ expect(result.message).toBe("Request timeout");
85
+ expect(callOnceCount).toBe(4);
86
+ }
87
+ finally {
88
+ vi.useRealTimers();
89
+ }
90
+ });
91
+ it("does not retry on non-timeout errors", async () => {
92
+ vi.useFakeTimers();
93
+ try {
94
+ let callOnceCount = 0;
95
+ const client = new TestableMCPClient();
96
+ client.callOnce = async (_method, _params) => {
97
+ callOnceCount++;
98
+ throw new Error("Some other error");
99
+ };
100
+ client.process = { stdin: { write: () => true } };
101
+ const retryPromise = client.callWithRetry("test/method", {});
102
+ retryPromise.catch(() => undefined);
103
+ await vi.runAllTimersAsync();
104
+ const result = await retryPromise.catch((e) => e);
105
+ expect(result).toBeInstanceOf(Error);
106
+ expect(result.message).toBe("Some other error");
107
+ expect(callOnceCount).toBe(1);
108
+ }
109
+ finally {
110
+ vi.useRealTimers();
111
+ }
112
+ });
113
+ it("property: retry delays follow exponential backoff pattern", () => {
114
+ vi.useFakeTimers();
115
+ try {
116
+ fc.assert(fc.property(fc.constant(null), () => {
117
+ const expectedDelays = [1000, 2000, 4000];
118
+ expect(expectedDelays).toHaveLength(3);
119
+ for (let i = 1; i < expectedDelays.length; i++) {
120
+ expect(expectedDelays[i]).toBe(expectedDelays[i - 1] * 2);
121
+ }
122
+ return true;
123
+ }));
124
+ }
125
+ finally {
126
+ vi.useRealTimers();
127
+ }
128
+ });
129
+ });
130
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/mcp/client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export declare const PROMPTS: {
2
+ "memory-agent-core": {
3
+ name: string;
4
+ description: string;
5
+ arguments: never[];
6
+ messages: {
7
+ role: string;
8
+ content: {
9
+ type: string;
10
+ text: string;
11
+ };
12
+ }[];
13
+ };
14
+ "memory-index-policy": {
15
+ name: string;
16
+ description: string;
17
+ arguments: never[];
18
+ messages: {
19
+ role: string;
20
+ content: {
21
+ type: string;
22
+ text: string;
23
+ };
24
+ }[];
25
+ };
26
+ "tool-usage-guidelines": {
27
+ name: string;
28
+ description: string;
29
+ arguments: never[];
30
+ messages: {
31
+ role: string;
32
+ content: {
33
+ type: string;
34
+ text: string;
35
+ };
36
+ }[];
37
+ };
38
+ };
39
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/prompts/registry.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwFnB,CAAC"}
@@ -0,0 +1,90 @@
1
+ export const PROMPTS = {
2
+ "memory-agent-core": {
3
+ name: "memory-agent-core",
4
+ description: "Core behavioral contract for memory-aware agents",
5
+ arguments: [],
6
+ messages: [
7
+ {
8
+ role: "user",
9
+ content: {
10
+ type: "text",
11
+ text: `You are a coding copilot agent working inside an active software project.
12
+
13
+ Your primary goal is to help write correct, maintainable, and consistent code.
14
+
15
+ You are memory-aware:
16
+ - Stored memory represents durable project knowledge
17
+ - Memory is a source of truth, not a suggestion
18
+ - You must respect stored decisions and constraints
19
+
20
+ Core Behavioral Rules:
21
+ 1. Never contradict stored decisions
22
+ 2. Never repeat known mistakes
23
+ 3. Never invent project rules
24
+ 4. Never use memory from another repository
25
+ 5. If memory conflicts with the user, ask for clarification
26
+
27
+ Memory Usage Policy:
28
+ Before generating code:
29
+ 1. Read project summary (if available)
30
+ 2. Search memory for relevant decisions, mistakes, or patterns
31
+ 3. Use memory ONLY if clearly relevant
32
+ 4. Prefer fewer, stronger memories over many weak ones
33
+
34
+ Auto-Memory Creation Policy:
35
+ You MAY store memory ONLY if:
36
+ - The information affects future behavior
37
+ - The scope (repository) is clear
38
+ - The knowledge is durable
39
+
40
+ Before storing memory:
41
+ - Explain briefly why it should be stored
42
+ - Ask for confirmation if unsure
43
+
44
+ Behave like a trusted senior engineer who remembers past decisions and protects the long-term health of the codebase.`
45
+ }
46
+ }
47
+ ]
48
+ },
49
+ "memory-index-policy": {
50
+ name: "memory-index-policy",
51
+ description: "Enforce strict memory discipline",
52
+ arguments: [],
53
+ messages: [
54
+ {
55
+ role: "user",
56
+ content: {
57
+ type: "text",
58
+ text: `Do not store:
59
+ - Temporary discussions
60
+ - Brainstorming
61
+ - Subjective opinions
62
+
63
+ Only store durable knowledge that affects future behavior.
64
+
65
+ Memory is a commit, not a log.`
66
+ }
67
+ }
68
+ ]
69
+ },
70
+ "tool-usage-guidelines": {
71
+ name: "tool-usage-guidelines",
72
+ description: "Prevent tool abuse",
73
+ arguments: [],
74
+ messages: [
75
+ {
76
+ role: "user",
77
+ content: {
78
+ type: "text",
79
+ text: `Only call memory.store when:
80
+ - The information affects future behavior
81
+ - The scope (repo) is clear
82
+ - The memory will still matter later
83
+
84
+ Better to not store anything than to store bad memory.`
85
+ }
86
+ }
87
+ ]
88
+ }
89
+ };
90
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/prompts/registry.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,mBAAmB,EAAE;QACnB,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,kDAAkD;QAC/D,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sHAiCsG;iBAC7G;aACF;SACF;KACF;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EAAE,kCAAkC;QAC/C,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;;;;;;;+BAOe;iBACtB;aACF;SACF;KACF;IACD,uBAAuB,EAAE;QACvB,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,oBAAoB;QACjC,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;;;;;uDAKuC;iBAC9C;aACF;SACF;KACF;CACF,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { SQLiteStore } from "../storage/sqlite.js";
2
+ export declare function listResources(): {
3
+ resources: {
4
+ uri: string;
5
+ name: string;
6
+ description: string;
7
+ mimeType: string;
8
+ }[];
9
+ };
10
+ export declare function readResource(uri: string, db: SQLiteStore): {
11
+ contents: {
12
+ uri: string;
13
+ mimeType: string;
14
+ text: string;
15
+ }[];
16
+ };
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,wBAAgB,aAAa;;;;;;;EA6B5B;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW;;;;;;EA+ExD"}
@@ -0,0 +1,100 @@
1
+ export function listResources() {
2
+ return {
3
+ resources: [
4
+ {
5
+ uri: "memory://index",
6
+ name: "Memory Index",
7
+ description: "Recent memory entries (metadata only)",
8
+ mimeType: "application/json"
9
+ },
10
+ {
11
+ uri: "memory://summary/{repo}",
12
+ name: "Project Summary",
13
+ description: "Antigravity summary for a repository",
14
+ mimeType: "text/plain"
15
+ },
16
+ {
17
+ uri: "memory://{id}",
18
+ name: "Memory by ID",
19
+ description: "View a specific memory by UUID",
20
+ mimeType: "application/json"
21
+ },
22
+ {
23
+ uri: "memory://{base64_query}",
24
+ name: "Search Memories",
25
+ description: "Search memories by query (base64 encoded)",
26
+ mimeType: "application/json"
27
+ }
28
+ ]
29
+ };
30
+ }
31
+ export function readResource(uri, db) {
32
+ if (uri === "memory://index" || uri.startsWith("memory://index?")) {
33
+ const parsed = new URL(uri.replace("memory://", "http://memory/"));
34
+ const repo = parsed.searchParams.get("repo");
35
+ const entries = repo
36
+ ? db.searchByRepo(repo, { limit: 20 })
37
+ : db.listRecent(20);
38
+ return {
39
+ contents: [
40
+ {
41
+ uri,
42
+ mimeType: "application/json",
43
+ text: JSON.stringify(entries, null, 2)
44
+ }
45
+ ]
46
+ };
47
+ }
48
+ if (uri.startsWith("memory://summary/")) {
49
+ const repo = uri.replace("memory://summary/", "");
50
+ const summary = db.getSummary(repo);
51
+ return {
52
+ contents: [
53
+ {
54
+ uri,
55
+ mimeType: "text/plain",
56
+ text: summary?.summary || "No summary available for this repository"
57
+ }
58
+ ]
59
+ };
60
+ }
61
+ // View memory by ID: memory://{uuid}
62
+ const idMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
63
+ if (idMatch) {
64
+ const id = idMatch[1];
65
+ const entry = db.getById(id);
66
+ if (!entry) {
67
+ throw new Error(`Memory not found: ${id}`);
68
+ }
69
+ return {
70
+ contents: [
71
+ {
72
+ uri,
73
+ mimeType: "application/json",
74
+ text: JSON.stringify(entry)
75
+ }
76
+ ]
77
+ };
78
+ }
79
+ // Search by query: memory://{base64_query}
80
+ if (uri.startsWith("memory://") && !uri.startsWith("memory://index") && !uri.startsWith("memory://summary")) {
81
+ const searchId = uri.replace("memory://", "");
82
+ const query = Buffer.from(searchId, 'base64').toString('utf-8');
83
+ const parsed = new URL(uri.replace("memory://", "http://memory/"));
84
+ const repo = parsed.searchParams.get("repo") || undefined;
85
+ const results = repo
86
+ ? db.searchBySimilarity(query, repo, 10)
87
+ : db.searchBySimilarity(query, "", 10);
88
+ return {
89
+ contents: [
90
+ {
91
+ uri,
92
+ mimeType: "application/json",
93
+ text: JSON.stringify({ query, repo, results })
94
+ }
95
+ ]
96
+ };
97
+ }
98
+ throw new Error(`Unknown resource URI: ${uri}`);
99
+ }
100
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/resources/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,96 @@
1
+ // Feature: memory-mcp-optimization, Property 19: memory://index filter repo
2
+ import { describe, it, expect } from "vitest";
3
+ import * as fc from "fast-check";
4
+ import { SQLiteStore } from "../storage/sqlite.js";
5
+ import { readResource } from "./index.js";
6
+ function makeEntry(id, repo) {
7
+ return {
8
+ id,
9
+ type: "code_fact",
10
+ title: `Memory ${id}`,
11
+ content: `Content for memory ${id} in repo ${repo}`,
12
+ importance: 3,
13
+ scope: { repo },
14
+ created_at: new Date().toISOString(),
15
+ updated_at: new Date().toISOString(),
16
+ hit_count: 0,
17
+ recall_count: 0,
18
+ last_used_at: null,
19
+ expires_at: null,
20
+ };
21
+ }
22
+ describe("readResource memory://index", () => {
23
+ it("returns recent entries when no repo filter", () => {
24
+ const db = new SQLiteStore(":memory:");
25
+ db.insert(makeEntry("id-1", "repo-a"));
26
+ db.insert(makeEntry("id-2", "repo-b"));
27
+ const result = readResource("memory://index", db);
28
+ const entries = JSON.parse(result.contents[0].text);
29
+ expect(entries.length).toBeGreaterThan(0);
30
+ db.close();
31
+ });
32
+ it("returns only entries for the specified repo when ?repo=X is given", () => {
33
+ const db = new SQLiteStore(":memory:");
34
+ db.insert(makeEntry("id-a1", "repo-alpha"));
35
+ db.insert(makeEntry("id-a2", "repo-alpha"));
36
+ db.insert(makeEntry("id-b1", "repo-beta"));
37
+ const result = readResource("memory://index?repo=repo-alpha", db);
38
+ const entries = JSON.parse(result.contents[0].text);
39
+ expect(entries.length).toBeGreaterThan(0);
40
+ for (const entry of entries) {
41
+ expect(entry.scope.repo).toBe("repo-alpha");
42
+ }
43
+ db.close();
44
+ });
45
+ it("returns empty array when repo has no entries", () => {
46
+ const db = new SQLiteStore(":memory:");
47
+ db.insert(makeEntry("id-1", "repo-a"));
48
+ const result = readResource("memory://index?repo=nonexistent", db);
49
+ const entries = JSON.parse(result.contents[0].text);
50
+ expect(entries).toEqual([]);
51
+ db.close();
52
+ });
53
+ /**
54
+ * Property 19: memory://index dengan filter repo mengembalikan subset yang benar
55
+ * Validates: Requirements 19.1, 19.3
56
+ */
57
+ it("Property 19: all returned entries have repo === queried repo", () => {
58
+ fc.assert(fc.property(
59
+ // Generate 2-4 distinct repo names
60
+ fc.uniqueArray(fc.stringMatching(/^[a-z][a-z0-9-]{2,8}$/), { minLength: 2, maxLength: 4 }),
61
+ // Generate 1-5 memories per repo
62
+ fc.integer({ min: 1, max: 5 }), (repos, memoriesPerRepo) => {
63
+ const db = new SQLiteStore(":memory:");
64
+ // Insert memories for each repo
65
+ let counter = 0;
66
+ for (const repo of repos) {
67
+ for (let i = 0; i < memoriesPerRepo; i++) {
68
+ db.insert(makeEntry(`id-${counter++}`, repo));
69
+ }
70
+ }
71
+ // Query with the first repo as filter
72
+ const targetRepo = repos[0];
73
+ const result = readResource(`memory://index?repo=${targetRepo}`, db);
74
+ const entries = JSON.parse(result.contents[0].text);
75
+ // All returned entries must belong to targetRepo
76
+ const allMatch = entries.every((e) => e.scope.repo === targetRepo);
77
+ db.close();
78
+ return allMatch;
79
+ }), { numRuns: 100 });
80
+ });
81
+ it("Property 19 (no filter): returns entries from all repos", () => {
82
+ fc.assert(fc.property(fc.uniqueArray(fc.stringMatching(/^[a-z][a-z0-9-]{2,8}$/), { minLength: 2, maxLength: 3 }), (repos) => {
83
+ const db = new SQLiteStore(":memory:");
84
+ for (const repo of repos) {
85
+ db.insert(makeEntry(`id-${repo}`, repo));
86
+ }
87
+ const result = readResource("memory://index", db);
88
+ const entries = JSON.parse(result.contents[0].text);
89
+ // Without filter, should return entries (listRecent returns id/type/repo)
90
+ expect(entries.length).toBeGreaterThan(0);
91
+ db.close();
92
+ return true;
93
+ }), { numRuns: 100 });
94
+ });
95
+ });
96
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/resources/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { SQLiteStore } from "./storage/sqlite.js";
2
+ import { VectorStore } from "./types.js";
3
+ export declare function createRouter(db: SQLiteStore, vectors: VectorStore): (method: string, params: any) => Promise<any>;
4
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAQzC,wBAAgB,YAAY,CAC1B,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,WAAW,GACnB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAgE/C"}
package/dist/router.js ADDED
@@ -0,0 +1,60 @@
1
+ import { listResources, readResource } from "./resources/index.js";
2
+ import { PROMPTS } from "./prompts/registry.js";
3
+ import { TOOL_DEFINITIONS } from "./tools/schemas.js";
4
+ import { handleMemoryStore } from "./tools/memory.store.js";
5
+ import { handleMemoryUpdate } from "./tools/memory.update.js";
6
+ import { handleMemorySearch } from "./tools/memory.search.js";
7
+ import { handleMemorySummarize } from "./tools/memory.summarize.js";
8
+ import { handleMemoryDelete } from "./tools/memory.delete.js";
9
+ import { handleMemoryRecap } from "./tools/memory.recap.js";
10
+ export function createRouter(db, vectors) {
11
+ async function handleMethod(method, params) {
12
+ switch (method) {
13
+ // ---- tools ----
14
+ case "tools/list":
15
+ return { tools: TOOL_DEFINITIONS };
16
+ case "tools/call":
17
+ return await handleToolCall(params);
18
+ // ---- resources ----
19
+ case "resources/list":
20
+ return listResources();
21
+ case "resources/read":
22
+ return readResource(params?.uri, db);
23
+ // ---- prompts ----
24
+ case "prompts/list":
25
+ return { prompts: Object.values(PROMPTS) };
26
+ case "prompts/get": {
27
+ const prompt = PROMPTS[params?.name];
28
+ if (!prompt) {
29
+ throw new Error(`Unknown prompt: ${params?.name}`);
30
+ }
31
+ return prompt;
32
+ }
33
+ default:
34
+ throw new Error(`Unsupported method: ${method}`);
35
+ }
36
+ }
37
+ async function handleToolCall(params) {
38
+ const { name, arguments: args } = params;
39
+ // Normalize tool naming: accept both dot (memory.store) and hyphen (memory-store)
40
+ const toolName = String(name).replace(/\./g, "-");
41
+ switch (toolName) {
42
+ case "memory-store":
43
+ return await handleMemoryStore(args, db, vectors);
44
+ case "memory-update":
45
+ return await handleMemoryUpdate(args, db, vectors);
46
+ case "memory-recap":
47
+ return await handleMemoryRecap(args, db);
48
+ case "memory-search":
49
+ return await handleMemorySearch(args, db, vectors);
50
+ case "memory-summarize":
51
+ return await handleMemorySummarize(args, db);
52
+ case "memory-delete":
53
+ return await handleMemoryDelete(args, db, vectors);
54
+ default:
55
+ throw new Error(`Unknown tool: ${name}`);
56
+ }
57
+ }
58
+ return handleMethod;
59
+ }
60
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,MAAM,UAAU,YAAY,CAC1B,EAAe,EACf,OAAoB;IAEpB,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,MAAW;QACrD,QAAQ,MAAM,EAAE,CAAC;YACf,kBAAkB;YAClB,KAAK,YAAY;gBACf,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YAErC,KAAK,YAAY;gBACf,OAAO,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;YAEtC,sBAAsB;YACtB,KAAK,gBAAgB;gBACnB,OAAO,aAAa,EAAE,CAAC;YAEzB,KAAK,gBAAgB;gBACnB,OAAO,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAEvC,oBAAoB;YACpB,KAAK,cAAc;gBACjB,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAE7C,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,IAA4B,CAAC,CAAC;gBAC7D,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrD,CAAC;gBACD,OAAO,MAAM,CAAC;YAChB,CAAC;YAED;gBACE,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,KAAK,UAAU,cAAc,CAAC,MAAW;QACvC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;QACzC,kFAAkF;QAClF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAElD,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,cAAc;gBACjB,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YAEpD,KAAK,eAAe;gBAClB,OAAO,MAAM,kBAAkB,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YAErD,KAAK,cAAc;gBACjB,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAE3C,KAAK,eAAe;gBAClB,OAAO,MAAM,kBAAkB,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YAErD,KAAK,kBAAkB;gBACrB,OAAO,MAAM,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAE/C,KAAK,eAAe;gBAClB,OAAO,MAAM,kBAAkB,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YAErD;gBACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=router.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../src/router.test.ts"],"names":[],"mappings":""}