bikky 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +323 -0
- package/bin/bikky.js +6 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +51 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +59 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +141 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +8 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +449 -0
- package/dist/config.test.js.map +1 -0
- package/dist/daemon/consolidation.d.ts +60 -0
- package/dist/daemon/consolidation.d.ts.map +1 -0
- package/dist/daemon/consolidation.js +448 -0
- package/dist/daemon/consolidation.js.map +1 -0
- package/dist/daemon/extraction.d.ts +17 -0
- package/dist/daemon/extraction.d.ts.map +1 -0
- package/dist/daemon/extraction.js +465 -0
- package/dist/daemon/extraction.js.map +1 -0
- package/dist/daemon/index.d.ts +3 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +3 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/loop.d.ts +3 -0
- package/dist/daemon/loop.d.ts.map +1 -0
- package/dist/daemon/loop.js +93 -0
- package/dist/daemon/loop.js.map +1 -0
- package/dist/daemon/qdrant.d.ts +103 -0
- package/dist/daemon/qdrant.d.ts.map +1 -0
- package/dist/daemon/qdrant.js +273 -0
- package/dist/daemon/qdrant.js.map +1 -0
- package/dist/daemon/qdrant.test.d.ts +8 -0
- package/dist/daemon/qdrant.test.d.ts.map +1 -0
- package/dist/daemon/qdrant.test.js +209 -0
- package/dist/daemon/qdrant.test.js.map +1 -0
- package/dist/daemon/relations.d.ts +54 -0
- package/dist/daemon/relations.d.ts.map +1 -0
- package/dist/daemon/relations.js +290 -0
- package/dist/daemon/relations.js.map +1 -0
- package/dist/daemon/staleness.d.ts +24 -0
- package/dist/daemon/staleness.d.ts.map +1 -0
- package/dist/daemon/staleness.js +63 -0
- package/dist/daemon/staleness.js.map +1 -0
- package/dist/daemon/watcher.d.ts +11 -0
- package/dist/daemon/watcher.d.ts.map +1 -0
- package/dist/daemon/watcher.js +38 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/daemon/watcher.test.d.ts +8 -0
- package/dist/daemon/watcher.test.d.ts.map +1 -0
- package/dist/daemon/watcher.test.js +214 -0
- package/dist/daemon/watcher.test.js.map +1 -0
- package/dist/install.d.ts +5 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +49 -0
- package/dist/install.js.map +1 -0
- package/dist/install.test.d.ts +9 -0
- package/dist/install.test.d.ts.map +1 -0
- package/dist/install.test.js +126 -0
- package/dist/install.test.js.map +1 -0
- package/dist/llm/embedding.d.ts +13 -0
- package/dist/llm/embedding.d.ts.map +1 -0
- package/dist/llm/embedding.js +127 -0
- package/dist/llm/embedding.js.map +1 -0
- package/dist/llm/embedding.test.d.ts +8 -0
- package/dist/llm/embedding.test.d.ts.map +1 -0
- package/dist/llm/embedding.test.js +117 -0
- package/dist/llm/embedding.test.js.map +1 -0
- package/dist/llm/index.d.ts +4 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +3 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/inference.d.ts +12 -0
- package/dist/llm/inference.d.ts.map +1 -0
- package/dist/llm/inference.js +146 -0
- package/dist/llm/inference.js.map +1 -0
- package/dist/llm/inference.test.d.ts +8 -0
- package/dist/llm/inference.test.d.ts.map +1 -0
- package/dist/llm/inference.test.js +117 -0
- package/dist/llm/inference.test.js.map +1 -0
- package/dist/llm/types.d.ts +41 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +5 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +41 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/api.d.ts +30 -0
- package/dist/mcp/api.d.ts.map +1 -0
- package/dist/mcp/api.js +150 -0
- package/dist/mcp/api.js.map +1 -0
- package/dist/mcp/helpers.d.ts +35 -0
- package/dist/mcp/helpers.d.ts.map +1 -0
- package/dist/mcp/helpers.js +152 -0
- package/dist/mcp/helpers.js.map +1 -0
- package/dist/mcp/helpers.test.d.ts +5 -0
- package/dist/mcp/helpers.test.d.ts.map +1 -0
- package/dist/mcp/helpers.test.js +487 -0
- package/dist/mcp/helpers.test.js.map +1 -0
- package/dist/mcp/index.d.ts +9 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +67 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/taxonomy.d.ts +38 -0
- package/dist/mcp/taxonomy.d.ts.map +1 -0
- package/dist/mcp/taxonomy.js +223 -0
- package/dist/mcp/taxonomy.js.map +1 -0
- package/dist/mcp/taxonomy.test.d.ts +5 -0
- package/dist/mcp/taxonomy.test.d.ts.map +1 -0
- package/dist/mcp/taxonomy.test.js +341 -0
- package/dist/mcp/taxonomy.test.js.map +1 -0
- package/dist/mcp/tools.d.ts +6 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +958 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +118 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +5 -0
- package/dist/mcp/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for pure helper functions in the Memory MCP server.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { contentHash, daysSince, lastActivityDate, computeEffectiveConfidence, computeFreshnessScore, computeReinforcementScore, computeCombinedScore, isStale, buildFilter, formatFact, } from "./helpers.js";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Factory helpers for building test payloads
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
function makePayload(overrides = {}) {
|
|
11
|
+
return {
|
|
12
|
+
content: "test content",
|
|
13
|
+
category: "infrastructure",
|
|
14
|
+
domain: "work",
|
|
15
|
+
kind: "fact",
|
|
16
|
+
entities: ["test"],
|
|
17
|
+
source: "agent",
|
|
18
|
+
confidence: 0.9,
|
|
19
|
+
importance: 0.5,
|
|
20
|
+
content_hash: "abc123",
|
|
21
|
+
reinforcement_count: 1,
|
|
22
|
+
last_reinforced_at: new Date().toISOString(),
|
|
23
|
+
superseded_by: null,
|
|
24
|
+
superseded_at: null,
|
|
25
|
+
created_at: new Date().toISOString(),
|
|
26
|
+
updated_at: new Date().toISOString(),
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function makePoint(overrides = {}, payloadOverrides = {}) {
|
|
31
|
+
return {
|
|
32
|
+
id: "test-id",
|
|
33
|
+
score: 0.85,
|
|
34
|
+
payload: makePayload(payloadOverrides),
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// contentHash
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
describe("contentHash", () => {
|
|
42
|
+
it("returns a hex string", () => {
|
|
43
|
+
const hash = contentHash("infrastructure", "some content");
|
|
44
|
+
assert.match(hash, /^[a-f0-9]{64}$/);
|
|
45
|
+
});
|
|
46
|
+
it("is deterministic — same input produces same hash", () => {
|
|
47
|
+
const a = contentHash("decisions", "we chose X");
|
|
48
|
+
const b = contentHash("decisions", "we chose X");
|
|
49
|
+
assert.strictEqual(a, b);
|
|
50
|
+
});
|
|
51
|
+
it("is case-insensitive", () => {
|
|
52
|
+
const a = contentHash("infrastructure", "ClickHouse port 8123");
|
|
53
|
+
const b = contentHash("infrastructure", "clickhouse port 8123");
|
|
54
|
+
assert.strictEqual(a, b);
|
|
55
|
+
});
|
|
56
|
+
it("normalizes whitespace", () => {
|
|
57
|
+
const a = contentHash("observation", "hello world");
|
|
58
|
+
const b = contentHash("observation", "hello world");
|
|
59
|
+
assert.strictEqual(a, b);
|
|
60
|
+
});
|
|
61
|
+
it("trims leading/trailing whitespace", () => {
|
|
62
|
+
const a = contentHash("observation", " hello world ");
|
|
63
|
+
const b = contentHash("observation", "hello world");
|
|
64
|
+
assert.strictEqual(a, b);
|
|
65
|
+
});
|
|
66
|
+
it("different categories produce different hashes", () => {
|
|
67
|
+
const a = contentHash("infrastructure", "content");
|
|
68
|
+
const b = contentHash("decisions", "content");
|
|
69
|
+
assert.notStrictEqual(a, b);
|
|
70
|
+
});
|
|
71
|
+
it("different content produces different hashes", () => {
|
|
72
|
+
const a = contentHash("infrastructure", "content A");
|
|
73
|
+
const b = contentHash("infrastructure", "content B");
|
|
74
|
+
assert.notStrictEqual(a, b);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// daysSince
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
describe("daysSince", () => {
|
|
81
|
+
it("returns Infinity for null", () => {
|
|
82
|
+
assert.strictEqual(daysSince(null), Infinity);
|
|
83
|
+
});
|
|
84
|
+
it("returns Infinity for undefined", () => {
|
|
85
|
+
assert.strictEqual(daysSince(undefined), Infinity);
|
|
86
|
+
});
|
|
87
|
+
it("returns 0 for future dates", () => {
|
|
88
|
+
const future = new Date(Date.now() + 86400000 * 10).toISOString();
|
|
89
|
+
assert.strictEqual(daysSince(future), 0);
|
|
90
|
+
});
|
|
91
|
+
it("returns positive number for past dates", () => {
|
|
92
|
+
const daysAgo10 = new Date(Date.now() - 86400000 * 10).toISOString();
|
|
93
|
+
const result = daysSince(daysAgo10);
|
|
94
|
+
assert.ok(result > 9.9 && result < 10.1);
|
|
95
|
+
});
|
|
96
|
+
it("returns ~0 for now", () => {
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
const result = daysSince(now);
|
|
99
|
+
assert.ok(result >= 0 && result < 0.01);
|
|
100
|
+
});
|
|
101
|
+
it("returns ~365 for one year ago", () => {
|
|
102
|
+
const oneYearAgo = new Date(Date.now() - 86400000 * 365).toISOString();
|
|
103
|
+
const result = daysSince(oneYearAgo);
|
|
104
|
+
assert.ok(result > 364.9 && result < 365.1);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// lastActivityDate
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
describe("lastActivityDate", () => {
|
|
111
|
+
it("returns last_verified_at when present", () => {
|
|
112
|
+
const payload = makePayload({
|
|
113
|
+
last_verified_at: "2025-01-15T00:00:00Z",
|
|
114
|
+
last_reinforced_at: "2025-01-10T00:00:00Z",
|
|
115
|
+
created_at: "2025-01-01T00:00:00Z",
|
|
116
|
+
});
|
|
117
|
+
assert.strictEqual(lastActivityDate(payload), "2025-01-15T00:00:00Z");
|
|
118
|
+
});
|
|
119
|
+
it("falls back to last_reinforced_at when last_verified_at is undefined", () => {
|
|
120
|
+
const payload = makePayload({
|
|
121
|
+
last_verified_at: undefined,
|
|
122
|
+
last_reinforced_at: "2025-01-10T00:00:00Z",
|
|
123
|
+
created_at: "2025-01-01T00:00:00Z",
|
|
124
|
+
});
|
|
125
|
+
assert.strictEqual(lastActivityDate(payload), "2025-01-10T00:00:00Z");
|
|
126
|
+
});
|
|
127
|
+
it("falls back to created_at when both verified and reinforced are undefined", () => {
|
|
128
|
+
// Set last_reinforced_at to empty string — which is falsy for ?? operator? No, it's truthy.
|
|
129
|
+
// We need to actually use a payload where last_reinforced_at is missing.
|
|
130
|
+
const payload = {
|
|
131
|
+
content: "test",
|
|
132
|
+
category: "infrastructure",
|
|
133
|
+
entities: [],
|
|
134
|
+
confidence: 0.9,
|
|
135
|
+
content_hash: "abc",
|
|
136
|
+
reinforcement_count: 1,
|
|
137
|
+
last_reinforced_at: undefined,
|
|
138
|
+
superseded_by: null,
|
|
139
|
+
superseded_at: null,
|
|
140
|
+
created_at: "2025-01-01T00:00:00Z",
|
|
141
|
+
updated_at: "2025-01-01T00:00:00Z",
|
|
142
|
+
};
|
|
143
|
+
// Since last_reinforced_at is required in the interface but we're testing the runtime behavior
|
|
144
|
+
// with undefined, the function should fall through to created_at
|
|
145
|
+
const result = lastActivityDate(payload);
|
|
146
|
+
assert.strictEqual(result, "2025-01-01T00:00:00Z");
|
|
147
|
+
});
|
|
148
|
+
it("returns undefined when no dates are present", () => {
|
|
149
|
+
const payload = {
|
|
150
|
+
content: "test",
|
|
151
|
+
category: "infrastructure",
|
|
152
|
+
entities: [],
|
|
153
|
+
confidence: 0.9,
|
|
154
|
+
content_hash: "abc",
|
|
155
|
+
reinforcement_count: 1,
|
|
156
|
+
last_reinforced_at: undefined,
|
|
157
|
+
superseded_by: null,
|
|
158
|
+
superseded_at: null,
|
|
159
|
+
created_at: undefined,
|
|
160
|
+
updated_at: undefined,
|
|
161
|
+
};
|
|
162
|
+
const result = lastActivityDate(payload);
|
|
163
|
+
assert.strictEqual(result, undefined);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// computeEffectiveConfidence
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
describe("computeEffectiveConfidence", () => {
|
|
170
|
+
it("returns original confidence for recent facts", () => {
|
|
171
|
+
const payload = makePayload({
|
|
172
|
+
confidence: 0.9,
|
|
173
|
+
last_reinforced_at: new Date().toISOString(),
|
|
174
|
+
});
|
|
175
|
+
const effective = computeEffectiveConfidence(payload);
|
|
176
|
+
assert.strictEqual(effective, 0.9);
|
|
177
|
+
});
|
|
178
|
+
it("decays confidence for old facts", () => {
|
|
179
|
+
const payload = makePayload({
|
|
180
|
+
category: "infrastructure",
|
|
181
|
+
confidence: 0.9,
|
|
182
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 60).toISOString(), // 60 days ago
|
|
183
|
+
last_verified_at: undefined,
|
|
184
|
+
});
|
|
185
|
+
const effective = computeEffectiveConfidence(payload);
|
|
186
|
+
assert.ok(effective < 0.9);
|
|
187
|
+
assert.ok(effective > 0);
|
|
188
|
+
});
|
|
189
|
+
it("returns ~50% confidence at half-life", () => {
|
|
190
|
+
// infrastructure half-life is 60 days
|
|
191
|
+
const payload = makePayload({
|
|
192
|
+
category: "infrastructure",
|
|
193
|
+
confidence: 1.0,
|
|
194
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 60).toISOString(),
|
|
195
|
+
last_verified_at: undefined,
|
|
196
|
+
});
|
|
197
|
+
const effective = computeEffectiveConfidence(payload);
|
|
198
|
+
assert.ok(effective >= 0.45 && effective <= 0.55, `Expected ~0.5, got ${effective}`);
|
|
199
|
+
});
|
|
200
|
+
it("different categories have different decay rates", () => {
|
|
201
|
+
const dayOffset = 86400000 * 90; // 90 days
|
|
202
|
+
const pastDate = new Date(Date.now() - dayOffset).toISOString();
|
|
203
|
+
const infraPayload = makePayload({
|
|
204
|
+
category: "infrastructure",
|
|
205
|
+
confidence: 0.9,
|
|
206
|
+
last_reinforced_at: pastDate,
|
|
207
|
+
last_verified_at: undefined,
|
|
208
|
+
});
|
|
209
|
+
const prefsPayload = makePayload({
|
|
210
|
+
category: "preferences",
|
|
211
|
+
confidence: 0.9,
|
|
212
|
+
last_reinforced_at: pastDate,
|
|
213
|
+
last_verified_at: undefined,
|
|
214
|
+
});
|
|
215
|
+
const infraEffective = computeEffectiveConfidence(infraPayload);
|
|
216
|
+
const prefsEffective = computeEffectiveConfidence(prefsPayload);
|
|
217
|
+
// preferences decay slower (half-life 365) than infrastructure (half-life 60)
|
|
218
|
+
assert.ok(prefsEffective > infraEffective, `preferences (${prefsEffective}) should decay slower than infrastructure (${infraEffective})`);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// computeFreshnessScore
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
describe("computeFreshnessScore", () => {
|
|
225
|
+
it("returns 1.0 for facts < 7 days old", () => {
|
|
226
|
+
const payload = makePayload({
|
|
227
|
+
last_reinforced_at: new Date().toISOString(),
|
|
228
|
+
});
|
|
229
|
+
assert.strictEqual(computeFreshnessScore(payload), 1.0);
|
|
230
|
+
});
|
|
231
|
+
it("returns 1.0 at exactly 7 days", () => {
|
|
232
|
+
const payload = makePayload({
|
|
233
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 7).toISOString(),
|
|
234
|
+
last_verified_at: undefined,
|
|
235
|
+
});
|
|
236
|
+
const score = computeFreshnessScore(payload);
|
|
237
|
+
assert.ok(score >= 0.99 && score <= 1.0, `Expected ~1.0, got ${score}`);
|
|
238
|
+
});
|
|
239
|
+
it("returns 0.3 for facts >= 180 days old", () => {
|
|
240
|
+
const payload = makePayload({
|
|
241
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 200).toISOString(),
|
|
242
|
+
last_verified_at: undefined,
|
|
243
|
+
});
|
|
244
|
+
assert.strictEqual(computeFreshnessScore(payload), 0.3);
|
|
245
|
+
});
|
|
246
|
+
it("returns value between 0.3 and 1.0 for facts between 7 and 180 days", () => {
|
|
247
|
+
const payload = makePayload({
|
|
248
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 90).toISOString(),
|
|
249
|
+
last_verified_at: undefined,
|
|
250
|
+
});
|
|
251
|
+
const score = computeFreshnessScore(payload);
|
|
252
|
+
assert.ok(score > 0.3 && score < 1.0, `Expected between 0.3 and 1.0, got ${score}`);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// computeReinforcementScore
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
describe("computeReinforcementScore", () => {
|
|
259
|
+
it("returns 0.2 for count=1", () => {
|
|
260
|
+
const payload = makePayload({ reinforcement_count: 1 });
|
|
261
|
+
assert.strictEqual(computeReinforcementScore(payload), 0.2);
|
|
262
|
+
});
|
|
263
|
+
it("returns 1.0 for count>=5", () => {
|
|
264
|
+
const payload = makePayload({ reinforcement_count: 5 });
|
|
265
|
+
assert.strictEqual(computeReinforcementScore(payload), 1.0);
|
|
266
|
+
});
|
|
267
|
+
it("returns 1.0 for count>5", () => {
|
|
268
|
+
const payload = makePayload({ reinforcement_count: 10 });
|
|
269
|
+
assert.strictEqual(computeReinforcementScore(payload), 1.0);
|
|
270
|
+
});
|
|
271
|
+
it("returns 0.6 for count=3", () => {
|
|
272
|
+
const payload = makePayload({ reinforcement_count: 3 });
|
|
273
|
+
assert.strictEqual(computeReinforcementScore(payload), 0.6);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
// computeCombinedScore
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
describe("computeCombinedScore", () => {
|
|
280
|
+
it("returns a number between 0 and ~1.5", () => {
|
|
281
|
+
const point = makePoint({ score: 0.85 });
|
|
282
|
+
const score = computeCombinedScore(point);
|
|
283
|
+
assert.ok(typeof score === "number");
|
|
284
|
+
assert.ok(score >= 0);
|
|
285
|
+
});
|
|
286
|
+
it("higher vector score produces higher combined score", () => {
|
|
287
|
+
const highScorePoint = makePoint({ score: 0.95 });
|
|
288
|
+
const lowScorePoint = makePoint({ score: 0.5 });
|
|
289
|
+
assert.ok(computeCombinedScore(highScorePoint) > computeCombinedScore(lowScorePoint));
|
|
290
|
+
});
|
|
291
|
+
it("uses importance from payload", () => {
|
|
292
|
+
const highImportance = makePoint({}, { importance: 1.0 });
|
|
293
|
+
const lowImportance = makePoint({}, { importance: 0.0 });
|
|
294
|
+
assert.ok(computeCombinedScore(highImportance) > computeCombinedScore(lowImportance));
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
// isStale
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
describe("isStale", () => {
|
|
301
|
+
it("returns false for recent facts", () => {
|
|
302
|
+
const payload = makePayload({
|
|
303
|
+
last_reinforced_at: new Date().toISOString(),
|
|
304
|
+
});
|
|
305
|
+
assert.strictEqual(isStale(payload), false);
|
|
306
|
+
});
|
|
307
|
+
it("returns true for facts older than STALENESS_DAYS", () => {
|
|
308
|
+
const payload = makePayload({
|
|
309
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 45).toISOString(),
|
|
310
|
+
last_verified_at: undefined,
|
|
311
|
+
});
|
|
312
|
+
assert.strictEqual(isStale(payload), true);
|
|
313
|
+
});
|
|
314
|
+
it("uses last_verified_at when more recent", () => {
|
|
315
|
+
const payload = makePayload({
|
|
316
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 45).toISOString(), // 45 days ago
|
|
317
|
+
last_verified_at: new Date().toISOString(), // now
|
|
318
|
+
});
|
|
319
|
+
assert.strictEqual(isStale(payload), false);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
// buildFilter
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
describe("buildFilter", () => {
|
|
326
|
+
it("returns undefined for empty params", () => {
|
|
327
|
+
// Note: excludeSuperseded defaults to true, so we set it to false for this test
|
|
328
|
+
const result = buildFilter({ excludeSuperseded: false });
|
|
329
|
+
assert.strictEqual(result, undefined);
|
|
330
|
+
});
|
|
331
|
+
it("excludes superseded by default", () => {
|
|
332
|
+
const result = buildFilter({});
|
|
333
|
+
assert.ok(result);
|
|
334
|
+
assert.ok(result.must.length >= 1);
|
|
335
|
+
const supersededFilter = result.must.find((c) => c.is_null && c.is_null.key === "superseded_by");
|
|
336
|
+
assert.ok(supersededFilter);
|
|
337
|
+
});
|
|
338
|
+
it("adds category filter", () => {
|
|
339
|
+
const result = buildFilter({ category: "infrastructure" });
|
|
340
|
+
assert.ok(result);
|
|
341
|
+
const catFilter = result.must.find((c) => c.key === "category");
|
|
342
|
+
assert.ok(catFilter);
|
|
343
|
+
assert.deepStrictEqual(catFilter.match, { value: "infrastructure" });
|
|
344
|
+
});
|
|
345
|
+
it("adds domain filter", () => {
|
|
346
|
+
const result = buildFilter({ domain: "personal" });
|
|
347
|
+
assert.ok(result);
|
|
348
|
+
const domFilter = result.must.find((c) => c.key === "domain");
|
|
349
|
+
assert.ok(domFilter);
|
|
350
|
+
assert.deepStrictEqual(domFilter.match, { value: "personal" });
|
|
351
|
+
});
|
|
352
|
+
it("adds kind filter", () => {
|
|
353
|
+
const result = buildFilter({ kind: "summary" });
|
|
354
|
+
assert.ok(result);
|
|
355
|
+
const kindFilter = result.must.find((c) => c.key === "kind");
|
|
356
|
+
assert.ok(kindFilter);
|
|
357
|
+
assert.deepStrictEqual(kindFilter.match, { value: "summary" });
|
|
358
|
+
});
|
|
359
|
+
it("adds entity filter (lowercased)", () => {
|
|
360
|
+
const result = buildFilter({ entity: "ClickHouse" });
|
|
361
|
+
assert.ok(result);
|
|
362
|
+
const entityFilter = result.must.find((c) => c.key === "entities");
|
|
363
|
+
assert.ok(entityFilter);
|
|
364
|
+
assert.deepStrictEqual(entityFilter.match, { value: "clickhouse" });
|
|
365
|
+
});
|
|
366
|
+
it("adds since filter with range gte", () => {
|
|
367
|
+
const result = buildFilter({ since: "2025-01-01T00:00:00Z" });
|
|
368
|
+
assert.ok(result);
|
|
369
|
+
const dateFilter = result.must.find((c) => c.key === "created_at");
|
|
370
|
+
assert.ok(dateFilter);
|
|
371
|
+
assert.strictEqual(dateFilter.range?.gte, "2025-01-01T00:00:00Z");
|
|
372
|
+
});
|
|
373
|
+
it("adds until filter with range lte", () => {
|
|
374
|
+
const result = buildFilter({ until: "2025-12-31T23:59:59Z" });
|
|
375
|
+
assert.ok(result);
|
|
376
|
+
const dateFilter = result.must.find((c) => c.key === "created_at");
|
|
377
|
+
assert.ok(dateFilter);
|
|
378
|
+
assert.strictEqual(dateFilter.range?.lte, "2025-12-31T23:59:59Z");
|
|
379
|
+
});
|
|
380
|
+
it("combines since and until into a single range", () => {
|
|
381
|
+
const result = buildFilter({
|
|
382
|
+
since: "2025-01-01T00:00:00Z",
|
|
383
|
+
until: "2025-06-01T00:00:00Z",
|
|
384
|
+
});
|
|
385
|
+
assert.ok(result);
|
|
386
|
+
const dateFilter = result.must.find((c) => c.key === "created_at");
|
|
387
|
+
assert.ok(dateFilter);
|
|
388
|
+
assert.strictEqual(dateFilter.range?.gte, "2025-01-01T00:00:00Z");
|
|
389
|
+
assert.strictEqual(dateFilter.range?.lte, "2025-06-01T00:00:00Z");
|
|
390
|
+
});
|
|
391
|
+
it("adds metadata filters", () => {
|
|
392
|
+
const result = buildFilter({
|
|
393
|
+
metadata: { session_id: "abc123", task_slug: "fix-bug" },
|
|
394
|
+
});
|
|
395
|
+
assert.ok(result);
|
|
396
|
+
const sessionFilter = result.must.find((c) => c.key === "metadata.session_id");
|
|
397
|
+
assert.ok(sessionFilter);
|
|
398
|
+
assert.deepStrictEqual(sessionFilter.match, { value: "abc123" });
|
|
399
|
+
const taskFilter = result.must.find((c) => c.key === "metadata.task_slug");
|
|
400
|
+
assert.ok(taskFilter);
|
|
401
|
+
assert.deepStrictEqual(taskFilter.match, { value: "fix-bug" });
|
|
402
|
+
});
|
|
403
|
+
it("combines all filters together", () => {
|
|
404
|
+
const result = buildFilter({
|
|
405
|
+
category: "infrastructure",
|
|
406
|
+
domain: "work",
|
|
407
|
+
kind: "fact",
|
|
408
|
+
entity: "redis",
|
|
409
|
+
since: "2025-01-01T00:00:00Z",
|
|
410
|
+
metadata: { source: "test" },
|
|
411
|
+
});
|
|
412
|
+
assert.ok(result);
|
|
413
|
+
// superseded (default) + category + domain + kind + entity + since + metadata
|
|
414
|
+
assert.strictEqual(result.must.length, 7);
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
// formatFact
|
|
419
|
+
// ---------------------------------------------------------------------------
|
|
420
|
+
describe("formatFact", () => {
|
|
421
|
+
it("includes category and content", () => {
|
|
422
|
+
const point = makePoint({}, { category: "infrastructure", content: "Redis on port 6379" });
|
|
423
|
+
const formatted = formatFact(point);
|
|
424
|
+
assert.ok(formatted.includes("[infrastructure]"));
|
|
425
|
+
assert.ok(formatted.includes("Redis on port 6379"));
|
|
426
|
+
});
|
|
427
|
+
it("includes entities when present", () => {
|
|
428
|
+
const point = makePoint({}, { entities: ["redis", "cache"] });
|
|
429
|
+
const formatted = formatFact(point);
|
|
430
|
+
assert.ok(formatted.includes("entities: redis, cache"));
|
|
431
|
+
});
|
|
432
|
+
it("includes point id", () => {
|
|
433
|
+
const point = makePoint({ id: "my-uuid-123" });
|
|
434
|
+
const formatted = formatFact(point);
|
|
435
|
+
assert.ok(formatted.includes("id: my-uuid-123"));
|
|
436
|
+
});
|
|
437
|
+
it("includes score when present", () => {
|
|
438
|
+
const point = makePoint({ score: 0.856 });
|
|
439
|
+
const formatted = formatFact(point);
|
|
440
|
+
assert.ok(formatted.includes("score: 0.856"));
|
|
441
|
+
});
|
|
442
|
+
it("includes rank when _combinedScore is present", () => {
|
|
443
|
+
const point = makePoint({ _combinedScore: 0.723 });
|
|
444
|
+
const formatted = formatFact(point);
|
|
445
|
+
assert.ok(formatted.includes("rank: 0.723"));
|
|
446
|
+
});
|
|
447
|
+
it("includes domain when not 'work'", () => {
|
|
448
|
+
const point = makePoint({}, { domain: "personal" });
|
|
449
|
+
const formatted = formatFact(point);
|
|
450
|
+
assert.ok(formatted.includes("domain: personal"));
|
|
451
|
+
});
|
|
452
|
+
it("does not include domain when 'work'", () => {
|
|
453
|
+
const point = makePoint({}, { domain: "work" });
|
|
454
|
+
const formatted = formatFact(point);
|
|
455
|
+
assert.ok(!formatted.includes("domain:"));
|
|
456
|
+
});
|
|
457
|
+
it("includes kind when not 'fact'", () => {
|
|
458
|
+
const point = makePoint({}, { kind: "summary" });
|
|
459
|
+
const formatted = formatFact(point);
|
|
460
|
+
assert.ok(formatted.includes("kind: summary"));
|
|
461
|
+
});
|
|
462
|
+
it("includes stale emoji for old facts", () => {
|
|
463
|
+
const point = makePoint({}, {
|
|
464
|
+
last_reinforced_at: new Date(Date.now() - 86400000 * 45).toISOString(),
|
|
465
|
+
last_verified_at: undefined,
|
|
466
|
+
});
|
|
467
|
+
const formatted = formatFact(point);
|
|
468
|
+
assert.ok(formatted.includes("🕰️"));
|
|
469
|
+
});
|
|
470
|
+
it("includes metadata when present", () => {
|
|
471
|
+
const point = makePoint({}, { metadata: { session_id: "abc" } });
|
|
472
|
+
const formatted = formatFact(point);
|
|
473
|
+
assert.ok(formatted.includes("metadata:"));
|
|
474
|
+
assert.ok(formatted.includes("session_id=abc"));
|
|
475
|
+
});
|
|
476
|
+
it("includes reinforced count when > 1", () => {
|
|
477
|
+
const point = makePoint({}, { reinforcement_count: 3 });
|
|
478
|
+
const formatted = formatFact(point);
|
|
479
|
+
assert.ok(formatted.includes("reinforced: 3x"));
|
|
480
|
+
});
|
|
481
|
+
it("includes verified count when > 0", () => {
|
|
482
|
+
const point = makePoint({}, { verification_count: 2 });
|
|
483
|
+
const formatted = formatFact(point);
|
|
484
|
+
assert.ok(formatted.includes("verified: 2x"));
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
//# sourceMappingURL=helpers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.test.js","sourceRoot":"","sources":["../../src/mcp/helpers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bikky MCP Server — episodic memory via Qdrant Cloud.
|
|
3
|
+
*
|
|
4
|
+
* Provides persistent memory across AI coding sessions. All facts, relations,
|
|
5
|
+
* and entity context live as Qdrant points with vector embeddings + structured
|
|
6
|
+
* payloads. Config stored in ~/.bikky/config.json.
|
|
7
|
+
*/
|
|
8
|
+
export declare function startMcpServer(): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAyDpD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bikky MCP Server — episodic memory via Qdrant Cloud.
|
|
3
|
+
*
|
|
4
|
+
* Provides persistent memory across AI coding sessions. All facts, relations,
|
|
5
|
+
* and entity context live as Qdrant points with vector embeddings + structured
|
|
6
|
+
* payloads. Config stored in ~/.bikky/config.json.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import { QDRANT_INDEXES } from "./taxonomy.js";
|
|
11
|
+
import { log, setQdrantUrl, setQdrantApiKey, setReady, setCollection, ensureCollection, initEmbedding, } from "./api.js";
|
|
12
|
+
import { registerTools } from "./tools.js";
|
|
13
|
+
import { loadConfig } from "../config.js";
|
|
14
|
+
export async function startMcpServer() {
|
|
15
|
+
log("INFO", `Starting bikky MCP server (PID ${process.pid})`);
|
|
16
|
+
const cfg = loadConfig();
|
|
17
|
+
// Resolve credentials from config (which already merges env vars)
|
|
18
|
+
const qUrl = cfg.qdrant_url?.replace(/\/+$/, "") || null;
|
|
19
|
+
const qKey = cfg.qdrant_api_key || null;
|
|
20
|
+
setQdrantUrl(qUrl);
|
|
21
|
+
setQdrantApiKey(qKey);
|
|
22
|
+
setCollection(cfg.collection);
|
|
23
|
+
// Initialize embedding provider
|
|
24
|
+
const embCfg = initEmbedding({
|
|
25
|
+
provider: cfg.embedding.provider,
|
|
26
|
+
baseUrl: cfg.embedding.base_url,
|
|
27
|
+
model: cfg.embedding.model,
|
|
28
|
+
dimensions: cfg.embedding.dimensions,
|
|
29
|
+
apiKey: cfg.embedding.api_key ?? null,
|
|
30
|
+
});
|
|
31
|
+
log("INFO", `Embedding: ${embCfg.provider}/${embCfg.model} (${embCfg.dimensions}d) @ ${embCfg.baseUrl || "(sdk)"}`);
|
|
32
|
+
if (qUrl && qKey) {
|
|
33
|
+
try {
|
|
34
|
+
await ensureCollection(QDRANT_INDEXES);
|
|
35
|
+
setReady(true);
|
|
36
|
+
log("INFO", "Memory system ready ✓");
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
log("ERROR", `Failed to initialize collection: ${e instanceof Error ? e.message : String(e)}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const missing = [];
|
|
44
|
+
if (!qUrl)
|
|
45
|
+
missing.push("qdrant-url");
|
|
46
|
+
if (!qKey)
|
|
47
|
+
missing.push("qdrant-api-key");
|
|
48
|
+
log("INFO", `Memory not configured — missing: ${missing.join(", ")}. Use get_setup_status + configure_credentials.`);
|
|
49
|
+
}
|
|
50
|
+
const mcp = new McpServer({
|
|
51
|
+
name: "bikky",
|
|
52
|
+
version: "0.1.0",
|
|
53
|
+
}, {
|
|
54
|
+
instructions: "Shared memory tools for AI coding sessions. Store and recall facts, entities, and relationships across sessions.",
|
|
55
|
+
});
|
|
56
|
+
registerTools(mcp);
|
|
57
|
+
const transport = new StdioServerTransport();
|
|
58
|
+
await mcp.connect(transport);
|
|
59
|
+
log("INFO", "MCP server connected on stdio");
|
|
60
|
+
for (const sig of ["SIGTERM", "SIGINT"]) {
|
|
61
|
+
process.on(sig, () => {
|
|
62
|
+
log("INFO", `Received ${sig}, shutting down...`);
|
|
63
|
+
process.exit(0);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Taxonomy — Single source of truth for all classification axes.
|
|
3
|
+
*
|
|
4
|
+
* Four orthogonal axes classify every fact:
|
|
5
|
+
* category — topic/subject matter (what the fact is about)
|
|
6
|
+
* domain — life scope (work vs personal context)
|
|
7
|
+
* kind — epistemic type (how the knowledge exists)
|
|
8
|
+
* source — provenance (who/what created this fact)
|
|
9
|
+
*/
|
|
10
|
+
import type { AxisDef, CategoryDef, QdrantIndex } from "./types.js";
|
|
11
|
+
export declare const CATEGORIES: Record<string, CategoryDef>;
|
|
12
|
+
export declare const DOMAINS: Record<string, AxisDef>;
|
|
13
|
+
export declare const DEFAULT_DOMAIN = "work";
|
|
14
|
+
export declare const KINDS: Record<string, AxisDef>;
|
|
15
|
+
export declare const DEFAULT_KIND = "fact";
|
|
16
|
+
export declare const SOURCES: Record<string, AxisDef>;
|
|
17
|
+
export declare const DEFAULT_SOURCE = "agent";
|
|
18
|
+
export declare const DECAY_DEFAULT_HALF_LIFE = 90;
|
|
19
|
+
export declare function getDecayHalfLife(opts?: {
|
|
20
|
+
kind?: string;
|
|
21
|
+
category?: string;
|
|
22
|
+
domain?: string;
|
|
23
|
+
}): number | null;
|
|
24
|
+
export declare const DECAY_HALF_LIFE: Record<string, number | null>;
|
|
25
|
+
export declare const STALENESS_DAYS = 30;
|
|
26
|
+
export declare const THRESHOLD_DUPLICATE = 0.92;
|
|
27
|
+
export declare const THRESHOLD_RELATED = 0.8;
|
|
28
|
+
export declare const QDRANT_INDEXES: QdrantIndex[];
|
|
29
|
+
export declare const SOURCE_MIGRATION: Record<string, string>;
|
|
30
|
+
export declare function normalizeCategory(cat: string): string;
|
|
31
|
+
export declare function normalizeDomain(d: string | undefined): string;
|
|
32
|
+
export declare function normalizeKind(k: string | undefined): string;
|
|
33
|
+
export declare function normalizeSource(s: string | undefined): string;
|
|
34
|
+
export declare const categoryValues: () => [string, ...string[]];
|
|
35
|
+
export declare const domainValues: () => [string, ...string[]];
|
|
36
|
+
export declare const kindValues: () => [string, ...string[]];
|
|
37
|
+
export declare const sourceValues: () => [string, ...string[]];
|
|
38
|
+
//# sourceMappingURL=taxonomy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taxonomy.d.ts","sourceRoot":"","sources":["../../src/mcp/taxonomy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAIpE,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAwDlD,CAAC;AAIF,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAG3C,CAAC;AAEF,eAAO,MAAM,cAAc,SAAS,CAAC;AAIrC,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAKzC,CAAC;AAEF,eAAO,MAAM,YAAY,SAAS,CAAC;AAInC,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAM3C,CAAC;AAEF,eAAO,MAAM,cAAc,UAAU,CAAC;AAgBtC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,wBAAgB,gBAAgB,CAAC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,GAAG,IAAI,CAehH;AAGD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAWzD,CAAC;AAIF,eAAO,MAAM,cAAc,KAAK,CAAC;AAIjC,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,iBAAiB,MAAO,CAAC;AAItC,eAAO,MAAM,cAAc,EAAE,WAAW,EAcvC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMnD,CAAC;AAIF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAcrD;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAM7D;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQ3D;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAO7D;AAID,eAAO,MAAM,cAAc,QAAO,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CACJ,CAAC;AAEnD,eAAO,MAAM,YAAY,QAAO,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CACL,CAAC;AAEhD,eAAO,MAAM,UAAU,QAAO,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CACL,CAAC;AAE9C,eAAO,MAAM,YAAY,QAAO,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CACL,CAAC"}
|