@codragraph/cli 1.6.3 → 2.0.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.
Files changed (89) hide show
  1. package/README.md +50 -16
  2. package/dist/cli/ai-context.js +2 -2
  3. package/dist/cli/analyze.d.ts +22 -0
  4. package/dist/cli/analyze.js +111 -8
  5. package/dist/cli/compress-stats.d.ts +29 -0
  6. package/dist/cli/compress-stats.js +97 -0
  7. package/dist/cli/graphstore.d.ts +6 -2
  8. package/dist/cli/graphstore.js +24 -2
  9. package/dist/cli/index.js +17 -6
  10. package/dist/cli/profile-heap.d.ts +35 -0
  11. package/dist/cli/profile-heap.js +126 -0
  12. package/dist/cli/setup.d.ts +13 -0
  13. package/dist/cli/setup.js +75 -29
  14. package/dist/cli/skill-gen.d.ts +14 -2
  15. package/dist/cli/skill-gen.js +53 -20
  16. package/dist/cli/tool.js +4 -0
  17. package/dist/config/ignore-service.js +1 -1
  18. package/dist/core/embeddings/embedding-pipeline.js +24 -7
  19. package/dist/core/group/bridge-db.js +111 -24
  20. package/dist/core/group/extractors/grpc-patterns/proto.js +1 -12
  21. package/dist/core/ingestion/call-processor.js +2 -2
  22. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1 -1
  23. package/dist/core/ingestion/cobol/jcl-parser.d.ts +1 -1
  24. package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
  25. package/dist/core/ingestion/cobol-processor.d.ts +1 -1
  26. package/dist/core/ingestion/cobol-processor.js +1 -1
  27. package/dist/core/ingestion/heritage-extractors/generic.js +1 -1
  28. package/dist/core/ingestion/heritage-processor.js +1 -1
  29. package/dist/core/ingestion/import-processor.js +1 -1
  30. package/dist/core/ingestion/mro-processor.js +1 -1
  31. package/dist/core/ingestion/parsing-processor.js +1 -1
  32. package/dist/core/ingestion/type-extractors/c-cpp.js +1 -1
  33. package/dist/core/ingestion/type-extractors/python.js +1 -1
  34. package/dist/core/ingestion/type-extractors/shared.js +0 -3
  35. package/dist/core/lbug/content-read.d.ts +46 -0
  36. package/dist/core/lbug/content-read.js +64 -0
  37. package/dist/core/lbug/csv-generator.d.ts +2 -6
  38. package/dist/core/lbug/csv-generator.js +45 -12
  39. package/dist/core/lbug/lbug-adapter.d.ts +4 -1
  40. package/dist/core/lbug/lbug-adapter.js +157 -25
  41. package/dist/core/lbug/pool-adapter.js +51 -44
  42. package/dist/core/lbug/schema.d.ts +7 -7
  43. package/dist/core/lbug/schema.js +18 -0
  44. package/dist/core/run-analyze.d.ts +13 -0
  45. package/dist/core/run-analyze.js +91 -4
  46. package/dist/core/search/bm25-index.js +153 -12
  47. package/dist/core/wiki/generator.js +4 -4
  48. package/dist/mcp/local/local-backend.js +22 -5
  49. package/dist/mcp/resources.js +2 -3
  50. package/dist/server/api.js +4 -3
  51. package/dist/storage/repo-manager.d.ts +39 -0
  52. package/dist/storage/repo-manager.js +19 -0
  53. package/hooks/claude/codragraph-hook.cjs +108 -5
  54. package/hooks/claude/pre-tool-use.sh +6 -1
  55. package/package.json +4 -4
  56. package/scripts/build-tree-sitter-proto.cjs +15 -3
  57. package/scripts/patch-tree-sitter-swift.cjs +17 -4
  58. package/skills/codragraph-api-surface.md +110 -0
  59. package/skills/codragraph-cli.md +5 -5
  60. package/skills/codragraph-config-audit.md +146 -0
  61. package/skills/codragraph-cross-repo-impact.md +135 -0
  62. package/skills/codragraph-data-lineage.md +137 -0
  63. package/skills/codragraph-dead-code.md +119 -0
  64. package/skills/codragraph-debugging.md +1 -1
  65. package/skills/codragraph-exploring.md +1 -1
  66. package/skills/codragraph-gh-actions-debug.md +162 -0
  67. package/skills/codragraph-gh-issue-workflow.md +178 -0
  68. package/skills/codragraph-gh-pr-workflow.md +176 -0
  69. package/skills/codragraph-gh-release-workflow.md +187 -0
  70. package/skills/codragraph-git-bisect.md +176 -0
  71. package/skills/codragraph-git-force-push.md +147 -0
  72. package/skills/codragraph-git-history-rewrite.md +174 -0
  73. package/skills/codragraph-git-rebase-vs-merge.md +138 -0
  74. package/skills/codragraph-git-recovery.md +181 -0
  75. package/skills/codragraph-git-worktree.md +145 -0
  76. package/skills/codragraph-guide.md +1 -1
  77. package/skills/codragraph-impact-analysis.md +1 -1
  78. package/skills/codragraph-migration-tracking.md +130 -0
  79. package/skills/codragraph-notebook-context.md +136 -0
  80. package/skills/codragraph-observability-coverage.md +125 -0
  81. package/skills/codragraph-onboarding.md +129 -0
  82. package/skills/codragraph-perf-hotspots.md +132 -0
  83. package/skills/codragraph-pr-review.md +1 -1
  84. package/skills/codragraph-project-switcher.md +116 -0
  85. package/skills/codragraph-refactoring.md +1 -1
  86. package/skills/codragraph-security-audit.md +144 -0
  87. package/skills/codragraph-sql-tracing.md +122 -0
  88. package/skills/codragraph-supply-chain-audit.md +153 -0
  89. package/skills/codragraph-test-coverage.md +97 -0
@@ -1,6 +1,7 @@
1
1
  import lbug from '@ladybugdb/core';
2
2
  import { KnowledgeGraph } from '../graph/types.js';
3
3
  import type { CachedEmbedding } from '../embeddings/types.js';
4
+ import type { ContentEncoding } from '@codragraph/graphstore';
4
5
  /** Factory for creating WriteStreams — injectable for testing. */
5
6
  export type WriteStreamFactory = (filePath: string) => import('fs').WriteStream;
6
7
  /** Result of splitting the relationship CSV into per-label-pair files. */
@@ -51,7 +52,9 @@ export declare const initLbug: (dbPath: string) => Promise<{
51
52
  */
52
53
  export declare const withLbugDb: <T>(dbPath: string, operation: () => Promise<T>) => Promise<T>;
53
54
  export type LbugProgressCallback = (message: string) => void;
54
- export declare const loadGraphToLbug: (graph: KnowledgeGraph, repoPath: string, storagePath: string, onProgress?: LbugProgressCallback) => Promise<{
55
+ export declare const loadGraphToLbug: (graph: KnowledgeGraph, repoPath: string, storagePath: string, onProgress?: LbugProgressCallback, options?: {
56
+ compress?: ContentEncoding;
57
+ }) => Promise<{
55
58
  success: boolean;
56
59
  insertedRels: number;
57
60
  skippedRels: number;
@@ -276,7 +276,7 @@ const doInitLbug = async (dbPath) => {
276
276
  const parentDir = path.dirname(dbPath);
277
277
  await fs.mkdir(parentDir, { recursive: true });
278
278
  db = new lbug.Database(dbPath);
279
- conn = new lbug.Connection(db);
279
+ conn = trackConnection(new lbug.Connection(db));
280
280
  for (const schemaQuery of SCHEMA_QUERIES) {
281
281
  try {
282
282
  await conn.query(schemaQuery);
@@ -294,14 +294,14 @@ const doInitLbug = async (dbPath) => {
294
294
  currentDbPath = dbPath;
295
295
  return { db, conn };
296
296
  };
297
- export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress) => {
297
+ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress, options) => {
298
298
  if (!conn) {
299
299
  throw new Error('LadybugDB not initialized. Call initLbug first.');
300
300
  }
301
301
  const log = onProgress || (() => { });
302
302
  const csvDir = path.join(storagePath, 'csv');
303
303
  log('Streaming CSVs to disk...');
304
- const csvResult = await streamAllCSVsToDisk(graph, repoPath, csvDir);
304
+ const csvResult = await streamAllCSVsToDisk(graph, repoPath, csvDir, options?.compress);
305
305
  const validTables = new Set(NODE_TABLES);
306
306
  const getNodeLabel = (nodeId) => {
307
307
  if (nodeId.startsWith('comm_'))
@@ -322,7 +322,7 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
322
322
  try {
323
323
  await conn.query(copyQuery);
324
324
  }
325
- catch (err) {
325
+ catch (_err) {
326
326
  try {
327
327
  const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
328
328
  await conn.query(retryQuery);
@@ -360,7 +360,7 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
360
360
  try {
361
361
  await conn.query(copyQuery);
362
362
  }
363
- catch (err) {
363
+ catch (_err) {
364
364
  try {
365
365
  const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
366
366
  await conn.query(retryQuery);
@@ -504,8 +504,12 @@ const TABLES_WITH_EXPORTED = new Set([
504
504
  ]);
505
505
  const getCopyQuery = (table, filePath) => {
506
506
  const t = escapeTableName(table);
507
+ // RFC 0001 Phase 2: every content-bearing table also lists
508
+ // `contentEncoding` immediately after `content` to match the schema +
509
+ // CSV layout. Tables without a content column (Folder, Community,
510
+ // Process, Route, Tool) are unchanged.
507
511
  if (table === 'File') {
508
- return `COPY ${t}(id, name, filePath, content) FROM "${filePath}" ${COPY_CSV_OPTS}`;
512
+ return `COPY ${t}(id, name, filePath, content, contentEncoding) FROM "${filePath}" ${COPY_CSV_OPTS}`;
509
513
  }
510
514
  if (table === 'Folder') {
511
515
  return `COPY ${t}(id, name, filePath) FROM "${filePath}" ${COPY_CSV_OPTS}`;
@@ -517,7 +521,7 @@ const getCopyQuery = (table, filePath) => {
517
521
  return `COPY ${t}(id, label, heuristicLabel, processType, stepCount, communities, entryPointId, terminalId) FROM "${filePath}" ${COPY_CSV_OPTS}`;
518
522
  }
519
523
  if (table === 'Section') {
520
- return `COPY ${t}(id, name, filePath, startLine, endLine, level, content, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
524
+ return `COPY ${t}(id, name, filePath, startLine, endLine, level, content, contentEncoding, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
521
525
  }
522
526
  if (table === 'Route') {
523
527
  return `COPY ${t}(id, name, filePath, responseKeys, errorKeys, middleware) FROM "${filePath}" ${COPY_CSV_OPTS}`;
@@ -526,14 +530,14 @@ const getCopyQuery = (table, filePath) => {
526
530
  return `COPY ${t}(id, name, filePath, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
527
531
  }
528
532
  if (table === 'Method') {
529
- return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content, description, parameterCount, returnType) FROM "${filePath}" ${COPY_CSV_OPTS}`;
533
+ return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content, contentEncoding, description, parameterCount, returnType) FROM "${filePath}" ${COPY_CSV_OPTS}`;
530
534
  }
531
535
  // TypeScript/JS code element tables have isExported; multi-language tables do not
532
536
  if (TABLES_WITH_EXPORTED.has(table)) {
533
- return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
537
+ return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content, contentEncoding, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
534
538
  }
535
539
  // Multi-language tables (Struct, Impl, Trait, Macro, etc.)
536
- return `COPY ${t}(id, name, filePath, startLine, endLine, content, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
540
+ return `COPY ${t}(id, name, filePath, startLine, endLine, content, contentEncoding, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
537
541
  };
538
542
  /**
539
543
  * Insert a single node to LadybugDB
@@ -587,9 +591,10 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
587
591
  // Use per-query connection if dbPath provided (avoids lock conflicts)
588
592
  if (targetDbPath) {
589
593
  const tempDb = new lbug.Database(targetDbPath);
590
- const tempConn = new lbug.Connection(tempDb);
594
+ const tempConn = trackConnection(new lbug.Connection(tempDb));
591
595
  try {
592
- await tempConn.query(query);
596
+ const qr = await tempConn.query(query);
597
+ await closeQueryResult(qr);
593
598
  return true;
594
599
  }
595
600
  finally {
@@ -635,7 +640,7 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
635
640
  };
636
641
  // Open a single connection for all inserts
637
642
  const tempDb = new lbug.Database(dbPath);
638
- const tempConn = new lbug.Connection(tempDb);
643
+ const tempConn = trackConnection(new lbug.Connection(tempDb));
639
644
  let inserted = 0;
640
645
  let failed = 0;
641
646
  try {
@@ -671,7 +676,7 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
671
676
  await tempConn.query(query);
672
677
  inserted++;
673
678
  }
674
- catch (e) {
679
+ catch (_e) {
675
680
  // Don't console.error here - it corrupts MCP JSON-RPC on stderr
676
681
  failed++;
677
682
  }
@@ -689,6 +694,83 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
689
694
  }
690
695
  return { inserted, failed };
691
696
  };
697
+ /**
698
+ * Track every live QueryResult / PreparedStatement returned by the
699
+ * connection, and force-close them in `closeLbug()` BEFORE `conn.close()`
700
+ * runs.
701
+ *
702
+ * Why this exists: per upstream Kuzu issue #5316 the close-order is
703
+ * QueryResult & PreparedStatement → Connection → Database
704
+ * Leaking any of these to GC means V8 finalizes the native handles AFTER
705
+ * `db.close()` has run, which corrupts memory and segfaults the process
706
+ * at exit (Windows: 0xC0000005, Linux: SIGSEGV). Kuzu was archived
707
+ * 2025-10-10 and LadybugDB inherits the same C++ core, so the
708
+ * close-discipline is on us — neither upstream is going to ship a fix.
709
+ *
710
+ * Per-call-site close (the `try/finally { closeQueryResult }` blocks
711
+ * below) handles the happy path. The tracking Set is a backstop for any
712
+ * call site that forgets, AND for the fire-and-forget DDL / COPY /
713
+ * extension-load queries that drop the QueryResult on the floor.
714
+ */
715
+ const liveLbugHandles = new Set();
716
+ const closeQueryResult = async (qr) => {
717
+ if (!qr)
718
+ return;
719
+ const candidates = Array.isArray(qr) ? qr : [qr];
720
+ for (const r of candidates) {
721
+ liveLbugHandles.delete(r);
722
+ try {
723
+ const close = r?.close;
724
+ if (typeof close === 'function')
725
+ await Promise.resolve(close.call(r));
726
+ }
727
+ catch {
728
+ /* best-effort */
729
+ }
730
+ }
731
+ };
732
+ const closeStmt = async (stmt) => {
733
+ if (!stmt)
734
+ return;
735
+ liveLbugHandles.delete(stmt);
736
+ try {
737
+ const close = stmt?.close;
738
+ if (typeof close === 'function')
739
+ await Promise.resolve(close.call(stmt));
740
+ }
741
+ catch {
742
+ /* best-effort */
743
+ }
744
+ };
745
+ /**
746
+ * Wrap `conn.query` and `conn.execute` to register every returned
747
+ * QueryResult in the live-handle tracker. PreparedStatements from
748
+ * `conn.prepare` are tracked the same way. Idempotent — safe to call
749
+ * twice on the same Connection.
750
+ */
751
+ const trackConnection = (rawConn) => {
752
+ const c = rawConn;
753
+ if (c.__lbugTracked)
754
+ return rawConn;
755
+ c.__lbugTracked = true;
756
+ const wrap = (orig) => async function (...args) {
757
+ const qr = await orig.apply(this, args);
758
+ if (qr && typeof qr === 'object') {
759
+ if (Array.isArray(qr))
760
+ qr.forEach((r) => r && liveLbugHandles.add(r));
761
+ else
762
+ liveLbugHandles.add(qr);
763
+ }
764
+ return qr;
765
+ };
766
+ if (typeof c.query === 'function')
767
+ c.query = wrap(c.query);
768
+ if (typeof c.execute === 'function')
769
+ c.execute = wrap(c.execute);
770
+ if (typeof c.prepare === 'function')
771
+ c.prepare = wrap(c.prepare);
772
+ return rawConn;
773
+ };
692
774
  export const executeQuery = async (cypher) => {
693
775
  if (!conn) {
694
776
  throw new Error('LadybugDB not initialized. Call initLbug first.');
@@ -697,8 +779,12 @@ export const executeQuery = async (cypher) => {
697
779
  // LadybugDB uses getAll() instead of hasNext()/getNext()
698
780
  // Query returns QueryResult for single queries, QueryResult[] for multi-statement
699
781
  const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
700
- const rows = await result.getAll();
701
- return rows;
782
+ try {
783
+ return await result.getAll();
784
+ }
785
+ finally {
786
+ await closeQueryResult(queryResult);
787
+ }
702
788
  };
703
789
  export const streamQuery = async (cypher, onRow) => {
704
790
  if (!conn) {
@@ -735,11 +821,18 @@ export const executePrepared = async (cypher, params) => {
735
821
  const stmt = await conn.prepare(cypher);
736
822
  if (!stmt.isSuccess()) {
737
823
  const errMsg = await stmt.getErrorMessage();
824
+ await closeStmt(stmt);
738
825
  throw new Error(`Prepare failed: ${errMsg}`);
739
826
  }
740
827
  const queryResult = await conn.execute(stmt, params);
741
828
  const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
742
- return await result.getAll();
829
+ try {
830
+ return await result.getAll();
831
+ }
832
+ finally {
833
+ await closeQueryResult(queryResult);
834
+ await closeStmt(stmt);
835
+ }
743
836
  };
744
837
  export const executeWithReusedStatement = async (cypher, paramsList) => {
745
838
  if (!conn) {
@@ -753,18 +846,27 @@ export const executeWithReusedStatement = async (cypher, paramsList) => {
753
846
  const stmt = await conn.prepare(cypher);
754
847
  if (!stmt.isSuccess()) {
755
848
  const errMsg = await stmt.getErrorMessage();
849
+ await closeStmt(stmt);
756
850
  throw new Error(`Prepare failed: ${errMsg}`);
757
851
  }
758
852
  try {
759
853
  for (const params of subBatch) {
760
- await conn.execute(stmt, params);
854
+ // `conn.execute` returns a QueryResult — close it as soon as
855
+ // we don't need its rows. Old code dropped the reference to GC,
856
+ // which is what segfaulted the process at exit on Windows
857
+ // (Kuzu issue #5316: QueryResult & PreparedStatement → Connection
858
+ // → Database close-order is required for native-binding safety).
859
+ const qr = await conn.execute(stmt, params);
860
+ await closeQueryResult(qr);
761
861
  }
762
862
  }
763
863
  catch (e) {
764
864
  // Log the error and continue with next batch
765
865
  console.warn('Batch execution error:', e);
766
866
  }
767
- // Note: LadybugDB PreparedStatement doesn't require explicit close()
867
+ finally {
868
+ await closeStmt(stmt);
869
+ }
768
870
  }
769
871
  };
770
872
  export const getLbugStats = async () => {
@@ -772,8 +874,9 @@ export const getLbugStats = async () => {
772
874
  return { nodes: 0, edges: 0 };
773
875
  let totalNodes = 0;
774
876
  for (const tableName of NODE_TABLES) {
877
+ let queryResult;
775
878
  try {
776
- const queryResult = await conn.query(`MATCH (n:${escapeTableName(tableName)}) RETURN count(n) AS cnt`);
879
+ queryResult = await conn.query(`MATCH (n:${escapeTableName(tableName)}) RETURN count(n) AS cnt`);
777
880
  const nodeResult = Array.isArray(queryResult) ? queryResult[0] : queryResult;
778
881
  const nodeRows = await nodeResult.getAll();
779
882
  if (nodeRows.length > 0) {
@@ -783,11 +886,15 @@ export const getLbugStats = async () => {
783
886
  catch {
784
887
  // ignore
785
888
  }
889
+ finally {
890
+ await closeQueryResult(queryResult);
891
+ }
786
892
  }
787
893
  let totalEdges = 0;
894
+ let edgeQueryResult;
788
895
  try {
789
- const queryResult = await conn.query(`MATCH ()-[r:${REL_TABLE_NAME}]->() RETURN count(r) AS cnt`);
790
- const edgeResult = Array.isArray(queryResult) ? queryResult[0] : queryResult;
896
+ edgeQueryResult = await conn.query(`MATCH ()-[r:${REL_TABLE_NAME}]->() RETURN count(r) AS cnt`);
897
+ const edgeResult = Array.isArray(edgeQueryResult) ? edgeQueryResult[0] : edgeQueryResult;
791
898
  const edgeRows = await edgeResult.getAll();
792
899
  if (edgeRows.length > 0) {
793
900
  totalEdges = Number(edgeRows[0]?.cnt ?? edgeRows[0]?.[0] ?? 0);
@@ -796,6 +903,9 @@ export const getLbugStats = async () => {
796
903
  catch {
797
904
  // ignore
798
905
  }
906
+ finally {
907
+ await closeQueryResult(edgeQueryResult);
908
+ }
799
909
  return { nodes: totalNodes, edges: totalEdges };
800
910
  };
801
911
  /**
@@ -929,6 +1039,24 @@ export const fetchExistingEmbeddingHashes = async (execQuery) => {
929
1039
  }
930
1040
  };
931
1041
  export const closeLbug = async () => {
1042
+ // Drain every live QueryResult / PreparedStatement BEFORE closing the
1043
+ // Connection or the Database. Required by upstream Kuzu (#5316) — the
1044
+ // close-order is `QueryResult/PreparedStatement → Connection → Database`,
1045
+ // and any outstanding handle held when `db.close()` runs corrupts memory
1046
+ // and crashes the process at exit (Windows: 0xC0000005, POSIX: SIGSEGV).
1047
+ // Snapshot the Set so concurrent close() calls don't deadlock the iteration.
1048
+ const handles = Array.from(liveLbugHandles);
1049
+ liveLbugHandles.clear();
1050
+ for (const h of handles) {
1051
+ try {
1052
+ const close = h?.close;
1053
+ if (typeof close === 'function')
1054
+ await Promise.resolve(close.call(h));
1055
+ }
1056
+ catch {
1057
+ /* best-effort */
1058
+ }
1059
+ }
932
1060
  if (conn) {
933
1061
  try {
934
1062
  await conn.close();
@@ -963,7 +1091,7 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
963
1091
  let targetConn = conn;
964
1092
  if (usePerQuery) {
965
1093
  tempDb = new lbug.Database(dbPath);
966
- tempConn = new lbug.Connection(tempDb);
1094
+ tempConn = trackConnection(new lbug.Connection(tempDb));
967
1095
  targetConn = tempConn;
968
1096
  }
969
1097
  else if (!conn) {
@@ -991,7 +1119,7 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
991
1119
  deletedNodes += count;
992
1120
  }
993
1121
  }
994
- catch (e) {
1122
+ catch (_e) {
995
1123
  // Some tables may not support this query, skip
996
1124
  }
997
1125
  }
@@ -1148,8 +1276,9 @@ export const queryFTS = async (tableName, indexName, query, limit = 20, conjunct
1148
1276
  ORDER BY score DESC
1149
1277
  LIMIT ${limit}
1150
1278
  `;
1279
+ let queryResult;
1151
1280
  try {
1152
- const queryResult = await conn.query(cypher);
1281
+ queryResult = await conn.query(cypher);
1153
1282
  const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
1154
1283
  const rows = await result.getAll();
1155
1284
  return rows.map((row) => {
@@ -1171,6 +1300,9 @@ export const queryFTS = async (tableName, indexName, query, limit = 20, conjunct
1171
1300
  }
1172
1301
  throw e;
1173
1302
  }
1303
+ finally {
1304
+ await closeQueryResult(queryResult);
1305
+ }
1174
1306
  };
1175
1307
  /**
1176
1308
  * Drop an FTS index
@@ -280,29 +280,18 @@ async function doInitLbug(repoId, dbPath) {
280
280
  finally {
281
281
  preWarmActive = false;
282
282
  }
283
- // Load FTS extension once per shared Database.
284
- // Done BEFORE pool registration so no concurrent checkout can grab
285
- // the connection while the async FTS load is in progress.
286
- if (!shared.ftsLoaded) {
287
- try {
288
- await available[0].query('LOAD EXTENSION fts');
289
- shared.ftsLoaded = true;
290
- }
291
- catch {
292
- // Extension may not be installed FTS queries will fail gracefully
293
- }
294
- }
295
- // Load VECTOR extension once per shared Database for semantic search support.
296
- if (!shared.vectorLoaded) {
297
- try {
298
- await available[0].query('INSTALL VECTOR');
299
- await available[0].query('LOAD EXTENSION VECTOR');
300
- shared.vectorLoaded = true;
301
- }
302
- catch {
303
- // VECTOR extension may not be available
304
- }
305
- }
283
+ // Load FTS + VECTOR extensions on EVERY connection in the pool.
284
+ //
285
+ // CRITICAL: LadybugDB's extension state is per-connection on macOS (and
286
+ // possibly other platforms) — loading on `available[0]` does NOT propagate
287
+ // to the other connections. Since checkout pops from the end of the array,
288
+ // queries would otherwise hit unloaded connections and `QUERY_FTS_INDEX`
289
+ // would silently return 0 rows (catch in queryFTSViaExecutor swallows the
290
+ // "extension not loaded" error). That broke every search on macOS.
291
+ //
292
+ // Load on all connections concurrently, but BEFORE the pool is registered
293
+ // so no checkout can race the load.
294
+ await loadExtensionsOnConnections(available, shared);
306
295
  // Register pool entry only after all connections are pre-warmed and FTS is
307
296
  // loaded. Concurrent executeQuery calls see either "not initialized"
308
297
  // (and throw cleanly) or a fully ready pool — never a half-built one.
@@ -317,6 +306,42 @@ async function doInitLbug(repoId, dbPath) {
317
306
  });
318
307
  ensureIdleTimer();
319
308
  }
309
+ /**
310
+ * Load FTS + VECTOR extensions on every connection in the pool.
311
+ * Per-connection load is required because LadybugDB's extension state is
312
+ * not always shared across connections of the same Database (observed on
313
+ * macOS native bindings — silent FTS failures otherwise).
314
+ */
315
+ async function loadExtensionsOnConnections(conns, shared) {
316
+ // FTS: every connection needs `LOAD EXTENSION fts` independently.
317
+ await Promise.all(conns.map(async (c) => {
318
+ try {
319
+ await c.query('LOAD EXTENSION fts');
320
+ }
321
+ catch {
322
+ // already-loaded / not-installed — FTS queries fail gracefully if missing
323
+ }
324
+ }));
325
+ shared.ftsLoaded = true;
326
+ // VECTOR: install once on the Database (idempotent), then LOAD on every
327
+ // connection. INSTALL is a no-op after the first call but we run it on
328
+ // conn[0] to guarantee the package is present before fanning out LOADs.
329
+ try {
330
+ await conns[0].query('INSTALL VECTOR');
331
+ }
332
+ catch {
333
+ /* not available — semantic search will be a no-op */
334
+ }
335
+ await Promise.all(conns.map(async (c) => {
336
+ try {
337
+ await c.query('LOAD EXTENSION VECTOR');
338
+ }
339
+ catch {
340
+ /* not available — semantic search will be a no-op */
341
+ }
342
+ }));
343
+ shared.vectorLoaded = true;
344
+ }
320
345
  /**
321
346
  * Initialize a pool entry from a pre-existing Database object.
322
347
  *
@@ -354,27 +379,9 @@ export async function initLbugWithDb(repoId, existingDb, dbPath) {
354
379
  finally {
355
380
  preWarmActive = false;
356
381
  }
357
- // Load FTS extension if not already loaded on this Database
358
- if (!shared.ftsLoaded) {
359
- try {
360
- await available[0].query('LOAD EXTENSION fts');
361
- shared.ftsLoaded = true;
362
- }
363
- catch {
364
- // Extension may already be loaded or not installed
365
- }
366
- }
367
- // Load VECTOR extension for semantic search support
368
- if (!shared.vectorLoaded) {
369
- try {
370
- await available[0].query('INSTALL VECTOR');
371
- await available[0].query('LOAD EXTENSION VECTOR');
372
- shared.vectorLoaded = true;
373
- }
374
- catch {
375
- // VECTOR extension may not be available
376
- }
377
- }
382
+ // Load FTS + VECTOR on every connection (see loadExtensionsOnConnections
383
+ // for why per-connection load is required on macOS native bindings).
384
+ await loadExtensionsOnConnections(available, shared);
378
385
  pool.set(repoId, {
379
386
  db: existingDb,
380
387
  available,
@@ -11,13 +11,13 @@
11
11
  import { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME } from '../../_shared/index.js';
12
12
  export { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME };
13
13
  export type { NodeTableName, RelType } from '../../_shared/index.js';
14
- export declare const FILE_SCHEMA = "\nCREATE NODE TABLE File (\n id STRING,\n name STRING,\n filePath STRING,\n content STRING,\n PRIMARY KEY (id)\n)";
14
+ export declare const FILE_SCHEMA = "\nCREATE NODE TABLE File (\n id STRING,\n name STRING,\n filePath STRING,\n content STRING,\n contentEncoding STRING DEFAULT 'none',\n PRIMARY KEY (id)\n)";
15
15
  export declare const FOLDER_SCHEMA = "\nCREATE NODE TABLE Folder (\n id STRING,\n name STRING,\n filePath STRING,\n PRIMARY KEY (id)\n)";
16
- export declare const FUNCTION_SCHEMA = "\nCREATE NODE TABLE Function (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
17
- export declare const CLASS_SCHEMA = "\nCREATE NODE TABLE Class (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
18
- export declare const INTERFACE_SCHEMA = "\nCREATE NODE TABLE Interface (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
19
- export declare const METHOD_SCHEMA = "\nCREATE NODE TABLE Method (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n parameterCount INT32,\n returnType STRING,\n PRIMARY KEY (id)\n)";
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 description STRING,\n PRIMARY KEY (id)\n)";
16
+ export declare const FUNCTION_SCHEMA = "\nCREATE NODE TABLE Function (\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)";
17
+ export declare const CLASS_SCHEMA = "\nCREATE NODE TABLE Class (\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)";
18
+ export declare const INTERFACE_SCHEMA = "\nCREATE NODE TABLE Interface (\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)";
19
+ export declare const METHOD_SCHEMA = "\nCREATE NODE TABLE Method (\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 parameterCount INT32,\n returnType STRING,\n PRIMARY KEY (id)\n)";
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
23
  export declare const STRUCT_SCHEMA: string;
@@ -41,7 +41,7 @@ export declare const TEMPLATE_SCHEMA: string;
41
41
  export declare const MODULE_SCHEMA: string;
42
42
  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
43
  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
- 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 description STRING,\n PRIMARY KEY (id)\n)";
44
+ 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
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
46
  export declare const EMBEDDING_DIMS: number;
47
47
  /** HNSW vector index name for the CodeEmbedding table. */
@@ -15,12 +15,23 @@ export { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME };
15
15
  // ============================================================================
16
16
  // NODE TABLE SCHEMAS
17
17
  // ============================================================================
18
+ // RFC 0001 Phase 2 — every node table that has `content STRING` also carries
19
+ // `contentEncoding STRING DEFAULT 'none'`. Default keeps existing
20
+ // uncompressed reads working (an empty/missing tag means "no decode
21
+ // needed"); writers opt into compression by setting it to 'brotli' or
22
+ // 'zstd' alongside the encoded bytes.
23
+ //
24
+ // Adding the column to every relevant table at once keeps the read path
25
+ // simple — every `RETURN n.content` site can also `RETURN n.contentEncoding`
26
+ // without per-table feature detection. Tables WITHOUT a content column
27
+ // (Folder, Community, Process, Route, Tool) are intentionally not touched.
18
28
  export const FILE_SCHEMA = `
19
29
  CREATE NODE TABLE File (
20
30
  id STRING,
21
31
  name STRING,
22
32
  filePath STRING,
23
33
  content STRING,
34
+ contentEncoding STRING DEFAULT 'none',
24
35
  PRIMARY KEY (id)
25
36
  )`;
26
37
  export const FOLDER_SCHEMA = `
@@ -39,6 +50,7 @@ CREATE NODE TABLE Function (
39
50
  endLine INT64,
40
51
  isExported BOOLEAN,
41
52
  content STRING,
53
+ contentEncoding STRING DEFAULT 'none',
42
54
  description STRING,
43
55
  PRIMARY KEY (id)
44
56
  )`;
@@ -51,6 +63,7 @@ CREATE NODE TABLE Class (
51
63
  endLine INT64,
52
64
  isExported BOOLEAN,
53
65
  content STRING,
66
+ contentEncoding STRING DEFAULT 'none',
54
67
  description STRING,
55
68
  PRIMARY KEY (id)
56
69
  )`;
@@ -63,6 +76,7 @@ CREATE NODE TABLE Interface (
63
76
  endLine INT64,
64
77
  isExported BOOLEAN,
65
78
  content STRING,
79
+ contentEncoding STRING DEFAULT 'none',
66
80
  description STRING,
67
81
  PRIMARY KEY (id)
68
82
  )`;
@@ -75,6 +89,7 @@ CREATE NODE TABLE Method (
75
89
  endLine INT64,
76
90
  isExported BOOLEAN,
77
91
  content STRING,
92
+ contentEncoding STRING DEFAULT 'none',
78
93
  description STRING,
79
94
  parameterCount INT32,
80
95
  returnType STRING,
@@ -89,6 +104,7 @@ CREATE NODE TABLE CodeElement (
89
104
  endLine INT64,
90
105
  isExported BOOLEAN,
91
106
  content STRING,
107
+ contentEncoding STRING DEFAULT 'none',
92
108
  description STRING,
93
109
  PRIMARY KEY (id)
94
110
  )`;
@@ -135,6 +151,7 @@ CREATE NODE TABLE \`${name}\` (
135
151
  startLine INT64,
136
152
  endLine INT64,
137
153
  content STRING,
154
+ contentEncoding STRING DEFAULT 'none',
138
155
  description STRING,
139
156
  PRIMARY KEY (id)
140
157
  )`;
@@ -187,6 +204,7 @@ CREATE NODE TABLE Section (
187
204
  endLine INT64,
188
205
  level INT64,
189
206
  content STRING,
207
+ contentEncoding STRING DEFAULT 'none',
190
208
  description STRING,
191
209
  PRIMARY KEY (id)
192
210
  )`;
@@ -8,6 +8,7 @@
8
8
  * IMPORTANT: This module must NEVER call process.exit(). The caller (CLI
9
9
  * wrapper or server worker) is responsible for process lifecycle.
10
10
  */
11
+ import type { ContentEncoding } from '@codragraph/graphstore';
11
12
  export interface AnalyzeCallbacks {
12
13
  onProgress: (phase: string, percent: number, message: string) => void;
13
14
  onLog?: (message: string) => void;
@@ -41,6 +42,18 @@ export interface AnalyzeOptions {
41
42
  * of a pipeline re-index.
42
43
  */
43
44
  allowDuplicateName?: boolean;
45
+ /**
46
+ * RFC 0001 Phase 2 — opt into per-row content compression. `'none'`
47
+ * (or undefined) writes plain text and the schema-default tag, exactly
48
+ * as pre-Phase-2 indexes do. `'brotli'` and `'zstd'` route every
49
+ * content field through `encodeContent` before it hits the CSV; the
50
+ * read path decodes via the per-row `contentEncoding` tag.
51
+ *
52
+ * Choosing `'zstd'` requires Node ≥ 22.15 on the indexer (the runtime
53
+ * that wrote the rows). Readers on older Node will get a clear
54
+ * forward-compat error rather than silently bad content.
55
+ */
56
+ compress?: ContentEncoding;
44
57
  }
45
58
  export interface AnalyzeResult {
46
59
  repoName: string;