@itkoren/sqmd 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 (128) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1052 -0
  4. package/dist/api/app.d.ts +14 -0
  5. package/dist/api/app.d.ts.map +1 -0
  6. package/dist/api/app.js +32 -0
  7. package/dist/api/app.js.map +1 -0
  8. package/dist/api/middleware.d.ts +5 -0
  9. package/dist/api/middleware.d.ts.map +1 -0
  10. package/dist/api/middleware.js +37 -0
  11. package/dist/api/middleware.js.map +1 -0
  12. package/dist/api/models.d.ts +178 -0
  13. package/dist/api/models.d.ts.map +1 -0
  14. package/dist/api/models.js +39 -0
  15. package/dist/api/models.js.map +1 -0
  16. package/dist/api/routes/documents.d.ts +4 -0
  17. package/dist/api/routes/documents.d.ts.map +1 -0
  18. package/dist/api/routes/documents.js +92 -0
  19. package/dist/api/routes/documents.js.map +1 -0
  20. package/dist/api/routes/health.d.ts +6 -0
  21. package/dist/api/routes/health.d.ts.map +1 -0
  22. package/dist/api/routes/health.js +38 -0
  23. package/dist/api/routes/health.js.map +1 -0
  24. package/dist/api/routes/index.d.ts +5 -0
  25. package/dist/api/routes/index.d.ts.map +1 -0
  26. package/dist/api/routes/index.js +83 -0
  27. package/dist/api/routes/index.js.map +1 -0
  28. package/dist/api/routes/search.d.ts +6 -0
  29. package/dist/api/routes/search.d.ts.map +1 -0
  30. package/dist/api/routes/search.js +104 -0
  31. package/dist/api/routes/search.js.map +1 -0
  32. package/dist/config/loader.d.ts +4 -0
  33. package/dist/config/loader.d.ts.map +1 -0
  34. package/dist/config/loader.js +144 -0
  35. package/dist/config/loader.js.map +1 -0
  36. package/dist/config/schema.d.ts +298 -0
  37. package/dist/config/schema.d.ts.map +1 -0
  38. package/dist/config/schema.js +50 -0
  39. package/dist/config/schema.js.map +1 -0
  40. package/dist/embeddings/ollama.d.ts +14 -0
  41. package/dist/embeddings/ollama.d.ts.map +1 -0
  42. package/dist/embeddings/ollama.js +46 -0
  43. package/dist/embeddings/ollama.js.map +1 -0
  44. package/dist/embeddings/transformers.d.ts +14 -0
  45. package/dist/embeddings/transformers.d.ts.map +1 -0
  46. package/dist/embeddings/transformers.js +64 -0
  47. package/dist/embeddings/transformers.js.map +1 -0
  48. package/dist/embeddings/types.d.ts +6 -0
  49. package/dist/embeddings/types.d.ts.map +1 -0
  50. package/dist/embeddings/types.js +2 -0
  51. package/dist/embeddings/types.js.map +1 -0
  52. package/dist/index.d.ts +3 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +233 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/ingestion/chunker.d.ts +21 -0
  57. package/dist/ingestion/chunker.d.ts.map +1 -0
  58. package/dist/ingestion/chunker.js +117 -0
  59. package/dist/ingestion/chunker.js.map +1 -0
  60. package/dist/ingestion/fingerprint.d.ts +6 -0
  61. package/dist/ingestion/fingerprint.d.ts.map +1 -0
  62. package/dist/ingestion/fingerprint.js +17 -0
  63. package/dist/ingestion/fingerprint.js.map +1 -0
  64. package/dist/ingestion/parser.d.ts +16 -0
  65. package/dist/ingestion/parser.d.ts.map +1 -0
  66. package/dist/ingestion/parser.js +98 -0
  67. package/dist/ingestion/parser.js.map +1 -0
  68. package/dist/ingestion/pipeline.d.ts +32 -0
  69. package/dist/ingestion/pipeline.d.ts.map +1 -0
  70. package/dist/ingestion/pipeline.js +191 -0
  71. package/dist/ingestion/pipeline.js.map +1 -0
  72. package/dist/ingestion/scanner.d.ts +2 -0
  73. package/dist/ingestion/scanner.d.ts.map +1 -0
  74. package/dist/ingestion/scanner.js +54 -0
  75. package/dist/ingestion/scanner.js.map +1 -0
  76. package/dist/mcp/server.d.ts +8 -0
  77. package/dist/mcp/server.d.ts.map +1 -0
  78. package/dist/mcp/server.js +73 -0
  79. package/dist/mcp/server.js.map +1 -0
  80. package/dist/mcp/tools.d.ts +6 -0
  81. package/dist/mcp/tools.d.ts.map +1 -0
  82. package/dist/mcp/tools.js +276 -0
  83. package/dist/mcp/tools.js.map +1 -0
  84. package/dist/rag/context-builder.d.ts +3 -0
  85. package/dist/rag/context-builder.d.ts.map +1 -0
  86. package/dist/rag/context-builder.js +27 -0
  87. package/dist/rag/context-builder.js.map +1 -0
  88. package/dist/rag/prompt-templates.d.ts +5 -0
  89. package/dist/rag/prompt-templates.d.ts.map +1 -0
  90. package/dist/rag/prompt-templates.js +41 -0
  91. package/dist/rag/prompt-templates.js.map +1 -0
  92. package/dist/search/hybrid.d.ts +14 -0
  93. package/dist/search/hybrid.d.ts.map +1 -0
  94. package/dist/search/hybrid.js +58 -0
  95. package/dist/search/hybrid.js.map +1 -0
  96. package/dist/search/query.d.ts +4 -0
  97. package/dist/search/query.d.ts.map +1 -0
  98. package/dist/search/query.js +23 -0
  99. package/dist/search/query.js.map +1 -0
  100. package/dist/search/reranker.d.ts +11 -0
  101. package/dist/search/reranker.d.ts.map +1 -0
  102. package/dist/search/reranker.js +44 -0
  103. package/dist/search/reranker.js.map +1 -0
  104. package/dist/store/db.d.ts +11 -0
  105. package/dist/store/db.d.ts.map +1 -0
  106. package/dist/store/db.js +75 -0
  107. package/dist/store/db.js.map +1 -0
  108. package/dist/store/reader.d.ts +8 -0
  109. package/dist/store/reader.d.ts.map +1 -0
  110. package/dist/store/reader.js +122 -0
  111. package/dist/store/reader.js.map +1 -0
  112. package/dist/store/schema.d.ts +39 -0
  113. package/dist/store/schema.d.ts.map +1 -0
  114. package/dist/store/schema.js +33 -0
  115. package/dist/store/schema.js.map +1 -0
  116. package/dist/store/writer.d.ts +6 -0
  117. package/dist/store/writer.d.ts.map +1 -0
  118. package/dist/store/writer.js +43 -0
  119. package/dist/store/writer.js.map +1 -0
  120. package/dist/watcher/daemon.d.ts +5 -0
  121. package/dist/watcher/daemon.d.ts.map +1 -0
  122. package/dist/watcher/daemon.js +43 -0
  123. package/dist/watcher/daemon.js.map +1 -0
  124. package/dist/watcher/handler.d.ts +14 -0
  125. package/dist/watcher/handler.d.ts.map +1 -0
  126. package/dist/watcher/handler.js +82 -0
  127. package/dist/watcher/handler.js.map +1 -0
  128. package/package.json +56 -0
@@ -0,0 +1,276 @@
1
+ import * as fs from 'node:fs';
2
+ import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
3
+ import { hashPath } from '../ingestion/fingerprint.js';
4
+ import { IndexPipeline } from '../ingestion/pipeline.js';
5
+ import { buildContext } from '../rag/context-builder.js';
6
+ import { hybridSearch } from '../search/hybrid.js';
7
+ import { getChunksTable, getDbStats, getFilesTable } from '../store/db.js';
8
+ import { getAllFiles, getFileById, getFileChunks } from '../store/reader.js';
9
+ export function registerTools(server, db, embedder, config) {
10
+ // List available tools
11
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
12
+ tools: [
13
+ {
14
+ name: 'search_documents',
15
+ description: 'Search indexed Markdown documents using semantic or full-text search',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ query: {
20
+ type: 'string',
21
+ description: 'Search query',
22
+ },
23
+ top_k: {
24
+ type: 'number',
25
+ description: 'Number of results to return (default: 10)',
26
+ },
27
+ mode: {
28
+ type: 'string',
29
+ enum: ['hybrid', 'vector', 'fts'],
30
+ description: 'Search mode (default: hybrid)',
31
+ },
32
+ filter_path: {
33
+ type: 'string',
34
+ description: 'Filter results to files matching this path prefix',
35
+ },
36
+ include_context: {
37
+ type: 'boolean',
38
+ description: 'Include assembled RAG context in response',
39
+ },
40
+ },
41
+ required: ['query'],
42
+ },
43
+ },
44
+ {
45
+ name: 'get_document',
46
+ description: 'Get a specific document by file path',
47
+ inputSchema: {
48
+ type: 'object',
49
+ properties: {
50
+ file_path: {
51
+ type: 'string',
52
+ description: 'Absolute path to the file',
53
+ },
54
+ section: {
55
+ type: 'string',
56
+ description: 'Optional section heading to filter to',
57
+ },
58
+ },
59
+ required: ['file_path'],
60
+ },
61
+ },
62
+ {
63
+ name: 'list_documents',
64
+ description: 'List all indexed documents',
65
+ inputSchema: {
66
+ type: 'object',
67
+ properties: {
68
+ path_prefix: {
69
+ type: 'string',
70
+ description: 'Filter to files matching this path prefix',
71
+ },
72
+ limit: {
73
+ type: 'number',
74
+ description: 'Maximum number of documents to return (default: 20)',
75
+ },
76
+ },
77
+ },
78
+ },
79
+ {
80
+ name: 'trigger_index',
81
+ description: 'Trigger re-indexing of documents',
82
+ inputSchema: {
83
+ type: 'object',
84
+ properties: {
85
+ paths: {
86
+ type: 'array',
87
+ items: { type: 'string' },
88
+ description: 'Paths to index (defaults to configured watch_dirs)',
89
+ },
90
+ force: {
91
+ type: 'boolean',
92
+ description: 'Force re-indexing even if files are unchanged',
93
+ },
94
+ },
95
+ },
96
+ },
97
+ {
98
+ name: 'get_index_status',
99
+ description: 'Get current index statistics',
100
+ inputSchema: {
101
+ type: 'object',
102
+ properties: {},
103
+ },
104
+ },
105
+ ],
106
+ }));
107
+ // Handle tool calls
108
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
109
+ const { name, arguments: args } = request.params;
110
+ const toolArgs = (args ?? {});
111
+ try {
112
+ switch (name) {
113
+ case 'search_documents': {
114
+ const query = String(toolArgs.query ?? '');
115
+ const topK = Number(toolArgs.top_k ?? config.search.default_top_k);
116
+ const mode = toolArgs.mode ?? 'hybrid';
117
+ const filterPath = toolArgs.filter_path ? String(toolArgs.filter_path) : undefined;
118
+ const includeContext = Boolean(toolArgs.include_context ?? false);
119
+ const chunksTable = await getChunksTable(db);
120
+ const results = await hybridSearch(chunksTable, embedder, {
121
+ query,
122
+ topK,
123
+ mode,
124
+ rrfK: config.search.rrf_k,
125
+ filterPath,
126
+ modelName: config.embeddings.model,
127
+ });
128
+ let contextText = '';
129
+ if (includeContext) {
130
+ contextText = buildContext(results, 2000);
131
+ }
132
+ return {
133
+ content: [
134
+ {
135
+ type: 'text',
136
+ text: JSON.stringify({
137
+ results: results.map((r) => ({
138
+ chunk_id: r.chunk_id,
139
+ file_path: r.file_path,
140
+ heading_path: r.heading_path,
141
+ text_raw: r.text_raw,
142
+ score: r.score,
143
+ line_start: r.line_start,
144
+ line_end: r.line_end,
145
+ })),
146
+ total: results.length,
147
+ ...(includeContext ? { context: contextText } : {}),
148
+ }),
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ case 'get_document': {
154
+ const filePath = String(toolArgs.file_path ?? '');
155
+ const section = toolArgs.section ? String(toolArgs.section) : undefined;
156
+ const fileId = hashPath(filePath);
157
+ const filesTable = await getFilesTable(db);
158
+ const chunksTable = await getChunksTable(db);
159
+ const file = await getFileById(filesTable, fileId);
160
+ if (!file) {
161
+ return {
162
+ content: [{ type: 'text', text: JSON.stringify({ error: 'File not found' }) }],
163
+ isError: true,
164
+ };
165
+ }
166
+ let chunks = await getFileChunks(chunksTable, fileId);
167
+ if (section) {
168
+ chunks = chunks.filter((c) => c.heading_text.toLowerCase().includes(section.toLowerCase()) ||
169
+ c.heading_path.toLowerCase().includes(section.toLowerCase()));
170
+ }
171
+ return {
172
+ content: [
173
+ {
174
+ type: 'text',
175
+ text: JSON.stringify({ file, chunks }),
176
+ },
177
+ ],
178
+ };
179
+ }
180
+ case 'list_documents': {
181
+ const pathPrefix = toolArgs.path_prefix ? String(toolArgs.path_prefix) : undefined;
182
+ const limit = Number(toolArgs.limit ?? 20);
183
+ const filesTable = await getFilesTable(db);
184
+ let files = await getAllFiles(filesTable);
185
+ if (pathPrefix) {
186
+ files = files.filter((f) => f.file_path.startsWith(pathPrefix));
187
+ }
188
+ const paginated = files.slice(0, limit);
189
+ return {
190
+ content: [
191
+ {
192
+ type: 'text',
193
+ text: JSON.stringify({ documents: paginated, total: files.length }),
194
+ },
195
+ ],
196
+ };
197
+ }
198
+ case 'trigger_index': {
199
+ const paths = toolArgs.paths ?? config.paths.watch_dirs;
200
+ const force = Boolean(toolArgs.force ?? false);
201
+ const pipeline = new IndexPipeline(config);
202
+ const result = await pipeline.run({ paths, force });
203
+ return {
204
+ content: [
205
+ {
206
+ type: 'text',
207
+ text: JSON.stringify(result),
208
+ },
209
+ ],
210
+ };
211
+ }
212
+ case 'get_index_status': {
213
+ const stats = await getDbStats(db);
214
+ return {
215
+ content: [
216
+ {
217
+ type: 'text',
218
+ text: JSON.stringify(stats),
219
+ },
220
+ ],
221
+ };
222
+ }
223
+ default:
224
+ return {
225
+ content: [{ type: 'text', text: JSON.stringify({ error: `Unknown tool: ${name}` }) }],
226
+ isError: true,
227
+ };
228
+ }
229
+ }
230
+ catch (err) {
231
+ return {
232
+ content: [
233
+ {
234
+ type: 'text',
235
+ text: JSON.stringify({
236
+ error: 'Tool execution failed',
237
+ message: err instanceof Error ? err.message : String(err),
238
+ }),
239
+ },
240
+ ],
241
+ isError: true,
242
+ };
243
+ }
244
+ });
245
+ // Register MCP Resources: md://{filePath}
246
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
247
+ const filesTable = await getFilesTable(db);
248
+ const files = await getAllFiles(filesTable);
249
+ return {
250
+ resources: files.map((f) => ({
251
+ uri: `md://${f.file_path}`,
252
+ name: f.file_path.split('/').pop() ?? f.file_path,
253
+ description: `Markdown file: ${f.file_path}`,
254
+ mimeType: 'text/markdown',
255
+ })),
256
+ };
257
+ });
258
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
259
+ const uri = request.params.uri;
260
+ const filePath = uri.replace(/^md:\/\//, '');
261
+ if (!fs.existsSync(filePath)) {
262
+ throw new Error(`File not found: ${filePath}`);
263
+ }
264
+ const content = fs.readFileSync(filePath, 'utf-8');
265
+ return {
266
+ contents: [
267
+ {
268
+ uri,
269
+ mimeType: 'text/markdown',
270
+ text: content,
271
+ },
272
+ ],
273
+ };
274
+ });
275
+ }
276
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SearchResult } from '../store/schema.js';
2
+ export declare function buildContext(results: SearchResult[], maxTokens: number): string;
3
+ //# sourceMappingURL=context-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/rag/context-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAoB/E"}
@@ -0,0 +1,27 @@
1
+ import { estimateTokens } from '../ingestion/chunker.js';
2
+ export function buildContext(results, maxTokens) {
3
+ const parts = [];
4
+ let tokenCount = 0;
5
+ for (const result of results) {
6
+ const attribution = formatAttribution(result);
7
+ const content = result.text_raw;
8
+ const chunk = `${attribution}\n${content}`;
9
+ const chunkTokens = estimateTokens(chunk);
10
+ if (tokenCount + chunkTokens > maxTokens && parts.length > 0) {
11
+ break;
12
+ }
13
+ parts.push(chunk);
14
+ tokenCount += chunkTokens;
15
+ }
16
+ return parts.join('\n\n---\n\n');
17
+ }
18
+ function formatAttribution(result) {
19
+ const lines = [];
20
+ lines.push(`Source: ${result.file_path}`);
21
+ if (result.heading_path) {
22
+ lines.push(`Section: ${result.heading_path}`);
23
+ }
24
+ lines.push(`Lines: ${result.line_start}-${result.line_end}`);
25
+ return lines.join('\n');
26
+ }
27
+ //# sourceMappingURL=context-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../src/rag/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGzD,MAAM,UAAU,YAAY,CAAC,OAAuB,EAAE,SAAiB;IACrE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC;QAEhC,MAAM,KAAK,GAAG,GAAG,WAAW,KAAK,OAAO,EAAE,CAAC;QAC3C,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAE1C,IAAI,UAAU,GAAG,WAAW,GAAG,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7D,MAAM;QACR,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,UAAU,IAAI,WAAW,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAoB;IAC7C,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAE1C,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE7D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { SearchResult } from '../store/schema.js';
2
+ export declare function ragSystemPrompt(): string;
3
+ export declare function formatResults(results: SearchResult[]): string;
4
+ export declare function buildRagPrompt(query: string, context: string): string;
5
+ //# sourceMappingURL=prompt-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-templates.d.ts","sourceRoot":"","sources":["../../src/rag/prompt-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wBAAgB,eAAe,IAAI,MAAM,CASxC;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAsB7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAYrE"}
@@ -0,0 +1,41 @@
1
+ export function ragSystemPrompt() {
2
+ return `You are a helpful assistant that answers questions based on provided document excerpts.
3
+
4
+ When answering:
5
+ - Base your response on the provided context documents
6
+ - Cite the source file and section when referencing specific information
7
+ - If the context doesn't contain enough information to answer the question, say so clearly
8
+ - Do not make up information that is not in the provided context
9
+ - Keep your answers concise and focused on the question asked`;
10
+ }
11
+ export function formatResults(results) {
12
+ if (results.length === 0) {
13
+ return 'No relevant documents found.';
14
+ }
15
+ const formatted = results.map((result, idx) => {
16
+ const lines = [];
17
+ lines.push(`[${idx + 1}] ${result.file_path}`);
18
+ if (result.heading_path) {
19
+ lines.push(` Section: ${result.heading_path}`);
20
+ }
21
+ lines.push(` Score: ${result.score.toFixed(4)}`);
22
+ lines.push('');
23
+ lines.push(result.text_raw);
24
+ return lines.join('\n');
25
+ });
26
+ return formatted.join('\n\n---\n\n');
27
+ }
28
+ export function buildRagPrompt(query, context) {
29
+ return `Based on the following document excerpts, please answer the question.
30
+
31
+ ## Context Documents
32
+
33
+ ${context}
34
+
35
+ ## Question
36
+
37
+ ${query}
38
+
39
+ ## Answer`;
40
+ }
41
+ //# sourceMappingURL=prompt-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-templates.js","sourceRoot":"","sources":["../../src/rag/prompt-templates.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,eAAe;IAC7B,OAAO;;;;;;;8DAOqD,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAuB;IACnD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,8BAA8B,CAAC;IACxC,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QAC5C,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAE/C,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAE5B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,OAAe;IAC3D,OAAO;;;;EAIP,OAAO;;;;EAIP,KAAK;;UAEG,CAAC;AACX,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type * as lancedb from '@lancedb/lancedb';
2
+ import type { Embedder } from '../embeddings/types.js';
3
+ import type { SearchResult } from '../store/schema.js';
4
+ export type SearchMode = 'hybrid' | 'vector' | 'fts';
5
+ export interface HybridSearchOptions {
6
+ query: string;
7
+ topK: number;
8
+ mode: SearchMode;
9
+ rrfK: number;
10
+ filterPath?: string;
11
+ modelName?: string;
12
+ }
13
+ export declare function hybridSearch(chunksTable: lancedb.Table, embedder: Embedder, options: HybridSearchOptions): Promise<SearchResult[]>;
14
+ //# sourceMappingURL=hybrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/search/hybrid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,OAAO,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6CD,wBAAsB,YAAY,CAChC,WAAW,EAAE,OAAO,CAAC,KAAK,EAC1B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,EAAE,CAAC,CA4BzB"}
@@ -0,0 +1,58 @@
1
+ import { ftsSearch, vectorSearch } from '../store/reader.js';
2
+ import { prepareQueryForEmbedding } from './query.js';
3
+ function buildFilter(filterPath) {
4
+ if (!filterPath)
5
+ return undefined;
6
+ // Escape single quotes in path
7
+ const escaped = filterPath.replace(/'/g, "\\'");
8
+ return `file_path LIKE '%${escaped}%'`;
9
+ }
10
+ function rrfFusion(vectorResults, ftsResults, k, topK) {
11
+ const scores = new Map();
12
+ const chunkMap = new Map();
13
+ // Score from vector search
14
+ vectorResults.forEach((result, rank) => {
15
+ const score = 1 / (k + rank + 1);
16
+ scores.set(result.chunk_id, (scores.get(result.chunk_id) ?? 0) + score);
17
+ chunkMap.set(result.chunk_id, result);
18
+ });
19
+ // Score from FTS search
20
+ ftsResults.forEach((result, rank) => {
21
+ const score = 1 / (k + rank + 1);
22
+ scores.set(result.chunk_id, (scores.get(result.chunk_id) ?? 0) + score);
23
+ if (!chunkMap.has(result.chunk_id)) {
24
+ chunkMap.set(result.chunk_id, result);
25
+ }
26
+ });
27
+ // Sort by RRF score
28
+ const sorted = Array.from(scores.entries())
29
+ .sort(([, a], [, b]) => b - a)
30
+ .slice(0, topK);
31
+ return sorted.map(([chunkId, score]) => ({
32
+ ...chunkMap.get(chunkId),
33
+ score,
34
+ }));
35
+ }
36
+ export async function hybridSearch(chunksTable, embedder, options) {
37
+ const { query, topK, mode, rrfK, filterPath, modelName = '' } = options;
38
+ const preparedQuery = prepareQueryForEmbedding(query, modelName);
39
+ const filter = buildFilter(filterPath);
40
+ const candidateK = topK * 3;
41
+ if (mode === 'vector') {
42
+ const embedding = await embedder.embed([preparedQuery]);
43
+ const vec = embedding[0];
44
+ return vectorSearch(chunksTable, vec, topK, filter);
45
+ }
46
+ if (mode === 'fts') {
47
+ return ftsSearch(chunksTable, query, topK, filter);
48
+ }
49
+ // Hybrid: run both in parallel
50
+ const embedding = await embedder.embed([preparedQuery]);
51
+ const vec = embedding[0];
52
+ const [vectorResults, ftsResults] = await Promise.all([
53
+ vectorSearch(chunksTable, vec, candidateK, filter),
54
+ ftsSearch(chunksTable, query, candidateK, filter),
55
+ ]);
56
+ return rrfFusion(vectorResults, ftsResults, rrfK, topK);
57
+ }
58
+ //# sourceMappingURL=hybrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid.js","sourceRoot":"","sources":["../../src/search/hybrid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function preprocessQuery(query: string): string;
2
+ export declare function prepareQueryForEmbedding(query: string, model: string): string;
3
+ export declare function prepareDocumentForEmbedding(text: string, model: string): string;
4
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/search/query.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS7E;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO/E"}
@@ -0,0 +1,23 @@
1
+ export function preprocessQuery(query) {
2
+ return query
3
+ .toLowerCase()
4
+ .replace(/[^\w\s-]/g, ' ')
5
+ .replace(/\s+/g, ' ')
6
+ .trim();
7
+ }
8
+ export function prepareQueryForEmbedding(query, model) {
9
+ const processed = preprocessQuery(query);
10
+ // For nomic models, prepend search_query prefix
11
+ if (model.includes('nomic')) {
12
+ return `search_query: ${processed}`;
13
+ }
14
+ return processed;
15
+ }
16
+ export function prepareDocumentForEmbedding(text, model) {
17
+ // For nomic models, prepend search_document prefix
18
+ if (model.includes('nomic')) {
19
+ return `search_document: ${text}`;
20
+ }
21
+ return text;
22
+ }
23
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/search/query.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;SACzB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAa,EAAE,KAAa;IACnE,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAEzC,gDAAgD;IAChD,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,iBAAiB,SAAS,EAAE,CAAC;IACtC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAY,EAAE,KAAa;IACrE,mDAAmD;IACnD,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,oBAAoB,IAAI,EAAE,CAAC;IACpC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { SearchResult } from '../store/schema.js';
2
+ export declare class CrossEncoderReranker {
3
+ private readonly modelName;
4
+ private readonly cacheDir;
5
+ private pipeline;
6
+ constructor(modelName: string, cacheDir: string);
7
+ private loadPipeline;
8
+ rerank(query: string, results: SearchResult[], topN: number): Promise<SearchResult[]>;
9
+ }
10
+ export declare function getReranker(modelName: string, cacheDir: string): CrossEncoderReranker;
11
+ //# sourceMappingURL=reranker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reranker.d.ts","sourceRoot":"","sources":["../../src/search/reranker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOvD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAqC;gBAEzC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;YAKjC,YAAY;IAepB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAoB5F;AAID,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAMrF"}
@@ -0,0 +1,44 @@
1
+ export class CrossEncoderReranker {
2
+ modelName;
3
+ cacheDir;
4
+ pipeline = null;
5
+ constructor(modelName, cacheDir) {
6
+ this.modelName = modelName;
7
+ this.cacheDir = cacheDir;
8
+ }
9
+ async loadPipeline() {
10
+ if (this.pipeline)
11
+ return this.pipeline;
12
+ const { pipeline, env } = await import('@huggingface/transformers');
13
+ env.cacheDir = this.cacheDir;
14
+ // text-classification pipeline for cross-encoder models
15
+ this.pipeline = (await pipeline('text-classification', this.modelName, {
16
+ dtype: 'fp32',
17
+ }));
18
+ return this.pipeline;
19
+ }
20
+ async rerank(query, results, topN) {
21
+ if (results.length === 0)
22
+ return [];
23
+ const pipe = await this.loadPipeline();
24
+ // Create query-document pairs
25
+ const pairs = results.map((r) => [query, r.text_raw]);
26
+ const scores = await pipe(pairs, { top_k: 1 });
27
+ // Attach scores and sort
28
+ const reranked = results.map((result, idx) => ({
29
+ ...result,
30
+ score: scores[idx]?.score ?? 0,
31
+ }));
32
+ reranked.sort((a, b) => b.score - a.score);
33
+ return reranked.slice(0, topN);
34
+ }
35
+ }
36
+ let rerankerInstance = null;
37
+ export function getReranker(modelName, cacheDir) {
38
+ // biome-ignore lint/complexity/useLiteralKeys: bracket notation required to access private field
39
+ if (!rerankerInstance || rerankerInstance['modelName'] !== modelName) {
40
+ rerankerInstance = new CrossEncoderReranker(modelName, cacheDir);
41
+ }
42
+ return rerankerInstance;
43
+ }
44
+ //# sourceMappingURL=reranker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reranker.js","sourceRoot":"","sources":["../../src/search/reranker.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,oBAAoB;IACd,SAAS,CAAS;IAClB,QAAQ,CAAS;IAC1B,QAAQ,GAAgC,IAAI,CAAC;IAErD,YAAY,SAAiB,EAAE,QAAgB;QAC7C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;QAExC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QAEpE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAE7B,wDAAwD;QACxD,IAAI,CAAC,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,qBAAqB,EAAE,IAAI,CAAC,SAAS,EAAE;YACrE,KAAK,EAAE,MAAM;SACd,CAAC,CAAoC,CAAC;QAEvC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,OAAuB,EAAE,IAAY;QAC/D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAEvC,8BAA8B;QAC9B,MAAM,KAAK,GAA4B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE/E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAE/C,yBAAyB;QACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAC7C,GAAG,MAAM;YACT,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;SAC/B,CAAC,CAAC,CAAC;QAEJ,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAE3C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;CACF;AAED,IAAI,gBAAgB,GAAgC,IAAI,CAAC;AAEzD,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,QAAgB;IAC7D,iGAAiG;IACjG,IAAI,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE,CAAC;QACrE,gBAAgB,GAAG,IAAI,oBAAoB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import * as lancedb from '@lancedb/lancedb';
2
+ export declare function getDb(dbPath: string): Promise<lancedb.Connection>;
3
+ export declare function closeDb(dbPath: string): void;
4
+ export declare function getChunksTable(db: lancedb.Connection): Promise<lancedb.Table>;
5
+ export declare function getFilesTable(db: lancedb.Connection): Promise<lancedb.Table>;
6
+ export declare function createIndexes(db: lancedb.Connection): Promise<void>;
7
+ export declare function getDbStats(db: lancedb.Connection): Promise<{
8
+ fileCount: number;
9
+ chunkCount: number;
10
+ }>;
11
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/store/db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAQ5C,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAYvE;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAUnF;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CASlF;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BzE;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,OAAO,CAAC,UAAU,GACrB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAYpD"}