@veewo/gitnexus 1.3.11 → 1.4.6-rc

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 (181) hide show
  1. package/README.md +37 -80
  2. package/dist/benchmark/agent-context/tool-runner.js +2 -2
  3. package/dist/benchmark/neonspark-candidates.js +3 -3
  4. package/dist/benchmark/tool-runner.js +2 -2
  5. package/dist/cli/ai-context.d.ts +2 -1
  6. package/dist/cli/ai-context.js +16 -12
  7. package/dist/cli/analyze.d.ts +2 -0
  8. package/dist/cli/analyze.js +68 -48
  9. package/dist/cli/augment.js +1 -1
  10. package/dist/cli/eval-server.d.ts +8 -1
  11. package/dist/cli/eval-server.js +30 -13
  12. package/dist/cli/index.js +28 -82
  13. package/dist/cli/lazy-action.d.ts +6 -0
  14. package/dist/cli/lazy-action.js +18 -0
  15. package/dist/cli/mcp.js +3 -1
  16. package/dist/cli/setup.js +87 -48
  17. package/dist/cli/setup.test.js +18 -13
  18. package/dist/cli/skill-gen.d.ts +26 -0
  19. package/dist/cli/skill-gen.js +549 -0
  20. package/dist/cli/status.js +13 -4
  21. package/dist/cli/tool.d.ts +3 -2
  22. package/dist/cli/tool.js +50 -16
  23. package/dist/cli/wiki.js +8 -4
  24. package/dist/config/ignore-service.d.ts +25 -0
  25. package/dist/config/ignore-service.js +76 -0
  26. package/dist/config/supported-languages.d.ts +4 -1
  27. package/dist/config/supported-languages.js +3 -2
  28. package/dist/core/augmentation/engine.js +94 -67
  29. package/dist/core/embeddings/embedder.d.ts +1 -1
  30. package/dist/core/embeddings/embedder.js +1 -1
  31. package/dist/core/embeddings/embedding-pipeline.d.ts +3 -3
  32. package/dist/core/embeddings/embedding-pipeline.js +52 -25
  33. package/dist/core/embeddings/types.d.ts +1 -1
  34. package/dist/core/graph/types.d.ts +7 -2
  35. package/dist/core/ingestion/ast-cache.js +3 -2
  36. package/dist/core/ingestion/call-processor.d.ts +8 -6
  37. package/dist/core/ingestion/call-processor.js +468 -206
  38. package/dist/core/ingestion/call-routing.d.ts +53 -0
  39. package/dist/core/ingestion/call-routing.js +108 -0
  40. package/dist/core/ingestion/constants.d.ts +16 -0
  41. package/dist/core/ingestion/constants.js +16 -0
  42. package/dist/core/ingestion/entry-point-scoring.d.ts +2 -1
  43. package/dist/core/ingestion/entry-point-scoring.js +116 -23
  44. package/dist/core/ingestion/export-detection.d.ts +18 -0
  45. package/dist/core/ingestion/export-detection.js +231 -0
  46. package/dist/core/ingestion/filesystem-walker.js +4 -3
  47. package/dist/core/ingestion/framework-detection.d.ts +19 -4
  48. package/dist/core/ingestion/framework-detection.js +182 -6
  49. package/dist/core/ingestion/heritage-processor.d.ts +13 -5
  50. package/dist/core/ingestion/heritage-processor.js +109 -55
  51. package/dist/core/ingestion/import-processor.d.ts +16 -20
  52. package/dist/core/ingestion/import-processor.js +199 -579
  53. package/dist/core/ingestion/language-config.d.ts +46 -0
  54. package/dist/core/ingestion/language-config.js +167 -0
  55. package/dist/core/ingestion/mro-processor.d.ts +45 -0
  56. package/dist/core/ingestion/mro-processor.js +369 -0
  57. package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
  58. package/dist/core/ingestion/named-binding-extraction.js +363 -0
  59. package/dist/core/ingestion/parsing-processor.d.ts +4 -1
  60. package/dist/core/ingestion/parsing-processor.js +107 -109
  61. package/dist/core/ingestion/pipeline.d.ts +6 -3
  62. package/dist/core/ingestion/pipeline.js +208 -114
  63. package/dist/core/ingestion/process-processor.js +8 -2
  64. package/dist/core/ingestion/resolution-context.d.ts +53 -0
  65. package/dist/core/ingestion/resolution-context.js +132 -0
  66. package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
  67. package/dist/core/ingestion/resolvers/csharp.js +109 -0
  68. package/dist/core/ingestion/resolvers/go.d.ts +19 -0
  69. package/dist/core/ingestion/resolvers/go.js +42 -0
  70. package/dist/core/ingestion/resolvers/index.d.ts +18 -0
  71. package/dist/core/ingestion/resolvers/index.js +13 -0
  72. package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
  73. package/dist/core/ingestion/resolvers/jvm.js +87 -0
  74. package/dist/core/ingestion/resolvers/php.d.ts +15 -0
  75. package/dist/core/ingestion/resolvers/php.js +35 -0
  76. package/dist/core/ingestion/resolvers/python.d.ts +19 -0
  77. package/dist/core/ingestion/resolvers/python.js +52 -0
  78. package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
  79. package/dist/core/ingestion/resolvers/ruby.js +15 -0
  80. package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
  81. package/dist/core/ingestion/resolvers/rust.js +73 -0
  82. package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
  83. package/dist/core/ingestion/resolvers/standard.js +123 -0
  84. package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
  85. package/dist/core/ingestion/resolvers/utils.js +122 -0
  86. package/dist/core/ingestion/symbol-table.d.ts +21 -1
  87. package/dist/core/ingestion/symbol-table.js +40 -12
  88. package/dist/core/ingestion/tree-sitter-queries.d.ts +13 -10
  89. package/dist/core/ingestion/tree-sitter-queries.js +297 -7
  90. package/dist/core/ingestion/type-env.d.ts +49 -0
  91. package/dist/core/ingestion/type-env.js +611 -0
  92. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
  93. package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
  94. package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
  95. package/dist/core/ingestion/type-extractors/csharp.js +383 -0
  96. package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
  97. package/dist/core/ingestion/type-extractors/go.js +467 -0
  98. package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
  99. package/dist/core/ingestion/type-extractors/index.js +31 -0
  100. package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
  101. package/dist/core/ingestion/type-extractors/jvm.js +681 -0
  102. package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
  103. package/dist/core/ingestion/type-extractors/php.js +549 -0
  104. package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
  105. package/dist/core/ingestion/type-extractors/python.js +406 -0
  106. package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
  107. package/dist/core/ingestion/type-extractors/ruby.js +389 -0
  108. package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
  109. package/dist/core/ingestion/type-extractors/rust.js +449 -0
  110. package/dist/core/ingestion/type-extractors/shared.d.ts +133 -0
  111. package/dist/core/ingestion/type-extractors/shared.js +703 -0
  112. package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
  113. package/dist/core/ingestion/type-extractors/swift.js +137 -0
  114. package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
  115. package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
  116. package/dist/core/ingestion/type-extractors/typescript.js +494 -0
  117. package/dist/core/ingestion/utils.d.ts +103 -0
  118. package/dist/core/ingestion/utils.js +1085 -4
  119. package/dist/core/ingestion/workers/parse-worker.d.ts +51 -4
  120. package/dist/core/ingestion/workers/parse-worker.js +634 -222
  121. package/dist/core/ingestion/workers/worker-pool.js +8 -0
  122. package/dist/core/{kuzu → lbug}/csv-generator.d.ts +12 -10
  123. package/dist/core/{kuzu → lbug}/csv-generator.js +82 -101
  124. package/dist/core/{kuzu/kuzu-adapter.d.ts → lbug/lbug-adapter.d.ts} +20 -25
  125. package/dist/core/{kuzu/kuzu-adapter.js → lbug/lbug-adapter.js} +150 -122
  126. package/dist/core/{kuzu → lbug}/schema.d.ts +4 -4
  127. package/dist/core/{kuzu → lbug}/schema.js +23 -22
  128. package/dist/core/lbug/schema.test.d.ts +1 -0
  129. package/dist/core/search/bm25-index.d.ts +4 -4
  130. package/dist/core/search/bm25-index.js +12 -11
  131. package/dist/core/search/hybrid-search.d.ts +2 -2
  132. package/dist/core/search/hybrid-search.js +6 -6
  133. package/dist/core/tree-sitter/parser-loader.d.ts +1 -0
  134. package/dist/core/tree-sitter/parser-loader.js +19 -0
  135. package/dist/core/wiki/generator.d.ts +2 -2
  136. package/dist/core/wiki/generator.js +6 -6
  137. package/dist/core/wiki/graph-queries.d.ts +4 -4
  138. package/dist/core/wiki/graph-queries.js +7 -7
  139. package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
  140. package/dist/mcp/compatible-stdio-transport.js +200 -0
  141. package/dist/mcp/core/{kuzu-adapter.d.ts → lbug-adapter.d.ts} +11 -10
  142. package/dist/mcp/core/lbug-adapter.js +327 -0
  143. package/dist/mcp/local/local-backend.d.ts +21 -16
  144. package/dist/mcp/local/local-backend.js +306 -706
  145. package/dist/mcp/local/unity-parity-seed-loader.d.ts +6 -1
  146. package/dist/mcp/local/unity-parity-seed-loader.js +119 -9
  147. package/dist/mcp/local/unity-parity-seed-loader.test.js +95 -7
  148. package/dist/mcp/resources.js +2 -2
  149. package/dist/mcp/server.js +28 -13
  150. package/dist/mcp/staleness.js +2 -2
  151. package/dist/mcp/tools.js +12 -3
  152. package/dist/server/api.js +12 -12
  153. package/dist/server/mcp-http.d.ts +1 -1
  154. package/dist/server/mcp-http.js +1 -1
  155. package/dist/storage/git.js +4 -1
  156. package/dist/storage/repo-manager.d.ts +20 -2
  157. package/dist/storage/repo-manager.js +74 -4
  158. package/dist/types/pipeline.d.ts +1 -1
  159. package/hooks/claude/gitnexus-hook.cjs +149 -46
  160. package/hooks/claude/pre-tool-use.sh +2 -1
  161. package/hooks/claude/session-start.sh +0 -0
  162. package/package.json +20 -4
  163. package/scripts/patch-tree-sitter-swift.cjs +74 -0
  164. package/skills/gitnexus-cli.md +8 -8
  165. package/skills/gitnexus-debugging.md +1 -1
  166. package/skills/gitnexus-exploring.md +1 -1
  167. package/skills/gitnexus-guide.md +1 -1
  168. package/skills/gitnexus-impact-analysis.md +1 -1
  169. package/skills/gitnexus-pr-review.md +163 -0
  170. package/skills/gitnexus-refactoring.md +1 -1
  171. package/dist/cli/claude-hooks.d.ts +0 -22
  172. package/dist/cli/claude-hooks.js +0 -97
  173. package/dist/mcp/core/kuzu-adapter.js +0 -231
  174. /package/dist/core/{kuzu/csv-generator.test.d.ts → ingestion/type-extractors/types.js} +0 -0
  175. /package/dist/core/{kuzu/relationship-pair-buckets.test.d.ts → lbug/csv-generator.test.d.ts} +0 -0
  176. /package/dist/core/{kuzu → lbug}/csv-generator.test.js +0 -0
  177. /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.d.ts +0 -0
  178. /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.js +0 -0
  179. /package/dist/core/{kuzu/schema.test.d.ts → lbug/relationship-pair-buckets.test.d.ts} +0 -0
  180. /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.test.js +0 -0
  181. /package/dist/core/{kuzu → lbug}/schema.test.js +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * KuzuDB Schema Definitions
2
+ * LadybugDB Schema Definitions
3
3
  *
4
4
  * Hybrid Schema:
5
5
  * - Separate node tables for each code element type (File, Function, Class, etc.)
@@ -22,20 +22,7 @@ export const NODE_TABLES = [
22
22
  // ============================================================================
23
23
  export const REL_TABLE_NAME = 'CodeRelation';
24
24
  // Valid relation types
25
- export const REL_TYPES = [
26
- 'CONTAINS',
27
- 'DEFINES',
28
- 'IMPORTS',
29
- 'CALLS',
30
- 'EXTENDS',
31
- 'IMPLEMENTS',
32
- 'MEMBER_OF',
33
- 'STEP_IN_PROCESS',
34
- 'UNITY_COMPONENT_IN',
35
- 'UNITY_COMPONENT_INSTANCE',
36
- 'UNITY_RESOURCE_SUMMARY',
37
- 'UNITY_SERIALIZED_TYPE_IN',
38
- ];
25
+ export const REL_TYPES = ['CONTAINS', 'DEFINES', 'IMPORTS', 'CALLS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'OVERRIDES', 'MEMBER_OF', 'STEP_IN_PROCESS'];
39
26
  // ============================================================================
40
27
  // EMBEDDING TABLE
41
28
  // ============================================================================
@@ -104,6 +91,8 @@ CREATE NODE TABLE Method (
104
91
  isExported BOOLEAN,
105
92
  content STRING,
106
93
  description STRING,
94
+ parameterCount INT32,
95
+ returnType STRING,
107
96
  PRIMARY KEY (id)
108
97
  )`;
109
98
  export const CODE_ELEMENT_SCHEMA = `
@@ -229,15 +218,13 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
229
218
  FROM Function TO \`Impl\`,
230
219
  FROM Function TO Interface,
231
220
  FROM Function TO \`Constructor\`,
232
- FROM Function TO \`Property\`,
233
221
  FROM Function TO \`Const\`,
234
222
  FROM Function TO \`Typedef\`,
235
223
  FROM Function TO \`Union\`,
224
+ FROM Function TO \`Property\`,
236
225
  FROM Class TO Method,
237
226
  FROM Class TO Function,
238
227
  FROM Class TO Class,
239
- FROM Class TO File,
240
- FROM Class TO CodeElement,
241
228
  FROM Class TO Interface,
242
229
  FROM Class TO Community,
243
230
  FROM Class TO \`Template\`,
@@ -253,7 +240,6 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
253
240
  FROM Class TO \`Namespace\`,
254
241
  FROM Class TO \`Typedef\`,
255
242
  FROM Class TO \`Property\`,
256
- FROM Class TO \`Delegate\`,
257
243
  FROM Method TO Function,
258
244
  FROM Method TO Method,
259
245
  FROM Method TO Class,
@@ -269,7 +255,6 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
269
255
  FROM Method TO Interface,
270
256
  FROM Method TO \`Constructor\`,
271
257
  FROM Method TO \`Property\`,
272
- FROM Method TO \`Delegate\`,
273
258
  FROM \`Template\` TO \`Template\`,
274
259
  FROM \`Template\` TO Function,
275
260
  FROM \`Template\` TO Method,
@@ -290,6 +275,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
290
275
  FROM Interface TO \`TypeAlias\`,
291
276
  FROM Interface TO \`Struct\`,
292
277
  FROM Interface TO \`Constructor\`,
278
+ FROM Interface TO \`Property\`,
293
279
  FROM \`Struct\` TO Community,
294
280
  FROM \`Struct\` TO \`Trait\`,
295
281
  FROM \`Struct\` TO \`Struct\`,
@@ -297,7 +283,13 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
297
283
  FROM \`Struct\` TO \`Enum\`,
298
284
  FROM \`Struct\` TO Function,
299
285
  FROM \`Struct\` TO Method,
286
+ FROM \`Struct\` TO Interface,
287
+ FROM \`Struct\` TO \`Constructor\`,
288
+ FROM \`Struct\` TO \`Property\`,
289
+ FROM \`Enum\` TO \`Enum\`,
300
290
  FROM \`Enum\` TO Community,
291
+ FROM \`Enum\` TO Class,
292
+ FROM \`Enum\` TO Interface,
301
293
  FROM \`Macro\` TO Community,
302
294
  FROM \`Macro\` TO Function,
303
295
  FROM \`Macro\` TO Method,
@@ -307,18 +299,26 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
307
299
  FROM \`Union\` TO Community,
308
300
  FROM \`Namespace\` TO Community,
309
301
  FROM \`Namespace\` TO \`Struct\`,
302
+ FROM \`Trait\` TO Method,
303
+ FROM \`Trait\` TO \`Constructor\`,
304
+ FROM \`Trait\` TO \`Property\`,
310
305
  FROM \`Trait\` TO Community,
306
+ FROM \`Impl\` TO Method,
307
+ FROM \`Impl\` TO \`Constructor\`,
308
+ FROM \`Impl\` TO \`Property\`,
311
309
  FROM \`Impl\` TO Community,
312
310
  FROM \`Impl\` TO \`Trait\`,
313
311
  FROM \`Impl\` TO \`Struct\`,
314
312
  FROM \`Impl\` TO \`Impl\`,
315
313
  FROM \`TypeAlias\` TO Community,
316
314
  FROM \`TypeAlias\` TO \`Trait\`,
315
+ FROM \`TypeAlias\` TO Class,
317
316
  FROM \`Const\` TO Community,
318
317
  FROM \`Static\` TO Community,
319
318
  FROM \`Property\` TO Community,
320
- FROM \`Property\` TO Class,
321
- FROM \`Property\` TO Interface,
319
+ FROM \`Record\` TO Method,
320
+ FROM \`Record\` TO \`Constructor\`,
321
+ FROM \`Record\` TO \`Property\`,
322
322
  FROM \`Record\` TO Community,
323
323
  FROM \`Delegate\` TO Community,
324
324
  FROM \`Annotation\` TO Community,
@@ -338,6 +338,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
338
338
  FROM \`Constructor\` TO \`Namespace\`,
339
339
  FROM \`Constructor\` TO \`Module\`,
340
340
  FROM \`Constructor\` TO \`Property\`,
341
+ FROM \`Constructor\` TO \`Typedef\`,
341
342
  FROM \`Template\` TO Community,
342
343
  FROM \`Module\` TO Community,
343
344
  FROM Function TO Process,
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Full-Text Search via KuzuDB FTS
2
+ * Full-Text Search via LadybugDB FTS
3
3
  *
4
- * Uses KuzuDB's built-in full-text search indexes for keyword-based search.
4
+ * Uses LadybugDB's built-in full-text search indexes for keyword-based search.
5
5
  * Always reads from the database (no cached state to drift).
6
6
  */
7
7
  export interface BM25SearchResult {
@@ -10,7 +10,7 @@ export interface BM25SearchResult {
10
10
  rank: number;
11
11
  }
12
12
  /**
13
- * Search using KuzuDB's built-in FTS (always fresh, reads from disk)
13
+ * Search using LadybugDB's built-in FTS (always fresh, reads from disk)
14
14
  *
15
15
  * Queries multiple node tables (File, Function, Class, Method) in parallel
16
16
  * and merges results by filePath, summing scores for the same file.
@@ -20,4 +20,4 @@ export interface BM25SearchResult {
20
20
  * @param repoId - If provided, queries will be routed via the MCP connection pool
21
21
  * @returns Ranked search results from FTS indexes
22
22
  */
23
- export declare const searchFTSFromKuzu: (query: string, limit?: number, repoId?: string) => Promise<BM25SearchResult[]>;
23
+ export declare const searchFTSFromLbug: (query: string, limit?: number, repoId?: string) => Promise<BM25SearchResult[]>;
@@ -1,16 +1,17 @@
1
1
  /**
2
- * Full-Text Search via KuzuDB FTS
2
+ * Full-Text Search via LadybugDB FTS
3
3
  *
4
- * Uses KuzuDB's built-in full-text search indexes for keyword-based search.
4
+ * Uses LadybugDB's built-in full-text search indexes for keyword-based search.
5
5
  * Always reads from the database (no cached state to drift).
6
6
  */
7
- import { queryFTS } from '../kuzu/kuzu-adapter.js';
7
+ import { queryFTS } from '../lbug/lbug-adapter.js';
8
8
  /**
9
9
  * Execute a single FTS query via a custom executor (for MCP connection pool).
10
- * Returns the same shape as core queryFTS.
10
+ * Returns the same shape as core queryFTS (from LadybugDB adapter).
11
11
  */
12
12
  async function queryFTSViaExecutor(executor, tableName, indexName, query, limit) {
13
- const escapedQuery = query.replace(/'/g, "''");
13
+ // Escape single quotes and backslashes to prevent Cypher injection
14
+ const escapedQuery = query.replace(/\\/g, '\\\\').replace(/'/g, "''");
14
15
  const cypher = `
15
16
  CALL QUERY_FTS_INDEX('${tableName}', '${indexName}', '${escapedQuery}', conjunctive := false)
16
17
  RETURN node, score
@@ -33,7 +34,7 @@ async function queryFTSViaExecutor(executor, tableName, indexName, query, limit)
33
34
  }
34
35
  }
35
36
  /**
36
- * Search using KuzuDB's built-in FTS (always fresh, reads from disk)
37
+ * Search using LadybugDB's built-in FTS (always fresh, reads from disk)
37
38
  *
38
39
  * Queries multiple node tables (File, Function, Class, Method) in parallel
39
40
  * and merges results by filePath, summing scores for the same file.
@@ -43,13 +44,13 @@ async function queryFTSViaExecutor(executor, tableName, indexName, query, limit)
43
44
  * @param repoId - If provided, queries will be routed via the MCP connection pool
44
45
  * @returns Ranked search results from FTS indexes
45
46
  */
46
- export const searchFTSFromKuzu = async (query, limit = 20, repoId) => {
47
+ export const searchFTSFromLbug = async (query, limit = 20, repoId) => {
47
48
  let fileResults, functionResults, classResults, methodResults, interfaceResults;
48
49
  if (repoId) {
49
50
  // Use MCP connection pool via dynamic import
50
- // IMPORTANT: KuzuDB uses a single connection per repo — queries must be sequential
51
- // to avoid deadlocking. Do NOT use Promise.all here.
52
- const { executeQuery } = await import('../../mcp/core/kuzu-adapter.js');
51
+ // IMPORTANT: FTS queries run sequentially to avoid connection contention.
52
+ // The MCP pool supports multiple connections, but FTS is best run serially.
53
+ const { executeQuery } = await import('../../mcp/core/lbug-adapter.js');
53
54
  const executor = (cypher) => executeQuery(repoId, cypher);
54
55
  fileResults = await queryFTSViaExecutor(executor, 'File', 'file_fts', query, limit);
55
56
  functionResults = await queryFTSViaExecutor(executor, 'Function', 'function_fts', query, limit);
@@ -58,7 +59,7 @@ export const searchFTSFromKuzu = async (query, limit = 20, repoId) => {
58
59
  interfaceResults = await queryFTSViaExecutor(executor, 'Interface', 'interface_fts', query, limit);
59
60
  }
60
61
  else {
61
- // Use core kuzu adapter (CLI / pipeline context) — also sequential for safety
62
+ // Use core lbug adapter (CLI / pipeline context) — also sequential for safety
62
63
  fileResults = await queryFTS('File', 'file_fts', query, limit, false).catch(() => []);
63
64
  functionResults = await queryFTS('Function', 'function_fts', query, limit, false).catch(() => []);
64
65
  classResults = await queryFTS('Class', 'class_fts', query, limit, false).catch(() => []);
@@ -33,7 +33,7 @@ export interface HybridSearchResult {
33
33
  export declare const mergeWithRRF: (bm25Results: BM25SearchResult[], semanticResults: SemanticSearchResult[], limit?: number) => HybridSearchResult[];
34
34
  /**
35
35
  * Check if hybrid search is available
36
- * KuzuDB FTS is always available once the database is initialized.
36
+ * LadybugDB FTS is always available once the database is initialized.
37
37
  * Semantic search is optional - hybrid works with just FTS if embeddings aren't ready.
38
38
  */
39
39
  export declare const isHybridSearchReady: () => boolean;
@@ -43,7 +43,7 @@ export declare const isHybridSearchReady: () => boolean;
43
43
  export declare const formatHybridResults: (results: HybridSearchResult[]) => string;
44
44
  /**
45
45
  * Execute BM25 + semantic search and merge with RRF.
46
- * Uses KuzuDB FTS for always-fresh BM25 results (no cached data).
46
+ * Uses LadybugDB FTS for always-fresh BM25 results (no cached data).
47
47
  * The semanticSearch function is injected to keep this module environment-agnostic.
48
48
  */
49
49
  export declare const hybridSearch: (query: string, limit: number, executeQuery: (cypher: string) => Promise<any[]>, semanticSearch: (executeQuery: (cypher: string) => Promise<any[]>, query: string, k?: number) => Promise<SemanticSearchResult[]>) => Promise<HybridSearchResult[]>;
@@ -7,7 +7,7 @@
7
7
  * This is the same approach used by Elasticsearch, Pinecone, and other
8
8
  * production search systems.
9
9
  */
10
- import { searchFTSFromKuzu } from './bm25-index.js';
10
+ import { searchFTSFromLbug } from './bm25-index.js';
11
11
  /**
12
12
  * RRF constant - standard value used in the literature
13
13
  * Higher values give more weight to lower-ranked results
@@ -80,11 +80,11 @@ export const mergeWithRRF = (bm25Results, semanticResults, limit = 10) => {
80
80
  };
81
81
  /**
82
82
  * Check if hybrid search is available
83
- * KuzuDB FTS is always available once the database is initialized.
83
+ * LadybugDB FTS is always available once the database is initialized.
84
84
  * Semantic search is optional - hybrid works with just FTS if embeddings aren't ready.
85
85
  */
86
86
  export const isHybridSearchReady = () => {
87
- return true; // FTS is always available via KuzuDB when DB is open
87
+ return true; // FTS is always available via LadybugDB when DB is open
88
88
  };
89
89
  /**
90
90
  * Format hybrid results for LLM consumption
@@ -107,12 +107,12 @@ export const formatHybridResults = (results) => {
107
107
  };
108
108
  /**
109
109
  * Execute BM25 + semantic search and merge with RRF.
110
- * Uses KuzuDB FTS for always-fresh BM25 results (no cached data).
110
+ * Uses LadybugDB FTS for always-fresh BM25 results (no cached data).
111
111
  * The semanticSearch function is injected to keep this module environment-agnostic.
112
112
  */
113
113
  export const hybridSearch = async (query, limit, executeQuery, semanticSearch) => {
114
- // Use KuzuDB FTS for always-fresh BM25 results
115
- const bm25Results = await searchFTSFromKuzu(query, limit);
114
+ // Use LadybugDB FTS for always-fresh BM25 results
115
+ const bm25Results = await searchFTSFromLbug(query, limit);
116
116
  const semanticResults = await semanticSearch(executeQuery, query, limit);
117
117
  return mergeWithRRF(bm25Results, semanticResults, limit);
118
118
  };
@@ -1,4 +1,5 @@
1
1
  import Parser from 'tree-sitter';
2
2
  import { SupportedLanguages } from '../../config/supported-languages.js';
3
+ export declare const isLanguageAvailable: (language: SupportedLanguages) => boolean;
3
4
  export declare const loadParser: () => Promise<Parser>;
4
5
  export declare const loadLanguage: (language: SupportedLanguages, filePath?: string) => Promise<void>;
@@ -9,7 +9,22 @@ import CSharp from 'tree-sitter-c-sharp';
9
9
  import Go from 'tree-sitter-go';
10
10
  import Rust from 'tree-sitter-rust';
11
11
  import PHP from 'tree-sitter-php';
12
+ import Ruby from 'tree-sitter-ruby';
13
+ import { createRequire } from 'node:module';
12
14
  import { SupportedLanguages } from '../../config/supported-languages.js';
15
+ // tree-sitter-swift is an optionalDependency — may not be installed
16
+ const _require = createRequire(import.meta.url);
17
+ let Swift = null;
18
+ try {
19
+ Swift = _require('tree-sitter-swift');
20
+ }
21
+ catch { }
22
+ // tree-sitter-kotlin is an optionalDependency — may not be installed
23
+ let Kotlin = null;
24
+ try {
25
+ Kotlin = _require('tree-sitter-kotlin');
26
+ }
27
+ catch { }
13
28
  let parser = null;
14
29
  const languageMap = {
15
30
  [SupportedLanguages.JavaScript]: JavaScript,
@@ -22,8 +37,12 @@ const languageMap = {
22
37
  [SupportedLanguages.CSharp]: CSharp,
23
38
  [SupportedLanguages.Go]: Go,
24
39
  [SupportedLanguages.Rust]: Rust,
40
+ ...(Kotlin ? { [SupportedLanguages.Kotlin]: Kotlin } : {}),
25
41
  [SupportedLanguages.PHP]: PHP.php_only,
42
+ [SupportedLanguages.Ruby]: Ruby,
43
+ ...(Swift ? { [SupportedLanguages.Swift]: Swift } : {}),
26
44
  };
45
+ export const isLanguageAvailable = (language) => language in languageMap;
27
46
  export const loadParser = async () => {
28
47
  if (parser)
29
48
  return parser;
@@ -36,14 +36,14 @@ export declare class WikiGenerator {
36
36
  private repoPath;
37
37
  private storagePath;
38
38
  private wikiDir;
39
- private kuzuPath;
39
+ private lbugPath;
40
40
  private llmConfig;
41
41
  private maxTokensPerModule;
42
42
  private concurrency;
43
43
  private options;
44
44
  private onProgress;
45
45
  private failedModules;
46
- constructor(repoPath: string, storagePath: string, kuzuPath: string, llmConfig: LLMConfig, options?: WikiOptions, onProgress?: ProgressCallback);
46
+ constructor(repoPath: string, storagePath: string, lbugPath: string, llmConfig: LLMConfig, options?: WikiOptions, onProgress?: ProgressCallback);
47
47
  private lastPercent;
48
48
  /**
49
49
  * Create streaming options that report LLM progress to the progress bar.
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import fs from 'fs/promises';
13
13
  import path from 'path';
14
- import { execSync } from 'child_process';
14
+ import { execSync, execFileSync } from 'child_process';
15
15
  import { initWikiDb, closeWikiDb, getFilesWithExports, getAllFiles, getIntraModuleCallEdges, getInterModuleCallEdges, getProcessesForFiles, getAllProcesses, getInterModuleEdgesForOverview, } from './graph-queries.js';
16
16
  import { generateHTMLViewer } from './html-viewer.js';
17
17
  import { callLLM, estimateTokens, } from './llm-client.js';
@@ -25,18 +25,18 @@ export class WikiGenerator {
25
25
  repoPath;
26
26
  storagePath;
27
27
  wikiDir;
28
- kuzuPath;
28
+ lbugPath;
29
29
  llmConfig;
30
30
  maxTokensPerModule;
31
31
  concurrency;
32
32
  options;
33
33
  onProgress;
34
34
  failedModules = [];
35
- constructor(repoPath, storagePath, kuzuPath, llmConfig, options = {}, onProgress) {
35
+ constructor(repoPath, storagePath, lbugPath, llmConfig, options = {}, onProgress) {
36
36
  this.repoPath = repoPath;
37
37
  this.storagePath = storagePath;
38
38
  this.wikiDir = path.join(storagePath, WIKI_DIR);
39
- this.kuzuPath = kuzuPath;
39
+ this.lbugPath = lbugPath;
40
40
  this.options = options;
41
41
  this.llmConfig = llmConfig;
42
42
  this.maxTokensPerModule = options.maxTokensPerModule ?? DEFAULT_MAX_TOKENS_PER_MODULE;
@@ -95,7 +95,7 @@ export class WikiGenerator {
95
95
  }
96
96
  // Init graph
97
97
  this.onProgress('init', 2, 'Connecting to knowledge graph...');
98
- await initWikiDb(this.kuzuPath);
98
+ await initWikiDb(this.lbugPath);
99
99
  let result;
100
100
  try {
101
101
  if (!forceMode && existingMeta && existingMeta.fromCommit) {
@@ -561,7 +561,7 @@ export class WikiGenerator {
561
561
  }
562
562
  getChangedFiles(fromCommit, toCommit) {
563
563
  try {
564
- const output = execSync(`git diff ${fromCommit}..${toCommit} --name-only`, { cwd: this.repoPath }).toString().trim();
564
+ const output = execFileSync('git', ['diff', `${fromCommit}..${toCommit}`, '--name-only'], { cwd: this.repoPath }).toString().trim();
565
565
  return output ? output.split('\n').filter(Boolean) : [];
566
566
  }
567
567
  catch {
@@ -2,7 +2,7 @@
2
2
  * Graph Queries for Wiki Generation
3
3
  *
4
4
  * Encapsulated Cypher queries against the GitNexus knowledge graph.
5
- * Uses the MCP-style pooled kuzu-adapter for connection management.
5
+ * Uses the MCP-style pooled lbug-adapter for connection management.
6
6
  */
7
7
  export interface FileWithExports {
8
8
  filePath: string;
@@ -30,11 +30,11 @@ export interface ProcessInfo {
30
30
  }>;
31
31
  }
32
32
  /**
33
- * Initialize the KuzuDB connection for wiki generation.
33
+ * Initialize the LadybugDB connection for wiki generation.
34
34
  */
35
- export declare function initWikiDb(kuzuPath: string): Promise<void>;
35
+ export declare function initWikiDb(lbugPath: string): Promise<void>;
36
36
  /**
37
- * Close the KuzuDB connection.
37
+ * Close the LadybugDB connection.
38
38
  */
39
39
  export declare function closeWikiDb(): Promise<void>;
40
40
  /**
@@ -2,21 +2,21 @@
2
2
  * Graph Queries for Wiki Generation
3
3
  *
4
4
  * Encapsulated Cypher queries against the GitNexus knowledge graph.
5
- * Uses the MCP-style pooled kuzu-adapter for connection management.
5
+ * Uses the MCP-style pooled lbug-adapter for connection management.
6
6
  */
7
- import { initKuzu, executeQuery, closeKuzu } from '../../mcp/core/kuzu-adapter.js';
7
+ import { initLbug, executeQuery, closeLbug } from '../../mcp/core/lbug-adapter.js';
8
8
  const REPO_ID = '__wiki__';
9
9
  /**
10
- * Initialize the KuzuDB connection for wiki generation.
10
+ * Initialize the LadybugDB connection for wiki generation.
11
11
  */
12
- export async function initWikiDb(kuzuPath) {
13
- await initKuzu(REPO_ID, kuzuPath);
12
+ export async function initWikiDb(lbugPath) {
13
+ await initLbug(REPO_ID, lbugPath);
14
14
  }
15
15
  /**
16
- * Close the KuzuDB connection.
16
+ * Close the LadybugDB connection.
17
17
  */
18
18
  export async function closeWikiDb() {
19
- await closeKuzu(REPO_ID);
19
+ await closeLbug(REPO_ID);
20
20
  }
21
21
  /**
22
22
  * Get all source files with their exported symbol names and types.
@@ -0,0 +1,25 @@
1
+ import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
2
+ import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
3
+ export type StdioFraming = 'content-length' | 'newline';
4
+ export declare class CompatibleStdioServerTransport implements Transport {
5
+ private readonly _stdin;
6
+ private readonly _stdout;
7
+ private _readBuffer;
8
+ private _started;
9
+ private _framing;
10
+ onmessage?: (message: JSONRPCMessage) => void;
11
+ onerror?: (error: Error) => void;
12
+ onclose?: () => void;
13
+ constructor(_stdin?: NodeJS.ReadableStream, _stdout?: NodeJS.WritableStream);
14
+ private readonly _ondata;
15
+ private readonly _onerror;
16
+ start(): Promise<void>;
17
+ private detectFraming;
18
+ private discardBufferedInput;
19
+ private readContentLengthMessage;
20
+ private readNewlineMessage;
21
+ private readMessage;
22
+ private processReadBuffer;
23
+ close(): Promise<void>;
24
+ send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void>;
25
+ }
@@ -0,0 +1,200 @@
1
+ import process from 'node:process';
2
+ import { JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
3
+ function deserializeMessage(raw) {
4
+ return JSONRPCMessageSchema.parse(JSON.parse(raw));
5
+ }
6
+ function serializeNewlineMessage(message) {
7
+ return `${JSON.stringify(message)}\n`;
8
+ }
9
+ function serializeContentLengthMessage(message) {
10
+ const body = JSON.stringify(message);
11
+ return `Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`;
12
+ }
13
+ function findHeaderEnd(buffer) {
14
+ const crlfEnd = buffer.indexOf('\r\n\r\n');
15
+ if (crlfEnd !== -1) {
16
+ return { index: crlfEnd, separatorLength: 4 };
17
+ }
18
+ const lfEnd = buffer.indexOf('\n\n');
19
+ if (lfEnd !== -1) {
20
+ return { index: lfEnd, separatorLength: 2 };
21
+ }
22
+ return null;
23
+ }
24
+ function looksLikeContentLength(buffer) {
25
+ if (buffer.length < 14) {
26
+ return false;
27
+ }
28
+ const probe = buffer.toString('utf8', 0, Math.min(buffer.length, 32));
29
+ return /^content-length\s*:/i.test(probe);
30
+ }
31
+ const MAX_BUFFER_SIZE = 10 * 1024 * 1024; // 10 MB — generous for JSON-RPC
32
+ export class CompatibleStdioServerTransport {
33
+ _stdin;
34
+ _stdout;
35
+ _readBuffer;
36
+ _started = false;
37
+ _framing = null;
38
+ onmessage;
39
+ onerror;
40
+ onclose;
41
+ constructor(_stdin = process.stdin, _stdout = process.stdout) {
42
+ this._stdin = _stdin;
43
+ this._stdout = _stdout;
44
+ }
45
+ _ondata = (chunk) => {
46
+ this._readBuffer = this._readBuffer ? Buffer.concat([this._readBuffer, chunk]) : chunk;
47
+ if (this._readBuffer.length > MAX_BUFFER_SIZE) {
48
+ this.onerror?.(new Error(`Read buffer exceeded maximum size (${MAX_BUFFER_SIZE} bytes)`));
49
+ this.discardBufferedInput();
50
+ return;
51
+ }
52
+ this.processReadBuffer();
53
+ };
54
+ _onerror = (error) => {
55
+ this.onerror?.(error);
56
+ };
57
+ async start() {
58
+ if (this._started) {
59
+ throw new Error('CompatibleStdioServerTransport already started!');
60
+ }
61
+ this._started = true;
62
+ this._stdin.on('data', this._ondata);
63
+ this._stdin.on('error', this._onerror);
64
+ }
65
+ detectFraming() {
66
+ if (!this._readBuffer || this._readBuffer.length === 0) {
67
+ return null;
68
+ }
69
+ const firstByte = this._readBuffer[0];
70
+ if (firstByte === 0x7b || firstByte === 0x5b) {
71
+ return 'newline';
72
+ }
73
+ if (looksLikeContentLength(this._readBuffer)) {
74
+ return 'content-length';
75
+ }
76
+ return null;
77
+ }
78
+ discardBufferedInput() {
79
+ this._readBuffer = undefined;
80
+ this._framing = null;
81
+ }
82
+ readContentLengthMessage() {
83
+ if (!this._readBuffer) {
84
+ return null;
85
+ }
86
+ const header = findHeaderEnd(this._readBuffer);
87
+ if (header === null) {
88
+ return null;
89
+ }
90
+ const headerText = this._readBuffer
91
+ .toString('utf8', 0, header.index)
92
+ .replace(/\r\n/g, '\n')
93
+ .replace(/\r/g, '\n');
94
+ const match = headerText.match(/(?:^|\n)content-length\s*:\s*(\d+)/i);
95
+ if (!match) {
96
+ this.discardBufferedInput();
97
+ throw new Error('Missing Content-Length header from MCP client');
98
+ }
99
+ const contentLength = Number.parseInt(match[1], 10);
100
+ if (!Number.isFinite(contentLength) || contentLength < 0) {
101
+ this.discardBufferedInput();
102
+ throw new Error('Invalid Content-Length header from MCP client');
103
+ }
104
+ if (contentLength > MAX_BUFFER_SIZE) {
105
+ this.discardBufferedInput();
106
+ throw new Error(`Content-Length ${contentLength} exceeds maximum allowed size (${MAX_BUFFER_SIZE} bytes)`);
107
+ }
108
+ const bodyStart = header.index + header.separatorLength;
109
+ const bodyEnd = bodyStart + contentLength;
110
+ if (this._readBuffer.length < bodyEnd) {
111
+ return null;
112
+ }
113
+ const body = this._readBuffer.toString('utf8', bodyStart, bodyEnd);
114
+ this._readBuffer = this._readBuffer.subarray(bodyEnd);
115
+ return deserializeMessage(body);
116
+ }
117
+ readNewlineMessage() {
118
+ if (!this._readBuffer) {
119
+ return null;
120
+ }
121
+ while (true) {
122
+ const newlineIndex = this._readBuffer.indexOf('\n');
123
+ if (newlineIndex === -1) {
124
+ return null;
125
+ }
126
+ const line = this._readBuffer.toString('utf8', 0, newlineIndex).replace(/\r$/, '');
127
+ this._readBuffer = this._readBuffer.subarray(newlineIndex + 1);
128
+ if (line.trim().length === 0) {
129
+ continue;
130
+ }
131
+ return deserializeMessage(line);
132
+ }
133
+ }
134
+ readMessage() {
135
+ if (!this._readBuffer || this._readBuffer.length === 0) {
136
+ return null;
137
+ }
138
+ if (this._framing === null) {
139
+ this._framing = this.detectFraming();
140
+ if (this._framing === null) {
141
+ return null;
142
+ }
143
+ }
144
+ return this._framing === 'content-length'
145
+ ? this.readContentLengthMessage()
146
+ : this.readNewlineMessage();
147
+ }
148
+ processReadBuffer() {
149
+ while (true) {
150
+ try {
151
+ const message = this.readMessage();
152
+ if (message === null) {
153
+ break;
154
+ }
155
+ this.onmessage?.(message);
156
+ }
157
+ catch (error) {
158
+ this.onerror?.(error);
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ async close() {
164
+ this._stdin.off('data', this._ondata);
165
+ this._stdin.off('error', this._onerror);
166
+ const remainingDataListeners = this._stdin.listenerCount('data');
167
+ if (remainingDataListeners === 0) {
168
+ this._stdin.pause();
169
+ }
170
+ this._started = false;
171
+ this._readBuffer = undefined;
172
+ this.onclose?.();
173
+ }
174
+ send(message, _options) {
175
+ return new Promise((resolve, reject) => {
176
+ if (!this._started) {
177
+ reject(new Error('Transport is closed'));
178
+ return;
179
+ }
180
+ const payload = this._framing === 'newline'
181
+ ? serializeNewlineMessage(message)
182
+ : serializeContentLengthMessage(message);
183
+ const onError = (error) => {
184
+ this._stdout.removeListener('error', onError);
185
+ reject(error);
186
+ };
187
+ this._stdout.on('error', onError);
188
+ if (this._stdout.write(payload)) {
189
+ this._stdout.removeListener('error', onError);
190
+ resolve();
191
+ }
192
+ else {
193
+ this._stdout.once('drain', () => {
194
+ this._stdout.removeListener('error', onError);
195
+ resolve();
196
+ });
197
+ }
198
+ });
199
+ }
200
+ }