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.
Files changed (67) hide show
  1. package/.claude-plugin/marketplace.json +14 -14
  2. package/.claude-plugin/plugin.json +18 -18
  3. package/.cursor/mcp.json +3 -1
  4. package/.cursor/skills/fastr-compress/SKILL.md +33 -33
  5. package/.cursor/skills/fastr-curate/SKILL.md +62 -62
  6. package/.cursor/skills/fastr-dag/SKILL.md +47 -47
  7. package/.cursor/skills/fastr-doctor/SKILL.md +39 -39
  8. package/.cursor/skills/fastr-memory/SKILL.md +51 -51
  9. package/.cursor/skills/fastr-plan-estimate/SKILL.md +45 -45
  10. package/.cursor/skills/fastr-session-commit/SKILL.md +49 -49
  11. package/.cursor/skills/fastr-setup/SKILL.md +45 -45
  12. package/.cursor/skills/fastr-trap-log/SKILL.md +39 -39
  13. package/.cursor/skills/fastr-vision/SKILL.md +35 -35
  14. package/.cursor/skills/skills.json +65 -65
  15. package/README.md +642 -729
  16. package/bin/fastr-guard.mjs +61 -0
  17. package/dist/bin/fastr.js +68 -10
  18. package/dist/bin/fastr.js.map +1 -1
  19. package/dist/src/bench/benchmark.js +13 -13
  20. package/dist/src/bench/harness.js +17 -17
  21. package/dist/src/bench/public-harness.js +5 -5
  22. package/dist/src/branch/manager.js +31 -31
  23. package/dist/src/ci/guardian.js +9 -9
  24. package/dist/src/db/doctor.js +25 -25
  25. package/dist/src/db/hygiene.js +23 -23
  26. package/dist/src/db/repository.js +283 -283
  27. package/dist/src/db/schema.js +268 -268
  28. package/dist/src/db/spool.js +4 -4
  29. package/dist/src/export/obsidian.js +15 -15
  30. package/dist/src/import/local.js +4 -4
  31. package/dist/src/installer/mcp-init.d.ts +65 -0
  32. package/dist/src/installer/mcp-init.d.ts.map +1 -0
  33. package/dist/src/installer/mcp-init.js +293 -0
  34. package/dist/src/installer/mcp-init.js.map +1 -0
  35. package/dist/src/installer/setup.d.ts +2 -0
  36. package/dist/src/installer/setup.d.ts.map +1 -1
  37. package/dist/src/installer/setup.js +24 -18
  38. package/dist/src/installer/setup.js.map +1 -1
  39. package/dist/src/mcp/server.js +25 -25
  40. package/dist/src/mirror/markdown-pages.js +22 -22
  41. package/dist/src/search/backfill.js +6 -6
  42. package/dist/src/search/hybrid-rrf.js +60 -60
  43. package/dist/src/ui/server.js +1259 -1259
  44. package/dist/src/vision/assets.js +6 -6
  45. package/dist-ui/assets/ActionsPage-B3quzFNF.js +11 -11
  46. package/dist-ui/assets/GraphPage-DetiATmC.js +1 -1
  47. package/dist-ui/assets/ObservatoryPage-QIGMwENf.js +16 -16
  48. package/dist-ui/assets/TreemapPage-C7uLZd37.js +2 -2
  49. package/dist-ui/assets/index-BJnPINTu.css +1 -1
  50. package/dist-ui/assets/index-DWAH--Fu.js +329 -329
  51. package/dist-ui/assets/maximize-2-BebkGbZA.js +6 -6
  52. package/dist-ui/build-manifest.json +95 -95
  53. package/dist-ui/index.html +26 -26
  54. package/llms-install.md +77 -69
  55. package/package.json +108 -107
  56. package/server.json +28 -28
  57. package/skills/fastr-compress/SKILL.md +33 -33
  58. package/skills/fastr-curate/SKILL.md +62 -62
  59. package/skills/fastr-dag/SKILL.md +47 -47
  60. package/skills/fastr-doctor/SKILL.md +39 -39
  61. package/skills/fastr-memory/SKILL.md +51 -51
  62. package/skills/fastr-plan-estimate/SKILL.md +45 -45
  63. package/skills/fastr-session-commit/SKILL.md +49 -49
  64. package/skills/fastr-setup/SKILL.md +45 -45
  65. package/skills/fastr-trap-log/SKILL.md +39 -39
  66. package/skills/fastr-vision/SKILL.md +35 -35
  67. 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);