@codragraph/cli 2.1.0 → 2.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.
Files changed (156) hide show
  1. package/README.md +62 -21
  2. package/dist/_shared/cgdb/schema-constants.d.ts +2 -2
  3. package/dist/_shared/cgdb/schema-constants.d.ts.map +1 -1
  4. package/dist/_shared/cgdb/schema-constants.js +3 -0
  5. package/dist/_shared/cgdb/schema-constants.js.map +1 -1
  6. package/dist/_shared/feature-clusters.d.ts +99 -0
  7. package/dist/_shared/feature-clusters.d.ts.map +1 -0
  8. package/dist/_shared/feature-clusters.js +2 -0
  9. package/dist/_shared/feature-clusters.js.map +1 -0
  10. package/dist/_shared/graph/types.d.ts +16 -2
  11. package/dist/_shared/graph/types.d.ts.map +1 -1
  12. package/dist/_shared/index.d.ts +1 -0
  13. package/dist/_shared/index.d.ts.map +1 -1
  14. package/dist/_shared/index.js.map +1 -1
  15. package/dist/_shared/pipeline.d.ts +1 -1
  16. package/dist/_shared/pipeline.d.ts.map +1 -1
  17. package/dist/cli/ai-context.js +4 -0
  18. package/dist/cli/analyze.js +46 -26
  19. package/dist/cli/index.js +39 -1
  20. package/dist/cli/serve.d.ts +1 -0
  21. package/dist/cli/serve.js +3 -1
  22. package/dist/cli/setup.js +42 -21
  23. package/dist/cli/status.d.ts +13 -0
  24. package/dist/cli/status.js +99 -0
  25. package/dist/cli/tool.d.ts +25 -0
  26. package/dist/cli/tool.js +74 -0
  27. package/dist/config/ignore-service.js +2 -0
  28. package/dist/config/supported-languages.d.ts +3 -3
  29. package/dist/config/supported-languages.js +3 -3
  30. package/dist/core/cgdb/cgdb-adapter.js +19 -3
  31. package/dist/core/cgdb/csv-generator.js +33 -2
  32. package/dist/core/cgdb/schema.d.ts +2 -1
  33. package/dist/core/cgdb/schema.js +55 -0
  34. package/dist/core/embeddings/embedder.js +4 -2
  35. package/dist/core/graphstore/cgdb-row-source.js +3 -2
  36. package/dist/core/graphstore/index.d.ts +1 -1
  37. package/dist/core/graphstore/index.js +1 -1
  38. package/dist/core/group/bridge-db.js +42 -10
  39. package/dist/core/group/service.d.ts +16 -0
  40. package/dist/core/group/service.js +360 -0
  41. package/dist/core/ingestion/emit-references.d.ts +1 -1
  42. package/dist/core/ingestion/emit-references.js +1 -1
  43. package/dist/core/ingestion/feature-cluster-processor.d.ts +62 -0
  44. package/dist/core/ingestion/feature-cluster-processor.js +626 -0
  45. package/dist/core/ingestion/finalize-orchestrator.js +1 -1
  46. package/dist/core/ingestion/model/registration-table.js +1 -0
  47. package/dist/core/ingestion/model/resolve.d.ts +2 -2
  48. package/dist/core/ingestion/model/resolve.js +3 -3
  49. package/dist/core/ingestion/model/semantic-model.d.ts +1 -1
  50. package/dist/core/ingestion/model/semantic-model.js +1 -1
  51. package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
  52. package/dist/core/ingestion/model/symbol-table.js +1 -1
  53. package/dist/core/ingestion/pipeline-phases/feature-clusters.d.ts +17 -0
  54. package/dist/core/ingestion/pipeline-phases/feature-clusters.js +88 -0
  55. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  56. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  57. package/dist/core/ingestion/pipeline.d.ts +4 -0
  58. package/dist/core/ingestion/pipeline.js +9 -5
  59. package/dist/core/run-analyze.d.ts +21 -0
  60. package/dist/core/run-analyze.js +213 -6
  61. package/dist/core/search/hybrid-search.js +11 -3
  62. package/dist/mcp/core/embedder.js +5 -2
  63. package/dist/mcp/local/local-backend.d.ts +12 -0
  64. package/dist/mcp/local/local-backend.js +381 -3
  65. package/dist/mcp/resources.js +139 -0
  66. package/dist/mcp/tools.js +174 -2
  67. package/dist/server/api.d.ts +14 -2
  68. package/dist/server/api.js +206 -7
  69. package/dist/server/mcp-http.d.ts +22 -0
  70. package/dist/server/mcp-http.js +21 -2
  71. package/dist/server/web-dashboard.d.ts +28 -0
  72. package/dist/server/web-dashboard.js +61 -0
  73. package/dist/storage/repo-manager.d.ts +6 -1
  74. package/dist/storage/repo-manager.js +5 -1
  75. package/dist/types/pipeline.d.ts +2 -0
  76. package/dist/web/assets/agent-D5lb0zXz.js +1089 -0
  77. package/dist/web/assets/architectureDiagram-EMZXCZ2Q-CZtc99v_.js +36 -0
  78. package/dist/web/assets/blockDiagram-IGV67L2C-BtoUp-6Y.js +132 -0
  79. package/dist/web/assets/c4Diagram-DFAF54RM-C4Hl3J2U.js +10 -0
  80. package/dist/web/assets/chunk-3GS5O3IE-DkUjU0WD.js +231 -0
  81. package/dist/web/assets/chunk-3YCYZ6SJ-CQkVgT_z.js +1 -0
  82. package/dist/web/assets/chunk-7RZVMHOQ-BitYcNVR.js +338 -0
  83. package/dist/web/assets/chunk-AEOMTBSW-BgTIXPsY.js +1 -0
  84. package/dist/web/assets/chunk-H3VCZNTA-Cx5XV_aC.js +13 -0
  85. package/dist/web/assets/chunk-HN6EAY2L-BBnyTNdB.js +1 -0
  86. package/dist/web/assets/chunk-KSICW3F5-BYzvDLNI.js +15 -0
  87. package/dist/web/assets/chunk-O5ABG6QK-dHwHzA6n.js +1 -0
  88. package/dist/web/assets/chunk-PK6DOVAG-CvsEnugt.js +206 -0
  89. package/dist/web/assets/chunk-RWUO3TPN-BgRTY0_k.js +1 -0
  90. package/dist/web/assets/chunk-TBF5ZNIQ-DL5stGM1.js +1 -0
  91. package/dist/web/assets/chunk-TU3PZOEN-RLyvLcv-.js +1 -0
  92. package/dist/web/assets/classDiagram-PPOCWD7C-DTr8QIOf.js +1 -0
  93. package/dist/web/assets/classDiagram-v2-23LJLIIU-DTr8QIOf.js +1 -0
  94. package/dist/web/assets/context-builder-22jU3V56.js +16 -0
  95. package/dist/web/assets/cose-bilkent-PNC4W37J-DVhePRYg.js +1 -0
  96. package/dist/web/assets/dagre-E77IOHMT-Dzx0A6ZU.js +4 -0
  97. package/dist/web/assets/diagram-H7BISOXX-CC9pRew1.js +43 -0
  98. package/dist/web/assets/diagram-JC5VWROH-Bau_i9tf.js +24 -0
  99. package/dist/web/assets/diagram-LXUTUG65-D9_FM2Gt.js +10 -0
  100. package/dist/web/assets/diagram-WEHSV5V5-BMlayouL.js +24 -0
  101. package/dist/web/assets/erDiagram-GCSMX5X6-C3dhDFA8.js +85 -0
  102. package/dist/web/assets/flowDiagram-OTCZ4VVT-CWSFWmhr.js +162 -0
  103. package/dist/web/assets/ganttDiagram-MUNLMDZQ-D3a67Yol.js +292 -0
  104. package/dist/web/assets/gitGraphDiagram-3HKGZ4G3-7jmry-vM.js +106 -0
  105. package/dist/web/assets/index-BgeqpYgd.js +1415 -0
  106. package/dist/web/assets/index-CT0GtFLZ.css +1 -0
  107. package/dist/web/assets/infoDiagram-MN7RKWGX-G7lhP0Ib.js +2 -0
  108. package/dist/web/assets/ishikawaDiagram-YMYX4NHK-DUoJvNP2.js +70 -0
  109. package/dist/web/assets/journeyDiagram-SO5T7YLQ-RMFPNNqz.js +139 -0
  110. package/dist/web/assets/kanban-definition-LJHFXRCJ-BzpDs1K9.js +89 -0
  111. package/dist/web/assets/katex-GD7MH7QM-DBQvrix-.js +261 -0
  112. package/dist/web/assets/mindmap-definition-2EUWGEK5-Bk0O4roa.js +96 -0
  113. package/dist/web/assets/pieDiagram-3IATQBI2-DKU7kpgS.js +30 -0
  114. package/dist/web/assets/quadrantDiagram-E256RVCF-BY0TGWCS.js +7 -0
  115. package/dist/web/assets/requirementDiagram-M5DCFWZL-DLHOVTSv.js +84 -0
  116. package/dist/web/assets/sankeyDiagram-L3NBLAOT-DVMj5rX2.js +10 -0
  117. package/dist/web/assets/sequenceDiagram-ZOUHS735-CJC73bV-.js +157 -0
  118. package/dist/web/assets/stateDiagram-MLPALWAM-BCFyESls.js +1 -0
  119. package/dist/web/assets/stateDiagram-v2-B5LQ5ZB2-DahzzIca.js +1 -0
  120. package/dist/web/assets/timeline-definition-5SPVSISX-TRSDRgPw.js +120 -0
  121. package/dist/web/assets/vennDiagram-IE5QUKF5-DNy7HRBM.js +34 -0
  122. package/dist/web/assets/wardley-RL74JXVD-BCRCBASE-B-eZEzf9.js +161 -0
  123. package/dist/web/assets/wardleyDiagram-XU3VSMPF-BP-r1xzR.js +20 -0
  124. package/dist/web/assets/xychartDiagram-ZHJ5623Y-Dr9r7a35.js +7 -0
  125. package/dist/web/codragraph-logo-512.png +0 -0
  126. package/dist/web/codragraph-logo.png +0 -0
  127. package/dist/web/favicon.png +0 -0
  128. package/dist/web/index.html +36 -0
  129. package/hooks/claude/codragraph-hook.cjs +24 -9
  130. package/hooks/claude/pre-tool-use.sh +6 -1
  131. package/package.json +15 -4
  132. package/scripts/build.js +75 -16
  133. package/scripts/patch-tree-sitter-swift.cjs +0 -1
  134. package/skills/codragraph-cli.md +17 -1
  135. package/skills/codragraph-guide.md +6 -2
  136. package/skills/codragraph-onboarding.md +2 -2
  137. package/vendor/leiden/index.cjs +272 -285
  138. package/vendor/leiden/utils.cjs +264 -274
  139. package/dist/_shared/lbug/schema-constants.d.ts +0 -16
  140. package/dist/_shared/lbug/schema-constants.d.ts.map +0 -1
  141. package/dist/_shared/lbug/schema-constants.js +0 -67
  142. package/dist/_shared/lbug/schema-constants.js.map +0 -1
  143. package/dist/core/graphstore/lbug-row-source.d.ts +0 -19
  144. package/dist/core/graphstore/lbug-row-source.js +0 -141
  145. package/dist/core/lbug/content-read.d.ts +0 -46
  146. package/dist/core/lbug/content-read.js +0 -64
  147. package/dist/core/lbug/csv-generator.d.ts +0 -29
  148. package/dist/core/lbug/csv-generator.js +0 -492
  149. package/dist/core/lbug/lbug-adapter.d.ts +0 -176
  150. package/dist/core/lbug/lbug-adapter.js +0 -1320
  151. package/dist/core/lbug/pool-adapter.d.ts +0 -93
  152. package/dist/core/lbug/pool-adapter.js +0 -550
  153. package/dist/core/lbug/schema.d.ts +0 -62
  154. package/dist/core/lbug/schema.js +0 -502
  155. package/dist/mcp/core/lbug-adapter.d.ts +0 -5
  156. package/dist/mcp/core/lbug-adapter.js +0 -5
@@ -507,7 +507,8 @@ const getCopyQuery = (table, filePath) => {
507
507
  // RFC 0001 Phase 2: every content-bearing table also lists
508
508
  // `contentEncoding` immediately after `content` to match the schema +
509
509
  // CSV layout. Tables without a content column (Folder, Community,
510
- // Process, Route, Tool) are unchanged.
510
+ // Process, Route, Tool) are unchanged. FeatureCluster carries rich metadata
511
+ // but still has no content/file snippet column.
511
512
  if (table === 'File') {
512
513
  return `COPY ${t}(id, name, filePath, content, contentEncoding) FROM "${filePath}" ${COPY_CSV_OPTS}`;
513
514
  }
@@ -520,6 +521,9 @@ const getCopyQuery = (table, filePath) => {
520
521
  if (table === 'Process') {
521
522
  return `COPY ${t}(id, label, heuristicLabel, processType, stepCount, communities, entryPointId, terminalId) FROM "${filePath}" ${COPY_CSV_OPTS}`;
522
523
  }
524
+ if (table === 'FeatureCluster') {
525
+ return `COPY ${t}(id, name, slug, featureKind, summary, description, repo, service, signals, memberCount, entryPointIds, routes, tools, testCoverageHints, lastIndexedCommit, confidence, source) FROM "${filePath}" ${COPY_CSV_OPTS}`;
526
+ }
523
527
  if (table === 'Section') {
524
528
  return `COPY ${t}(id, name, filePath, startLine, endLine, level, content, contentEncoding, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
525
529
  }
@@ -557,6 +561,9 @@ export const insertNodeToCgdb = async (label, properties, dbPath) => {
557
561
  return 'NULL';
558
562
  if (typeof v === 'number')
559
563
  return String(v);
564
+ if (Array.isArray(v)) {
565
+ return `[${v.map((item) => `'${String(item).replace(/\\/g, '\\\\').replace(/'/g, "''")}'`).join(',')}]`;
566
+ }
560
567
  // Escape backslashes first (for Windows paths), then single quotes
561
568
  return `'${String(v).replace(/\\/g, '\\\\').replace(/'/g, "''").replace(/\n/g, '\\n').replace(/\r/g, '\\r')}'`;
562
569
  };
@@ -575,6 +582,9 @@ export const insertNodeToCgdb = async (label, properties, dbPath) => {
575
582
  : '';
576
583
  query = `CREATE (n:Section {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, level: ${properties.level || 1}, content: ${escapeValue(properties.content || '')}${descPart}})`;
577
584
  }
585
+ else if (label === 'FeatureCluster') {
586
+ query = `CREATE (n:FeatureCluster {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, slug: ${escapeValue(properties.slug)}, featureKind: ${escapeValue(properties.featureKind || 'feature')}, summary: ${escapeValue(properties.summary || '')}, description: ${escapeValue(properties.description || '')}, repo: ${escapeValue(properties.repo || '')}, service: ${escapeValue(properties.service || '')}, signals: ${escapeValue(properties.signals || [])}, memberCount: ${properties.memberCount || 0}, entryPointIds: ${escapeValue(properties.entryPointIds || [])}, routes: ${escapeValue(properties.routes || [])}, tools: ${escapeValue(properties.tools || [])}, testCoverageHints: ${escapeValue(properties.testCoverageHints || [])}, lastIndexedCommit: ${escapeValue(properties.lastIndexedCommit || '')}, confidence: ${properties.confidence || 0}, source: ${escapeValue(properties.source || 'heuristic')}})`;
587
+ }
578
588
  else if (TABLES_WITH_EXPORTED.has(label)) {
579
589
  const descPart = properties.description
580
590
  ? `, description: ${escapeValue(properties.description)}`
@@ -635,6 +645,9 @@ export const batchInsertNodesToCgdb = async (nodes, dbPath) => {
635
645
  return 'NULL';
636
646
  if (typeof v === 'number')
637
647
  return String(v);
648
+ if (Array.isArray(v)) {
649
+ return `[${v.map((item) => `'${String(item).replace(/\\/g, '\\\\').replace(/'/g, "''")}'`).join(',')}]`;
650
+ }
638
651
  // Escape backslashes first (for Windows paths), then single quotes, then newlines
639
652
  return `'${String(v).replace(/\\/g, '\\\\').replace(/'/g, "''").replace(/\n/g, '\\n').replace(/\r/g, '\\r')}'`;
640
653
  };
@@ -661,6 +674,9 @@ export const batchInsertNodesToCgdb = async (nodes, dbPath) => {
661
674
  : '';
662
675
  query = `MERGE (n:Section {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.level = ${properties.level || 1}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
663
676
  }
677
+ else if (label === 'FeatureCluster') {
678
+ query = `MERGE (n:FeatureCluster {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.slug = ${escapeValue(properties.slug)}, n.featureKind = ${escapeValue(properties.featureKind || 'feature')}, n.summary = ${escapeValue(properties.summary || '')}, n.description = ${escapeValue(properties.description || '')}, n.repo = ${escapeValue(properties.repo || '')}, n.service = ${escapeValue(properties.service || '')}, n.signals = ${escapeValue(properties.signals || [])}, n.memberCount = ${properties.memberCount || 0}, n.entryPointIds = ${escapeValue(properties.entryPointIds || [])}, n.routes = ${escapeValue(properties.routes || [])}, n.tools = ${escapeValue(properties.tools || [])}, n.testCoverageHints = ${escapeValue(properties.testCoverageHints || [])}, n.lastIndexedCommit = ${escapeValue(properties.lastIndexedCommit || '')}, n.confidence = ${properties.confidence || 0}, n.source = ${escapeValue(properties.source || 'heuristic')}`;
679
+ }
664
680
  else if (TABLES_WITH_EXPORTED.has(label)) {
665
681
  const descPart = properties.description
666
682
  ? `, n.description = ${escapeValue(properties.description)}`
@@ -1103,8 +1119,8 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
1103
1119
  // Delete nodes from each table that has filePath
1104
1120
  // DETACH DELETE removes the node and all its relationships
1105
1121
  for (const tableName of NODE_TABLES) {
1106
- // Skip tables that don't have filePath (Community, Process)
1107
- if (tableName === 'Community' || tableName === 'Process')
1122
+ // Skip tables that don't have filePath (Community, Process, FeatureCluster)
1123
+ if (tableName === 'Community' || tableName === 'Process' || tableName === 'FeatureCluster')
1108
1124
  continue;
1109
1125
  try {
1110
1126
  // First count how many we'll delete
@@ -40,6 +40,13 @@ export const escapeCSVNumber = (value, defaultValue = -1) => {
40
40
  return String(defaultValue);
41
41
  return String(value);
42
42
  };
43
+ const toCgdbStringArray = (value) => {
44
+ const values = Array.isArray(value) ? value : [];
45
+ return `[${values
46
+ .map((item) => String(item).replace(/\\/g, '\\\\').replace(/'/g, "''").replace(/,/g, '\\,'))
47
+ .map((item) => `'${item}'`)
48
+ .join(',')}]`;
49
+ };
43
50
  // ============================================================================
44
51
  // CONTENT EXTRACTION (lazy — reads from disk on demand)
45
52
  // ============================================================================
@@ -231,6 +238,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, compress) =>
231
238
  const codeElemWriter = new BufferedCSVWriter(path.join(csvDir, 'codeelement.csv'), codeElementHeader);
232
239
  const communityWriter = new BufferedCSVWriter(path.join(csvDir, 'community.csv'), 'id,label,heuristicLabel,keywords,description,enrichedBy,cohesion,symbolCount');
233
240
  const processWriter = new BufferedCSVWriter(path.join(csvDir, 'process.csv'), 'id,label,heuristicLabel,processType,stepCount,communities,entryPointId,terminalId');
241
+ const featureClusterWriter = new BufferedCSVWriter(path.join(csvDir, 'featurecluster.csv'), 'id,name,slug,featureKind,summary,description,repo,service,signals,memberCount,entryPointIds,routes,tools,testCoverageHints,lastIndexedCommit,confidence,source');
234
242
  // Section nodes have an extra 'level' column
235
243
  const sectionWriter = new BufferedCSVWriter(path.join(csvDir, 'section.csv'), 'id,name,filePath,startLine,endLine,level,content,contentEncoding,description');
236
244
  // Route nodes for API endpoint mapping
@@ -315,8 +323,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, compress) =>
315
323
  break;
316
324
  }
317
325
  case 'Process': {
318
- const communities = node.properties.communities || [];
319
- const communitiesStr = `[${communities.map((c) => `'${c.replace(/'/g, "''")}'`).join(',')}]`;
326
+ const communitiesStr = toCgdbStringArray(node.properties.communities);
320
327
  await processWriter.addRow([
321
328
  escapeCSVField(node.id),
322
329
  escapeCSVField(node.properties.name || ''),
@@ -329,6 +336,28 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, compress) =>
329
336
  ].join(','));
330
337
  break;
331
338
  }
339
+ case 'FeatureCluster': {
340
+ await featureClusterWriter.addRow([
341
+ escapeCSVField(node.id),
342
+ escapeCSVField(node.properties.name || ''),
343
+ escapeCSVField(node.properties.slug || ''),
344
+ escapeCSVField(node.properties.featureKind || 'feature'),
345
+ escapeCSVField(node.properties.summary || ''),
346
+ escapeCSVField(node.properties.description || ''),
347
+ escapeCSVField(node.properties.repo || ''),
348
+ escapeCSVField(node.properties.service || ''),
349
+ escapeCSVField(toCgdbStringArray(node.properties.signals)),
350
+ escapeCSVNumber(node.properties.memberCount, 0),
351
+ escapeCSVField(toCgdbStringArray(node.properties.entryPointIds)),
352
+ escapeCSVField(toCgdbStringArray(node.properties.routes)),
353
+ escapeCSVField(toCgdbStringArray(node.properties.tools)),
354
+ escapeCSVField(toCgdbStringArray(node.properties.testCoverageHints)),
355
+ escapeCSVField(node.properties.lastIndexedCommit || ''),
356
+ escapeCSVNumber(node.properties.confidence, 0),
357
+ escapeCSVField(node.properties.source || 'heuristic'),
358
+ ].join(','));
359
+ break;
360
+ }
332
361
  case 'Method': {
333
362
  const content = await extractContent(node, contentCache);
334
363
  const { wireContent, tag } = applyEncoding(content, compress);
@@ -441,6 +470,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, compress) =>
441
470
  codeElemWriter,
442
471
  communityWriter,
443
472
  processWriter,
473
+ featureClusterWriter,
444
474
  sectionWriter,
445
475
  routeWriter,
446
476
  toolWriter,
@@ -473,6 +503,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, compress) =>
473
503
  ['CodeElement', codeElemWriter],
474
504
  ['Community', communityWriter],
475
505
  ['Process', processWriter],
506
+ ['FeatureCluster', featureClusterWriter],
476
507
  ['Section', sectionWriter],
477
508
  ['Route', routeWriter],
478
509
  ['Tool', toolWriter],
@@ -20,6 +20,7 @@ export declare const METHOD_SCHEMA = "\nCREATE NODE TABLE Method (\n id STRING,
20
20
  export declare const CODE_ELEMENT_SCHEMA = "\nCREATE NODE TABLE CodeElement (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n contentEncoding STRING DEFAULT 'none',\n description STRING,\n PRIMARY KEY (id)\n)";
21
21
  export declare const COMMUNITY_SCHEMA = "\nCREATE NODE TABLE Community (\n id STRING,\n label STRING,\n heuristicLabel STRING,\n keywords STRING[],\n description STRING,\n enrichedBy STRING,\n cohesion DOUBLE,\n symbolCount INT32,\n PRIMARY KEY (id)\n)";
22
22
  export declare const PROCESS_SCHEMA = "\nCREATE NODE TABLE Process (\n id STRING,\n label STRING,\n heuristicLabel STRING,\n processType STRING,\n stepCount INT32,\n communities STRING[],\n entryPointId STRING,\n terminalId STRING,\n PRIMARY KEY (id)\n)";
23
+ export declare const FEATURE_CLUSTER_SCHEMA = "\nCREATE NODE TABLE FeatureCluster (\n id STRING,\n name STRING,\n slug STRING,\n featureKind STRING,\n summary STRING,\n description STRING,\n repo STRING,\n service STRING,\n signals STRING[],\n memberCount INT32,\n entryPointIds STRING[],\n routes STRING[],\n tools STRING[],\n testCoverageHints STRING[],\n lastIndexedCommit STRING,\n confidence DOUBLE,\n source STRING,\n PRIMARY KEY (id)\n)";
23
24
  export declare const STRUCT_SCHEMA: string;
24
25
  export declare const ENUM_SCHEMA: string;
25
26
  export declare const MACRO_SCHEMA: string;
@@ -42,7 +43,7 @@ export declare const MODULE_SCHEMA: string;
42
43
  export declare const ROUTE_SCHEMA = "\nCREATE NODE TABLE Route (\n id STRING,\n name STRING,\n filePath STRING,\n responseKeys STRING[],\n errorKeys STRING[],\n middleware STRING[],\n PRIMARY KEY (id)\n)";
43
44
  export declare const TOOL_SCHEMA = "\nCREATE NODE TABLE Tool (\n id STRING,\n name STRING,\n filePath STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
44
45
  export declare const SECTION_SCHEMA = "\nCREATE NODE TABLE Section (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n level INT64,\n content STRING,\n contentEncoding STRING DEFAULT 'none',\n description STRING,\n PRIMARY KEY (id)\n)";
45
- 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 `Variable`,\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 File TO Section,\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 Function TO `Property`,\n FROM Function TO CodeElement,\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 Class TO `Namespace`,\n FROM Class TO `Typedef`,\n FROM Class TO `Property`,\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 Method TO `Property`,\n FROM Method TO CodeElement,\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 Section TO Section,\n FROM Section TO File,\n FROM File TO Route,\n FROM Function TO Route,\n FROM Method TO Route,\n FROM File TO Tool,\n FROM Function TO Tool,\n FROM Method TO Tool,\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 Interface TO `Property`,\n FROM `Struct` TO Community,\n FROM `Struct` TO `Trait`,\n FROM `Struct` TO `Struct`,\n FROM `Struct` TO Class,\n FROM `Struct` TO `Enum`,\n FROM `Struct` TO Function,\n FROM `Struct` TO Method,\n FROM `Struct` TO Interface,\n FROM `Struct` TO `Constructor`,\n FROM `Struct` TO `Property`,\n FROM `Enum` TO `Enum`,\n FROM `Enum` TO Community,\n FROM `Enum` TO Class,\n FROM `Enum` TO Interface,\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 `Namespace` TO `Struct`,\n FROM `Trait` TO Method,\n FROM `Trait` TO `Constructor`,\n FROM `Trait` TO `Property`,\n FROM `Trait` TO Community,\n FROM `Impl` TO Method,\n FROM `Impl` TO `Constructor`,\n FROM `Impl` TO `Property`,\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 `TypeAlias` TO Class,\n FROM `Const` TO Community,\n FROM `Static` TO Community,\n FROM `Variable` TO Community,\n FROM `Property` TO Community,\n FROM `Record` TO Method,\n FROM `Record` TO `Constructor`,\n FROM `Record` TO `Property`,\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 `Constructor` TO `Property`,\n FROM `Constructor` TO `Typedef`,\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 `Variable` 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 FROM Route TO Process,\n FROM Tool TO Process,\n type STRING,\n confidence DOUBLE,\n reason STRING,\n step INT32\n)";
46
+ 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 `Variable`,\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 File TO Section,\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 Function TO `Property`,\n FROM Function TO CodeElement,\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 Class TO `Namespace`,\n FROM Class TO `Typedef`,\n FROM Class TO `Property`,\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 Method TO `Property`,\n FROM Method TO CodeElement,\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 Section TO Section,\n FROM Section TO File,\n FROM File TO Route,\n FROM Function TO Route,\n FROM Method TO Route,\n FROM File TO Tool,\n FROM Function TO Tool,\n FROM Method TO Tool,\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 Interface TO `Property`,\n FROM `Struct` TO Community,\n FROM `Struct` TO `Trait`,\n FROM `Struct` TO `Struct`,\n FROM `Struct` TO Class,\n FROM `Struct` TO `Enum`,\n FROM `Struct` TO Function,\n FROM `Struct` TO Method,\n FROM `Struct` TO Interface,\n FROM `Struct` TO `Constructor`,\n FROM `Struct` TO `Property`,\n FROM `Enum` TO `Enum`,\n FROM `Enum` TO Community,\n FROM `Enum` TO Class,\n FROM `Enum` TO Interface,\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 `Namespace` TO `Struct`,\n FROM `Trait` TO Method,\n FROM `Trait` TO `Constructor`,\n FROM `Trait` TO `Property`,\n FROM `Trait` TO Community,\n FROM `Impl` TO Method,\n FROM `Impl` TO `Constructor`,\n FROM `Impl` TO `Property`,\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 `TypeAlias` TO Class,\n FROM `Const` TO Community,\n FROM `Static` TO Community,\n FROM `Variable` TO Community,\n FROM `Property` TO Community,\n FROM `Record` TO Method,\n FROM `Record` TO `Constructor`,\n FROM `Record` TO `Property`,\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 `Constructor` TO `Property`,\n FROM `Constructor` TO `Typedef`,\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 `Variable` 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 FROM Route TO Process,\n FROM Tool TO Process,\n FROM File TO FeatureCluster,\n FROM Function TO FeatureCluster,\n FROM Method TO FeatureCluster,\n FROM Class TO FeatureCluster,\n FROM Interface TO FeatureCluster,\n FROM CodeElement TO FeatureCluster,\n FROM Section TO FeatureCluster,\n FROM Route TO FeatureCluster,\n FROM Tool TO FeatureCluster,\n FROM Process TO FeatureCluster,\n FROM `Struct` TO FeatureCluster,\n FROM `Enum` TO FeatureCluster,\n FROM `Macro` TO FeatureCluster,\n FROM `Typedef` TO FeatureCluster,\n FROM `Union` TO FeatureCluster,\n FROM `Namespace` TO FeatureCluster,\n FROM `Trait` TO FeatureCluster,\n FROM `Impl` TO FeatureCluster,\n FROM `TypeAlias` TO FeatureCluster,\n FROM `Const` TO FeatureCluster,\n FROM `Static` TO FeatureCluster,\n FROM `Variable` TO FeatureCluster,\n FROM `Property` TO FeatureCluster,\n FROM `Record` TO FeatureCluster,\n FROM `Delegate` TO FeatureCluster,\n FROM `Annotation` TO FeatureCluster,\n FROM `Constructor` TO FeatureCluster,\n FROM `Template` TO FeatureCluster,\n FROM `Module` TO FeatureCluster,\n FROM FeatureCluster TO FeatureCluster,\n type STRING,\n confidence DOUBLE,\n reason STRING,\n step INT32\n)";
46
47
  export declare const EMBEDDING_DIMS: number;
47
48
  /** HNSW vector index name for the CodeEmbedding table. */
48
49
  export declare const EMBEDDING_INDEX_NAME = "code_embedding_idx";
@@ -139,6 +139,30 @@ CREATE NODE TABLE Process (
139
139
  PRIMARY KEY (id)
140
140
  )`;
141
141
  // ============================================================================
142
+ // FEATURE CLUSTER NODE TABLE (human-facing feature/domain clusters)
143
+ // ============================================================================
144
+ export const FEATURE_CLUSTER_SCHEMA = `
145
+ CREATE NODE TABLE FeatureCluster (
146
+ id STRING,
147
+ name STRING,
148
+ slug STRING,
149
+ featureKind STRING,
150
+ summary STRING,
151
+ description STRING,
152
+ repo STRING,
153
+ service STRING,
154
+ signals STRING[],
155
+ memberCount INT32,
156
+ entryPointIds STRING[],
157
+ routes STRING[],
158
+ tools STRING[],
159
+ testCoverageHints STRING[],
160
+ lastIndexedCommit STRING,
161
+ confidence DOUBLE,
162
+ source STRING,
163
+ PRIMARY KEY (id)
164
+ )`;
165
+ // ============================================================================
142
166
  // MULTI-LANGUAGE NODE TABLE SCHEMAS
143
167
  // ============================================================================
144
168
  // Generic code element with startLine/endLine for C, C++, Rust, Go, Java, C#
@@ -417,6 +441,36 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
417
441
  FROM CodeElement TO Process,
418
442
  FROM Route TO Process,
419
443
  FROM Tool TO Process,
444
+ FROM File TO FeatureCluster,
445
+ FROM Function TO FeatureCluster,
446
+ FROM Method TO FeatureCluster,
447
+ FROM Class TO FeatureCluster,
448
+ FROM Interface TO FeatureCluster,
449
+ FROM CodeElement TO FeatureCluster,
450
+ FROM Section TO FeatureCluster,
451
+ FROM Route TO FeatureCluster,
452
+ FROM Tool TO FeatureCluster,
453
+ FROM Process TO FeatureCluster,
454
+ FROM \`Struct\` TO FeatureCluster,
455
+ FROM \`Enum\` TO FeatureCluster,
456
+ FROM \`Macro\` TO FeatureCluster,
457
+ FROM \`Typedef\` TO FeatureCluster,
458
+ FROM \`Union\` TO FeatureCluster,
459
+ FROM \`Namespace\` TO FeatureCluster,
460
+ FROM \`Trait\` TO FeatureCluster,
461
+ FROM \`Impl\` TO FeatureCluster,
462
+ FROM \`TypeAlias\` TO FeatureCluster,
463
+ FROM \`Const\` TO FeatureCluster,
464
+ FROM \`Static\` TO FeatureCluster,
465
+ FROM \`Variable\` TO FeatureCluster,
466
+ FROM \`Property\` TO FeatureCluster,
467
+ FROM \`Record\` TO FeatureCluster,
468
+ FROM \`Delegate\` TO FeatureCluster,
469
+ FROM \`Annotation\` TO FeatureCluster,
470
+ FROM \`Constructor\` TO FeatureCluster,
471
+ FROM \`Template\` TO FeatureCluster,
472
+ FROM \`Module\` TO FeatureCluster,
473
+ FROM FeatureCluster TO FeatureCluster,
420
474
  type STRING,
421
475
  confidence DOUBLE,
422
476
  reason STRING,
@@ -471,6 +525,7 @@ export const NODE_SCHEMA_QUERIES = [
471
525
  CODE_ELEMENT_SCHEMA,
472
526
  COMMUNITY_SCHEMA,
473
527
  PROCESS_SCHEMA,
528
+ FEATURE_CLUSTER_SCHEMA,
474
529
  // Multi-language support
475
530
  STRUCT_SCHEMA,
476
531
  ENUM_SCHEMA,
@@ -16,6 +16,7 @@ import { pipeline, env } from '@huggingface/transformers';
16
16
  import { existsSync } from 'fs';
17
17
  import { execFileSync } from 'child_process';
18
18
  import { join, dirname } from 'path';
19
+ import { homedir } from 'os';
19
20
  import { createRequire } from 'module';
20
21
  import { DEFAULT_EMBEDDING_CONFIG } from './types.js';
21
22
  import { isHttpMode, getHttpDimensions, httpEmbed } from './http-client.js';
@@ -134,8 +135,9 @@ export const initEmbedder = async (onProgress, config = {}, forceDevice) => {
134
135
  // Default cache to user-writable location. transformers.js defaults to
135
136
  // ./node_modules/.cache inside its own install dir, which is unwritable
136
137
  // when codragraph is installed globally (e.g. /usr/lib/node_modules/).
137
- // Respect HF_HOME if set, otherwise fall back to ~/.cache/huggingface.
138
- env.cacheDir = process.env.HF_HOME ?? `${process.env.HOME}/.cache/huggingface`;
138
+ // Respect HF_HOME if set, otherwise fall back to a user-writable cache
139
+ // path using Node's OS-aware home directory resolution.
140
+ env.cacheDir = process.env.HF_HOME ?? join(homedir(), '.cache', 'huggingface');
139
141
  const isDev = process.env.NODE_ENV === 'development';
140
142
  if (isDev) {
141
143
  console.log(`🧠 Loading embedding model: ${finalConfig.modelId}`);
@@ -26,7 +26,7 @@ export const createCgdbRowSource = (opts = {}) => {
26
26
  // `core/search/bm25-index.ts` for FTS results. Tables that do not
27
27
  // exist on disk for a given repo throw here — we treat that as
28
28
  // "no rows" via the onSkip callback rather than a hard failure.
29
- rows = await executeQuery(`MATCH (n:${tableName}) RETURN n`);
29
+ rows = await executeQuery(`MATCH (n:${quoteCypherIdentifier(tableName)}) RETURN n`);
30
30
  }
31
31
  catch (err) {
32
32
  onSkip(tableName, err);
@@ -55,7 +55,7 @@ export const createCgdbRowSource = (opts = {}) => {
55
55
  // `rel`. Scalars give us a deterministic edge id even if the rel
56
56
  // payload's shape changes; `rel` carries any extra properties for
57
57
  // hashing.
58
- rows = await executeQuery(`MATCH (a)-[r:${REL_TABLE_NAME}]->(b) RETURN a.id AS \`from\`, b.id AS \`to\`, r.type AS type, r AS rel`);
58
+ rows = await executeQuery(`MATCH (a)-[r:${quoteCypherIdentifier(REL_TABLE_NAME)}]->(b) RETURN a.id AS \`from\`, b.id AS \`to\`, r.type AS type, r AS rel`);
59
59
  }
60
60
  catch (err) {
61
61
  onSkip(REL_TABLE_NAME, err);
@@ -100,6 +100,7 @@ const pickField = (row, named, positional) => {
100
100
  return row[named] ?? row[positional];
101
101
  };
102
102
  const isPlainObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
103
+ const quoteCypherIdentifier = (identifier) => `\`${identifier.replace(/`/g, '``')}\``;
103
104
  /**
104
105
  * Sanitize a node row for canonical hashing:
105
106
  * - Drop LadybugDB-specific internal fields (`_id`, `_label`) that are
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Codragraph-side glue for the Phase 4 versioned graph store.
2
+ * CodraGraph-side glue for the Phase 4 versioned graph store.
3
3
  *
4
4
  * The graphstore package itself is engine-agnostic; everything that
5
5
  * touches LadybugDB lives here, in codragraph/. Best-effort by design:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Codragraph-side glue for the Phase 4 versioned graph store.
2
+ * CodraGraph-side glue for the Phase 4 versioned graph store.
3
3
  *
4
4
  * The graphstore package itself is engine-agnostic; everything that
5
5
  * touches LadybugDB lives here, in codragraph/. Best-effort by design:
@@ -74,7 +74,7 @@ export function findContractNode(index, repo, role, symbolUid, filePath, symbolN
74
74
  export async function openBridgeDb(dbPath) {
75
75
  const parentDir = path.dirname(dbPath);
76
76
  await fsp.mkdir(parentDir, { recursive: true });
77
- const db = new cgdb.Database(dbPath, 0, false, false); // writable
77
+ const db = new cgdb.Database(dbPath, 0, false, false, BRIDGE_MAX_DB_SIZE_BYTES); // writable
78
78
  const conn = new cgdb.Connection(db);
79
79
  return { _db: db, _conn: conn, groupDir: parentDir };
80
80
  }
@@ -238,6 +238,25 @@ export async function retryRename(src, dst, attempts = 3) {
238
238
  }
239
239
  }
240
240
  }
241
+ async function removeBridgeArtifacts(basePath) {
242
+ for (const candidate of [basePath, `${basePath}.wal`, `${basePath}.lock`]) {
243
+ try {
244
+ await fsp.rm(candidate, { recursive: true, force: true });
245
+ }
246
+ catch {
247
+ /* ignore */
248
+ }
249
+ }
250
+ }
251
+ async function renameBridgeArtifactIfExists(src, dst) {
252
+ try {
253
+ await fsp.access(src);
254
+ }
255
+ catch {
256
+ return;
257
+ }
258
+ await retryRename(src, dst);
259
+ }
241
260
  /* ------------------------------------------------------------------ */
242
261
  /* writeBridgeMeta / readBridgeMeta */
243
262
  /* ------------------------------------------------------------------ */
@@ -261,6 +280,10 @@ export async function readBridgeMeta(groupDir) {
261
280
  }
262
281
  }
263
282
  const MAX_SAMPLE_ERRORS = 10;
283
+ // LadybugDB defaults maxDBSize to an 8 TiB mmap window on some platforms.
284
+ // Bridge databases are small contract registries, so cap the mapping to keep
285
+ // CI and low-resource user machines from failing before the first query.
286
+ const BRIDGE_MAX_DB_SIZE_BYTES = 512 * 1024 * 1024;
264
287
  function errMessage(err) {
265
288
  if (err instanceof Error)
266
289
  return err.message;
@@ -293,13 +316,9 @@ export async function writeBridge(groupDir, input) {
293
316
  report.sampleErrors.push({ kind, id, message: errMessage(err) });
294
317
  }
295
318
  };
296
- // Clean up any leftover tmp
297
- try {
298
- await fsp.rm(tmpPath, { recursive: true, force: true });
299
- }
300
- catch {
301
- /* ignore */
302
- }
319
+ // Clean up any leftover tmp plus native sidecars. LadybugDB stores WAL/lock
320
+ // files next to the database path, not inside it.
321
+ await removeBridgeArtifacts(tmpPath);
303
322
  // 1. Create temp DB, insert all data.
304
323
  //
305
324
  // Everything after `openBridgeDb` must run inside a try/finally so that
@@ -440,16 +459,27 @@ export async function writeBridge(groupDir, input) {
440
459
  }
441
460
  }
442
461
  // 3. Atomic swap: old→.bak, tmp→final, rm .bak
462
+ // Keep LadybugDB sidecars paired with the path rename. WAL files live next
463
+ // to the DB path, so renaming only the base path can hide fresh schema/data.
464
+ await removeBridgeArtifacts(bakPath);
443
465
  try {
444
466
  await fsp.access(finalPath);
445
467
  await retryRename(finalPath, bakPath);
468
+ await renameBridgeArtifactIfExists(`${finalPath}.wal`, `${bakPath}.wal`);
446
469
  }
447
470
  catch {
448
471
  /* no existing db */
449
472
  }
450
473
  await retryRename(tmpPath, finalPath);
474
+ await renameBridgeArtifactIfExists(`${tmpPath}.wal`, `${finalPath}.wal`);
475
+ try {
476
+ await fsp.rm(`${tmpPath}.lock`, { force: true });
477
+ }
478
+ catch {
479
+ /* ignore */
480
+ }
451
481
  try {
452
- await fsp.rm(bakPath, { recursive: true, force: true });
482
+ await removeBridgeArtifacts(bakPath);
453
483
  }
454
484
  catch {
455
485
  /* ignore */
@@ -480,6 +510,8 @@ export async function openBridgeDbReadOnly(groupDir) {
480
510
  try {
481
511
  await fsp.access(bakPath);
482
512
  await retryRename(bakPath, dbPath);
513
+ await renameBridgeArtifactIfExists(`${bakPath}.wal`, `${dbPath}.wal`);
514
+ await fsp.rm(`${bakPath}.lock`, { force: true });
483
515
  }
484
516
  catch {
485
517
  return null;
@@ -506,7 +538,7 @@ export async function openBridgeDbReadOnly(groupDir) {
506
538
  let db;
507
539
  let conn;
508
540
  try {
509
- db = new cgdb.Database(dbPath, 0, false, true); // readOnly
541
+ db = new cgdb.Database(dbPath, 0, false, true, BRIDGE_MAX_DB_SIZE_BYTES); // readOnly
510
542
  conn = new cgdb.Connection(db);
511
543
  return { _db: db, _conn: conn, groupDir };
512
544
  }
@@ -41,6 +41,19 @@ export interface GroupToolPort {
41
41
  file_path?: string;
42
42
  include_content?: boolean;
43
43
  }): Promise<unknown>;
44
+ featureClusters?(repo: GroupRepoHandle, params: {
45
+ query?: string;
46
+ limit?: number;
47
+ }): Promise<unknown>;
48
+ featureContext?(repo: GroupRepoHandle, params: {
49
+ name: string;
50
+ limit?: number;
51
+ }): Promise<unknown>;
52
+ featureImpact?(repo: GroupRepoHandle, params: {
53
+ name: string;
54
+ direction?: 'upstream' | 'downstream' | 'both';
55
+ limit?: number;
56
+ }): Promise<unknown>;
44
57
  }
45
58
  export declare class GroupService {
46
59
  private readonly port;
@@ -51,5 +64,8 @@ export declare class GroupService {
51
64
  groupImpact(params: Record<string, unknown>): Promise<unknown>;
52
65
  groupContext(params: Record<string, unknown>): Promise<GroupContextResult>;
53
66
  groupQuery(params: Record<string, unknown>): Promise<unknown>;
67
+ groupFeatureClusters(params: Record<string, unknown>): Promise<unknown>;
68
+ groupFeatureContext(params: Record<string, unknown>): Promise<unknown>;
69
+ groupFeatureImpact(params: Record<string, unknown>): Promise<unknown>;
54
70
  groupStatus(params: Record<string, unknown>): Promise<unknown>;
55
71
  }