@seanhogg/builderforce-memory-mcp 2026.7.12 → 2026.9.27
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/README.md +47 -5
- package/dist/backend.d.ts +32 -0
- package/dist/backend.d.ts.map +1 -1
- package/dist/backends/memory-store.d.ts +32 -9
- package/dist/backends/memory-store.d.ts.map +1 -1
- package/dist/backends/memory-store.js +155 -33
- package/dist/backends/memory-store.js.map +1 -1
- package/dist/bin/http.d.ts +5 -0
- package/dist/bin/http.d.ts.map +1 -1
- package/dist/bin/http.js +11 -0
- package/dist/bin/http.js.map +1 -1
- package/dist/bin/install.js +3 -2
- package/dist/bin/install.js.map +1 -1
- package/dist/bin/stdio.d.ts +17 -7
- package/dist/bin/stdio.d.ts.map +1 -1
- package/dist/bin/stdio.js +24 -8
- package/dist/bin/stdio.js.map +1 -1
- package/dist/compaction.d.ts +76 -0
- package/dist/compaction.d.ts.map +1 -0
- package/dist/compaction.js +77 -0
- package/dist/compaction.js.map +1 -0
- package/dist/embedding/evermind-embedder.d.ts +119 -0
- package/dist/embedding/evermind-embedder.d.ts.map +1 -0
- package/dist/embedding/evermind-embedder.js +201 -0
- package/dist/embedding/evermind-embedder.js.map +1 -0
- package/dist/embedding/index.d.ts +38 -0
- package/dist/embedding/index.d.ts.map +1 -0
- package/dist/embedding/index.js +44 -0
- package/dist/embedding/index.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/install/claude-hooks.d.ts +42 -2
- package/dist/install/claude-hooks.d.ts.map +1 -1
- package/dist/install/claude-hooks.js +111 -16
- package/dist/install/claude-hooks.js.map +1 -1
- package/dist/install/server-spec.d.ts +12 -0
- package/dist/install/server-spec.d.ts.map +1 -1
- package/dist/install/server-spec.js +18 -0
- package/dist/install/server-spec.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +117 -6
- package/dist/tools.js.map +1 -1
- package/package.json +15 -4
- package/server.json +47 -0
- package/src/backend.ts +36 -0
- package/src/backends/memory-store.ts +184 -35
- package/src/bin/http.ts +12 -0
- package/src/bin/install.ts +3 -2
- package/src/bin/stdio.ts +25 -8
- package/src/compaction.ts +126 -0
- package/src/embedding/evermind-embedder.ts +276 -0
- package/src/embedding/index.ts +54 -0
- package/src/index.ts +18 -4
- package/src/install/claude-hooks.ts +116 -15
- package/src/install/server-spec.ts +25 -0
- package/src/tools.ts +133 -12
package/README.md
CHANGED
|
@@ -20,6 +20,9 @@ your whole memory file into every prompt. That only pays off if recall is
|
|
|
20
20
|
- `memory_recall` returns a **ranked top-K** (default 5, hard-capped), never the store.
|
|
21
21
|
- Each entry's content is **truncated** (default 500 chars) before it hits context.
|
|
22
22
|
- There is **no "return everything" tool** — a dump-all is more expensive than inlining.
|
|
23
|
+
- `memory_compact` shrinks a fact that something durable has already ABSORBED down to a
|
|
24
|
+
one-line pointer stub, so it stops being recalled in full. It writes **through the live
|
|
25
|
+
store**, which is what keeps memory and the on-disk snapshot in agreement — see below.
|
|
23
26
|
|
|
24
27
|
Tool descriptions are prescriptive ("call this *before* answering when…") because
|
|
25
28
|
recent Claude models reach for tools more conservatively; the trigger condition in
|
|
@@ -65,17 +68,52 @@ for await (const msg of query({
|
|
|
65
68
|
}
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
###
|
|
71
|
+
### The snapshot is shared — the server watches it
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
With `persistFile` set, the store lives in memory and the JSON snapshot is the source of
|
|
74
|
+
truth across process lifetimes. Other processes edit that file too (the BuilderForce VS
|
|
75
|
+
Code extension rewrites absorbed entries to stubs in place), so before every operation the
|
|
76
|
+
backend stats the file and **re-hydrates from disk when it changed underneath** — otherwise
|
|
77
|
+
this server, still holding the pre-edit bodies, would re-snapshot over that work on its next
|
|
78
|
+
write. Its own writes are stamped (mtime + size + content hash) the moment they land, so the
|
|
79
|
+
steady-state cost is one `stat` and there is no write-loop.
|
|
80
|
+
|
|
81
|
+
### SSM-embedding recall — including on a headless host (no GPU)
|
|
82
|
+
|
|
83
|
+
With no model configured the local backend ranks recall **lexically** (BM25). Point it
|
|
84
|
+
at an Evermind checkpoint and the ordering becomes the SSM embedding's cosine ranking
|
|
85
|
+
**fused with** the lexical one (Reciprocal Rank Fusion — dense ⊕ sparse, so exact
|
|
86
|
+
tokens like identifiers and error codes are still caught). Every `memory_recall`
|
|
87
|
+
result names the ranker it used, so a degrade to lexical is never silent:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Ranked by: semantic recall (SSM embedding fused with lexical).
|
|
91
|
+
Ranked by: lexical recall (fallback - no embedding model loaded).
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**The stdio/HTTP servers do not need a GPU for this.** `EvermindLM` is a pure-CPU
|
|
95
|
+
model and `EvermindLM.embed()` mean-pools + L2-normalises the same hidden state the
|
|
96
|
+
GPU `HybridMambaModel.embed()` does, to the same contract. Configure it with:
|
|
97
|
+
|
|
98
|
+
| Env | Meaning |
|
|
99
|
+
|-----|---------|
|
|
100
|
+
| `BUILDERFORCE_MEMORY_MODEL` | Path to a `.evermind` package holding an `evermind-lm`. |
|
|
101
|
+
| `BUILDERFORCE_MEMORY_TOKENIZER` | Tokenizer JSON for that checkpoint. Default `<model>.tokenizer.json`. |
|
|
102
|
+
| `BUILDERFORCE_MEMORY_VECTORS` | Vector-cache path. Defaults beside the memory snapshot. |
|
|
103
|
+
|
|
104
|
+
Vectors are cached **across process lifetimes** (stamped with the model's
|
|
105
|
+
fingerprint, so an adapted checkpoint invalidates them), because a per-session
|
|
106
|
+
subprocess that re-embedded the whole store on its first recall would cost more than
|
|
107
|
+
the lexical ranking it replaces.
|
|
108
|
+
|
|
109
|
+
In-process hosts pass an embedder directly — reuse an already-loaded GPU Evermind
|
|
110
|
+
runtime rather than standing up a second model:
|
|
73
111
|
|
|
74
112
|
```ts
|
|
75
113
|
const backend = await createLocalMemoryStoreBackend({ runtime: ssmMemoryService.runtime });
|
|
76
114
|
```
|
|
77
115
|
|
|
78
|
-
|
|
116
|
+
Either way, recall quality improves automatically as that model is adapted/distilled.
|
|
79
117
|
|
|
80
118
|
## One-shot install into any MCP host (not just Claude)
|
|
81
119
|
|
|
@@ -165,6 +203,10 @@ const remote: MemoryBackend = {
|
|
|
165
203
|
const server = await createMemoryMcpServer(remote);
|
|
166
204
|
```
|
|
167
205
|
|
|
206
|
+
## Compaction rules (`@seanhogg/builderforce-memory-mcp/compaction`)
|
|
207
|
+
|
|
208
|
+
The stub format that `memory_compact` writes (`[absorbed→Evermind vN] <first line>`) is published as a dependency-free subpath. An external compactor imports `planCompaction`, `memoryStub` and `isStub` from it, so its stubs are byte-identical to the server's and neither re-stubs the other.
|
|
209
|
+
|
|
168
210
|
## Dependencies
|
|
169
211
|
|
|
170
212
|
`@modelcontextprotocol/sdk` + `zod` are hard deps. `@anthropic-ai/claude-agent-sdk`
|
package/dist/backend.d.ts
CHANGED
|
@@ -26,6 +26,19 @@ export interface RecallHit {
|
|
|
26
26
|
/** Unix-ms write time. */
|
|
27
27
|
timestamp?: number;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Which ranker produced a recall ordering.
|
|
31
|
+
*
|
|
32
|
+
* Same vocabulary the gateway's Evermind recall/validate result uses, so a host
|
|
33
|
+
* renders one chip ("Semantic recall" / "Lexical recall (fallback)") no matter
|
|
34
|
+
* which layer answered.
|
|
35
|
+
*/
|
|
36
|
+
export type RecallMethod = "embedding" | "lexical";
|
|
37
|
+
/** A recall ordering plus the ranker that produced it. */
|
|
38
|
+
export interface RankedRecall {
|
|
39
|
+
hits: RecallHit[];
|
|
40
|
+
method: RecallMethod;
|
|
41
|
+
}
|
|
29
42
|
/** Arguments for writing a memory. */
|
|
30
43
|
export interface RememberInput {
|
|
31
44
|
key: string;
|
|
@@ -48,12 +61,31 @@ export interface MemoryBackend {
|
|
|
48
61
|
* clamped by the caller — the backend may return fewer, never more.
|
|
49
62
|
*/
|
|
50
63
|
recall(query: string, topK: number): Promise<RecallHit[]>;
|
|
64
|
+
/**
|
|
65
|
+
* {@link recall} with the ranker named. Optional; callers MUST fall back to
|
|
66
|
+
* plain `recall` (and report nothing) when it is absent.
|
|
67
|
+
*
|
|
68
|
+
* It exists because "did this ordering come from the SSM embedding or from
|
|
69
|
+
* word overlap?" is the difference between semantic recall and a fallback, and
|
|
70
|
+
* an answer that silently degrades to lexical is indistinguishable from one
|
|
71
|
+
* that did not. A backend that knows which path it took says so here.
|
|
72
|
+
*/
|
|
73
|
+
recallRanked?(query: string, topK: number): Promise<RankedRecall>;
|
|
51
74
|
/** Exact lookup by key. Returns undefined when absent or expired. */
|
|
52
75
|
get(key: string): Promise<RecallHit | undefined>;
|
|
53
76
|
/** All non-expired entries carrying `tag`, capped to `limit`. */
|
|
54
77
|
recallByTag(tag: string, limit: number): Promise<RecallHit[]>;
|
|
55
78
|
/** Store or overwrite a memory. Optional — read-only backends omit it. */
|
|
56
79
|
remember?(input: RememberInput): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Store several memories as ONE durable unit. Optional; callers MUST fall
|
|
82
|
+
* back to a `remember` loop when it is absent.
|
|
83
|
+
*
|
|
84
|
+
* It exists for the batch writer (`memory_compact`): a durable backend that
|
|
85
|
+
* flushes after every write would otherwise re-serialise the entire store
|
|
86
|
+
* once per compacted key, which is quadratic in the size of the store.
|
|
87
|
+
*/
|
|
88
|
+
rememberMany?(inputs: RememberInput[]): Promise<void>;
|
|
57
89
|
/** Delete a memory by key. Optional — read-only backends omit it. */
|
|
58
90
|
forget?(key: string): Promise<void>;
|
|
59
91
|
}
|
package/dist/backend.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,SAAS;IACtB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE1D,qEAAqE;IACrE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEjD,iEAAiE;IACjE,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE9D,0EAA0E;IAC1E,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C,qEAAqE;IACrE,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC"}
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,SAAS;IACtB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnD,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;CACxB;AAED,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE1D;;;;;;;;OAQG;IACH,YAAY,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAElE,qEAAqE;IACrE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEjD,iEAAiE;IACjE,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE9D,0EAA0E;IAC1E,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,YAAY,CAAC,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtD,qEAAqE;IACrE,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC"}
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
* MemoryStoreBackend — local adapter mapping @seanhogg/builderforce-memory's MemoryStore
|
|
3
3
|
* onto the MemoryBackend seam.
|
|
4
4
|
*
|
|
5
|
-
* Recall quality: when
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Recall quality: when a text embedder is supplied it is forwarded to the store's
|
|
6
|
+
* `recallRanked`, so the ordering is the shared hybrid retrieval — the SSM
|
|
7
|
+
* embedding's cosine ranking FUSED with BM25 by Reciprocal Rank Fusion — and it
|
|
8
|
+
* sharpens as the model is adapted/distilled. With no embedder the same call
|
|
9
|
+
* degrades to the lexical ranking alone. Either way the backend reports which of
|
|
10
|
+
* the two produced the ordering (`method`), so a silent degrade is visible.
|
|
11
|
+
*
|
|
12
|
+
* The embedder does NOT have to be a GPU runtime: `EvermindTextEmbedder` from the
|
|
13
|
+
* engine is a pure-CPU `EvermindLM`, which is what lets the headless stdio server
|
|
14
|
+
* rank recall semantically (see ./evermind-embedder.ts).
|
|
9
15
|
*/
|
|
10
|
-
import type { MemoryBackend, RecallHit, RememberInput } from "../backend.js";
|
|
16
|
+
import type { MemoryBackend, RankedRecall, RecallHit, RememberInput } from "../backend.js";
|
|
11
17
|
interface MemoryEntryLike {
|
|
12
18
|
key: string;
|
|
13
19
|
content: string;
|
|
@@ -24,7 +30,14 @@ interface MemoryStoreLike {
|
|
|
24
30
|
recall(key: string): Promise<MemoryEntryLike | undefined>;
|
|
25
31
|
recallAll(): Promise<MemoryEntryLike[]>;
|
|
26
32
|
recallByTag(tag: string): Promise<MemoryEntryLike[]>;
|
|
27
|
-
|
|
33
|
+
/** Hybrid (dense⊕BM25) recall with each hit's fused score and the ranker used. */
|
|
34
|
+
recallRanked(query: string, topK: number, runtime?: unknown): Promise<{
|
|
35
|
+
hits: Array<{
|
|
36
|
+
entry: MemoryEntryLike;
|
|
37
|
+
score: number;
|
|
38
|
+
}>;
|
|
39
|
+
method: "embedding" | "lexical";
|
|
40
|
+
}>;
|
|
28
41
|
forget(key: string): Promise<void>;
|
|
29
42
|
}
|
|
30
43
|
export declare class MemoryStoreBackend implements MemoryBackend {
|
|
@@ -34,10 +47,14 @@ export declare class MemoryStoreBackend implements MemoryBackend {
|
|
|
34
47
|
constructor(store: MemoryStoreLike,
|
|
35
48
|
/** Optional SSMRuntime; enables embedding-based recall when present. */
|
|
36
49
|
runtime?: unknown | undefined);
|
|
50
|
+
/** Plain recall — {@link recallRanked} with the ranker's name dropped. ONE path. */
|
|
37
51
|
recall(query: string, topK: number): Promise<RecallHit[]>;
|
|
52
|
+
recallRanked(query: string, topK: number): Promise<RankedRecall>;
|
|
38
53
|
get(key: string): Promise<RecallHit | undefined>;
|
|
39
54
|
recallByTag(tag: string, limit: number): Promise<RecallHit[]>;
|
|
40
55
|
remember(input: RememberInput): Promise<void>;
|
|
56
|
+
/** The store has no batch write; sequencing here keeps ONE definition of a write. */
|
|
57
|
+
rememberMany(inputs: RememberInput[]): Promise<void>;
|
|
41
58
|
forget(key: string): Promise<void>;
|
|
42
59
|
}
|
|
43
60
|
/** Options for {@link createLocalMemoryStoreBackend}. */
|
|
@@ -45,9 +62,11 @@ export interface LocalBackendOptions {
|
|
|
45
62
|
/** IndexedDB database name. Defaults to MemoryStore's own default ('ssmjs'). */
|
|
46
63
|
dbName?: string;
|
|
47
64
|
/**
|
|
48
|
-
* Optional
|
|
49
|
-
* recall.
|
|
50
|
-
*
|
|
65
|
+
* Optional text embedder — anything with `embed(text): Promise<Float32Array>`.
|
|
66
|
+
* Omit for lexical-only recall. Pass the agent-runtime's
|
|
67
|
+
* `ssmMemoryService.runtime` to reuse an already-loaded GPU Evermind, or an
|
|
68
|
+
* `EvermindTextEmbedder` (pure CPU) via {@link createEvermindEmbedder} on a
|
|
69
|
+
* headless host.
|
|
51
70
|
*/
|
|
52
71
|
runtime?: unknown;
|
|
53
72
|
/**
|
|
@@ -59,6 +78,10 @@ export interface LocalBackendOptions {
|
|
|
59
78
|
* When set, the store is hydrated from the file on creation and re-snapshotted
|
|
60
79
|
* after every remember/forget, giving durable cross-process memory. TTLs are
|
|
61
80
|
* dropped on persist: the snapshot is the durable long-term tier.
|
|
81
|
+
*
|
|
82
|
+
* The file is also WATCHED: it is a shared artifact (other processes compact it
|
|
83
|
+
* in place), so the store re-hydrates from disk whenever it changed underneath —
|
|
84
|
+
* see {@link DiskPersistedBackend} for the loop guard.
|
|
62
85
|
*/
|
|
63
86
|
persistFile?: string;
|
|
64
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI3F,UAAU,eAAe;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,eAAe;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IAC1D,SAAS,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACxC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACrD,kFAAkF;IAClF,YAAY,CACR,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,eAAe,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IACxG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAaD,qBAAa,kBAAmB,YAAW,aAAa;IAEhD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAFR,KAAK,EAAE,eAAe;IACvC,wEAAwE;IACvD,OAAO,CAAC,EAAE,OAAO,YAAA;IAGtC,oFAAoF;IAC9E,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAIzD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAKhE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAKhD,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,qFAAqF;IAC/E,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3C;AAED,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAChC,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAwMD;;;;;GAKG;AACH,wBAAsB,6BAA6B,CAAC,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC,CAkC1G"}
|
|
@@ -2,15 +2,22 @@
|
|
|
2
2
|
* MemoryStoreBackend — local adapter mapping @seanhogg/builderforce-memory's MemoryStore
|
|
3
3
|
* onto the MemoryBackend seam.
|
|
4
4
|
*
|
|
5
|
-
* Recall quality: when
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Recall quality: when a text embedder is supplied it is forwarded to the store's
|
|
6
|
+
* `recallRanked`, so the ordering is the shared hybrid retrieval — the SSM
|
|
7
|
+
* embedding's cosine ranking FUSED with BM25 by Reciprocal Rank Fusion — and it
|
|
8
|
+
* sharpens as the model is adapted/distilled. With no embedder the same call
|
|
9
|
+
* degrades to the lexical ranking alone. Either way the backend reports which of
|
|
10
|
+
* the two produced the ordering (`method`), so a silent degrade is visible.
|
|
11
|
+
*
|
|
12
|
+
* The embedder does NOT have to be a GPU runtime: `EvermindTextEmbedder` from the
|
|
13
|
+
* engine is a pure-CPU `EvermindLM`, which is what lets the headless stdio server
|
|
14
|
+
* rank recall semantically (see ./evermind-embedder.ts).
|
|
9
15
|
*/
|
|
10
|
-
function toHit(e) {
|
|
16
|
+
function toHit(e, score) {
|
|
11
17
|
return {
|
|
12
18
|
key: e.key,
|
|
13
19
|
content: e.content,
|
|
20
|
+
...(score === undefined ? {} : { score }),
|
|
14
21
|
tags: e.tags,
|
|
15
22
|
importance: e.importance,
|
|
16
23
|
timestamp: e.timestamp,
|
|
@@ -25,9 +32,13 @@ export class MemoryStoreBackend {
|
|
|
25
32
|
this.store = store;
|
|
26
33
|
this.runtime = runtime;
|
|
27
34
|
}
|
|
35
|
+
/** Plain recall — {@link recallRanked} with the ranker's name dropped. ONE path. */
|
|
28
36
|
async recall(query, topK) {
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
return (await this.recallRanked(query, topK)).hits;
|
|
38
|
+
}
|
|
39
|
+
async recallRanked(query, topK) {
|
|
40
|
+
const ranked = await this.store.recallRanked(query, topK, this.runtime);
|
|
41
|
+
return { hits: ranked.hits.map((h) => toHit(h.entry, h.score)), method: ranked.method };
|
|
31
42
|
}
|
|
32
43
|
async get(key) {
|
|
33
44
|
const e = await this.store.recall(key);
|
|
@@ -44,44 +55,163 @@ export class MemoryStoreBackend {
|
|
|
44
55
|
importance: input.importance,
|
|
45
56
|
});
|
|
46
57
|
}
|
|
58
|
+
/** The store has no batch write; sequencing here keeps ONE definition of a write. */
|
|
59
|
+
async rememberMany(inputs) {
|
|
60
|
+
for (const input of inputs)
|
|
61
|
+
await this.remember(input);
|
|
62
|
+
}
|
|
47
63
|
async forget(key) {
|
|
48
64
|
await this.store.forget(key);
|
|
49
65
|
}
|
|
50
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* FNV-1a over the snapshot text. Non-cryptographic on purpose: this only has to
|
|
69
|
+
* separate "someone rewrote the file" from "the mtime moved but the bytes are
|
|
70
|
+
* ours", and node:crypto is deliberately not imported here (this module must stay
|
|
71
|
+
* bundleable for the browser, where the disk path is never taken).
|
|
72
|
+
*/
|
|
73
|
+
function contentHash(text) {
|
|
74
|
+
let h = 0x811c9dc5;
|
|
75
|
+
for (let i = 0; i < text.length; i++) {
|
|
76
|
+
h ^= text.charCodeAt(i);
|
|
77
|
+
h = Math.imul(h, 0x01000193);
|
|
78
|
+
}
|
|
79
|
+
return (h >>> 0).toString(16);
|
|
80
|
+
}
|
|
81
|
+
/** Parse a snapshot's text into its durable entries, or null when unusable. */
|
|
82
|
+
function parseSnapshot(text) {
|
|
83
|
+
let parsed;
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(text);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
if (!Array.isArray(parsed))
|
|
91
|
+
return null;
|
|
92
|
+
return parsed.filter((raw) => !!raw && typeof raw.key === "string" && typeof raw.content === "string");
|
|
93
|
+
}
|
|
51
94
|
/**
|
|
52
95
|
* Wraps a MemoryStoreBackend so every write is mirrored to a JSON file, and
|
|
53
96
|
* hydrates that file back into the store on boot. This is what turns a respawned
|
|
54
97
|
* stdio subprocess into a persistent memory: the store itself is in-memory, the
|
|
55
98
|
* file is the source of truth across process lifetimes.
|
|
99
|
+
*
|
|
100
|
+
* It also WATCHES the file for external edits. The snapshot is a shared artifact —
|
|
101
|
+
* the BuilderForce VS Code extension compacts absorbed entries by rewriting it
|
|
102
|
+
* directly, and a second server instance may be mirroring the same path. Without a
|
|
103
|
+
* watch this server, still holding the pre-edit bodies, would silently re-snapshot
|
|
104
|
+
* over that work on its very next remember/forget; the edit would only stick once
|
|
105
|
+
* the client respawned the subprocess. So every operation first calls
|
|
106
|
+
* {@link DiskPersistedBackend.ensureFresh}, which re-hydrates the store from disk
|
|
107
|
+
* when — and only when — the file changed underneath us.
|
|
108
|
+
*
|
|
109
|
+
* The loop guard is the {@link FileStamp} recorded immediately AFTER each of our own
|
|
110
|
+
* writes: the next check stats the file, sees the same mtime+size, and returns
|
|
111
|
+
* without reading a byte. A stat per call is the entire steady-state cost.
|
|
56
112
|
*/
|
|
57
113
|
class DiskPersistedBackend {
|
|
58
114
|
inner;
|
|
59
115
|
store;
|
|
60
116
|
file;
|
|
61
117
|
fs;
|
|
118
|
+
/** How the file looked when this process last wrote or read it. */
|
|
119
|
+
stamp = null;
|
|
62
120
|
constructor(inner, store, file, fs) {
|
|
63
121
|
this.inner = inner;
|
|
64
122
|
this.store = store;
|
|
65
123
|
this.file = file;
|
|
66
124
|
this.fs = fs;
|
|
67
125
|
}
|
|
68
|
-
recall(query, topK) {
|
|
126
|
+
async recall(query, topK) {
|
|
127
|
+
await this.ensureFresh();
|
|
69
128
|
return this.inner.recall(query, topK);
|
|
70
129
|
}
|
|
71
|
-
|
|
130
|
+
async recallRanked(query, topK) {
|
|
131
|
+
await this.ensureFresh();
|
|
132
|
+
return this.inner.recallRanked(query, topK);
|
|
133
|
+
}
|
|
134
|
+
async get(key) {
|
|
135
|
+
await this.ensureFresh();
|
|
72
136
|
return this.inner.get(key);
|
|
73
137
|
}
|
|
74
|
-
recallByTag(tag, limit) {
|
|
138
|
+
async recallByTag(tag, limit) {
|
|
139
|
+
await this.ensureFresh();
|
|
75
140
|
return this.inner.recallByTag(tag, limit);
|
|
76
141
|
}
|
|
77
142
|
async remember(input) {
|
|
143
|
+
await this.ensureFresh();
|
|
78
144
|
await this.inner.remember(input);
|
|
79
145
|
await this.snapshot();
|
|
80
146
|
}
|
|
147
|
+
/** Batch write — ONE snapshot for the whole set, so compacting N keys is not N full rewrites. */
|
|
148
|
+
async rememberMany(inputs) {
|
|
149
|
+
await this.ensureFresh();
|
|
150
|
+
await this.inner.rememberMany(inputs);
|
|
151
|
+
await this.snapshot();
|
|
152
|
+
}
|
|
81
153
|
async forget(key) {
|
|
154
|
+
await this.ensureFresh();
|
|
82
155
|
await this.inner.forget(key);
|
|
83
156
|
await this.snapshot();
|
|
84
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Re-read the snapshot into the store when the file changed since we last
|
|
160
|
+
* touched it. Also the BOOT hydration: with no stamp yet, an existing file is
|
|
161
|
+
* always read in — one routine, so disk and memory can never diverge by taking
|
|
162
|
+
* two different paths.
|
|
163
|
+
*/
|
|
164
|
+
async ensureFresh() {
|
|
165
|
+
if (!this.fs.existsSync(this.file))
|
|
166
|
+
return;
|
|
167
|
+
let st;
|
|
168
|
+
try {
|
|
169
|
+
st = this.fs.statSync(this.file);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Fast path: byte-for-byte what we last wrote. No read, no parse, no writes.
|
|
175
|
+
if (this.stamp && st.mtimeMs === this.stamp.mtimeMs && st.size === this.stamp.size)
|
|
176
|
+
return;
|
|
177
|
+
let text;
|
|
178
|
+
try {
|
|
179
|
+
text = this.fs.readFileSync(this.file, "utf8");
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const hash = contentHash(text);
|
|
185
|
+
// Touched (mtime moved) but identical content — re-stamp, don't re-hydrate.
|
|
186
|
+
if (this.stamp && hash === this.stamp.hash) {
|
|
187
|
+
this.stamp = { mtimeMs: st.mtimeMs, size: st.size, hash };
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const entries = parseSnapshot(text);
|
|
191
|
+
// Corrupt/partial snapshot (a half-written file, say): keep what we have
|
|
192
|
+
// rather than wiping the live store, and leave the stamp alone so the next
|
|
193
|
+
// call re-checks.
|
|
194
|
+
if (!entries)
|
|
195
|
+
return;
|
|
196
|
+
await this.replaceStore(entries);
|
|
197
|
+
this.stamp = { mtimeMs: st.mtimeMs, size: st.size, hash };
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Make the in-memory store equal the snapshot: drop keys the file no longer has,
|
|
201
|
+
* then replay every entry (a re-remember overwrites, so a body shortened to a
|
|
202
|
+
* stub on disk becomes the stub in memory). Replayed as durable — TTLs are
|
|
203
|
+
* dropped on persist; the snapshot is the long-term tier.
|
|
204
|
+
*/
|
|
205
|
+
async replaceStore(entries) {
|
|
206
|
+
const wanted = new Set(entries.map((e) => e.key));
|
|
207
|
+
for (const existing of await this.store.recallAll()) {
|
|
208
|
+
if (!wanted.has(existing.key))
|
|
209
|
+
await this.store.forget(existing.key);
|
|
210
|
+
}
|
|
211
|
+
for (const raw of entries) {
|
|
212
|
+
await this.store.remember(raw.key, raw.content, { tags: raw.tags, importance: raw.importance });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
85
215
|
async snapshot() {
|
|
86
216
|
const entries = await this.store.recallAll();
|
|
87
217
|
const out = entries.map((e) => ({
|
|
@@ -90,27 +220,17 @@ class DiskPersistedBackend {
|
|
|
90
220
|
tags: e.tags,
|
|
91
221
|
importance: e.importance,
|
|
92
222
|
}));
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
catch {
|
|
105
|
-
// Corrupt/partial snapshot — start clean rather than crash the server.
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (!Array.isArray(parsed))
|
|
109
|
-
return;
|
|
110
|
-
for (const raw of parsed) {
|
|
111
|
-
if (!raw || typeof raw.key !== "string" || typeof raw.content !== "string")
|
|
112
|
-
continue;
|
|
113
|
-
await store.remember(raw.key, raw.content, { tags: raw.tags, importance: raw.importance });
|
|
223
|
+
const json = JSON.stringify(out, null, 2);
|
|
224
|
+
this.fs.writeFileSync(this.file, json);
|
|
225
|
+
// Stamp OUR write immediately — this is what stops the watch above from
|
|
226
|
+
// treating our own output as an external edit (and looping).
|
|
227
|
+
try {
|
|
228
|
+
const st = this.fs.statSync(this.file);
|
|
229
|
+
this.stamp = { mtimeMs: st.mtimeMs, size: st.size, hash: contentHash(json) };
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
this.stamp = null;
|
|
233
|
+
}
|
|
114
234
|
}
|
|
115
235
|
}
|
|
116
236
|
/**
|
|
@@ -146,7 +266,9 @@ export async function createLocalMemoryStoreBackend(opts = {}) {
|
|
|
146
266
|
const dir = path.dirname(opts.persistFile);
|
|
147
267
|
if (dir && !fs.existsSync(dir))
|
|
148
268
|
fs.mkdirSync(dir, { recursive: true });
|
|
149
|
-
|
|
150
|
-
|
|
269
|
+
const persisted = new DiskPersistedBackend(backend, store, opts.persistFile, fs);
|
|
270
|
+
// Boot hydration IS the freshness check with no stamp yet — see ensureFresh().
|
|
271
|
+
await persisted.ensureFresh();
|
|
272
|
+
return persisted;
|
|
151
273
|
}
|
|
152
274
|
//# sourceMappingURL=memory-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/http.d.ts
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
* BUILDERFORCE_MEMORY_TOKEN Bearer token required on every request (recommended).
|
|
10
10
|
* BUILDERFORCE_MEMORY_DB IndexedDB database name.
|
|
11
11
|
* BUILDERFORCE_MEMORY_READONLY '1' to disable remember/forget tools.
|
|
12
|
+
* BUILDERFORCE_MEMORY_FILE JSON snapshot path (also sites the vector cache).
|
|
13
|
+
* BUILDERFORCE_MEMORY_MODEL `.evermind` package to rank recall by SSM embedding
|
|
14
|
+
* (pure CPU, no GPU). Unset = lexical ranking.
|
|
15
|
+
* BUILDERFORCE_MEMORY_TOKENIZER Tokenizer JSON for that checkpoint.
|
|
16
|
+
* BUILDERFORCE_MEMORY_VECTORS Persistent vector-cache path.
|
|
12
17
|
* BUILDERFORCE_GATEWAY_URL Gateway base URL (default https://api.builderforce.ai).
|
|
13
18
|
* BUILDERFORCE_API_KEY `bfk_*` tenant key. When set, exposes the cost tools.
|
|
14
19
|
*/
|
package/dist/bin/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/bin/http.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/bin/http.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG"}
|
package/dist/bin/http.js
CHANGED
|
@@ -9,14 +9,25 @@
|
|
|
9
9
|
* BUILDERFORCE_MEMORY_TOKEN Bearer token required on every request (recommended).
|
|
10
10
|
* BUILDERFORCE_MEMORY_DB IndexedDB database name.
|
|
11
11
|
* BUILDERFORCE_MEMORY_READONLY '1' to disable remember/forget tools.
|
|
12
|
+
* BUILDERFORCE_MEMORY_FILE JSON snapshot path (also sites the vector cache).
|
|
13
|
+
* BUILDERFORCE_MEMORY_MODEL `.evermind` package to rank recall by SSM embedding
|
|
14
|
+
* (pure CPU, no GPU). Unset = lexical ranking.
|
|
15
|
+
* BUILDERFORCE_MEMORY_TOKENIZER Tokenizer JSON for that checkpoint.
|
|
16
|
+
* BUILDERFORCE_MEMORY_VECTORS Persistent vector-cache path.
|
|
12
17
|
* BUILDERFORCE_GATEWAY_URL Gateway base URL (default https://api.builderforce.ai).
|
|
13
18
|
* BUILDERFORCE_API_KEY `bfk_*` tenant key. When set, exposes the cost tools.
|
|
14
19
|
*/
|
|
15
20
|
import http from "node:http";
|
|
16
21
|
import { createLocalMemoryStoreBackend } from "../backends/memory-store.js";
|
|
22
|
+
import { createRecallEmbedder } from "../embedding/index.js";
|
|
23
|
+
import { resolveMemoryFile } from "../install/server-spec.js";
|
|
17
24
|
import { createMemoryHttpHandler } from "../transports/http.js";
|
|
25
|
+
const memoryFile = resolveMemoryFile();
|
|
18
26
|
const backend = await createLocalMemoryStoreBackend({
|
|
19
27
|
dbName: process.env["BUILDERFORCE_MEMORY_DB"],
|
|
28
|
+
// Same embedder decision as the stdio bin, from the same helper — the two
|
|
29
|
+
// servers must not rank recall differently.
|
|
30
|
+
runtime: (await createRecallEmbedder({ memoryFile })) ?? undefined,
|
|
20
31
|
});
|
|
21
32
|
const handler = createMemoryHttpHandler(backend, {
|
|
22
33
|
authToken: process.env["BUILDERFORCE_MEMORY_TOKEN"],
|
package/dist/bin/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/bin/http.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/bin/http.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;AAEvC,MAAM,OAAO,GAAG,MAAM,6BAA6B,CAAC;IAChD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAC7C,0EAA0E;IAC1E,4CAA4C;IAC5C,OAAO,EAAE,CAAC,MAAM,oBAAoB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,SAAS;CACrE,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,uBAAuB,CAAC,OAAO,EAAE;IAC7C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;IACnD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,KAAK,GAAG;IAC7D,2EAA2E;IAC3E,0EAA0E;IAC1E,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,IAAI,6BAA6B;IACpF,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;CACrD,CAAC,CAAC;AAEH,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;AAEjD,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC3B,KAAK,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,IAAI,CAAC,GAAG,CAAC,WAAW;YAAE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACjF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gDAAgD,IAAI,IAAI,CAAC,CAAC;AACnF,CAAC,CAAC,CAAC"}
|
package/dist/bin/install.js
CHANGED
|
@@ -21,6 +21,7 @@ import nodeFs from "node:fs";
|
|
|
21
21
|
import { HOSTS } from "../install/hosts.js";
|
|
22
22
|
import { installMemoryServer } from "../install/install.js";
|
|
23
23
|
import { installClaudeCombo } from "../install/claude-hooks.js";
|
|
24
|
+
import { defaultMemoryFile } from "../install/server-spec.js";
|
|
24
25
|
function argValue(name) {
|
|
25
26
|
const hit = process.argv.find((a) => a.startsWith(`--${name}=`));
|
|
26
27
|
return hit ? hit.slice(name.length + 3) : undefined;
|
|
@@ -46,7 +47,7 @@ const hosts = hostArg === undefined || hostArg === "auto"
|
|
|
46
47
|
: hostArg === "all"
|
|
47
48
|
? "all"
|
|
48
49
|
: hostArg.split(",").map((s) => s.trim()).filter(Boolean);
|
|
49
|
-
const memoryFile = argValue("memory-file") ??
|
|
50
|
+
const memoryFile = argValue("memory-file") ?? defaultMemoryFile();
|
|
50
51
|
let results;
|
|
51
52
|
try {
|
|
52
53
|
results = installMemoryServer({
|
|
@@ -99,6 +100,6 @@ if (results.length === 0) {
|
|
|
99
100
|
process.stdout.write("No MCP hosts detected. Pass --host=all to write configs anyway, or --host=cursor (etc.).\n");
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
|
-
process.stdout.write(`\nDone — ${wrote} config(s) written. Store: ${memoryFile}\nRestart the agent(s) to connect. Tools: memory_recall · memory_remember · memory_get · memory_recall_by_tag · memory_forget\n`);
|
|
103
|
+
process.stdout.write(`\nDone — ${wrote} config(s) written. Store: ${memoryFile}\nRestart the agent(s) to connect. Tools: memory_recall · memory_remember · memory_get · memory_recall_by_tag · memory_forget · memory_compact\n`);
|
|
103
104
|
}
|
|
104
105
|
//# sourceMappingURL=install.js.map
|
package/dist/bin/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/bin/install.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAqB,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/bin/install.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAqB,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,SAAS,QAAQ,CAAC,IAAY;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC;IACjE,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AACD,MAAM,OAAO,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAE9E,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB;QACI,8EAA8E;QAC9E,EAAE;QACF,yEAAyE;QACzE,yFAAyF;QACzF,yDAAyD;QACzD,qEAAqE;QACrE,EAAE;QACF,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACnD,EAAE;KACL,CAAC,IAAI,CAAC,IAAI,CAAC,CACf,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjC,MAAM,KAAK,GACP,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM;IACvC,CAAC,CAAC,MAAM;IACR,CAAC,CAAC,OAAO,KAAK,KAAK;QACjB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAEpE,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,iBAAiB,EAAE,CAAC;AAElE,IAAI,OAAO,CAAC;AACZ,IAAI,CAAC;IACD,OAAO,GAAG,mBAAmB,CAAC;QAC1B,KAAK;QACL,UAAU;QACV,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC;QAC7B,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;AACP,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,CAAE,GAAa,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,IAAI,GAA2B;IACjC,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,GAAG;IAChB,KAAK,EAAE,GAAG;CACb,CAAC;AAEF,IAAI,KAAK,GAAG,CAAC,CAAC;AACd,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC;IACzF,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,IAAI,CAAC,CAAC;AACvE,CAAC;AAED,gFAAgF;AAChF,0EAA0E;AAC1E,kFAAkF;AAClF,mFAAmF;AACnF,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;AACnE,MAAM,aAAa,GAAG,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,aAAa,IAAI,YAAY,CAAC,MAAM,KAAK,OAAO,CAAC;AAC/G,IAAI,aAAa,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;IACxC,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,kBAAkB,CAAC;YAC7B,EAAE,EAAE,MAAM;YACV,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC;YAC7C,UAAU;SACb,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC;QAClG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,IAAI,uCAAuC,CAAC,CAAC;IAC3G,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,MAAM,CAAE,GAAa,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5F,CAAC;AACL,CAAC;AAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,4FAA4F,CAC/F,CAAC;AACN,CAAC;KAAM,CAAC;IACJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,YAAY,KAAK,8BAA8B,UAAU,kJAAkJ,CAC9M,CAAC;AACN,CAAC"}
|