@aarav-j/zephyr-mcp-server 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/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # Zephyr RTOS MCP Server
2
+
3
+ An MCP (Model Context Protocol) server that gives LLMs grounded access to Zephyr RTOS documentation — Kconfig symbols, Devicetree bindings, and API signatures. No more hallucinated driver structs or made-up Kconfig options.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ git clone https://github.com/Aarav-J/zephyr-mcp-server.git
9
+ cd zephyr-mcp-server
10
+ npm install
11
+ npm run build
12
+ ```
13
+
14
+ Add to your MCP client config (e.g. `~/.cursor/mcp.json`):
15
+
16
+ ```json
17
+ {
18
+ "mcpServers": {
19
+ "zephyr": {
20
+ "command": "node",
21
+ "args": ["/absolute/path/to/zephyr-mcp-server/dist/index.js"]
22
+ }
23
+ }
24
+ }
25
+ ```
26
+
27
+ First startup auto-downloads a pre-built index (8.5 MB) with data from the latest Zephyr release. No manual setup needed.
28
+
29
+ ## Tools
30
+
31
+ ### `get_function_signature`
32
+
33
+ Look up exact C function or macro signatures, parameters, return types, and header locations.
34
+
35
+ ```
36
+ Arguments:
37
+ name — Function or macro name (e.g. k_sem_take, GPIO_DT_SPEC_GET)
38
+ version? — Zephyr version tag. Defaults to latest cached.
39
+
40
+ Returns:
41
+ - signature — Exact C signature with types
42
+ - brief — One-line description
43
+ - params — Typed parameter list with descriptions
44
+ - return_type — Return type
45
+ - return_desc — Return value description
46
+ - header — Declaring header file
47
+ - section — Doxygen group/section
48
+ ```
49
+
50
+ > Requires Doxygen XML output to be indexed (see Building a Full Index).
51
+
52
+ ### `find_kconfig`
53
+
54
+ Search Zephyr Kconfig symbols by name or description.
55
+
56
+ ```
57
+ Arguments:
58
+ pattern — Search string (e.g. GPIO, CONFIG_I2C, USB)
59
+ limit? — Max results. Default 10, max 50.
60
+ version? — Zephyr version tag.
61
+
62
+ Returns:
63
+ - name — Symbol name (CONFIG_*)
64
+ - type — bool, string, int, hex, tristate
65
+ - prompt — User-visible prompt text
66
+ - default — Default value
67
+ - depends_on — Dependency symbol chain
68
+ - path — File path in Zephyr tree
69
+ ```
70
+
71
+ ### `get_dt_binding`
72
+
73
+ Look up a Devicetree binding by compatible string.
74
+
75
+ ```
76
+ Arguments:
77
+ compatible — Compatible string (e.g. st,stm32-i2c, arm,cortex-m4)
78
+ version? — Zephyr version tag.
79
+
80
+ Returns:
81
+ - compatible — Compatible string
82
+ - description — Binding description
83
+ - properties — Schema with types, required/optional status, defaults
84
+ - child_binding — Child binding schema (if any)
85
+ - bus — Bus type this binding provides
86
+ - on_bus — Bus this binding lives on
87
+ - path — YAML file path in Zephyr tree
88
+ ```
89
+
90
+ ### `search_docs`
91
+
92
+ Full-text search across indexed documentation domains.
93
+
94
+ ```
95
+ Arguments:
96
+ query — Search query (e.g. "semaphore", "i2c stm32", "gpio interrupt")
97
+ domain? — Scope: "api", "kconfig", "dt", or omit for all
98
+ limit? — Max results. Default 10, max 30.
99
+ version? — Zephyr version tag.
100
+
101
+ Returns:
102
+ - query — Original query
103
+ - count — Total results found
104
+ - results — Ranked list of { domain, title, snippet, path }
105
+ ```
106
+
107
+ ## Index
108
+
109
+ ### Pre-built Index (auto-downloaded)
110
+
111
+ The server automatically downloads a pre-built index from GitHub Releases on first startup. The current index covers:
112
+
113
+ | Data | Count |
114
+ |---|---|
115
+ | Kconfig symbols | 24,118 |
116
+ | Devicetree bindings | 3,553 |
117
+ | Index size | 8.5 MB |
118
+
119
+ This is enough for the `find_kconfig`, `get_dt_binding`, and `search_docs` tools to work immediately.
120
+
121
+ ### Building a Full Index (with API signatures)
122
+
123
+ To also index function signatures, you need Doxygen XML output from Zephyr's documentation build:
124
+
125
+ ```bash
126
+ # Option 1: Build Zephyr docs yourself
127
+ # (requires a full Zephyr build environment)
128
+ cd /path/to/zephyr
129
+ west build -t doxygen
130
+ # Doxygen XML will be in build/zephyr-doc/xml/
131
+
132
+ # Option 2: Use the pre-built docs source
133
+ npx tsx scripts/build-index.ts v4.4.1 \
134
+ --source /path/to/zephyr \
135
+ --doxygen /path/to/zephyr/build/zephyr-doc/xml/
136
+ ```
137
+
138
+ ### Building from Source
139
+
140
+ If you want to build the index from a specific Zephyr release:
141
+
142
+ ```bash
143
+ # Download and index Kconfig + DT bindings from Zephyr source
144
+ npx tsx scripts/build-index.ts v4.4.1 --source /path/to/zephyr
145
+ ```
146
+
147
+ The CLI accepts a local Zephyr source directory. On first run against a new version, it will download the Zephyr source tarball automatically.
148
+
149
+ ## Version Management
150
+
151
+ The server checks for new Zephyr releases on startup and logs a message when one is available:
152
+
153
+ ```
154
+ [update] New Zephyr release: v4.5.0 (cached: v4.4.1)
155
+ [update] Run: cd zephyr-mcp-server && npm run build-index v4.5.0
156
+ ```
157
+
158
+ ## Architecture
159
+
160
+ ```
161
+ zephyr-mcp-server/
162
+ ├── src/
163
+ │ ├── index.ts # MCP server + tool handlers
164
+ │ ├── db.ts # SQLite FTS5 database layer
165
+ │ └── parsers/
166
+ │ ├── doxygen.ts # Doxygen XML → FunctionRow[]
167
+ │ ├── kconfig.ts # Kconfig → KconfigRow[]
168
+ │ └── dt-bindings.ts # YAML bindings → DtBindingRow[]
169
+ ├── scripts/
170
+ │ └── build-index.ts # Index builder CLI
171
+ ├── dist/ # Compiled output
172
+ └── test/
173
+ └── fixtures/ # Test fixtures
174
+ ```
175
+
176
+ ## Development
177
+
178
+ ```bash
179
+ npm run build # Compile TypeScript
180
+ npm run start # Start MCP server on stdio
181
+ npm run build-index <version> --source <path> # Build index
182
+ ```
183
+
184
+ ## Contributing
185
+
186
+ PRs welcome. Key areas for improvement:
187
+
188
+ - **Doxygen XML fetching** — Automate downloading or building Doxygen XML for pre-built index releases
189
+ - **Kconfig parser quality** — Current parser is regex-based; switching to kconfiglib (Python) would improve accuracy
190
+ - **RST docs chunking** — Parse Zephyr's RST documentation for richer prose search results
191
+ - **CI pipeline** — GitHub Action to auto-build indexes on new Zephyr releases
192
+
193
+ ## License
194
+
195
+ MIT
196
+
197
+ ---
198
+
199
+ Built for [Oh My Pi](https://github.com/Aarav-J/personal_hermes) club.
package/dist/db.d.ts ADDED
@@ -0,0 +1,72 @@
1
+ export interface FunctionRow {
2
+ id?: number;
3
+ name: string;
4
+ signature: string;
5
+ brief: string | null;
6
+ description: string | null;
7
+ params: string | null;
8
+ return_type: string | null;
9
+ return_desc: string | null;
10
+ header: string | null;
11
+ section: string | null;
12
+ group_id: string | null;
13
+ }
14
+ export interface KconfigRow {
15
+ id?: number;
16
+ name: string;
17
+ type: string | null;
18
+ prompt: string | null;
19
+ default_val: string | null;
20
+ depends_on: string | null;
21
+ select_list: string | null;
22
+ range_min: string | null;
23
+ range_max: string | null;
24
+ help_text: string | null;
25
+ path: string | null;
26
+ }
27
+ export interface DtBindingRow {
28
+ id?: number;
29
+ compatible: string;
30
+ description: string | null;
31
+ properties: string | null;
32
+ child_binding: string | null;
33
+ bus: string | null;
34
+ on_bus: string | null;
35
+ path: string | null;
36
+ }
37
+ export interface DocChunkRow {
38
+ id?: number;
39
+ title: string | null;
40
+ heading_path: string | null;
41
+ body: string | null;
42
+ source_url: string | null;
43
+ domain: string | null;
44
+ }
45
+ export declare function getCacheDir(): string;
46
+ export declare class ZephyrDatabase {
47
+ private db;
48
+ constructor(dbPath: string);
49
+ /** Create or migrate schema. Idempotent. */
50
+ initialize(): void;
51
+ insertFunction(row: FunctionRow): void;
52
+ insertFunctionsBatch(rows: FunctionRow[]): void;
53
+ insertKconfig(row: KconfigRow): void;
54
+ insertKconfigsBatch(rows: KconfigRow[]): void;
55
+ insertDtBinding(row: DtBindingRow): void;
56
+ insertDtBindingsBatch(rows: DtBindingRow[]): void;
57
+ insertDocChunk(row: DocChunkRow): void;
58
+ insertDocChunksBatch(rows: DocChunkRow[]): void;
59
+ rebuildFts(): void;
60
+ setMeta(key: string, value: string): void;
61
+ getMeta(key: string): string | undefined;
62
+ /** Add FTS5 prefix wildcard to last token, and escape special characters. */
63
+ private ftsQuery;
64
+ getFunctionByName(name: string): FunctionRow | undefined;
65
+ getBindingByCompatible(compatible: string): DtBindingRow | undefined;
66
+ searchFunctions(query: string, limit?: number): FunctionRow[];
67
+ searchKconfig(query: string, limit?: number): KconfigRow[];
68
+ searchBindings(query: string, limit?: number): DtBindingRow[];
69
+ searchDocs(query: string, limit?: number): DocChunkRow[];
70
+ close(): void;
71
+ }
72
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
package/dist/db.js ADDED
@@ -0,0 +1,343 @@
1
+ import Database from "better-sqlite3";
2
+ import { mkdirSync, existsSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ // --- Database Manager ---
6
+ export function getCacheDir() {
7
+ const dir = join(homedir(), ".zephyr-mcp", "indexes");
8
+ if (!existsSync(dir)) {
9
+ mkdirSync(dir, { recursive: true });
10
+ }
11
+ return dir;
12
+ }
13
+ export class ZephyrDatabase {
14
+ db;
15
+ constructor(dbPath) {
16
+ this.db = new Database(dbPath);
17
+ this.db.pragma("journal_mode = WAL");
18
+ this.db.pragma("foreign_keys = ON");
19
+ }
20
+ /** Create or migrate schema. Idempotent. */
21
+ initialize() {
22
+ this.db.exec(`
23
+ -- Functions table
24
+ CREATE TABLE IF NOT EXISTS functions (
25
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
26
+ name TEXT NOT NULL,
27
+ signature TEXT NOT NULL,
28
+ brief TEXT,
29
+ description TEXT,
30
+ params TEXT,
31
+ return_type TEXT,
32
+ return_desc TEXT,
33
+ header TEXT,
34
+ section TEXT,
35
+ group_id TEXT
36
+ );
37
+ CREATE INDEX IF NOT EXISTS idx_functions_name ON functions(name);
38
+
39
+ -- Kconfig symbols table
40
+ CREATE TABLE IF NOT EXISTS kconfig_symbols (
41
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
42
+ name TEXT NOT NULL,
43
+ type TEXT,
44
+ prompt TEXT,
45
+ default_val TEXT,
46
+ depends_on TEXT,
47
+ select_list TEXT,
48
+ range_min TEXT,
49
+ range_max TEXT,
50
+ help_text TEXT,
51
+ path TEXT
52
+ );
53
+ CREATE INDEX IF NOT EXISTS idx_kconfig_name ON kconfig_symbols(name);
54
+
55
+ -- Devicetree bindings table
56
+ CREATE TABLE IF NOT EXISTS dt_bindings (
57
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58
+ compatible TEXT NOT NULL,
59
+ description TEXT,
60
+ properties TEXT,
61
+ child_binding TEXT,
62
+ bus TEXT,
63
+ on_bus TEXT,
64
+ path TEXT
65
+ );
66
+ CREATE INDEX IF NOT EXISTS idx_dt_compatible ON dt_bindings(compatible);
67
+
68
+ -- Docs chunks table
69
+ CREATE TABLE IF NOT EXISTS docs_chunks (
70
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
71
+ title TEXT,
72
+ heading_path TEXT,
73
+ body TEXT,
74
+ source_url TEXT,
75
+ domain TEXT
76
+ );
77
+
78
+ -- FTS indexes
79
+ CREATE VIRTUAL TABLE IF NOT EXISTS functions_fts USING fts5(
80
+ name, signature, brief, description, params,
81
+ content='functions',
82
+ content_rowid='id'
83
+ );
84
+
85
+ CREATE VIRTUAL TABLE IF NOT EXISTS kconfig_fts USING fts5(
86
+ name, prompt, help_text,
87
+ content='kconfig_symbols',
88
+ content_rowid='id'
89
+ );
90
+
91
+ CREATE VIRTUAL TABLE IF NOT EXISTS dt_fts USING fts5(
92
+ compatible, description, properties,
93
+ content='dt_bindings',
94
+ content_rowid='id'
95
+ );
96
+
97
+ CREATE VIRTUAL TABLE IF NOT EXISTS docs_fts USING fts5(
98
+ title, heading_path, body,
99
+ content='docs_chunks',
100
+ content_rowid='id'
101
+ );
102
+
103
+ -- Meta table for version tracking
104
+ CREATE TABLE IF NOT EXISTS meta (
105
+ key TEXT PRIMARY KEY,
106
+ value TEXT NOT NULL
107
+ );
108
+ `);
109
+ }
110
+ // --- Insert helpers ---
111
+ insertFunction(row) {
112
+ const stmt = this.db.prepare(`INSERT INTO functions (name, signature, brief, description, params, return_type, return_desc, header, section, group_id)
113
+ VALUES (@name, @signature, @brief, @description, @params, @return_type, @return_desc, @header, @section, @group_id)`);
114
+ stmt.run({
115
+ name: row.name,
116
+ signature: row.signature,
117
+ brief: row.brief ?? null,
118
+ description: row.description ?? null,
119
+ params: row.params ?? null,
120
+ return_type: row.return_type ?? null,
121
+ return_desc: row.return_desc ?? null,
122
+ header: row.header ?? null,
123
+ section: row.section ?? null,
124
+ group_id: row.group_id ?? null,
125
+ });
126
+ }
127
+ insertFunctionsBatch(rows) {
128
+ const stmt = this.db.prepare(`INSERT INTO functions (name, signature, brief, description, params, return_type, return_desc, header, section, group_id)
129
+ VALUES (@name, @signature, @brief, @description, @params, @return_type, @return_desc, @header, @section, @group_id)`);
130
+ const txn = this.db.transaction((items) => {
131
+ for (const row of items) {
132
+ stmt.run({
133
+ name: row.name,
134
+ signature: row.signature,
135
+ brief: row.brief ?? null,
136
+ description: row.description ?? null,
137
+ params: row.params ?? null,
138
+ return_type: row.return_type ?? null,
139
+ return_desc: row.return_desc ?? null,
140
+ header: row.header ?? null,
141
+ section: row.section ?? null,
142
+ group_id: row.group_id ?? null,
143
+ });
144
+ }
145
+ });
146
+ txn(rows);
147
+ }
148
+ insertKconfig(row) {
149
+ const stmt = this.db.prepare(`INSERT INTO kconfig_symbols (name, type, prompt, default_val, depends_on, select_list, range_min, range_max, help_text, path)
150
+ VALUES (@name, @type, @prompt, @default_val, @depends_on, @select_list, @range_min, @range_max, @help_text, @path)`);
151
+ stmt.run({
152
+ name: row.name,
153
+ type: row.type ?? null,
154
+ prompt: row.prompt ?? null,
155
+ default_val: row.default_val ?? null,
156
+ depends_on: row.depends_on ?? null,
157
+ select_list: row.select_list ?? null,
158
+ range_min: row.range_min ?? null,
159
+ range_max: row.range_max ?? null,
160
+ help_text: row.help_text ?? null,
161
+ path: row.path ?? null,
162
+ });
163
+ }
164
+ insertKconfigsBatch(rows) {
165
+ const stmt = this.db.prepare(`INSERT INTO kconfig_symbols (name, type, prompt, default_val, depends_on, select_list, range_min, range_max, help_text, path)
166
+ VALUES (@name, @type, @prompt, @default_val, @depends_on, @select_list, @range_min, @range_max, @help_text, @path)`);
167
+ const txn = this.db.transaction((items) => {
168
+ for (const row of items) {
169
+ stmt.run({
170
+ name: row.name,
171
+ type: row.type ?? null,
172
+ prompt: row.prompt ?? null,
173
+ default_val: row.default_val ?? null,
174
+ depends_on: row.depends_on ?? null,
175
+ select_list: row.select_list ?? null,
176
+ range_min: row.range_min ?? null,
177
+ range_max: row.range_max ?? null,
178
+ help_text: row.help_text ?? null,
179
+ path: row.path ?? null,
180
+ });
181
+ }
182
+ });
183
+ txn(rows);
184
+ }
185
+ insertDtBinding(row) {
186
+ const stmt = this.db.prepare(`INSERT INTO dt_bindings (compatible, description, properties, child_binding, bus, on_bus, path)
187
+ VALUES (@compatible, @description, @properties, @child_binding, @bus, @on_bus, @path)`);
188
+ stmt.run({
189
+ compatible: row.compatible,
190
+ description: row.description ?? null,
191
+ properties: row.properties ?? null,
192
+ child_binding: row.child_binding ?? null,
193
+ bus: row.bus ?? null,
194
+ on_bus: row.on_bus ?? null,
195
+ path: row.path ?? null,
196
+ });
197
+ }
198
+ insertDtBindingsBatch(rows) {
199
+ const stmt = this.db.prepare(`INSERT INTO dt_bindings (compatible, description, properties, child_binding, bus, on_bus, path)
200
+ VALUES (@compatible, @description, @properties, @child_binding, @bus, @on_bus, @path)`);
201
+ const txn = this.db.transaction((items) => {
202
+ for (const row of items) {
203
+ stmt.run({
204
+ compatible: row.compatible,
205
+ description: row.description ?? null,
206
+ properties: row.properties ?? null,
207
+ child_binding: row.child_binding ?? null,
208
+ bus: row.bus ?? null,
209
+ on_bus: row.on_bus ?? null,
210
+ path: row.path ?? null,
211
+ });
212
+ }
213
+ });
214
+ txn(rows);
215
+ }
216
+ insertDocChunk(row) {
217
+ const stmt = this.db.prepare(`INSERT INTO docs_chunks (title, heading_path, body, source_url, domain)
218
+ VALUES (@title, @heading_path, @body, @source_url, @domain)`);
219
+ stmt.run({
220
+ title: row.title ?? null,
221
+ heading_path: row.heading_path ?? null,
222
+ body: row.body ?? null,
223
+ source_url: row.source_url ?? null,
224
+ domain: row.domain ?? null,
225
+ });
226
+ }
227
+ insertDocChunksBatch(rows) {
228
+ const stmt = this.db.prepare(`INSERT INTO docs_chunks (title, heading_path, body, source_url, domain)
229
+ VALUES (@title, @heading_path, @body, @source_url, @domain)`);
230
+ const txn = this.db.transaction((items) => {
231
+ for (const row of items) {
232
+ stmt.run({
233
+ title: row.title ?? null,
234
+ heading_path: row.heading_path ?? null,
235
+ body: row.body ?? null,
236
+ source_url: row.source_url ?? null,
237
+ domain: row.domain ?? null,
238
+ });
239
+ }
240
+ });
241
+ txn(rows);
242
+ }
243
+ // --- FTS rebuild ---
244
+ rebuildFts() {
245
+ this.db.exec(`
246
+ INSERT INTO functions_fts(rowid, name, signature, brief, description, params)
247
+ SELECT id, name, signature, brief, description, params FROM functions;
248
+ INSERT INTO kconfig_fts(rowid, name, prompt, help_text)
249
+ SELECT id, name, prompt, help_text FROM kconfig_symbols;
250
+ INSERT INTO dt_fts(rowid, compatible, description, properties)
251
+ SELECT id, compatible, description, properties FROM dt_bindings;
252
+ INSERT INTO docs_fts(rowid, title, heading_path, body)
253
+ SELECT id, title, heading_path, body FROM docs_chunks;
254
+ `);
255
+ }
256
+ // --- Meta ---
257
+ setMeta(key, value) {
258
+ this.db
259
+ .prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)")
260
+ .run(key, value);
261
+ }
262
+ getMeta(key) {
263
+ const row = this.db
264
+ .prepare("SELECT value FROM meta WHERE key = ?")
265
+ .get(key);
266
+ return row?.value;
267
+ }
268
+ /** Add FTS5 prefix wildcard to last token, and escape special characters. */
269
+ ftsQuery(query) {
270
+ const trimmed = query.trim();
271
+ if (trimmed.length === 0)
272
+ return query;
273
+ // Already escaped as a phrase or has wildcard — return as-is
274
+ if (trimmed.endsWith("*") || (trimmed.startsWith('"') && trimmed.endsWith('"'))) {
275
+ return trimmed;
276
+ }
277
+ // If query contains special FTS5 chars (,, , (, ), NEAR, etc.), treat as phrase
278
+ if (/[,()]/.test(trimmed)) {
279
+ return `"${trimmed}"`;
280
+ }
281
+ // Add prefix wildcard to last token
282
+ const tokens = trimmed.split(/\s+/);
283
+ if (tokens.length === 0)
284
+ return query;
285
+ tokens[tokens.length - 1] = tokens[tokens.length - 1] + "*";
286
+ return tokens.join(" ");
287
+ }
288
+ // --- Query helpers ---
289
+ getFunctionByName(name) {
290
+ return this.db
291
+ .prepare("SELECT * FROM functions WHERE name = ? ORDER BY id LIMIT 1")
292
+ .get(name);
293
+ }
294
+ getBindingByCompatible(compatible) {
295
+ return this.db
296
+ .prepare("SELECT * FROM dt_bindings WHERE compatible = ? ORDER BY id LIMIT 1")
297
+ .get(compatible);
298
+ }
299
+ searchFunctions(query, limit = 10) {
300
+ const fts = this.ftsQuery(query);
301
+ return this.db
302
+ .prepare(`SELECT f.* FROM functions_fts ft
303
+ JOIN functions f ON f.id = ft.rowid
304
+ WHERE functions_fts MATCH ?
305
+ ORDER BY rank
306
+ LIMIT ?`)
307
+ .all(fts, limit);
308
+ }
309
+ searchKconfig(query, limit = 10) {
310
+ const fts = this.ftsQuery(query);
311
+ return this.db
312
+ .prepare(`SELECT k.* FROM kconfig_fts ft
313
+ JOIN kconfig_symbols k ON k.id = ft.rowid
314
+ WHERE kconfig_fts MATCH ?
315
+ ORDER BY rank
316
+ LIMIT ?`)
317
+ .all(fts, limit);
318
+ }
319
+ searchBindings(query, limit = 10) {
320
+ const fts = this.ftsQuery(query);
321
+ return this.db
322
+ .prepare(`SELECT d.* FROM dt_fts ft
323
+ JOIN dt_bindings d ON d.id = ft.rowid
324
+ WHERE dt_fts MATCH ?
325
+ ORDER BY rank
326
+ LIMIT ?`)
327
+ .all(fts, limit);
328
+ }
329
+ searchDocs(query, limit = 10) {
330
+ const fts = this.ftsQuery(query);
331
+ return this.db
332
+ .prepare(`SELECT d.* FROM docs_fts ft
333
+ JOIN docs_chunks d ON d.id = ft.rowid
334
+ WHERE docs_fts MATCH ?
335
+ ORDER BY rank
336
+ LIMIT ?`)
337
+ .all(fts, limit);
338
+ }
339
+ close() {
340
+ this.db.close();
341
+ }
342
+ }
343
+ //# sourceMappingURL=db.js.map
package/dist/db.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}