claude-launchpad 0.8.2 → 0.9.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.
Files changed (32) hide show
  1. package/README.md +2 -2
  2. package/dist/chunk-CSLWJEGD.js +0 -0
  3. package/dist/chunk-FL3JGYDM.js +0 -0
  4. package/dist/{chunk-NNVJCKEP.js → chunk-JPVLFY2R.js} +36 -1
  5. package/dist/chunk-JPVLFY2R.js.map +1 -0
  6. package/dist/chunk-MQJA7TGY.js +60 -0
  7. package/dist/chunk-MQJA7TGY.js.map +1 -0
  8. package/dist/chunk-NAW47BYA.js +0 -0
  9. package/dist/chunk-TALTTAMW.js +0 -0
  10. package/dist/chunk-UN2XVQ5K.js +0 -0
  11. package/dist/{chunk-EUAVDA7W.js → chunk-X7ZY2Y2Z.js} +2 -2
  12. package/dist/cli.js +6 -6
  13. package/dist/cli.js.map +1 -1
  14. package/dist/commands/memory/server.js +252 -3
  15. package/dist/commands/memory/server.js.map +1 -1
  16. package/dist/{context-QU2QFVS3.js → context-HX5BOXYM.js} +158 -70
  17. package/dist/context-HX5BOXYM.js.map +1 -0
  18. package/dist/{extract-ADZYHMUP.js → extract-7D2EEXYD.js} +3 -3
  19. package/dist/{install-3IW2PDOS.js → install-ULZUZI7T.js} +2 -2
  20. package/dist/require-deps-6D6IBICL.js +0 -0
  21. package/dist/{stats-XLVVS3JA.js → stats-Y5ZFAZVF.js} +3 -3
  22. package/dist/{tui-BXRHLYAS.js → tui-DTIXPD2V.js} +2 -2
  23. package/package.json +21 -14
  24. package/dist/chunk-NNVJCKEP.js.map +0 -1
  25. package/dist/chunk-OYSKBXBB.js +0 -311
  26. package/dist/chunk-OYSKBXBB.js.map +0 -1
  27. package/dist/context-QU2QFVS3.js.map +0 -1
  28. /package/dist/{chunk-EUAVDA7W.js.map → chunk-X7ZY2Y2Z.js.map} +0 -0
  29. /package/dist/{extract-ADZYHMUP.js.map → extract-7D2EEXYD.js.map} +0 -0
  30. /package/dist/{install-3IW2PDOS.js.map → install-ULZUZI7T.js.map} +0 -0
  31. /package/dist/{stats-XLVVS3JA.js.map → stats-Y5ZFAZVF.js.map} +0 -0
  32. /package/dist/{tui-BXRHLYAS.js.map → tui-DTIXPD2V.js.map} +0 -0
@@ -1,311 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- SCORING_WEIGHTS
4
- } from "./chunk-NNVJCKEP.js";
5
-
6
- // src/commands/memory/utils/git-context.ts
7
- import { execSync } from "child_process";
8
- var cached = null;
9
- function getGitContext() {
10
- if (cached) return cached;
11
- let branch = null;
12
- let recentFiles = [];
13
- try {
14
- branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8", timeout: 3e3 }).trim() || null;
15
- } catch {
16
- }
17
- try {
18
- const raw = execSync("git diff --name-only HEAD~5", { encoding: "utf-8", timeout: 3e3 }).trim();
19
- recentFiles = raw ? raw.split("\n").filter(Boolean) : [];
20
- } catch {
21
- }
22
- cached = { branch, recentFiles };
23
- return cached;
24
- }
25
- function computeContextScore(storedContext, currentContext, query) {
26
- if (!storedContext) return 0;
27
- let parsed;
28
- try {
29
- parsed = JSON.parse(storedContext);
30
- } catch {
31
- return 0;
32
- }
33
- const branchScore = parsed.branch && currentContext.branch && parsed.branch === currentContext.branch ? 1 : 0;
34
- let fileScore = 0;
35
- if (parsed.files?.length && currentContext.recentFiles.length) {
36
- const stored = new Set(parsed.files);
37
- const current = new Set(currentContext.recentFiles);
38
- let intersection = 0;
39
- for (const f of stored) {
40
- if (current.has(f)) intersection++;
41
- }
42
- const union = stored.size + current.size - intersection;
43
- fileScore = union > 0 ? intersection / union : 0;
44
- }
45
- let intentScore = 0;
46
- if (parsed.intent && query) {
47
- const intentWords = new Set(parsed.intent.toLowerCase().split(/\s+/).filter(Boolean));
48
- const queryWords = new Set(query.toLowerCase().split(/\s+/).filter(Boolean));
49
- let overlap = 0;
50
- for (const w of intentWords) {
51
- if (queryWords.has(w)) overlap++;
52
- }
53
- const union = intentWords.size + queryWords.size - overlap;
54
- intentScore = union > 0 ? overlap / union : 0;
55
- }
56
- return branchScore * 0.4 + fileScore * 0.4 + intentScore * 0.2;
57
- }
58
-
59
- // src/commands/memory/services/retrieval-service.ts
60
- var STALENESS_THRESHOLDS = {
61
- working: 1,
62
- episodic: 7,
63
- pattern: 14,
64
- semantic: 30,
65
- procedural: 90
66
- };
67
- var RetrievalService = class {
68
- #deps;
69
- #gitContext;
70
- constructor(deps) {
71
- this.#deps = deps;
72
- this.#gitContext = deps.gitContext ?? getGitContext();
73
- }
74
- /**
75
- * FTS5 keyword search with multi-signal scoring, context awareness,
76
- * and relation-based graph expansion.
77
- */
78
- async search(input) {
79
- if (input.id) {
80
- const memory = this.#deps.memoryRepo.getById(input.id);
81
- if (!memory) return [];
82
- this.#deps.memoryRepo.incrementAccess(input.id);
83
- return [{
84
- memory,
85
- score: 1,
86
- explanation: "Direct lookup by ID"
87
- }];
88
- }
89
- const ftsResults = this.#deps.searchRepo.searchFts({
90
- query: input.query,
91
- limit: input.limit * 3,
92
- type: input.type,
93
- minImportance: input.min_importance,
94
- project: input.project
95
- });
96
- const textScores = ftsOnlyScores(ftsResults);
97
- if (textScores.size === 0) return [];
98
- const candidates = [];
99
- for (const [memoryId, textScore] of textScores) {
100
- const memory = this.#deps.memoryRepo.getById(memoryId);
101
- if (!memory) continue;
102
- if (input.type && memory.type !== input.type) continue;
103
- if (memory.importance < input.min_importance) continue;
104
- if (input.tags?.length) {
105
- const memTags = new Set(memory.tags);
106
- if (!input.tags.every((t) => memTags.has(t))) continue;
107
- }
108
- const parts = computeScoreParts(memory, textScore, this.#gitContext, input.query);
109
- const composite = computeComposite(parts);
110
- candidates.push({ memory, composite, parts });
111
- }
112
- candidates.sort((a, b) => b.composite - a.composite);
113
- let topN = candidates.slice(0, input.limit);
114
- const seenIds = new Set(topN.map((c) => c.memory.id));
115
- const expanded = this.#expandWithRelations(topN, input.limit, seenIds, input.min_importance);
116
- if (expanded.length > 0) {
117
- topN = [...topN, ...expanded].sort((a, b) => b.composite - a.composite).slice(0, input.limit);
118
- }
119
- return topN.map(({ memory, composite, parts }) => {
120
- this.#deps.memoryRepo.incrementAccess(memory.id);
121
- return {
122
- memory,
123
- score: composite,
124
- explanation: parts.relationSource ? `Related (${parts.relationSource.type}) to: ${parts.relationSource.title ?? parts.relationSource.id}` : buildExplanation(parts, memory)
125
- };
126
- });
127
- }
128
- /**
129
- * Smart session loading: returns context-matched, recent, and related memories
130
- * for session start context injection.
131
- */
132
- loadSessionContext(input) {
133
- const contextBudget = Math.floor(input.limit * 0.4);
134
- const recentBudget = Math.floor(input.limit * 0.4);
135
- const relatedBudget = input.limit - contextBudget - recentBudget;
136
- const seenIds = /* @__PURE__ */ new Set();
137
- const contextMatched = this.#loadContextMatched(contextBudget, input.project, input.type, seenIds);
138
- const recent = this.#loadRecent(recentBudget, input.project, input.type, seenIds);
139
- const sourceIds = [...contextMatched, ...recent].map((r) => r.result.memory.id);
140
- const related = this.#loadRelatedExpansion(sourceIds, relatedBudget, seenIds);
141
- const all = [...contextMatched, ...recent, ...related];
142
- for (const entry of all) {
143
- this.#deps.memoryRepo.incrementAccess(entry.result.memory.id);
144
- }
145
- return all;
146
- }
147
- #loadContextMatched(budget, project, type, seenIds) {
148
- if (budget <= 0) return [];
149
- const candidates = this.#deps.memoryRepo.getRecent(budget * 5, project, type);
150
- const scored = [];
151
- for (const m of candidates) {
152
- const ctxScore = computeContextScore(m.context, this.#gitContext, "");
153
- if (ctxScore <= 0.1) continue;
154
- const composite = ctxScore * 0.5 + m.importance * 0.3 + computeRecencyScore(m.updatedAt) * 0.2;
155
- scored.push({ memory: m, ctxScore, composite });
156
- }
157
- scored.sort((a, b) => b.composite - a.composite);
158
- const results = [];
159
- for (const s of scored.slice(0, budget)) {
160
- seenIds?.add(s.memory.id);
161
- results.push({ section: "context", result: { memory: s.memory, score: s.composite, explanation: "Context match" } });
162
- }
163
- return results;
164
- }
165
- #loadRecent(budget, project, type, seenIds) {
166
- if (budget <= 0) return [];
167
- const candidates = this.#deps.memoryRepo.getRecent(budget * 2, project, type);
168
- const results = [];
169
- for (const m of candidates) {
170
- if (seenIds?.has(m.id)) continue;
171
- const score = m.importance * 0.4 + computeRecencyScore(m.updatedAt) * 0.6;
172
- seenIds?.add(m.id);
173
- results.push({ section: "recent", result: { memory: m, score, explanation: "Recent" } });
174
- if (results.length >= budget) break;
175
- }
176
- return results;
177
- }
178
- #loadRelatedExpansion(sourceIds, budget, seenIds) {
179
- if (budget <= 0) return [];
180
- const results = [];
181
- for (const srcId of sourceIds) {
182
- const relations = this.#deps.relationRepo.getByMemory(srcId);
183
- for (const rel of relations) {
184
- const otherId = rel.sourceId === srcId ? rel.targetId : rel.sourceId;
185
- if (otherId === srcId || seenIds.has(otherId)) continue;
186
- const other = this.#deps.memoryRepo.getById(otherId);
187
- if (!other) continue;
188
- const src = this.#deps.memoryRepo.getById(srcId);
189
- const weight = RELATION_TYPE_WEIGHTS[rel.relationType] ?? 0.5;
190
- seenIds.add(otherId);
191
- results.push({
192
- section: "related",
193
- result: {
194
- memory: other,
195
- score: other.importance * weight,
196
- explanation: `Related (${rel.relationType}) to: ${src?.title ?? srcId}`
197
- }
198
- });
199
- if (results.length >= budget) return results;
200
- }
201
- }
202
- return results;
203
- }
204
- #expandWithRelations(topResults, limit, seenIds, minImportance) {
205
- if (topResults.length >= limit) return [];
206
- const expanded = [];
207
- const remaining = limit - topResults.length;
208
- const sourcesToExpand = topResults.slice(0, 5);
209
- for (const parent of sourcesToExpand) {
210
- const relations = this.#deps.relationRepo.getByMemory(parent.memory.id);
211
- for (const rel of relations) {
212
- const otherId = rel.sourceId === parent.memory.id ? rel.targetId : rel.sourceId;
213
- if (otherId === parent.memory.id || seenIds.has(otherId)) continue;
214
- const other = this.#deps.memoryRepo.getById(otherId);
215
- if (!other || other.importance < minImportance) continue;
216
- const weight = RELATION_TYPE_WEIGHTS[rel.relationType] ?? 0.5;
217
- const composite = parent.composite * 0.7 * weight;
218
- const parts = {
219
- textScore: 0,
220
- importanceScore: other.importance,
221
- recencyScore: computeRecencyScore(other.updatedAt),
222
- accessScore: computeAccessScore(other.accessCount, other.lastAccessed),
223
- contextScore: 0,
224
- relationSource: { id: parent.memory.id, title: parent.memory.title, type: rel.relationType }
225
- };
226
- seenIds.add(otherId);
227
- expanded.push({ memory: other, composite, parts });
228
- if (expanded.length >= remaining) return expanded;
229
- }
230
- }
231
- return expanded;
232
- }
233
- };
234
- var RELATION_TYPE_WEIGHTS = {
235
- depends_on: 1,
236
- extends: 0.9,
237
- implements: 0.9,
238
- relates_to: 0.7,
239
- derived_from: 0.6,
240
- contradicts: 0.3
241
- };
242
- function ftsOnlyScores(ftsResults) {
243
- const scores = /* @__PURE__ */ new Map();
244
- for (const r of ftsResults) {
245
- const score = Math.min(1, -r.rank / 20);
246
- scores.set(r.memoryId, score);
247
- }
248
- return scores;
249
- }
250
- function computeScoreParts(memory, textScore, gitContext, query) {
251
- return {
252
- textScore,
253
- importanceScore: memory.importance,
254
- recencyScore: computeRecencyScore(memory.updatedAt),
255
- accessScore: computeAccessScore(memory.accessCount, memory.lastAccessed),
256
- contextScore: computeContextScore(memory.context, gitContext, query)
257
- };
258
- }
259
- function computeComposite(parts) {
260
- return parts.textScore * SCORING_WEIGHTS.text + parts.importanceScore * SCORING_WEIGHTS.importance + parts.recencyScore * SCORING_WEIGHTS.recency + parts.accessScore * SCORING_WEIGHTS.access + parts.contextScore * SCORING_WEIGHTS.context;
261
- }
262
- function computeRecencyScore(updatedAt) {
263
- const ageMs = Date.now() - new Date(updatedAt).getTime();
264
- const ageDays = ageMs / (1e3 * 60 * 60 * 24);
265
- if (ageDays < 0) return 1;
266
- return Math.exp(-ageDays * Math.LN2 / 30);
267
- }
268
- function computeAccessScore(accessCount, lastAccessed) {
269
- if (accessCount <= 0) return 0;
270
- const countScore = Math.min(1, Math.log10(accessCount + 1) / Math.log10(31));
271
- if (!lastAccessed) return countScore * 0.5;
272
- const ageDays = (Date.now() - new Date(lastAccessed).getTime()) / 864e5;
273
- const recency = Math.exp(-ageDays * Math.LN2 / 30);
274
- return countScore * (0.5 + 0.5 * recency);
275
- }
276
- function buildExplanation(parts, memory) {
277
- const factors = [];
278
- if (parts.textScore > 0.7) {
279
- factors.push(`High text match (${(parts.textScore * 100).toFixed(0)}%)`);
280
- } else if (parts.textScore > 0.3) {
281
- factors.push(`Moderate text match (${(parts.textScore * 100).toFixed(0)}%)`);
282
- }
283
- if (memory.importance > 0.7) {
284
- factors.push("High importance");
285
- }
286
- if (parts.recencyScore > 0.8) {
287
- factors.push("Very recent");
288
- } else if (parts.recencyScore > 0.5) {
289
- factors.push("Recent");
290
- }
291
- if (memory.accessCount > 10) {
292
- factors.push(`Frequently accessed (${memory.accessCount}x)`);
293
- } else if (memory.accessCount > 3) {
294
- factors.push(`Accessed ${memory.accessCount}x`);
295
- }
296
- if (parts.contextScore > 0.3) {
297
- factors.push("Context match");
298
- }
299
- const ageDays = Math.floor((Date.now() - new Date(memory.createdAt).getTime()) / 864e5);
300
- const stalenessThreshold = STALENESS_THRESHOLDS[memory.type];
301
- if (stalenessThreshold !== void 0 && ageDays > stalenessThreshold) {
302
- factors.push(`${ageDays}d old - verify before acting`);
303
- }
304
- return factors.length > 0 ? factors.join(" + ") : "Matched query";
305
- }
306
-
307
- export {
308
- getGitContext,
309
- RetrievalService
310
- };
311
- //# sourceMappingURL=chunk-OYSKBXBB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/utils/git-context.ts","../src/commands/memory/services/retrieval-service.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\n\nexport interface GitContext {\n readonly branch: string | null;\n readonly recentFiles: readonly string[];\n}\n\nlet cached: GitContext | null = null;\n\nexport function getGitContext(): GitContext {\n if (cached) return cached;\n\n let branch: string | null = null;\n let recentFiles: string[] = [];\n\n try {\n branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8', timeout: 3000 }).trim() || null;\n } catch { /* not in a git repo or git not available */ }\n\n try {\n const raw = execSync('git diff --name-only HEAD~5', { encoding: 'utf-8', timeout: 3000 }).trim();\n recentFiles = raw ? raw.split('\\n').filter(Boolean) : [];\n } catch { /* shallow clone or no commits */ }\n\n cached = { branch, recentFiles };\n return cached;\n}\n\nexport function clearGitContextCache(): void {\n cached = null;\n}\n\nexport function computeContextScore(\n storedContext: string | null,\n currentContext: GitContext,\n query: string,\n): number {\n if (!storedContext) return 0;\n\n let parsed: { files?: string[]; branch?: string; intent?: string };\n try {\n parsed = JSON.parse(storedContext) as { files?: string[]; branch?: string; intent?: string };\n } catch {\n return 0;\n }\n\n // Branch match (weight 0.4)\n const branchScore = (parsed.branch && currentContext.branch && parsed.branch === currentContext.branch) ? 1.0 : 0;\n\n // File overlap — Jaccard similarity (weight 0.4)\n let fileScore = 0;\n if (parsed.files?.length && currentContext.recentFiles.length) {\n const stored = new Set(parsed.files);\n const current = new Set(currentContext.recentFiles);\n let intersection = 0;\n for (const f of stored) {\n if (current.has(f)) intersection++;\n }\n const union = stored.size + current.size - intersection;\n fileScore = union > 0 ? intersection / union : 0;\n }\n\n // Intent keyword overlap with query (weight 0.2)\n let intentScore = 0;\n if (parsed.intent && query) {\n const intentWords = new Set(parsed.intent.toLowerCase().split(/\\s+/).filter(Boolean));\n const queryWords = new Set(query.toLowerCase().split(/\\s+/).filter(Boolean));\n let overlap = 0;\n for (const w of intentWords) {\n if (queryWords.has(w)) overlap++;\n }\n const union = intentWords.size + queryWords.size - overlap;\n intentScore = union > 0 ? overlap / union : 0;\n }\n\n return branchScore * 0.4 + fileScore * 0.4 + intentScore * 0.2;\n}\n","import type { Memory, MemoryType, SearchResult, SearchInput, RelationType } from '../types.js';\nimport type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\nimport type { SearchRepo } from '../storage/search-repo.js';\nimport { SCORING_WEIGHTS } from '../config.js';\nimport { type GitContext, getGitContext, computeContextScore } from '../utils/git-context.js';\n\nconst STALENESS_THRESHOLDS = {\n working: 1,\n episodic: 7,\n pattern: 14,\n semantic: 30,\n procedural: 90,\n} as const;\n\nexport interface RetrievalDeps {\n readonly memoryRepo: MemoryRepo;\n readonly relationRepo: RelationRepo;\n readonly searchRepo: SearchRepo;\n readonly gitContext?: GitContext;\n}\n\nexport class RetrievalService {\n readonly #deps: RetrievalDeps;\n readonly #gitContext: GitContext;\n\n constructor(deps: RetrievalDeps) {\n this.#deps = deps;\n this.#gitContext = deps.gitContext ?? getGitContext();\n }\n\n /**\n * FTS5 keyword search with multi-signal scoring, context awareness,\n * and relation-based graph expansion.\n */\n async search(input: SearchInput): Promise<readonly SearchResult[]> {\n // Direct ID lookup\n if (input.id) {\n const memory = this.#deps.memoryRepo.getById(input.id);\n if (!memory) return [];\n this.#deps.memoryRepo.incrementAccess(input.id);\n return [{\n memory,\n score: 1.0,\n explanation: 'Direct lookup by ID',\n }];\n }\n\n // Phase 1: FTS5 keyword search\n const ftsResults = this.#deps.searchRepo.searchFts({\n query: input.query,\n limit: input.limit * 3,\n type: input.type,\n minImportance: input.min_importance,\n project: input.project,\n });\n\n const textScores = ftsOnlyScores(ftsResults);\n if (textScores.size === 0) return [];\n\n // Phase 2: Load memories and compute composite scores\n const candidates: { memory: Memory; composite: number; parts: ScoreParts }[] = [];\n\n for (const [memoryId, textScore] of textScores) {\n const memory = this.#deps.memoryRepo.getById(memoryId);\n if (!memory) continue;\n if (input.type && memory.type !== input.type) continue;\n if (memory.importance < input.min_importance) continue;\n if (input.tags?.length) {\n const memTags = new Set(memory.tags);\n if (!input.tags.every(t => memTags.has(t))) continue;\n }\n\n const parts = computeScoreParts(memory, textScore, this.#gitContext, input.query);\n const composite = computeComposite(parts);\n candidates.push({ memory, composite, parts });\n }\n\n // Phase 3: Sort by composite score\n candidates.sort((a, b) => b.composite - a.composite);\n let topN = candidates.slice(0, input.limit);\n\n // Phase 4: Relation expansion — surface connected memories\n const seenIds = new Set(topN.map(c => c.memory.id));\n const expanded = this.#expandWithRelations(topN, input.limit, seenIds, input.min_importance);\n if (expanded.length > 0) {\n topN = [...topN, ...expanded].sort((a, b) => b.composite - a.composite).slice(0, input.limit);\n }\n\n // Phase 5: Build results with explanations, increment access\n return topN.map(({ memory, composite, parts }) => {\n this.#deps.memoryRepo.incrementAccess(memory.id);\n return {\n memory,\n score: composite,\n explanation: parts.relationSource\n ? `Related (${parts.relationSource.type}) to: ${parts.relationSource.title ?? parts.relationSource.id}`\n : buildExplanation(parts, memory),\n };\n });\n }\n\n /**\n * Smart session loading: returns context-matched, recent, and related memories\n * for session start context injection.\n */\n loadSessionContext(input: {\n readonly limit: number;\n readonly project?: string;\n readonly type?: MemoryType;\n }): readonly SessionContextResult[] {\n const contextBudget = Math.floor(input.limit * 0.4);\n const recentBudget = Math.floor(input.limit * 0.4);\n const relatedBudget = input.limit - contextBudget - recentBudget;\n const seenIds = new Set<string>();\n\n const contextMatched = this.#loadContextMatched(contextBudget, input.project, input.type, seenIds);\n const recent = this.#loadRecent(recentBudget, input.project, input.type, seenIds);\n\n const sourceIds = [...contextMatched, ...recent].map(r => r.result.memory.id);\n const related = this.#loadRelatedExpansion(sourceIds, relatedBudget, seenIds);\n\n const all = [...contextMatched, ...recent, ...related];\n for (const entry of all) {\n this.#deps.memoryRepo.incrementAccess(entry.result.memory.id);\n }\n return all;\n }\n\n #loadContextMatched(\n budget: number, project?: string, type?: MemoryType, seenIds?: Set<string>,\n ): SessionContextResult[] {\n if (budget <= 0) return [];\n const candidates = this.#deps.memoryRepo.getRecent(budget * 5, project, type);\n const scored: { memory: Memory; ctxScore: number; composite: number }[] = [];\n\n for (const m of candidates) {\n const ctxScore = computeContextScore(m.context, this.#gitContext, '');\n if (ctxScore <= 0.1) continue;\n const composite = ctxScore * 0.5 + m.importance * 0.3 + computeRecencyScore(m.updatedAt) * 0.2;\n scored.push({ memory: m, ctxScore, composite });\n }\n\n scored.sort((a, b) => b.composite - a.composite);\n const results: SessionContextResult[] = [];\n for (const s of scored.slice(0, budget)) {\n seenIds?.add(s.memory.id);\n results.push({ section: 'context', result: { memory: s.memory, score: s.composite, explanation: 'Context match' } });\n }\n return results;\n }\n\n #loadRecent(\n budget: number, project?: string, type?: MemoryType, seenIds?: Set<string>,\n ): SessionContextResult[] {\n if (budget <= 0) return [];\n const candidates = this.#deps.memoryRepo.getRecent(budget * 2, project, type);\n const results: SessionContextResult[] = [];\n\n for (const m of candidates) {\n if (seenIds?.has(m.id)) continue;\n const score = m.importance * 0.4 + computeRecencyScore(m.updatedAt) * 0.6;\n seenIds?.add(m.id);\n results.push({ section: 'recent', result: { memory: m, score, explanation: 'Recent' } });\n if (results.length >= budget) break;\n }\n return results;\n }\n\n #loadRelatedExpansion(\n sourceIds: readonly string[], budget: number, seenIds: Set<string>,\n ): SessionContextResult[] {\n if (budget <= 0) return [];\n const results: SessionContextResult[] = [];\n\n for (const srcId of sourceIds) {\n const relations = this.#deps.relationRepo.getByMemory(srcId);\n for (const rel of relations) {\n const otherId = rel.sourceId === srcId ? rel.targetId : rel.sourceId;\n if (otherId === srcId || seenIds.has(otherId)) continue;\n\n const other = this.#deps.memoryRepo.getById(otherId);\n if (!other) continue;\n\n const src = this.#deps.memoryRepo.getById(srcId);\n const weight = RELATION_TYPE_WEIGHTS[rel.relationType] ?? 0.5;\n seenIds.add(otherId);\n results.push({\n section: 'related',\n result: {\n memory: other,\n score: other.importance * weight,\n explanation: `Related (${rel.relationType}) to: ${src?.title ?? srcId}`,\n },\n });\n if (results.length >= budget) return results;\n }\n }\n return results;\n }\n\n #expandWithRelations(\n topResults: readonly { memory: Memory; composite: number; parts: ScoreParts }[],\n limit: number,\n seenIds: Set<string>,\n minImportance: number,\n ): { memory: Memory; composite: number; parts: ScoreParts }[] {\n if (topResults.length >= limit) return [];\n\n const expanded: { memory: Memory; composite: number; parts: ScoreParts }[] = [];\n const remaining = limit - topResults.length;\n const sourcesToExpand = topResults.slice(0, 5);\n\n for (const parent of sourcesToExpand) {\n const relations = this.#deps.relationRepo.getByMemory(parent.memory.id);\n for (const rel of relations) {\n const otherId = rel.sourceId === parent.memory.id ? rel.targetId : rel.sourceId;\n if (otherId === parent.memory.id || seenIds.has(otherId)) continue;\n\n const other = this.#deps.memoryRepo.getById(otherId);\n if (!other || other.importance < minImportance) continue;\n\n const weight = RELATION_TYPE_WEIGHTS[rel.relationType] ?? 0.5;\n const composite = parent.composite * 0.7 * weight;\n const parts: ScoreParts = {\n textScore: 0,\n importanceScore: other.importance,\n recencyScore: computeRecencyScore(other.updatedAt),\n accessScore: computeAccessScore(other.accessCount, other.lastAccessed),\n contextScore: 0,\n relationSource: { id: parent.memory.id, title: parent.memory.title, type: rel.relationType },\n };\n\n seenIds.add(otherId);\n expanded.push({ memory: other, composite, parts });\n if (expanded.length >= remaining) return expanded;\n }\n }\n\n return expanded;\n }\n}\n\n// ── Relation Expansion ──────────────────────────────────────\n\nconst RELATION_TYPE_WEIGHTS: Record<RelationType, number> = {\n depends_on: 1.0,\n extends: 0.9,\n implements: 0.9,\n relates_to: 0.7,\n derived_from: 0.6,\n contradicts: 0.3,\n};\n\n// ── FTS5-Only Fallback ───────────────────────────────────────\n\nfunction ftsOnlyScores(ftsResults: readonly { memoryId: string; rank: number }[]): Map<string, number> {\n const scores = new Map<string, number>();\n for (const r of ftsResults) {\n const score = Math.min(1, -r.rank / 20);\n scores.set(r.memoryId, score);\n }\n return scores;\n}\n\n// ── Scoring ───────────────────────────────────────────────────\n\ninterface ScoreParts {\n readonly textScore: number;\n readonly importanceScore: number;\n readonly recencyScore: number;\n readonly accessScore: number;\n readonly contextScore: number;\n readonly relationSource?: { readonly id: string; readonly title: string | null; readonly type: RelationType };\n}\n\nfunction computeScoreParts(\n memory: Memory,\n textScore: number,\n gitContext: GitContext,\n query: string,\n): ScoreParts {\n return {\n textScore,\n importanceScore: memory.importance,\n recencyScore: computeRecencyScore(memory.updatedAt),\n accessScore: computeAccessScore(memory.accessCount, memory.lastAccessed),\n contextScore: computeContextScore(memory.context, gitContext, query),\n };\n}\n\nfunction computeComposite(parts: ScoreParts): number {\n return (\n parts.textScore * SCORING_WEIGHTS.text +\n parts.importanceScore * SCORING_WEIGHTS.importance +\n parts.recencyScore * SCORING_WEIGHTS.recency +\n parts.accessScore * SCORING_WEIGHTS.access +\n parts.contextScore * SCORING_WEIGHTS.context\n );\n}\n\n/**\n * Recency score: 1.0 for today, decays exponentially.\n * Uses a 30-day half-life.\n */\nfunction computeRecencyScore(updatedAt: string): number {\n const ageMs = Date.now() - new Date(updatedAt).getTime();\n const ageDays = ageMs / (1000 * 60 * 60 * 24);\n if (ageDays < 0) return 1.0;\n return Math.exp(-ageDays * Math.LN2 / 30);\n}\n\n/**\n * Access score: logarithmic count x recency of last access.\n */\nfunction computeAccessScore(accessCount: number, lastAccessed: string | null): number {\n if (accessCount <= 0) return 0;\n const countScore = Math.min(1.0, Math.log10(accessCount + 1) / Math.log10(31));\n if (!lastAccessed) return countScore * 0.5;\n const ageDays = (Date.now() - new Date(lastAccessed).getTime()) / 86_400_000;\n const recency = Math.exp(-ageDays * Math.LN2 / 30);\n return countScore * (0.5 + 0.5 * recency);\n}\n\n// ── Explanation ───────────────────────────────────────────────\n\nfunction buildExplanation(parts: ScoreParts, memory: Memory): string {\n const factors: string[] = [];\n\n if (parts.textScore > 0.7) {\n factors.push(`High text match (${(parts.textScore * 100).toFixed(0)}%)`);\n } else if (parts.textScore > 0.3) {\n factors.push(`Moderate text match (${(parts.textScore * 100).toFixed(0)}%)`);\n }\n\n if (memory.importance > 0.7) {\n factors.push('High importance');\n }\n\n if (parts.recencyScore > 0.8) {\n factors.push('Very recent');\n } else if (parts.recencyScore > 0.5) {\n factors.push('Recent');\n }\n\n if (memory.accessCount > 10) {\n factors.push(`Frequently accessed (${memory.accessCount}x)`);\n } else if (memory.accessCount > 3) {\n factors.push(`Accessed ${memory.accessCount}x`);\n }\n\n if (parts.contextScore > 0.3) {\n factors.push('Context match');\n }\n\n const ageDays = Math.floor((Date.now() - new Date(memory.createdAt).getTime()) / 86_400_000);\n const stalenessThreshold = STALENESS_THRESHOLDS[memory.type];\n if (stalenessThreshold !== undefined && ageDays > stalenessThreshold) {\n factors.push(`${ageDays}d old - verify before acting`);\n }\n\n return factors.length > 0 ? factors.join(' + ') : 'Matched query';\n}\n\n// ── Types ────────────────────────────────────────────────────\n\nexport interface SessionContextResult {\n readonly section: 'context' | 'recent' | 'related';\n readonly result: SearchResult;\n}\n\n// Exported for testing\nexport { computeRecencyScore, computeAccessScore, computeComposite, computeScoreParts, ftsOnlyScores };\nexport type { ScoreParts };\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/context.ts","../src/commands/memory/services/decay-service.ts","../src/commands/memory/services/consolidation-service.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { RetrievalService } from '../services/retrieval-service.js';\nimport { DecayService } from '../services/decay-service.js';\nimport { ConsolidationService } from '../services/consolidation-service.js';\nimport { detectProject } from '../utils/project.js';\nimport { initStorage } from './init-storage.js';\nimport type { MemoryType } from '../types.js';\n\ninterface ContextOpts {\n readonly json?: boolean;\n readonly type?: string;\n readonly limit?: number;\n readonly dbPath?: string;\n}\n\nconst FULL_INJECT_THRESHOLD = 10;\nconst CONSOLIDATION_FILE = '.last-consolidation';\n\nfunction shouldConsolidate(dataDir: string, intervalDays: number): boolean {\n const checkpointPath = join(dataDir, CONSOLIDATION_FILE);\n try {\n const raw = readFileSync(checkpointPath, 'utf-8').trim();\n const lastRun = parseInt(raw, 10);\n if (isNaN(lastRun)) return true;\n const daysSince = (Date.now() - lastRun) / 86_400_000;\n return daysSince >= intervalDays;\n } catch {\n return true;\n }\n}\n\nfunction markConsolidated(dataDir: string): void {\n writeFileSync(join(dataDir, CONSOLIDATION_FILE), String(Date.now()), 'utf-8');\n}\n\nfunction write(msg: string): void {\n process.stdout.write(msg + '\\n');\n}\n\nexport async function runContext(opts: ContextOpts): Promise<void> {\n const ctx = initStorage(opts.dbPath);\n\n try {\n // Run maintenance (decay + consolidation) before loading context\n try {\n const decayService = new DecayService({\n memoryRepo: ctx.memoryRepo,\n relationRepo: ctx.relationRepo,\n });\n decayService.run();\n\n if (shouldConsolidate(ctx.dataDir, ctx.config.consolidationInterval)) {\n const consolidationService = new ConsolidationService({\n memoryRepo: ctx.memoryRepo,\n relationRepo: ctx.relationRepo,\n });\n await consolidationService.consolidate();\n markConsolidated(ctx.dataDir);\n }\n } catch (err) {\n process.stderr.write(`[agentic-memory] maintenance error: ${err instanceof Error ? err.message : err}\\n`);\n }\n\n const retrievalService = new RetrievalService({\n memoryRepo: ctx.memoryRepo,\n relationRepo: ctx.relationRepo,\n searchRepo: ctx.searchRepo,\n });\n\n const project = detectProject(process.cwd());\n const totalCount = ctx.memoryRepo.count(project ?? undefined);\n\n const results = retrievalService.loadSessionContext({\n limit: opts.limit ?? FULL_INJECT_THRESHOLD,\n project: project ?? undefined,\n type: opts.type as MemoryType | undefined,\n });\n\n if (results.length === 0) {\n write('No memories found for this project.');\n return;\n }\n\n const useGraph = totalCount > FULL_INJECT_THRESHOLD;\n\n if (opts.json) {\n write('# Agentic Memory - Session Context');\n if (useGraph) {\n write(`${totalCount} memories stored. Showing index only - use memory_search to get full content.\\n`);\n const graph = results.map(r => formatGraphEntry(r));\n write(JSON.stringify({ mode: 'graph', totalMemories: totalCount, memories: graph }, null, 2));\n } else {\n write('The following memories were loaded from previous sessions. Treat these as known facts.');\n write('When the user asks about something covered here, answer from these memories directly.\\n');\n const sections = {\n contextMatched: results.filter(r => r.section === 'context').map(formatFullEntry),\n recent: results.filter(r => r.section === 'recent').map(formatFullEntry),\n related: results.filter(r => r.section === 'related').map(formatFullEntry),\n };\n write(JSON.stringify({ mode: 'full', ...sections }, null, 2));\n }\n } else {\n write(`agentic-memory - Session context (${results.length}/${totalCount} memories)\\n`);\n for (const r of results) {\n const m = r.result.memory;\n write(` ${m.title ?? '(untitled)'} [${m.type}] - ${m.content.slice(0, 100)}${m.content.length > 100 ? '...' : ''}`);\n }\n }\n } finally {\n ctx.close();\n }\n}\n\ninterface ContextEntry {\n readonly section: string;\n readonly result: {\n readonly memory: {\n readonly id: string;\n readonly type: string;\n readonly title: string | null;\n readonly content: string;\n readonly importance: number;\n readonly tags: readonly string[];\n readonly createdAt: string;\n };\n readonly score: number;\n readonly explanation: string;\n };\n}\n\nfunction formatFullEntry(entry: ContextEntry) {\n const m = entry.result.memory;\n return {\n id: m.id,\n type: m.type,\n title: m.title,\n content: m.content.slice(0, 500),\n importance: m.importance,\n tags: m.tags,\n score: Math.round(entry.result.score * 100) / 100,\n createdAt: m.createdAt,\n };\n}\n\nfunction formatGraphEntry(entry: ContextEntry) {\n const m = entry.result.memory;\n return {\n id: m.id,\n type: m.type,\n title: m.title,\n importance: m.importance,\n tags: m.tags,\n section: entry.section,\n };\n}\n","import type { Memory, DecayParams } from '../types.js';\nimport type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\nimport { DEFAULT_DECAY_PARAMS } from '../config.js';\n\n// ── Types ────────────────────────────────────────────────────\n\nexport interface DecayServiceDeps {\n readonly memoryRepo: MemoryRepo;\n readonly relationRepo: RelationRepo;\n readonly params?: DecayParams;\n}\n\nexport interface DecayReport {\n readonly decayed: number;\n readonly pruned: number;\n readonly workingCleared: number;\n}\n\n// ── Decay Service ────────────────────────────────────────────\n\nexport class DecayService {\n readonly #memoryRepo: MemoryRepo;\n readonly #relationRepo: RelationRepo;\n readonly #params: DecayParams;\n\n constructor(deps: DecayServiceDeps) {\n this.#memoryRepo = deps.memoryRepo;\n this.#relationRepo = deps.relationRepo;\n this.#params = deps.params ?? DEFAULT_DECAY_PARAMS;\n }\n\n /**\n * Run full decay cycle: clear working memories, apply decay, prune dead memories.\n */\n run(): DecayReport {\n const workingCleared = this.clearWorkingMemories();\n const decayed = this.decayAll();\n const pruned = this.prune();\n return { decayed, pruned, workingCleared };\n }\n\n clearWorkingMemories(): number {\n return this.#memoryRepo.deleteByType('working');\n }\n\n /**\n * Apply decay formula to all non-working memories.\n */\n decayAll(): number {\n const memories = this.#memoryRepo.getAll();\n let updated = 0;\n\n for (const memory of memories) {\n if (memory.type === 'working') continue;\n\n const newImportance = this.computeDecayedImportance(memory);\n if (Math.abs(newImportance - memory.importance) > 0.001) {\n this.#memoryRepo.updateImportanceOnly(memory.id, newImportance);\n updated++;\n }\n }\n\n return updated;\n }\n\n /**\n * Hard-delete memories below prune threshold.\n */\n prune(): number {\n const memories = this.#memoryRepo.getAll();\n const now = Date.now();\n let pruned = 0;\n\n for (const memory of memories) {\n if (memory.type === 'working') continue;\n\n const ageDays = (now - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (\n ageDays > this.#params.pruneMinAgeDays &&\n memory.importance < this.#params.pruneThreshold &&\n memory.accessCount === 0\n ) {\n this.#memoryRepo.hardDelete(memory.id);\n pruned++;\n }\n }\n\n return pruned;\n }\n\n /**\n * Compute decayed importance as a pure function of age from creation.\n * Uses createdAt (immutable) to avoid compounding decay across sessions.\n */\n computeDecayedImportance(memory: Memory): number {\n const tau = this.#params.tauByType[memory.type];\n if (tau === 0) return memory.importance;\n\n const ageDays = (Date.now() - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (ageDays < 0) return memory.importance;\n\n // Synaptic consolidation window (days 0-7)\n if (ageDays <= 7) {\n if (memory.type === 'episodic') {\n const ebbinghaus = Math.exp(-ageDays * 0.4);\n return Math.max(this.#params.importanceFloor, memory.importance * ebbinghaus);\n }\n return memory.importance;\n }\n\n // Access modifier: higher access count = larger tau = slower decay\n const accessModifier = this.getAccessModifier(memory.accessCount);\n\n // Relation modifier: connected memories decay slower\n const relationCount = this.#relationRepo.countByMemory(memory.id);\n const relationModifier = relationCount >= this.#params.relationModifier.connectedThreshold\n ? this.#params.relationModifier.connectedMultiplier\n : this.#params.relationModifier.isolatedMultiplier;\n\n let effectiveTau = tau * accessModifier * relationModifier;\n\n // Injection penalty: surfaced but never used = noise\n if (memory.injectionCount > 5 && memory.accessCount === 0) {\n effectiveTau /= 1.5;\n }\n\n const decayFactor = Math.exp(-(ageDays - 7) / effectiveTau);\n const newImportance = memory.importance * decayFactor;\n\n return Math.max(this.#params.importanceFloor, newImportance);\n }\n\n private getAccessModifier(accessCount: number): number {\n for (const tier of this.#params.accessModifiers) {\n if (accessCount <= tier.maxCount) return tier.multiplier;\n }\n return 1.0;\n }\n}\n","import type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\n\n// ── Types ────────────────────────────────────────────────────\n\nexport interface ConsolidationDeps {\n readonly memoryRepo: MemoryRepo;\n readonly relationRepo: RelationRepo;\n}\n\nexport interface ConsolidationReport {\n readonly deduplicated: number;\n readonly episodicsCompressed: number;\n readonly pruned: number;\n}\n\n// ── Consolidation Service ────────────────────────────────────\n\nexport class ConsolidationService {\n readonly #deps: ConsolidationDeps;\n\n constructor(deps: ConsolidationDeps) {\n this.#deps = deps;\n }\n\n /**\n * Run consolidation pipeline.\n * Phase 1: Deduplicate exact/near-exact content matches\n * Phase 2: Compress old consolidated episodics\n * Phase 3: Prune dead memories\n */\n async consolidate(): Promise<ConsolidationReport> {\n const deduplicated = this.deduplicateMemories();\n const episodicsCompressed = this.compressEpisodics();\n const pruned = this.prune();\n return { deduplicated, episodicsCompressed, pruned };\n }\n\n /**\n * Phase 1: Deduplication via content similarity.\n */\n deduplicateMemories(): number {\n const memories = this.#deps.memoryRepo.getAll();\n const seen = new Set<string>();\n let merged = 0;\n\n for (const memory of memories) {\n if (seen.has(memory.id)) continue;\n\n const normalizedContent = normalizeText(memory.content);\n\n for (const other of memories) {\n if (other.id === memory.id) continue;\n if (seen.has(other.id)) continue;\n\n const otherNormalized = normalizeText(other.content);\n if (normalizedContent !== otherNormalized) continue;\n\n const [keeper, discard] = memory.importance >= other.importance\n ? [memory, other] : [other, memory];\n\n const mergedTags = [...new Set([...keeper.tags, ...discard.tags])];\n this.#deps.memoryRepo.updateContent(keeper.id, {\n tags: mergedTags,\n importance: Math.max(keeper.importance, discard.importance),\n });\n\n this.#deps.memoryRepo.hardDelete(discard.id);\n seen.add(discard.id);\n merged++;\n\n if (discard.id === memory.id) break;\n }\n\n seen.add(memory.id);\n }\n\n return merged;\n }\n\n /**\n * Phase 2: Compress old episodic memories that have been consolidated.\n */\n compressEpisodics(): number {\n const episodics = this.#deps.memoryRepo.getByType('episodic');\n const now = Date.now();\n let compressed = 0;\n\n for (const memory of episodics) {\n const ageDays = (now - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (ageDays <= 60) continue;\n if (memory.accessCount > 0) continue;\n if (memory.importance >= 0.2) continue;\n\n const relations = this.#deps.relationRepo.getBySource(memory.id);\n const isConsolidated = relations.some(r => r.relationType === 'derived_from');\n if (!isConsolidated) continue;\n\n this.#deps.memoryRepo.hardDelete(memory.id);\n compressed++;\n }\n\n return compressed;\n }\n\n /**\n * Phase 3: Prune dead memories.\n */\n prune(): number {\n const memories = this.#deps.memoryRepo.getAll();\n const now = Date.now();\n let pruned = 0;\n\n for (const memory of memories) {\n if (memory.type === 'working') continue;\n const ageDays = (now - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (ageDays > 90 && memory.importance < 0.1 && memory.accessCount === 0) {\n this.#deps.memoryRepo.hardDelete(memory.id);\n pruned++;\n }\n }\n\n return pruned;\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────\n\nfunction normalizeText(text: string): string {\n return text.toLowerCase().replace(/\\s+/g, ' ').trim();\n}\n"],"mappings":"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","names":[]}