@naveenadi/mnemonic 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.
Files changed (80) hide show
  1. package/README.md +93 -0
  2. package/SKILL.md +158 -0
  3. package/bin/mne +8 -0
  4. package/dist/chunker/index.d.ts +8 -0
  5. package/dist/chunker/index.d.ts.map +1 -0
  6. package/dist/chunker/index.js +157 -0
  7. package/dist/chunker/index.js.map +1 -0
  8. package/dist/cli/commands.d.ts +2 -0
  9. package/dist/cli/commands.d.ts.map +1 -0
  10. package/dist/cli/commands.js +793 -0
  11. package/dist/cli/commands.js.map +1 -0
  12. package/dist/cli/index.d.ts +3 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +7 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/cli/mne.d.ts +3 -0
  17. package/dist/cli/mne.d.ts.map +1 -0
  18. package/dist/cli/mne.js +7 -0
  19. package/dist/cli/mne.js.map +1 -0
  20. package/dist/index.d.ts +13 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +15 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/llm/factory.d.ts +15 -0
  25. package/dist/llm/factory.d.ts.map +1 -0
  26. package/dist/llm/factory.js +60 -0
  27. package/dist/llm/factory.js.map +1 -0
  28. package/dist/llm/index.d.ts +19 -0
  29. package/dist/llm/index.d.ts.map +1 -0
  30. package/dist/llm/index.js +18 -0
  31. package/dist/llm/index.js.map +1 -0
  32. package/dist/llm/node-llama-cpp.d.ts +30 -0
  33. package/dist/llm/node-llama-cpp.d.ts.map +1 -0
  34. package/dist/llm/node-llama-cpp.js +143 -0
  35. package/dist/llm/node-llama-cpp.js.map +1 -0
  36. package/dist/llm/ollama.d.ts +19 -0
  37. package/dist/llm/ollama.d.ts.map +1 -0
  38. package/dist/llm/ollama.js +99 -0
  39. package/dist/llm/ollama.js.map +1 -0
  40. package/dist/mcp/server.d.ts +2 -0
  41. package/dist/mcp/server.d.ts.map +1 -0
  42. package/dist/mcp/server.js +360 -0
  43. package/dist/mcp/server.js.map +1 -0
  44. package/dist/pi-extension/index.d.ts +3 -0
  45. package/dist/pi-extension/index.d.ts.map +1 -0
  46. package/dist/pi-extension/index.js +193 -0
  47. package/dist/pi-extension/index.js.map +1 -0
  48. package/dist/search/fts.d.ts +17 -0
  49. package/dist/search/fts.d.ts.map +1 -0
  50. package/dist/search/fts.js +110 -0
  51. package/dist/search/fts.js.map +1 -0
  52. package/dist/search/fusion.d.ts +33 -0
  53. package/dist/search/fusion.d.ts.map +1 -0
  54. package/dist/search/fusion.js +97 -0
  55. package/dist/search/fusion.js.map +1 -0
  56. package/dist/search/pipeline.d.ts +34 -0
  57. package/dist/search/pipeline.d.ts.map +1 -0
  58. package/dist/search/pipeline.js +216 -0
  59. package/dist/search/pipeline.js.map +1 -0
  60. package/dist/search/vector.d.ts +20 -0
  61. package/dist/search/vector.d.ts.map +1 -0
  62. package/dist/search/vector.js +70 -0
  63. package/dist/search/vector.js.map +1 -0
  64. package/dist/store/collections.d.ts +23 -0
  65. package/dist/store/collections.d.ts.map +1 -0
  66. package/dist/store/collections.js +99 -0
  67. package/dist/store/collections.js.map +1 -0
  68. package/dist/store/database.d.ts +22 -0
  69. package/dist/store/database.d.ts.map +1 -0
  70. package/dist/store/database.js +209 -0
  71. package/dist/store/database.js.map +1 -0
  72. package/dist/store/documents.d.ts +68 -0
  73. package/dist/store/documents.d.ts.map +1 -0
  74. package/dist/store/documents.js +273 -0
  75. package/dist/store/documents.js.map +1 -0
  76. package/dist/types.d.ts +193 -0
  77. package/dist/types.d.ts.map +1 -0
  78. package/dist/types.js +3 -0
  79. package/dist/types.js.map +1 -0
  80. package/package.json +58 -0
@@ -0,0 +1,110 @@
1
+ export class FTSSearch {
2
+ db;
3
+ constructor(db) {
4
+ this.db = db;
5
+ }
6
+ /** BM25 search via FTS5 */
7
+ search(query, options = {}) {
8
+ const limit = options.limit ?? 20;
9
+ const minScore = options.minScore ?? 0;
10
+ // FTS5 syntax: clean the query
11
+ const cleanQuery = this.cleanQuery(query);
12
+ if (!cleanQuery)
13
+ return [];
14
+ const collectionFilter = options.collection?.length
15
+ ? options.collection.map((c) => `AND d.collection = '${c.replace(/'/g, "''")}'`).join(' ')
16
+ : '';
17
+ const sql = `
18
+ SELECT d.docid, d.collection, d.path, d.full_path, d.title, d.tags,
19
+ fts.rank as bm25_score,
20
+ snippet(documents_fts, 0, '<mark>', '</mark>', '...', 32) as snippet,
21
+ d.modified_at
22
+ FROM documents_fts fts
23
+ JOIN documents d ON d.id = fts.rowid
24
+ WHERE documents_fts MATCH ? ${collectionFilter}
25
+ ORDER BY rank
26
+ LIMIT ?
27
+ `;
28
+ try {
29
+ const rows = this.db.db.prepare(sql).all(cleanQuery, limit);
30
+ return rows
31
+ .filter((r) => {
32
+ const score = Math.abs(r.bm25_score);
33
+ return score >= minScore;
34
+ })
35
+ .map((r) => ({
36
+ docid: r.docid,
37
+ collection: r.collection,
38
+ path: `mne://${r.collection}/${r.path}`,
39
+ fullPath: r.full_path,
40
+ title: r.title,
41
+ score: Math.abs(r.bm25_score),
42
+ snippet: r.snippet.replace(/<mark>/g, '**').replace(/<\/mark>/g, '**'),
43
+ context: [],
44
+ tags: r.tags ? JSON.parse(r.tags) : [],
45
+ line: 1,
46
+ heading: '',
47
+ modifiedAt: r.modified_at ?? '',
48
+ }));
49
+ }
50
+ catch {
51
+ // FTS5 query syntax error — fall back to LIKE search
52
+ return this.fallbackSearch(cleanQuery, options);
53
+ }
54
+ }
55
+ /** Fallback to LIKE-based search when FTS5 syntax fails */
56
+ fallbackSearch(query, options) {
57
+ const limit = options.limit ?? 20;
58
+ const terms = query
59
+ .replace(/["*()]/g, '')
60
+ .split(/\s+/)
61
+ .filter(Boolean);
62
+ if (terms.length === 0)
63
+ return [];
64
+ const likeClauses = terms.map(() => '(d.title LIKE ? OR d.content LIKE ?)').join(' AND ');
65
+ const params = terms.flatMap((t) => [`%${t}%`, `%${t}%`]);
66
+ const collectionFilter = options.collection?.length
67
+ ? options.collection.map((c) => `AND d.collection = '${c.replace(/'/g, "''")}'`).join(' ')
68
+ : '';
69
+ const sql = `
70
+ SELECT d.docid, d.collection, d.path, d.full_path, d.title, d.tags,
71
+ d.content, d.modified_at
72
+ FROM documents d
73
+ WHERE ${likeClauses} ${collectionFilter}
74
+ ORDER BY d.size DESC
75
+ LIMIT ?
76
+ `;
77
+ const rows = this.db.db.prepare(sql).all(...params, limit);
78
+ return rows.map((r) => ({
79
+ docid: r.docid,
80
+ collection: r.collection,
81
+ path: `mne://${r.collection}/${r.path}`,
82
+ fullPath: r.full_path,
83
+ title: r.title,
84
+ score: 0.5, // uniform score for LIKE results
85
+ snippet: r.content.slice(0, 200).replace(/\n/g, ' '),
86
+ context: [],
87
+ tags: r.tags ? JSON.parse(r.tags) : [],
88
+ line: 1,
89
+ heading: '',
90
+ modifiedAt: r.modified_at ?? '',
91
+ }));
92
+ }
93
+ /** Clean a query for FTS5 syntax */
94
+ cleanQuery(query) {
95
+ // If already FTS5 syntax (has quotes, operators), keep as-is
96
+ if (/["*()OR AND NEAR]/.test(query))
97
+ return query;
98
+ // Convert to FTS5: escape special chars, wrap phrases in quotes
99
+ return query
100
+ .split(/\s+/)
101
+ .filter(Boolean)
102
+ .map((term) => {
103
+ if (/^[a-zA-Z0-9_-]+$/.test(term))
104
+ return term;
105
+ return `"${term.replace(/"/g, '')}"`;
106
+ })
107
+ .join(' ');
108
+ }
109
+ }
110
+ //# sourceMappingURL=fts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fts.js","sourceRoot":"","sources":["../../src/search/fts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { SearchResult } from '../types.js';
2
+ interface RankedResult {
3
+ result: SearchResult;
4
+ contributions: Array<{
5
+ source: 'fts' | 'vector' | 'hyde';
6
+ queryType: 'original' | 'expanded' | 'hyde';
7
+ query: string;
8
+ rank: number;
9
+ weight: number;
10
+ backendScore: number;
11
+ rrfContribution: number;
12
+ }>;
13
+ totalRRF: number;
14
+ bestRank: number;
15
+ }
16
+ /** Apply Reciprocal Rank Fusion to merge ranked result sets */
17
+ export declare function fuseResults(lists: Array<{
18
+ results: SearchResult[];
19
+ source: 'fts' | 'vector' | 'hyde';
20
+ queryType: 'original' | 'expanded' | 'hyde';
21
+ query: string;
22
+ weight: number;
23
+ }>, options?: {
24
+ topRankBonus?: boolean;
25
+ candidateLimit?: number;
26
+ }): {
27
+ results: SearchResult[];
28
+ ranked: Map<string, RankedResult>;
29
+ };
30
+ /** Apply position-aware blending between RRF and reranker scores */
31
+ export declare function blendWithRerank(rrfRanked: Map<string, RankedResult>, rerankScores: Map<string, number>, limit?: number): SearchResult[];
32
+ export {};
33
+ //# sourceMappingURL=fusion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fusion.d.ts","sourceRoot":"","sources":["../../src/search/fusion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,aAAa,CAAC;AAI9D,UAAU,YAAY;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,KAAK,CAAC;QACnB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;QAClC,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;QAC5C,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,CAAC;IACX,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,EACF,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GACA;IAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;CAAE,CAmEhE;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAC7B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACpC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,EAAE,CA0ChB"}
@@ -0,0 +1,97 @@
1
+ const RRF_K = 60;
2
+ /** Apply Reciprocal Rank Fusion to merge ranked result sets */
3
+ export function fuseResults(lists, options) {
4
+ const rankMap = new Map();
5
+ const candidateLimit = options?.candidateLimit ?? 30;
6
+ // Collect all results into rank map
7
+ for (const list of lists) {
8
+ const w = list.weight;
9
+ for (let i = 0; i < list.results.length; i++) {
10
+ const r = list.results[i];
11
+ const rank = i + 1;
12
+ const rrfScore = 1 / (RRF_K + rank);
13
+ if (!rankMap.has(r.docid)) {
14
+ rankMap.set(r.docid, {
15
+ result: r,
16
+ contributions: [],
17
+ totalRRF: 0,
18
+ bestRank: rank,
19
+ });
20
+ }
21
+ const entry = rankMap.get(r.docid);
22
+ const contribution = {
23
+ source: list.source,
24
+ queryType: list.queryType,
25
+ query: list.query,
26
+ rank,
27
+ weight: w,
28
+ backendScore: r.score,
29
+ rrfContribution: rrfScore * w,
30
+ };
31
+ entry.contributions.push(contribution);
32
+ entry.totalRRF += rrfScore * w;
33
+ entry.bestRank = Math.min(entry.bestRank, rank);
34
+ }
35
+ }
36
+ // Apply top-rank bonus: docs ranked #1 in any list get +0.05, #2-3 get +0.02
37
+ if (options?.topRankBonus !== false) {
38
+ for (const [, entry] of rankMap) {
39
+ for (const c of entry.contributions) {
40
+ if (c.rank === 1 && c.weight >= 1) {
41
+ entry.totalRRF += 0.05;
42
+ }
43
+ else if (c.rank <= 3) {
44
+ entry.totalRRF += 0.02;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ // Sort by RRF score descending
50
+ const sorted = [...rankMap.entries()]
51
+ .sort((a, b) => b[1].totalRRF - a[1].totalRRF)
52
+ .slice(0, candidateLimit);
53
+ // Build results with scores
54
+ const results = [];
55
+ const ranked = new Map();
56
+ for (const [docid, entry] of sorted) {
57
+ entry.result.score = entry.totalRRF;
58
+ results.push(entry.result);
59
+ ranked.set(docid, entry);
60
+ }
61
+ return { results, ranked };
62
+ }
63
+ /** Apply position-aware blending between RRF and reranker scores */
64
+ export function blendWithRerank(rrfRanked, rerankScores, limit) {
65
+ const blended = [];
66
+ // Sort RRF entries by rank to determine position
67
+ const sortedRrf = [...rrfRanked.entries()].sort((a, b) => b[1].totalRRF - a[1].totalRRF);
68
+ for (let i = 0; i < sortedRrf.length; i++) {
69
+ const [docid, entry] = sortedRrf[i];
70
+ const rank = i + 1;
71
+ const rerankScore = rerankScores.get(docid);
72
+ let rrfWeight;
73
+ let rerankWeight;
74
+ if (rank <= 3) {
75
+ rrfWeight = 0.75;
76
+ rerankWeight = 0.25;
77
+ }
78
+ else if (rank <= 10) {
79
+ rrfWeight = 0.6;
80
+ rerankWeight = 0.4;
81
+ }
82
+ else {
83
+ rrfWeight = 0.4;
84
+ rerankWeight = 0.6;
85
+ }
86
+ const finalScore = rrfWeight * entry.totalRRF +
87
+ (rerankScore !== undefined ? rerankWeight * rerankScore : 0);
88
+ const result = { ...entry.result };
89
+ result.score = Math.min(1, Math.max(0, finalScore));
90
+ blended.push({ result, score: finalScore });
91
+ }
92
+ // Sort by blended score
93
+ blended.sort((a, b) => b.score - a.score);
94
+ const limitNum = limit ?? 10;
95
+ return blended.slice(0, limitNum).map((b) => b.result);
96
+ }
97
+ //# sourceMappingURL=fusion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fusion.js","sourceRoot":"","sources":["../../src/search/fusion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { MnemonicDB } from '../store/database.js';
2
+ import type { LLMBackend, SearchOptions, SearchResult } from '../types.js';
3
+ export declare class SearchPipeline {
4
+ private db;
5
+ private llm?;
6
+ private fts;
7
+ private vector;
8
+ private docs;
9
+ constructor(db: MnemonicDB, llm?: LLMBackend);
10
+ /** Set LLM backend after construction */
11
+ setLLM(llm: LLMBackend): void;
12
+ /** Main search entry point */
13
+ search(options: SearchOptions): Promise<SearchResult[]>;
14
+ /** Apply time decay and link boost post-processors */
15
+ private applyPostProcessors;
16
+ /** Apply exponential time decay based on modification date */
17
+ private applyTimeDecay;
18
+ /** Boost results that have more incoming links */
19
+ private applyLinkBoost;
20
+ /** Get default collection names */
21
+ private getDefaultCollections;
22
+ /** BM25-only search (fast, no LLM) */
23
+ searchLex(query: string, options?: {
24
+ collection?: string[];
25
+ limit?: number;
26
+ minScore?: number;
27
+ }): SearchResult[];
28
+ /** Vector-only search */
29
+ searchVector(query: string, options?: {
30
+ collection?: string[];
31
+ limit?: number;
32
+ }): Promise<SearchResult[]>;
33
+ }
34
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/search/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAK1F,qBAAa,cAAc;IAMvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,GAAG,CAAC;IANd,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,IAAI,CAAgB;gBAGlB,EAAE,EAAE,UAAU,EACd,GAAG,CAAC,EAAE,UAAU;IAO1B,yCAAyC;IACzC,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAI7B,8BAA8B;IACxB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAmI7D,sDAAsD;IACtD,OAAO,CAAC,mBAAmB;IAuB3B,8DAA8D;IAC9D,OAAO,CAAC,cAAc;IAyBtB,kDAAkD;IAClD,OAAO,CAAC,cAAc;IAwBtB,mCAAmC;IACnC,OAAO,CAAC,qBAAqB;IAO7B,sCAAsC;IACtC,SAAS,CACP,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GACrE,YAAY,EAAE;IAIjB,yBAAyB;IACnB,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,YAAY,EAAE,CAAC;CAU3B"}
@@ -0,0 +1,216 @@
1
+ import { DocumentStore } from '../store/documents.js';
2
+ import { FTSSearch } from './fts.js';
3
+ import { VectorSearch } from './vector.js';
4
+ import { fuseResults, blendWithRerank } from './fusion.js';
5
+ export class SearchPipeline {
6
+ db;
7
+ llm;
8
+ fts;
9
+ vector;
10
+ docs;
11
+ constructor(db, llm) {
12
+ this.db = db;
13
+ this.llm = llm;
14
+ this.fts = new FTSSearch(db);
15
+ this.vector = new VectorSearch(db);
16
+ this.docs = new DocumentStore(db);
17
+ }
18
+ /** Set LLM backend after construction */
19
+ setLLM(llm) {
20
+ this.llm = llm;
21
+ }
22
+ /** Main search entry point */
23
+ async search(options) {
24
+ const { query, queries, intent, collection, limit, minScore, rerank } = options;
25
+ const expand = options.expand ?? true;
26
+ const useHyde = options.hyde ?? true;
27
+ const limitNum = limit ?? 10;
28
+ const candidateLimit = options.candidateLimit ?? 40;
29
+ // Resolve collection filter
30
+ const collectionFilter = collection
31
+ ? (Array.isArray(collection) ? collection : [collection])
32
+ : undefined;
33
+ // If no filter, use default collections
34
+ const collections = collectionFilter ?? this.getDefaultCollections();
35
+ // Determine which queries to run
36
+ let expandedQueries = queries ?? [];
37
+ if (!queries && query) {
38
+ // Auto-expand query
39
+ if (expand && this.llm) {
40
+ const expansions = await this.llm.expandQuery(query, intent);
41
+ expandedQueries = [
42
+ { type: 'lex', query },
43
+ { type: 'vec', query },
44
+ ...expansions.map((q) => ({ type: 'vec', query: q })),
45
+ ];
46
+ }
47
+ else {
48
+ expandedQueries = [
49
+ { type: 'lex', query },
50
+ { type: 'vec', query },
51
+ ];
52
+ }
53
+ // Add HyDE if enabled
54
+ if (useHyde && this.llm) {
55
+ const hydeDoc = await this.llm.generateHyde(query, intent);
56
+ if (hydeDoc && hydeDoc !== query) {
57
+ expandedQueries.push({ type: 'hyde', query: hydeDoc });
58
+ }
59
+ }
60
+ }
61
+ // Run all sub-queries against FTS and vector backends
62
+ const lists = [];
63
+ for (const eq of expandedQueries) {
64
+ let isOriginal = false;
65
+ if (!queries && eq.query === query && eq.type !== 'hyde') {
66
+ isOriginal = true;
67
+ }
68
+ const weight = isOriginal ? 2 : 1;
69
+ const queryType = eq.type === 'hyde' ? 'hyde' : (isOriginal ? 'original' : 'expanded');
70
+ const source = eq.type === 'lex' ? 'fts' : eq.type === 'hyde' ? 'hyde' : 'vector';
71
+ if (eq.type === 'lex') {
72
+ const results = this.fts.search(eq.query, {
73
+ collection: collections,
74
+ limit: candidateLimit,
75
+ minScore,
76
+ });
77
+ lists.push({ results, source: 'fts', queryType: queryType, query: eq.query, weight });
78
+ }
79
+ else if (eq.type === 'vec' && this.llm) {
80
+ try {
81
+ const [embedding] = await this.llm.embed([eq.query]);
82
+ const results = this.vector.search(embedding, {
83
+ collection: collections,
84
+ limit: candidateLimit,
85
+ minScore,
86
+ });
87
+ lists.push({ results, source: 'vector', queryType: queryType, query: eq.query, weight });
88
+ }
89
+ catch {
90
+ // Embedding failed, skip
91
+ }
92
+ }
93
+ else if (eq.type === 'hyde' && this.llm) {
94
+ try {
95
+ const [embedding] = await this.llm.embed([eq.query]);
96
+ const results = this.vector.search(embedding, {
97
+ collection: collections,
98
+ limit: candidateLimit,
99
+ minScore,
100
+ });
101
+ lists.push({ results, source: 'hyde', queryType: 'hyde', query: eq.query, weight });
102
+ }
103
+ catch {
104
+ // HyDE embedding failed, skip
105
+ }
106
+ }
107
+ }
108
+ if (lists.length === 0)
109
+ return [];
110
+ // RRF Fusion
111
+ const { results: fused, ranked } = fuseResults(lists, {
112
+ topRankBonus: true,
113
+ candidateLimit,
114
+ });
115
+ if (fused.length === 0)
116
+ return [];
117
+ // LLM Reranking
118
+ if (rerank !== false && this.llm && fused.length > 1) {
119
+ try {
120
+ const docs = fused.map((r) => r.snippet || r.title);
121
+ const scores = await this.llm.rerank(query ?? '', docs);
122
+ const rerankScores = new Map();
123
+ for (let i = 0; i < fused.length; i++) {
124
+ rerankScores.set(fused[i].docid, scores[i] ?? 0);
125
+ }
126
+ const blended = blendWithRerank(ranked, rerankScores, limitNum);
127
+ // Apply time decay and link boost
128
+ return this.applyPostProcessors(blended, options);
129
+ }
130
+ catch {
131
+ // Reranking failed, use fused results
132
+ }
133
+ }
134
+ // Without reranking, use fused results directly
135
+ const results = fused.slice(0, limitNum);
136
+ return this.applyPostProcessors(results, options);
137
+ }
138
+ /** Apply time decay and link boost post-processors */
139
+ applyPostProcessors(results, options) {
140
+ let processed = results;
141
+ if (options.decay) {
142
+ processed = this.applyTimeDecay(processed, options.decayHalfLifeDays ?? 30);
143
+ }
144
+ if (options.boostLinks) {
145
+ processed = this.applyLinkBoost(processed);
146
+ }
147
+ // Add context
148
+ processed = processed.map((r) => ({
149
+ ...r,
150
+ context: this.docs.getContextChain(r.collection, r.path.replace(`mne://${r.collection}/`, '')),
151
+ }));
152
+ return processed;
153
+ }
154
+ /** Apply exponential time decay based on modification date */
155
+ applyTimeDecay(results, halfLifeDays) {
156
+ const now = Date.now();
157
+ const halfLifeMs = halfLifeDays * 24 * 60 * 60 * 1000;
158
+ return results.map((r) => {
159
+ let decayFactor = 1;
160
+ if (r.modifiedAt) {
161
+ const modified = new Date(r.modifiedAt).getTime();
162
+ if (!isNaN(modified)) {
163
+ const ageMs = now - modified;
164
+ decayFactor = Math.pow(0.5, ageMs / halfLifeMs);
165
+ }
166
+ }
167
+ return {
168
+ ...r,
169
+ score: r.score * (0.7 + 0.3 * decayFactor),
170
+ };
171
+ }).sort((a, b) => b.score - a.score);
172
+ }
173
+ /** Boost results that have more incoming links */
174
+ applyLinkBoost(results) {
175
+ const maxLinks = Math.max(1, ...results.map((r) => {
176
+ const count = this.db.db
177
+ .prepare('SELECT COUNT(*) as c FROM links WHERE target_docid = ?')
178
+ .get(r.docid);
179
+ return count.c;
180
+ }));
181
+ return results.map((r) => {
182
+ const count = this.db.db
183
+ .prepare('SELECT COUNT(*) as c FROM links WHERE target_docid = ?')
184
+ .get(r.docid);
185
+ const boost = 1 + 0.2 * (count.c / maxLinks);
186
+ return {
187
+ ...r,
188
+ score: r.score * boost,
189
+ };
190
+ }).sort((a, b) => b.score - a.score);
191
+ }
192
+ /** Get default collection names */
193
+ getDefaultCollections() {
194
+ const rows = this.db.db
195
+ .prepare('SELECT name FROM collections WHERE include_by_default = 1')
196
+ .all();
197
+ return rows.map((r) => r.name);
198
+ }
199
+ /** BM25-only search (fast, no LLM) */
200
+ searchLex(query, options) {
201
+ return this.fts.search(query, options);
202
+ }
203
+ /** Vector-only search */
204
+ async searchVector(query, options) {
205
+ if (!this.llm)
206
+ return [];
207
+ try {
208
+ const [embedding] = await this.llm.embed([query]);
209
+ return this.vector.search(embedding, options);
210
+ }
211
+ catch {
212
+ return [];
213
+ }
214
+ }
215
+ }
216
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/search/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { MnemonicDB } from '../store/database.js';
2
+ import type { SearchResult } from '../types.js';
3
+ export declare class VectorSearch {
4
+ private db;
5
+ constructor(db: MnemonicDB);
6
+ /** Search by embedding (cosine similarity) */
7
+ search(embedding: number[], options?: {
8
+ collection?: string[];
9
+ limit?: number;
10
+ minScore?: number;
11
+ }): SearchResult[];
12
+ /** Store embeddings in the vector index */
13
+ storeVectors(vectors: Array<{
14
+ hash: string;
15
+ embedding: number[];
16
+ }>): void;
17
+ /** Delete vectors for a document */
18
+ deleteVectors(hash: string): void;
19
+ }
20
+ //# sourceMappingURL=vector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/search/vector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,qBAAa,YAAY;IACX,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,UAAU;IAElC,8CAA8C;IAC9C,MAAM,CACJ,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,GAAE;QACP,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACd,GACL,YAAY,EAAE;IA4DjB,2CAA2C;IAC3C,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,GAAG,IAAI;IAmBzE,oCAAoC;IACpC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAIlC"}
@@ -0,0 +1,70 @@
1
+ export class VectorSearch {
2
+ db;
3
+ constructor(db) {
4
+ this.db = db;
5
+ }
6
+ /** Search by embedding (cosine similarity) */
7
+ search(embedding, options = {}) {
8
+ const limit = options.limit ?? 20;
9
+ const minScore = options.minScore ?? 0;
10
+ // Check if vector table exists
11
+ if (!this.db.hasVectorIndex())
12
+ return [];
13
+ const collectionFilter = options.collection?.length
14
+ ? options.collection.map((c) => `AND d.collection = '${c.replace(/'/g, "''")}'`).join(' ')
15
+ : '';
16
+ // Format embedding for vec0 query
17
+ const embeddingStr = `[${embedding.join(',')}]`;
18
+ const sql = `
19
+ SELECT d.docid, d.collection, d.path, d.full_path, d.title, d.tags,
20
+ v.distance, c.heading, c.pos, d.modified_at
21
+ FROM vectors_vec v
22
+ JOIN vectors v2 ON v.hash = v2.hash
23
+ JOIN chunks c ON c.docid = v2.hash AND c.seq = 0
24
+ JOIN documents d ON d.docid = v2.hash
25
+ WHERE v.embedding MATCH ? ${collectionFilter}
26
+ AND v.distance <= ${1 - minScore}
27
+ ORDER BY v.distance
28
+ LIMIT ?
29
+ `;
30
+ try {
31
+ const rows = this.db.db.prepare(sql).all(embeddingStr, limit);
32
+ return rows.map((r) => ({
33
+ docid: r.docid,
34
+ collection: r.collection,
35
+ path: `mne://${r.collection}/${r.path}`,
36
+ fullPath: r.full_path,
37
+ title: r.title,
38
+ score: 1 / (1 + r.distance), // Convert distance to similarity score
39
+ snippet: '',
40
+ context: [],
41
+ tags: r.tags ? JSON.parse(r.tags) : [],
42
+ line: r.pos,
43
+ heading: r.heading,
44
+ modifiedAt: r.modified_at ?? '',
45
+ }));
46
+ }
47
+ catch {
48
+ return [];
49
+ }
50
+ }
51
+ /** Store embeddings in the vector index */
52
+ storeVectors(vectors) {
53
+ const insertVec = this.db.db.prepare('INSERT OR REPLACE INTO vectors (hash, embedding) VALUES (?, ?)');
54
+ const insertVec0 = this.db.db.prepare('INSERT OR REPLACE INTO vectors_vec (hash, embedding) VALUES (?, ?)');
55
+ const tx = this.db.db.transaction(() => {
56
+ for (const v of vectors) {
57
+ const blob = Buffer.from(new Float32Array(v.embedding).buffer);
58
+ insertVec.run(v.hash, blob);
59
+ insertVec0.run(v.hash, JSON.stringify(v.embedding));
60
+ }
61
+ });
62
+ tx();
63
+ }
64
+ /** Delete vectors for a document */
65
+ deleteVectors(hash) {
66
+ this.db.db.prepare('DELETE FROM vectors WHERE hash = ?').run(hash);
67
+ // vec0 cascades deletion automatically
68
+ }
69
+ }
70
+ //# sourceMappingURL=vector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector.js","sourceRoot":"","sources":["../../src/search/vector.ts"],"names":[],"mappings":"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"}