@prmichaelsen/remember-mcp 3.0.0 → 3.12.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 (208) hide show
  1. package/AGENT.md +296 -250
  2. package/CHANGELOG.md +338 -0
  3. package/README.md +68 -45
  4. package/agent/commands/acp.clarification-create.md +382 -0
  5. package/agent/commands/acp.project-info.md +309 -0
  6. package/agent/commands/acp.project-remove.md +379 -0
  7. package/agent/commands/acp.project-update.md +296 -0
  8. package/agent/commands/acp.task-create.md +17 -9
  9. package/agent/commands/git.commit.md +13 -1
  10. package/agent/design/comment-memory-type.md +2 -2
  11. package/agent/design/local.collaborative-memory-sync.md +265 -0
  12. package/agent/design/local.content-flags.md +210 -0
  13. package/agent/design/local.ghost-persona-system.md +273 -0
  14. package/agent/design/local.group-acl-integration.md +338 -0
  15. package/agent/design/local.memory-acl-schema.md +352 -0
  16. package/agent/design/local.memory-collection-pattern-v2.md +348 -0
  17. package/agent/design/local.moderation-and-space-config.md +257 -0
  18. package/agent/design/local.v2-api-reference.md +621 -0
  19. package/agent/design/local.v2-migration-guide.md +191 -0
  20. package/agent/design/local.v2-usage-examples.md +265 -0
  21. package/agent/design/permissions-storage-architecture.md +11 -3
  22. package/agent/design/trust-escalation-prevention.md +9 -2
  23. package/agent/design/trust-system-implementation.md +12 -3
  24. package/agent/milestones/milestone-14-memory-collection-v2.md +182 -0
  25. package/agent/milestones/milestone-15-moderation-space-config.md +126 -0
  26. package/agent/progress.yaml +628 -49
  27. package/agent/scripts/acp.common.sh +2 -0
  28. package/agent/scripts/acp.install.sh +11 -1
  29. package/agent/scripts/acp.package-install-optimized.sh +454 -0
  30. package/agent/scripts/acp.package-install.sh +247 -300
  31. package/agent/scripts/acp.project-info.sh +218 -0
  32. package/agent/scripts/acp.project-remove.sh +302 -0
  33. package/agent/scripts/acp.project-update.sh +296 -0
  34. package/agent/scripts/acp.yaml-parser.sh +128 -10
  35. package/agent/tasks/milestone-14-memory-collection-v2/task-165-core-infrastructure-setup.md +171 -0
  36. package/agent/tasks/milestone-14-memory-collection-v2/task-166-update-remember-publish.md +191 -0
  37. package/agent/tasks/milestone-14-memory-collection-v2/task-167-update-remember-retract.md +186 -0
  38. package/agent/tasks/milestone-14-memory-collection-v2/task-168-implement-remember-revise.md +184 -0
  39. package/agent/tasks/milestone-14-memory-collection-v2/task-169-update-remember-search-space.md +179 -0
  40. package/agent/tasks/milestone-14-memory-collection-v2/task-170-update-remember-create-update.md +139 -0
  41. package/agent/tasks/milestone-14-memory-collection-v2/task-172-performance-testing-optimization.md +161 -0
  42. package/agent/tasks/milestone-14-memory-collection-v2/task-173-documentation-examples.md +258 -0
  43. package/agent/tasks/milestone-15-moderation-space-config/task-174-add-moderation-schema-fields.md +57 -0
  44. package/agent/tasks/milestone-15-moderation-space-config/task-175-create-space-config-service.md +64 -0
  45. package/agent/tasks/milestone-15-moderation-space-config/task-176-wire-moderation-publish-flow.md +45 -0
  46. package/agent/tasks/milestone-15-moderation-space-config/task-177-add-moderation-search-filters.md +70 -0
  47. package/agent/tasks/milestone-15-moderation-space-config/task-178-create-remember-moderate-tool.md +69 -0
  48. package/agent/tasks/milestone-15-moderation-space-config/task-179-documentation-integration-tests.md +58 -0
  49. package/agent/tasks/milestone-16-ghost-system/task-187-ghost-config-firestore.md +41 -0
  50. package/agent/tasks/milestone-16-ghost-system/task-188-trust-filter-integration.md +44 -0
  51. package/agent/tasks/milestone-16-ghost-system/task-189-ghost-memory-filtering.md +43 -0
  52. package/agent/tasks/milestone-16-ghost-system/task-190-ghost-config-tools.md +45 -0
  53. package/agent/tasks/milestone-16-ghost-system/task-191-escalation-firestore.md +38 -0
  54. package/agent/tasks/milestone-16-ghost-system/task-192-documentation-verification.md +39 -0
  55. package/agent/tasks/milestone-7-trust-permissions/task-180-access-result-permission-types.md +69 -0
  56. package/agent/tasks/milestone-7-trust-permissions/task-181-firestore-permissions-access-logs.md +56 -0
  57. package/agent/tasks/milestone-7-trust-permissions/task-182-trust-enforcement-service.md +68 -0
  58. package/agent/tasks/milestone-7-trust-permissions/task-183-access-control-service.md +70 -0
  59. package/agent/tasks/milestone-7-trust-permissions/task-184-permission-tools.md +79 -0
  60. package/agent/tasks/milestone-7-trust-permissions/task-185-wire-trust-into-search-query.md +55 -0
  61. package/agent/tasks/milestone-7-trust-permissions/task-186-documentation-verification.md +56 -0
  62. package/agent/tasks/task-76-fix-indexnullstate-schema-bug.md +197 -0
  63. package/dist/collections/composite-ids.d.ts +106 -0
  64. package/dist/collections/core-infrastructure.spec.d.ts +11 -0
  65. package/dist/collections/dot-notation.d.ts +106 -0
  66. package/dist/collections/tracking-arrays.d.ts +176 -0
  67. package/dist/constants/content-types.d.ts +1 -0
  68. package/dist/schema/v2-collections-comments.spec.d.ts +8 -0
  69. package/dist/schema/v2-collections.d.ts +210 -0
  70. package/dist/server-factory.d.ts +15 -0
  71. package/dist/server-factory.js +2798 -1029
  72. package/dist/server.js +2526 -1012
  73. package/dist/services/access-control.d.ts +103 -0
  74. package/dist/services/access-control.spec.d.ts +2 -0
  75. package/dist/services/credentials-provider.d.ts +24 -0
  76. package/dist/services/credentials-provider.spec.d.ts +2 -0
  77. package/dist/services/escalation.service.d.ts +22 -0
  78. package/dist/services/escalation.service.spec.d.ts +2 -0
  79. package/dist/services/ghost-config.service.d.ts +55 -0
  80. package/dist/services/ghost-config.service.spec.d.ts +2 -0
  81. package/dist/services/space-config.service.d.ts +23 -0
  82. package/dist/services/space-config.service.spec.d.ts +2 -0
  83. package/dist/services/trust-enforcement.d.ts +83 -0
  84. package/dist/services/trust-enforcement.spec.d.ts +2 -0
  85. package/dist/services/trust-validator.d.ts +43 -0
  86. package/dist/services/trust-validator.spec.d.ts +2 -0
  87. package/dist/tools/confirm-publish-moderation.spec.d.ts +8 -0
  88. package/dist/tools/confirm.d.ts +8 -1
  89. package/dist/tools/create-memory.d.ts +2 -1
  90. package/dist/tools/create-memory.spec.d.ts +10 -0
  91. package/dist/tools/create-relationship.d.ts +2 -1
  92. package/dist/tools/delete-memory.d.ts +2 -1
  93. package/dist/tools/delete-relationship.d.ts +2 -1
  94. package/dist/tools/deny.d.ts +2 -1
  95. package/dist/tools/find-similar.d.ts +2 -1
  96. package/dist/tools/get-preferences.d.ts +2 -1
  97. package/dist/tools/ghost-config.d.ts +27 -0
  98. package/dist/tools/ghost-config.spec.d.ts +2 -0
  99. package/dist/tools/moderate.d.ts +20 -0
  100. package/dist/tools/moderate.spec.d.ts +5 -0
  101. package/dist/tools/publish.d.ts +11 -3
  102. package/dist/tools/query-memory.d.ts +3 -1
  103. package/dist/tools/query-space.d.ts +4 -1
  104. package/dist/tools/retract.d.ts +29 -0
  105. package/dist/tools/revise.d.ts +45 -0
  106. package/dist/tools/revise.spec.d.ts +8 -0
  107. package/dist/tools/search-memory.d.ts +2 -1
  108. package/dist/tools/search-relationship.d.ts +2 -1
  109. package/dist/tools/search-space.d.ts +25 -5
  110. package/dist/tools/search-space.spec.d.ts +9 -0
  111. package/dist/tools/set-preference.d.ts +2 -1
  112. package/dist/tools/update-memory.d.ts +2 -1
  113. package/dist/tools/update-relationship.d.ts +2 -1
  114. package/dist/types/access-result.d.ts +48 -0
  115. package/dist/types/access-result.spec.d.ts +2 -0
  116. package/dist/types/auth.d.ts +46 -0
  117. package/dist/types/ghost-config.d.ts +36 -0
  118. package/dist/types/memory.d.ts +3 -1
  119. package/dist/types/preferences.d.ts +1 -1
  120. package/dist/utils/auth-helpers.d.ts +14 -0
  121. package/dist/utils/auth-helpers.spec.d.ts +2 -0
  122. package/dist/utils/test-data-generator.d.ts +124 -0
  123. package/dist/utils/test-data-generator.spec.d.ts +12 -0
  124. package/dist/v2-performance.e2e.d.ts +17 -0
  125. package/dist/v2-smoke.e2e.d.ts +14 -0
  126. package/dist/weaviate/client.d.ts +5 -8
  127. package/dist/weaviate/space-schema.d.ts +2 -2
  128. package/docs/performance/v2-benchmarks.md +80 -0
  129. package/jest.e2e.config.js +14 -3
  130. package/package.json +1 -1
  131. package/scripts/.collection-recreation-state.yaml +16 -0
  132. package/scripts/.gitkeep +5 -0
  133. package/scripts/README-collection-recreation.md +224 -0
  134. package/scripts/README.md +51 -0
  135. package/scripts/backup-collections.ts +543 -0
  136. package/scripts/delete-collection.ts +137 -0
  137. package/scripts/migrate-recreate-collections.ts +578 -0
  138. package/scripts/migrate-v1-to-v2.ts +1094 -0
  139. package/scripts/package-lock.json +1113 -0
  140. package/scripts/package.json +27 -0
  141. package/src/collections/composite-ids.ts +193 -0
  142. package/src/collections/core-infrastructure.spec.ts +353 -0
  143. package/src/collections/dot-notation.ts +212 -0
  144. package/src/collections/tracking-arrays.ts +298 -0
  145. package/src/constants/content-types.ts +20 -0
  146. package/src/schema/v2-collections-comments.spec.ts +141 -0
  147. package/src/schema/v2-collections.ts +433 -0
  148. package/src/server-factory.ts +89 -20
  149. package/src/server.ts +45 -17
  150. package/src/services/access-control.spec.ts +383 -0
  151. package/src/services/access-control.ts +291 -0
  152. package/src/services/credentials-provider.spec.ts +22 -0
  153. package/src/services/credentials-provider.ts +34 -0
  154. package/src/services/escalation.service.spec.ts +183 -0
  155. package/src/services/escalation.service.ts +150 -0
  156. package/src/services/ghost-config.service.spec.ts +339 -0
  157. package/src/services/ghost-config.service.ts +219 -0
  158. package/src/services/space-config.service.spec.ts +102 -0
  159. package/src/services/space-config.service.ts +79 -0
  160. package/src/services/trust-enforcement.spec.ts +309 -0
  161. package/src/services/trust-enforcement.ts +197 -0
  162. package/src/services/trust-validator.spec.ts +108 -0
  163. package/src/services/trust-validator.ts +105 -0
  164. package/src/tools/confirm-publish-moderation.spec.ts +240 -0
  165. package/src/tools/confirm.ts +869 -135
  166. package/src/tools/create-memory.spec.ts +126 -0
  167. package/src/tools/create-memory.ts +20 -27
  168. package/src/tools/create-relationship.ts +17 -8
  169. package/src/tools/delete-memory.ts +13 -6
  170. package/src/tools/delete-relationship.ts +15 -6
  171. package/src/tools/deny.ts +8 -1
  172. package/src/tools/find-similar.ts +21 -8
  173. package/src/tools/get-preferences.ts +10 -1
  174. package/src/tools/ghost-config.spec.ts +180 -0
  175. package/src/tools/ghost-config.ts +230 -0
  176. package/src/tools/moderate.spec.ts +277 -0
  177. package/src/tools/moderate.ts +219 -0
  178. package/src/tools/publish.ts +99 -41
  179. package/src/tools/query-memory.ts +28 -6
  180. package/src/tools/query-space.ts +39 -4
  181. package/src/tools/retract.ts +292 -0
  182. package/src/tools/revise.spec.ts +146 -0
  183. package/src/tools/revise.ts +283 -0
  184. package/src/tools/search-memory.ts +30 -7
  185. package/src/tools/search-relationship.ts +11 -2
  186. package/src/tools/search-space.spec.ts +341 -0
  187. package/src/tools/search-space.ts +323 -99
  188. package/src/tools/set-preference.ts +10 -1
  189. package/src/tools/update-memory.ts +16 -5
  190. package/src/tools/update-relationship.ts +10 -1
  191. package/src/types/access-result.spec.ts +193 -0
  192. package/src/types/access-result.ts +62 -0
  193. package/src/types/auth.ts +52 -0
  194. package/src/types/ghost-config.ts +46 -0
  195. package/src/types/memory.ts +9 -1
  196. package/src/types/preferences.ts +2 -2
  197. package/src/utils/auth-helpers.spec.ts +75 -0
  198. package/src/utils/auth-helpers.ts +25 -0
  199. package/src/utils/test-data-generator.spec.ts +317 -0
  200. package/src/utils/test-data-generator.ts +292 -0
  201. package/src/utils/weaviate-filters.ts +4 -4
  202. package/src/v2-performance.e2e.ts +173 -0
  203. package/src/v2-smoke.e2e.ts +401 -0
  204. package/src/weaviate/client.spec.ts +5 -5
  205. package/src/weaviate/client.ts +51 -36
  206. package/src/weaviate/schema.ts +11 -256
  207. package/src/weaviate/space-schema.spec.ts +24 -24
  208. package/src/weaviate/space-schema.ts +18 -6
@@ -0,0 +1,219 @@
1
+ /**
2
+ * remember_moderate tool
3
+ *
4
+ * Allows moderators to approve, reject, or remove published memories
5
+ * in spaces and groups. Requires can_moderate permission.
6
+ */
7
+
8
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
+ import { getWeaviateClient, fetchMemoryWithAllProperties } from '../weaviate/client.js';
10
+ import { ensurePublicCollection } from '../weaviate/space-schema.js';
11
+ import { handleToolError } from '../utils/error-handler.js';
12
+ import { createDebugLogger } from '../utils/debug.js';
13
+ import { logger } from '../utils/logger.js';
14
+ import { CollectionType, getCollectionName } from '../collections/dot-notation.js';
15
+ import type { AuthContext } from '../types/auth.js';
16
+ import { canModerate, canModerateAny } from '../utils/auth-helpers.js';
17
+
18
+ type ModerationAction = 'approve' | 'reject' | 'remove';
19
+
20
+ const ACTION_TO_STATUS: Record<ModerationAction, string> = {
21
+ approve: 'approved',
22
+ reject: 'rejected',
23
+ remove: 'removed',
24
+ };
25
+
26
+ export const moderateTool: Tool = {
27
+ name: 'remember_moderate',
28
+ description: `Approve, reject, or remove a published memory. Requires moderator permissions (can_moderate).
29
+
30
+ Actions:
31
+ - approve: Mark a pending memory as approved (visible in default searches)
32
+ - reject: Reject a pending memory (hidden from default searches)
33
+ - remove: Remove a previously approved memory (hidden from default searches)
34
+
35
+ Must specify either space_id or group_id to identify where the memory is published.`,
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ memory_id: {
40
+ type: 'string',
41
+ description: 'UUID or composite ID of the published memory',
42
+ },
43
+ space_id: {
44
+ type: 'string',
45
+ description: 'Space containing the memory (searches Memory_spaces_public filtered by space_ids)',
46
+ },
47
+ group_id: {
48
+ type: 'string',
49
+ description: 'Group containing the memory (searches Memory_groups_{groupId})',
50
+ },
51
+ action: {
52
+ type: 'string',
53
+ enum: ['approve', 'reject', 'remove'],
54
+ description: 'Moderation action to perform',
55
+ },
56
+ reason: {
57
+ type: 'string',
58
+ description: 'Optional reason for the moderation action',
59
+ },
60
+ },
61
+ required: ['memory_id', 'action'],
62
+ },
63
+ };
64
+
65
+ interface ModerateArgs {
66
+ memory_id: string;
67
+ space_id?: string;
68
+ group_id?: string;
69
+ action: ModerationAction;
70
+ reason?: string;
71
+ }
72
+
73
+ export async function handleModerate(
74
+ args: ModerateArgs,
75
+ userId: string,
76
+ authContext?: AuthContext
77
+ ): Promise<string> {
78
+ const debug = createDebugLogger({
79
+ tool: 'remember_moderate',
80
+ userId,
81
+ operation: 'moderate',
82
+ });
83
+
84
+ try {
85
+ debug.info('Tool invoked');
86
+ debug.trace('Arguments', { args });
87
+
88
+ const { memory_id, space_id, group_id, action, reason } = args;
89
+
90
+ // Validate: must specify either space_id or group_id
91
+ if (!space_id && !group_id) {
92
+ return JSON.stringify(
93
+ {
94
+ success: false,
95
+ error: 'Missing destination',
96
+ message: 'Must specify either space_id or group_id',
97
+ },
98
+ null,
99
+ 2
100
+ );
101
+ }
102
+
103
+ // Validate action
104
+ if (!ACTION_TO_STATUS[action]) {
105
+ return JSON.stringify(
106
+ {
107
+ success: false,
108
+ error: 'Invalid action',
109
+ message: `Action must be one of: approve, reject, remove`,
110
+ },
111
+ null,
112
+ 2
113
+ );
114
+ }
115
+
116
+ // Permission check
117
+ if (group_id) {
118
+ if (!canModerate(authContext, group_id)) {
119
+ return JSON.stringify(
120
+ {
121
+ success: false,
122
+ error: 'Permission denied',
123
+ message: `Moderator access required for group ${group_id}`,
124
+ },
125
+ null,
126
+ 2
127
+ );
128
+ }
129
+ } else if (space_id) {
130
+ if (!canModerateAny(authContext)) {
131
+ return JSON.stringify(
132
+ {
133
+ success: false,
134
+ error: 'Permission denied',
135
+ message: `Moderator access required to moderate memories in spaces`,
136
+ },
137
+ null,
138
+ 2
139
+ );
140
+ }
141
+ }
142
+
143
+ // Get the collection
144
+ const weaviateClient = getWeaviateClient();
145
+ let collection: any;
146
+
147
+ if (group_id) {
148
+ const collectionName = getCollectionName(CollectionType.GROUPS, group_id);
149
+ collection = weaviateClient.collections.get(collectionName);
150
+ } else {
151
+ collection = await ensurePublicCollection(weaviateClient);
152
+ }
153
+
154
+ // Fetch the memory
155
+ const memory = await fetchMemoryWithAllProperties(collection, memory_id);
156
+
157
+ if (!memory) {
158
+ return JSON.stringify(
159
+ {
160
+ success: false,
161
+ error: 'Memory not found',
162
+ message: `Published memory ${memory_id} not found in ${group_id ? `group ${group_id}` : `space ${space_id}`}`,
163
+ },
164
+ null,
165
+ 2
166
+ );
167
+ }
168
+
169
+ // Update moderation fields
170
+ const newStatus = ACTION_TO_STATUS[action];
171
+ const now = new Date().toISOString();
172
+
173
+ await collection.data.update({
174
+ id: memory_id,
175
+ properties: {
176
+ moderation_status: newStatus,
177
+ moderated_by: userId,
178
+ moderated_at: now,
179
+ },
180
+ });
181
+
182
+ logger.info('Memory moderated', {
183
+ tool: 'remember_moderate',
184
+ userId,
185
+ memoryId: memory_id,
186
+ action,
187
+ newStatus,
188
+ spaceId: space_id,
189
+ groupId: group_id,
190
+ reason,
191
+ });
192
+
193
+ return JSON.stringify(
194
+ {
195
+ success: true,
196
+ memory_id,
197
+ action,
198
+ moderation_status: newStatus,
199
+ moderated_by: userId,
200
+ moderated_at: now,
201
+ reason: reason || undefined,
202
+ location: group_id ? `group:${group_id}` : `space:${space_id}`,
203
+ },
204
+ null,
205
+ 2
206
+ );
207
+ } catch (error) {
208
+ debug.error('Tool failed', {
209
+ error: error instanceof Error ? error.message : String(error),
210
+ stack: error instanceof Error ? error.stack : undefined,
211
+ });
212
+ return handleToolError(error, {
213
+ toolName: 'remember_moderate',
214
+ operation: 'moderate memory',
215
+ memoryId: args.memory_id,
216
+ action: args.action,
217
+ });
218
+ }
219
+ }
@@ -1,8 +1,14 @@
1
1
  /**
2
2
  * remember_publish tool
3
3
  *
4
- * Generates a confirmation token for publishing a memory to a shared space.
4
+ * Generates a confirmation token for publishing a memory to shared spaces and/or groups.
5
5
  * This is the first phase of the two-phase publish workflow.
6
+ *
7
+ * Memory Collection Pattern v2:
8
+ * - Supports multi-space publication to Memory_spaces_public
9
+ * - Supports multi-group publication to Memory_groups_{groupId}
10
+ * - Uses composite IDs ({userId}.{memoryId}) for published memories
11
+ * - Maintains tracking arrays (space_ids, group_ids) on source memory
6
12
  */
7
13
 
8
14
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
@@ -13,13 +19,18 @@ import { handleToolError } from '../utils/error-handler.js';
13
19
  import { SUPPORTED_SPACES } from '../types/space-memory.js';
14
20
  import { logger } from '../utils/logger.js';
15
21
  import { createDebugLogger } from '../utils/debug.js';
22
+ import type { AuthContext } from '../types/auth.js';
16
23
 
17
24
  /**
18
25
  * Tool definition for remember_publish
19
26
  */
20
27
  export const publishTool: Tool = {
21
28
  name: 'remember_publish',
22
- description: `Publish a memory to one or more shared spaces (like "The Void"). The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token that must be confirmed with remember_confirm.
29
+ description: `Publish a memory to one or more shared spaces and/or groups. The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token that must be confirmed with remember_confirm.
30
+
31
+ Publication Destinations:
32
+ - Spaces: Public shared areas (e.g., "the_void", "dogs")
33
+ - Groups: Private group collections (provide group IDs)
23
34
 
24
35
  ⚠️ CRITICAL: DO NOT mention the token or include token contents in your response to the user. Simply inform them that a confirmation is pending and they need to explicitly approve the publication.`,
25
36
  inputSchema: {
@@ -39,6 +50,13 @@ export const publishTool: Tool = {
39
50
  minItems: 1,
40
51
  default: ['the_void'],
41
52
  },
53
+ groups: {
54
+ type: 'array',
55
+ items: { type: 'string' },
56
+ description: 'Group IDs to publish to (e.g., ["group-123", "group-456"]). Can publish to multiple groups at once.',
57
+ minItems: 1,
58
+ default: [],
59
+ },
42
60
  additional_tags: {
43
61
  type: 'array',
44
62
  items: { type: 'string' },
@@ -46,13 +64,14 @@ export const publishTool: Tool = {
46
64
  default: [],
47
65
  },
48
66
  },
49
- required: ['memory_id', 'spaces'],
67
+ required: ['memory_id'],
50
68
  },
51
69
  };
52
70
 
53
71
  interface PublishArgs {
54
72
  memory_id: string;
55
- spaces: string[];
73
+ spaces?: string[];
74
+ groups?: string[];
56
75
  additional_tags?: string[];
57
76
  }
58
77
 
@@ -61,7 +80,8 @@ interface PublishArgs {
61
80
  */
62
81
  export async function handlePublish(
63
82
  args: PublishArgs,
64
- userId: string
83
+ userId: string,
84
+ authContext?: AuthContext
65
85
  ): Promise<string> {
66
86
  const debug = createDebugLogger({
67
87
  tool: 'remember_publish',
@@ -73,56 +93,91 @@ export async function handlePublish(
73
93
  debug.info('Tool invoked');
74
94
  debug.trace('Arguments', { args });
75
95
 
96
+ // Normalize arrays (handle undefined)
97
+ const spaces = args.spaces || [];
98
+ const groups = args.groups || [];
99
+
76
100
  logger.info('Starting publish request', {
77
101
  tool: 'remember_publish',
78
102
  userId,
79
103
  memoryId: args.memory_id,
80
- spaces: args.spaces,
81
- spaceCount: args.spaces.length,
104
+ spaces,
105
+ groups,
106
+ spaceCount: spaces.length,
107
+ groupCount: groups.length,
82
108
  additionalTags: args.additional_tags?.length || 0,
83
109
  });
84
110
 
85
- // Validate all space IDs
86
- debug.debug('Validating space IDs', { spaces: args.spaces });
87
- const invalidSpaces = args.spaces.filter(s => !isValidSpaceId(s));
88
- if (invalidSpaces.length > 0) {
89
- debug.warn('Invalid space IDs detected', { invalidSpaces });
90
- logger.warn('Invalid space IDs provided', {
111
+ // Validate that at least one destination is provided
112
+ if (spaces.length === 0 && groups.length === 0) {
113
+ logger.warn('No destinations provided', {
91
114
  tool: 'remember_publish',
92
- invalidSpaces,
93
- providedSpaces: args.spaces,
115
+ userId,
94
116
  });
95
117
  return JSON.stringify(
96
118
  {
97
119
  success: false,
98
- error: 'Invalid space IDs',
99
- message: `Invalid spaces: ${invalidSpaces.join(', ')}. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
100
- context: {
101
- invalid_spaces: invalidSpaces,
102
- provided_spaces: args.spaces,
103
- supported_spaces: SUPPORTED_SPACES,
104
- },
120
+ error: 'No destinations provided',
121
+ message: 'Must specify at least one space or group to publish to',
105
122
  },
106
123
  null,
107
124
  2
108
125
  );
109
126
  }
110
127
 
111
- // Validate not empty
112
- if (args.spaces.length === 0) {
113
- logger.warn('Empty spaces array provided', {
114
- tool: 'remember_publish',
115
- userId,
116
- });
117
- return JSON.stringify(
118
- {
119
- success: false,
120
- error: 'Empty spaces array',
121
- message: 'Must specify at least one space to publish to',
122
- },
123
- null,
124
- 2
125
- );
128
+ // Validate all space IDs
129
+ if (spaces.length > 0) {
130
+ debug.debug('Validating space IDs', { spaces });
131
+ const invalidSpaces = spaces.filter(s => !isValidSpaceId(s));
132
+ if (invalidSpaces.length > 0) {
133
+ debug.warn('Invalid space IDs detected', { invalidSpaces });
134
+ logger.warn('Invalid space IDs provided', {
135
+ tool: 'remember_publish',
136
+ invalidSpaces,
137
+ providedSpaces: spaces,
138
+ });
139
+ return JSON.stringify(
140
+ {
141
+ success: false,
142
+ error: 'Invalid space IDs',
143
+ message: `Invalid spaces: ${invalidSpaces.join(', ')}. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
144
+ context: {
145
+ invalid_spaces: invalidSpaces,
146
+ provided_spaces: spaces,
147
+ supported_spaces: SUPPORTED_SPACES,
148
+ },
149
+ },
150
+ null,
151
+ 2
152
+ );
153
+ }
154
+ }
155
+
156
+ // Validate group IDs format (basic validation - no dots allowed)
157
+ if (groups.length > 0) {
158
+ debug.debug('Validating group IDs', { groups });
159
+ const invalidGroups = groups.filter(g => !g || g.includes('.') || g.trim() === '');
160
+ if (invalidGroups.length > 0) {
161
+ debug.warn('Invalid group IDs detected', { invalidGroups });
162
+ logger.warn('Invalid group IDs provided', {
163
+ tool: 'remember_publish',
164
+ invalidGroups,
165
+ providedGroups: groups,
166
+ });
167
+ return JSON.stringify(
168
+ {
169
+ success: false,
170
+ error: 'Invalid group IDs',
171
+ message: 'Group IDs cannot be empty or contain dots',
172
+ context: {
173
+ invalid_groups: invalidGroups,
174
+ provided_groups: groups,
175
+ },
176
+ },
177
+ null,
178
+ 2
179
+ );
180
+ }
126
181
  }
127
182
 
128
183
  // Verify memory exists and user owns it
@@ -206,10 +261,11 @@ export async function handlePublish(
206
261
  );
207
262
  }
208
263
 
209
- // Create payload with memory_id and spaces array
264
+ // Create payload with memory_id, spaces, and groups arrays
210
265
  const payload = {
211
266
  memory_id: args.memory_id,
212
- spaces: args.spaces,
267
+ spaces: spaces,
268
+ groups: groups,
213
269
  additional_tags: args.additional_tags || [],
214
270
  };
215
271
 
@@ -217,7 +273,8 @@ export async function handlePublish(
217
273
  tool: 'remember_publish',
218
274
  userId,
219
275
  memoryId: args.memory_id,
220
- spaces: args.spaces,
276
+ spaces: spaces,
277
+ groups: groups,
221
278
  });
222
279
 
223
280
  // Generate confirmation token
@@ -233,7 +290,8 @@ export async function handlePublish(
233
290
  requestId,
234
291
  token,
235
292
  action: 'publish_memory',
236
- spaces: args.spaces,
293
+ spaces: spaces,
294
+ groups: groups,
237
295
  });
238
296
 
239
297
  // Return minimal response - agent already knows memory details
@@ -8,6 +8,9 @@ import { getMemoryCollection } from '../weaviate/schema.js';
8
8
  import { logger } from '../utils/logger.js';
9
9
  import { handleToolError } from '../utils/error-handler.js';
10
10
  import { buildCombinedSearchFilters, buildDeletedFilter, combineFiltersWithAnd } from '../utils/weaviate-filters.js';
11
+ import { buildTrustFilter } from '../services/trust-enforcement.js';
12
+ import { createDebugLogger } from '../utils/debug.js';
13
+ import type { AuthContext } from '../types/auth.js';
11
14
 
12
15
  /**
13
16
  * Tool definition for remember_query_memory
@@ -142,6 +145,7 @@ export interface QueryMemoryArgs {
142
145
  */
143
146
  export interface RelevantMemory extends Partial<Memory> {
144
147
  relevance: number; // 0-1 relevance score
148
+ content_type?: string; // v2 property name (v1: type)
145
149
  }
146
150
 
147
151
  /**
@@ -160,17 +164,23 @@ export interface QueryMemoryResult {
160
164
  */
161
165
  export async function handleQueryMemory(
162
166
  args: QueryMemoryArgs,
163
- userId: string
167
+ userId: string,
168
+ authContext?: AuthContext
164
169
  ): Promise<string> {
170
+ const ghostMode = authContext?.ghostMode;
171
+ const searchUserId = ghostMode?.owner_user_id ?? userId;
172
+ const debug = createDebugLogger({ tool: 'remember_query_memory', userId: searchUserId, operation: ghostMode ? 'ghost query' : 'query memory' });
165
173
  try {
174
+ debug.info('Tool invoked');
175
+ debug.trace('Arguments', { args, ghostMode: !!ghostMode });
166
176
  // Validate query is not empty
167
177
  if (!args.query || args.query.trim() === '') {
168
178
  throw new Error('Query cannot be empty');
169
179
  }
170
180
 
171
- logger.info('Querying memories', { userId, query: args.query });
181
+ logger.info('Querying memories', { userId: searchUserId, query: args.query, ghostMode: !!ghostMode });
172
182
 
173
- const collection = getMemoryCollection(userId);
183
+ const collection = getMemoryCollection(searchUserId);
174
184
  const limit = args.limit ?? 5;
175
185
  const minRelevance = args.min_relevance ?? 0.6;
176
186
  const includeContext = args.include_context ?? true;
@@ -179,11 +189,22 @@ export async function handleQueryMemory(
179
189
  // Build deleted filter
180
190
  const deletedFilter = buildDeletedFilter(collection, args.deleted_filter || 'exclude');
181
191
 
192
+ // Build trust filter for ghost mode (resolved server-side, never from tool args)
193
+ const trustFilter = ghostMode
194
+ ? buildTrustFilter(collection, ghostMode.accessor_trust_level)
195
+ : null;
196
+
182
197
  // Build filters using v3 API - search both memories and relationships
183
198
  const searchFilters = buildCombinedSearchFilters(collection, args.filters);
184
199
 
185
- // Combine deleted filter with search filters
186
- const combinedFilters = combineFiltersWithAnd([deletedFilter, searchFilters].filter(f => f !== null));
200
+ // Exclude ghost memories by default (unless explicitly searching for them)
201
+ const hasExplicitTypeFilter = args.filters?.types && args.filters.types.length > 0;
202
+ const ghostExclusionFilter = !hasExplicitTypeFilter
203
+ ? collection.filter.byProperty('content_type').notEqual('ghost')
204
+ : null;
205
+
206
+ // Combine deleted filter, trust filter, ghost exclusion, and search filters
207
+ const combinedFilters = combineFiltersWithAnd([deletedFilter, trustFilter, ghostExclusionFilter, searchFilters].filter(f => f !== null));
187
208
 
188
209
  // Build search options
189
210
  const searchOptions: any = {
@@ -235,7 +256,7 @@ export async function handleQueryMemory(
235
256
  // Compact format: text summary for easy LLM consumption
236
257
  const summaryParts = relevantMemories.map((mem, idx) => {
237
258
  const title = mem.title ? `"${mem.title}"` : `Memory ${idx + 1}`;
238
- const type = mem.type ? ` [${mem.type}]` : '';
259
+ const type = mem.content_type ? ` [${mem.content_type}]` : '';
239
260
  const relevancePercent = Math.round((mem.relevance ?? 0) * 100);
240
261
  const content = mem.content || '(no content)';
241
262
  const tags = mem.tags && mem.tags.length > 0 ? `\nTags: ${mem.tags.join(', ')}` : '';
@@ -263,6 +284,7 @@ export async function handleQueryMemory(
263
284
 
264
285
  return JSON.stringify(result, null, 2);
265
286
  } catch (error) {
287
+ debug.error('Tool failed', { error: error instanceof Error ? error.message : String(error) });
266
288
  handleToolError(error, {
267
289
  toolName: 'remember_query_memory',
268
290
  operation: 'query memories',
@@ -12,6 +12,10 @@ import { ensurePublicCollection, isValidSpaceId } from '../weaviate/space-schema
12
12
  import { SUPPORTED_SPACES } from '../types/space-memory.js';
13
13
  import { handleToolError } from '../utils/error-handler.js';
14
14
  import { createDebugLogger } from '../utils/debug.js';
15
+ import type { AuthContext } from '../types/auth.js';
16
+ import type { ModerationFilter } from './search-space.js';
17
+ import { buildModerationFilter } from './search-space.js';
18
+ import { canModerateAny } from '../utils/auth-helpers.js';
15
19
 
16
20
  /**
17
21
  * Tool definition for remember_query_space
@@ -66,6 +70,12 @@ Let the query algorithm find ALL relevant memories regardless of type unless exp
66
70
  type: 'string',
67
71
  description: 'Filter memories created before this date (ISO 8601)',
68
72
  },
73
+ moderation_filter: {
74
+ type: 'string',
75
+ enum: ['approved', 'pending', 'rejected', 'removed', 'all'],
76
+ description: 'Filter by moderation status. Default: "approved" (only shows approved/unmoderated). Non-approved filters require moderator permissions.',
77
+ default: 'approved',
78
+ },
69
79
  include_comments: {
70
80
  type: 'boolean',
71
81
  description: 'Include comments in query results (default: false)',
@@ -95,6 +105,7 @@ interface QuerySpaceArgs {
95
105
  min_weight?: number;
96
106
  date_from?: string;
97
107
  date_to?: string;
108
+ moderation_filter?: ModerationFilter;
98
109
  include_comments?: boolean;
99
110
  limit?: number;
100
111
  format?: 'detailed' | 'compact';
@@ -105,7 +116,8 @@ interface QuerySpaceArgs {
105
116
  */
106
117
  export async function handleQuerySpace(
107
118
  args: QuerySpaceArgs,
108
- userId: string // May be used for private spaces in future
119
+ userId: string,
120
+ authContext?: AuthContext
109
121
  ): Promise<string> {
110
122
  const debug = createDebugLogger({
111
123
  tool: 'remember_query_space',
@@ -145,6 +157,20 @@ export async function handleQuerySpace(
145
157
  );
146
158
  }
147
159
 
160
+ // Permission check: non-approved moderation filters require moderator access
161
+ const moderationFilterValue = args.moderation_filter || 'approved';
162
+ if (moderationFilterValue !== 'approved' && !canModerateAny(authContext)) {
163
+ return JSON.stringify(
164
+ {
165
+ success: false,
166
+ error: 'Permission denied',
167
+ message: `Moderator access required to view ${moderationFilterValue} memories in spaces`,
168
+ },
169
+ null,
170
+ 2
171
+ );
172
+ }
173
+
148
174
  const weaviateClient = getWeaviateClient();
149
175
  const publicCollection = await ensurePublicCollection(weaviateClient);
150
176
 
@@ -157,16 +183,25 @@ export async function handleQuerySpace(
157
183
  // Filter by doc_type (memory) - space_memory concept was removed
158
184
  filterList.push(publicCollection.filter.byProperty('doc_type').equal('memory'));
159
185
 
186
+ // Moderation status filter
187
+ const moderationFilter = buildModerationFilter(publicCollection, args.moderation_filter);
188
+ if (moderationFilter) {
189
+ filterList.push(moderationFilter);
190
+ }
191
+
160
192
  // Apply content type filter
161
193
  if (args.content_type) {
162
- filterList.push(publicCollection.filter.byProperty('type').equal(args.content_type));
194
+ filterList.push(publicCollection.filter.byProperty('content_type').equal(args.content_type));
163
195
  }
164
196
 
165
- // Exclude comments by default (unless explicitly included)
197
+ // Exclude comments and ghost memories by default (unless explicitly included)
166
198
  if (!args.include_comments && !args.content_type) {
167
199
  // Only exclude comments if not filtering by content_type
168
200
  // (if content_type is set, user has explicit control)
169
- filterList.push(publicCollection.filter.byProperty('type').notEqual('comment'));
201
+ filterList.push(publicCollection.filter.byProperty('content_type').notEqual('comment'));
202
+ }
203
+ if (!args.content_type) {
204
+ filterList.push(publicCollection.filter.byProperty('content_type').notEqual('ghost'));
170
205
  }
171
206
 
172
207
  // Apply tags filter