gitnexus 1.2.9 → 1.3.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.
@@ -1,8 +1,10 @@
1
1
  import fs from 'fs/promises';
2
+ import { createReadStream } from 'fs';
3
+ import { createInterface } from 'readline';
2
4
  import path from 'path';
3
5
  import kuzu from 'kuzu';
4
6
  import { NODE_TABLES, REL_TABLE_NAME, SCHEMA_QUERIES, EMBEDDING_TABLE_NAME, } from './schema.js';
5
- import { generateAllCSVs } from './csv-generator.js';
7
+ import { streamAllCSVsToDisk } from './csv-generator.js';
6
8
  let db = null;
7
9
  let conn = null;
8
10
  const normalizeCopyPath = (filePath) => filePath.replace(/\\/g, '/');
@@ -49,26 +51,14 @@ export const initKuzu = async (dbPath) => {
49
51
  }
50
52
  return { db, conn };
51
53
  };
52
- export const loadGraphToKuzu = async (graph, fileContents, storagePath, onProgress) => {
54
+ export const loadGraphToKuzu = async (graph, repoPath, storagePath, onProgress) => {
53
55
  if (!conn) {
54
56
  throw new Error('KuzuDB not initialized. Call initKuzu first.');
55
57
  }
56
58
  const log = onProgress || (() => { });
57
- const csvData = generateAllCSVs(graph, fileContents);
58
59
  const csvDir = path.join(storagePath, 'csv');
59
- await fs.mkdir(csvDir, { recursive: true });
60
- log('Generating CSVs...');
61
- const nodeFiles = [];
62
- for (const [tableName, csv] of csvData.nodes.entries()) {
63
- const rowCount = csv.split('\n').length - 1;
64
- if (rowCount <= 0)
65
- continue;
66
- const filePath = path.join(csvDir, `${tableName.toLowerCase()}.csv`);
67
- await fs.writeFile(filePath, csv, 'utf-8');
68
- nodeFiles.push({ table: tableName, path: filePath, rows: rowCount });
69
- }
70
- // Write relationship CSV to disk for bulk COPY
71
- const relCsvPath = path.join(csvDir, 'relations.csv');
60
+ log('Streaming CSVs to disk...');
61
+ const csvResult = await streamAllCSVsToDisk(graph, repoPath, csvDir);
72
62
  const validTables = new Set(NODE_TABLES);
73
63
  const getNodeLabel = (nodeId) => {
74
64
  if (nodeId.startsWith('comm_'))
@@ -77,35 +67,14 @@ export const loadGraphToKuzu = async (graph, fileContents, storagePath, onProgre
77
67
  return 'Process';
78
68
  return nodeId.split(':')[0];
79
69
  };
80
- const relLines = csvData.relCSV.split('\n');
81
- const relHeader = relLines[0];
82
- const validRelLines = [relHeader];
83
- let skippedRels = 0;
84
- for (let i = 1; i < relLines.length; i++) {
85
- const line = relLines[i];
86
- if (!line.trim())
87
- continue;
88
- const match = line.match(/"([^"]*)","([^"]*)"/);
89
- if (!match) {
90
- skippedRels++;
91
- continue;
92
- }
93
- const fromLabel = getNodeLabel(match[1]);
94
- const toLabel = getNodeLabel(match[2]);
95
- if (!validTables.has(fromLabel) || !validTables.has(toLabel)) {
96
- skippedRels++;
97
- continue;
98
- }
99
- validRelLines.push(line);
100
- }
101
- await fs.writeFile(relCsvPath, validRelLines.join('\n'), 'utf-8');
102
- // Bulk COPY all node CSVs
70
+ // Bulk COPY all node CSVs (sequential — KuzuDB allows only one write txn at a time)
71
+ const nodeFiles = [...csvResult.nodeFiles.entries()];
103
72
  const totalSteps = nodeFiles.length + 1; // +1 for relationships
104
73
  let stepsDone = 0;
105
- for (const { table, path: filePath, rows } of nodeFiles) {
74
+ for (const [table, { csvPath, rows }] of nodeFiles) {
106
75
  stepsDone++;
107
76
  log(`Loading nodes ${stepsDone}/${totalSteps}: ${table} (${rows.toLocaleString()} rows)`);
108
- const normalizedPath = normalizeCopyPath(filePath);
77
+ const normalizedPath = normalizeCopyPath(csvPath);
109
78
  const copyQuery = getCopyQuery(table, normalizedPath);
110
79
  try {
111
80
  await conn.query(copyQuery);
@@ -122,17 +91,33 @@ export const loadGraphToKuzu = async (graph, fileContents, storagePath, onProgre
122
91
  }
123
92
  }
124
93
  // Bulk COPY relationships — split by FROM→TO label pair (KuzuDB requires it)
125
- const insertedRels = validRelLines.length - 1;
126
- const warnings = [];
127
- if (insertedRels > 0) {
128
- const relsByPair = new Map();
129
- for (let i = 1; i < validRelLines.length; i++) {
130
- const line = validRelLines[i];
94
+ // Stream-read the relation CSV line by line to avoid exceeding V8 max string length
95
+ let relHeader = '';
96
+ const relsByPair = new Map();
97
+ let skippedRels = 0;
98
+ let totalValidRels = 0;
99
+ await new Promise((resolve, reject) => {
100
+ const rl = createInterface({ input: createReadStream(csvResult.relCsvPath, 'utf-8'), crlfDelay: Infinity });
101
+ let isFirst = true;
102
+ rl.on('line', (line) => {
103
+ if (isFirst) {
104
+ relHeader = line;
105
+ isFirst = false;
106
+ return;
107
+ }
108
+ if (!line.trim())
109
+ return;
131
110
  const match = line.match(/"([^"]*)","([^"]*)"/);
132
- if (!match)
133
- continue;
111
+ if (!match) {
112
+ skippedRels++;
113
+ return;
114
+ }
134
115
  const fromLabel = getNodeLabel(match[1]);
135
116
  const toLabel = getNodeLabel(match[2]);
117
+ if (!validTables.has(fromLabel) || !validTables.has(toLabel)) {
118
+ skippedRels++;
119
+ return;
120
+ }
136
121
  const pairKey = `${fromLabel}|${toLabel}`;
137
122
  let list = relsByPair.get(pairKey);
138
123
  if (!list) {
@@ -140,7 +125,14 @@ export const loadGraphToKuzu = async (graph, fileContents, storagePath, onProgre
140
125
  relsByPair.set(pairKey, list);
141
126
  }
142
127
  list.push(line);
143
- }
128
+ totalValidRels++;
129
+ });
130
+ rl.on('close', resolve);
131
+ rl.on('error', reject);
132
+ });
133
+ const insertedRels = totalValidRels;
134
+ const warnings = [];
135
+ if (insertedRels > 0) {
144
136
  log(`Loading edges: ${insertedRels.toLocaleString()} across ${relsByPair.size} types`);
145
137
  let pairIdx = 0;
146
138
  let failedPairEdges = 0;
@@ -182,12 +174,12 @@ export const loadGraphToKuzu = async (graph, fileContents, storagePath, onProgre
182
174
  }
183
175
  // Cleanup all CSVs
184
176
  try {
185
- await fs.unlink(relCsvPath);
177
+ await fs.unlink(csvResult.relCsvPath);
186
178
  }
187
179
  catch { }
188
- for (const { path: filePath } of nodeFiles) {
180
+ for (const [, { csvPath }] of csvResult.nodeFiles) {
189
181
  try {
190
- await fs.unlink(filePath);
182
+ await fs.unlink(csvPath);
191
183
  }
192
184
  catch { }
193
185
  }
@@ -253,6 +245,8 @@ const fallbackRelationshipInserts = async (validRelLines, validTables, getNodeLa
253
245
  }
254
246
  }
255
247
  };
248
+ /** Tables with isExported column (TypeScript/JS-native types) */
249
+ const TABLES_WITH_EXPORTED = new Set(['Function', 'Class', 'Interface', 'Method', 'CodeElement']);
256
250
  const getCopyQuery = (table, filePath) => {
257
251
  const t = escapeTableName(table);
258
252
  if (table === 'File') {
@@ -267,8 +261,12 @@ const getCopyQuery = (table, filePath) => {
267
261
  if (table === 'Process') {
268
262
  return `COPY ${t}(id, label, heuristicLabel, processType, stepCount, communities, entryPointId, terminalId) FROM "${filePath}" ${COPY_CSV_OPTS}`;
269
263
  }
270
- // Code element tables (Function, Class, Interface, Method, CodeElement, and multi-language)
271
- return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content) FROM "${filePath}" ${COPY_CSV_OPTS}`;
264
+ // TypeScript/JS code element tables have isExported; multi-language tables do not
265
+ if (TABLES_WITH_EXPORTED.has(table)) {
266
+ return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content) FROM "${filePath}" ${COPY_CSV_OPTS}`;
267
+ }
268
+ // Multi-language tables (Struct, Impl, Trait, Macro, etc.)
269
+ return `COPY ${t}(id, name, filePath, startLine, endLine, content) FROM "${filePath}" ${COPY_CSV_OPTS}`;
272
270
  };
273
271
  /**
274
272
  * Insert a single node to KuzuDB
@@ -292,6 +290,7 @@ export const insertNodeToKuzu = async (label, properties, dbPath) => {
292
290
  return `'${String(v).replace(/\\/g, '\\\\').replace(/'/g, "''")}'`;
293
291
  };
294
292
  // Build INSERT query based on node type
293
+ const t = escapeTableName(label);
295
294
  let query;
296
295
  if (label === 'File') {
297
296
  query = `CREATE (n:File {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, content: ${escapeValue(properties.content || '')}})`;
@@ -299,9 +298,12 @@ export const insertNodeToKuzu = async (label, properties, dbPath) => {
299
298
  else if (label === 'Folder') {
300
299
  query = `CREATE (n:Folder {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}})`;
301
300
  }
301
+ else if (TABLES_WITH_EXPORTED.has(label)) {
302
+ query = `CREATE (n:${t} {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, isExported: ${!!properties.isExported}, content: ${escapeValue(properties.content || '')}})`;
303
+ }
302
304
  else {
303
- // Function, Class, Method, Interface, etc. - standard code element schema
304
- query = `CREATE (n:${label} {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, content: ${escapeValue(properties.content || '')}})`;
305
+ // Multi-language tables (Struct, Impl, Trait, Macro, etc.) no isExported
306
+ query = `CREATE (n:${t} {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, content: ${escapeValue(properties.content || '')}})`;
305
307
  }
306
308
  // Use per-query connection if dbPath provided (avoids lock conflicts)
307
309
  if (targetDbPath) {
@@ -362,14 +364,18 @@ export const batchInsertNodesToKuzu = async (nodes, dbPath) => {
362
364
  try {
363
365
  let query;
364
366
  // Use MERGE instead of CREATE for upsert behavior (handles duplicates gracefully)
367
+ const t = escapeTableName(label);
365
368
  if (label === 'File') {
366
369
  query = `MERGE (n:File {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.content = ${escapeValue(properties.content || '')}`;
367
370
  }
368
371
  else if (label === 'Folder') {
369
372
  query = `MERGE (n:Folder {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}`;
370
373
  }
374
+ else if (TABLES_WITH_EXPORTED.has(label)) {
375
+ query = `MERGE (n:${t} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.isExported = ${!!properties.isExported}, n.content = ${escapeValue(properties.content || '')}`;
376
+ }
371
377
  else {
372
- query = `MERGE (n:${label} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.content = ${escapeValue(properties.content || '')}`;
378
+ query = `MERGE (n:${t} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.content = ${escapeValue(properties.content || '')}`;
373
379
  }
374
380
  await tempConn.query(query);
375
381
  inserted++;
@@ -435,7 +441,7 @@ export const getKuzuStats = async () => {
435
441
  let totalNodes = 0;
436
442
  for (const tableName of NODE_TABLES) {
437
443
  try {
438
- const queryResult = await conn.query(`MATCH (n:${tableName}) RETURN count(n) AS cnt`);
444
+ const queryResult = await conn.query(`MATCH (n:${escapeTableName(tableName)}) RETURN count(n) AS cnt`);
439
445
  const nodeResult = Array.isArray(queryResult) ? queryResult[0] : queryResult;
440
446
  const nodeRows = await nodeResult.getAll();
441
447
  if (nodeRows.length > 0) {
@@ -506,6 +512,7 @@ export const closeKuzu = async () => {
506
512
  catch { }
507
513
  db = null;
508
514
  }
515
+ ftsLoaded = false;
509
516
  };
510
517
  export const isKuzuReady = () => conn !== null && db !== null;
511
518
  /**
@@ -539,13 +546,14 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
539
546
  continue;
540
547
  try {
541
548
  // First count how many we'll delete
542
- const countResult = await targetConn.query(`MATCH (n:${tableName}) WHERE n.filePath = '${escapedPath}' RETURN count(n) AS cnt`);
549
+ const tn = escapeTableName(tableName);
550
+ const countResult = await targetConn.query(`MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' RETURN count(n) AS cnt`);
543
551
  const result = Array.isArray(countResult) ? countResult[0] : countResult;
544
552
  const rows = await result.getAll();
545
553
  const count = Number(rows[0]?.cnt ?? rows[0]?.[0] ?? 0);
546
554
  if (count > 0) {
547
555
  // Delete nodes (and implicitly their relationships via DETACH)
548
- await targetConn.query(`MATCH (n:${tableName}) WHERE n.filePath = '${escapedPath}' DETACH DELETE n`);
556
+ await targetConn.query(`MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' DETACH DELETE n`);
549
557
  deletedNodes += count;
550
558
  }
551
559
  }
@@ -583,9 +591,13 @@ export const getEmbeddingTableName = () => EMBEDDING_TABLE_NAME;
583
591
  // Full-Text Search (FTS) Functions
584
592
  // ============================================================================
585
593
  /**
586
- * Load the FTS extension (required before using FTS functions)
594
+ * Load the FTS extension (required before using FTS functions).
595
+ * Safe to call multiple times — tracks loaded state.
587
596
  */
597
+ let ftsLoaded = false;
588
598
  export const loadFTSExtension = async () => {
599
+ if (ftsLoaded)
600
+ return;
589
601
  if (!conn) {
590
602
  throw new Error('KuzuDB not initialized. Call initKuzu first.');
591
603
  }
@@ -596,6 +608,7 @@ export const loadFTSExtension = async () => {
596
608
  catch {
597
609
  // Extension may already be loaded
598
610
  }
611
+ ftsLoaded = true;
599
612
  };
600
613
  /**
601
614
  * Create a full-text search index on a table
@@ -615,7 +628,6 @@ export const createFTSIndex = async (tableName, indexName, properties, stemmer =
615
628
  await conn.query(query);
616
629
  }
617
630
  catch (e) {
618
- // Index may already exist
619
631
  if (!e.message?.includes('already exists')) {
620
632
  throw e;
621
633
  }
@@ -41,7 +41,7 @@ export declare const ANNOTATION_SCHEMA: string;
41
41
  export declare const CONSTRUCTOR_SCHEMA: string;
42
42
  export declare const TEMPLATE_SCHEMA: string;
43
43
  export declare const MODULE_SCHEMA: string;
44
- export declare const RELATION_SCHEMA = "\nCREATE REL TABLE CodeRelation (\n FROM File TO File,\n FROM File TO Folder,\n FROM File TO Function,\n FROM File TO Class,\n FROM File TO Interface,\n FROM File TO Method,\n FROM File TO CodeElement,\n FROM File TO `Struct`,\n FROM File TO `Enum`,\n FROM File TO `Macro`,\n FROM File TO `Typedef`,\n FROM File TO `Union`,\n FROM File TO `Namespace`,\n FROM File TO `Trait`,\n FROM File TO `Impl`,\n FROM File TO `TypeAlias`,\n FROM File TO `Const`,\n FROM File TO `Static`,\n FROM File TO `Property`,\n FROM File TO `Record`,\n FROM File TO `Delegate`,\n FROM File TO `Annotation`,\n FROM File TO `Constructor`,\n FROM File TO `Template`,\n FROM File TO `Module`,\n FROM Folder TO Folder,\n FROM Folder TO File,\n FROM Function TO Function,\n FROM Function TO Method,\n FROM Function TO Class,\n FROM Function TO Community,\n FROM Function TO `Macro`,\n FROM Function TO `Struct`,\n FROM Function TO `Template`,\n FROM Function TO `Enum`,\n FROM Function TO `Namespace`,\n FROM Function TO `TypeAlias`,\n FROM Function TO `Module`,\n FROM Function TO `Impl`,\n FROM Function TO Interface,\n FROM Function TO `Constructor`,\n FROM Class TO Method,\n FROM Class TO Function,\n FROM Class TO Class,\n FROM Class TO Interface,\n FROM Class TO Community,\n FROM Class TO `Template`,\n FROM Class TO `TypeAlias`,\n FROM Class TO `Struct`,\n FROM Class TO `Enum`,\n FROM Class TO `Annotation`,\n FROM Class TO `Constructor`,\n FROM Method TO Function,\n FROM Method TO Method,\n FROM Method TO Class,\n FROM Method TO Community,\n FROM Method TO `Template`,\n FROM Method TO `Struct`,\n FROM Method TO `TypeAlias`,\n FROM Method TO `Enum`,\n FROM Method TO `Macro`,\n FROM Method TO `Namespace`,\n FROM Method TO `Module`,\n FROM Method TO `Impl`,\n FROM Method TO Interface,\n FROM Method TO `Constructor`,\n FROM `Template` TO `Template`,\n FROM `Template` TO Function,\n FROM `Template` TO Method,\n FROM `Template` TO Class,\n FROM `Template` TO `Struct`,\n FROM `Template` TO `TypeAlias`,\n FROM `Template` TO `Enum`,\n FROM `Template` TO `Macro`,\n FROM `Template` TO Interface,\n FROM `Template` TO `Constructor`,\n FROM `Module` TO `Module`,\n FROM CodeElement TO Community,\n FROM Interface TO Community,\n FROM Interface TO Function,\n FROM Interface TO Method,\n FROM Interface TO Class,\n FROM Interface TO Interface,\n FROM Interface TO `TypeAlias`,\n FROM Interface TO `Struct`,\n FROM Interface TO `Constructor`,\n FROM `Struct` TO Community,\n FROM `Struct` TO `Trait`,\n FROM `Struct` TO Function,\n FROM `Struct` TO Method,\n FROM `Enum` TO Community,\n FROM `Macro` TO Community,\n FROM `Macro` TO Function,\n FROM `Macro` TO Method,\n FROM `Module` TO Function,\n FROM `Module` TO Method,\n FROM `Typedef` TO Community,\n FROM `Union` TO Community,\n FROM `Namespace` TO Community,\n FROM `Trait` TO Community,\n FROM `Impl` TO Community,\n FROM `Impl` TO `Trait`,\n FROM `TypeAlias` TO Community,\n FROM `Const` TO Community,\n FROM `Static` TO Community,\n FROM `Property` TO Community,\n FROM `Record` TO Community,\n FROM `Delegate` TO Community,\n FROM `Annotation` TO Community,\n FROM `Constructor` TO Community,\n FROM `Constructor` TO Interface,\n FROM `Constructor` TO Class,\n FROM `Constructor` TO Method,\n FROM `Constructor` TO Function,\n FROM `Constructor` TO `Constructor`,\n FROM `Constructor` TO `Struct`,\n FROM `Constructor` TO `Macro`,\n FROM `Constructor` TO `Template`,\n FROM `Constructor` TO `TypeAlias`,\n FROM `Constructor` TO `Enum`,\n FROM `Constructor` TO `Annotation`,\n FROM `Constructor` TO `Impl`,\n FROM `Constructor` TO `Namespace`,\n FROM `Constructor` TO `Module`,\n FROM `Template` TO Community,\n FROM `Module` TO Community,\n FROM Function TO Process,\n FROM Method TO Process,\n FROM Class TO Process,\n FROM Interface TO Process,\n FROM `Struct` TO Process,\n FROM `Constructor` TO Process,\n FROM `Module` TO Process,\n FROM `Macro` TO Process,\n FROM `Impl` TO Process,\n FROM `Typedef` TO Process,\n FROM `TypeAlias` TO Process,\n FROM `Enum` TO Process,\n FROM `Union` TO Process,\n FROM `Namespace` TO Process,\n FROM `Trait` TO Process,\n FROM `Const` TO Process,\n FROM `Static` TO Process,\n FROM `Property` TO Process,\n FROM `Record` TO Process,\n FROM `Delegate` TO Process,\n FROM `Annotation` TO Process,\n FROM `Template` TO Process,\n FROM CodeElement TO Process,\n type STRING,\n confidence DOUBLE,\n reason STRING,\n step INT32\n)";
44
+ export declare const RELATION_SCHEMA = "\nCREATE REL TABLE CodeRelation (\n FROM File TO File,\n FROM File TO Folder,\n FROM File TO Function,\n FROM File TO Class,\n FROM File TO Interface,\n FROM File TO Method,\n FROM File TO CodeElement,\n FROM File TO `Struct`,\n FROM File TO `Enum`,\n FROM File TO `Macro`,\n FROM File TO `Typedef`,\n FROM File TO `Union`,\n FROM File TO `Namespace`,\n FROM File TO `Trait`,\n FROM File TO `Impl`,\n FROM File TO `TypeAlias`,\n FROM File TO `Const`,\n FROM File TO `Static`,\n FROM File TO `Property`,\n FROM File TO `Record`,\n FROM File TO `Delegate`,\n FROM File TO `Annotation`,\n FROM File TO `Constructor`,\n FROM File TO `Template`,\n FROM File TO `Module`,\n FROM Folder TO Folder,\n FROM Folder TO File,\n FROM Function TO Function,\n FROM Function TO Method,\n FROM Function TO Class,\n FROM Function TO Community,\n FROM Function TO `Macro`,\n FROM Function TO `Struct`,\n FROM Function TO `Template`,\n FROM Function TO `Enum`,\n FROM Function TO `Namespace`,\n FROM Function TO `TypeAlias`,\n FROM Function TO `Module`,\n FROM Function TO `Impl`,\n FROM Function TO Interface,\n FROM Function TO `Constructor`,\n FROM Function TO `Const`,\n FROM Function TO `Typedef`,\n FROM Function TO `Union`,\n FROM Class TO Method,\n FROM Class TO Function,\n FROM Class TO Class,\n FROM Class TO Interface,\n FROM Class TO Community,\n FROM Class TO `Template`,\n FROM Class TO `TypeAlias`,\n FROM Class TO `Struct`,\n FROM Class TO `Enum`,\n FROM Class TO `Annotation`,\n FROM Class TO `Constructor`,\n FROM Class TO `Trait`,\n FROM Class TO `Macro`,\n FROM Class TO `Impl`,\n FROM Class TO `Union`,\n FROM Method TO Function,\n FROM Method TO Method,\n FROM Method TO Class,\n FROM Method TO Community,\n FROM Method TO `Template`,\n FROM Method TO `Struct`,\n FROM Method TO `TypeAlias`,\n FROM Method TO `Enum`,\n FROM Method TO `Macro`,\n FROM Method TO `Namespace`,\n FROM Method TO `Module`,\n FROM Method TO `Impl`,\n FROM Method TO Interface,\n FROM Method TO `Constructor`,\n FROM `Template` TO `Template`,\n FROM `Template` TO Function,\n FROM `Template` TO Method,\n FROM `Template` TO Class,\n FROM `Template` TO `Struct`,\n FROM `Template` TO `TypeAlias`,\n FROM `Template` TO `Enum`,\n FROM `Template` TO `Macro`,\n FROM `Template` TO Interface,\n FROM `Template` TO `Constructor`,\n FROM `Module` TO `Module`,\n FROM CodeElement TO Community,\n FROM Interface TO Community,\n FROM Interface TO Function,\n FROM Interface TO Method,\n FROM Interface TO Class,\n FROM Interface TO Interface,\n FROM Interface TO `TypeAlias`,\n FROM Interface TO `Struct`,\n FROM Interface TO `Constructor`,\n FROM `Struct` TO Community,\n FROM `Struct` TO `Trait`,\n FROM `Struct` TO Function,\n FROM `Struct` TO Method,\n FROM `Enum` TO Community,\n FROM `Macro` TO Community,\n FROM `Macro` TO Function,\n FROM `Macro` TO Method,\n FROM `Module` TO Function,\n FROM `Module` TO Method,\n FROM `Typedef` TO Community,\n FROM `Union` TO Community,\n FROM `Namespace` TO Community,\n FROM `Trait` TO Community,\n FROM `Impl` TO Community,\n FROM `Impl` TO `Trait`,\n FROM `Impl` TO `Struct`,\n FROM `Impl` TO `Impl`,\n FROM `TypeAlias` TO Community,\n FROM `TypeAlias` TO `Trait`,\n FROM `Const` TO Community,\n FROM `Static` TO Community,\n FROM `Property` TO Community,\n FROM `Record` TO Community,\n FROM `Delegate` TO Community,\n FROM `Annotation` TO Community,\n FROM `Constructor` TO Community,\n FROM `Constructor` TO Interface,\n FROM `Constructor` TO Class,\n FROM `Constructor` TO Method,\n FROM `Constructor` TO Function,\n FROM `Constructor` TO `Constructor`,\n FROM `Constructor` TO `Struct`,\n FROM `Constructor` TO `Macro`,\n FROM `Constructor` TO `Template`,\n FROM `Constructor` TO `TypeAlias`,\n FROM `Constructor` TO `Enum`,\n FROM `Constructor` TO `Annotation`,\n FROM `Constructor` TO `Impl`,\n FROM `Constructor` TO `Namespace`,\n FROM `Constructor` TO `Module`,\n FROM `Template` TO Community,\n FROM `Module` TO Community,\n FROM Function TO Process,\n FROM Method TO Process,\n FROM Class TO Process,\n FROM Interface TO Process,\n FROM `Struct` TO Process,\n FROM `Constructor` TO Process,\n FROM `Module` TO Process,\n FROM `Macro` TO Process,\n FROM `Impl` TO Process,\n FROM `Typedef` TO Process,\n FROM `TypeAlias` TO Process,\n FROM `Enum` TO Process,\n FROM `Union` TO Process,\n FROM `Namespace` TO Process,\n FROM `Trait` TO Process,\n FROM `Const` TO Process,\n FROM `Static` TO Process,\n FROM `Property` TO Process,\n FROM `Record` TO Process,\n FROM `Delegate` TO Process,\n FROM `Annotation` TO Process,\n FROM `Template` TO Process,\n FROM CodeElement TO Process,\n type STRING,\n confidence DOUBLE,\n reason STRING,\n step INT32\n)";
45
45
  export declare const EMBEDDING_SCHEMA = "\nCREATE NODE TABLE CodeEmbedding (\n nodeId STRING,\n embedding FLOAT[384],\n PRIMARY KEY (nodeId)\n)";
46
46
  /**
47
47
  * Create vector index for semantic search
@@ -209,6 +209,9 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
209
209
  FROM Function TO \`Impl\`,
210
210
  FROM Function TO Interface,
211
211
  FROM Function TO \`Constructor\`,
212
+ FROM Function TO \`Const\`,
213
+ FROM Function TO \`Typedef\`,
214
+ FROM Function TO \`Union\`,
212
215
  FROM Class TO Method,
213
216
  FROM Class TO Function,
214
217
  FROM Class TO Class,
@@ -220,6 +223,10 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
220
223
  FROM Class TO \`Enum\`,
221
224
  FROM Class TO \`Annotation\`,
222
225
  FROM Class TO \`Constructor\`,
226
+ FROM Class TO \`Trait\`,
227
+ FROM Class TO \`Macro\`,
228
+ FROM Class TO \`Impl\`,
229
+ FROM Class TO \`Union\`,
223
230
  FROM Method TO Function,
224
231
  FROM Method TO Method,
225
232
  FROM Method TO Class,
@@ -270,7 +277,10 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
270
277
  FROM \`Trait\` TO Community,
271
278
  FROM \`Impl\` TO Community,
272
279
  FROM \`Impl\` TO \`Trait\`,
280
+ FROM \`Impl\` TO \`Struct\`,
281
+ FROM \`Impl\` TO \`Impl\`,
273
282
  FROM \`TypeAlias\` TO Community,
283
+ FROM \`TypeAlias\` TO \`Trait\`,
274
284
  FROM \`Const\` TO Community,
275
285
  FROM \`Static\` TO Community,
276
286
  FROM \`Property\` TO Community,
@@ -15,14 +15,18 @@ export interface PipelineProgress {
15
15
  }
16
16
  export interface PipelineResult {
17
17
  graph: KnowledgeGraph;
18
- fileContents: Map<string, string>;
18
+ /** Absolute path to the repo root — used for lazy file reads during KuzuDB loading */
19
+ repoPath: string;
20
+ /** Total files scanned (for stats) */
21
+ totalFileCount: number;
19
22
  communityResult?: CommunityDetectionResult;
20
23
  processResult?: ProcessDetectionResult;
21
24
  }
22
25
  export interface SerializablePipelineResult {
23
26
  nodes: GraphNode[];
24
27
  relationships: GraphRelationship[];
25
- fileContents: Record<string, string>;
28
+ repoPath: string;
29
+ totalFileCount: number;
26
30
  }
27
31
  export declare const serializePipelineResult: (result: PipelineResult) => SerializablePipelineResult;
28
32
  export declare const deserializePipelineResult: (serialized: SerializablePipelineResult, createGraph: () => KnowledgeGraph) => PipelineResult;
@@ -1,8 +1,9 @@
1
1
  // Helper to convert PipelineResult to serializable format
2
2
  export const serializePipelineResult = (result) => ({
3
- nodes: result.graph.nodes,
4
- relationships: result.graph.relationships,
5
- fileContents: Object.fromEntries(result.fileContents),
3
+ nodes: [...result.graph.iterNodes()],
4
+ relationships: [...result.graph.iterRelationships()],
5
+ repoPath: result.repoPath,
6
+ totalFileCount: result.totalFileCount,
6
7
  });
7
8
  // Helper to reconstruct from serializable format (used in main thread)
8
9
  export const deserializePipelineResult = (serialized, createGraph) => {
@@ -11,6 +12,7 @@ export const deserializePipelineResult = (serialized, createGraph) => {
11
12
  serialized.relationships.forEach(rel => graph.addRelationship(rel));
12
13
  return {
13
14
  graph,
14
- fileContents: new Map(Object.entries(serialized.fileContents)),
15
+ repoPath: serialized.repoPath,
16
+ totalFileCount: serialized.totalFileCount,
15
17
  };
16
18
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.2.9",
3
+ "version": "1.3.0",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",