@synth-coder/memhub 0.2.3 → 0.2.4

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 (143) hide show
  1. package/.eslintrc.cjs +45 -45
  2. package/.factory/commands/opsx-apply.md +150 -150
  3. package/.factory/commands/opsx-archive.md +155 -155
  4. package/.factory/commands/opsx-explore.md +171 -171
  5. package/.factory/commands/opsx-propose.md +104 -104
  6. package/.factory/skills/openspec-apply-change/SKILL.md +156 -156
  7. package/.factory/skills/openspec-archive-change/SKILL.md +114 -114
  8. package/.factory/skills/openspec-explore/SKILL.md +288 -288
  9. package/.factory/skills/openspec-propose/SKILL.md +110 -110
  10. package/.github/workflows/ci.yml +110 -74
  11. package/.github/workflows/release.yml +67 -0
  12. package/.iflow/commands/opsx-apply.md +152 -152
  13. package/.iflow/commands/opsx-archive.md +157 -157
  14. package/.iflow/commands/opsx-explore.md +173 -173
  15. package/.iflow/commands/opsx-propose.md +106 -106
  16. package/.iflow/skills/openspec-apply-change/SKILL.md +156 -156
  17. package/.iflow/skills/openspec-archive-change/SKILL.md +114 -114
  18. package/.iflow/skills/openspec-explore/SKILL.md +288 -288
  19. package/.iflow/skills/openspec-propose/SKILL.md +110 -110
  20. package/.prettierrc +11 -11
  21. package/AGENTS.md +167 -169
  22. package/README.md +276 -195
  23. package/README.zh-CN.md +245 -193
  24. package/dist/src/cli/agents/claude-code.d.ts +5 -0
  25. package/dist/src/cli/agents/claude-code.d.ts.map +1 -0
  26. package/dist/src/cli/agents/claude-code.js +14 -0
  27. package/dist/src/cli/agents/claude-code.js.map +1 -0
  28. package/dist/src/cli/agents/cline.d.ts +5 -0
  29. package/dist/src/cli/agents/cline.d.ts.map +1 -0
  30. package/dist/src/cli/agents/cline.js +14 -0
  31. package/dist/src/cli/agents/cline.js.map +1 -0
  32. package/dist/src/cli/agents/codex.d.ts +5 -0
  33. package/dist/src/cli/agents/codex.d.ts.map +1 -0
  34. package/dist/src/cli/agents/codex.js +14 -0
  35. package/dist/src/cli/agents/codex.js.map +1 -0
  36. package/dist/src/cli/agents/cursor.d.ts +5 -0
  37. package/dist/src/cli/agents/cursor.d.ts.map +1 -0
  38. package/dist/src/cli/agents/cursor.js +14 -0
  39. package/dist/src/cli/agents/cursor.js.map +1 -0
  40. package/dist/src/cli/agents/factory-droid.d.ts +5 -0
  41. package/dist/src/cli/agents/factory-droid.d.ts.map +1 -0
  42. package/dist/src/cli/agents/factory-droid.js +14 -0
  43. package/dist/src/cli/agents/factory-droid.js.map +1 -0
  44. package/dist/src/cli/agents/gemini-cli.d.ts +5 -0
  45. package/dist/src/cli/agents/gemini-cli.d.ts.map +1 -0
  46. package/dist/src/cli/agents/gemini-cli.js +14 -0
  47. package/dist/src/cli/agents/gemini-cli.js.map +1 -0
  48. package/dist/src/cli/agents/index.d.ts +14 -0
  49. package/dist/src/cli/agents/index.d.ts.map +1 -0
  50. package/dist/src/cli/agents/index.js +30 -0
  51. package/dist/src/cli/agents/index.js.map +1 -0
  52. package/dist/src/cli/agents/windsurf.d.ts +5 -0
  53. package/dist/src/cli/agents/windsurf.d.ts.map +1 -0
  54. package/dist/src/cli/agents/windsurf.js +14 -0
  55. package/dist/src/cli/agents/windsurf.js.map +1 -0
  56. package/dist/src/cli/index.d.ts +8 -0
  57. package/dist/src/cli/index.d.ts.map +1 -0
  58. package/dist/src/cli/index.js +168 -0
  59. package/dist/src/cli/index.js.map +1 -0
  60. package/dist/src/cli/init.d.ts +34 -0
  61. package/dist/src/cli/init.d.ts.map +1 -0
  62. package/dist/src/cli/init.js +160 -0
  63. package/dist/src/cli/init.js.map +1 -0
  64. package/dist/src/cli/instructions.d.ts +29 -0
  65. package/dist/src/cli/instructions.d.ts.map +1 -0
  66. package/dist/src/cli/instructions.js +141 -0
  67. package/dist/src/cli/instructions.js.map +1 -0
  68. package/dist/src/cli/types.d.ts +22 -0
  69. package/dist/src/cli/types.d.ts.map +1 -0
  70. package/dist/src/cli/types.js +86 -0
  71. package/dist/src/cli/types.js.map +1 -0
  72. package/dist/src/contracts/mcp.js +34 -34
  73. package/dist/src/contracts/schemas.js.map +1 -1
  74. package/dist/src/server/mcp-server.d.ts.map +1 -1
  75. package/dist/src/server/mcp-server.js +7 -14
  76. package/dist/src/server/mcp-server.js.map +1 -1
  77. package/dist/src/services/embedding-service.d.ts.map +1 -1
  78. package/dist/src/services/embedding-service.js +1 -1
  79. package/dist/src/services/embedding-service.js.map +1 -1
  80. package/dist/src/services/memory-service.d.ts.map +1 -1
  81. package/dist/src/services/memory-service.js.map +1 -1
  82. package/dist/src/storage/markdown-storage.d.ts.map +1 -1
  83. package/dist/src/storage/markdown-storage.js +1 -1
  84. package/dist/src/storage/markdown-storage.js.map +1 -1
  85. package/dist/src/storage/vector-index.d.ts.map +1 -1
  86. package/dist/src/storage/vector-index.js +4 -5
  87. package/dist/src/storage/vector-index.js.map +1 -1
  88. package/docs/README.md +21 -0
  89. package/docs/mcp-tools.md +136 -0
  90. package/docs/user-guide.md +182 -0
  91. package/package.json +61 -59
  92. package/src/cli/agents/claude-code.ts +14 -0
  93. package/src/cli/agents/cline.ts +14 -0
  94. package/src/cli/agents/codex.ts +14 -0
  95. package/src/cli/agents/cursor.ts +14 -0
  96. package/src/cli/agents/factory-droid.ts +14 -0
  97. package/src/cli/agents/gemini-cli.ts +14 -0
  98. package/src/cli/agents/index.ts +36 -0
  99. package/src/cli/agents/windsurf.ts +14 -0
  100. package/src/cli/index.ts +192 -0
  101. package/src/cli/init.ts +218 -0
  102. package/src/cli/instructions.ts +156 -0
  103. package/src/cli/types.ts +112 -0
  104. package/src/contracts/index.ts +12 -12
  105. package/src/contracts/mcp.ts +223 -223
  106. package/src/contracts/schemas.ts +307 -307
  107. package/src/contracts/types.ts +410 -410
  108. package/src/index.ts +8 -8
  109. package/src/server/index.ts +5 -5
  110. package/src/server/mcp-server.ts +169 -186
  111. package/src/services/embedding-service.ts +114 -114
  112. package/src/services/index.ts +5 -5
  113. package/src/services/memory-service.ts +656 -663
  114. package/src/storage/frontmatter-parser.ts +243 -243
  115. package/src/storage/index.ts +6 -6
  116. package/src/storage/markdown-storage.ts +228 -236
  117. package/src/storage/vector-index.ts +159 -160
  118. package/src/utils/index.ts +5 -5
  119. package/src/utils/slugify.ts +63 -63
  120. package/test/cli/init.test.ts +380 -0
  121. package/test/contracts/schemas.test.ts +313 -313
  122. package/test/contracts/types.test.ts +21 -21
  123. package/test/frontmatter-parser-more.test.ts +94 -94
  124. package/test/server/mcp-server.test.ts +211 -210
  125. package/test/services/memory-service-edge.test.ts +248 -248
  126. package/test/services/memory-service.test.ts +291 -279
  127. package/test/storage/frontmatter-parser.test.ts +223 -223
  128. package/test/storage/markdown-storage.test.ts +226 -217
  129. package/test/storage/storage-edge.test.ts +238 -238
  130. package/test/storage/vector-index.test.ts +149 -153
  131. package/test/utils/slugify-edge.test.ts +94 -94
  132. package/test/utils/slugify.test.ts +72 -68
  133. package/tsconfig.json +25 -25
  134. package/tsconfig.test.json +8 -8
  135. package/vitest.config.ts +29 -29
  136. package/docs/architecture-diagrams.md +0 -368
  137. package/docs/architecture.md +0 -381
  138. package/docs/contracts.md +0 -190
  139. package/docs/prompt-template.md +0 -33
  140. package/docs/proposals/mcp-typescript-sdk-refactor.md +0 -568
  141. package/docs/proposals/proposal-close-gates.md +0 -58
  142. package/docs/tool-calling-policy.md +0 -101
  143. package/docs/vector-search.md +0 -306
@@ -1,313 +1,313 @@
1
- /**
2
- * Schema validation tests - RED phase (TDD)
3
- * These tests define the expected behavior of Zod schemas
4
- * They will fail until implementations are written
5
- */
6
-
7
- import { describe, it, expect } from 'vitest';
8
- import {
9
- UUIDSchema,
10
- ISO8601TimestampSchema,
11
- TagSchema,
12
- CategorySchema,
13
- ImportanceSchema,
14
- MemorySchema,
15
- CreateMemoryInputSchema,
16
- ReadMemoryInputSchema,
17
- UpdateMemoryInputSchema,
18
- DeleteMemoryInputSchema,
19
- ListMemoryInputSchema,
20
- SearchMemoryInputSchema,
21
- } from '../../src/contracts/schemas.js';
22
-
23
- describe('Schema Validation', () => {
24
- describe('UUIDSchema', () => {
25
- it('should accept valid UUID v4', () => {
26
- const validUuid = '550e8400-e29b-41d4-a716-446655440000';
27
- expect(UUIDSchema.safeParse(validUuid).success).toBe(true);
28
- });
29
-
30
- it('should reject invalid UUID format', () => {
31
- const invalidUuid = 'not-a-uuid';
32
- expect(UUIDSchema.safeParse(invalidUuid).success).toBe(false);
33
- });
34
-
35
- it('should reject empty string', () => {
36
- expect(UUIDSchema.safeParse('').success).toBe(false);
37
- });
38
- });
39
-
40
- describe('ISO8601TimestampSchema', () => {
41
- it('should accept valid ISO 8601 timestamp', () => {
42
- const validTimestamp = '2024-03-15T10:30:00Z';
43
- expect(ISO8601TimestampSchema.safeParse(validTimestamp).success).toBe(true);
44
- });
45
-
46
- it('should reject invalid timestamp format', () => {
47
- const invalidTimestamp = '2024-03-15';
48
- expect(ISO8601TimestampSchema.safeParse(invalidTimestamp).success).toBe(false);
49
- });
50
-
51
- it('should reject non-ISO date strings', () => {
52
- const nonIsoDate = 'March 15, 2024';
53
- expect(ISO8601TimestampSchema.safeParse(nonIsoDate).success).toBe(false);
54
- });
55
- });
56
-
57
- describe('TagSchema', () => {
58
- it('should accept valid tag with lowercase letters and hyphens', () => {
59
- expect(TagSchema.safeParse('project-management').success).toBe(true);
60
- });
61
-
62
- it('should accept tag with numbers', () => {
63
- expect(TagSchema.safeParse('task-123').success).toBe(true);
64
- });
65
-
66
- it('should reject uppercase letters', () => {
67
- expect(TagSchema.safeParse('Project').success).toBe(false);
68
- });
69
-
70
- it('should reject spaces', () => {
71
- expect(TagSchema.safeParse('project management').success).toBe(false);
72
- });
73
-
74
- it('should reject special characters', () => {
75
- expect(TagSchema.safeParse('project@work').success).toBe(false);
76
- });
77
-
78
- it('should reject empty string', () => {
79
- expect(TagSchema.safeParse('').success).toBe(false);
80
- });
81
-
82
- it('should reject tags over 50 characters', () => {
83
- const longTag = 'a'.repeat(51);
84
- expect(TagSchema.safeParse(longTag).success).toBe(false);
85
- });
86
- });
87
-
88
- describe('CategorySchema', () => {
89
- it('should accept valid category', () => {
90
- expect(CategorySchema.safeParse('work').success).toBe(true);
91
- });
92
-
93
- it('should reject uppercase letters', () => {
94
- expect(CategorySchema.safeParse('Work').success).toBe(false);
95
- });
96
-
97
- it('should reject empty string', () => {
98
- expect(CategorySchema.safeParse('').success).toBe(false);
99
- });
100
- });
101
-
102
- describe('ImportanceSchema', () => {
103
- it('should accept importance level 1', () => {
104
- expect(ImportanceSchema.safeParse(1).success).toBe(true);
105
- });
106
-
107
- it('should accept importance level 5', () => {
108
- expect(ImportanceSchema.safeParse(5).success).toBe(true);
109
- });
110
-
111
- it('should reject level 0', () => {
112
- expect(ImportanceSchema.safeParse(0).success).toBe(false);
113
- });
114
-
115
- it('should reject level 6', () => {
116
- expect(ImportanceSchema.safeParse(6).success).toBe(false);
117
- });
118
-
119
- it('should reject non-integer values', () => {
120
- expect(ImportanceSchema.safeParse(3.5).success).toBe(false);
121
- });
122
- });
123
-
124
- describe('MemorySchema', () => {
125
- const validMemory = {
126
- id: '550e8400-e29b-41d4-a716-446655440000',
127
- createdAt: '2024-03-15T10:30:00Z',
128
- updatedAt: '2024-03-15T10:30:00Z',
129
- tags: ['work', 'project'],
130
- category: 'general',
131
- importance: 3,
132
- title: 'Test Memory',
133
- content: 'This is test content',
134
- };
135
-
136
- it('should accept valid memory object', () => {
137
- expect(MemorySchema.safeParse(validMemory).success).toBe(true);
138
- });
139
-
140
- it('should reject memory with invalid UUID', () => {
141
- const invalid = { ...validMemory, id: 'invalid-uuid' };
142
- expect(MemorySchema.safeParse(invalid).success).toBe(false);
143
- });
144
-
145
- it('should reject memory with invalid timestamp', () => {
146
- const invalid = { ...validMemory, createdAt: 'invalid-date' };
147
- expect(MemorySchema.safeParse(invalid).success).toBe(false);
148
- });
149
-
150
- it('should reject memory with empty title', () => {
151
- const invalid = { ...validMemory, title: '' };
152
- expect(MemorySchema.safeParse(invalid).success).toBe(false);
153
- });
154
-
155
- it('should reject memory with title over 200 characters', () => {
156
- const invalid = { ...validMemory, title: 'a'.repeat(201) };
157
- expect(MemorySchema.safeParse(invalid).success).toBe(false);
158
- });
159
-
160
- it('should reject memory with content over 100000 characters', () => {
161
- const invalid = { ...validMemory, content: 'a'.repeat(100001) };
162
- expect(MemorySchema.safeParse(invalid).success).toBe(false);
163
- });
164
-
165
- it('should reject memory with invalid importance', () => {
166
- const invalid = { ...validMemory, importance: 10 };
167
- expect(MemorySchema.safeParse(invalid).success).toBe(false);
168
- });
169
- });
170
-
171
- describe('CreateMemoryInputSchema', () => {
172
- it('should accept valid create input', () => {
173
- const input = {
174
- title: 'New Memory',
175
- content: 'Content here',
176
- };
177
- expect(CreateMemoryInputSchema.safeParse(input).success).toBe(true);
178
- });
179
-
180
- it('should accept input with optional fields', () => {
181
- const input = {
182
- title: 'New Memory',
183
- content: 'Content here',
184
- tags: ['tag1', 'tag2'],
185
- category: 'work',
186
- importance: 4,
187
- };
188
- expect(CreateMemoryInputSchema.safeParse(input).success).toBe(true);
189
- });
190
-
191
- it('should reject missing title', () => {
192
- const input = { content: 'Content here' };
193
- expect(CreateMemoryInputSchema.safeParse(input).success).toBe(false);
194
- });
195
-
196
- it('should reject missing content', () => {
197
- const input = { title: 'New Memory' };
198
- expect(CreateMemoryInputSchema.safeParse(input).success).toBe(false);
199
- });
200
-
201
- it('should apply default values for optional fields', () => {
202
- const input = {
203
- title: 'New Memory',
204
- content: 'Content here',
205
- };
206
- const result = CreateMemoryInputSchema.parse(input);
207
- expect(result.tags).toEqual([]);
208
- expect(result.category).toBe('general');
209
- expect(result.importance).toBe(3);
210
- });
211
- });
212
-
213
- describe('ReadMemoryInputSchema', () => {
214
- it('should accept valid read input', () => {
215
- const input = { id: '550e8400-e29b-41d4-a716-446655440000' };
216
- expect(ReadMemoryInputSchema.safeParse(input).success).toBe(true);
217
- });
218
-
219
- it('should reject invalid UUID', () => {
220
- const input = { id: 'invalid-uuid' };
221
- expect(ReadMemoryInputSchema.safeParse(input).success).toBe(false);
222
- });
223
- });
224
-
225
- describe('UpdateMemoryInputSchema', () => {
226
- it('should accept valid update input with ID only', () => {
227
- const input = { id: '550e8400-e29b-41d4-a716-446655440000' };
228
- expect(UpdateMemoryInputSchema.safeParse(input).success).toBe(true);
229
- });
230
-
231
- it('should accept update with partial fields', () => {
232
- const input = {
233
- id: '550e8400-e29b-41d4-a716-446655440000',
234
- title: 'Updated Title',
235
- };
236
- expect(UpdateMemoryInputSchema.safeParse(input).success).toBe(true);
237
- });
238
-
239
- it('should reject missing ID', () => {
240
- const input = { title: 'Updated Title' };
241
- expect(UpdateMemoryInputSchema.safeParse(input).success).toBe(false);
242
- });
243
- });
244
-
245
- describe('DeleteMemoryInputSchema', () => {
246
- it('should accept valid delete input', () => {
247
- const input = { id: '550e8400-e29b-41d4-a716-446655440000' };
248
- expect(DeleteMemoryInputSchema.safeParse(input).success).toBe(true);
249
- });
250
-
251
- it('should reject invalid UUID', () => {
252
- const input = { id: 'invalid' };
253
- expect(DeleteMemoryInputSchema.safeParse(input).success).toBe(false);
254
- });
255
- });
256
-
257
- describe('ListMemoryInputSchema', () => {
258
- it('should accept empty list input', () => {
259
- expect(ListMemoryInputSchema.safeParse({}).success).toBe(true);
260
- });
261
-
262
- it('should accept input with all filters', () => {
263
- const input = {
264
- category: 'work',
265
- tags: ['project'],
266
- fromDate: '2024-01-01T00:00:00Z',
267
- toDate: '2024-12-31T23:59:59Z',
268
- limit: 50,
269
- offset: 10,
270
- sortBy: 'createdAt',
271
- sortOrder: 'desc',
272
- };
273
- expect(ListMemoryInputSchema.safeParse(input).success).toBe(true);
274
- });
275
-
276
- it('should reject limit over 100', () => {
277
- const input = { limit: 101 };
278
- expect(ListMemoryInputSchema.safeParse(input).success).toBe(false);
279
- });
280
-
281
- it('should reject negative offset', () => {
282
- const input = { offset: -1 };
283
- expect(ListMemoryInputSchema.safeParse(input).success).toBe(false);
284
- });
285
- });
286
-
287
- describe('SearchMemoryInputSchema', () => {
288
- it('should accept valid search input', () => {
289
- const input = { query: 'search term' };
290
- expect(SearchMemoryInputSchema.safeParse(input).success).toBe(true);
291
- });
292
-
293
- it('should reject empty query', () => {
294
- const input = { query: '' };
295
- expect(SearchMemoryInputSchema.safeParse(input).success).toBe(false);
296
- });
297
-
298
- it('should reject query over 1000 characters', () => {
299
- const input = { query: 'a'.repeat(1001) };
300
- expect(SearchMemoryInputSchema.safeParse(input).success).toBe(false);
301
- });
302
-
303
- it('should accept search with filters', () => {
304
- const input = {
305
- query: 'project',
306
- limit: 20,
307
- category: 'work',
308
- tags: ['important'],
309
- };
310
- expect(SearchMemoryInputSchema.safeParse(input).success).toBe(true);
311
- });
312
- });
313
- });
1
+ /**
2
+ * Schema validation tests - RED phase (TDD)
3
+ * These tests define the expected behavior of Zod schemas
4
+ * They will fail until implementations are written
5
+ */
6
+
7
+ import { describe, it, expect } from 'vitest';
8
+ import {
9
+ UUIDSchema,
10
+ ISO8601TimestampSchema,
11
+ TagSchema,
12
+ CategorySchema,
13
+ ImportanceSchema,
14
+ MemorySchema,
15
+ CreateMemoryInputSchema,
16
+ ReadMemoryInputSchema,
17
+ UpdateMemoryInputSchema,
18
+ DeleteMemoryInputSchema,
19
+ ListMemoryInputSchema,
20
+ SearchMemoryInputSchema,
21
+ } from '../../src/contracts/schemas.js';
22
+
23
+ describe('Schema Validation', () => {
24
+ describe('UUIDSchema', () => {
25
+ it('should accept valid UUID v4', () => {
26
+ const validUuid = '550e8400-e29b-41d4-a716-446655440000';
27
+ expect(UUIDSchema.safeParse(validUuid).success).toBe(true);
28
+ });
29
+
30
+ it('should reject invalid UUID format', () => {
31
+ const invalidUuid = 'not-a-uuid';
32
+ expect(UUIDSchema.safeParse(invalidUuid).success).toBe(false);
33
+ });
34
+
35
+ it('should reject empty string', () => {
36
+ expect(UUIDSchema.safeParse('').success).toBe(false);
37
+ });
38
+ });
39
+
40
+ describe('ISO8601TimestampSchema', () => {
41
+ it('should accept valid ISO 8601 timestamp', () => {
42
+ const validTimestamp = '2024-03-15T10:30:00Z';
43
+ expect(ISO8601TimestampSchema.safeParse(validTimestamp).success).toBe(true);
44
+ });
45
+
46
+ it('should reject invalid timestamp format', () => {
47
+ const invalidTimestamp = '2024-03-15';
48
+ expect(ISO8601TimestampSchema.safeParse(invalidTimestamp).success).toBe(false);
49
+ });
50
+
51
+ it('should reject non-ISO date strings', () => {
52
+ const nonIsoDate = 'March 15, 2024';
53
+ expect(ISO8601TimestampSchema.safeParse(nonIsoDate).success).toBe(false);
54
+ });
55
+ });
56
+
57
+ describe('TagSchema', () => {
58
+ it('should accept valid tag with lowercase letters and hyphens', () => {
59
+ expect(TagSchema.safeParse('project-management').success).toBe(true);
60
+ });
61
+
62
+ it('should accept tag with numbers', () => {
63
+ expect(TagSchema.safeParse('task-123').success).toBe(true);
64
+ });
65
+
66
+ it('should reject uppercase letters', () => {
67
+ expect(TagSchema.safeParse('Project').success).toBe(false);
68
+ });
69
+
70
+ it('should reject spaces', () => {
71
+ expect(TagSchema.safeParse('project management').success).toBe(false);
72
+ });
73
+
74
+ it('should reject special characters', () => {
75
+ expect(TagSchema.safeParse('project@work').success).toBe(false);
76
+ });
77
+
78
+ it('should reject empty string', () => {
79
+ expect(TagSchema.safeParse('').success).toBe(false);
80
+ });
81
+
82
+ it('should reject tags over 50 characters', () => {
83
+ const longTag = 'a'.repeat(51);
84
+ expect(TagSchema.safeParse(longTag).success).toBe(false);
85
+ });
86
+ });
87
+
88
+ describe('CategorySchema', () => {
89
+ it('should accept valid category', () => {
90
+ expect(CategorySchema.safeParse('work').success).toBe(true);
91
+ });
92
+
93
+ it('should reject uppercase letters', () => {
94
+ expect(CategorySchema.safeParse('Work').success).toBe(false);
95
+ });
96
+
97
+ it('should reject empty string', () => {
98
+ expect(CategorySchema.safeParse('').success).toBe(false);
99
+ });
100
+ });
101
+
102
+ describe('ImportanceSchema', () => {
103
+ it('should accept importance level 1', () => {
104
+ expect(ImportanceSchema.safeParse(1).success).toBe(true);
105
+ });
106
+
107
+ it('should accept importance level 5', () => {
108
+ expect(ImportanceSchema.safeParse(5).success).toBe(true);
109
+ });
110
+
111
+ it('should reject level 0', () => {
112
+ expect(ImportanceSchema.safeParse(0).success).toBe(false);
113
+ });
114
+
115
+ it('should reject level 6', () => {
116
+ expect(ImportanceSchema.safeParse(6).success).toBe(false);
117
+ });
118
+
119
+ it('should reject non-integer values', () => {
120
+ expect(ImportanceSchema.safeParse(3.5).success).toBe(false);
121
+ });
122
+ });
123
+
124
+ describe('MemorySchema', () => {
125
+ const validMemory = {
126
+ id: '550e8400-e29b-41d4-a716-446655440000',
127
+ createdAt: '2024-03-15T10:30:00Z',
128
+ updatedAt: '2024-03-15T10:30:00Z',
129
+ tags: ['work', 'project'],
130
+ category: 'general',
131
+ importance: 3,
132
+ title: 'Test Memory',
133
+ content: 'This is test content',
134
+ };
135
+
136
+ it('should accept valid memory object', () => {
137
+ expect(MemorySchema.safeParse(validMemory).success).toBe(true);
138
+ });
139
+
140
+ it('should reject memory with invalid UUID', () => {
141
+ const invalid = { ...validMemory, id: 'invalid-uuid' };
142
+ expect(MemorySchema.safeParse(invalid).success).toBe(false);
143
+ });
144
+
145
+ it('should reject memory with invalid timestamp', () => {
146
+ const invalid = { ...validMemory, createdAt: 'invalid-date' };
147
+ expect(MemorySchema.safeParse(invalid).success).toBe(false);
148
+ });
149
+
150
+ it('should reject memory with empty title', () => {
151
+ const invalid = { ...validMemory, title: '' };
152
+ expect(MemorySchema.safeParse(invalid).success).toBe(false);
153
+ });
154
+
155
+ it('should reject memory with title over 200 characters', () => {
156
+ const invalid = { ...validMemory, title: 'a'.repeat(201) };
157
+ expect(MemorySchema.safeParse(invalid).success).toBe(false);
158
+ });
159
+
160
+ it('should reject memory with content over 100000 characters', () => {
161
+ const invalid = { ...validMemory, content: 'a'.repeat(100001) };
162
+ expect(MemorySchema.safeParse(invalid).success).toBe(false);
163
+ });
164
+
165
+ it('should reject memory with invalid importance', () => {
166
+ const invalid = { ...validMemory, importance: 10 };
167
+ expect(MemorySchema.safeParse(invalid).success).toBe(false);
168
+ });
169
+ });
170
+
171
+ describe('CreateMemoryInputSchema', () => {
172
+ it('should accept valid create input', () => {
173
+ const input = {
174
+ title: 'New Memory',
175
+ content: 'Content here',
176
+ };
177
+ expect(CreateMemoryInputSchema.safeParse(input).success).toBe(true);
178
+ });
179
+
180
+ it('should accept input with optional fields', () => {
181
+ const input = {
182
+ title: 'New Memory',
183
+ content: 'Content here',
184
+ tags: ['tag1', 'tag2'],
185
+ category: 'work',
186
+ importance: 4,
187
+ };
188
+ expect(CreateMemoryInputSchema.safeParse(input).success).toBe(true);
189
+ });
190
+
191
+ it('should reject missing title', () => {
192
+ const input = { content: 'Content here' };
193
+ expect(CreateMemoryInputSchema.safeParse(input).success).toBe(false);
194
+ });
195
+
196
+ it('should reject missing content', () => {
197
+ const input = { title: 'New Memory' };
198
+ expect(CreateMemoryInputSchema.safeParse(input).success).toBe(false);
199
+ });
200
+
201
+ it('should apply default values for optional fields', () => {
202
+ const input = {
203
+ title: 'New Memory',
204
+ content: 'Content here',
205
+ };
206
+ const result = CreateMemoryInputSchema.parse(input);
207
+ expect(result.tags).toEqual([]);
208
+ expect(result.category).toBe('general');
209
+ expect(result.importance).toBe(3);
210
+ });
211
+ });
212
+
213
+ describe('ReadMemoryInputSchema', () => {
214
+ it('should accept valid read input', () => {
215
+ const input = { id: '550e8400-e29b-41d4-a716-446655440000' };
216
+ expect(ReadMemoryInputSchema.safeParse(input).success).toBe(true);
217
+ });
218
+
219
+ it('should reject invalid UUID', () => {
220
+ const input = { id: 'invalid-uuid' };
221
+ expect(ReadMemoryInputSchema.safeParse(input).success).toBe(false);
222
+ });
223
+ });
224
+
225
+ describe('UpdateMemoryInputSchema', () => {
226
+ it('should accept valid update input with ID only', () => {
227
+ const input = { id: '550e8400-e29b-41d4-a716-446655440000' };
228
+ expect(UpdateMemoryInputSchema.safeParse(input).success).toBe(true);
229
+ });
230
+
231
+ it('should accept update with partial fields', () => {
232
+ const input = {
233
+ id: '550e8400-e29b-41d4-a716-446655440000',
234
+ title: 'Updated Title',
235
+ };
236
+ expect(UpdateMemoryInputSchema.safeParse(input).success).toBe(true);
237
+ });
238
+
239
+ it('should reject missing ID', () => {
240
+ const input = { title: 'Updated Title' };
241
+ expect(UpdateMemoryInputSchema.safeParse(input).success).toBe(false);
242
+ });
243
+ });
244
+
245
+ describe('DeleteMemoryInputSchema', () => {
246
+ it('should accept valid delete input', () => {
247
+ const input = { id: '550e8400-e29b-41d4-a716-446655440000' };
248
+ expect(DeleteMemoryInputSchema.safeParse(input).success).toBe(true);
249
+ });
250
+
251
+ it('should reject invalid UUID', () => {
252
+ const input = { id: 'invalid' };
253
+ expect(DeleteMemoryInputSchema.safeParse(input).success).toBe(false);
254
+ });
255
+ });
256
+
257
+ describe('ListMemoryInputSchema', () => {
258
+ it('should accept empty list input', () => {
259
+ expect(ListMemoryInputSchema.safeParse({}).success).toBe(true);
260
+ });
261
+
262
+ it('should accept input with all filters', () => {
263
+ const input = {
264
+ category: 'work',
265
+ tags: ['project'],
266
+ fromDate: '2024-01-01T00:00:00Z',
267
+ toDate: '2024-12-31T23:59:59Z',
268
+ limit: 50,
269
+ offset: 10,
270
+ sortBy: 'createdAt',
271
+ sortOrder: 'desc',
272
+ };
273
+ expect(ListMemoryInputSchema.safeParse(input).success).toBe(true);
274
+ });
275
+
276
+ it('should reject limit over 100', () => {
277
+ const input = { limit: 101 };
278
+ expect(ListMemoryInputSchema.safeParse(input).success).toBe(false);
279
+ });
280
+
281
+ it('should reject negative offset', () => {
282
+ const input = { offset: -1 };
283
+ expect(ListMemoryInputSchema.safeParse(input).success).toBe(false);
284
+ });
285
+ });
286
+
287
+ describe('SearchMemoryInputSchema', () => {
288
+ it('should accept valid search input', () => {
289
+ const input = { query: 'search term' };
290
+ expect(SearchMemoryInputSchema.safeParse(input).success).toBe(true);
291
+ });
292
+
293
+ it('should reject empty query', () => {
294
+ const input = { query: '' };
295
+ expect(SearchMemoryInputSchema.safeParse(input).success).toBe(false);
296
+ });
297
+
298
+ it('should reject query over 1000 characters', () => {
299
+ const input = { query: 'a'.repeat(1001) };
300
+ expect(SearchMemoryInputSchema.safeParse(input).success).toBe(false);
301
+ });
302
+
303
+ it('should accept search with filters', () => {
304
+ const input = {
305
+ query: 'project',
306
+ limit: 20,
307
+ category: 'work',
308
+ tags: ['important'],
309
+ };
310
+ expect(SearchMemoryInputSchema.safeParse(input).success).toBe(true);
311
+ });
312
+ });
313
+ });
@@ -1,21 +1,21 @@
1
- /**
2
- * Types Tests
3
- * Tests for type definitions and error codes
4
- */
5
-
6
- import { describe, it, expect } from 'vitest';
7
- import { ErrorCode } from '../../src/contracts/types.js';
8
-
9
- describe('ErrorCode', () => {
10
- it('should have correct error code values', () => {
11
- expect(ErrorCode.PARSE_ERROR).toBe(-32700);
12
- expect(ErrorCode.INVALID_REQUEST).toBe(-32600);
13
- expect(ErrorCode.METHOD_NOT_FOUND).toBe(-32601);
14
- expect(ErrorCode.INVALID_PARAMS).toBe(-32602);
15
- expect(ErrorCode.INTERNAL_ERROR).toBe(-32603);
16
- expect(ErrorCode.NOT_FOUND).toBe(-32001);
17
- expect(ErrorCode.STORAGE_ERROR).toBe(-32002);
18
- expect(ErrorCode.VALIDATION_ERROR).toBe(-32003);
19
- expect(ErrorCode.DUPLICATE_ERROR).toBe(-32004);
20
- });
21
- });
1
+ /**
2
+ * Types Tests
3
+ * Tests for type definitions and error codes
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest';
7
+ import { ErrorCode } from '../../src/contracts/types.js';
8
+
9
+ describe('ErrorCode', () => {
10
+ it('should have correct error code values', () => {
11
+ expect(ErrorCode.PARSE_ERROR).toBe(-32700);
12
+ expect(ErrorCode.INVALID_REQUEST).toBe(-32600);
13
+ expect(ErrorCode.METHOD_NOT_FOUND).toBe(-32601);
14
+ expect(ErrorCode.INVALID_PARAMS).toBe(-32602);
15
+ expect(ErrorCode.INTERNAL_ERROR).toBe(-32603);
16
+ expect(ErrorCode.NOT_FOUND).toBe(-32001);
17
+ expect(ErrorCode.STORAGE_ERROR).toBe(-32002);
18
+ expect(ErrorCode.VALIDATION_ERROR).toBe(-32003);
19
+ expect(ErrorCode.DUPLICATE_ERROR).toBe(-32004);
20
+ });
21
+ });