@ngommans/codefocus 0.1.3 → 0.1.4

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.

Potentially problematic release.


This version of @ngommans/codefocus might be problematic. Click here for more details.

@@ -1,559 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- IndexDatabase,
4
3
  resolveRoot
5
- } from "./chunk-ITVAEU6K.js";
4
+ } from "./chunk-ZIVIJRW3.js";
5
+ import {
6
+ indexProject
7
+ } from "./chunk-FQ3L6YEU.js";
8
+ import {
9
+ IndexDatabase
10
+ } from "./chunk-472RLVFC.js";
6
11
 
7
12
  // src/mcp.ts
8
- import { createRequire as createRequire3 } from "module";
9
- import { resolve as resolve2 } from "path";
13
+ import { createRequire } from "module";
14
+ import { resolve } from "path";
10
15
  import { existsSync } from "fs";
11
16
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
17
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
18
  import { z } from "zod";
14
-
15
- // src/indexer.ts
16
- import { createRequire as createRequire2 } from "module";
17
- import { readFileSync } from "fs";
18
- import { resolve, relative, dirname, extname } from "path";
19
- import { createHash } from "crypto";
20
-
21
- // src/parser.ts
22
- import { createRequire } from "module";
23
19
  var require2 = createRequire(import.meta.url);
24
- var Parser = require2("tree-sitter");
25
- var TypeScriptLang = require2("tree-sitter-typescript").typescript;
26
- var parser = null;
27
- function getParser() {
28
- if (!parser) {
29
- parser = new Parser();
30
- parser.setLanguage(TypeScriptLang);
31
- }
32
- return parser;
33
- }
34
- function extractSignature(node, source) {
35
- const kind = node.type;
36
- if (kind === "function_declaration" || kind === "arrow_function") {
37
- const nameNode = node.childForFieldName("name");
38
- const paramsNode = node.childForFieldName("parameters");
39
- const returnType = node.childForFieldName("return_type");
40
- if (nameNode && paramsNode) {
41
- let sig = `function ${nameNode.text}${paramsNode.text}`;
42
- if (returnType) sig += returnType.text;
43
- return sig;
44
- }
45
- }
46
- if (kind === "class_declaration") {
47
- const nameNode = node.childForFieldName("name");
48
- if (nameNode) return `class ${nameNode.text}`;
49
- }
50
- if (kind === "interface_declaration") {
51
- const nameNode = node.childForFieldName("name");
52
- if (nameNode) return `interface ${nameNode.text}`;
53
- }
54
- if (kind === "type_alias_declaration") {
55
- const text = node.text;
56
- const semiIdx = text.indexOf(";");
57
- return semiIdx > 0 ? text.slice(0, semiIdx) : text;
58
- }
59
- if (kind === "enum_declaration") {
60
- const nameNode = node.childForFieldName("name");
61
- if (nameNode) return `enum ${nameNode.text}`;
62
- }
63
- if (kind === "method_definition") {
64
- const nameNode = node.childForFieldName("name");
65
- const paramsNode = node.childForFieldName("parameters");
66
- const returnType = node.childForFieldName("return_type");
67
- if (nameNode && paramsNode) {
68
- let sig = `${nameNode.text}${paramsNode.text}`;
69
- if (returnType) sig += returnType.text;
70
- return sig;
71
- }
72
- }
73
- return null;
74
- }
75
- function getSymbolName(node) {
76
- const nameNode = node.childForFieldName("name") ?? node.childForFieldName("declarator");
77
- return nameNode?.text ?? null;
78
- }
79
- function extractDeclaration(node, source, exported) {
80
- const kindMap = {
81
- function_declaration: "function",
82
- class_declaration: "class",
83
- interface_declaration: "interface",
84
- type_alias_declaration: "type",
85
- enum_declaration: "enum"
86
- };
87
- const kind = kindMap[node.type];
88
- if (!kind) return null;
89
- const name = getSymbolName(node);
90
- if (!name) return null;
91
- return {
92
- name,
93
- kind,
94
- startByte: node.startIndex,
95
- endByte: node.endIndex,
96
- startLine: node.startPosition.row + 1,
97
- endLine: node.endPosition.row + 1,
98
- startColumn: node.startPosition.column,
99
- endColumn: node.endPosition.column,
100
- signature: extractSignature(node, source),
101
- exported
102
- };
103
- }
104
- function extractMethods(classNode, source, exported) {
105
- const methods = [];
106
- const body = classNode.childForFieldName("body");
107
- if (!body) return methods;
108
- for (const child of body.namedChildren) {
109
- if (child.type === "method_definition") {
110
- const nameNode = child.childForFieldName("name");
111
- if (!nameNode) continue;
112
- methods.push({
113
- name: nameNode.text,
114
- kind: "method",
115
- startByte: child.startIndex,
116
- endByte: child.endIndex,
117
- startLine: child.startPosition.row + 1,
118
- endLine: child.endPosition.row + 1,
119
- startColumn: child.startPosition.column,
120
- endColumn: child.endPosition.column,
121
- signature: extractSignature(child, source),
122
- exported
123
- });
124
- }
125
- }
126
- return methods;
127
- }
128
- function extractVariableDeclarations(node, exported) {
129
- const symbols = [];
130
- for (const child of node.namedChildren) {
131
- if (child.type === "variable_declarator") {
132
- const nameNode = child.childForFieldName("name");
133
- if (nameNode) {
134
- symbols.push({
135
- name: nameNode.text,
136
- kind: "variable",
137
- startByte: node.startIndex,
138
- endByte: node.endIndex,
139
- startLine: node.startPosition.row + 1,
140
- endLine: node.endPosition.row + 1,
141
- startColumn: node.startPosition.column,
142
- endColumn: node.endPosition.column,
143
- signature: null,
144
- exported
145
- });
146
- }
147
- }
148
- }
149
- return symbols;
150
- }
151
- function extractImport(node) {
152
- let sourceNode = null;
153
- for (const child of node.children) {
154
- if (child.type === "string") {
155
- sourceNode = child;
156
- break;
157
- }
158
- }
159
- if (!sourceNode) return null;
160
- const rawSource = sourceNode.text;
161
- const source = rawSource.replace(/^['"]|['"]$/g, "");
162
- const specifiers = [];
163
- const isTypeOnly = node.children.some(
164
- (c) => c.type === "type" && c.text === "type"
165
- );
166
- for (const child of node.children) {
167
- if (child.type === "import_clause") {
168
- for (const clause of child.namedChildren) {
169
- if (clause.type === "named_imports") {
170
- for (const spec of clause.namedChildren) {
171
- if (spec.type === "import_specifier") {
172
- const nameNode = spec.childForFieldName("name");
173
- const aliasNode = spec.childForFieldName("alias");
174
- specifiers.push(aliasNode?.text ?? nameNode?.text ?? spec.text);
175
- }
176
- }
177
- } else if (clause.type === "identifier") {
178
- specifiers.push(clause.text);
179
- } else if (clause.type === "namespace_import") {
180
- const nameNode = clause.namedChildren.find(
181
- (c) => c.type === "identifier"
182
- );
183
- if (nameNode) specifiers.push(`* as ${nameNode.text}`);
184
- }
185
- }
186
- }
187
- }
188
- return { specifiers, source, isTypeOnly };
189
- }
190
- function extractReExportSpecifiers(node) {
191
- const specifiers = [];
192
- for (const child of node.children) {
193
- if (child.type === "export_clause") {
194
- for (const spec of child.namedChildren) {
195
- if (spec.type === "export_specifier") {
196
- const nameNode = spec.childForFieldName("name");
197
- if (nameNode) specifiers.push(nameNode.text);
198
- }
199
- }
200
- }
201
- }
202
- return specifiers;
203
- }
204
- function findIdentifierUsages(source, names) {
205
- if (names.size === 0) return [];
206
- const p = getParser();
207
- const tree = p.parse(source);
208
- const root = tree.rootNode;
209
- const usages = [];
210
- function walk(node) {
211
- if ((node.type === "identifier" || node.type === "type_identifier") && names.has(node.text)) {
212
- let parent = node.parent;
213
- let isImportExport = false;
214
- while (parent) {
215
- if (parent.type === "import_statement" || parent.type === "import_clause" || parent.type === "import_specifier" || parent.type === "export_statement" && parent.children.some((c) => c.type === "from")) {
216
- isImportExport = true;
217
- break;
218
- }
219
- parent = parent.parent;
220
- }
221
- if (!isImportExport) {
222
- usages.push({
223
- name: node.text,
224
- line: node.startPosition.row + 1,
225
- column: node.startPosition.column
226
- });
227
- }
228
- }
229
- for (const child of node.children) {
230
- walk(child);
231
- }
232
- }
233
- walk(root);
234
- return usages;
235
- }
236
- function extractDynamicImports(root) {
237
- const imports = [];
238
- function walk(node) {
239
- if (node.type === "call_expression") {
240
- const fn = node.child(0);
241
- if (fn && fn.type === "import") {
242
- const argsNode = node.childForFieldName("arguments");
243
- if (argsNode) {
244
- const strArg = argsNode.namedChildren.find(
245
- (c) => c.type === "string"
246
- );
247
- if (strArg) {
248
- const modulePath = strArg.text.replace(/^['"]|['"]$/g, "");
249
- const specifiers = extractDynamicImportSpecifiers(node);
250
- imports.push({ specifiers, source: modulePath, isTypeOnly: false });
251
- }
252
- }
253
- return;
254
- }
255
- }
256
- for (const child of node.children) {
257
- walk(child);
258
- }
259
- }
260
- walk(root);
261
- return imports;
262
- }
263
- function extractDynamicImportSpecifiers(importCall) {
264
- let current = importCall.parent;
265
- if (current && current.type === "await_expression") {
266
- current = current.parent;
267
- }
268
- if (current && current.type === "variable_declarator") {
269
- const pattern = current.childForFieldName("name");
270
- if (pattern && pattern.type === "object_pattern") {
271
- const specs = [];
272
- for (const child of pattern.namedChildren) {
273
- if (child.type === "shorthand_property_identifier_pattern") {
274
- specs.push(child.text);
275
- } else if (child.type === "pair_pattern") {
276
- const value = child.childForFieldName("value");
277
- if (value) specs.push(value.text);
278
- }
279
- }
280
- return specs;
281
- }
282
- }
283
- return [];
284
- }
285
- function parseSource(source) {
286
- const p = getParser();
287
- const tree = p.parse(source);
288
- const root = tree.rootNode;
289
- const symbols = [];
290
- const imports = [];
291
- for (const node of root.namedChildren) {
292
- if (node.type === "import_statement") {
293
- const imp = extractImport(node);
294
- if (imp) imports.push(imp);
295
- continue;
296
- }
297
- if (node.type === "export_statement") {
298
- const hasFrom = node.children.some(
299
- (c) => c.type === "from"
300
- );
301
- if (hasFrom) {
302
- let sourceNode = null;
303
- for (const child of node.children) {
304
- if (child.type === "string") {
305
- sourceNode = child;
306
- break;
307
- }
308
- }
309
- if (sourceNode) {
310
- const rawSource = sourceNode.text;
311
- const source2 = rawSource.replace(/^['"]|['"]$/g, "");
312
- const specifiers = extractReExportSpecifiers(node);
313
- const isTypeOnly = node.children.some(
314
- (c) => c.type === "type" && c.text === "type"
315
- );
316
- imports.push({ specifiers, source: source2, isTypeOnly });
317
- }
318
- continue;
319
- }
320
- for (const child of node.namedChildren) {
321
- const decl2 = extractDeclaration(child, source, true);
322
- if (decl2) {
323
- symbols.push(decl2);
324
- if (child.type === "class_declaration") {
325
- symbols.push(...extractMethods(child, source, true));
326
- }
327
- }
328
- if (child.type === "lexical_declaration" || child.type === "variable_declaration") {
329
- symbols.push(...extractVariableDeclarations(child, true));
330
- }
331
- }
332
- continue;
333
- }
334
- const decl = extractDeclaration(node, source, false);
335
- if (decl) {
336
- symbols.push(decl);
337
- if (node.type === "class_declaration") {
338
- symbols.push(...extractMethods(node, source, false));
339
- }
340
- }
341
- if (node.type === "lexical_declaration" || node.type === "variable_declaration") {
342
- symbols.push(...extractVariableDeclarations(node, false));
343
- }
344
- }
345
- imports.push(...extractDynamicImports(root));
346
- return { symbols, imports };
347
- }
348
-
349
- // src/indexer.ts
350
- var require3 = createRequire2(import.meta.url);
351
- var fg = require3("fast-glob");
352
- var TS_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
353
- var IGNORE_PATTERNS = [
354
- "**/node_modules/**",
355
- "**/dist/**",
356
- "**/.codefocus/**",
357
- "**/__tests__/**",
358
- "**/*.test.*",
359
- "**/*.spec.*",
360
- "**/*.d.ts"
361
- ];
362
- function hashContent(content) {
363
- return createHash("sha256").update(content).digest("hex").slice(0, 16);
364
- }
365
- function resolveImportPath(importSource, fromFile, rootDir2, allFiles) {
366
- if (!importSource.startsWith(".")) return null;
367
- const fromDir = dirname(fromFile);
368
- const basePath = resolve(rootDir2, fromDir, importSource);
369
- const ext = extname(basePath);
370
- const strippedBase = ext === ".js" || ext === ".jsx" ? basePath.slice(0, -ext.length) : null;
371
- const candidates = [
372
- basePath,
373
- ...Array.from(TS_EXTENSIONS).map((e) => basePath + e),
374
- ...Array.from(TS_EXTENSIONS).map((e) => resolve(basePath, "index" + e))
375
- ];
376
- if (strippedBase) {
377
- candidates.push(
378
- ...Array.from(TS_EXTENSIONS).map((e) => strippedBase + e),
379
- ...Array.from(TS_EXTENSIONS).map(
380
- (e) => resolve(strippedBase, "index" + e)
381
- )
382
- );
383
- }
384
- for (const candidate of candidates) {
385
- const rel = relative(rootDir2, candidate);
386
- if (allFiles.has(rel)) return rel;
387
- }
388
- return null;
389
- }
390
- async function indexProject(rootDir2, dbPath) {
391
- const startTime = Date.now();
392
- const absRoot = resolve(rootDir2);
393
- const files = await fg("**/*.{ts,tsx,js,jsx}", {
394
- cwd: absRoot,
395
- ignore: IGNORE_PATTERNS,
396
- absolute: false
397
- });
398
- const allFiles = new Set(files);
399
- const db2 = new IndexDatabase(dbPath);
400
- let filesIndexed = 0;
401
- let filesSkipped = 0;
402
- let symbolsExtracted = 0;
403
- let importsFound = 0;
404
- let referencesCreated = 0;
405
- const symbolIdMap = /* @__PURE__ */ new Map();
406
- const fileImports = /* @__PURE__ */ new Map();
407
- const fileContents = /* @__PURE__ */ new Map();
408
- db2.transaction(() => {
409
- for (const filePath of files) {
410
- const absPath = resolve(absRoot, filePath);
411
- let content;
412
- try {
413
- content = readFileSync(absPath, "utf-8");
414
- } catch {
415
- filesSkipped++;
416
- continue;
417
- }
418
- const hash = hashContent(content);
419
- const existingHash = db2.getFileHash(filePath);
420
- const result = parseSource(content);
421
- if (result.imports.length > 0) {
422
- fileImports.set(filePath, result.imports);
423
- fileContents.set(filePath, content);
424
- }
425
- if (existingHash === hash) {
426
- filesSkipped++;
427
- for (const sym of db2.getSymbolsByFile(filePath)) {
428
- symbolIdMap.set(`${filePath}:${sym.name}`, sym.id);
429
- }
430
- continue;
431
- }
432
- db2.clearFile(filePath);
433
- const ext = extname(filePath);
434
- const language = ext === ".js" || ext === ".jsx" ? "javascript" : "typescript";
435
- db2.upsertFile({
436
- path: filePath,
437
- content_hash: hash,
438
- language,
439
- last_indexed: Date.now()
440
- });
441
- db2.upsertFileContent(filePath, content);
442
- for (const sym of result.symbols) {
443
- const id = db2.insertSymbol({
444
- file_path: filePath,
445
- name: sym.name,
446
- kind: sym.kind,
447
- start_byte: sym.startByte,
448
- end_byte: sym.endByte,
449
- start_line: sym.startLine,
450
- end_line: sym.endLine,
451
- start_column: sym.startColumn,
452
- end_column: sym.endColumn,
453
- signature: sym.signature
454
- });
455
- symbolIdMap.set(`${filePath}:${sym.name}`, id);
456
- symbolsExtracted++;
457
- }
458
- filesIndexed++;
459
- }
460
- db2.clearAllImports();
461
- db2.clearAllReferences();
462
- for (const [filePath, imports] of fileImports) {
463
- const fileSymbolRows = db2.getSymbolsByFile(filePath);
464
- const sourceSymbols = fileSymbolRows.map((sym) => ({
465
- name: sym.name,
466
- id: sym.id,
467
- startLine: sym.start_line,
468
- endLine: sym.end_line
469
- }));
470
- const allImportedNames = /* @__PURE__ */ new Set();
471
- for (const imp of imports) {
472
- for (const specName of imp.specifiers) {
473
- const cleanName = specName.startsWith("* as ") ? specName.slice(5) : specName;
474
- allImportedNames.add(cleanName);
475
- }
476
- }
477
- const content = fileContents.get(filePath);
478
- const usages = content ? findIdentifierUsages(content, allImportedNames) : [];
479
- for (const imp of imports) {
480
- const targetFile = resolveImportPath(
481
- imp.source,
482
- filePath,
483
- absRoot,
484
- allFiles
485
- );
486
- for (const specName of imp.specifiers) {
487
- const cleanName = specName.startsWith("* as ") ? specName.slice(5) : specName;
488
- db2.insertImport({
489
- file_path: filePath,
490
- specifier: cleanName,
491
- source_path: targetFile,
492
- raw_module: imp.source,
493
- is_type_only: imp.isTypeOnly ? 1 : 0
494
- });
495
- importsFound++;
496
- }
497
- if (!targetFile) continue;
498
- const refType = imp.isTypeOnly ? "type_ref" : "import";
499
- for (const specName of imp.specifiers) {
500
- const cleanName = specName.startsWith("* as ") ? specName.slice(5) : specName;
501
- const targetKey = `${targetFile}:${cleanName}`;
502
- const targetId = symbolIdMap.get(targetKey);
503
- if (!targetId) continue;
504
- const nameUsages = usages.filter((u) => u.name === cleanName);
505
- if (nameUsages.length > 0) {
506
- const referencingSymbolIds = /* @__PURE__ */ new Set();
507
- for (const usage of nameUsages) {
508
- for (const srcSym of sourceSymbols) {
509
- if (srcSym.id !== targetId && usage.line >= srcSym.startLine && usage.line <= srcSym.endLine) {
510
- referencingSymbolIds.add(srcSym.id);
511
- }
512
- }
513
- }
514
- for (const sourceId of referencingSymbolIds) {
515
- db2.insertReference({
516
- source_symbol_id: sourceId,
517
- target_symbol_id: targetId,
518
- ref_type: refType
519
- });
520
- referencesCreated++;
521
- }
522
- } else {
523
- for (const srcSym of sourceSymbols) {
524
- if (srcSym.id !== targetId) {
525
- db2.insertReference({
526
- source_symbol_id: srcSym.id,
527
- target_symbol_id: targetId,
528
- ref_type: refType
529
- });
530
- referencesCreated++;
531
- }
532
- }
533
- }
534
- }
535
- }
536
- }
537
- });
538
- db2.close();
539
- return {
540
- filesIndexed,
541
- filesSkipped,
542
- symbolsExtracted,
543
- importsFound,
544
- referencesCreated,
545
- timeMs: Date.now() - startTime
546
- };
547
- }
548
-
549
- // src/mcp.ts
550
- var require4 = createRequire3(import.meta.url);
551
- var pkg = require4("../package.json");
20
+ var pkg = require2("../package.json");
552
21
  var db = null;
553
22
  var rootDir = "";
554
23
  function getDb(root) {
555
24
  if (db && rootDir === root) return db;
556
- const dbPath = resolve2(root, ".codefocus", "index.db");
25
+ const dbPath = resolve(root, ".codefocus", "index.db");
557
26
  if (!existsSync(dbPath)) {
558
27
  throw new Error(
559
28
  `no index found at ${dbPath}
@@ -660,7 +129,7 @@ function createMcpServer(defaultRoot) {
660
129
  return server;
661
130
  }
662
131
  async function captureQueryOutput(root, term, budget, depth) {
663
- const { runQueryCore } = await import("./query-PS6QVPXP.js");
132
+ const { runQueryCore } = await import("./query-64CFCXTD.js");
664
133
  return runQueryCore(root, term, budget, depth);
665
134
  }
666
135
  function captureGraphOutput(root, target, direction) {
@@ -673,8 +142,8 @@ function captureGraphOutput(root, target, direction) {
673
142
  }
674
143
  }
675
144
  function renderFileGraphToString(database, target, direction) {
676
- const require5 = createRequire3(import.meta.url);
677
- const { DirectedGraph } = require5("graphology");
145
+ const require3 = createRequire(import.meta.url);
146
+ const { DirectedGraph } = require3("graphology");
678
147
  const graph = new DirectedGraph();
679
148
  for (const file of database.getAllFiles()) {
680
149
  graph.addNode(file.path);
@@ -762,10 +231,10 @@ ${lines.join("\n")}` : "Dependents (incoming): (none)"
762
231
  ${sections.join("\n\n")}`;
763
232
  }
764
233
  function captureMapOutput(root, budget) {
765
- const require5 = createRequire3(import.meta.url);
766
- const { DirectedGraph } = require5("graphology");
767
- const pagerank = require5("graphology-metrics/centrality/pagerank");
768
- const { getEncoding } = require5("js-tiktoken");
234
+ const require3 = createRequire(import.meta.url);
235
+ const { DirectedGraph } = require3("graphology");
236
+ const pagerank = require3("graphology-metrics/centrality/pagerank");
237
+ const { getEncoding } = require3("js-tiktoken");
769
238
  const database = getDb(root);
770
239
  const files = database.getAllFiles();
771
240
  if (files.length === 0) {
@@ -864,24 +333,42 @@ Usage with Claude Code:
864
333
  return;
865
334
  }
866
335
  const root = resolveRoot(flags2.root);
867
- const dbPath = resolve2(root, ".codefocus", "index.db");
868
- if (!existsSync(dbPath)) {
869
- if (!existsSync(root)) {
870
- console.error(
871
- `Error: root directory does not exist: ${root}`
872
- );
873
- process.exitCode = 1;
874
- return;
875
- }
876
- console.error(`[codefocus] No index found \u2014 auto-indexing ${root} ...`);
877
- const stats = await indexProject(root, dbPath);
878
- console.error(
879
- `[codefocus] Index complete: ${stats.filesIndexed} files, ${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`
880
- );
336
+ const dbPath = resolve(root, ".codefocus", "index.db");
337
+ if (!existsSync(root)) {
338
+ console.error(`Error: root directory does not exist: ${root}`);
339
+ process.exitCode = 1;
340
+ return;
881
341
  }
342
+ console.error(`[codefocus] Indexing ${root} ...`);
343
+ const stats = await indexProject(root, dbPath);
344
+ console.error(
345
+ `[codefocus] Index complete: ${stats.filesIndexed} files, ${stats.symbolsExtracted} symbols (${stats.timeMs}ms)`
346
+ );
882
347
  getDb(root);
883
348
  console.error(`[codefocus] MCP server starting (root: ${root})`);
884
349
  console.error(`[codefocus] Database: ${dbPath}`);
350
+ const { startWatcher } = await import("./watcher-6WHIBMPS.js");
351
+ const watcher = await startWatcher({
352
+ rootDir: root,
353
+ dbPath,
354
+ onReindex: (stats2) => {
355
+ if (stats2.filesIndexed > 0) {
356
+ if (db) {
357
+ db.close();
358
+ db = null;
359
+ }
360
+ getDb(root);
361
+ console.error(
362
+ `[codefocus] Re-indexed: ${stats2.filesIndexed} files, ${stats2.symbolsExtracted} symbols (${stats2.timeMs}ms)`
363
+ );
364
+ }
365
+ }
366
+ });
367
+ process.on("SIGINT", () => {
368
+ watcher.close();
369
+ if (db) db.close();
370
+ process.exit(0);
371
+ });
885
372
  const server = createMcpServer(root);
886
373
  const transport = new StdioServerTransport();
887
374
  await server.connect(transport);