@prmichaelsen/remember-mcp 3.13.0 → 3.14.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 (62) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/agent/milestones/milestone-17-remember-core-migration.md +140 -0
  3. package/agent/progress.yaml +123 -6
  4. package/agent/tasks/milestone-17-remember-core-migration/task-193-foundation-setup.md +58 -0
  5. package/agent/tasks/milestone-17-remember-core-migration/task-194-migrate-relationship-tools.md +47 -0
  6. package/agent/tasks/milestone-17-remember-core-migration/task-195-migrate-preference-tools.md +34 -0
  7. package/agent/tasks/milestone-17-remember-core-migration/task-196-migrate-memory-tools.md +46 -0
  8. package/agent/tasks/milestone-17-remember-core-migration/task-197-migrate-space-confirmation-tools.md +49 -0
  9. package/agent/tasks/milestone-17-remember-core-migration/task-198-migrate-space-search-moderate.md +46 -0
  10. package/agent/tasks/milestone-17-remember-core-migration/task-199-migrate-delete-memory.md +43 -0
  11. package/agent/tasks/milestone-17-remember-core-migration/task-200-code-cleanup-verification.md +52 -0
  12. package/dist/core-services.d.ts +25 -0
  13. package/dist/server-factory.js +3208 -3978
  14. package/dist/server.js +3708 -4474
  15. package/dist/tools/confirm-publish-moderation.spec.d.ts +3 -2
  16. package/dist/tools/create-memory.d.ts +1 -1
  17. package/dist/tools/query-space.d.ts +1 -1
  18. package/dist/tools/search-space.d.ts +10 -14
  19. package/jest.config.js +11 -0
  20. package/package.json +3 -1
  21. package/src/core-services.ts +50 -0
  22. package/src/tools/confirm-publish-moderation.spec.ts +120 -176
  23. package/src/tools/confirm.ts +70 -1035
  24. package/src/tools/create-memory.ts +16 -67
  25. package/src/tools/create-relationship.ts +13 -181
  26. package/src/tools/delete-memory.ts +7 -72
  27. package/src/tools/delete-relationship.ts +7 -91
  28. package/src/tools/deny.ts +4 -14
  29. package/src/tools/find-similar.ts +16 -110
  30. package/src/tools/get-preferences.ts +3 -8
  31. package/src/tools/moderate.spec.ts +65 -81
  32. package/src/tools/moderate.ts +18 -121
  33. package/src/tools/publish.ts +7 -204
  34. package/src/tools/query-space.ts +28 -140
  35. package/src/tools/retract.ts +7 -185
  36. package/src/tools/revise.ts +4 -136
  37. package/src/tools/search-relationship.ts +17 -116
  38. package/src/tools/search-space.ts +58 -304
  39. package/src/tools/set-preference.ts +3 -8
  40. package/src/tools/update-memory.ts +22 -190
  41. package/src/tools/update-relationship.ts +16 -90
  42. package/src/v2-smoke.e2e.ts +3 -2
  43. package/dist/collections/composite-ids.d.ts +0 -106
  44. package/dist/collections/core-infrastructure.spec.d.ts +0 -11
  45. package/dist/collections/dot-notation.d.ts +0 -106
  46. package/dist/collections/tracking-arrays.d.ts +0 -176
  47. package/dist/constants/content-types.d.ts +0 -61
  48. package/dist/services/confirmation-token.service.d.ts +0 -99
  49. package/dist/services/confirmation-token.service.spec.d.ts +0 -5
  50. package/dist/services/preferences-database.service.d.ts +0 -22
  51. package/dist/services/space-config.service.d.ts +0 -23
  52. package/dist/services/space-config.service.spec.d.ts +0 -2
  53. package/src/collections/composite-ids.ts +0 -193
  54. package/src/collections/core-infrastructure.spec.ts +0 -353
  55. package/src/collections/dot-notation.ts +0 -212
  56. package/src/collections/tracking-arrays.ts +0 -298
  57. package/src/constants/content-types.ts +0 -490
  58. package/src/services/confirmation-token.service.spec.ts +0 -254
  59. package/src/services/confirmation-token.service.ts +0 -328
  60. package/src/services/preferences-database.service.ts +0 -120
  61. package/src/services/space-config.service.spec.ts +0 -102
  62. package/src/services/space-config.service.ts +0 -79
@@ -1,353 +0,0 @@
1
- /**
2
- * Unit tests for Memory Collection Pattern v2 Core Infrastructure
3
- *
4
- * Tests core functionality of:
5
- * - Dot notation collection utilities
6
- * - Composite ID utilities
7
- * - Tracking array management
8
- * - Schema definitions
9
- */
10
-
11
- import {
12
- CollectionType,
13
- getCollectionName,
14
- parseCollectionName,
15
- validateCollectionName,
16
- isUserCollection,
17
- isSpacesCollection,
18
- isGroupCollection,
19
- } from './dot-notation.js';
20
-
21
- import {
22
- generateCompositeId,
23
- parseCompositeId,
24
- isCompositeId,
25
- validateCompositeId,
26
- } from './composite-ids.js';
27
-
28
- import {
29
- addToSpaceIds,
30
- removeFromSpaceIds,
31
- addToGroupIds,
32
- removeFromGroupIds,
33
- isPublishedToSpace,
34
- isPublishedToGroup,
35
- getPublishedLocations,
36
- isPublished,
37
- getPublishedCount,
38
- initializeTracking,
39
- addMultipleSpaceIds,
40
- addMultipleGroupIds,
41
- type MemoryWithTracking,
42
- } from './tracking-arrays.js';
43
-
44
- import {
45
- createUserCollectionSchema,
46
- createSpaceCollectionSchema,
47
- createGroupCollectionSchema,
48
- getUserCollectionProperties,
49
- getPublishedCollectionProperties,
50
- validateV2CollectionName,
51
- getCollectionType,
52
- extractIdFromCollectionName,
53
- } from '../schema/v2-collections.js';
54
-
55
- // ============================================================================
56
- // Dot Notation Collection Utilities Tests
57
- // ============================================================================
58
-
59
- describe('Dot Notation Collection Utilities', () => {
60
- describe('getCollectionName', () => {
61
- it('should generate user collection name', () => {
62
- expect(getCollectionName(CollectionType.USERS, 'user123')).toBe('Memory_users_user123');
63
- });
64
-
65
- it('should generate spaces collection name', () => {
66
- expect(getCollectionName(CollectionType.SPACES)).toBe('Memory_spaces_public');
67
- });
68
-
69
- it('should generate group collection name', () => {
70
- expect(getCollectionName(CollectionType.GROUPS, 'group456')).toBe('Memory_groups_group456');
71
- });
72
-
73
- it('should throw error for user collection without ID', () => {
74
- expect(() => getCollectionName(CollectionType.USERS)).toThrow('User ID is required');
75
- });
76
-
77
- it('should throw error for ID with invalid characters', () => {
78
- expect(() => getCollectionName(CollectionType.USERS, 'user.123')).toThrow();
79
- });
80
- });
81
-
82
- describe('parseCollectionName', () => {
83
- it('should parse user collection name', () => {
84
- const result = parseCollectionName('Memory_users_user123');
85
- expect(result.type).toBe(CollectionType.USERS);
86
- expect(result.id).toBe('user123');
87
- });
88
-
89
- it('should parse spaces collection name', () => {
90
- const result = parseCollectionName('Memory_spaces_public');
91
- expect(result.type).toBe(CollectionType.SPACES);
92
- expect(result.id).toBeUndefined();
93
- });
94
-
95
- it('should parse group collection name', () => {
96
- const result = parseCollectionName('Memory_groups_group456');
97
- expect(result.type).toBe(CollectionType.GROUPS);
98
- expect(result.id).toBe('group456');
99
- });
100
- });
101
-
102
- describe('Collection type checkers', () => {
103
- it('should identify user collections', () => {
104
- expect(isUserCollection('Memory_users_user123')).toBe(true);
105
- expect(isUserCollection('Memory_spaces_public')).toBe(false);
106
- });
107
-
108
- it('should identify spaces collection', () => {
109
- expect(isSpacesCollection('Memory_spaces_public')).toBe(true);
110
- expect(isSpacesCollection('Memory_users_user123')).toBe(false);
111
- });
112
-
113
- it('should identify group collections', () => {
114
- expect(isGroupCollection('Memory_groups_group456')).toBe(true);
115
- expect(isGroupCollection('Memory_users_user123')).toBe(false);
116
- });
117
- });
118
- });
119
-
120
- // ============================================================================
121
- // Composite ID Utilities Tests
122
- // ============================================================================
123
-
124
- describe('Composite ID Utilities', () => {
125
- describe('generateCompositeId', () => {
126
- it('should generate composite ID', () => {
127
- expect(generateCompositeId('user123', 'my-recipe')).toBe('user123.my-recipe');
128
- });
129
-
130
- it('should throw error for userId with dots', () => {
131
- expect(() => generateCompositeId('user.123', 'recipe')).toThrow('cannot contain dots');
132
- });
133
-
134
- it('should throw error for empty userId', () => {
135
- expect(() => generateCompositeId('', 'recipe')).toThrow('cannot be empty');
136
- });
137
- });
138
-
139
- describe('parseCompositeId', () => {
140
- it('should parse composite ID', () => {
141
- const result = parseCompositeId('user123.my-recipe');
142
- expect(result.userId).toBe('user123');
143
- expect(result.memoryId).toBe('my-recipe');
144
- });
145
-
146
- it('should throw error for invalid format', () => {
147
- expect(() => parseCompositeId('invalid')).toThrow('must be exactly 2 parts');
148
- });
149
- });
150
-
151
- describe('isCompositeId', () => {
152
- it('should identify valid composite IDs', () => {
153
- expect(isCompositeId('user123.my-recipe')).toBe(true);
154
- expect(isCompositeId('simple-id')).toBe(false);
155
- });
156
- });
157
-
158
- describe('validateCompositeId', () => {
159
- it('should validate correct composite IDs', () => {
160
- expect(validateCompositeId('user123.my-recipe')).toBe(true);
161
- });
162
-
163
- it('should throw error for invalid IDs', () => {
164
- expect(() => validateCompositeId('invalid')).toThrow();
165
- });
166
- });
167
- });
168
-
169
- // ============================================================================
170
- // Tracking Array Management Tests
171
- // ============================================================================
172
-
173
- describe('Tracking Array Management', () => {
174
- describe('addToSpaceIds', () => {
175
- it('should add space ID to existing arrays', () => {
176
- const memory: MemoryWithTracking = { space_ids: [], group_ids: [] };
177
- const result = addToSpaceIds(memory, 'cooking');
178
- expect(result.space_ids).toEqual(['cooking']);
179
- });
180
-
181
- it('should not add duplicate space IDs', () => {
182
- const memory: MemoryWithTracking = { space_ids: ['cooking'], group_ids: [] };
183
- const result = addToSpaceIds(memory, 'cooking');
184
- expect(result.space_ids).toEqual(['cooking']);
185
- });
186
-
187
- it('should be immutable', () => {
188
- const memory: MemoryWithTracking = { space_ids: ['cooking'], group_ids: [] };
189
- const result = addToSpaceIds(memory, 'recipes');
190
- expect(memory.space_ids).toEqual(['cooking']); // Original unchanged
191
- expect(result.space_ids).toEqual(['cooking', 'recipes']);
192
- });
193
- });
194
-
195
- describe('removeFromSpaceIds', () => {
196
- it('should remove space ID', () => {
197
- const memory: MemoryWithTracking = { space_ids: ['cooking', 'recipes'], group_ids: [] };
198
- const result = removeFromSpaceIds(memory, 'cooking');
199
- expect(result.space_ids).toEqual(['recipes']);
200
- });
201
- });
202
-
203
- describe('addToGroupIds', () => {
204
- it('should add group ID', () => {
205
- const memory: MemoryWithTracking = { space_ids: [], group_ids: ['family'] };
206
- const result = addToGroupIds(memory, 'friends');
207
- expect(result.group_ids).toEqual(['family', 'friends']);
208
- });
209
- });
210
-
211
- describe('removeFromGroupIds', () => {
212
- it('should remove group ID', () => {
213
- const memory: MemoryWithTracking = { space_ids: [], group_ids: ['family', 'friends'] };
214
- const result = removeFromGroupIds(memory, 'family');
215
- expect(result.group_ids).toEqual(['friends']);
216
- });
217
- });
218
-
219
- describe('Publication checks', () => {
220
- it('should check if published to space', () => {
221
- const memory: MemoryWithTracking = { space_ids: ['cooking'], group_ids: [] };
222
- expect(isPublishedToSpace(memory, 'cooking')).toBe(true);
223
- expect(isPublishedToSpace(memory, 'travel')).toBe(false);
224
- });
225
-
226
- it('should check if published to group', () => {
227
- const memory: MemoryWithTracking = { space_ids: [], group_ids: ['family'] };
228
- expect(isPublishedToGroup(memory, 'family')).toBe(true);
229
- expect(isPublishedToGroup(memory, 'coworkers')).toBe(false);
230
- });
231
-
232
- it('should get publication locations', () => {
233
- const memory: MemoryWithTracking = { space_ids: ['cooking'], group_ids: ['family'] };
234
- const result = getPublishedLocations(memory);
235
- expect(result).toEqual({ spaces: ['cooking'], groups: ['family'] });
236
- });
237
-
238
- it('should check if published anywhere', () => {
239
- const memory1: MemoryWithTracking = { space_ids: ['cooking'], group_ids: [] };
240
- expect(isPublished(memory1)).toBe(true);
241
-
242
- const memory2: MemoryWithTracking = { space_ids: [], group_ids: [] };
243
- expect(isPublished(memory2)).toBe(false);
244
- });
245
-
246
- it('should count publications', () => {
247
- const memory: MemoryWithTracking = { space_ids: ['cooking', 'recipes'], group_ids: ['family'] };
248
- expect(getPublishedCount(memory)).toBe(3);
249
- });
250
- });
251
-
252
- describe('Batch operations', () => {
253
- it('should add multiple space IDs', () => {
254
- const memory: MemoryWithTracking = { space_ids: ['cooking'], group_ids: [] };
255
- const result = addMultipleSpaceIds(memory, ['recipes', 'baking']);
256
- expect(result.space_ids).toEqual(['cooking', 'recipes', 'baking']);
257
- });
258
-
259
- it('should add multiple group IDs', () => {
260
- const memory: MemoryWithTracking = { space_ids: [], group_ids: ['family'] };
261
- const result = addMultipleGroupIds(memory, ['friends', 'coworkers']);
262
- expect(result.group_ids).toEqual(['family', 'friends', 'coworkers']);
263
- });
264
- });
265
-
266
- describe('Utility functions', () => {
267
- it('should initialize tracking arrays', () => {
268
- const memory = { content: 'My recipe' };
269
- const result = initializeTracking(memory);
270
- expect(result.space_ids).toEqual([]);
271
- expect(result.group_ids).toEqual([]);
272
- });
273
- });
274
- });
275
-
276
- // ============================================================================
277
- // Schema Definitions Tests
278
- // ============================================================================
279
-
280
- describe('Schema Definitions', () => {
281
- describe('Schema creation', () => {
282
- it('should create user collection schema', () => {
283
- const schema = createUserCollectionSchema('user123');
284
- expect(schema.name).toBe('Memory_users_user123');
285
- expect(schema.description).toContain('user123');
286
- expect(schema.properties).toBeDefined();
287
- expect(schema.vectorizers).toBeDefined();
288
- });
289
-
290
- it('should create space collection schema', () => {
291
- const schema = createSpaceCollectionSchema();
292
- expect(schema.name).toBe('Memory_spaces_public');
293
- expect(schema.properties).toBeDefined();
294
- });
295
-
296
- it('should create group collection schema', () => {
297
- const schema = createGroupCollectionSchema('group456');
298
- expect(schema.name).toBe('Memory_groups_group456');
299
- expect(schema.properties).toBeDefined();
300
- });
301
- });
302
-
303
- describe('Property lists', () => {
304
- it('should get user collection properties', () => {
305
- const props = getUserCollectionProperties();
306
- expect(props).not.toContain('id'); // 'id' is reserved by Weaviate
307
- expect(props).toContain('content');
308
- expect(props).toContain('space_ids');
309
- expect(props).toContain('group_ids');
310
- });
311
-
312
- it('should get published collection properties', () => {
313
- const props = getPublishedCollectionProperties();
314
- expect(props).not.toContain('id'); // 'id' is reserved by Weaviate
315
- expect(props).toContain('published_at');
316
- expect(props).toContain('author_id');
317
- });
318
- });
319
-
320
- describe('Collection name validation', () => {
321
- it('should validate v2 collection names', () => {
322
- expect(validateV2CollectionName('Memory_users_user123')).toBe(true);
323
- expect(validateV2CollectionName('Memory_spaces_public')).toBe(true);
324
- expect(validateV2CollectionName('Memory_groups_group456')).toBe(true);
325
- });
326
-
327
- it('should reject invalid collection names', () => {
328
- expect(() => validateV2CollectionName('InvalidName')).toThrow('Invalid v2 collection name');
329
- });
330
- });
331
-
332
- describe('Collection type detection', () => {
333
- it('should detect collection types', () => {
334
- expect(getCollectionType('Memory_users_user123')).toBe('users');
335
- expect(getCollectionType('Memory_spaces_public')).toBe('spaces');
336
- expect(getCollectionType('Memory_groups_group456')).toBe('groups');
337
- });
338
- });
339
-
340
- describe('ID extraction', () => {
341
- it('should extract user ID', () => {
342
- expect(extractIdFromCollectionName('Memory_users_user123')).toBe('user123');
343
- });
344
-
345
- it('should extract group ID', () => {
346
- expect(extractIdFromCollectionName('Memory_groups_group456')).toBe('group456');
347
- });
348
-
349
- it('should return null for spaces collection', () => {
350
- expect(extractIdFromCollectionName('Memory_spaces_public')).toBeNull();
351
- });
352
- });
353
- });
@@ -1,212 +0,0 @@
1
- /**
2
- * Dot Notation Collection Utilities
3
- *
4
- * Provides utilities for working with Memory Collection Pattern v2's
5
- * dot notation collection naming scheme.
6
- *
7
- * Collection Types:
8
- * - USERS: Memory_users_{userId} - Private user memories
9
- * - SPACES: Memory_spaces_public - All public space memories
10
- * - GROUPS: Memory_groups_{groupId} - Group memories
11
- */
12
-
13
- /**
14
- * Collection type enum for Memory Collection Pattern v2
15
- */
16
- export enum CollectionType {
17
- USERS = 'USERS',
18
- SPACES = 'SPACES',
19
- GROUPS = 'GROUPS',
20
- }
21
-
22
- /**
23
- * Metadata about a parsed collection
24
- */
25
- export interface CollectionMetadata {
26
- type: CollectionType
27
- id?: string
28
- name: string
29
- }
30
-
31
- /**
32
- * Error thrown when collection name is invalid
33
- */
34
- export class InvalidCollectionNameError extends Error {
35
- constructor(message: string) {
36
- super(message)
37
- this.name = 'InvalidCollectionNameError'
38
- }
39
- }
40
-
41
- /**
42
- * Get the Weaviate collection name for a given type and optional ID
43
- *
44
- * @param type - Collection type (USERS, SPACES, or GROUPS)
45
- * @param id - Optional ID (required for USERS and GROUPS, not used for SPACES)
46
- * @returns Weaviate collection name
47
- *
48
- * @example
49
- * getCollectionName(CollectionType.USERS, 'user123')
50
- * // Returns: 'Memory_users_user123'
51
- *
52
- * @example
53
- * getCollectionName(CollectionType.SPACES)
54
- * // Returns: 'Memory_spaces_public'
55
- *
56
- * @example
57
- * getCollectionName(CollectionType.GROUPS, 'group456')
58
- * // Returns: 'Memory_groups_group456'
59
- */
60
- export function getCollectionName(type: CollectionType, id?: string): string {
61
- switch (type) {
62
- case CollectionType.USERS:
63
- if (!id) {
64
- throw new InvalidCollectionNameError('User ID is required for USERS collection type')
65
- }
66
- if (id.includes('.')) {
67
- throw new InvalidCollectionNameError(`User ID cannot contain dots: ${id}`)
68
- }
69
- return `Memory_users_${id}`
70
-
71
- case CollectionType.SPACES:
72
- // SPACES collection is always public, ID is not used
73
- return 'Memory_spaces_public'
74
-
75
- case CollectionType.GROUPS:
76
- if (!id) {
77
- throw new InvalidCollectionNameError('Group ID is required for GROUPS collection type')
78
- }
79
- if (id.includes('.')) {
80
- throw new InvalidCollectionNameError(`Group ID cannot contain dots: ${id}`)
81
- }
82
- return `Memory_groups_${id}`
83
-
84
- default:
85
- throw new InvalidCollectionNameError(`Unknown collection type: ${type}`)
86
- }
87
- }
88
-
89
- /**
90
- * Parse a collection name into its components
91
- *
92
- * @param name - Weaviate collection name
93
- * @returns Collection metadata with type, optional ID, and name
94
- *
95
- * @example
96
- * parseCollectionName('Memory_users_user123')
97
- * // Returns: { type: CollectionType.USERS, id: 'user123', name: 'Memory_users_user123' }
98
- *
99
- * @example
100
- * parseCollectionName('Memory_spaces_public')
101
- * // Returns: { type: CollectionType.SPACES, id: undefined, name: 'Memory_spaces_public' }
102
- *
103
- * @example
104
- * parseCollectionName('Memory_groups_group456')
105
- * // Returns: { type: CollectionType.GROUPS, id: 'group456', name: 'Memory_groups_group456' }
106
- */
107
- export function parseCollectionName(name: string): CollectionMetadata {
108
- // Match pattern: Memory_{type}_{id} or Memory_{type}_public
109
- const match = name.match(/^Memory_(users|spaces|groups)_(.+)$/)
110
-
111
- if (!match) {
112
- throw new InvalidCollectionNameError(
113
- `Invalid collection name format: ${name}. Expected format: Memory_{type}_{id}`
114
- )
115
- }
116
-
117
- const [, typeStr, idOrPublic] = match
118
-
119
- switch (typeStr) {
120
- case 'users':
121
- return {
122
- type: CollectionType.USERS,
123
- id: idOrPublic,
124
- name,
125
- }
126
-
127
- case 'spaces':
128
- if (idOrPublic !== 'public') {
129
- throw new InvalidCollectionNameError(
130
- `Invalid SPACES collection name: ${name}. Expected: Memory_spaces_public`
131
- )
132
- }
133
- return {
134
- type: CollectionType.SPACES,
135
- id: undefined,
136
- name,
137
- }
138
-
139
- case 'groups':
140
- return {
141
- type: CollectionType.GROUPS,
142
- id: idOrPublic,
143
- name,
144
- }
145
-
146
- default:
147
- throw new InvalidCollectionNameError(`Unknown collection type: ${typeStr}`)
148
- }
149
- }
150
-
151
- /**
152
- * Validate a collection name
153
- *
154
- * @param name - Collection name to validate
155
- * @returns true if valid, false otherwise
156
- *
157
- * @example
158
- * validateCollectionName('Memory_users_user123') // true
159
- * validateCollectionName('Memory_spaces_public') // true
160
- * validateCollectionName('Invalid_name') // false
161
- */
162
- export function validateCollectionName(name: string): boolean {
163
- try {
164
- parseCollectionName(name)
165
- return true
166
- } catch (error) {
167
- if (error instanceof InvalidCollectionNameError) {
168
- return false
169
- }
170
- throw error
171
- }
172
- }
173
-
174
- /**
175
- * Check if a collection name is a user collection
176
- *
177
- * @param name - Collection name to check
178
- * @returns true if user collection, false otherwise
179
- */
180
- export function isUserCollection(name: string): boolean {
181
- try {
182
- const metadata = parseCollectionName(name)
183
- return metadata.type === CollectionType.USERS
184
- } catch {
185
- return false
186
- }
187
- }
188
-
189
- /**
190
- * Check if a collection name is the spaces collection
191
- *
192
- * @param name - Collection name to check
193
- * @returns true if spaces collection, false otherwise
194
- */
195
- export function isSpacesCollection(name: string): boolean {
196
- return name === 'Memory_spaces_public'
197
- }
198
-
199
- /**
200
- * Check if a collection name is a group collection
201
- *
202
- * @param name - Collection name to check
203
- * @returns true if group collection, false otherwise
204
- */
205
- export function isGroupCollection(name: string): boolean {
206
- try {
207
- const metadata = parseCollectionName(name)
208
- return metadata.type === CollectionType.GROUPS
209
- } catch {
210
- return false
211
- }
212
- }