@prmichaelsen/remember-mcp 3.17.3 → 3.17.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.
package/AGENT.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Agent Context Protocol (ACP)
2
2
 
3
3
  **Also Known As**: The Agent Directory Pattern
4
- **Version**: 5.13.1
4
+ **Version**: 5.15.0
5
5
  **Created**: 2026-02-11
6
6
  **Status**: Production Pattern
7
7
 
@@ -3,9 +3,9 @@
3
3
  > **🤖 Agent Directive**: If you are reading this file, the command `@acp-init` has been invoked. Follow the steps below to execute this command.
4
4
 
5
5
  **Namespace**: acp
6
- **Version**: 1.0.0
6
+ **Version**: 1.1.0
7
7
  **Created**: 2026-02-16
8
- **Last Updated**: 2026-02-16
8
+ **Last Updated**: 2026-03-09
9
9
  **Status**: Active
10
10
  **Scripts**: None
11
11
 
@@ -17,6 +17,38 @@
17
17
 
18
18
  ---
19
19
 
20
+ ## Arguments
21
+
22
+ | Argument | Aliases | Description |
23
+ |---|---|---|
24
+ | `--quick` | `-q` | Fast init: skips version checks, source file review, and documentation sync. Equivalent to `--skip checks,files,sync` |
25
+ | `--skip <items>` | | Comma-separated list of steps to skip. Valid items: `checks`, `sessions`, `docs`, `global`, `keys`, `files`, `sync`, `progress` |
26
+
27
+ ### Skip Items Reference
28
+
29
+ | Item | Steps Skipped | Description |
30
+ |---|---|---|
31
+ | `checks` | Step 1 | ACP version update check |
32
+ | `sessions` | Step 1.5 | Session registration and sibling display |
33
+ | `docs` | Step 2 | Reading agent documentation (progress, designs, milestones, tasks, patterns) |
34
+ | `global` | Step 2.5 | Global package discovery |
35
+ | `keys` | Step 2.8 | Key file index reading |
36
+ | `files` | Steps 3-4 | Source file identification and review |
37
+ | `sync` | Steps 5-6 | Documentation drift detection and stale doc updates |
38
+ | `progress` | Step 7 | Progress tracking updates |
39
+
40
+ ### Argument Parsing
41
+
42
+ Arguments are parsed from the user's invocation using natural language matching:
43
+ - `@acp-init --quick` or `@acp-init -q`
44
+ - `@acp-init --skip checks,sync`
45
+ - `@acp-init --quick --skip sessions` (quick mode plus additional skips)
46
+ - `@acp-init --skip checks,files,sync,progress` (granular control)
47
+
48
+ When `--quick` is combined with `--skip`, the skip sets are merged (union).
49
+
50
+ ---
51
+
20
52
  ## What This Command Does
21
53
 
22
54
  This command performs a comprehensive initialization of the agent's context for working on an ACP-structured project. It checks for ACP updates, reads all documentation in the `agent/` directory, reviews key source files to understand the current implementation, updates any stale documentation, and refreshes progress tracking.
@@ -39,6 +71,8 @@ Unlike `@acp-status` which only reads progress.yaml, or `@acp-proceed` which foc
39
71
 
40
72
  ### 1. Check for ACP Updates
41
73
 
74
+ **Skip item**: `checks` | **Skipped by**: `--quick`
75
+
42
76
  Check if newer version of ACP is available.
43
77
 
44
78
  **Actions**:
@@ -51,6 +85,8 @@ Check if newer version of ACP is available.
51
85
 
52
86
  ### 1.5. Register Session and Show Siblings (Optional)
53
87
 
88
+ **Skip item**: `sessions`
89
+
54
90
  Register this agent session and display any active sibling sessions.
55
91
 
56
92
  **Actions**:
@@ -70,6 +106,8 @@ Active Sessions: 2 others
70
106
 
71
107
  ### 2. Read All Agent Documentation
72
108
 
109
+ **Skip item**: `docs`
110
+
73
111
  Load complete context from the agent/ directory.
74
112
 
75
113
  **Actions**:
@@ -85,6 +123,8 @@ Load complete context from the agent/ directory.
85
123
 
86
124
  ### 2.5. Discover Global Packages (Optional)
87
125
 
126
+ **Skip item**: `global`
127
+
88
128
  Check for globally installed ACP packages.
89
129
 
90
130
  **Actions**:
@@ -119,6 +159,8 @@ Check for globally installed ACP packages.
119
159
 
120
160
  ### 2.8. Read Key Files from Index
121
161
 
162
+ **Skip item**: `keys`
163
+
122
164
  Load critical project files from the key file index.
123
165
 
124
166
  **Actions**:
@@ -147,6 +189,8 @@ Load critical project files from the key file index.
147
189
 
148
190
  ### 3. Identify Key Source Files
149
191
 
192
+ **Skip item**: `files` | **Skipped by**: `--quick`
193
+
150
194
  Determine which source files are most important to review.
151
195
 
152
196
  **Actions**:
@@ -160,6 +204,8 @@ Determine which source files are most important to review.
160
204
 
161
205
  ### 4. Review Key Source Files
162
206
 
207
+ **Skip item**: `files` | **Skipped by**: `--quick`
208
+
163
209
  Read important source files to understand current implementation.
164
210
 
165
211
  **Actions**:
@@ -174,6 +220,8 @@ Read important source files to understand current implementation.
174
220
 
175
221
  ### 5. Identify Documentation Drift
176
222
 
223
+ **Skip item**: `sync` | **Skipped by**: `--quick`
224
+
177
225
  Compare documentation with actual implementation.
178
226
 
179
227
  **Actions**:
@@ -187,6 +235,8 @@ Compare documentation with actual implementation.
187
235
 
188
236
  ### 6. Update Stale Documentation
189
237
 
238
+ **Skip item**: `sync` | **Skipped by**: `--quick`
239
+
190
240
  Refresh outdated documentation to match current state.
191
241
 
192
242
  **Actions**:
@@ -200,6 +250,8 @@ Refresh outdated documentation to match current state.
200
250
 
201
251
  ### 7. Update Progress Tracking
202
252
 
253
+ **Skip item**: `progress`
254
+
203
255
  Refresh progress.yaml with latest status.
204
256
 
205
257
  **Actions**:
@@ -227,6 +279,26 @@ Provide comprehensive status report.
227
279
 
228
280
  **Expected Outcome**: User has complete context and knows what to do next
229
281
 
282
+ ### 9. Display Usage Tip
283
+
284
+ Show a helpful tip about init flags when no flags were used.
285
+
286
+ **Actions**:
287
+ - If the user invoked `@acp-init` **without** `--quick` or `--skip`, display the following tip at the end of the output:
288
+ ```
289
+ Tip: Use `@acp-init --quick` to skip version checks, source file review, and doc sync for faster startup. Use `--skip <items>` to skip individual steps (e.g. `--skip checks,files`).
290
+ ```
291
+ - If the user already used `--quick` or `--skip`, do **not** display the tip (they already know about it).
292
+
293
+ **Expected Outcome**: Users discover the faster init modes naturally
294
+
295
+ ### Handling Skipped Steps
296
+
297
+ When a step is skipped (via `--quick` or `--skip`), the agent should:
298
+ 1. **Not execute** any actions for that step
299
+ 2. **Not display** the step's section header or output block
300
+ 3. Simply omit the step silently — no "skipped" messages needed unless the agent chooses to show a compact summary of what was skipped at the top of the output
301
+
230
302
  ---
231
303
 
232
304
  ## Verification
@@ -372,6 +444,22 @@ Ready to proceed with task-2 completion.
372
444
 
373
445
  **Result**: Complete onboarding - reads all documentation, understands architecture from source code, gets current status, ready to contribute immediately
374
446
 
447
+ ### Example 4: Quick Init
448
+
449
+ **Context**: Returning to a familiar project, just need docs and status
450
+
451
+ **Invocation**: `@acp-init --quick`
452
+
453
+ **Result**: Skips version checks, source file review, and doc sync. Reads agent documentation, key files, reports status — fast startup in ~10 seconds
454
+
455
+ ### Example 5: Selective Skip
456
+
457
+ **Context**: Want everything except version checks and session registration
458
+
459
+ **Invocation**: `@acp-init --skip checks,sessions`
460
+
461
+ **Result**: Full init minus the two skipped steps. All docs read, files reviewed, sync performed, status reported
462
+
375
463
  ---
376
464
 
377
465
  ## Related Commands
@@ -450,9 +538,9 @@ Ready to proceed with task-2 completion.
450
538
 
451
539
  **Namespace**: acp
452
540
  **Command**: init
453
- **Version**: 1.0.0
541
+ **Version**: 1.1.0
454
542
  **Created**: 2026-02-16
455
- **Last Updated**: 2026-02-16
543
+ **Last Updated**: 2026-03-09
456
544
  **Status**: Active
457
545
  **Compatibility**: ACP 1.0.3+
458
546
  **Author**: ACP Project
@@ -3857,8 +3857,8 @@ var RelationshipService = class {
3857
3857
  }
3858
3858
  // ── Create ──────────────────────────────────────────────────────────
3859
3859
  async create(input) {
3860
- if (input.memory_ids.length < 2) {
3861
- throw new Error("At least 2 memory IDs are required to create a relationship");
3860
+ if (input.memory_ids.length < 1) {
3861
+ throw new Error("At least 1 memory ID is required to create a relationship");
3862
3862
  }
3863
3863
  const validated = await this.validateMemoryIds(input.memory_ids);
3864
3864
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -4669,24 +4669,76 @@ var SpaceService = class {
4669
4669
  const parentId = String(originalMemory.properties.parent_id ?? "");
4670
4670
  const threadRootId = String(originalMemory.properties.thread_root_id ?? parentId);
4671
4671
  const contentPreview = String(originalMemory.properties.content ?? "").slice(0, 200);
4672
- if (successfulPublications.some((p) => p.startsWith("spaces:"))) {
4673
- for (const spaceId of spaces) {
4674
- this.eventBus.emit({ type: "comment.published_to_space", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, space_id: spaceId, owner_id: this.userId }, actor);
4672
+ let parentOwnerId = "";
4673
+ try {
4674
+ const parentMemory = await fetchMemoryWithAllProperties(this.userCollection, parentId);
4675
+ if (parentMemory) {
4676
+ const parentUserId = String(parentMemory.properties.user_id ?? "");
4677
+ if (parentUserId && parentUserId !== this.userId) {
4678
+ parentOwnerId = parentUserId;
4679
+ } else if (parentUserId === this.userId) {
4680
+ parentOwnerId = this.userId;
4681
+ }
4682
+ }
4683
+ if (!parentOwnerId) {
4684
+ const publicCollection = await ensurePublicCollection(this.weaviateClient);
4685
+ const directHit = await fetchMemoryWithAllProperties(publicCollection, parentId);
4686
+ if (directHit) {
4687
+ parentOwnerId = String(directHit.properties.author_id ?? directHit.properties.user_id ?? "");
4688
+ }
4689
+ if (!parentOwnerId) {
4690
+ const filter = publicCollection.filter.byProperty("original_memory_id").equal(parentId);
4691
+ const result = await publicCollection.query.fetchObjects({ filters: filter, limit: 1 });
4692
+ if (result.objects.length > 0) {
4693
+ parentOwnerId = String(result.objects[0].properties.author_id ?? "");
4694
+ }
4695
+ }
4696
+ }
4697
+ if (!parentOwnerId) {
4698
+ for (const groupId of groups) {
4699
+ try {
4700
+ const groupCollectionName = getCollectionName(CollectionType.GROUPS, groupId);
4701
+ const groupCollection = this.weaviateClient.collections.get(groupCollectionName);
4702
+ const gDirect = await fetchMemoryWithAllProperties(groupCollection, parentId);
4703
+ if (gDirect) {
4704
+ parentOwnerId = String(gDirect.properties.author_id ?? gDirect.properties.user_id ?? "");
4705
+ break;
4706
+ }
4707
+ const gFilter = groupCollection.filter.byProperty("original_memory_id").equal(parentId);
4708
+ const gResult = await groupCollection.query.fetchObjects({ filters: gFilter, limit: 1 });
4709
+ if (gResult.objects.length > 0) {
4710
+ parentOwnerId = String(gResult.objects[0].properties.author_id ?? "");
4711
+ break;
4712
+ }
4713
+ } catch {
4714
+ }
4715
+ }
4675
4716
  }
4717
+ } catch (err2) {
4718
+ this.logger.warn("Failed to resolve parent owner for comment event", { parentId, err: err2 });
4676
4719
  }
4677
- const publishedGroups = groups.filter((g) => successfulPublications.some((p) => p === `group: ${g}`));
4678
- for (const groupId of publishedGroups) {
4679
- this.eventBus.emit({ type: "comment.published_to_group", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, group_id: groupId, owner_id: this.userId }, actor);
4720
+ if (!parentOwnerId) {
4721
+ this.logger.warn("Skipping comment webhook \u2014 could not resolve parent_owner_id", { parentId, memoryId: request.payload.memory_id });
4722
+ } else {
4723
+ if (successfulPublications.some((p) => p.startsWith("spaces:"))) {
4724
+ for (const spaceId of spaces) {
4725
+ await this.eventBus.emit({ type: "comment.published_to_space", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, space_id: spaceId, owner_id: this.userId, parent_owner_id: parentOwnerId }, actor);
4726
+ }
4727
+ }
4728
+ const publishedGroups = groups.filter((g) => successfulPublications.some((p) => p === `group: ${g}`));
4729
+ for (const groupId of publishedGroups) {
4730
+ await this.eventBus.emit({ type: "comment.published_to_group", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, group_id: groupId, owner_id: this.userId, parent_owner_id: parentOwnerId }, actor);
4731
+ }
4680
4732
  }
4681
4733
  } else {
4682
4734
  if (successfulPublications.some((p) => p.startsWith("spaces:"))) {
4683
4735
  for (const spaceId of spaces) {
4684
- this.eventBus.emit({ type: "memory.published_to_space", memory_id: request.payload.memory_id, title, space_id: spaceId, owner_id: this.userId }, actor);
4736
+ await this.eventBus.emit({ type: "memory.published_to_space", memory_id: request.payload.memory_id, title, space_id: spaceId, owner_id: this.userId }, actor);
4685
4737
  }
4686
4738
  }
4687
4739
  const publishedGroups = groups.filter((g) => successfulPublications.some((p) => p === `group: ${g}`));
4688
4740
  for (const groupId of publishedGroups) {
4689
- this.eventBus.emit({ type: "memory.published_to_group", memory_id: request.payload.memory_id, title, group_id: groupId, owner_id: this.userId }, actor);
4741
+ await this.eventBus.emit({ type: "memory.published_to_group", memory_id: request.payload.memory_id, title, group_id: groupId, owner_id: this.userId }, actor);
4690
4742
  }
4691
4743
  }
4692
4744
  }
@@ -4783,7 +4835,7 @@ var SpaceService = class {
4783
4835
  targets.push({ kind: "group", id: groupId });
4784
4836
  }
4785
4837
  if (targets.length > 0) {
4786
- this.eventBus.emit({ type: "memory.retracted", memory_id: request.payload.memory_id, owner_id: this.userId, targets }, { type: "user", id: this.userId });
4838
+ await this.eventBus.emit({ type: "memory.retracted", memory_id: request.payload.memory_id, owner_id: this.userId, targets }, { type: "user", id: this.userId });
4787
4839
  }
4788
4840
  }
4789
4841
  return {
@@ -5487,13 +5539,28 @@ var SpaceService = class {
5487
5539
  } catch {
5488
5540
  }
5489
5541
  }
5490
- if (!props) {
5491
- return { space_ids: [], group_ids: [] };
5542
+ if (props) {
5543
+ return {
5544
+ space_ids: Array.isArray(props.space_ids) ? props.space_ids : [],
5545
+ group_ids: Array.isArray(props.group_ids) ? props.group_ids : []
5546
+ };
5492
5547
  }
5493
- return {
5494
- space_ids: Array.isArray(props.space_ids) ? props.space_ids : [],
5495
- group_ids: Array.isArray(props.group_ids) ? props.group_ids : []
5496
- };
5548
+ try {
5549
+ const collectionName = await this.memoryIndex.lookup(memoryId);
5550
+ if (collectionName) {
5551
+ const collection = this.weaviateClient.collections.get(collectionName);
5552
+ const obj = await fetchMemoryWithAllProperties(collection, memoryId);
5553
+ if (obj) {
5554
+ const p = obj.properties;
5555
+ return {
5556
+ space_ids: Array.isArray(p.space_ids) ? p.space_ids : [],
5557
+ group_ids: Array.isArray(p.group_ids) ? p.group_ids : []
5558
+ };
5559
+ }
5560
+ }
5561
+ } catch {
5562
+ }
5563
+ return { space_ids: [], group_ids: [] };
5497
5564
  }
5498
5565
  };
5499
5566
 
@@ -5746,7 +5813,7 @@ var BatchedWebhookService = class {
5746
5813
  this.timeoutMs = config2.timeoutMs ?? DEFAULT_TIMEOUT_MS;
5747
5814
  this.onError = config2.onError;
5748
5815
  }
5749
- emit(event, actor) {
5816
+ async emit(event, actor) {
5750
5817
  const ownerId = event.owner_id;
5751
5818
  const endpoints = this.resolveEndpoint(ownerId);
5752
5819
  if (endpoints.length === 0) {
@@ -5757,6 +5824,7 @@ var BatchedWebhookService = class {
5757
5824
  return;
5758
5825
  }
5759
5826
  const envelope = this.buildEnvelope(event, actor);
5827
+ const flushPromises = [];
5760
5828
  for (const endpoint of endpoints) {
5761
5829
  const url = endpoint.url;
5762
5830
  let buffer = this.buffers.get(url);
@@ -5766,13 +5834,16 @@ var BatchedWebhookService = class {
5766
5834
  }
5767
5835
  buffer.envelopes.push(envelope);
5768
5836
  if (buffer.envelopes.length >= this.maxBatchSize) {
5769
- this.flush(url);
5837
+ flushPromises.push(this.flush(url));
5770
5838
  } else if (!buffer.timer) {
5771
5839
  buffer.timer = setTimeout(() => this.flush(url), this.flushIntervalMs);
5772
5840
  }
5773
5841
  }
5842
+ if (flushPromises.length > 0) {
5843
+ await Promise.all(flushPromises);
5844
+ }
5774
5845
  }
5775
- flush(url) {
5846
+ async flush(url) {
5776
5847
  const buffer = this.buffers.get(url);
5777
5848
  if (!buffer || buffer.envelopes.length === 0)
5778
5849
  return;
@@ -5783,19 +5854,23 @@ var BatchedWebhookService = class {
5783
5854
  }
5784
5855
  buffer.envelopes = [];
5785
5856
  buffer.timer = null;
5786
- this.sendBatch(url, endpoint, envelopes).catch((err2) => {
5857
+ try {
5858
+ await this.sendBatch(url, endpoint, envelopes);
5859
+ } catch (err2) {
5787
5860
  this.logger.error?.("[BatchedWebhookService] batch delivery failed", {
5788
5861
  error: err2,
5789
5862
  url,
5790
5863
  count: envelopes.length
5791
5864
  });
5792
5865
  this.onError?.(err2, envelopes);
5793
- });
5866
+ }
5794
5867
  }
5795
- dispose() {
5868
+ async dispose() {
5869
+ const promises = [];
5796
5870
  for (const url of this.buffers.keys()) {
5797
- this.flush(url);
5871
+ promises.push(this.flush(url));
5798
5872
  }
5873
+ await Promise.all(promises);
5799
5874
  }
5800
5875
  async sendBatch(url, endpoint, envelopes) {
5801
5876
  const batchId = v4_default();
package/dist/server.js CHANGED
@@ -3861,8 +3861,8 @@ var RelationshipService = class {
3861
3861
  }
3862
3862
  // ── Create ──────────────────────────────────────────────────────────
3863
3863
  async create(input) {
3864
- if (input.memory_ids.length < 2) {
3865
- throw new Error("At least 2 memory IDs are required to create a relationship");
3864
+ if (input.memory_ids.length < 1) {
3865
+ throw new Error("At least 1 memory ID is required to create a relationship");
3866
3866
  }
3867
3867
  const validated = await this.validateMemoryIds(input.memory_ids);
3868
3868
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -4673,24 +4673,76 @@ var SpaceService = class {
4673
4673
  const parentId = String(originalMemory.properties.parent_id ?? "");
4674
4674
  const threadRootId = String(originalMemory.properties.thread_root_id ?? parentId);
4675
4675
  const contentPreview = String(originalMemory.properties.content ?? "").slice(0, 200);
4676
- if (successfulPublications.some((p) => p.startsWith("spaces:"))) {
4677
- for (const spaceId of spaces) {
4678
- this.eventBus.emit({ type: "comment.published_to_space", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, space_id: spaceId, owner_id: this.userId }, actor);
4676
+ let parentOwnerId = "";
4677
+ try {
4678
+ const parentMemory = await fetchMemoryWithAllProperties(this.userCollection, parentId);
4679
+ if (parentMemory) {
4680
+ const parentUserId = String(parentMemory.properties.user_id ?? "");
4681
+ if (parentUserId && parentUserId !== this.userId) {
4682
+ parentOwnerId = parentUserId;
4683
+ } else if (parentUserId === this.userId) {
4684
+ parentOwnerId = this.userId;
4685
+ }
4686
+ }
4687
+ if (!parentOwnerId) {
4688
+ const publicCollection = await ensurePublicCollection(this.weaviateClient);
4689
+ const directHit = await fetchMemoryWithAllProperties(publicCollection, parentId);
4690
+ if (directHit) {
4691
+ parentOwnerId = String(directHit.properties.author_id ?? directHit.properties.user_id ?? "");
4692
+ }
4693
+ if (!parentOwnerId) {
4694
+ const filter = publicCollection.filter.byProperty("original_memory_id").equal(parentId);
4695
+ const result = await publicCollection.query.fetchObjects({ filters: filter, limit: 1 });
4696
+ if (result.objects.length > 0) {
4697
+ parentOwnerId = String(result.objects[0].properties.author_id ?? "");
4698
+ }
4699
+ }
4700
+ }
4701
+ if (!parentOwnerId) {
4702
+ for (const groupId of groups) {
4703
+ try {
4704
+ const groupCollectionName = getCollectionName(CollectionType.GROUPS, groupId);
4705
+ const groupCollection = this.weaviateClient.collections.get(groupCollectionName);
4706
+ const gDirect = await fetchMemoryWithAllProperties(groupCollection, parentId);
4707
+ if (gDirect) {
4708
+ parentOwnerId = String(gDirect.properties.author_id ?? gDirect.properties.user_id ?? "");
4709
+ break;
4710
+ }
4711
+ const gFilter = groupCollection.filter.byProperty("original_memory_id").equal(parentId);
4712
+ const gResult = await groupCollection.query.fetchObjects({ filters: gFilter, limit: 1 });
4713
+ if (gResult.objects.length > 0) {
4714
+ parentOwnerId = String(gResult.objects[0].properties.author_id ?? "");
4715
+ break;
4716
+ }
4717
+ } catch {
4718
+ }
4719
+ }
4679
4720
  }
4721
+ } catch (err2) {
4722
+ this.logger.warn("Failed to resolve parent owner for comment event", { parentId, err: err2 });
4680
4723
  }
4681
- const publishedGroups = groups.filter((g) => successfulPublications.some((p) => p === `group: ${g}`));
4682
- for (const groupId of publishedGroups) {
4683
- this.eventBus.emit({ type: "comment.published_to_group", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, group_id: groupId, owner_id: this.userId }, actor);
4724
+ if (!parentOwnerId) {
4725
+ this.logger.warn("Skipping comment webhook \u2014 could not resolve parent_owner_id", { parentId, memoryId: request.payload.memory_id });
4726
+ } else {
4727
+ if (successfulPublications.some((p) => p.startsWith("spaces:"))) {
4728
+ for (const spaceId of spaces) {
4729
+ await this.eventBus.emit({ type: "comment.published_to_space", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, space_id: spaceId, owner_id: this.userId, parent_owner_id: parentOwnerId }, actor);
4730
+ }
4731
+ }
4732
+ const publishedGroups = groups.filter((g) => successfulPublications.some((p) => p === `group: ${g}`));
4733
+ for (const groupId of publishedGroups) {
4734
+ await this.eventBus.emit({ type: "comment.published_to_group", memory_id: request.payload.memory_id, parent_id: parentId, thread_root_id: threadRootId, content_preview: contentPreview, group_id: groupId, owner_id: this.userId, parent_owner_id: parentOwnerId }, actor);
4735
+ }
4684
4736
  }
4685
4737
  } else {
4686
4738
  if (successfulPublications.some((p) => p.startsWith("spaces:"))) {
4687
4739
  for (const spaceId of spaces) {
4688
- this.eventBus.emit({ type: "memory.published_to_space", memory_id: request.payload.memory_id, title, space_id: spaceId, owner_id: this.userId }, actor);
4740
+ await this.eventBus.emit({ type: "memory.published_to_space", memory_id: request.payload.memory_id, title, space_id: spaceId, owner_id: this.userId }, actor);
4689
4741
  }
4690
4742
  }
4691
4743
  const publishedGroups = groups.filter((g) => successfulPublications.some((p) => p === `group: ${g}`));
4692
4744
  for (const groupId of publishedGroups) {
4693
- this.eventBus.emit({ type: "memory.published_to_group", memory_id: request.payload.memory_id, title, group_id: groupId, owner_id: this.userId }, actor);
4745
+ await this.eventBus.emit({ type: "memory.published_to_group", memory_id: request.payload.memory_id, title, group_id: groupId, owner_id: this.userId }, actor);
4694
4746
  }
4695
4747
  }
4696
4748
  }
@@ -4787,7 +4839,7 @@ var SpaceService = class {
4787
4839
  targets.push({ kind: "group", id: groupId });
4788
4840
  }
4789
4841
  if (targets.length > 0) {
4790
- this.eventBus.emit({ type: "memory.retracted", memory_id: request.payload.memory_id, owner_id: this.userId, targets }, { type: "user", id: this.userId });
4842
+ await this.eventBus.emit({ type: "memory.retracted", memory_id: request.payload.memory_id, owner_id: this.userId, targets }, { type: "user", id: this.userId });
4791
4843
  }
4792
4844
  }
4793
4845
  return {
@@ -5491,13 +5543,28 @@ var SpaceService = class {
5491
5543
  } catch {
5492
5544
  }
5493
5545
  }
5494
- if (!props) {
5495
- return { space_ids: [], group_ids: [] };
5546
+ if (props) {
5547
+ return {
5548
+ space_ids: Array.isArray(props.space_ids) ? props.space_ids : [],
5549
+ group_ids: Array.isArray(props.group_ids) ? props.group_ids : []
5550
+ };
5496
5551
  }
5497
- return {
5498
- space_ids: Array.isArray(props.space_ids) ? props.space_ids : [],
5499
- group_ids: Array.isArray(props.group_ids) ? props.group_ids : []
5500
- };
5552
+ try {
5553
+ const collectionName = await this.memoryIndex.lookup(memoryId);
5554
+ if (collectionName) {
5555
+ const collection = this.weaviateClient.collections.get(collectionName);
5556
+ const obj = await fetchMemoryWithAllProperties(collection, memoryId);
5557
+ if (obj) {
5558
+ const p = obj.properties;
5559
+ return {
5560
+ space_ids: Array.isArray(p.space_ids) ? p.space_ids : [],
5561
+ group_ids: Array.isArray(p.group_ids) ? p.group_ids : []
5562
+ };
5563
+ }
5564
+ }
5565
+ } catch {
5566
+ }
5567
+ return { space_ids: [], group_ids: [] };
5501
5568
  }
5502
5569
  };
5503
5570
 
@@ -5750,7 +5817,7 @@ var BatchedWebhookService = class {
5750
5817
  this.timeoutMs = config3.timeoutMs ?? DEFAULT_TIMEOUT_MS;
5751
5818
  this.onError = config3.onError;
5752
5819
  }
5753
- emit(event, actor) {
5820
+ async emit(event, actor) {
5754
5821
  const ownerId = event.owner_id;
5755
5822
  const endpoints = this.resolveEndpoint(ownerId);
5756
5823
  if (endpoints.length === 0) {
@@ -5761,6 +5828,7 @@ var BatchedWebhookService = class {
5761
5828
  return;
5762
5829
  }
5763
5830
  const envelope = this.buildEnvelope(event, actor);
5831
+ const flushPromises = [];
5764
5832
  for (const endpoint of endpoints) {
5765
5833
  const url = endpoint.url;
5766
5834
  let buffer = this.buffers.get(url);
@@ -5770,13 +5838,16 @@ var BatchedWebhookService = class {
5770
5838
  }
5771
5839
  buffer.envelopes.push(envelope);
5772
5840
  if (buffer.envelopes.length >= this.maxBatchSize) {
5773
- this.flush(url);
5841
+ flushPromises.push(this.flush(url));
5774
5842
  } else if (!buffer.timer) {
5775
5843
  buffer.timer = setTimeout(() => this.flush(url), this.flushIntervalMs);
5776
5844
  }
5777
5845
  }
5846
+ if (flushPromises.length > 0) {
5847
+ await Promise.all(flushPromises);
5848
+ }
5778
5849
  }
5779
- flush(url) {
5850
+ async flush(url) {
5780
5851
  const buffer = this.buffers.get(url);
5781
5852
  if (!buffer || buffer.envelopes.length === 0)
5782
5853
  return;
@@ -5787,19 +5858,23 @@ var BatchedWebhookService = class {
5787
5858
  }
5788
5859
  buffer.envelopes = [];
5789
5860
  buffer.timer = null;
5790
- this.sendBatch(url, endpoint, envelopes).catch((err2) => {
5861
+ try {
5862
+ await this.sendBatch(url, endpoint, envelopes);
5863
+ } catch (err2) {
5791
5864
  this.logger.error?.("[BatchedWebhookService] batch delivery failed", {
5792
5865
  error: err2,
5793
5866
  url,
5794
5867
  count: envelopes.length
5795
5868
  });
5796
5869
  this.onError?.(err2, envelopes);
5797
- });
5870
+ }
5798
5871
  }
5799
- dispose() {
5872
+ async dispose() {
5873
+ const promises = [];
5800
5874
  for (const url of this.buffers.keys()) {
5801
- this.flush(url);
5875
+ promises.push(this.flush(url));
5802
5876
  }
5877
+ await Promise.all(promises);
5803
5878
  }
5804
5879
  async sendBatch(url, endpoint, envelopes) {
5805
5880
  const batchId = v4_default();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/remember-mcp",
3
- "version": "3.17.3",
3
+ "version": "3.17.4",
4
4
  "description": "Multi-tenant memory system MCP server with vector search and relationships",
5
5
  "main": "dist/server.js",
6
6
  "type": "module",
@@ -35,7 +35,8 @@
35
35
  "test:all": "npm test && npm run test:e2e",
36
36
  "lint": "eslint src/**/*.ts",
37
37
  "typecheck": "tsc --noEmit",
38
- "prepublishOnly": "npm run clean && npm run build"
38
+ "prepublishOnly": "npm run clean && npm run build",
39
+ "update:core": "npm i @prmichaelsen/remember-core@latest && git add package* && git commit -m \"bump: remember-core\" && npm version patch && npm publish"
39
40
  },
40
41
  "keywords": [
41
42
  "mcp",
@@ -51,7 +52,7 @@
51
52
  "@google-cloud/vision": "^5.3.4",
52
53
  "@modelcontextprotocol/sdk": "^1.0.4",
53
54
  "@prmichaelsen/firebase-admin-sdk-v8": "^2.2.0",
54
- "@prmichaelsen/remember-core": "^0.55.1",
55
+ "@prmichaelsen/remember-core": "^0.56.3",
55
56
  "dotenv": "^16.4.5",
56
57
  "uuid": "^13.0.0",
57
58
  "weaviate-client": "^3.2.0"