@ulrichc1/sparn 1.0.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 +21 -0
- package/PRIVACY.md +350 -0
- package/README.md +683 -0
- package/SECURITY.md +247 -0
- package/dist/cli/index.cjs +1897 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1868 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +948 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +567 -0
- package/dist/index.d.ts +567 -0
- package/dist/index.js +900 -0
- package/dist/index.js.map +1 -0
- package/package.json +77 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,948 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
34
|
+
createBTSPEmbedder: () => createBTSPEmbedder,
|
|
35
|
+
createClaudeCodeAdapter: () => createClaudeCodeAdapter,
|
|
36
|
+
createConfidenceStates: () => createConfidenceStates,
|
|
37
|
+
createEngramScorer: () => createEngramScorer,
|
|
38
|
+
createGenericAdapter: () => createGenericAdapter,
|
|
39
|
+
createKVMemory: () => createKVMemory,
|
|
40
|
+
createLogger: () => createLogger,
|
|
41
|
+
createSleepCompressor: () => createSleepCompressor,
|
|
42
|
+
createSparsePruner: () => createSparsePruner,
|
|
43
|
+
estimateTokens: () => estimateTokens,
|
|
44
|
+
hashContent: () => hashContent
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(src_exports);
|
|
47
|
+
|
|
48
|
+
// src/adapters/claude-code.ts
|
|
49
|
+
var import_node_crypto3 = require("crypto");
|
|
50
|
+
|
|
51
|
+
// src/core/btsp-embedder.ts
|
|
52
|
+
var import_node_crypto2 = require("crypto");
|
|
53
|
+
|
|
54
|
+
// src/utils/hash.ts
|
|
55
|
+
var import_node_crypto = require("crypto");
|
|
56
|
+
function hashContent(content) {
|
|
57
|
+
return (0, import_node_crypto.createHash)("sha256").update(content, "utf8").digest("hex");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/core/btsp-embedder.ts
|
|
61
|
+
function createBTSPEmbedder() {
|
|
62
|
+
const BTSP_PATTERNS = [
|
|
63
|
+
// Error patterns
|
|
64
|
+
/\b(error|exception|failure|fatal|critical|panic)\b/i,
|
|
65
|
+
/\b(TypeError|ReferenceError|SyntaxError|RangeError|URIError)\b/,
|
|
66
|
+
/\bENOENT|EACCES|ECONNREFUSED|ETIMEDOUT\b/,
|
|
67
|
+
// Stack trace patterns
|
|
68
|
+
/^\s+at\s+.*\(.*:\d+:\d+\)/m,
|
|
69
|
+
// JavaScript stack trace
|
|
70
|
+
/^\s+at\s+.*\.[a-zA-Z]+:\d+/m,
|
|
71
|
+
// Python/Ruby stack trace
|
|
72
|
+
// Git diff new files
|
|
73
|
+
/^new file mode \d+$/m,
|
|
74
|
+
/^--- \/dev\/null$/m,
|
|
75
|
+
// Merge conflict markers
|
|
76
|
+
/^<<<<<<< /m,
|
|
77
|
+
/^=======/m,
|
|
78
|
+
/^>>>>>>> /m
|
|
79
|
+
];
|
|
80
|
+
function detectBTSP(content) {
|
|
81
|
+
return BTSP_PATTERNS.some((pattern) => pattern.test(content));
|
|
82
|
+
}
|
|
83
|
+
function createBTSPEntry(content, tags = [], metadata = {}) {
|
|
84
|
+
return {
|
|
85
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
86
|
+
content,
|
|
87
|
+
hash: hashContent(content),
|
|
88
|
+
timestamp: Date.now(),
|
|
89
|
+
score: 1,
|
|
90
|
+
// Maximum initial score
|
|
91
|
+
ttl: 365 * 24 * 3600,
|
|
92
|
+
// 1 year in seconds (long retention)
|
|
93
|
+
state: "active",
|
|
94
|
+
// Always active
|
|
95
|
+
accessCount: 0,
|
|
96
|
+
tags: [...tags, "btsp"],
|
|
97
|
+
metadata,
|
|
98
|
+
isBTSP: true
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
detectBTSP,
|
|
103
|
+
createBTSPEntry
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/core/confidence-states.ts
|
|
108
|
+
function createConfidenceStates(config) {
|
|
109
|
+
const { activeThreshold, readyThreshold } = config;
|
|
110
|
+
function calculateState(entry) {
|
|
111
|
+
if (entry.isBTSP) {
|
|
112
|
+
return "active";
|
|
113
|
+
}
|
|
114
|
+
if (entry.score > activeThreshold) {
|
|
115
|
+
return "active";
|
|
116
|
+
}
|
|
117
|
+
if (entry.score >= readyThreshold) {
|
|
118
|
+
return "ready";
|
|
119
|
+
}
|
|
120
|
+
return "silent";
|
|
121
|
+
}
|
|
122
|
+
function transition(entry) {
|
|
123
|
+
const newState = calculateState(entry);
|
|
124
|
+
return {
|
|
125
|
+
...entry,
|
|
126
|
+
state: newState
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function getDistribution(entries) {
|
|
130
|
+
const distribution = {
|
|
131
|
+
silent: 0,
|
|
132
|
+
ready: 0,
|
|
133
|
+
active: 0,
|
|
134
|
+
total: entries.length
|
|
135
|
+
};
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
const state = calculateState(entry);
|
|
138
|
+
distribution[state]++;
|
|
139
|
+
}
|
|
140
|
+
return distribution;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
calculateState,
|
|
144
|
+
transition,
|
|
145
|
+
getDistribution
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/core/engram-scorer.ts
|
|
150
|
+
function createEngramScorer(config) {
|
|
151
|
+
const { defaultTTL } = config;
|
|
152
|
+
function calculateDecay(ageInSeconds, ttlInSeconds) {
|
|
153
|
+
if (ttlInSeconds === 0) return 1;
|
|
154
|
+
if (ageInSeconds <= 0) return 0;
|
|
155
|
+
const ratio = ageInSeconds / ttlInSeconds;
|
|
156
|
+
const decay = 1 - Math.exp(-ratio);
|
|
157
|
+
return Math.max(0, Math.min(1, decay));
|
|
158
|
+
}
|
|
159
|
+
function calculateScore(entry, currentTime = Date.now()) {
|
|
160
|
+
const ageInMilliseconds = currentTime - entry.timestamp;
|
|
161
|
+
const ageInSeconds = Math.max(0, ageInMilliseconds / 1e3);
|
|
162
|
+
const decay = calculateDecay(ageInSeconds, entry.ttl);
|
|
163
|
+
let score = entry.score * (1 - decay);
|
|
164
|
+
if (entry.accessCount > 0) {
|
|
165
|
+
const accessBonus = Math.log(entry.accessCount + 1) * 0.1;
|
|
166
|
+
score = Math.min(1, score + accessBonus);
|
|
167
|
+
}
|
|
168
|
+
if (entry.isBTSP) {
|
|
169
|
+
score = Math.max(score, 0.9);
|
|
170
|
+
}
|
|
171
|
+
return Math.max(0, Math.min(1, score));
|
|
172
|
+
}
|
|
173
|
+
function refreshTTL(entry) {
|
|
174
|
+
return {
|
|
175
|
+
...entry,
|
|
176
|
+
ttl: defaultTTL * 3600,
|
|
177
|
+
// Convert hours to seconds
|
|
178
|
+
timestamp: Date.now()
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
calculateScore,
|
|
183
|
+
refreshTTL,
|
|
184
|
+
calculateDecay
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/utils/tokenizer.ts
|
|
189
|
+
function estimateTokens(text) {
|
|
190
|
+
if (!text || text.length === 0) {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
194
|
+
const wordCount = words.length;
|
|
195
|
+
const charCount = text.length;
|
|
196
|
+
const charEstimate = Math.ceil(charCount / 4);
|
|
197
|
+
const wordEstimate = Math.ceil(wordCount * 0.75);
|
|
198
|
+
return Math.max(wordEstimate, charEstimate);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/core/sparse-pruner.ts
|
|
202
|
+
function createSparsePruner(config) {
|
|
203
|
+
const { threshold } = config;
|
|
204
|
+
function tokenize(text) {
|
|
205
|
+
return text.toLowerCase().split(/\s+/).filter((word) => word.length > 0);
|
|
206
|
+
}
|
|
207
|
+
function calculateTF(term, tokens) {
|
|
208
|
+
const count = tokens.filter((t) => t === term).length;
|
|
209
|
+
return Math.sqrt(count);
|
|
210
|
+
}
|
|
211
|
+
function calculateIDF(term, allEntries) {
|
|
212
|
+
const totalDocs = allEntries.length;
|
|
213
|
+
const docsWithTerm = allEntries.filter((entry) => {
|
|
214
|
+
const tokens = tokenize(entry.content);
|
|
215
|
+
return tokens.includes(term);
|
|
216
|
+
}).length;
|
|
217
|
+
if (docsWithTerm === 0) return 0;
|
|
218
|
+
return Math.log(totalDocs / docsWithTerm);
|
|
219
|
+
}
|
|
220
|
+
function scoreEntry(entry, allEntries) {
|
|
221
|
+
const tokens = tokenize(entry.content);
|
|
222
|
+
if (tokens.length === 0) return 0;
|
|
223
|
+
const uniqueTerms = [...new Set(tokens)];
|
|
224
|
+
let totalScore = 0;
|
|
225
|
+
for (const term of uniqueTerms) {
|
|
226
|
+
const tf = calculateTF(term, tokens);
|
|
227
|
+
const idf = calculateIDF(term, allEntries);
|
|
228
|
+
totalScore += tf * idf;
|
|
229
|
+
}
|
|
230
|
+
return totalScore / tokens.length;
|
|
231
|
+
}
|
|
232
|
+
function prune(entries) {
|
|
233
|
+
if (entries.length === 0) {
|
|
234
|
+
return {
|
|
235
|
+
kept: [],
|
|
236
|
+
removed: [],
|
|
237
|
+
originalTokens: 0,
|
|
238
|
+
prunedTokens: 0
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const originalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);
|
|
242
|
+
const scored = entries.map((entry) => ({
|
|
243
|
+
entry,
|
|
244
|
+
score: scoreEntry(entry, entries)
|
|
245
|
+
}));
|
|
246
|
+
scored.sort((a, b) => b.score - a.score);
|
|
247
|
+
const keepCount = Math.max(1, Math.ceil(entries.length * (threshold / 100)));
|
|
248
|
+
const kept = scored.slice(0, keepCount).map((s) => s.entry);
|
|
249
|
+
const removed = scored.slice(keepCount).map((s) => s.entry);
|
|
250
|
+
const prunedTokens = kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);
|
|
251
|
+
return {
|
|
252
|
+
kept,
|
|
253
|
+
removed,
|
|
254
|
+
originalTokens,
|
|
255
|
+
prunedTokens
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
prune,
|
|
260
|
+
scoreEntry
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/adapters/claude-code.ts
|
|
265
|
+
var CLAUDE_CODE_PROFILE = {
|
|
266
|
+
// More aggressive pruning for tool results (they can be verbose)
|
|
267
|
+
toolResultThreshold: 3,
|
|
268
|
+
// Keep top 3% of tool results
|
|
269
|
+
// Preserve conversation turns more aggressively
|
|
270
|
+
conversationBoost: 1.5,
|
|
271
|
+
// 50% boost for User/Assistant exchanges
|
|
272
|
+
// Prioritize recent context (Claude Code sessions are typically focused)
|
|
273
|
+
recentContextWindow: 10 * 60,
|
|
274
|
+
// Last 10 minutes gets priority
|
|
275
|
+
// BTSP patterns specific to Claude Code
|
|
276
|
+
btspPatterns: [
|
|
277
|
+
// Error patterns
|
|
278
|
+
/\b(error|exception|failure|fatal|critical|panic)\b/i,
|
|
279
|
+
/^\s+at\s+.*\(.*:\d+:\d+\)/m,
|
|
280
|
+
// Stack traces
|
|
281
|
+
/^Error:/m,
|
|
282
|
+
// Git conflict markers
|
|
283
|
+
/^<<<<<<< /m,
|
|
284
|
+
/^=======/m,
|
|
285
|
+
/^>>>>>>> /m,
|
|
286
|
+
// Tool use patterns (important for context)
|
|
287
|
+
/<function_calls>/,
|
|
288
|
+
/<invoke>/,
|
|
289
|
+
/<tool_use>/,
|
|
290
|
+
// File operation results (often critical)
|
|
291
|
+
/ENOENT|EACCES|EISDIR|EEXIST/
|
|
292
|
+
]
|
|
293
|
+
};
|
|
294
|
+
function createClaudeCodeAdapter(memory, config) {
|
|
295
|
+
const pruner = createSparsePruner({
|
|
296
|
+
threshold: config.pruning.threshold
|
|
297
|
+
});
|
|
298
|
+
const scorer = createEngramScorer(config.decay);
|
|
299
|
+
const states = createConfidenceStates(config.states);
|
|
300
|
+
const btsp = createBTSPEmbedder();
|
|
301
|
+
async function optimize(context, options = {}) {
|
|
302
|
+
const startTime = Date.now();
|
|
303
|
+
const entries = parseClaudeCodeContext(context);
|
|
304
|
+
const entriesWithBTSP = entries.map((entry) => {
|
|
305
|
+
const isBTSP = CLAUDE_CODE_PROFILE.btspPatterns.some(
|
|
306
|
+
(pattern) => pattern.test(entry.content)
|
|
307
|
+
);
|
|
308
|
+
if (isBTSP) {
|
|
309
|
+
const btspEntry = btsp.createBTSPEntry(entry.content, [...entry.tags, "claude-code"], {
|
|
310
|
+
originalTimestamp: entry.timestamp
|
|
311
|
+
});
|
|
312
|
+
return {
|
|
313
|
+
...btspEntry,
|
|
314
|
+
timestamp: entry.timestamp
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
return entry;
|
|
318
|
+
});
|
|
319
|
+
const boostedEntries = entriesWithBTSP.map((entry) => {
|
|
320
|
+
const isConversationTurn = entry.content.trim().startsWith("User:") || entry.content.trim().startsWith("Assistant:");
|
|
321
|
+
if (isConversationTurn) {
|
|
322
|
+
return {
|
|
323
|
+
...entry,
|
|
324
|
+
score: entry.score * CLAUDE_CODE_PROFILE.conversationBoost
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
return entry;
|
|
328
|
+
});
|
|
329
|
+
const scoredEntries = boostedEntries.map((entry) => {
|
|
330
|
+
const decayScore = scorer.calculateScore(entry);
|
|
331
|
+
return {
|
|
332
|
+
...entry,
|
|
333
|
+
score: decayScore
|
|
334
|
+
};
|
|
335
|
+
});
|
|
336
|
+
const entriesWithStates = scoredEntries.map((entry) => {
|
|
337
|
+
const state = states.calculateState(entry);
|
|
338
|
+
return {
|
|
339
|
+
...entry,
|
|
340
|
+
state
|
|
341
|
+
};
|
|
342
|
+
});
|
|
343
|
+
const pruneResult = pruner.prune(entriesWithStates);
|
|
344
|
+
if (!options.dryRun) {
|
|
345
|
+
for (const entry of pruneResult.kept) {
|
|
346
|
+
await memory.put(entry);
|
|
347
|
+
}
|
|
348
|
+
await memory.recordOptimization({
|
|
349
|
+
timestamp: Date.now(),
|
|
350
|
+
tokens_before: pruneResult.originalTokens,
|
|
351
|
+
tokens_after: pruneResult.prunedTokens,
|
|
352
|
+
entries_pruned: pruneResult.removed.length,
|
|
353
|
+
duration_ms: Date.now() - startTime
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const optimizedContext = pruneResult.kept.map((entry) => entry.content).join("\n");
|
|
357
|
+
const stateDistribution = states.getDistribution(pruneResult.kept);
|
|
358
|
+
const result = {
|
|
359
|
+
optimizedContext,
|
|
360
|
+
tokensBefore: pruneResult.originalTokens,
|
|
361
|
+
tokensAfter: pruneResult.prunedTokens,
|
|
362
|
+
reduction: pruneResult.originalTokens > 0 ? (pruneResult.originalTokens - pruneResult.prunedTokens) / pruneResult.originalTokens : 0,
|
|
363
|
+
entriesProcessed: entries.length,
|
|
364
|
+
entriesKept: pruneResult.kept.length,
|
|
365
|
+
durationMs: Date.now() - startTime,
|
|
366
|
+
stateDistribution
|
|
367
|
+
};
|
|
368
|
+
if (options.verbose) {
|
|
369
|
+
result.details = pruneResult.kept.map((entry) => ({
|
|
370
|
+
id: entry.id,
|
|
371
|
+
score: entry.score,
|
|
372
|
+
state: entry.state || "unknown",
|
|
373
|
+
isBTSP: entry.tags.includes("btsp"),
|
|
374
|
+
tokens: estimateTokens(entry.content)
|
|
375
|
+
}));
|
|
376
|
+
}
|
|
377
|
+
return result;
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
optimize
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function parseClaudeCodeContext(context) {
|
|
384
|
+
const entries = [];
|
|
385
|
+
const now = Date.now();
|
|
386
|
+
const lines = context.split("\n");
|
|
387
|
+
let currentBlock = [];
|
|
388
|
+
let blockType = "other";
|
|
389
|
+
for (const line of lines) {
|
|
390
|
+
const trimmed = line.trim();
|
|
391
|
+
if (trimmed.startsWith("User:") || trimmed.startsWith("Assistant:")) {
|
|
392
|
+
if (currentBlock.length > 0) {
|
|
393
|
+
entries.push(createEntry(currentBlock.join("\n"), blockType, now));
|
|
394
|
+
currentBlock = [];
|
|
395
|
+
}
|
|
396
|
+
blockType = "conversation";
|
|
397
|
+
currentBlock.push(line);
|
|
398
|
+
} else if (trimmed.includes("<function_calls>") || trimmed.includes("<invoke>") || trimmed.includes("<tool_use>")) {
|
|
399
|
+
if (currentBlock.length > 0) {
|
|
400
|
+
entries.push(createEntry(currentBlock.join("\n"), blockType, now));
|
|
401
|
+
currentBlock = [];
|
|
402
|
+
}
|
|
403
|
+
blockType = "tool";
|
|
404
|
+
currentBlock.push(line);
|
|
405
|
+
} else if (trimmed.includes("<function_results>") || trimmed.includes("</function_results>")) {
|
|
406
|
+
if (currentBlock.length > 0 && blockType !== "result") {
|
|
407
|
+
entries.push(createEntry(currentBlock.join("\n"), blockType, now));
|
|
408
|
+
currentBlock = [];
|
|
409
|
+
}
|
|
410
|
+
blockType = "result";
|
|
411
|
+
currentBlock.push(line);
|
|
412
|
+
} else if (currentBlock.length > 0) {
|
|
413
|
+
currentBlock.push(line);
|
|
414
|
+
} else if (trimmed.length > 0) {
|
|
415
|
+
currentBlock.push(line);
|
|
416
|
+
blockType = "other";
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (currentBlock.length > 0) {
|
|
420
|
+
entries.push(createEntry(currentBlock.join("\n"), blockType, now));
|
|
421
|
+
}
|
|
422
|
+
return entries.filter((e) => e.content.trim().length > 0);
|
|
423
|
+
}
|
|
424
|
+
function createEntry(content, type, baseTime) {
|
|
425
|
+
const tags = [type];
|
|
426
|
+
let initialScore = 0.5;
|
|
427
|
+
if (type === "conversation") initialScore = 0.8;
|
|
428
|
+
if (type === "tool") initialScore = 0.7;
|
|
429
|
+
if (type === "result") initialScore = 0.4;
|
|
430
|
+
return {
|
|
431
|
+
id: (0, import_node_crypto3.randomUUID)(),
|
|
432
|
+
content,
|
|
433
|
+
hash: hashContent(content),
|
|
434
|
+
timestamp: baseTime,
|
|
435
|
+
score: initialScore,
|
|
436
|
+
state: initialScore > 0.7 ? "active" : initialScore > 0.3 ? "ready" : "silent",
|
|
437
|
+
ttl: 24 * 3600,
|
|
438
|
+
// 24 hours default
|
|
439
|
+
accessCount: 0,
|
|
440
|
+
tags,
|
|
441
|
+
metadata: { type },
|
|
442
|
+
isBTSP: false
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/adapters/generic.ts
|
|
447
|
+
var import_node_crypto4 = require("crypto");
|
|
448
|
+
function createGenericAdapter(memory, config) {
|
|
449
|
+
const pruner = createSparsePruner(config.pruning);
|
|
450
|
+
const scorer = createEngramScorer(config.decay);
|
|
451
|
+
const states = createConfidenceStates(config.states);
|
|
452
|
+
const btsp = createBTSPEmbedder();
|
|
453
|
+
async function optimize(context, options = {}) {
|
|
454
|
+
const startTime = Date.now();
|
|
455
|
+
const lines = context.split("\n").filter((line) => line.trim().length > 0);
|
|
456
|
+
const entries = lines.map((content) => ({
|
|
457
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
458
|
+
content,
|
|
459
|
+
hash: hashContent(content),
|
|
460
|
+
timestamp: Date.now(),
|
|
461
|
+
score: btsp.detectBTSP(content) ? 1 : 0.5,
|
|
462
|
+
// BTSP gets high initial score
|
|
463
|
+
ttl: config.decay.defaultTTL * 3600,
|
|
464
|
+
// Convert hours to seconds
|
|
465
|
+
state: "ready",
|
|
466
|
+
accessCount: 0,
|
|
467
|
+
tags: [],
|
|
468
|
+
metadata: {},
|
|
469
|
+
isBTSP: btsp.detectBTSP(content)
|
|
470
|
+
}));
|
|
471
|
+
const tokensBefore = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);
|
|
472
|
+
const scoredEntries = entries.map((entry) => ({
|
|
473
|
+
...entry,
|
|
474
|
+
score: scorer.calculateScore(entry)
|
|
475
|
+
}));
|
|
476
|
+
const statedEntries = scoredEntries.map((entry) => states.transition(entry));
|
|
477
|
+
const pruneResult = pruner.prune(statedEntries);
|
|
478
|
+
const optimizedEntries = pruneResult.kept.filter(
|
|
479
|
+
(e) => e.state === "active" || e.state === "ready"
|
|
480
|
+
);
|
|
481
|
+
const tokensAfter = optimizedEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);
|
|
482
|
+
const optimizedContext = optimizedEntries.map((e) => e.content).join("\n");
|
|
483
|
+
if (!options.dryRun) {
|
|
484
|
+
for (const entry of optimizedEntries) {
|
|
485
|
+
await memory.put(entry);
|
|
486
|
+
}
|
|
487
|
+
await memory.recordOptimization({
|
|
488
|
+
timestamp: Date.now(),
|
|
489
|
+
tokens_before: tokensBefore,
|
|
490
|
+
tokens_after: tokensAfter,
|
|
491
|
+
entries_pruned: entries.length - optimizedEntries.length,
|
|
492
|
+
duration_ms: Date.now() - startTime
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
const distribution = states.getDistribution(optimizedEntries);
|
|
496
|
+
const result = {
|
|
497
|
+
optimizedContext,
|
|
498
|
+
tokensBefore,
|
|
499
|
+
tokensAfter,
|
|
500
|
+
reduction: tokensBefore > 0 ? (tokensBefore - tokensAfter) / tokensBefore : 0,
|
|
501
|
+
entriesProcessed: entries.length,
|
|
502
|
+
entriesKept: optimizedEntries.length,
|
|
503
|
+
stateDistribution: distribution,
|
|
504
|
+
durationMs: Date.now() - startTime
|
|
505
|
+
};
|
|
506
|
+
if (options.verbose) {
|
|
507
|
+
result.details = optimizedEntries.map((e) => ({
|
|
508
|
+
id: e.id,
|
|
509
|
+
score: e.score,
|
|
510
|
+
state: e.state,
|
|
511
|
+
isBTSP: e.isBTSP,
|
|
512
|
+
tokens: estimateTokens(e.content)
|
|
513
|
+
}));
|
|
514
|
+
}
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
optimize
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/core/kv-memory.ts
|
|
523
|
+
var import_node_fs = require("fs");
|
|
524
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
525
|
+
function createBackup(dbPath) {
|
|
526
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
527
|
+
const backupPath = `${dbPath}.backup-${timestamp}`;
|
|
528
|
+
try {
|
|
529
|
+
(0, import_node_fs.copyFileSync)(dbPath, backupPath);
|
|
530
|
+
console.log(`\u2713 Database backed up to: ${backupPath}`);
|
|
531
|
+
return backupPath;
|
|
532
|
+
} catch (error) {
|
|
533
|
+
console.error(`Warning: Could not create backup: ${error}`);
|
|
534
|
+
return "";
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
async function createKVMemory(dbPath) {
|
|
538
|
+
let db;
|
|
539
|
+
try {
|
|
540
|
+
db = new import_better_sqlite3.default(dbPath);
|
|
541
|
+
const integrityCheck = db.pragma("quick_check", { simple: true });
|
|
542
|
+
if (integrityCheck !== "ok") {
|
|
543
|
+
console.error("\u26A0 Database corruption detected!");
|
|
544
|
+
if ((0, import_node_fs.existsSync)(dbPath)) {
|
|
545
|
+
const backupPath = createBackup(dbPath);
|
|
546
|
+
if (backupPath) {
|
|
547
|
+
console.log(`Backup created at: ${backupPath}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
console.log("Attempting database recovery...");
|
|
551
|
+
db.close();
|
|
552
|
+
db = new import_better_sqlite3.default(dbPath);
|
|
553
|
+
}
|
|
554
|
+
} catch (error) {
|
|
555
|
+
console.error("\u26A0 Database error detected:", error);
|
|
556
|
+
if ((0, import_node_fs.existsSync)(dbPath)) {
|
|
557
|
+
createBackup(dbPath);
|
|
558
|
+
console.log("Creating new database...");
|
|
559
|
+
}
|
|
560
|
+
db = new import_better_sqlite3.default(dbPath);
|
|
561
|
+
}
|
|
562
|
+
db.pragma("journal_mode = WAL");
|
|
563
|
+
db.exec(`
|
|
564
|
+
CREATE TABLE IF NOT EXISTS entries_index (
|
|
565
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
566
|
+
hash TEXT UNIQUE NOT NULL,
|
|
567
|
+
timestamp INTEGER NOT NULL,
|
|
568
|
+
score REAL NOT NULL DEFAULT 0.0 CHECK(score >= 0.0 AND score <= 1.0),
|
|
569
|
+
ttl INTEGER NOT NULL CHECK(ttl >= 0),
|
|
570
|
+
state TEXT NOT NULL CHECK(state IN ('silent', 'ready', 'active')),
|
|
571
|
+
accessCount INTEGER NOT NULL DEFAULT 0 CHECK(accessCount >= 0),
|
|
572
|
+
isBTSP INTEGER NOT NULL DEFAULT 0 CHECK(isBTSP IN (0, 1)),
|
|
573
|
+
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
|
574
|
+
);
|
|
575
|
+
`);
|
|
576
|
+
db.exec(`
|
|
577
|
+
CREATE TABLE IF NOT EXISTS entries_value (
|
|
578
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
579
|
+
content TEXT NOT NULL,
|
|
580
|
+
tags TEXT,
|
|
581
|
+
metadata TEXT,
|
|
582
|
+
FOREIGN KEY (id) REFERENCES entries_index(id) ON DELETE CASCADE
|
|
583
|
+
);
|
|
584
|
+
`);
|
|
585
|
+
db.exec(`
|
|
586
|
+
CREATE TABLE IF NOT EXISTS optimization_stats (
|
|
587
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
588
|
+
timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
|
|
589
|
+
tokens_before INTEGER NOT NULL,
|
|
590
|
+
tokens_after INTEGER NOT NULL,
|
|
591
|
+
entries_pruned INTEGER NOT NULL,
|
|
592
|
+
duration_ms INTEGER NOT NULL
|
|
593
|
+
);
|
|
594
|
+
`);
|
|
595
|
+
db.exec(`
|
|
596
|
+
CREATE INDEX IF NOT EXISTS idx_entries_state ON entries_index(state);
|
|
597
|
+
CREATE INDEX IF NOT EXISTS idx_entries_score ON entries_index(score DESC);
|
|
598
|
+
CREATE INDEX IF NOT EXISTS idx_entries_hash ON entries_index(hash);
|
|
599
|
+
CREATE INDEX IF NOT EXISTS idx_entries_timestamp ON entries_index(timestamp DESC);
|
|
600
|
+
CREATE INDEX IF NOT EXISTS idx_stats_timestamp ON optimization_stats(timestamp DESC);
|
|
601
|
+
`);
|
|
602
|
+
const putIndexStmt = db.prepare(`
|
|
603
|
+
INSERT OR REPLACE INTO entries_index
|
|
604
|
+
(id, hash, timestamp, score, ttl, state, accessCount, isBTSP)
|
|
605
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
606
|
+
`);
|
|
607
|
+
const putValueStmt = db.prepare(`
|
|
608
|
+
INSERT OR REPLACE INTO entries_value
|
|
609
|
+
(id, content, tags, metadata)
|
|
610
|
+
VALUES (?, ?, ?, ?)
|
|
611
|
+
`);
|
|
612
|
+
const getStmt = db.prepare(`
|
|
613
|
+
SELECT
|
|
614
|
+
i.id, i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,
|
|
615
|
+
v.content, v.tags, v.metadata
|
|
616
|
+
FROM entries_index i
|
|
617
|
+
JOIN entries_value v ON i.id = v.id
|
|
618
|
+
WHERE i.id = ?
|
|
619
|
+
`);
|
|
620
|
+
const deleteIndexStmt = db.prepare("DELETE FROM entries_index WHERE id = ?");
|
|
621
|
+
const deleteValueStmt = db.prepare("DELETE FROM entries_value WHERE id = ?");
|
|
622
|
+
return {
|
|
623
|
+
async put(entry) {
|
|
624
|
+
const transaction = db.transaction(() => {
|
|
625
|
+
putIndexStmt.run(
|
|
626
|
+
entry.id,
|
|
627
|
+
entry.hash,
|
|
628
|
+
entry.timestamp,
|
|
629
|
+
entry.score,
|
|
630
|
+
entry.ttl,
|
|
631
|
+
entry.state,
|
|
632
|
+
entry.accessCount,
|
|
633
|
+
entry.isBTSP ? 1 : 0
|
|
634
|
+
);
|
|
635
|
+
putValueStmt.run(
|
|
636
|
+
entry.id,
|
|
637
|
+
entry.content,
|
|
638
|
+
JSON.stringify(entry.tags),
|
|
639
|
+
JSON.stringify(entry.metadata)
|
|
640
|
+
);
|
|
641
|
+
});
|
|
642
|
+
transaction();
|
|
643
|
+
},
|
|
644
|
+
async get(id) {
|
|
645
|
+
const row = getStmt.get(id);
|
|
646
|
+
if (!row) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
const r = row;
|
|
650
|
+
return {
|
|
651
|
+
id: r.id,
|
|
652
|
+
content: r.content,
|
|
653
|
+
hash: r.hash,
|
|
654
|
+
timestamp: r.timestamp,
|
|
655
|
+
score: r.score,
|
|
656
|
+
ttl: r.ttl,
|
|
657
|
+
state: r.state,
|
|
658
|
+
accessCount: r.accessCount,
|
|
659
|
+
tags: r.tags ? JSON.parse(r.tags) : [],
|
|
660
|
+
metadata: r.metadata ? JSON.parse(r.metadata) : {},
|
|
661
|
+
isBTSP: r.isBTSP === 1
|
|
662
|
+
};
|
|
663
|
+
},
|
|
664
|
+
async query(filters) {
|
|
665
|
+
let sql = `
|
|
666
|
+
SELECT
|
|
667
|
+
i.id, i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,
|
|
668
|
+
v.content, v.tags, v.metadata
|
|
669
|
+
FROM entries_index i
|
|
670
|
+
JOIN entries_value v ON i.id = v.id
|
|
671
|
+
WHERE 1=1
|
|
672
|
+
`;
|
|
673
|
+
const params = [];
|
|
674
|
+
if (filters.state) {
|
|
675
|
+
sql += " AND i.state = ?";
|
|
676
|
+
params.push(filters.state);
|
|
677
|
+
}
|
|
678
|
+
if (filters.minScore !== void 0) {
|
|
679
|
+
sql += " AND i.score >= ?";
|
|
680
|
+
params.push(filters.minScore);
|
|
681
|
+
}
|
|
682
|
+
if (filters.maxScore !== void 0) {
|
|
683
|
+
sql += " AND i.score <= ?";
|
|
684
|
+
params.push(filters.maxScore);
|
|
685
|
+
}
|
|
686
|
+
if (filters.isBTSP !== void 0) {
|
|
687
|
+
sql += " AND i.isBTSP = ?";
|
|
688
|
+
params.push(filters.isBTSP ? 1 : 0);
|
|
689
|
+
}
|
|
690
|
+
sql += " ORDER BY i.score DESC";
|
|
691
|
+
if (filters.limit) {
|
|
692
|
+
sql += " LIMIT ?";
|
|
693
|
+
params.push(filters.limit);
|
|
694
|
+
}
|
|
695
|
+
if (filters.offset) {
|
|
696
|
+
sql += " OFFSET ?";
|
|
697
|
+
params.push(filters.offset);
|
|
698
|
+
}
|
|
699
|
+
const stmt = db.prepare(sql);
|
|
700
|
+
const rows = stmt.all(...params);
|
|
701
|
+
return rows.map((row) => {
|
|
702
|
+
const r = row;
|
|
703
|
+
return {
|
|
704
|
+
id: r.id,
|
|
705
|
+
content: r.content,
|
|
706
|
+
hash: r.hash,
|
|
707
|
+
timestamp: r.timestamp,
|
|
708
|
+
score: r.score,
|
|
709
|
+
ttl: r.ttl,
|
|
710
|
+
state: r.state,
|
|
711
|
+
accessCount: r.accessCount,
|
|
712
|
+
tags: r.tags ? JSON.parse(r.tags) : [],
|
|
713
|
+
metadata: r.metadata ? JSON.parse(r.metadata) : {},
|
|
714
|
+
isBTSP: r.isBTSP === 1
|
|
715
|
+
};
|
|
716
|
+
});
|
|
717
|
+
},
|
|
718
|
+
async delete(id) {
|
|
719
|
+
const transaction = db.transaction(() => {
|
|
720
|
+
deleteIndexStmt.run(id);
|
|
721
|
+
deleteValueStmt.run(id);
|
|
722
|
+
});
|
|
723
|
+
transaction();
|
|
724
|
+
},
|
|
725
|
+
async list() {
|
|
726
|
+
const stmt = db.prepare("SELECT id FROM entries_index");
|
|
727
|
+
const rows = stmt.all();
|
|
728
|
+
return rows.map((r) => r.id);
|
|
729
|
+
},
|
|
730
|
+
async compact() {
|
|
731
|
+
const before = db.prepare("SELECT COUNT(*) as count FROM entries_index").get();
|
|
732
|
+
db.exec("DELETE FROM entries_index WHERE ttl <= 0");
|
|
733
|
+
db.exec("VACUUM");
|
|
734
|
+
const after = db.prepare("SELECT COUNT(*) as count FROM entries_index").get();
|
|
735
|
+
return before.count - after.count;
|
|
736
|
+
},
|
|
737
|
+
async close() {
|
|
738
|
+
db.close();
|
|
739
|
+
},
|
|
740
|
+
async recordOptimization(stats) {
|
|
741
|
+
const stmt = db.prepare(`
|
|
742
|
+
INSERT INTO optimization_stats (timestamp, tokens_before, tokens_after, entries_pruned, duration_ms)
|
|
743
|
+
VALUES (?, ?, ?, ?, ?)
|
|
744
|
+
`);
|
|
745
|
+
stmt.run(
|
|
746
|
+
stats.timestamp,
|
|
747
|
+
stats.tokens_before,
|
|
748
|
+
stats.tokens_after,
|
|
749
|
+
stats.entries_pruned,
|
|
750
|
+
stats.duration_ms
|
|
751
|
+
);
|
|
752
|
+
},
|
|
753
|
+
async getOptimizationStats() {
|
|
754
|
+
const stmt = db.prepare(`
|
|
755
|
+
SELECT id, timestamp, tokens_before, tokens_after, entries_pruned, duration_ms
|
|
756
|
+
FROM optimization_stats
|
|
757
|
+
ORDER BY timestamp DESC
|
|
758
|
+
`);
|
|
759
|
+
const rows = stmt.all();
|
|
760
|
+
return rows;
|
|
761
|
+
},
|
|
762
|
+
async clearOptimizationStats() {
|
|
763
|
+
db.exec("DELETE FROM optimization_stats");
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// src/core/sleep-compressor.ts
|
|
769
|
+
function createSleepCompressor() {
|
|
770
|
+
const scorer = createEngramScorer({ defaultTTL: 24, decayThreshold: 0.95 });
|
|
771
|
+
function consolidate(entries) {
|
|
772
|
+
const startTime = Date.now();
|
|
773
|
+
const originalCount = entries.length;
|
|
774
|
+
const now = Date.now();
|
|
775
|
+
const nonDecayed = entries.filter((entry) => {
|
|
776
|
+
const ageInSeconds = (now - entry.timestamp) / 1e3;
|
|
777
|
+
const decay = scorer.calculateDecay(ageInSeconds, entry.ttl);
|
|
778
|
+
return decay < 0.95;
|
|
779
|
+
});
|
|
780
|
+
const decayedRemoved = originalCount - nonDecayed.length;
|
|
781
|
+
const duplicateGroups = findDuplicates(nonDecayed);
|
|
782
|
+
const merged = mergeDuplicates(duplicateGroups);
|
|
783
|
+
const duplicateIds = new Set(duplicateGroups.flatMap((g) => g.entries.map((e) => e.id)));
|
|
784
|
+
const nonDuplicates = nonDecayed.filter((e) => !duplicateIds.has(e.id));
|
|
785
|
+
const kept = [...merged, ...nonDuplicates];
|
|
786
|
+
const removed = entries.filter((e) => !kept.some((k) => k.id === e.id));
|
|
787
|
+
const duplicatesRemoved = duplicateGroups.reduce((sum, g) => sum + (g.entries.length - 1), 0);
|
|
788
|
+
return {
|
|
789
|
+
kept,
|
|
790
|
+
removed,
|
|
791
|
+
entriesBefore: originalCount,
|
|
792
|
+
entriesAfter: kept.length,
|
|
793
|
+
decayedRemoved,
|
|
794
|
+
duplicatesRemoved,
|
|
795
|
+
compressionRatio: originalCount > 0 ? kept.length / originalCount : 0,
|
|
796
|
+
durationMs: Date.now() - startTime
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
function findDuplicates(entries) {
|
|
800
|
+
const groups = [];
|
|
801
|
+
const processed = /* @__PURE__ */ new Set();
|
|
802
|
+
for (let i = 0; i < entries.length; i++) {
|
|
803
|
+
const entry = entries[i];
|
|
804
|
+
if (!entry || processed.has(entry.id)) continue;
|
|
805
|
+
const duplicates = entries.filter((e, idx) => idx !== i && e.hash === entry.hash);
|
|
806
|
+
if (duplicates.length > 0) {
|
|
807
|
+
const group = {
|
|
808
|
+
entries: [entry, ...duplicates],
|
|
809
|
+
similarity: 1
|
|
810
|
+
// Exact match
|
|
811
|
+
};
|
|
812
|
+
groups.push(group);
|
|
813
|
+
processed.add(entry.id);
|
|
814
|
+
for (const dup of duplicates) {
|
|
815
|
+
processed.add(dup.id);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
for (let i = 0; i < entries.length; i++) {
|
|
820
|
+
const entryI = entries[i];
|
|
821
|
+
if (!entryI || processed.has(entryI.id)) continue;
|
|
822
|
+
for (let j = i + 1; j < entries.length; j++) {
|
|
823
|
+
const entryJ = entries[j];
|
|
824
|
+
if (!entryJ || processed.has(entryJ.id)) continue;
|
|
825
|
+
const similarity = cosineSimilarity(entryI.content, entryJ.content);
|
|
826
|
+
if (similarity >= 0.85) {
|
|
827
|
+
const group = {
|
|
828
|
+
entries: [entryI, entryJ],
|
|
829
|
+
similarity
|
|
830
|
+
};
|
|
831
|
+
groups.push(group);
|
|
832
|
+
processed.add(entryI.id);
|
|
833
|
+
processed.add(entryJ.id);
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return groups;
|
|
839
|
+
}
|
|
840
|
+
function mergeDuplicates(groups) {
|
|
841
|
+
const merged = [];
|
|
842
|
+
for (const group of groups) {
|
|
843
|
+
const sorted = [...group.entries].sort((a, b) => b.score - a.score);
|
|
844
|
+
const best = sorted[0];
|
|
845
|
+
if (!best) continue;
|
|
846
|
+
const totalAccessCount = group.entries.reduce((sum, e) => sum + e.accessCount, 0);
|
|
847
|
+
const allTags = new Set(group.entries.flatMap((e) => e.tags));
|
|
848
|
+
merged.push({
|
|
849
|
+
...best,
|
|
850
|
+
accessCount: totalAccessCount,
|
|
851
|
+
tags: Array.from(allTags)
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
return merged;
|
|
855
|
+
}
|
|
856
|
+
function cosineSimilarity(text1, text2) {
|
|
857
|
+
const words1 = tokenize(text1);
|
|
858
|
+
const words2 = tokenize(text2);
|
|
859
|
+
const vocab = /* @__PURE__ */ new Set([...words1, ...words2]);
|
|
860
|
+
const vec1 = {};
|
|
861
|
+
const vec2 = {};
|
|
862
|
+
for (const word of vocab) {
|
|
863
|
+
vec1[word] = words1.filter((w) => w === word).length;
|
|
864
|
+
vec2[word] = words2.filter((w) => w === word).length;
|
|
865
|
+
}
|
|
866
|
+
let dotProduct = 0;
|
|
867
|
+
let mag1 = 0;
|
|
868
|
+
let mag2 = 0;
|
|
869
|
+
for (const word of vocab) {
|
|
870
|
+
const count1 = vec1[word] ?? 0;
|
|
871
|
+
const count2 = vec2[word] ?? 0;
|
|
872
|
+
dotProduct += count1 * count2;
|
|
873
|
+
mag1 += count1 * count1;
|
|
874
|
+
mag2 += count2 * count2;
|
|
875
|
+
}
|
|
876
|
+
mag1 = Math.sqrt(mag1);
|
|
877
|
+
mag2 = Math.sqrt(mag2);
|
|
878
|
+
if (mag1 === 0 || mag2 === 0) return 0;
|
|
879
|
+
return dotProduct / (mag1 * mag2);
|
|
880
|
+
}
|
|
881
|
+
function tokenize(text) {
|
|
882
|
+
return text.toLowerCase().split(/\s+/).filter((word) => word.length > 0);
|
|
883
|
+
}
|
|
884
|
+
return {
|
|
885
|
+
consolidate,
|
|
886
|
+
findDuplicates,
|
|
887
|
+
mergeDuplicates
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// src/types/config.ts
|
|
892
|
+
var DEFAULT_CONFIG = {
|
|
893
|
+
pruning: {
|
|
894
|
+
threshold: 5,
|
|
895
|
+
aggressiveness: 50
|
|
896
|
+
},
|
|
897
|
+
decay: {
|
|
898
|
+
defaultTTL: 24,
|
|
899
|
+
decayThreshold: 0.95
|
|
900
|
+
},
|
|
901
|
+
states: {
|
|
902
|
+
activeThreshold: 0.7,
|
|
903
|
+
readyThreshold: 0.3
|
|
904
|
+
},
|
|
905
|
+
agent: "generic",
|
|
906
|
+
ui: {
|
|
907
|
+
colors: true,
|
|
908
|
+
sounds: false,
|
|
909
|
+
verbose: false
|
|
910
|
+
},
|
|
911
|
+
autoConsolidate: null
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
// src/utils/logger.ts
|
|
915
|
+
function createLogger(verbose = false) {
|
|
916
|
+
return {
|
|
917
|
+
debug(message, ...args) {
|
|
918
|
+
if (verbose) {
|
|
919
|
+
console.debug(`[DEBUG] ${message}`, ...args);
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
info(message, ...args) {
|
|
923
|
+
console.info(`[INFO] ${message}`, ...args);
|
|
924
|
+
},
|
|
925
|
+
warn(message, ...args) {
|
|
926
|
+
console.warn(`[WARN] ${message}`, ...args);
|
|
927
|
+
},
|
|
928
|
+
error(message, ...args) {
|
|
929
|
+
console.error(`[ERROR] ${message}`, ...args);
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
934
|
+
0 && (module.exports = {
|
|
935
|
+
DEFAULT_CONFIG,
|
|
936
|
+
createBTSPEmbedder,
|
|
937
|
+
createClaudeCodeAdapter,
|
|
938
|
+
createConfidenceStates,
|
|
939
|
+
createEngramScorer,
|
|
940
|
+
createGenericAdapter,
|
|
941
|
+
createKVMemory,
|
|
942
|
+
createLogger,
|
|
943
|
+
createSleepCompressor,
|
|
944
|
+
createSparsePruner,
|
|
945
|
+
estimateTokens,
|
|
946
|
+
hashContent
|
|
947
|
+
});
|
|
948
|
+
//# sourceMappingURL=index.cjs.map
|