@prmichaelsen/remember-mcp 2.2.1 → 2.3.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 (61) hide show
  1. package/AGENT.md +4 -4
  2. package/CHANGELOG.md +45 -0
  3. package/README.md +43 -3
  4. package/agent/commands/acp.init.md +376 -0
  5. package/agent/commands/acp.proceed.md +311 -0
  6. package/agent/commands/acp.status.md +280 -0
  7. package/agent/commands/acp.version-check-for-updates.md +275 -0
  8. package/agent/commands/acp.version-check.md +190 -0
  9. package/agent/commands/acp.version-update.md +288 -0
  10. package/agent/commands/command.template.md +273 -0
  11. package/agent/design/core-memory-user-profile.md +1253 -0
  12. package/agent/design/ghost-profiles-pseudonymous-identity.md +194 -0
  13. package/agent/design/publish-tools-confirmation-flow.md +922 -0
  14. package/agent/milestones/milestone-10-shared-spaces.md +169 -0
  15. package/agent/progress.yaml +90 -4
  16. package/agent/scripts/install.sh +118 -0
  17. package/agent/scripts/update.sh +22 -10
  18. package/agent/scripts/version.sh +35 -0
  19. package/agent/tasks/task-27-implement-llm-provider-interface.md +51 -0
  20. package/agent/tasks/task-28-implement-llm-provider-factory.md +64 -0
  21. package/agent/tasks/task-29-update-config-for-llm.md +71 -0
  22. package/agent/tasks/task-30-implement-bedrock-provider.md +147 -0
  23. package/agent/tasks/task-31-implement-background-job-service.md +120 -0
  24. package/agent/tasks/task-32-test-llm-provider-integration.md +152 -0
  25. package/agent/tasks/task-34-create-confirmation-token-service.md +191 -0
  26. package/agent/tasks/task-35-create-space-memory-types-schema.md +183 -0
  27. package/agent/tasks/task-36-implement-remember-publish.md +227 -0
  28. package/agent/tasks/task-37-implement-remember-confirm.md +225 -0
  29. package/agent/tasks/task-38-implement-remember-deny.md +161 -0
  30. package/agent/tasks/task-39-implement-remember-search-space.md +188 -0
  31. package/agent/tasks/task-40-implement-remember-query-space.md +193 -0
  32. package/agent/tasks/task-41-configure-firestore-ttl.md +188 -0
  33. package/agent/tasks/task-42-create-tests-shared-spaces.md +216 -0
  34. package/agent/tasks/task-43-update-documentation.md +255 -0
  35. package/dist/llm/types.d.ts +1 -0
  36. package/dist/server-factory.js +914 -1
  37. package/dist/server.js +916 -3
  38. package/dist/services/confirmation-token.service.d.ts +99 -0
  39. package/dist/services/confirmation-token.service.spec.d.ts +5 -0
  40. package/dist/tools/confirm.d.ts +20 -0
  41. package/dist/tools/deny.d.ts +19 -0
  42. package/dist/tools/publish.d.ts +22 -0
  43. package/dist/tools/query-space.d.ts +28 -0
  44. package/dist/tools/search-space.d.ts +29 -0
  45. package/dist/types/space-memory.d.ts +80 -0
  46. package/dist/weaviate/space-schema.d.ts +59 -0
  47. package/dist/weaviate/space-schema.spec.d.ts +5 -0
  48. package/package.json +1 -1
  49. package/src/llm/types.ts +0 -0
  50. package/src/server-factory.ts +33 -0
  51. package/src/server.ts +33 -0
  52. package/src/services/confirmation-token.service.spec.ts +254 -0
  53. package/src/services/confirmation-token.service.ts +232 -0
  54. package/src/tools/confirm.ts +176 -0
  55. package/src/tools/deny.ts +70 -0
  56. package/src/tools/publish.ts +167 -0
  57. package/src/tools/query-space.ts +197 -0
  58. package/src/tools/search-space.ts +189 -0
  59. package/src/types/space-memory.ts +94 -0
  60. package/src/weaviate/space-schema.spec.ts +131 -0
  61. package/src/weaviate/space-schema.ts +275 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * remember_deny tool
3
+ *
4
+ * Generic denial tool for any pending action.
5
+ */
6
+
7
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
8
+ import { confirmationTokenService } from '../services/confirmation-token.service.js';
9
+ import { handleToolError } from '../utils/error-handler.js';
10
+
11
+ /**
12
+ * Tool definition for remember_deny
13
+ */
14
+ export const denyTool: Tool = {
15
+ name: 'remember_deny',
16
+ description: 'Deny a pending action. The request will be marked as denied and the token invalidated. Works for any action that requires confirmation.',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ token: {
21
+ type: 'string',
22
+ description: 'The confirmation token from the action tool',
23
+ },
24
+ },
25
+ required: ['token'],
26
+ },
27
+ };
28
+
29
+ interface DenyArgs {
30
+ token: string;
31
+ }
32
+
33
+ /**
34
+ * Handle remember_deny tool execution
35
+ */
36
+ export async function handleDeny(
37
+ args: DenyArgs,
38
+ userId: string
39
+ ): Promise<string> {
40
+ try {
41
+ const success = await confirmationTokenService.denyRequest(userId, args.token);
42
+
43
+ if (!success) {
44
+ return JSON.stringify(
45
+ {
46
+ success: false,
47
+ error: 'Invalid token',
48
+ message: 'Token not found or already used',
49
+ },
50
+ null,
51
+ 2
52
+ );
53
+ }
54
+
55
+ return JSON.stringify(
56
+ {
57
+ success: true,
58
+ },
59
+ null,
60
+ 2
61
+ );
62
+ } catch (error) {
63
+ handleToolError(error, {
64
+ toolName: 'remember_deny',
65
+ userId,
66
+ operation: 'deny action',
67
+ token: args.token,
68
+ });
69
+ }
70
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * remember_publish tool
3
+ *
4
+ * Generates a confirmation token for publishing a memory to a shared space.
5
+ * This is the first phase of the two-phase publish workflow.
6
+ */
7
+
8
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
+ import { confirmationTokenService } from '../services/confirmation-token.service.js';
10
+ import { getWeaviateClient, getMemoryCollectionName } from '../weaviate/client.js';
11
+ import { isValidSpaceId } from '../weaviate/space-schema.js';
12
+ import { handleToolError } from '../utils/error-handler.js';
13
+ import { SUPPORTED_SPACES } from '../types/space-memory.js';
14
+
15
+ /**
16
+ * Tool definition for remember_publish
17
+ */
18
+ export const publishTool: Tool = {
19
+ name: 'remember_publish',
20
+ description: 'Publish a memory to a shared space (like "The Void"). The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token. Use remember_confirm to execute.',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {
24
+ memory_id: {
25
+ type: 'string',
26
+ description: 'ID of the memory from your personal collection to publish',
27
+ },
28
+ target: {
29
+ type: 'string',
30
+ description: 'Target space to publish to (snake_case ID)',
31
+ enum: SUPPORTED_SPACES,
32
+ default: 'the_void',
33
+ },
34
+ additional_tags: {
35
+ type: 'array',
36
+ items: { type: 'string' },
37
+ description: 'Additional tags for discovery (merged with original tags)',
38
+ default: [],
39
+ },
40
+ },
41
+ required: ['memory_id', 'target'],
42
+ },
43
+ };
44
+
45
+ interface PublishArgs {
46
+ memory_id: string;
47
+ target: string;
48
+ additional_tags?: string[];
49
+ }
50
+
51
+ /**
52
+ * Handle remember_publish tool execution
53
+ */
54
+ export async function handlePublish(
55
+ args: PublishArgs,
56
+ userId: string
57
+ ): Promise<string> {
58
+ try {
59
+ // Validate space ID
60
+ if (!isValidSpaceId(args.target)) {
61
+ return JSON.stringify(
62
+ {
63
+ success: false,
64
+ error: 'Invalid space ID',
65
+ message: `Space "${args.target}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
66
+ context: {
67
+ provided_space: args.target,
68
+ supported_spaces: SUPPORTED_SPACES,
69
+ },
70
+ },
71
+ null,
72
+ 2
73
+ );
74
+ }
75
+
76
+ // Verify memory exists and user owns it
77
+ const weaviateClient = getWeaviateClient();
78
+ const userCollection = weaviateClient.collections.get(
79
+ getMemoryCollectionName(userId)
80
+ );
81
+
82
+ const memory = await userCollection.query.fetchObjectById(args.memory_id);
83
+
84
+ if (!memory) {
85
+ return JSON.stringify(
86
+ {
87
+ success: false,
88
+ error: 'Memory not found',
89
+ message: `No memory found with ID: ${args.memory_id}`,
90
+ context: {
91
+ collection_name: getMemoryCollectionName(userId),
92
+ memory_id: args.memory_id,
93
+ },
94
+ },
95
+ null,
96
+ 2
97
+ );
98
+ }
99
+
100
+ // Verify ownership
101
+ if (memory.properties.user_id !== userId) {
102
+ return JSON.stringify(
103
+ {
104
+ success: false,
105
+ error: 'Permission denied',
106
+ message: 'You can only publish your own memories',
107
+ context: {
108
+ memory_id: args.memory_id,
109
+ memory_owner: memory.properties.user_id,
110
+ requesting_user: userId,
111
+ },
112
+ },
113
+ null,
114
+ 2
115
+ );
116
+ }
117
+
118
+ // Verify it's a memory (not a relationship)
119
+ if (memory.properties.doc_type !== 'memory') {
120
+ return JSON.stringify(
121
+ {
122
+ success: false,
123
+ error: 'Invalid document type',
124
+ message: 'Only memories can be published (not relationships)',
125
+ context: {
126
+ memory_id: args.memory_id,
127
+ doc_type: memory.properties.doc_type,
128
+ },
129
+ },
130
+ null,
131
+ 2
132
+ );
133
+ }
134
+
135
+ // Create payload with only memory_id (content fetched during confirmation)
136
+ const payload = {
137
+ memory_id: args.memory_id,
138
+ additional_tags: args.additional_tags || [],
139
+ };
140
+
141
+ // Generate confirmation token
142
+ const { requestId, token } = await confirmationTokenService.createRequest(
143
+ userId,
144
+ 'publish_memory',
145
+ payload,
146
+ args.target
147
+ );
148
+
149
+ // Return minimal response - agent already knows memory details
150
+ return JSON.stringify(
151
+ {
152
+ success: true,
153
+ token,
154
+ },
155
+ null,
156
+ 2
157
+ );
158
+ } catch (error) {
159
+ handleToolError(error, {
160
+ toolName: 'remember_publish',
161
+ userId,
162
+ operation: 'publish memory',
163
+ memory_id: args.memory_id,
164
+ target: args.target,
165
+ });
166
+ }
167
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * remember_query_space tool
3
+ *
4
+ * RAG-optimized natural language queries for shared spaces.
5
+ * Similar to remember_query_memory but queries space collections.
6
+ */
7
+
8
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
+ import { Filters } from 'weaviate-client';
10
+ import { getWeaviateClient } from '../weaviate/client.js';
11
+ import { ensureSpaceCollection, isValidSpaceId } from '../weaviate/space-schema.js';
12
+ import { SUPPORTED_SPACES } from '../types/space-memory.js';
13
+ import { handleToolError } from '../utils/error-handler.js';
14
+
15
+ /**
16
+ * Tool definition for remember_query_space
17
+ */
18
+ export const querySpaceTool: Tool = {
19
+ name: 'remember_query_space',
20
+ description: 'Ask natural language questions about memories in shared spaces. Works like remember_query_memory but queries shared spaces.',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {
24
+ question: {
25
+ type: 'string',
26
+ description: 'Natural language question',
27
+ },
28
+ space: {
29
+ type: 'string',
30
+ description: 'Which space to query',
31
+ enum: SUPPORTED_SPACES,
32
+ default: 'the_void',
33
+ },
34
+ content_type: {
35
+ type: 'string',
36
+ description: 'Filter by content type',
37
+ },
38
+ tags: {
39
+ type: 'array',
40
+ items: { type: 'string' },
41
+ description: 'Filter by tags',
42
+ },
43
+ min_weight: {
44
+ type: 'number',
45
+ minimum: 0,
46
+ maximum: 1,
47
+ description: 'Minimum weight/significance (0-1)',
48
+ },
49
+ date_from: {
50
+ type: 'string',
51
+ description: 'Filter memories created after this date (ISO 8601)',
52
+ },
53
+ date_to: {
54
+ type: 'string',
55
+ description: 'Filter memories created before this date (ISO 8601)',
56
+ },
57
+ limit: {
58
+ type: 'number',
59
+ default: 10,
60
+ description: 'Maximum number of results',
61
+ },
62
+ format: {
63
+ type: 'string',
64
+ enum: ['detailed', 'compact'],
65
+ default: 'detailed',
66
+ description: 'Output format: detailed (full objects) or compact (text summary)',
67
+ },
68
+ },
69
+ required: ['question', 'space'],
70
+ },
71
+ };
72
+
73
+ interface QuerySpaceArgs {
74
+ question: string;
75
+ space: string;
76
+ content_type?: string;
77
+ tags?: string[];
78
+ min_weight?: number;
79
+ date_from?: string;
80
+ date_to?: string;
81
+ limit?: number;
82
+ format?: 'detailed' | 'compact';
83
+ }
84
+
85
+ /**
86
+ * Handle remember_query_space tool execution
87
+ */
88
+ export async function handleQuerySpace(
89
+ args: QuerySpaceArgs,
90
+ userId: string // May be used for private spaces in future
91
+ ): Promise<string> {
92
+ try {
93
+ // Validate space ID
94
+ if (!isValidSpaceId(args.space)) {
95
+ return JSON.stringify(
96
+ {
97
+ success: false,
98
+ error: 'Invalid space ID',
99
+ message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
100
+ },
101
+ null,
102
+ 2
103
+ );
104
+ }
105
+
106
+ const weaviateClient = getWeaviateClient();
107
+ const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
108
+
109
+ // Build filters
110
+ const filterList: any[] = [];
111
+
112
+ // Filter by space_id
113
+ filterList.push(spaceCollection.filter.byProperty('space_id').equal(args.space));
114
+
115
+ // Filter by doc_type (space_memory)
116
+ filterList.push(spaceCollection.filter.byProperty('doc_type').equal('space_memory'));
117
+
118
+ // Apply content type filter
119
+ if (args.content_type) {
120
+ filterList.push(spaceCollection.filter.byProperty('type').equal(args.content_type));
121
+ }
122
+
123
+ // Apply tags filter
124
+ if (args.tags && args.tags.length > 0) {
125
+ args.tags.forEach(tag => {
126
+ filterList.push(spaceCollection.filter.byProperty('tags').containsAny([tag]));
127
+ });
128
+ }
129
+
130
+ // Apply weight filter
131
+ if (args.min_weight !== undefined) {
132
+ filterList.push(spaceCollection.filter.byProperty('weight').greaterOrEqual(args.min_weight));
133
+ }
134
+
135
+ // Apply date filters
136
+ if (args.date_from) {
137
+ filterList.push(spaceCollection.filter.byProperty('created_at').greaterOrEqual(new Date(args.date_from)));
138
+ }
139
+
140
+ if (args.date_to) {
141
+ filterList.push(spaceCollection.filter.byProperty('created_at').lessOrEqual(new Date(args.date_to)));
142
+ }
143
+
144
+ const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
145
+
146
+ // Execute semantic search using nearText
147
+ const searchResults = await spaceCollection.query.nearText(args.question, {
148
+ limit: args.limit || 10,
149
+ ...(whereFilter && { where: whereFilter }),
150
+ });
151
+
152
+ // Format results based on requested format
153
+ const format = args.format || 'detailed';
154
+
155
+ if (format === 'compact') {
156
+ // Compact format: text summary for LLM context
157
+ const summaries = searchResults.objects.map((obj, idx) => {
158
+ const props = obj.properties;
159
+ return `${idx + 1}. ${props.title || props.content?.substring(0, 100) || 'Untitled'}`;
160
+ });
161
+
162
+ const result = {
163
+ question: args.question,
164
+ space: args.space,
165
+ format: 'compact',
166
+ summary: summaries.join('\n'),
167
+ count: searchResults.objects.length,
168
+ };
169
+
170
+ return JSON.stringify(result, null, 2);
171
+ } else {
172
+ // Detailed format: full objects
173
+ const memories = searchResults.objects.map((obj) => ({
174
+ id: obj.uuid,
175
+ ...obj.properties,
176
+ _distance: obj.metadata?.distance,
177
+ }));
178
+
179
+ const result = {
180
+ question: args.question,
181
+ space: args.space,
182
+ format: 'detailed',
183
+ memories,
184
+ total: memories.length,
185
+ };
186
+
187
+ return JSON.stringify(result, null, 2);
188
+ }
189
+ } catch (error) {
190
+ handleToolError(error, {
191
+ toolName: 'remember_query_space',
192
+ operation: 'query space',
193
+ space: args.space,
194
+ question: args.question,
195
+ });
196
+ }
197
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * remember_search_space tool
3
+ *
4
+ * Search shared spaces to discover memories from other users.
5
+ * Similar to remember_search_memory but searches space collections.
6
+ */
7
+
8
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
+ import { Filters } from 'weaviate-client';
10
+ import { getWeaviateClient } from '../weaviate/client.js';
11
+ import { ensureSpaceCollection, isValidSpaceId } from '../weaviate/space-schema.js';
12
+ import { SUPPORTED_SPACES } from '../types/space-memory.js';
13
+ import { handleToolError } from '../utils/error-handler.js';
14
+ import type { SearchFilters } from '../types/memory.js';
15
+
16
+ /**
17
+ * Tool definition for remember_search_space
18
+ */
19
+ export const searchSpaceTool: Tool = {
20
+ name: 'remember_search_space',
21
+ description: 'Search shared spaces to discover thoughts, ideas, and memories. Works like remember_search_memory but searches shared spaces instead of personal memories.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: {
25
+ query: {
26
+ type: 'string',
27
+ description: 'Search query (semantic + keyword hybrid)',
28
+ },
29
+ space: {
30
+ type: 'string',
31
+ description: 'Which space to search',
32
+ enum: SUPPORTED_SPACES,
33
+ default: 'the_void',
34
+ },
35
+ content_type: {
36
+ type: 'string',
37
+ description: 'Filter by content type',
38
+ },
39
+ tags: {
40
+ type: 'array',
41
+ items: { type: 'string' },
42
+ description: 'Filter by tags (must have all specified tags)',
43
+ },
44
+ min_weight: {
45
+ type: 'number',
46
+ minimum: 0,
47
+ maximum: 1,
48
+ description: 'Minimum weight/significance (0-1)',
49
+ },
50
+ max_weight: {
51
+ type: 'number',
52
+ minimum: 0,
53
+ maximum: 1,
54
+ description: 'Maximum weight/significance (0-1)',
55
+ },
56
+ date_from: {
57
+ type: 'string',
58
+ description: 'Filter memories created after this date (ISO 8601)',
59
+ },
60
+ date_to: {
61
+ type: 'string',
62
+ description: 'Filter memories created before this date (ISO 8601)',
63
+ },
64
+ limit: {
65
+ type: 'number',
66
+ default: 10,
67
+ description: 'Maximum number of results',
68
+ },
69
+ offset: {
70
+ type: 'number',
71
+ default: 0,
72
+ description: 'Offset for pagination',
73
+ },
74
+ },
75
+ required: ['query', 'space'],
76
+ },
77
+ };
78
+
79
+ interface SearchSpaceArgs {
80
+ query: string;
81
+ space: string;
82
+ content_type?: string;
83
+ tags?: string[];
84
+ min_weight?: number;
85
+ max_weight?: number;
86
+ date_from?: string;
87
+ date_to?: string;
88
+ limit?: number;
89
+ offset?: number;
90
+ }
91
+
92
+ /**
93
+ * Handle remember_search_space tool execution
94
+ */
95
+ export async function handleSearchSpace(
96
+ args: SearchSpaceArgs,
97
+ userId: string // May be used for private spaces in future
98
+ ): Promise<string> {
99
+ try {
100
+ // Validate space ID
101
+ if (!isValidSpaceId(args.space)) {
102
+ return JSON.stringify(
103
+ {
104
+ success: false,
105
+ error: 'Invalid space ID',
106
+ message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
107
+ },
108
+ null,
109
+ 2
110
+ );
111
+ }
112
+
113
+ const weaviateClient = getWeaviateClient();
114
+ const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
115
+
116
+ // Build filters for space search
117
+ const filterList: any[] = [];
118
+
119
+ // Filter by space_id
120
+ filterList.push(spaceCollection.filter.byProperty('space_id').equal(args.space));
121
+
122
+ // Filter by doc_type (space_memory)
123
+ filterList.push(spaceCollection.filter.byProperty('doc_type').equal('space_memory'));
124
+
125
+ // Apply content type filter
126
+ if (args.content_type) {
127
+ filterList.push(spaceCollection.filter.byProperty('type').equal(args.content_type));
128
+ }
129
+
130
+ // Apply tags filter
131
+ if (args.tags && args.tags.length > 0) {
132
+ args.tags.forEach(tag => {
133
+ filterList.push(spaceCollection.filter.byProperty('tags').containsAny([tag]));
134
+ });
135
+ }
136
+
137
+ // Apply weight filters
138
+ if (args.min_weight !== undefined) {
139
+ filterList.push(spaceCollection.filter.byProperty('weight').greaterOrEqual(args.min_weight));
140
+ }
141
+
142
+ if (args.max_weight !== undefined) {
143
+ filterList.push(spaceCollection.filter.byProperty('weight').lessOrEqual(args.max_weight));
144
+ }
145
+
146
+ // Apply date filters (convert ISO strings to Date objects)
147
+ if (args.date_from) {
148
+ filterList.push(spaceCollection.filter.byProperty('created_at').greaterOrEqual(new Date(args.date_from)));
149
+ }
150
+
151
+ if (args.date_to) {
152
+ filterList.push(spaceCollection.filter.byProperty('created_at').lessOrEqual(new Date(args.date_to)));
153
+ }
154
+
155
+ const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
156
+
157
+ // Execute hybrid search
158
+ const searchResults = await spaceCollection.query.hybrid(args.query, {
159
+ limit: args.limit || 10,
160
+ offset: args.offset || 0,
161
+ ...(whereFilter && { where: whereFilter }),
162
+ });
163
+
164
+ // Format results
165
+ const memories = searchResults.objects.map((obj) => ({
166
+ id: obj.uuid,
167
+ ...obj.properties,
168
+ _score: obj.metadata?.score,
169
+ }));
170
+
171
+ const result = {
172
+ space: args.space,
173
+ query: args.query,
174
+ memories,
175
+ total: memories.length,
176
+ offset: args.offset || 0,
177
+ limit: args.limit || 10,
178
+ };
179
+
180
+ return JSON.stringify(result, null, 2);
181
+ } catch (error) {
182
+ handleToolError(error, {
183
+ toolName: 'remember_search_space',
184
+ operation: 'search space',
185
+ space: args.space,
186
+ query: args.query,
187
+ });
188
+ }
189
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Space Memory type definitions for remember-mcp
3
+ *
4
+ * Space memories are memories published to shared collections
5
+ * where they can be discovered by other users.
6
+ */
7
+
8
+ import type { Memory, SearchOptions, SearchResult } from './memory.js';
9
+
10
+ /**
11
+ * Space memory - a memory published to a shared space
12
+ *
13
+ * Extends Memory with additional fields for attribution and discovery
14
+ */
15
+ export interface SpaceMemory extends Omit<Memory, 'user_id' | 'doc_type'> {
16
+ /**
17
+ * Space identifier (snake_case)
18
+ * Examples: 'the_void', 'public_space'
19
+ */
20
+ space_id: string;
21
+
22
+ /**
23
+ * Original author's user_id (for permissions)
24
+ * This is private and not shown publicly
25
+ */
26
+ author_id: string;
27
+
28
+ /**
29
+ * Optional ghost profile ID for pseudonymous publishing
30
+ * If present, memory is attributed to ghost instead of user
31
+ */
32
+ ghost_id?: string;
33
+
34
+ /**
35
+ * When the memory was published to the space
36
+ */
37
+ published_at: string;
38
+
39
+ /**
40
+ * How many times this memory has been discovered/viewed
41
+ */
42
+ discovery_count: number;
43
+
44
+ /**
45
+ * Attribution type
46
+ * - 'user': Published as the user (shows author_id)
47
+ * - 'ghost': Published as a ghost (shows ghost_id)
48
+ */
49
+ attribution: 'user' | 'ghost';
50
+
51
+ /**
52
+ * Document type discriminator
53
+ * Always 'space_memory' for space memories
54
+ */
55
+ doc_type: 'space_memory';
56
+ }
57
+
58
+ /**
59
+ * Search options for space memories
60
+ * Same as SearchOptions but for space collections
61
+ */
62
+ export interface SpaceSearchOptions extends Omit<SearchOptions, 'include_relationships'> {
63
+ /**
64
+ * Space to search
65
+ */
66
+ space: string;
67
+ }
68
+
69
+ /**
70
+ * Search result for space memories
71
+ */
72
+ export interface SpaceSearchResult extends Omit<SearchResult, 'memories' | 'relationships'> {
73
+ /**
74
+ * Found space memories
75
+ */
76
+ space_memories: SpaceMemory[];
77
+ }
78
+
79
+ /**
80
+ * Supported space IDs
81
+ */
82
+ export type SpaceId = 'the_void';
83
+
84
+ /**
85
+ * Space display names mapped to IDs
86
+ */
87
+ export const SPACE_DISPLAY_NAMES: Record<SpaceId, string> = {
88
+ the_void: 'The Void',
89
+ };
90
+
91
+ /**
92
+ * Supported spaces constant
93
+ */
94
+ export const SUPPORTED_SPACES: SpaceId[] = ['the_void'];