codemap-ai 0.2.0 → 3.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.
@@ -1,350 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
-
4
- // src/graph/storage.ts
5
- import Database from "better-sqlite3";
6
- var GraphStorage = class {
7
- db;
8
- constructor(dbPath) {
9
- this.db = new Database(dbPath);
10
- this.initSchema();
11
- }
12
- initSchema() {
13
- this.db.exec(`
14
- -- Nodes table
15
- CREATE TABLE IF NOT EXISTS nodes (
16
- id TEXT PRIMARY KEY,
17
- type TEXT NOT NULL,
18
- name TEXT NOT NULL,
19
- file_path TEXT NOT NULL,
20
- start_line INTEGER NOT NULL,
21
- end_line INTEGER NOT NULL,
22
- language TEXT NOT NULL,
23
- metadata TEXT
24
- );
25
-
26
- -- Edges table
27
- CREATE TABLE IF NOT EXISTS edges (
28
- id TEXT PRIMARY KEY,
29
- type TEXT NOT NULL,
30
- source_id TEXT NOT NULL,
31
- target_id TEXT NOT NULL,
32
- metadata TEXT
33
- );
34
-
35
- -- Files table for tracking analyzed files
36
- CREATE TABLE IF NOT EXISTS files (
37
- path TEXT PRIMARY KEY,
38
- language TEXT NOT NULL,
39
- last_modified INTEGER,
40
- analyzed_at TEXT NOT NULL
41
- );
42
-
43
- -- Imports table
44
- CREATE TABLE IF NOT EXISTS imports (
45
- id INTEGER PRIMARY KEY AUTOINCREMENT,
46
- file_path TEXT NOT NULL,
47
- source TEXT NOT NULL,
48
- specifiers TEXT NOT NULL,
49
- is_default INTEGER NOT NULL,
50
- is_namespace INTEGER NOT NULL,
51
- line INTEGER NOT NULL
52
- );
53
-
54
- -- Exports table
55
- CREATE TABLE IF NOT EXISTS exports (
56
- id INTEGER PRIMARY KEY AUTOINCREMENT,
57
- file_path TEXT NOT NULL,
58
- name TEXT NOT NULL,
59
- is_default INTEGER NOT NULL,
60
- line INTEGER NOT NULL
61
- );
62
-
63
- -- Project metadata
64
- CREATE TABLE IF NOT EXISTS project_meta (
65
- key TEXT PRIMARY KEY,
66
- value TEXT NOT NULL
67
- );
68
-
69
- -- Indexes for faster queries
70
- CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_path);
71
- CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
72
- CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);
73
- CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);
74
- CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);
75
- CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
76
- CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path);
77
- CREATE INDEX IF NOT EXISTS idx_imports_source ON imports(source);
78
- CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path);
79
- `);
80
- }
81
- // ============ Node Operations ============
82
- insertNode(node) {
83
- const stmt = this.db.prepare(`
84
- INSERT OR REPLACE INTO nodes (id, type, name, file_path, start_line, end_line, language, metadata)
85
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
86
- `);
87
- stmt.run(
88
- node.id,
89
- node.type,
90
- node.name,
91
- node.filePath,
92
- node.startLine,
93
- node.endLine,
94
- node.language,
95
- node.metadata ? JSON.stringify(node.metadata) : null
96
- );
97
- }
98
- getNode(id) {
99
- const stmt = this.db.prepare("SELECT * FROM nodes WHERE id = ?");
100
- const row = stmt.get(id);
101
- if (!row) return null;
102
- return this.rowToNode(row);
103
- }
104
- getNodesByFile(filePath) {
105
- const stmt = this.db.prepare("SELECT * FROM nodes WHERE file_path = ?");
106
- const rows = stmt.all(filePath);
107
- return rows.map(this.rowToNode);
108
- }
109
- getNodesByType(type) {
110
- const stmt = this.db.prepare("SELECT * FROM nodes WHERE type = ?");
111
- const rows = stmt.all(type);
112
- return rows.map(this.rowToNode);
113
- }
114
- searchNodes(query) {
115
- const stmt = this.db.prepare(
116
- "SELECT * FROM nodes WHERE name LIKE ? OR file_path LIKE ?"
117
- );
118
- const pattern = `%${query}%`;
119
- const rows = stmt.all(pattern, pattern);
120
- return rows.map(this.rowToNode);
121
- }
122
- getAllNodes() {
123
- const stmt = this.db.prepare("SELECT * FROM nodes");
124
- const rows = stmt.all();
125
- return rows.map(this.rowToNode);
126
- }
127
- rowToNode(row) {
128
- return {
129
- id: row.id,
130
- type: row.type,
131
- name: row.name,
132
- filePath: row.file_path,
133
- startLine: row.start_line,
134
- endLine: row.end_line,
135
- language: row.language,
136
- metadata: row.metadata ? JSON.parse(row.metadata) : void 0
137
- };
138
- }
139
- // ============ Edge Operations ============
140
- insertEdge(edge) {
141
- const stmt = this.db.prepare(`
142
- INSERT OR REPLACE INTO edges (id, type, source_id, target_id, metadata)
143
- VALUES (?, ?, ?, ?, ?)
144
- `);
145
- stmt.run(
146
- edge.id,
147
- edge.type,
148
- edge.sourceId,
149
- edge.targetId,
150
- edge.metadata ? JSON.stringify(edge.metadata) : null
151
- );
152
- }
153
- getEdgesFrom(sourceId) {
154
- const stmt = this.db.prepare("SELECT * FROM edges WHERE source_id = ?");
155
- const rows = stmt.all(sourceId);
156
- return rows.map(this.rowToEdge);
157
- }
158
- getEdgesTo(targetId) {
159
- const stmt = this.db.prepare("SELECT * FROM edges WHERE target_id = ?");
160
- const rows = stmt.all(targetId);
161
- return rows.map(this.rowToEdge);
162
- }
163
- getEdgesByType(type) {
164
- const stmt = this.db.prepare("SELECT * FROM edges WHERE type = ?");
165
- const rows = stmt.all(type);
166
- return rows.map(this.rowToEdge);
167
- }
168
- getAllEdges() {
169
- const stmt = this.db.prepare("SELECT * FROM edges");
170
- const rows = stmt.all();
171
- return rows.map(this.rowToEdge);
172
- }
173
- rowToEdge(row) {
174
- return {
175
- id: row.id,
176
- type: row.type,
177
- sourceId: row.source_id,
178
- targetId: row.target_id,
179
- metadata: row.metadata ? JSON.parse(row.metadata) : void 0
180
- };
181
- }
182
- // ============ File Analysis Operations ============
183
- insertFileAnalysis(analysis) {
184
- const transaction = this.db.transaction(() => {
185
- this.deleteFileData(analysis.filePath);
186
- const fileStmt = this.db.prepare(`
187
- INSERT OR REPLACE INTO files (path, language, analyzed_at)
188
- VALUES (?, ?, ?)
189
- `);
190
- fileStmt.run(analysis.filePath, analysis.language, (/* @__PURE__ */ new Date()).toISOString());
191
- for (const node of analysis.nodes) {
192
- this.insertNode(node);
193
- }
194
- for (const edge of analysis.edges) {
195
- this.insertEdge(edge);
196
- }
197
- const importStmt = this.db.prepare(`
198
- INSERT INTO imports (file_path, source, specifiers, is_default, is_namespace, line)
199
- VALUES (?, ?, ?, ?, ?, ?)
200
- `);
201
- for (const imp of analysis.imports) {
202
- importStmt.run(
203
- analysis.filePath,
204
- imp.source,
205
- JSON.stringify(imp.specifiers),
206
- imp.isDefault ? 1 : 0,
207
- imp.isNamespace ? 1 : 0,
208
- imp.line
209
- );
210
- }
211
- const exportStmt = this.db.prepare(`
212
- INSERT INTO exports (file_path, name, is_default, line)
213
- VALUES (?, ?, ?, ?)
214
- `);
215
- for (const exp of analysis.exports) {
216
- exportStmt.run(analysis.filePath, exp.name, exp.isDefault ? 1 : 0, exp.line);
217
- }
218
- });
219
- transaction();
220
- }
221
- deleteFileData(filePath) {
222
- this.db.prepare("DELETE FROM nodes WHERE file_path = ?").run(filePath);
223
- this.db.prepare("DELETE FROM imports WHERE file_path = ?").run(filePath);
224
- this.db.prepare("DELETE FROM exports WHERE file_path = ?").run(filePath);
225
- this.db.prepare("DELETE FROM files WHERE path = ?").run(filePath);
226
- }
227
- // ============ Query Operations ============
228
- /**
229
- * Get all files that import from a given file/module
230
- */
231
- getFilesThatImport(modulePath) {
232
- const stmt = this.db.prepare(`
233
- SELECT DISTINCT file_path FROM imports
234
- WHERE source LIKE ? OR source LIKE ?
235
- `);
236
- const rows = stmt.all(`%${modulePath}%`, modulePath);
237
- return rows.map((r) => r.file_path);
238
- }
239
- /**
240
- * Get all callers of a function/method
241
- */
242
- getCallers(nodeName) {
243
- const stmt = this.db.prepare(`
244
- SELECT DISTINCT n.* FROM nodes n
245
- JOIN edges e ON n.id = e.source_id
246
- WHERE e.type = 'calls' AND e.target_id LIKE ?
247
- `);
248
- const rows = stmt.all(`%${nodeName}%`);
249
- return rows.map(this.rowToNode);
250
- }
251
- /**
252
- * Get all functions/methods called by a node
253
- */
254
- getCallees(nodeId) {
255
- const stmt = this.db.prepare(`
256
- SELECT target_id, metadata FROM edges
257
- WHERE source_id = ? AND type = 'calls'
258
- `);
259
- const rows = stmt.all(nodeId);
260
- return rows.map((r) => ({
261
- name: r.target_id.replace("ref:", ""),
262
- line: r.metadata ? JSON.parse(r.metadata).line : void 0
263
- }));
264
- }
265
- /**
266
- * Get the dependency tree for a file
267
- */
268
- getFileDependencies(filePath) {
269
- const importsStmt = this.db.prepare(
270
- "SELECT DISTINCT source FROM imports WHERE file_path = ?"
271
- );
272
- const imports = importsStmt.all(filePath).map((r) => r.source);
273
- const importedBy = this.getFilesThatImport(
274
- filePath.replace(/\.(ts|tsx|js|jsx|py)$/, "")
275
- );
276
- return { imports, importedBy };
277
- }
278
- /**
279
- * Get statistics about the graph
280
- */
281
- getStats() {
282
- const totalFiles = this.db.prepare("SELECT COUNT(*) as count FROM files").get().count;
283
- const totalNodes = this.db.prepare("SELECT COUNT(*) as count FROM nodes").get().count;
284
- const totalEdges = this.db.prepare("SELECT COUNT(*) as count FROM edges").get().count;
285
- const nodesByType = {};
286
- const nodeTypeRows = this.db.prepare("SELECT type, COUNT(*) as count FROM nodes GROUP BY type").all();
287
- for (const row of nodeTypeRows) {
288
- nodesByType[row.type] = row.count;
289
- }
290
- const edgesByType = {};
291
- const edgeTypeRows = this.db.prepare("SELECT type, COUNT(*) as count FROM edges GROUP BY type").all();
292
- for (const row of edgeTypeRows) {
293
- edgesByType[row.type] = row.count;
294
- }
295
- const languages = {};
296
- const langRows = this.db.prepare("SELECT language, COUNT(*) as count FROM files GROUP BY language").all();
297
- for (const row of langRows) {
298
- languages[row.language] = row.count;
299
- }
300
- return {
301
- totalFiles,
302
- totalNodes,
303
- totalEdges,
304
- nodesByType,
305
- edgesByType,
306
- languages
307
- };
308
- }
309
- // ============ Graph Export ============
310
- exportForVisualization() {
311
- const nodes = this.getAllNodes().map((n) => ({
312
- id: n.id,
313
- label: n.name,
314
- type: n.type,
315
- file: n.filePath
316
- }));
317
- const edges = this.getAllEdges().filter((e) => !e.targetId.startsWith("ref:")).map((e) => ({
318
- source: e.sourceId,
319
- target: e.targetId,
320
- type: e.type
321
- }));
322
- return { nodes, edges };
323
- }
324
- // ============ Cleanup ============
325
- clear() {
326
- this.db.exec(`
327
- DELETE FROM nodes;
328
- DELETE FROM edges;
329
- DELETE FROM files;
330
- DELETE FROM imports;
331
- DELETE FROM exports;
332
- `);
333
- }
334
- close() {
335
- this.db.close();
336
- }
337
- // ============ Metadata ============
338
- setMeta(key, value) {
339
- this.db.prepare("INSERT OR REPLACE INTO project_meta (key, value) VALUES (?, ?)").run(key, value);
340
- }
341
- getMeta(key) {
342
- const row = this.db.prepare("SELECT value FROM project_meta WHERE key = ?").get(key);
343
- return row?.value || null;
344
- }
345
- };
346
-
347
- export {
348
- GraphStorage
349
- };
350
- //# sourceMappingURL=chunk-5ONPBEWJ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/graph/storage.ts"],"sourcesContent":["/**\n * SQLite-based graph storage\n */\n\nimport Database from \"better-sqlite3\";\nimport type { GraphNode, GraphEdge, FileAnalysis, ProjectAnalysis } from \"../types.js\";\n\nexport class GraphStorage {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.initSchema();\n }\n\n private initSchema(): void {\n this.db.exec(`\n -- Nodes table\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n language TEXT NOT NULL,\n metadata TEXT\n );\n\n -- Edges table\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n metadata TEXT\n );\n\n -- Files table for tracking analyzed files\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n language TEXT NOT NULL,\n last_modified INTEGER,\n analyzed_at TEXT NOT NULL\n );\n\n -- Imports table\n CREATE TABLE IF NOT EXISTS imports (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n file_path TEXT NOT NULL,\n source TEXT NOT NULL,\n specifiers TEXT NOT NULL,\n is_default INTEGER NOT NULL,\n is_namespace INTEGER NOT NULL,\n line INTEGER NOT NULL\n );\n\n -- Exports table\n CREATE TABLE IF NOT EXISTS exports (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n file_path TEXT NOT NULL,\n name TEXT NOT NULL,\n is_default INTEGER NOT NULL,\n line INTEGER NOT NULL\n );\n\n -- Project metadata\n CREATE TABLE IF NOT EXISTS project_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n\n -- Indexes for faster queries\n CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_path);\n CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);\n CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);\n CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);\n CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);\n CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);\n CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path);\n CREATE INDEX IF NOT EXISTS idx_imports_source ON imports(source);\n CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path);\n `);\n }\n\n // ============ Node Operations ============\n\n insertNode(node: GraphNode): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO nodes (id, type, name, file_path, start_line, end_line, language, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n node.id,\n node.type,\n node.name,\n node.filePath,\n node.startLine,\n node.endLine,\n node.language,\n node.metadata ? JSON.stringify(node.metadata) : null\n );\n }\n\n getNode(id: string): GraphNode | null {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE id = ?\");\n const row = stmt.get(id) as any;\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n getNodesByFile(filePath: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE file_path = ?\");\n const rows = stmt.all(filePath) as any[];\n return rows.map(this.rowToNode);\n }\n\n getNodesByType(type: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE type = ?\");\n const rows = stmt.all(type) as any[];\n return rows.map(this.rowToNode);\n }\n\n searchNodes(query: string): GraphNode[] {\n const stmt = this.db.prepare(\n \"SELECT * FROM nodes WHERE name LIKE ? OR file_path LIKE ?\"\n );\n const pattern = `%${query}%`;\n const rows = stmt.all(pattern, pattern) as any[];\n return rows.map(this.rowToNode);\n }\n\n getAllNodes(): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes\");\n const rows = stmt.all() as any[];\n return rows.map(this.rowToNode);\n }\n\n private rowToNode(row: any): GraphNode {\n return {\n id: row.id,\n type: row.type,\n name: row.name,\n filePath: row.file_path,\n startLine: row.start_line,\n endLine: row.end_line,\n language: row.language,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n };\n }\n\n // ============ Edge Operations ============\n\n insertEdge(edge: GraphEdge): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO edges (id, type, source_id, target_id, metadata)\n VALUES (?, ?, ?, ?, ?)\n `);\n stmt.run(\n edge.id,\n edge.type,\n edge.sourceId,\n edge.targetId,\n edge.metadata ? JSON.stringify(edge.metadata) : null\n );\n }\n\n getEdgesFrom(sourceId: string): GraphEdge[] {\n const stmt = this.db.prepare(\"SELECT * FROM edges WHERE source_id = ?\");\n const rows = stmt.all(sourceId) as any[];\n return rows.map(this.rowToEdge);\n }\n\n getEdgesTo(targetId: string): GraphEdge[] {\n const stmt = this.db.prepare(\"SELECT * FROM edges WHERE target_id = ?\");\n const rows = stmt.all(targetId) as any[];\n return rows.map(this.rowToEdge);\n }\n\n getEdgesByType(type: string): GraphEdge[] {\n const stmt = this.db.prepare(\"SELECT * FROM edges WHERE type = ?\");\n const rows = stmt.all(type) as any[];\n return rows.map(this.rowToEdge);\n }\n\n getAllEdges(): GraphEdge[] {\n const stmt = this.db.prepare(\"SELECT * FROM edges\");\n const rows = stmt.all() as any[];\n return rows.map(this.rowToEdge);\n }\n\n private rowToEdge(row: any): GraphEdge {\n return {\n id: row.id,\n type: row.type,\n sourceId: row.source_id,\n targetId: row.target_id,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n };\n }\n\n // ============ File Analysis Operations ============\n\n insertFileAnalysis(analysis: FileAnalysis): void {\n const transaction = this.db.transaction(() => {\n // Delete old data for this file\n this.deleteFileData(analysis.filePath);\n\n // Insert file record\n const fileStmt = this.db.prepare(`\n INSERT OR REPLACE INTO files (path, language, analyzed_at)\n VALUES (?, ?, ?)\n `);\n fileStmt.run(analysis.filePath, analysis.language, new Date().toISOString());\n\n // Insert nodes\n for (const node of analysis.nodes) {\n this.insertNode(node);\n }\n\n // Insert edges\n for (const edge of analysis.edges) {\n this.insertEdge(edge);\n }\n\n // Insert imports\n const importStmt = this.db.prepare(`\n INSERT INTO imports (file_path, source, specifiers, is_default, is_namespace, line)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n for (const imp of analysis.imports) {\n importStmt.run(\n analysis.filePath,\n imp.source,\n JSON.stringify(imp.specifiers),\n imp.isDefault ? 1 : 0,\n imp.isNamespace ? 1 : 0,\n imp.line\n );\n }\n\n // Insert exports\n const exportStmt = this.db.prepare(`\n INSERT INTO exports (file_path, name, is_default, line)\n VALUES (?, ?, ?, ?)\n `);\n for (const exp of analysis.exports) {\n exportStmt.run(analysis.filePath, exp.name, exp.isDefault ? 1 : 0, exp.line);\n }\n });\n\n transaction();\n }\n\n deleteFileData(filePath: string): void {\n this.db.prepare(\"DELETE FROM nodes WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM imports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM exports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(filePath);\n // Note: Edges are more complex, we keep them and clean up later\n }\n\n // ============ Query Operations ============\n\n /**\n * Get all files that import from a given file/module\n */\n getFilesThatImport(modulePath: string): string[] {\n const stmt = this.db.prepare(`\n SELECT DISTINCT file_path FROM imports\n WHERE source LIKE ? OR source LIKE ?\n `);\n // Match both relative and absolute imports\n const rows = stmt.all(`%${modulePath}%`, modulePath) as any[];\n return rows.map((r) => r.file_path);\n }\n\n /**\n * Get all callers of a function/method\n */\n getCallers(nodeName: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT DISTINCT n.* FROM nodes n\n JOIN edges e ON n.id = e.source_id\n WHERE e.type = 'calls' AND e.target_id LIKE ?\n `);\n const rows = stmt.all(`%${nodeName}%`) as any[];\n return rows.map(this.rowToNode);\n }\n\n /**\n * Get all functions/methods called by a node\n */\n getCallees(nodeId: string): { name: string; line?: number }[] {\n const stmt = this.db.prepare(`\n SELECT target_id, metadata FROM edges\n WHERE source_id = ? AND type = 'calls'\n `);\n const rows = stmt.all(nodeId) as any[];\n return rows.map((r) => ({\n name: r.target_id.replace(\"ref:\", \"\"),\n line: r.metadata ? JSON.parse(r.metadata).line : undefined,\n }));\n }\n\n /**\n * Get the dependency tree for a file\n */\n getFileDependencies(filePath: string): { imports: string[]; importedBy: string[] } {\n const importsStmt = this.db.prepare(\n \"SELECT DISTINCT source FROM imports WHERE file_path = ?\"\n );\n const imports = (importsStmt.all(filePath) as any[]).map((r) => r.source);\n\n const importedBy = this.getFilesThatImport(\n filePath.replace(/\\.(ts|tsx|js|jsx|py)$/, \"\")\n );\n\n return { imports, importedBy };\n }\n\n /**\n * Get statistics about the graph\n */\n getStats(): {\n totalFiles: number;\n totalNodes: number;\n totalEdges: number;\n nodesByType: Record<string, number>;\n edgesByType: Record<string, number>;\n languages: Record<string, number>;\n } {\n const totalFiles =\n (this.db.prepare(\"SELECT COUNT(*) as count FROM files\").get() as any).count;\n const totalNodes =\n (this.db.prepare(\"SELECT COUNT(*) as count FROM nodes\").get() as any).count;\n const totalEdges =\n (this.db.prepare(\"SELECT COUNT(*) as count FROM edges\").get() as any).count;\n\n const nodesByType: Record<string, number> = {};\n const nodeTypeRows = this.db\n .prepare(\"SELECT type, COUNT(*) as count FROM nodes GROUP BY type\")\n .all() as any[];\n for (const row of nodeTypeRows) {\n nodesByType[row.type] = row.count;\n }\n\n const edgesByType: Record<string, number> = {};\n const edgeTypeRows = this.db\n .prepare(\"SELECT type, COUNT(*) as count FROM edges GROUP BY type\")\n .all() as any[];\n for (const row of edgeTypeRows) {\n edgesByType[row.type] = row.count;\n }\n\n const languages: Record<string, number> = {};\n const langRows = this.db\n .prepare(\"SELECT language, COUNT(*) as count FROM files GROUP BY language\")\n .all() as any[];\n for (const row of langRows) {\n languages[row.language] = row.count;\n }\n\n return {\n totalFiles,\n totalNodes,\n totalEdges,\n nodesByType,\n edgesByType,\n languages,\n };\n }\n\n // ============ Graph Export ============\n\n exportForVisualization(): {\n nodes: Array<{ id: string; label: string; type: string; file: string }>;\n edges: Array<{ source: string; target: string; type: string }>;\n } {\n const nodes = this.getAllNodes().map((n) => ({\n id: n.id,\n label: n.name,\n type: n.type,\n file: n.filePath,\n }));\n\n const edges = this.getAllEdges()\n .filter((e) => !e.targetId.startsWith(\"ref:\")) // Only resolved edges\n .map((e) => ({\n source: e.sourceId,\n target: e.targetId,\n type: e.type,\n }));\n\n return { nodes, edges };\n }\n\n // ============ Cleanup ============\n\n clear(): void {\n this.db.exec(`\n DELETE FROM nodes;\n DELETE FROM edges;\n DELETE FROM files;\n DELETE FROM imports;\n DELETE FROM exports;\n `);\n }\n\n close(): void {\n this.db.close();\n }\n\n // ============ Metadata ============\n\n setMeta(key: string, value: string): void {\n this.db.prepare(\"INSERT OR REPLACE INTO project_meta (key, value) VALUES (?, ?)\").run(key, value);\n }\n\n getMeta(key: string): string | null {\n const row = this.db.prepare(\"SELECT value FROM project_meta WHERE key = ?\").get(key) as any;\n return row?.value || null;\n }\n}\n"],"mappings":"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","names":[]}