@malindar/whyline 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/.claude/settings.local.json +33 -0
- package/.github/workflows/ci.yml +35 -0
- package/.github/workflows/publish.yml +37 -0
- package/.prettierrc.json +7 -0
- package/CLAUDE.md +74 -0
- package/LICENSE +21 -0
- package/README.md +359 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +125 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.js +42 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +111 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/edit.d.ts +1 -0
- package/dist/commands/edit.js +78 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/export.d.ts +8 -0
- package/dist/commands/export.js +90 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/import.d.ts +1 -0
- package/dist/commands/import.js +110 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +23 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install-claude.d.ts +3 -0
- package/dist/commands/install-claude.js +180 -0
- package/dist/commands/install-claude.js.map +1 -0
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.js +35 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/mcp.js +10 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/save.d.ts +4 -0
- package/dist/commands/save.js +74 -0
- package/dist/commands/save.js.map +1 -0
- package/dist/commands/search.d.ts +7 -0
- package/dist/commands/search.js +46 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/show.d.ts +3 -0
- package/dist/commands/show.js +30 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/stats.d.ts +1 -0
- package/dist/commands/stats.js +27 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/summarize.d.ts +3 -0
- package/dist/commands/summarize.js +140 -0
- package/dist/commands/summarize.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +17 -0
- package/dist/config.js.map +1 -0
- package/dist/db/connection.d.ts +2 -0
- package/dist/db/connection.js +8 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrations.d.ts +2 -0
- package/dist/db/migrations.js +19 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/schema.d.ts +5 -0
- package/dist/db/schema.js +64 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/git/diff.d.ts +2 -0
- package/dist/git/diff.js +45 -0
- package/dist/git/diff.js.map +1 -0
- package/dist/git/git.d.ts +3 -0
- package/dist/git/git.js +25 -0
- package/dist/git/git.js.map +1 -0
- package/dist/git/repoId.d.ts +3 -0
- package/dist/git/repoId.js +49 -0
- package/dist/git/repoId.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +296 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +119 -0
- package/dist/mcp/tools.js +43 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/memory/parseSummary.d.ts +14 -0
- package/dist/memory/parseSummary.js +53 -0
- package/dist/memory/parseSummary.js.map +1 -0
- package/dist/memory/qualityCheck.d.ts +13 -0
- package/dist/memory/qualityCheck.js +78 -0
- package/dist/memory/qualityCheck.js.map +1 -0
- package/dist/memory/redactSecrets.d.ts +7 -0
- package/dist/memory/redactSecrets.js +29 -0
- package/dist/memory/redactSecrets.js.map +1 -0
- package/dist/memory/repoContext.d.ts +2 -0
- package/dist/memory/repoContext.js +23 -0
- package/dist/memory/repoContext.js.map +1 -0
- package/dist/memory/saveMemory.d.ts +40 -0
- package/dist/memory/saveMemory.js +223 -0
- package/dist/memory/saveMemory.js.map +1 -0
- package/dist/memory/searchMemory.d.ts +17 -0
- package/dist/memory/searchMemory.js +122 -0
- package/dist/memory/searchMemory.js.map +1 -0
- package/dist/memory/types.d.ts +48 -0
- package/dist/memory/types.js +2 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/output/format.d.ts +3 -0
- package/dist/output/format.js +43 -0
- package/dist/output/format.js.map +1 -0
- package/docs/architecture.md +387 -0
- package/docs/ec6ab3bf-60cf-4629-ad9e-3048e8e3c43a.png +0 -0
- package/docs/logo.png +0 -0
- package/eslint.config.js +16 -0
- package/how-to-run/01-install.md +69 -0
- package/how-to-run/02-wire-up-your-repo.md +80 -0
- package/how-to-run/03-test-it-manually.md +91 -0
- package/how-to-run/04-test-with-claude-code.md +70 -0
- package/how-to-run/CLAUDE.md.template +72 -0
- package/how-to-run/README.md +49 -0
- package/package.json +60 -0
- package/src/cli.ts +142 -0
- package/src/commands/delete.ts +47 -0
- package/src/commands/doctor.ts +128 -0
- package/src/commands/edit.ts +80 -0
- package/src/commands/export.ts +95 -0
- package/src/commands/import.ts +119 -0
- package/src/commands/init.ts +31 -0
- package/src/commands/install-claude.ts +203 -0
- package/src/commands/list.ts +41 -0
- package/src/commands/mcp.ts +12 -0
- package/src/commands/save.ts +85 -0
- package/src/commands/search.ts +56 -0
- package/src/commands/show.ts +37 -0
- package/src/commands/stats.ts +31 -0
- package/src/commands/summarize.ts +183 -0
- package/src/config.ts +26 -0
- package/src/db/connection.ts +8 -0
- package/src/db/migrations.ts +26 -0
- package/src/db/schema.ts +68 -0
- package/src/git/diff.ts +43 -0
- package/src/git/git.ts +25 -0
- package/src/git/repoId.ts +49 -0
- package/src/hooks/post-commit.sample.sh +9 -0
- package/src/mcp/server.ts +326 -0
- package/src/mcp/tools.ts +53 -0
- package/src/memory/parseSummary.ts +72 -0
- package/src/memory/qualityCheck.ts +102 -0
- package/src/memory/redactSecrets.ts +32 -0
- package/src/memory/repoContext.ts +25 -0
- package/src/memory/saveMemory.ts +369 -0
- package/src/memory/searchMemory.ts +153 -0
- package/src/memory/types.ts +57 -0
- package/src/output/format.ts +44 -0
- package/src/skill/SKILL.md +95 -0
- package/tests/cliV02.test.ts +213 -0
- package/tests/doctor.test.ts +253 -0
- package/tests/exportImport.test.ts +248 -0
- package/tests/fileRename.test.ts +156 -0
- package/tests/gitHelpers.test.ts +94 -0
- package/tests/init.test.ts +93 -0
- package/tests/installClaude.test.ts +157 -0
- package/tests/parseSummary.test.ts +111 -0
- package/tests/qualityCheck.test.ts +182 -0
- package/tests/redactSecrets.test.ts +75 -0
- package/tests/saveMemory.test.ts +196 -0
- package/tests/searchFilters.test.ts +139 -0
- package/tests/searchMemory.test.ts +273 -0
- package/tests/stale.test.ts +47 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
export function generateMemoryId() {
|
|
3
|
+
const timestamp = Date.now().toString(36);
|
|
4
|
+
const random = crypto.randomUUID().replace(/-/g, "").slice(0, 8);
|
|
5
|
+
return `mem_${timestamp}${random}`;
|
|
6
|
+
}
|
|
7
|
+
export function buildEmbeddingText(memory) {
|
|
8
|
+
return [
|
|
9
|
+
memory.intent,
|
|
10
|
+
memory.summary,
|
|
11
|
+
memory.decision,
|
|
12
|
+
memory.why,
|
|
13
|
+
...memory.alternativesRejected,
|
|
14
|
+
...memory.risks,
|
|
15
|
+
...memory.followUps,
|
|
16
|
+
...memory.tags,
|
|
17
|
+
...memory.files,
|
|
18
|
+
memory.commitSha ?? "",
|
|
19
|
+
]
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.join(" ");
|
|
22
|
+
}
|
|
23
|
+
export function saveMemory(db, memory) {
|
|
24
|
+
const insertMemory = db.prepare(`
|
|
25
|
+
INSERT INTO memories (
|
|
26
|
+
id, created_at, updated_at,
|
|
27
|
+
repo_id, repo_path, repo_name, branch, commit_sha,
|
|
28
|
+
task, intent, summary, decision, why,
|
|
29
|
+
source, raw_transcript_path, embedding_text
|
|
30
|
+
) VALUES (
|
|
31
|
+
?, ?, ?,
|
|
32
|
+
?, ?, ?, ?, ?,
|
|
33
|
+
?, ?, ?, ?, ?,
|
|
34
|
+
?, ?, ?
|
|
35
|
+
)
|
|
36
|
+
`);
|
|
37
|
+
const insertFile = db.prepare("INSERT OR IGNORE INTO memory_files (memory_id, file_path) VALUES (?, ?)");
|
|
38
|
+
const insertTag = db.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
|
|
39
|
+
const insertAlt = db.prepare("INSERT OR IGNORE INTO memory_alternatives (memory_id, value) VALUES (?, ?)");
|
|
40
|
+
const insertRisk = db.prepare("INSERT OR IGNORE INTO memory_risks (memory_id, value) VALUES (?, ?)");
|
|
41
|
+
const insertFollowup = db.prepare("INSERT OR IGNORE INTO memory_followups (memory_id, value) VALUES (?, ?)");
|
|
42
|
+
const run = db.transaction(() => {
|
|
43
|
+
insertMemory.run(memory.id, memory.createdAt, memory.updatedAt, memory.repoId, memory.repoPath ?? null, memory.repoName ?? null, memory.branch ?? null, memory.commitSha ?? null, memory.task ?? null, memory.intent, memory.summary, memory.decision, memory.why, memory.source, memory.rawTranscriptPath ?? null, memory.embeddingText);
|
|
44
|
+
for (const f of memory.files)
|
|
45
|
+
insertFile.run(memory.id, f);
|
|
46
|
+
for (const t of memory.tags)
|
|
47
|
+
insertTag.run(memory.id, t);
|
|
48
|
+
for (const a of memory.alternativesRejected)
|
|
49
|
+
insertAlt.run(memory.id, a);
|
|
50
|
+
for (const r of memory.risks)
|
|
51
|
+
insertRisk.run(memory.id, r);
|
|
52
|
+
for (const fu of memory.followUps)
|
|
53
|
+
insertFollowup.run(memory.id, fu);
|
|
54
|
+
});
|
|
55
|
+
run();
|
|
56
|
+
}
|
|
57
|
+
function hydrateMemory(db, row) {
|
|
58
|
+
const files = db
|
|
59
|
+
.prepare("SELECT file_path FROM memory_files WHERE memory_id = ?")
|
|
60
|
+
.all(row.id)
|
|
61
|
+
.map((r) => r.file_path);
|
|
62
|
+
const tags = db
|
|
63
|
+
.prepare("SELECT tag FROM memory_tags WHERE memory_id = ?")
|
|
64
|
+
.all(row.id)
|
|
65
|
+
.map((r) => r.tag);
|
|
66
|
+
const alternativesRejected = db
|
|
67
|
+
.prepare("SELECT value FROM memory_alternatives WHERE memory_id = ?")
|
|
68
|
+
.all(row.id)
|
|
69
|
+
.map((r) => r.value);
|
|
70
|
+
const risks = db
|
|
71
|
+
.prepare("SELECT value FROM memory_risks WHERE memory_id = ?")
|
|
72
|
+
.all(row.id)
|
|
73
|
+
.map((r) => r.value);
|
|
74
|
+
const followUps = db
|
|
75
|
+
.prepare("SELECT value FROM memory_followups WHERE memory_id = ?")
|
|
76
|
+
.all(row.id)
|
|
77
|
+
.map((r) => r.value);
|
|
78
|
+
return {
|
|
79
|
+
id: row.id,
|
|
80
|
+
createdAt: row.created_at,
|
|
81
|
+
updatedAt: row.updated_at,
|
|
82
|
+
repoId: row.repo_id,
|
|
83
|
+
repoPath: row.repo_path ?? undefined,
|
|
84
|
+
repoName: row.repo_name ?? undefined,
|
|
85
|
+
branch: row.branch ?? undefined,
|
|
86
|
+
commitSha: row.commit_sha ?? undefined,
|
|
87
|
+
task: row.task ?? undefined,
|
|
88
|
+
intent: row.intent,
|
|
89
|
+
summary: row.summary,
|
|
90
|
+
decision: row.decision,
|
|
91
|
+
why: row.why,
|
|
92
|
+
source: row.source,
|
|
93
|
+
rawTranscriptPath: row.raw_transcript_path ?? undefined,
|
|
94
|
+
embeddingText: row.embedding_text,
|
|
95
|
+
files,
|
|
96
|
+
tags,
|
|
97
|
+
alternativesRejected,
|
|
98
|
+
risks,
|
|
99
|
+
followUps,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function getMemoryById(db, id) {
|
|
103
|
+
const row = db
|
|
104
|
+
.prepare("SELECT * FROM memories WHERE id = ?")
|
|
105
|
+
.get(id);
|
|
106
|
+
return row ? hydrateMemory(db, row) : null;
|
|
107
|
+
}
|
|
108
|
+
export function getMemoryByCommit(db, commitSha) {
|
|
109
|
+
const row = db
|
|
110
|
+
.prepare("SELECT * FROM memories WHERE commit_sha = ? LIMIT 1")
|
|
111
|
+
.get(commitSha);
|
|
112
|
+
return row ? hydrateMemory(db, row) : null;
|
|
113
|
+
}
|
|
114
|
+
export function getMemoriesByCommit(db, commitSha) {
|
|
115
|
+
const rows = db
|
|
116
|
+
.prepare("SELECT * FROM memories WHERE commit_sha = ?")
|
|
117
|
+
.all(commitSha);
|
|
118
|
+
return rows.map((r) => hydrateMemory(db, r));
|
|
119
|
+
}
|
|
120
|
+
export function getMemoriesByFile(db, repoId, filePaths, limit) {
|
|
121
|
+
const paths = Array.isArray(filePaths) ? filePaths : [filePaths];
|
|
122
|
+
const placeholders = paths.map(() => "?").join(", ");
|
|
123
|
+
let rows;
|
|
124
|
+
if (repoId) {
|
|
125
|
+
rows = db
|
|
126
|
+
.prepare(`SELECT DISTINCT m.* FROM memories m
|
|
127
|
+
JOIN memory_files f ON f.memory_id = m.id
|
|
128
|
+
WHERE m.repo_id = ? AND f.file_path IN (${placeholders})
|
|
129
|
+
ORDER BY m.created_at DESC
|
|
130
|
+
LIMIT ?`)
|
|
131
|
+
.all(repoId, ...paths, limit);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
rows = db
|
|
135
|
+
.prepare(`SELECT DISTINCT m.* FROM memories m
|
|
136
|
+
JOIN memory_files f ON f.memory_id = m.id
|
|
137
|
+
WHERE f.file_path IN (${placeholders})
|
|
138
|
+
ORDER BY m.created_at DESC
|
|
139
|
+
LIMIT ?`)
|
|
140
|
+
.all(...paths, limit);
|
|
141
|
+
}
|
|
142
|
+
return rows.map((r) => hydrateMemory(db, r));
|
|
143
|
+
}
|
|
144
|
+
export function getAllMemories(db) {
|
|
145
|
+
const rows = db
|
|
146
|
+
.prepare("SELECT * FROM memories ORDER BY created_at DESC")
|
|
147
|
+
.all();
|
|
148
|
+
return rows.map((r) => hydrateMemory(db, r));
|
|
149
|
+
}
|
|
150
|
+
export function getMemoriesByRepoId(db, repoId) {
|
|
151
|
+
const rows = db
|
|
152
|
+
.prepare("SELECT * FROM memories WHERE repo_id = ? ORDER BY created_at DESC")
|
|
153
|
+
.all(repoId);
|
|
154
|
+
return rows.map((r) => hydrateMemory(db, r));
|
|
155
|
+
}
|
|
156
|
+
export function getMemoriesByRepoPath(db, repoPath) {
|
|
157
|
+
const rows = db
|
|
158
|
+
.prepare("SELECT * FROM memories WHERE repo_path LIKE ? ORDER BY created_at DESC")
|
|
159
|
+
.all(`%${repoPath}%`);
|
|
160
|
+
return rows.map((r) => hydrateMemory(db, r));
|
|
161
|
+
}
|
|
162
|
+
export function listMemories(db, options) {
|
|
163
|
+
let rows;
|
|
164
|
+
if (options.repoId) {
|
|
165
|
+
rows = db
|
|
166
|
+
.prepare("SELECT * FROM memories WHERE repo_id = ? ORDER BY created_at DESC LIMIT ?")
|
|
167
|
+
.all(options.repoId, options.limit);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
rows = db
|
|
171
|
+
.prepare("SELECT * FROM memories ORDER BY created_at DESC LIMIT ?")
|
|
172
|
+
.all(options.limit);
|
|
173
|
+
}
|
|
174
|
+
return rows.map((r) => hydrateMemory(db, r));
|
|
175
|
+
}
|
|
176
|
+
export function deleteMemory(db, id) {
|
|
177
|
+
db.prepare("DELETE FROM memories WHERE id = ?").run(id);
|
|
178
|
+
}
|
|
179
|
+
export function getStats(db) {
|
|
180
|
+
const row = db
|
|
181
|
+
.prepare("SELECT COUNT(*) as total, COUNT(DISTINCT repo_id) as repos, MIN(created_at) as oldest, MAX(created_at) as newest FROM memories")
|
|
182
|
+
.get();
|
|
183
|
+
const topFiles = db
|
|
184
|
+
.prepare("SELECT file_path, COUNT(*) as count FROM memory_files GROUP BY file_path ORDER BY count DESC LIMIT 10")
|
|
185
|
+
.all()
|
|
186
|
+
.map((r) => ({ filePath: r.file_path, count: r.count }));
|
|
187
|
+
return {
|
|
188
|
+
total: row?.total ?? 0,
|
|
189
|
+
repos: row?.repos ?? 0,
|
|
190
|
+
oldest: row?.oldest ? new Date(row.oldest).toLocaleDateString() : "-",
|
|
191
|
+
newest: row?.newest ? new Date(row.newest).toLocaleDateString() : "-",
|
|
192
|
+
topFiles,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export function updateMemory(db, id, updates) {
|
|
196
|
+
const now = new Date().toISOString();
|
|
197
|
+
db.prepare("UPDATE memories SET intent = ?, summary = ?, decision = ?, why = ?, task = ?, embedding_text = ?, updated_at = ? WHERE id = ?").run(updates.intent ?? "", updates.summary ?? "", updates.decision ?? "", updates.why ?? "", updates.task ?? null, updates.embeddingText ?? "", now, id);
|
|
198
|
+
if (updates.tags !== undefined) {
|
|
199
|
+
db.prepare("DELETE FROM memory_tags WHERE memory_id = ?").run(id);
|
|
200
|
+
const ins = db.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
|
|
201
|
+
for (const t of updates.tags)
|
|
202
|
+
ins.run(id, t);
|
|
203
|
+
}
|
|
204
|
+
if (updates.alternativesRejected !== undefined) {
|
|
205
|
+
db.prepare("DELETE FROM memory_alternatives WHERE memory_id = ?").run(id);
|
|
206
|
+
const ins = db.prepare("INSERT OR IGNORE INTO memory_alternatives (memory_id, value) VALUES (?, ?)");
|
|
207
|
+
for (const a of updates.alternativesRejected)
|
|
208
|
+
ins.run(id, a);
|
|
209
|
+
}
|
|
210
|
+
if (updates.risks !== undefined) {
|
|
211
|
+
db.prepare("DELETE FROM memory_risks WHERE memory_id = ?").run(id);
|
|
212
|
+
const ins = db.prepare("INSERT OR IGNORE INTO memory_risks (memory_id, value) VALUES (?, ?)");
|
|
213
|
+
for (const r of updates.risks)
|
|
214
|
+
ins.run(id, r);
|
|
215
|
+
}
|
|
216
|
+
if (updates.followUps !== undefined) {
|
|
217
|
+
db.prepare("DELETE FROM memory_followups WHERE memory_id = ?").run(id);
|
|
218
|
+
const ins = db.prepare("INSERT OR IGNORE INTO memory_followups (memory_id, value) VALUES (?, ?)");
|
|
219
|
+
for (const fu of updates.followUps)
|
|
220
|
+
ins.run(id, fu);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=saveMemory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saveMemory.js","sourceRoot":"","sources":["../../src/memory/saveMemory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { CodingMemory, ScoreBreakdown, SearchResult } from "./types.js";
|
|
3
|
+
export declare const STALE_THRESHOLD_DAYS = 90;
|
|
4
|
+
export declare function isStale(memory: CodingMemory, thresholdDays?: number): boolean;
|
|
5
|
+
export type SearchOptions = {
|
|
6
|
+
query: string;
|
|
7
|
+
repoId?: string;
|
|
8
|
+
repoPath?: string;
|
|
9
|
+
files?: string[];
|
|
10
|
+
tags?: string[];
|
|
11
|
+
since?: string;
|
|
12
|
+
before?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function scoreMemory(memory: CodingMemory, query: string, contextRepoId: string | null, contextFiles: string[]): ScoreBreakdown;
|
|
16
|
+
export declare function explainRelevance(scores: ScoreBreakdown): string;
|
|
17
|
+
export declare function searchMemory(db: Database.Database, options: SearchOptions): SearchResult[];
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { getMemoriesByRepoId, getMemoriesByRepoPath, getAllMemories, } from "./saveMemory.js";
|
|
2
|
+
export const STALE_THRESHOLD_DAYS = 90;
|
|
3
|
+
export function isStale(memory, thresholdDays = STALE_THRESHOLD_DAYS) {
|
|
4
|
+
const ageMs = Date.now() - new Date(memory.createdAt).getTime();
|
|
5
|
+
return ageMs > thresholdDays * 24 * 60 * 60 * 1000;
|
|
6
|
+
}
|
|
7
|
+
export function scoreMemory(memory, query, contextRepoId, contextFiles) {
|
|
8
|
+
const words = query
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.split(/\s+/)
|
|
11
|
+
.filter(Boolean);
|
|
12
|
+
if (words.length === 0) {
|
|
13
|
+
const sameRepo = contextRepoId && memory.repoId === contextRepoId ? 10 : 0;
|
|
14
|
+
const ageMs = Date.now() - new Date(memory.createdAt).getTime();
|
|
15
|
+
const recency = ageMs < 30 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
|
16
|
+
return { total: sameRepo + recency, sameRepo, fileOverlap: 0, tagMatch: 0, decisionMatch: 0, whyMatch: 0, summaryMatch: 0, filePathMatch: 0, recency };
|
|
17
|
+
}
|
|
18
|
+
const hasKeyword = (text) => words.some((w) => text.toLowerCase().includes(w));
|
|
19
|
+
const sameRepo = contextRepoId && memory.repoId === contextRepoId ? 10 : 0;
|
|
20
|
+
const fileOverlap = contextFiles.some((f) => memory.files.includes(f)) ? 8 : 0;
|
|
21
|
+
const tagMatch = memory.tags.some(hasKeyword) ? 5 : 0;
|
|
22
|
+
const decisionMatch = hasKeyword(memory.decision) ? 4 : 0;
|
|
23
|
+
const whyMatch = hasKeyword(memory.why) ? 3 : 0;
|
|
24
|
+
const summaryMatch = hasKeyword(memory.summary) ? 2 : 0;
|
|
25
|
+
const filePathMatch = memory.files.some(hasKeyword) ? 2 : 0;
|
|
26
|
+
const ageMs = Date.now() - new Date(memory.createdAt).getTime();
|
|
27
|
+
const recency = ageMs < 30 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
|
28
|
+
const total = sameRepo +
|
|
29
|
+
fileOverlap +
|
|
30
|
+
tagMatch +
|
|
31
|
+
decisionMatch +
|
|
32
|
+
whyMatch +
|
|
33
|
+
summaryMatch +
|
|
34
|
+
filePathMatch +
|
|
35
|
+
recency;
|
|
36
|
+
return {
|
|
37
|
+
total,
|
|
38
|
+
sameRepo,
|
|
39
|
+
fileOverlap,
|
|
40
|
+
tagMatch,
|
|
41
|
+
decisionMatch,
|
|
42
|
+
whyMatch,
|
|
43
|
+
summaryMatch,
|
|
44
|
+
filePathMatch,
|
|
45
|
+
recency,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function explainRelevance(scores) {
|
|
49
|
+
const parts = [];
|
|
50
|
+
if (scores.sameRepo)
|
|
51
|
+
parts.push(`same repo (+${scores.sameRepo})`);
|
|
52
|
+
if (scores.fileOverlap)
|
|
53
|
+
parts.push(`file overlap (+${scores.fileOverlap})`);
|
|
54
|
+
if (scores.tagMatch)
|
|
55
|
+
parts.push(`tag match (+${scores.tagMatch})`);
|
|
56
|
+
if (scores.decisionMatch)
|
|
57
|
+
parts.push(`keyword in decision (+${scores.decisionMatch})`);
|
|
58
|
+
if (scores.whyMatch)
|
|
59
|
+
parts.push(`keyword in why (+${scores.whyMatch})`);
|
|
60
|
+
if (scores.summaryMatch)
|
|
61
|
+
parts.push(`keyword in summary (+${scores.summaryMatch})`);
|
|
62
|
+
if (scores.filePathMatch)
|
|
63
|
+
parts.push(`keyword in file path (+${scores.filePathMatch})`);
|
|
64
|
+
if (scores.recency)
|
|
65
|
+
parts.push(`recent memory (+${scores.recency})`);
|
|
66
|
+
return parts.length ? `Matched: ${parts.join(", ")}` : "No specific match factors";
|
|
67
|
+
}
|
|
68
|
+
export function searchMemory(db, options) {
|
|
69
|
+
const { query, repoId, repoPath, files = [], tags = [], since, before, limit = 10 } = options;
|
|
70
|
+
let memories = [];
|
|
71
|
+
if (repoId) {
|
|
72
|
+
memories = getMemoriesByRepoId(db, repoId);
|
|
73
|
+
if (memories.length === 0 && repoPath) {
|
|
74
|
+
memories = getMemoriesByRepoPath(db, repoPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (repoPath) {
|
|
78
|
+
memories = getMemoriesByRepoPath(db, repoPath);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
memories = getAllMemories(db);
|
|
82
|
+
}
|
|
83
|
+
// Date filters
|
|
84
|
+
const sinceMs = since ? new Date(since).getTime() : null;
|
|
85
|
+
const beforeMs = before ? new Date(before).getTime() : null;
|
|
86
|
+
if (sinceMs !== null || beforeMs !== null) {
|
|
87
|
+
memories = memories.filter((m) => {
|
|
88
|
+
const t = new Date(m.createdAt).getTime();
|
|
89
|
+
if (sinceMs !== null && t < sinceMs)
|
|
90
|
+
return false;
|
|
91
|
+
if (beforeMs !== null && t > beforeMs)
|
|
92
|
+
return false;
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Tag filter — memory must have ALL requested tags
|
|
97
|
+
if (tags.length > 0) {
|
|
98
|
+
const lowerTags = tags.map((t) => t.toLowerCase());
|
|
99
|
+
memories = memories.filter((m) => lowerTags.every((tag) => m.tags.map((t) => t.toLowerCase()).includes(tag)));
|
|
100
|
+
}
|
|
101
|
+
const emptyQuery = query.trim() === "";
|
|
102
|
+
const results = memories
|
|
103
|
+
.map((memory) => {
|
|
104
|
+
const score = scoreMemory(memory, query, repoId ?? null, files);
|
|
105
|
+
return { memory, score, relevanceReason: explainRelevance(score) };
|
|
106
|
+
})
|
|
107
|
+
.filter((r) => {
|
|
108
|
+
if (emptyQuery)
|
|
109
|
+
return true;
|
|
110
|
+
const contentScore = r.score.fileOverlap +
|
|
111
|
+
r.score.tagMatch +
|
|
112
|
+
r.score.decisionMatch +
|
|
113
|
+
r.score.whyMatch +
|
|
114
|
+
r.score.summaryMatch +
|
|
115
|
+
r.score.filePathMatch;
|
|
116
|
+
return contentScore > 0;
|
|
117
|
+
})
|
|
118
|
+
.sort((a, b) => b.score.total - a.score.total)
|
|
119
|
+
.slice(0, limit);
|
|
120
|
+
return results;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=searchMemory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"searchMemory.js","sourceRoot":"","sources":["../../src/memory/searchMemory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type CodingMemory = {
|
|
2
|
+
id: string;
|
|
3
|
+
createdAt: string;
|
|
4
|
+
updatedAt: string;
|
|
5
|
+
repoId: string;
|
|
6
|
+
repoPath?: string;
|
|
7
|
+
repoName?: string;
|
|
8
|
+
branch?: string;
|
|
9
|
+
commitSha?: string;
|
|
10
|
+
files: string[];
|
|
11
|
+
tags: string[];
|
|
12
|
+
task?: string;
|
|
13
|
+
intent: string;
|
|
14
|
+
summary: string;
|
|
15
|
+
decision: string;
|
|
16
|
+
why: string;
|
|
17
|
+
alternativesRejected: string[];
|
|
18
|
+
risks: string[];
|
|
19
|
+
followUps: string[];
|
|
20
|
+
source: "manual" | "claude-code" | "cli" | "hook";
|
|
21
|
+
rawTranscriptPath?: string;
|
|
22
|
+
embeddingText: string;
|
|
23
|
+
};
|
|
24
|
+
export type ScoreBreakdown = {
|
|
25
|
+
total: number;
|
|
26
|
+
sameRepo: number;
|
|
27
|
+
fileOverlap: number;
|
|
28
|
+
tagMatch: number;
|
|
29
|
+
decisionMatch: number;
|
|
30
|
+
whyMatch: number;
|
|
31
|
+
summaryMatch: number;
|
|
32
|
+
filePathMatch: number;
|
|
33
|
+
recency: number;
|
|
34
|
+
};
|
|
35
|
+
export type SearchResult = {
|
|
36
|
+
memory: CodingMemory;
|
|
37
|
+
score: ScoreBreakdown;
|
|
38
|
+
relevanceReason: string;
|
|
39
|
+
};
|
|
40
|
+
export type RepoContext = {
|
|
41
|
+
repoRoot: string;
|
|
42
|
+
repoId: string;
|
|
43
|
+
repoPath: string;
|
|
44
|
+
repoName: string;
|
|
45
|
+
branch: string | null;
|
|
46
|
+
commitSha: string;
|
|
47
|
+
changedFiles: string[];
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/memory/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isStale } from "../memory/searchMemory.js";
|
|
2
|
+
export function formatMemory(memory, verbose = false) {
|
|
3
|
+
const staleNote = isStale(memory) ? " [STALE — older than 90 days, verify still applies]" : "";
|
|
4
|
+
const lines = [memory.id + staleNote];
|
|
5
|
+
if (memory.commitSha)
|
|
6
|
+
lines.push(`Commit: ${memory.commitSha.slice(0, 8)}`);
|
|
7
|
+
if (memory.repoName)
|
|
8
|
+
lines.push(`Repo: ${memory.repoName}`);
|
|
9
|
+
if (memory.files.length)
|
|
10
|
+
lines.push(`Files: ${memory.files.join(", ")}`);
|
|
11
|
+
lines.push("", "Intent:", ` ${memory.intent}`);
|
|
12
|
+
lines.push("", "Decision:", ` ${memory.decision}`);
|
|
13
|
+
lines.push("", "Why:", ` ${memory.why}`);
|
|
14
|
+
if (memory.risks.length) {
|
|
15
|
+
lines.push("", "Risks:");
|
|
16
|
+
for (const r of memory.risks)
|
|
17
|
+
lines.push(` - ${r}`);
|
|
18
|
+
}
|
|
19
|
+
if (verbose) {
|
|
20
|
+
if (memory.alternativesRejected.length) {
|
|
21
|
+
lines.push("", "Alternatives rejected:");
|
|
22
|
+
for (const a of memory.alternativesRejected)
|
|
23
|
+
lines.push(` - ${a}`);
|
|
24
|
+
}
|
|
25
|
+
if (memory.followUps.length) {
|
|
26
|
+
lines.push("", "Follow-ups:");
|
|
27
|
+
for (const fu of memory.followUps)
|
|
28
|
+
lines.push(` - ${fu}`);
|
|
29
|
+
}
|
|
30
|
+
if (memory.tags.length) {
|
|
31
|
+
lines.push("", `Tags: ${memory.tags.join(", ")}`);
|
|
32
|
+
}
|
|
33
|
+
if (memory.task) {
|
|
34
|
+
lines.push("", `Task: ${memory.task}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push("", `Summary: ${memory.summary}`);
|
|
37
|
+
}
|
|
38
|
+
return lines.join("\n");
|
|
39
|
+
}
|
|
40
|
+
export function formatSearchResult(result) {
|
|
41
|
+
return `${formatMemory(result.memory)}\n\n [${result.relevanceReason}]`;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/output/format.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpD,MAAM,UAAU,YAAY,CAAC,MAAoB,EAAE,OAAO,GAAG,KAAK;IAChE,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,sDAAsD,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;IAEhD,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5E,IAAI,MAAM,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEzE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAE1C,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC;YACzC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,oBAAoB;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;YAC9B,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,MAAM,CAAC,eAAe,GAAG,CAAC;AAC3E,CAAC"}
|