@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 +1 -1
- package/agent/commands/acp.init.md +92 -4
- package/dist/server-factory.js +99 -24
- package/dist/server.js +99 -24
- package/package.json +4 -3
package/AGENT.md
CHANGED
|
@@ -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.
|
|
6
|
+
**Version**: 1.1.0
|
|
7
7
|
**Created**: 2026-02-16
|
|
8
|
-
**Last Updated**: 2026-
|
|
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.
|
|
541
|
+
**Version**: 1.1.0
|
|
454
542
|
**Created**: 2026-02-16
|
|
455
|
-
**Last Updated**: 2026-
|
|
543
|
+
**Last Updated**: 2026-03-09
|
|
456
544
|
**Status**: Active
|
|
457
545
|
**Compatibility**: ACP 1.0.3+
|
|
458
546
|
**Author**: ACP Project
|
package/dist/server-factory.js
CHANGED
|
@@ -3857,8 +3857,8 @@ var RelationshipService = class {
|
|
|
3857
3857
|
}
|
|
3858
3858
|
// ── Create ──────────────────────────────────────────────────────────
|
|
3859
3859
|
async create(input) {
|
|
3860
|
-
if (input.memory_ids.length <
|
|
3861
|
-
throw new Error("At least
|
|
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
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
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
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
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 (
|
|
5491
|
-
return {
|
|
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
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
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
|
-
|
|
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 <
|
|
3865
|
-
throw new Error("At least
|
|
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
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
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
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
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 (
|
|
5495
|
-
return {
|
|
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
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
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
|
-
|
|
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
|
+
"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
|
+
"@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"
|