@codragraph/cli 2.0.0 → 2.1.1

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 (101) hide show
  1. package/README.md +60 -22
  2. package/dist/_shared/cgdb/schema-constants.d.ts +16 -0
  3. package/dist/_shared/cgdb/schema-constants.d.ts.map +1 -0
  4. package/dist/_shared/cgdb/schema-constants.js +70 -0
  5. package/dist/_shared/cgdb/schema-constants.js.map +1 -0
  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 +3 -2
  13. package/dist/_shared/index.d.ts.map +1 -1
  14. package/dist/_shared/index.js +1 -1
  15. package/dist/_shared/index.js.map +1 -1
  16. package/dist/_shared/pipeline.d.ts +1 -1
  17. package/dist/_shared/pipeline.d.ts.map +1 -1
  18. package/dist/cli/ai-context.js +4 -0
  19. package/dist/cli/analyze.js +30 -27
  20. package/dist/cli/graphstore.js +21 -21
  21. package/dist/cli/index-repo.js +3 -3
  22. package/dist/cli/index.js +37 -0
  23. package/dist/cli/setup.js +9 -5
  24. package/dist/cli/tool.d.ts +25 -0
  25. package/dist/cli/tool.js +74 -0
  26. package/dist/cli/wiki.js +3 -3
  27. package/dist/config/supported-languages.d.ts +3 -3
  28. package/dist/config/supported-languages.js +3 -3
  29. package/dist/core/augmentation/engine.js +7 -7
  30. package/dist/core/cgdb/cgdb-adapter.d.ts +176 -0
  31. package/dist/core/cgdb/cgdb-adapter.js +1336 -0
  32. package/dist/core/cgdb/content-read.d.ts +46 -0
  33. package/dist/core/cgdb/content-read.js +64 -0
  34. package/dist/core/cgdb/csv-generator.d.ts +29 -0
  35. package/dist/core/cgdb/csv-generator.js +523 -0
  36. package/dist/core/cgdb/pool-adapter.d.ts +93 -0
  37. package/dist/core/cgdb/pool-adapter.js +550 -0
  38. package/dist/core/cgdb/schema.d.ts +63 -0
  39. package/dist/core/cgdb/schema.js +557 -0
  40. package/dist/core/embeddings/embedder.js +4 -2
  41. package/dist/core/embeddings/embedding-pipeline.js +4 -4
  42. package/dist/core/graphstore/cgdb-row-source.d.ts +19 -0
  43. package/dist/core/graphstore/cgdb-row-source.js +141 -0
  44. package/dist/core/graphstore/index.d.ts +2 -2
  45. package/dist/core/graphstore/index.js +4 -4
  46. package/dist/core/group/bridge-db.d.ts +2 -2
  47. package/dist/core/group/bridge-db.js +18 -18
  48. package/dist/core/group/bridge-schema.d.ts +4 -4
  49. package/dist/core/group/bridge-schema.js +4 -4
  50. package/dist/core/group/cross-impact.js +3 -3
  51. package/dist/core/group/service.d.ts +16 -0
  52. package/dist/core/group/service.js +360 -0
  53. package/dist/core/group/sync.js +4 -4
  54. package/dist/core/ingestion/emit-references.d.ts +1 -1
  55. package/dist/core/ingestion/emit-references.js +1 -1
  56. package/dist/core/ingestion/feature-cluster-processor.d.ts +62 -0
  57. package/dist/core/ingestion/feature-cluster-processor.js +626 -0
  58. package/dist/core/ingestion/finalize-orchestrator.js +1 -1
  59. package/dist/core/ingestion/model/registration-table.js +1 -0
  60. package/dist/core/ingestion/model/resolve.d.ts +2 -2
  61. package/dist/core/ingestion/model/resolve.js +3 -3
  62. package/dist/core/ingestion/model/semantic-model.d.ts +1 -1
  63. package/dist/core/ingestion/model/semantic-model.js +1 -1
  64. package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
  65. package/dist/core/ingestion/model/symbol-table.js +1 -1
  66. package/dist/core/ingestion/pipeline-phases/feature-clusters.d.ts +17 -0
  67. package/dist/core/ingestion/pipeline-phases/feature-clusters.js +88 -0
  68. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  69. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  70. package/dist/core/ingestion/pipeline.d.ts +4 -0
  71. package/dist/core/ingestion/pipeline.js +9 -5
  72. package/dist/core/run-analyze.d.ts +1 -0
  73. package/dist/core/run-analyze.js +36 -30
  74. package/dist/core/search/bm25-index.d.ts +3 -3
  75. package/dist/core/search/bm25-index.js +9 -9
  76. package/dist/core/search/hybrid-search.js +2 -2
  77. package/dist/core/wiki/generator.d.ts +2 -2
  78. package/dist/core/wiki/generator.js +4 -4
  79. package/dist/core/wiki/graph-queries.d.ts +2 -2
  80. package/dist/core/wiki/graph-queries.js +5 -5
  81. package/dist/mcp/core/cgdb-adapter.d.ts +5 -0
  82. package/dist/mcp/core/cgdb-adapter.js +5 -0
  83. package/dist/mcp/core/embedder.js +6 -3
  84. package/dist/mcp/local/local-backend.d.ts +14 -2
  85. package/dist/mcp/local/local-backend.js +396 -18
  86. package/dist/mcp/resources.js +139 -0
  87. package/dist/mcp/server.js +3 -3
  88. package/dist/mcp/tools.js +175 -3
  89. package/dist/server/analyze-worker.js +2 -2
  90. package/dist/server/api.js +147 -31
  91. package/dist/storage/repo-manager.d.ts +10 -5
  92. package/dist/storage/repo-manager.js +10 -6
  93. package/dist/types/pipeline.d.ts +2 -0
  94. package/hooks/claude/codragraph-hook.cjs +4 -4
  95. package/package.json +15 -6
  96. package/scripts/build.js +21 -21
  97. package/skills/codragraph-cli.md +17 -1
  98. package/skills/codragraph-guide.md +6 -2
  99. package/skills/codragraph-onboarding.md +2 -2
  100. package/vendor/tree-sitter-proto/bindings/node/index.js +3 -3
  101. package/vendor/tree-sitter-proto/src/node-types.json +1 -1
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Adapter exposing a live LadybugDB instance as a `@codragraph/graphstore`
3
+ * `RowSource`. Used by the analyze pipeline (Phase 4) to snapshot the
4
+ * loaded graph into the content-addressed store.
5
+ *
6
+ * Best-effort by design: any table that errors at query time is skipped
7
+ * (with the failure surfaced through the optional `onSkip` callback) so
8
+ * the surrounding analyze flow never breaks because the versioning hook
9
+ * misbehaves.
10
+ */
11
+ import type { RowSource } from '@codragraph/graphstore';
12
+ import { type NodeTableName } from '../../_shared/index.js';
13
+ export interface CgdbRowSourceOptions {
14
+ /** Filter the node tables enumerated by `listNodeTables` — defaults to every NODE_TABLE. */
15
+ readonly nodeTables?: readonly NodeTableName[];
16
+ /** Called with `(table, error)` when a table query fails — defaults to a no-op. */
17
+ readonly onSkip?: (tableName: string, error: unknown) => void;
18
+ }
19
+ export declare const createCgdbRowSource: (opts?: CgdbRowSourceOptions) => RowSource;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Adapter exposing a live LadybugDB instance as a `@codragraph/graphstore`
3
+ * `RowSource`. Used by the analyze pipeline (Phase 4) to snapshot the
4
+ * loaded graph into the content-addressed store.
5
+ *
6
+ * Best-effort by design: any table that errors at query time is skipped
7
+ * (with the failure surfaced through the optional `onSkip` callback) so
8
+ * the surrounding analyze flow never breaks because the versioning hook
9
+ * misbehaves.
10
+ */
11
+ import { NODE_TABLES, REL_TABLE_NAME } from '../../_shared/index.js';
12
+ import { executeQuery } from '../cgdb/cgdb-adapter.js';
13
+ export const createCgdbRowSource = (opts = {}) => {
14
+ const onSkip = opts.onSkip ?? (() => { });
15
+ const tables = opts.nodeTables ?? NODE_TABLES;
16
+ const listNodeTables = async () => {
17
+ return [...tables];
18
+ };
19
+ const streamNodeTable = async function* (tableName) {
20
+ let rows;
21
+ try {
22
+ // `MATCH (n:T) RETURN n` returns one row per node. The node value
23
+ // is reachable as either `row.n` (named-column form) or `row[0]`
24
+ // (positional form) depending on the LadybugDB result-shape mode;
25
+ // we accept both, mirroring the resilient pattern used by
26
+ // `core/search/bm25-index.ts` for FTS results. Tables that do not
27
+ // exist on disk for a given repo throw here — we treat that as
28
+ // "no rows" via the onSkip callback rather than a hard failure.
29
+ rows = await executeQuery(`MATCH (n:${tableName}) RETURN n`);
30
+ }
31
+ catch (err) {
32
+ onSkip(tableName, err);
33
+ return;
34
+ }
35
+ let yielded = 0;
36
+ for (const raw of rows) {
37
+ const node = unwrapNode(raw);
38
+ if (!node)
39
+ continue;
40
+ yield normalizeNodeRow(node);
41
+ yielded++;
42
+ }
43
+ // If the query reported rows but none unwrapped, surface that as a
44
+ // skip so the analyze log makes the silent-empty failure mode
45
+ // visible instead of producing a 0-row snapshot for the table.
46
+ if (rows.length > 0 && yielded === 0) {
47
+ onSkip(tableName, new Error(`cgdb-row-source: query returned ${rows.length} row(s) for "${tableName}" but none had an unwrappable node — ` +
48
+ `result shape changed? expected row.n or row[0] to be the node`));
49
+ }
50
+ };
51
+ const streamEdges = async function* () {
52
+ let rows;
53
+ try {
54
+ // Project `from`/`to`/`type` as scalar columns and the full rel as
55
+ // `rel`. Scalars give us a deterministic edge id even if the rel
56
+ // payload's shape changes; `rel` carries any extra properties for
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`);
59
+ }
60
+ catch (err) {
61
+ onSkip(REL_TABLE_NAME, err);
62
+ return;
63
+ }
64
+ let yielded = 0;
65
+ for (const raw of rows) {
66
+ const r = raw;
67
+ const from = pickField(r, 'from', 0);
68
+ const to = pickField(r, 'to', 1);
69
+ const type = pickField(r, 'type', 2);
70
+ const rel = pickField(r, 'rel', 3);
71
+ if (typeof from !== 'string' || typeof to !== 'string')
72
+ continue;
73
+ yield normalizeEdgeRow({ from, to, type, rel: isPlainObject(rel) ? rel : null });
74
+ yielded++;
75
+ }
76
+ if (rows.length > 0 && yielded === 0) {
77
+ onSkip(REL_TABLE_NAME, new Error(`cgdb-row-source: edges query returned ${rows.length} row(s) but none had a string from/to — ` +
78
+ `result shape changed?`));
79
+ }
80
+ };
81
+ return { listNodeTables, streamNodeTable, streamEdges };
82
+ };
83
+ /**
84
+ * Pull the node out of an executeQuery result row, accepting either the
85
+ * named-column form (`row.n`) or the positional form (`row[0]`). Returns
86
+ * null when the row is missing or the node value isn't an object — the
87
+ * caller treats that as "skip and surface".
88
+ */
89
+ const unwrapNode = (raw) => {
90
+ if (!raw || typeof raw !== 'object')
91
+ return null;
92
+ const r = raw;
93
+ const candidate = r['n'] ?? r[0];
94
+ return isPlainObject(candidate) ? candidate : null;
95
+ };
96
+ /** Read a field from an executeQuery row, falling back to the positional index. */
97
+ const pickField = (row, named, positional) => {
98
+ if (!row)
99
+ return undefined;
100
+ return row[named] ?? row[positional];
101
+ };
102
+ const isPlainObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
103
+ /**
104
+ * Sanitize a node row for canonical hashing:
105
+ * - Drop LadybugDB-specific internal fields (`_id`, `_label`) that are
106
+ * not content-bearing — including them would make the hash sensitive
107
+ * to internal storage offsets and break dedup across snapshots.
108
+ * - Sort keys deterministically (canonical JSON in the serializer
109
+ * already does this, but doing it once here keeps the row payload
110
+ * stable when we ever swap engines).
111
+ */
112
+ const normalizeNodeRow = (node) => {
113
+ const out = {};
114
+ for (const key of Object.keys(node).sort()) {
115
+ if (key === '_id' || key === '_label')
116
+ continue;
117
+ out[key] = node[key];
118
+ }
119
+ return out;
120
+ };
121
+ const normalizeEdgeRow = (r) => {
122
+ const props = {};
123
+ if (r.rel && typeof r.rel === 'object') {
124
+ for (const key of Object.keys(r.rel).sort()) {
125
+ // Skip the synthetic from/to/type that show up under `rel` too —
126
+ // we already project them as top-level columns and don't want
127
+ // duplication in the canonical row.
128
+ if (key === 'from' || key === 'to' || key === 'type')
129
+ continue;
130
+ if (key.startsWith('_'))
131
+ continue;
132
+ props[key] = r.rel[key];
133
+ }
134
+ }
135
+ return {
136
+ from: String(r.from),
137
+ to: String(r.to),
138
+ type: typeof r.type === 'string' ? r.type : String(r.type ?? ''),
139
+ ...props,
140
+ };
141
+ };
@@ -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:
@@ -38,7 +38,7 @@ export interface RecordAnalysisSnapshotResult {
38
38
  /**
39
39
  * Snapshot the currently-loaded LadybugDB into the content-addressed
40
40
  * store and advance the active branch's HEAD to the new commit. Caller
41
- * is expected to have already initialized lbug with `initLbug(...)`.
41
+ * is expected to have already initialized cgdb with `initCgdb(...)`.
42
42
  *
43
43
  * Returns null if anything goes sideways (logged via `onSkipTable`); the
44
44
  * analyze pipeline treats that as "no snapshot for this run".
@@ -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:
@@ -9,13 +9,13 @@
9
9
  */
10
10
  import path from 'node:path';
11
11
  import { FsCAS, serializeSnapshot, createCommit, setHead, writeHeadBranch, resolveHeadCommit, DEFAULT_BRANCH, } from '@codragraph/graphstore';
12
- import { createLbugRowSource } from './lbug-row-source.js';
12
+ import { createCgdbRowSource } from './cgdb-row-source.js';
13
13
  /** Subdirectory of `<repo>/.codragraph` that holds versioning artifacts. */
14
14
  export const GRAPHSTORE_SUBDIR = 'graphstore';
15
15
  /**
16
16
  * Snapshot the currently-loaded LadybugDB into the content-addressed
17
17
  * store and advance the active branch's HEAD to the new commit. Caller
18
- * is expected to have already initialized lbug with `initLbug(...)`.
18
+ * is expected to have already initialized cgdb with `initCgdb(...)`.
19
19
  *
20
20
  * Returns null if anything goes sideways (logged via `onSkipTable`); the
21
21
  * analyze pipeline treats that as "no snapshot for this run".
@@ -26,7 +26,7 @@ export const recordAnalysisSnapshot = async (opts) => {
26
26
  let serialized;
27
27
  try {
28
28
  serialized = await serializeSnapshot({
29
- source: createLbugRowSource({ onSkip: opts.onSkipTable }),
29
+ source: createCgdbRowSource({ onSkip: opts.onSkipTable }),
30
30
  cas,
31
31
  indexedRepoCommit: opts.indexedRepoCommit,
32
32
  });
@@ -1,4 +1,4 @@
1
- import type { LbugValue } from '@ladybugdb/core';
1
+ import type { LbugValue as CgdbValue } from '@ladybugdb/core';
2
2
  import type { BridgeHandle, BridgeMeta, StoredContract, CrossLink, RepoSnapshot } from './types.js';
3
3
  export declare function contractNodeId(repo: string, contractId: string, role: string, filePath: string): string;
4
4
  /**
@@ -46,7 +46,7 @@ export declare function indexContract(index: ContractLookupIndex, contract: Stor
46
46
  export declare function findContractNode(index: ContractLookupIndex, repo: string, role: 'consumer' | 'provider', symbolUid: string, filePath: string, symbolName: string): string | null;
47
47
  export declare function openBridgeDb(dbPath: string): Promise<BridgeHandle>;
48
48
  export declare function ensureBridgeSchema(handle: BridgeHandle): Promise<void>;
49
- export declare function queryBridge<T>(handle: BridgeHandle, cypher: string, params?: Record<string, LbugValue>): Promise<T[]>;
49
+ export declare function queryBridge<T>(handle: BridgeHandle, cypher: string, params?: Record<string, CgdbValue>): Promise<T[]>;
50
50
  export declare function closeBridgeDb(handle: BridgeHandle): Promise<void>;
51
51
  export declare function retryRename(src: string, dst: string, attempts?: number): Promise<void>;
52
52
  export declare function writeBridgeMeta(groupDir: string, meta: BridgeMeta): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import fsp from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { createHash } from 'node:crypto';
4
- import lbug from '@ladybugdb/core';
4
+ import cgdb from '@ladybugdb/core';
5
5
  import { BRIDGE_SCHEMA_QUERIES, BRIDGE_SCHEMA_VERSION } from './bridge-schema.js';
6
6
  import { dedupeContracts, dedupeCrossLinks } from './normalization.js';
7
7
  export function contractNodeId(repo, contractId, role, filePath) {
@@ -74,8 +74,8 @@ 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 lbug.Database(dbPath, 0, false, false); // writable
78
- const conn = new lbug.Connection(db);
77
+ const db = new cgdb.Database(dbPath, 0, false, false); // writable
78
+ const conn = new cgdb.Connection(db);
79
79
  return { _db: db, _conn: conn, groupDir: parentDir };
80
80
  }
81
81
  /**
@@ -83,10 +83,10 @@ export async function openBridgeDb(dbPath) {
83
83
  * CREATE NODE TABLE or CREATE REL TABLE statement hits an already-existing
84
84
  * table. LadybugDB DDL doesn't support IF NOT EXISTS, and its JS driver
85
85
  * doesn't expose typed error codes, so we match on the message substring —
86
- * the same pattern used by `core/lbug/lbug-adapter.ts`. If a future
86
+ * the same pattern used by `core/cgdb/cgdb-adapter.ts`. If a future
87
87
  * LadybugDB release changes the wording, update this constant.
88
88
  */
89
- const LBUG_ALREADY_EXISTS_MSG = 'already exists';
89
+ const CGDB_ALREADY_EXISTS_MSG = 'already exists';
90
90
  export async function ensureBridgeSchema(handle) {
91
91
  const conn = handle._conn;
92
92
  for (const q of BRIDGE_SCHEMA_QUERIES) {
@@ -95,14 +95,14 @@ export async function ensureBridgeSchema(handle) {
95
95
  }
96
96
  catch (err) {
97
97
  const msg = err instanceof Error ? err.message : String(err);
98
- if (!msg.includes(LBUG_ALREADY_EXISTS_MSG))
98
+ if (!msg.includes(CGDB_ALREADY_EXISTS_MSG))
99
99
  throw err;
100
100
  }
101
101
  }
102
102
  }
103
103
  /**
104
104
  * Close every QueryResult / PreparedStatement before letting V8 GC them.
105
- * Same close-order discipline as `core/lbug/lbug-adapter.ts:closeQueryResult`
105
+ * Same close-order discipline as `core/cgdb/cgdb-adapter.ts:closeQueryResult`
106
106
  * — leaking these handles past `conn.close()` corrupts LadybugDB's native
107
107
  * file lock on Windows ("Error 33: The process cannot access the file
108
108
  * because it is being used by another process") and segfaults on
@@ -132,7 +132,7 @@ async function closeBridgeHandle(h) {
132
132
  * fully released the exclusive lock yet. Retrying with backoff is the
133
133
  * documented workaround for this class of Windows-fs interactions.
134
134
  */
135
- function isTransientLbugLockError(err) {
135
+ function isTransientCgdbLockError(err) {
136
136
  const msg = err?.message ?? '';
137
137
  return (msg.includes('Error 33') ||
138
138
  msg.includes('locked a portion of the file') ||
@@ -180,7 +180,7 @@ export async function queryBridge(handle, cypher, params) {
180
180
  return await queryBridgeOnce(handle, cypher, params);
181
181
  }
182
182
  catch (err) {
183
- if (!isTransientLbugLockError(err) || attempt === ATTEMPTS - 1)
183
+ if (!isTransientCgdbLockError(err) || attempt === ATTEMPTS - 1)
184
184
  throw err;
185
185
  await new Promise((r) => setTimeout(r, 50 * Math.pow(2, attempt)));
186
186
  }
@@ -248,7 +248,7 @@ export async function writeBridgeMeta(groupDir, meta) {
248
248
  // Use retryRename for consistency with writeBridge's atomic swap — on
249
249
  // Windows a concurrent reader can cause EBUSY/EPERM even on a tiny
250
250
  // meta.json, and we don't want meta write to be less robust than the
251
- // bridge.lbug swap it accompanies.
251
+ // bridge.cgdb swap it accompanies.
252
252
  await retryRename(tmp, target);
253
253
  }
254
254
  export async function readBridgeMeta(groupDir) {
@@ -275,9 +275,9 @@ export async function writeBridge(groupDir, input) {
275
275
  await fsp.mkdir(groupDir, { recursive: true });
276
276
  const contracts = dedupeContracts(input.contracts);
277
277
  const crossLinks = dedupeCrossLinks(input.crossLinks);
278
- const finalPath = path.join(groupDir, 'bridge.lbug');
279
- const tmpPath = path.join(groupDir, 'bridge.lbug.tmp');
280
- const bakPath = path.join(groupDir, 'bridge.lbug.bak');
278
+ const finalPath = path.join(groupDir, 'bridge.cgdb');
279
+ const tmpPath = path.join(groupDir, 'bridge.cgdb.tmp');
280
+ const bakPath = path.join(groupDir, 'bridge.cgdb.bak');
281
281
  const report = {
282
282
  contractsInserted: 0,
283
283
  contractsFailed: 0,
@@ -466,7 +466,7 @@ export async function writeBridge(groupDir, input) {
466
466
  /* openBridgeDbReadOnly */
467
467
  /* ------------------------------------------------------------------ */
468
468
  export async function openBridgeDbReadOnly(groupDir) {
469
- const dbPath = path.join(groupDir, 'bridge.lbug');
469
+ const dbPath = path.join(groupDir, 'bridge.cgdb');
470
470
  try {
471
471
  await fsp.access(dbPath);
472
472
  }
@@ -476,7 +476,7 @@ export async function openBridgeDbReadOnly(groupDir) {
476
476
  // triggers bak recovery is an interrupted writer, which on Windows may
477
477
  // still be holding an open handle on `.bak` for a few milliseconds when
478
478
  // a reader races in. EBUSY/EPERM retries recover that case silently.
479
- const bakPath = path.join(groupDir, 'bridge.lbug.bak');
479
+ const bakPath = path.join(groupDir, 'bridge.cgdb.bak');
480
480
  try {
481
481
  await fsp.access(bakPath);
482
482
  await retryRename(bakPath, dbPath);
@@ -506,8 +506,8 @@ export async function openBridgeDbReadOnly(groupDir) {
506
506
  let db;
507
507
  let conn;
508
508
  try {
509
- db = new lbug.Database(dbPath, 0, false, true); // readOnly
510
- conn = new lbug.Connection(db);
509
+ db = new cgdb.Database(dbPath, 0, false, true); // readOnly
510
+ conn = new cgdb.Connection(db);
511
511
  return { _db: db, _conn: conn, groupDir };
512
512
  }
513
513
  catch (err) {
@@ -527,7 +527,7 @@ export async function openBridgeDbReadOnly(groupDir) {
527
527
  /* ignore */
528
528
  }
529
529
  }
530
- if (!isTransientLbugLockError(err) || attempt === ATTEMPTS - 1)
530
+ if (!isTransientCgdbLockError(err) || attempt === ATTEMPTS - 1)
531
531
  return null;
532
532
  await new Promise((r) => setTimeout(r, 50 * Math.pow(2, attempt)));
533
533
  continue;
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * Bridge LadybugDB schema for cross-repo Contract Registry.
3
- * Separate from per-repo schema in lbug/schema.ts.
3
+ * Separate from per-repo schema in cgdb/schema.ts.
4
4
  */
5
5
  /**
6
- * Version of the bridge.lbug schema below. `openBridgeDbReadOnly` compares
6
+ * Version of the bridge.cgdb schema below. `openBridgeDbReadOnly` compares
7
7
  * this against `meta.json`'s version field and returns `null` on mismatch,
8
8
  * which trips the caller into either the JSON fallback path or a fresh
9
- * `group sync` that rebuilds `bridge.lbug` from scratch.
9
+ * `group sync` that rebuilds `bridge.cgdb` from scratch.
10
10
  *
11
11
  * Migration contract for contributors bumping this constant:
12
12
  * 1. Bump the number (e.g. `1` → `2`).
13
13
  * 2. Update the DDL below to match the new schema.
14
14
  * 3. DO NOT attempt an online migration in this file — the version gate
15
15
  * is intentionally a "discard and re-sync" strategy for V1. An old
16
- * bridge.lbug whose version doesn't match is treated as opaque and
16
+ * bridge.cgdb whose version doesn't match is treated as opaque and
17
17
  * rebuilt by the next `group sync`.
18
18
  * 4. If online migration becomes necessary (e.g. when groups accumulate
19
19
  * large amounts of embedding data), add a migration path as a
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * Bridge LadybugDB schema for cross-repo Contract Registry.
3
- * Separate from per-repo schema in lbug/schema.ts.
3
+ * Separate from per-repo schema in cgdb/schema.ts.
4
4
  */
5
5
  /**
6
- * Version of the bridge.lbug schema below. `openBridgeDbReadOnly` compares
6
+ * Version of the bridge.cgdb schema below. `openBridgeDbReadOnly` compares
7
7
  * this against `meta.json`'s version field and returns `null` on mismatch,
8
8
  * which trips the caller into either the JSON fallback path or a fresh
9
- * `group sync` that rebuilds `bridge.lbug` from scratch.
9
+ * `group sync` that rebuilds `bridge.cgdb` from scratch.
10
10
  *
11
11
  * Migration contract for contributors bumping this constant:
12
12
  * 1. Bump the number (e.g. `1` → `2`).
13
13
  * 2. Update the DDL below to match the new schema.
14
14
  * 3. DO NOT attempt an online migration in this file — the version gate
15
15
  * is intentionally a "discard and re-sync" strategy for V1. An old
16
- * bridge.lbug whose version doesn't match is treated as opaque and
16
+ * bridge.cgdb whose version doesn't match is treated as opaque and
17
17
  * rebuilt by the next `group sync`.
18
18
  * 4. If online migration becomes necessary (e.g. when groups accumulate
19
19
  * large amounts of embedding data), add a migration path as a
@@ -199,19 +199,19 @@ async function ensureBridgeReady(groupDir) {
199
199
  error: `Bridge schema version mismatch (meta.json has ${meta.version}, expected ${BRIDGE_SCHEMA_VERSION}). Run codragraph group sync for this group.`,
200
200
  };
201
201
  }
202
- const dbPath = path.join(groupDir, 'bridge.lbug');
202
+ const dbPath = path.join(groupDir, 'bridge.cgdb');
203
203
  try {
204
204
  await fsp.access(dbPath);
205
205
  }
206
206
  catch {
207
207
  return {
208
- error: `No bridge.lbug in this group directory. Run codragraph group sync (schema ${BRIDGE_SCHEMA_VERSION}).`,
208
+ error: `No bridge.cgdb in this group directory. Run codragraph group sync (schema ${BRIDGE_SCHEMA_VERSION}).`,
209
209
  };
210
210
  }
211
211
  const handle = await openBridgeDbReadOnly(groupDir);
212
212
  if (!handle) {
213
213
  return {
214
- error: `Could not open bridge.lbug read-only (schema ${BRIDGE_SCHEMA_VERSION}). Run codragraph group sync.`,
214
+ error: `Could not open bridge.cgdb read-only (schema ${BRIDGE_SCHEMA_VERSION}). Run codragraph group sync.`,
215
215
  };
216
216
  }
217
217
  return { handle };
@@ -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
  }