fastrmemory 0.3.0 → 0.4.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-plugin/marketplace.json +14 -14
- package/.claude-plugin/plugin.json +18 -18
- package/.cursor/mcp.json +3 -1
- package/.cursor/skills/fastr-compress/SKILL.md +33 -33
- package/.cursor/skills/fastr-curate/SKILL.md +62 -62
- package/.cursor/skills/fastr-dag/SKILL.md +47 -47
- package/.cursor/skills/fastr-doctor/SKILL.md +39 -39
- package/.cursor/skills/fastr-memory/SKILL.md +51 -51
- package/.cursor/skills/fastr-plan-estimate/SKILL.md +45 -45
- package/.cursor/skills/fastr-session-commit/SKILL.md +49 -49
- package/.cursor/skills/fastr-setup/SKILL.md +45 -45
- package/.cursor/skills/fastr-trap-log/SKILL.md +39 -39
- package/.cursor/skills/fastr-vision/SKILL.md +35 -35
- package/.cursor/skills/skills.json +65 -65
- package/README.md +642 -729
- package/bin/fastr-guard.mjs +61 -0
- package/dist/bin/fastr.js +68 -10
- package/dist/bin/fastr.js.map +1 -1
- package/dist/src/bench/benchmark.js +13 -13
- package/dist/src/bench/harness.js +17 -17
- package/dist/src/bench/public-harness.js +5 -5
- package/dist/src/branch/manager.js +31 -31
- package/dist/src/ci/guardian.js +9 -9
- package/dist/src/db/doctor.js +25 -25
- package/dist/src/db/hygiene.js +23 -23
- package/dist/src/db/repository.js +283 -283
- package/dist/src/db/schema.js +268 -268
- package/dist/src/db/spool.js +4 -4
- package/dist/src/export/obsidian.js +15 -15
- package/dist/src/import/local.js +4 -4
- package/dist/src/installer/mcp-init.d.ts +65 -0
- package/dist/src/installer/mcp-init.d.ts.map +1 -0
- package/dist/src/installer/mcp-init.js +293 -0
- package/dist/src/installer/mcp-init.js.map +1 -0
- package/dist/src/installer/setup.d.ts +2 -0
- package/dist/src/installer/setup.d.ts.map +1 -1
- package/dist/src/installer/setup.js +24 -18
- package/dist/src/installer/setup.js.map +1 -1
- package/dist/src/mcp/server.js +25 -25
- package/dist/src/mirror/markdown-pages.js +22 -22
- package/dist/src/search/backfill.js +6 -6
- package/dist/src/search/hybrid-rrf.js +60 -60
- package/dist/src/ui/server.js +1259 -1259
- package/dist/src/vision/assets.js +6 -6
- package/dist-ui/assets/ActionsPage-B3quzFNF.js +11 -11
- package/dist-ui/assets/GraphPage-DetiATmC.js +1 -1
- package/dist-ui/assets/ObservatoryPage-QIGMwENf.js +16 -16
- package/dist-ui/assets/TreemapPage-C7uLZd37.js +2 -2
- package/dist-ui/assets/index-BJnPINTu.css +1 -1
- package/dist-ui/assets/index-DWAH--Fu.js +329 -329
- package/dist-ui/assets/maximize-2-BebkGbZA.js +6 -6
- package/dist-ui/build-manifest.json +95 -95
- package/dist-ui/index.html +26 -26
- package/llms-install.md +77 -69
- package/package.json +108 -107
- package/server.json +28 -28
- package/skills/fastr-compress/SKILL.md +33 -33
- package/skills/fastr-curate/SKILL.md +62 -62
- package/skills/fastr-dag/SKILL.md +47 -47
- package/skills/fastr-doctor/SKILL.md +39 -39
- package/skills/fastr-memory/SKILL.md +51 -51
- package/skills/fastr-plan-estimate/SKILL.md +45 -45
- package/skills/fastr-session-commit/SKILL.md +49 -49
- package/skills/fastr-setup/SKILL.md +45 -45
- package/skills/fastr-trap-log/SKILL.md +39 -39
- package/skills/fastr-vision/SKILL.md +35 -35
- package/skills/skills.json +65 -65
|
@@ -45,28 +45,28 @@ export function modulePageFileName(moduleName) {
|
|
|
45
45
|
export function renderModuleMarkdown(db, projectId, moduleName) {
|
|
46
46
|
const normModule = moduleName.trim().toLowerCase();
|
|
47
47
|
// 1. Fetch active memories
|
|
48
|
-
const activeRows = db.prepare(`
|
|
49
|
-
SELECT m.*, GROUP_CONCAT(DISTINCT fl.file_path) as linked_files
|
|
50
|
-
FROM memories m
|
|
51
|
-
LEFT JOIN file_links fl ON fl.memory_id = m.id
|
|
52
|
-
WHERE m.project_id = ?
|
|
53
|
-
AND m.module = ?
|
|
54
|
-
AND m.valid_to IS NULL
|
|
55
|
-
AND m.status != 'superseded'
|
|
56
|
-
AND m.status != 'dormant'
|
|
57
|
-
GROUP BY m.id
|
|
58
|
-
ORDER BY m.pinned DESC, (m.kind = 'error_trap') DESC, m.reward_score DESC, m.created_at DESC
|
|
48
|
+
const activeRows = db.prepare(`
|
|
49
|
+
SELECT m.*, GROUP_CONCAT(DISTINCT fl.file_path) as linked_files
|
|
50
|
+
FROM memories m
|
|
51
|
+
LEFT JOIN file_links fl ON fl.memory_id = m.id
|
|
52
|
+
WHERE m.project_id = ?
|
|
53
|
+
AND m.module = ?
|
|
54
|
+
AND m.valid_to IS NULL
|
|
55
|
+
AND m.status != 'superseded'
|
|
56
|
+
AND m.status != 'dormant'
|
|
57
|
+
GROUP BY m.id
|
|
58
|
+
ORDER BY m.pinned DESC, (m.kind = 'error_trap') DESC, m.reward_score DESC, m.created_at DESC
|
|
59
59
|
`).all(projectId, normModule);
|
|
60
60
|
// 2. Fetch superseded/historical memories
|
|
61
|
-
const supersededRows = db.prepare(`
|
|
62
|
-
SELECT m.*, GROUP_CONCAT(DISTINCT fl.file_path) as linked_files
|
|
63
|
-
FROM memories m
|
|
64
|
-
LEFT JOIN file_links fl ON fl.memory_id = m.id
|
|
65
|
-
WHERE m.project_id = ?
|
|
66
|
-
AND m.module = ?
|
|
67
|
-
AND (m.valid_to IS NOT NULL OR m.status = 'superseded')
|
|
68
|
-
GROUP BY m.id
|
|
69
|
-
ORDER BY COALESCE(m.valid_to, m.created_at) DESC
|
|
61
|
+
const supersededRows = db.prepare(`
|
|
62
|
+
SELECT m.*, GROUP_CONCAT(DISTINCT fl.file_path) as linked_files
|
|
63
|
+
FROM memories m
|
|
64
|
+
LEFT JOIN file_links fl ON fl.memory_id = m.id
|
|
65
|
+
WHERE m.project_id = ?
|
|
66
|
+
AND m.module = ?
|
|
67
|
+
AND (m.valid_to IS NOT NULL OR m.status = 'superseded')
|
|
68
|
+
GROUP BY m.id
|
|
69
|
+
ORDER BY COALESCE(m.valid_to, m.created_at) DESC
|
|
70
70
|
`).all(projectId, normModule);
|
|
71
71
|
const lines = [
|
|
72
72
|
`# Module: ${normModule}`,
|
|
@@ -129,8 +129,8 @@ export function syncModulePage(db, projectRoot, projectId, moduleName) {
|
|
|
129
129
|
return targetFile;
|
|
130
130
|
}
|
|
131
131
|
export function syncAllModulePages(db, projectRoot, projectId) {
|
|
132
|
-
const rows = db.prepare(`
|
|
133
|
-
SELECT DISTINCT module FROM memories WHERE project_id = ?
|
|
132
|
+
const rows = db.prepare(`
|
|
133
|
+
SELECT DISTINCT module FROM memories WHERE project_id = ?
|
|
134
134
|
`).all(projectId);
|
|
135
135
|
const syncedFiles = [];
|
|
136
136
|
for (const row of rows) {
|
|
@@ -13,12 +13,12 @@ export async function backfillEmbeddings(db, repo, projectId, opts = {}) {
|
|
|
13
13
|
return 0;
|
|
14
14
|
const provider = getAvailableEmbeddingProvider();
|
|
15
15
|
const header = embeddingHeader(provider.modelId);
|
|
16
|
-
const rows = db.prepare(`
|
|
17
|
-
SELECT id, title, content, module FROM memories
|
|
18
|
-
WHERE project_id IN (?, 'global')
|
|
19
|
-
AND (embedded = 0 OR embedding IS NULL OR substr(embedding, 1, 4) != ?)
|
|
20
|
-
ORDER BY embedded ASC, created_at DESC
|
|
21
|
-
LIMIT ?
|
|
16
|
+
const rows = db.prepare(`
|
|
17
|
+
SELECT id, title, content, module FROM memories
|
|
18
|
+
WHERE project_id IN (?, 'global')
|
|
19
|
+
AND (embedded = 0 OR embedding IS NULL OR substr(embedding, 1, 4) != ?)
|
|
20
|
+
ORDER BY embedded ASC, created_at DESC
|
|
21
|
+
LIMIT ?
|
|
22
22
|
`).all(projectId, header, limit);
|
|
23
23
|
let count = 0;
|
|
24
24
|
for (const row of rows) {
|
|
@@ -17,15 +17,15 @@ function attachConflictMarkers(db, projectId, scored) {
|
|
|
17
17
|
const placeholders = chunk.map(() => '?').join(',');
|
|
18
18
|
let rows;
|
|
19
19
|
try {
|
|
20
|
-
rows = db.prepare(`
|
|
21
|
-
SELECT c.id, c.memory_a_id, c.memory_b_id, c.reason, c.score,
|
|
22
|
-
ma.title AS a_title, mb.title AS b_title
|
|
23
|
-
FROM memory_conflicts c
|
|
24
|
-
LEFT JOIN memories ma ON ma.id = c.memory_a_id
|
|
25
|
-
LEFT JOIN memories mb ON mb.id = c.memory_b_id
|
|
26
|
-
WHERE c.project_id = ? AND c.status = 'open'
|
|
27
|
-
AND (c.memory_a_id IN (${placeholders}) OR c.memory_b_id IN (${placeholders}))
|
|
28
|
-
ORDER BY c.id DESC
|
|
20
|
+
rows = db.prepare(`
|
|
21
|
+
SELECT c.id, c.memory_a_id, c.memory_b_id, c.reason, c.score,
|
|
22
|
+
ma.title AS a_title, mb.title AS b_title
|
|
23
|
+
FROM memory_conflicts c
|
|
24
|
+
LEFT JOIN memories ma ON ma.id = c.memory_a_id
|
|
25
|
+
LEFT JOIN memories mb ON mb.id = c.memory_b_id
|
|
26
|
+
WHERE c.project_id = ? AND c.status = 'open'
|
|
27
|
+
AND (c.memory_a_id IN (${placeholders}) OR c.memory_b_id IN (${placeholders}))
|
|
28
|
+
ORDER BY c.id DESC
|
|
29
29
|
`).all(projectId, ...chunk, ...chunk);
|
|
30
30
|
}
|
|
31
31
|
catch {
|
|
@@ -141,16 +141,16 @@ export async function searchMemories(db, params) {
|
|
|
141
141
|
// Column order is id (UNINDEXED), title, module, content. The leading 0.0 weight
|
|
142
142
|
// keeps the unindexed id column out of the score while boosting title and module.
|
|
143
143
|
const bm25Expr = 'bm25(memories_fts, 0.0, 10.0, 5.0, 1.0)';
|
|
144
|
-
let querySql = `
|
|
145
|
-
SELECT * FROM (
|
|
146
|
-
SELECT m.*, ${bm25Expr} AS rank
|
|
147
|
-
FROM memories_fts f
|
|
148
|
-
JOIN memories m ON m.id = f.id
|
|
149
|
-
WHERE (m.project_id = ? OR m.project_id = 'global')
|
|
150
|
-
AND memories_fts MATCH ?
|
|
151
|
-
ORDER BY rank ASC
|
|
152
|
-
LIMIT 50
|
|
153
|
-
)
|
|
144
|
+
let querySql = `
|
|
145
|
+
SELECT * FROM (
|
|
146
|
+
SELECT m.*, ${bm25Expr} AS rank
|
|
147
|
+
FROM memories_fts f
|
|
148
|
+
JOIN memories m ON m.id = f.id
|
|
149
|
+
WHERE (m.project_id = ? OR m.project_id = 'global')
|
|
150
|
+
AND memories_fts MATCH ?
|
|
151
|
+
ORDER BY rank ASC
|
|
152
|
+
LIMIT 50
|
|
153
|
+
)
|
|
154
154
|
`;
|
|
155
155
|
const ftsParams = [projectId, ftsQuery];
|
|
156
156
|
if (isGlobalAttached) {
|
|
@@ -158,16 +158,16 @@ export async function searchMemories(db, params) {
|
|
|
158
158
|
// name or an alias. Keeping the FTS table unaliased makes the unqualified
|
|
159
159
|
// `memories_fts` resolve to the attached table in this subquery.
|
|
160
160
|
const globalBm25Expr = 'bm25(memories_fts, 0.0, 10.0, 5.0, 1.0)';
|
|
161
|
-
querySql += `
|
|
162
|
-
UNION ALL
|
|
163
|
-
SELECT * FROM (
|
|
164
|
-
SELECT gm.*, ${globalBm25Expr} AS rank
|
|
165
|
-
FROM global_db.memories_fts
|
|
166
|
-
JOIN global_db.memories gm ON gm.id = memories_fts.id
|
|
167
|
-
WHERE memories_fts MATCH ?
|
|
168
|
-
ORDER BY rank ASC
|
|
169
|
-
LIMIT 50
|
|
170
|
-
)
|
|
161
|
+
querySql += `
|
|
162
|
+
UNION ALL
|
|
163
|
+
SELECT * FROM (
|
|
164
|
+
SELECT gm.*, ${globalBm25Expr} AS rank
|
|
165
|
+
FROM global_db.memories_fts
|
|
166
|
+
JOIN global_db.memories gm ON gm.id = memories_fts.id
|
|
167
|
+
WHERE memories_fts MATCH ?
|
|
168
|
+
ORDER BY rank ASC
|
|
169
|
+
LIMIT 50
|
|
170
|
+
)
|
|
171
171
|
`;
|
|
172
172
|
ftsParams.push(ftsQuery);
|
|
173
173
|
}
|
|
@@ -202,18 +202,18 @@ export async function searchMemories(db, params) {
|
|
|
202
202
|
}
|
|
203
203
|
if (enableVector && query.trim().length > 0) {
|
|
204
204
|
const isGlobalAttached = hasGlobalDb(db);
|
|
205
|
-
let vecSql = `
|
|
206
|
-
SELECT * FROM memories
|
|
207
|
-
WHERE (project_id = ? OR project_id = 'global')
|
|
208
|
-
AND embedded = 1
|
|
209
|
-
AND embedding IS NOT NULL
|
|
205
|
+
let vecSql = `
|
|
206
|
+
SELECT * FROM memories
|
|
207
|
+
WHERE (project_id = ? OR project_id = 'global')
|
|
208
|
+
AND embedded = 1
|
|
209
|
+
AND embedding IS NOT NULL
|
|
210
210
|
`;
|
|
211
211
|
if (isGlobalAttached) {
|
|
212
|
-
vecSql += `
|
|
213
|
-
UNION ALL
|
|
214
|
-
SELECT * FROM global_db.memories
|
|
215
|
-
WHERE embedded = 1
|
|
216
|
-
AND embedding IS NOT NULL
|
|
212
|
+
vecSql += `
|
|
213
|
+
UNION ALL
|
|
214
|
+
SELECT * FROM global_db.memories
|
|
215
|
+
WHERE embedded = 1
|
|
216
|
+
AND embedding IS NOT NULL
|
|
217
217
|
`;
|
|
218
218
|
}
|
|
219
219
|
let embeddedRows = [];
|
|
@@ -279,12 +279,12 @@ export async function searchMemories(db, params) {
|
|
|
279
279
|
// Round 1: Direct file link matches
|
|
280
280
|
if (seedFiles.size > 0) {
|
|
281
281
|
const placeholders = Array.from(seedFiles).map(() => '?').join(',');
|
|
282
|
-
const fileRows = db.prepare(`
|
|
283
|
-
SELECT DISTINCT m.id
|
|
284
|
-
FROM file_links fl
|
|
285
|
-
JOIN memories m ON m.id = fl.memory_id
|
|
286
|
-
WHERE m.project_id = ?
|
|
287
|
-
AND fl.file_path IN (${placeholders})
|
|
282
|
+
const fileRows = db.prepare(`
|
|
283
|
+
SELECT DISTINCT m.id
|
|
284
|
+
FROM file_links fl
|
|
285
|
+
JOIN memories m ON m.id = fl.memory_id
|
|
286
|
+
WHERE m.project_id = ?
|
|
287
|
+
AND fl.file_path IN (${placeholders})
|
|
288
288
|
`).all(projectId, ...Array.from(seedFiles));
|
|
289
289
|
for (const r of fileRows) {
|
|
290
290
|
activationScores.set(r.id, (activationScores.get(r.id) || 0) + 1.0);
|
|
@@ -293,12 +293,12 @@ export async function searchMemories(db, params) {
|
|
|
293
293
|
// Round 1: Direct entity link matches
|
|
294
294
|
if (seedEntityNames.length > 0) {
|
|
295
295
|
const placeholders = seedEntityNames.map(() => '?').join(',');
|
|
296
|
-
const entityRows = db.prepare(`
|
|
297
|
-
SELECT DISTINCT ge.source_id AS memory_id, ge.weight
|
|
298
|
-
FROM entities e
|
|
299
|
-
JOIN graph_edges ge ON ge.target_id = e.id AND ge.edge_type = 'entity_link'
|
|
300
|
-
WHERE e.project_id = ?
|
|
301
|
-
AND LOWER(e.name) IN (${placeholders})
|
|
296
|
+
const entityRows = db.prepare(`
|
|
297
|
+
SELECT DISTINCT ge.source_id AS memory_id, ge.weight
|
|
298
|
+
FROM entities e
|
|
299
|
+
JOIN graph_edges ge ON ge.target_id = e.id AND ge.edge_type = 'entity_link'
|
|
300
|
+
WHERE e.project_id = ?
|
|
301
|
+
AND LOWER(e.name) IN (${placeholders})
|
|
302
302
|
`).all(projectId, ...seedEntityNames);
|
|
303
303
|
for (const r of entityRows) {
|
|
304
304
|
activationScores.set(r.memory_id, (activationScores.get(r.memory_id) || 0) + (r.weight * 1.8));
|
|
@@ -328,11 +328,11 @@ export async function searchMemories(db, params) {
|
|
|
328
328
|
if (activeKeys.length === 0)
|
|
329
329
|
break;
|
|
330
330
|
const placeholders = activeKeys.map(() => '?').join(',');
|
|
331
|
-
const edgeRows = db.prepare(`
|
|
332
|
-
SELECT ge.source_id, ge.target_id, ge.edge_type, ge.weight
|
|
333
|
-
FROM graph_edges ge
|
|
334
|
-
WHERE ge.project_id = ?
|
|
335
|
-
AND (ge.source_id IN (${placeholders}) OR ge.target_id IN (${placeholders}))
|
|
331
|
+
const edgeRows = db.prepare(`
|
|
332
|
+
SELECT ge.source_id, ge.target_id, ge.edge_type, ge.weight
|
|
333
|
+
FROM graph_edges ge
|
|
334
|
+
WHERE ge.project_id = ?
|
|
335
|
+
AND (ge.source_id IN (${placeholders}) OR ge.target_id IN (${placeholders}))
|
|
336
336
|
`).all(projectId, ...activeKeys, ...activeKeys);
|
|
337
337
|
for (const edge of edgeRows) {
|
|
338
338
|
const isOutward = activationScores.has(edge.source_id);
|
|
@@ -394,14 +394,14 @@ export async function searchMemories(db, params) {
|
|
|
394
394
|
if (files.length > 0) {
|
|
395
395
|
const placeholders = files.map(() => '?').join(',');
|
|
396
396
|
try {
|
|
397
|
-
const rows = db.prepare(`
|
|
398
|
-
SELECT DISTINCT memory_id FROM file_links WHERE file_path IN (${placeholders})
|
|
397
|
+
const rows = db.prepare(`
|
|
398
|
+
SELECT DISTINCT memory_id FROM file_links WHERE file_path IN (${placeholders})
|
|
399
399
|
`).all(...files);
|
|
400
400
|
for (const row of rows)
|
|
401
401
|
fileLinkedMemoryIds.add(row.memory_id);
|
|
402
402
|
if (hasGlobalDb(db)) {
|
|
403
|
-
const globalRows = db.prepare(`
|
|
404
|
-
SELECT DISTINCT memory_id FROM global_db.file_links WHERE file_path IN (${placeholders})
|
|
403
|
+
const globalRows = db.prepare(`
|
|
404
|
+
SELECT DISTINCT memory_id FROM global_db.file_links WHERE file_path IN (${placeholders})
|
|
405
405
|
`).all(...files);
|
|
406
406
|
for (const row of globalRows)
|
|
407
407
|
fileLinkedMemoryIds.add(row.memory_id);
|