scai 0.1.115 β†’ 0.1.117

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.
@@ -9,7 +9,6 @@ if (!repoKey) {
9
9
  console.error("❌ No active repo found. Use `scai set-index` to set one.");
10
10
  process.exit(1);
11
11
  }
12
- // Get the basename (repo name) from the full repoKey (which is the path)
13
12
  const repoName = path.basename(repoKey);
14
13
  const scaiRepoRoot = path.join(os.homedir(), ".scai", "repos", repoName);
15
14
  const dbPath = path.join(scaiRepoRoot, "db.sqlite");
@@ -18,307 +17,253 @@ if (!fs.existsSync(dbPath)) {
18
17
  process.exit(1);
19
18
  }
20
19
  const db = new Database(dbPath);
21
- // === Basic Stats ===
22
- const stats = {
23
- total: db.prepare('SELECT COUNT(*) as count FROM files').get().count,
24
- withSummary: db.prepare(`SELECT COUNT(*) as count FROM files WHERE summary IS NOT NULL AND summary != ''`).get().count,
25
- withoutSummary: db.prepare(`SELECT COUNT(*) as count FROM files WHERE summary IS NULL OR summary = ''`).get().count,
26
- withEmbedding: db.prepare(`SELECT COUNT(*) as count FROM files WHERE embedding IS NOT NULL AND embedding != ''`).get().count,
27
- withoutEmbedding: db.prepare(`SELECT COUNT(*) as count FROM files WHERE embedding IS NULL OR embedding = ''`).get().count,
28
- withProcessingStatusExtracted: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'extracted'`).get().count,
29
- withoutProcessingStatusExtracted: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status IS NULL OR processing_status != 'extracted'`).get().count,
30
- withProcessingStatusSkipped: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'skipped'`).get().count,
31
- withProcessingStatusFailed: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'failed'`).get().count,
32
- withProcessingStatusUnprocessed: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'unprocessed'`).get().count,
33
- };
34
- console.log("πŸ“Š SQLite Stats for Table: files");
35
- console.log("-------------------------------------------");
36
- console.log(`πŸ”’ Total rows: ${stats.total}`);
37
- console.log(`βœ… With summary: ${stats.withSummary}`);
38
- console.log(`❌ Without summary: ${stats.withoutSummary}`);
39
- console.log(`βœ… With embedding: ${stats.withEmbedding}`);
40
- console.log(`❌ Without embedding: ${stats.withoutEmbedding}`);
41
- console.log(`βœ… With processing_status = 'extracted': ${stats.withProcessingStatusExtracted}`);
42
- console.log(`❌ Without processing_status = 'extracted': ${stats.withoutProcessingStatusExtracted}`);
43
- console.log(`βœ… With processing_status = 'skipped': ${stats.withProcessingStatusSkipped}`);
44
- console.log(`βœ… With processing_status = 'failed': ${stats.withProcessingStatusFailed}`);
45
- console.log(`βœ… With processing_status = 'unprocessed': ${stats.withProcessingStatusUnprocessed}`);
46
- // === Example Summaries ===
47
- console.log("\n🧾 Example summaries and embeddings:\n--------------------------");
48
- console.log("Example summaries (first 50 characters):");
49
- const summaries = db.prepare(`
50
- SELECT id, substr(summary, 1, 50) || '...' AS short_summary
20
+ // Utility to log simple table stats
21
+ function tableStats(table, column) {
22
+ const total = db.prepare(`SELECT COUNT(*) AS count FROM ${table}`).get().count;
23
+ let extra = "";
24
+ if (column) {
25
+ const nonNull = db.prepare(`SELECT COUNT(*) AS count FROM ${table} WHERE ${column} IS NOT NULL AND ${column} != ''`).get().count;
26
+ extra = ` | Non-null ${column}: ${nonNull}`;
27
+ }
28
+ console.log(`πŸ“Š ${table}: ${total}${extra}`);
29
+ }
30
+ // === Files Table ===
31
+ console.log("\nπŸ—‚ Table: files");
32
+ tableStats("files", "summary");
33
+ tableStats("files", "embedding");
34
+ const processingStatuses = ["extracted", "skipped", "failed", "unprocessed"];
35
+ for (const status of processingStatuses) {
36
+ const count = db.prepare(`SELECT COUNT(*) AS count FROM files WHERE processing_status = ?`).get(status).count;
37
+ console.log(` Status '${status}': ${count}`);
38
+ }
39
+ // === Example Files ===
40
+ const exampleFiles = db.prepare(`
41
+ SELECT id, filename, substr(summary,1,50) AS summary, substr(embedding,1,50) AS embedding
51
42
  FROM files
52
- WHERE summary IS NOT NULL AND summary != ''
53
43
  LIMIT 5
54
44
  `).all();
55
- summaries.forEach(row => {
56
- console.log(`${row.id.toString().padEnd(4)} ${row.short_summary}`);
45
+ console.log("\n🧾 Example Files:");
46
+ exampleFiles.forEach(f => {
47
+ console.log(` [${f.id}] ${f.filename} | summary: "${f.summary}" | embedding: "${f.embedding}"`);
57
48
  });
58
- console.log("\nExample embeddings (first 50 characters):");
59
- const embeddings = db.prepare(`
60
- SELECT id, substr(embedding, 1, 50) || '...' AS short_embedding
61
- FROM files
62
- WHERE embedding IS NOT NULL AND embedding != ''
49
+ // === FTS5 Check ===
50
+ const ftsExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='files_fts'`).get();
51
+ console.log("\nπŸ” FTS5 Table:", ftsExists ? "βœ… exists" : "❌ missing");
52
+ // === Functions Table ===
53
+ console.log("\nπŸ§‘β€πŸ’» Table: functions");
54
+ tableStats("functions");
55
+ const sampleFuncs = db.prepare(`
56
+ SELECT id, name, file_id, substr(content,1,50) AS preview
57
+ FROM functions
58
+ ORDER BY RANDOM()
63
59
  LIMIT 5
64
60
  `).all();
65
- embeddings.forEach(row => {
66
- console.log(`${row.id.toString().padEnd(4)} ${row.short_embedding}`);
61
+ sampleFuncs.forEach(f => {
62
+ console.log(` [${f.id}] ${f.name} (file ${f.file_id}): ${f.preview}`);
67
63
  });
68
- // === FTS5 Check ===
69
- console.log("\nπŸ” FTS5 Check");
70
- console.log("--------------------------");
71
- try {
72
- const ftsExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='files_fts'`).get();
73
- if (!ftsExists) {
74
- console.log("❌ No FTS5 table `files_fts` found in database.");
75
- }
76
- else {
77
- const ftsRowCount = db.prepare(`SELECT COUNT(*) AS count FROM files_fts`).get().count;
78
- console.log(`βœ… files_fts table exists. Rows: ${ftsRowCount}`);
79
- }
80
- }
81
- catch (err) {
82
- console.error("❌ Error while accessing files_fts:", err.message);
83
- }
84
- // === Rebuild FTS Index ===
85
- console.log("\nπŸ”§ Rebuilding FTS5 index...");
86
- try {
87
- db.prepare(`INSERT INTO files_fts(files_fts) VALUES ('rebuild')`).run();
88
- console.log(`βœ… Rebuild completed.`);
89
- }
90
- catch (err) {
91
- console.error("❌ FTS5 rebuild failed:", err.message);
92
- }
93
- // === FTS Search Test ===
94
- console.log('\nπŸ” Test MATCH query for "minimap":');
95
- try {
96
- const minimapMatches = db.prepare(`
97
- SELECT f.id, f.path
98
- FROM files f
99
- JOIN files_fts fts ON f.id = fts.rowid
100
- WHERE fts.files_fts MATCH 'minimap'
101
- LIMIT 10
102
- `).all();
103
- if (minimapMatches.length === 0) {
104
- console.warn('⚠️ No matches for "minimap" in FTS index');
105
- }
106
- else {
107
- minimapMatches.forEach(row => {
108
- console.log(`πŸ“„ ${row.path}`);
109
- });
110
- }
111
- }
112
- catch (err) {
113
- console.error('❌ Error running MATCH query:', err.message);
114
- }
115
- // === Direct LIKE Fallback ===
116
- console.log('\nπŸ” Direct LIKE query on path for "minimap":');
117
- const likeMatches = db.prepare(`
118
- SELECT id, path
119
- FROM files
120
- WHERE path LIKE '%minimap%'
121
- LIMIT 10
64
+ // === Graph Classes Table ===
65
+ console.log("\n🏷 Table: graph_classes");
66
+ tableStats("graph_classes");
67
+ const sampleClasses = db.prepare(`
68
+ SELECT id, name, file_id, substr(content,1,50) AS preview
69
+ FROM graph_classes
70
+ ORDER BY RANDOM()
71
+ LIMIT 5
122
72
  `).all();
123
- if (likeMatches.length === 0) {
124
- console.warn('⚠️ No file paths contain "minimap"');
125
- }
126
- else {
127
- likeMatches.forEach(row => {
128
- console.log(`πŸ“„ ${row.path}`);
129
- });
130
- }
131
- // === Function Table Stats ===
132
- console.log('\nπŸ“Š Stats for Table: functions');
133
- console.log('-------------------------------------------');
134
- try {
135
- const funcCount = db.prepare(`SELECT COUNT(*) AS count FROM functions`).get().count;
136
- const distinctFiles = db.prepare(`SELECT COUNT(DISTINCT file_id) AS count FROM functions`).get().count;
137
- console.log(`πŸ”’ Total functions: ${funcCount}`);
138
- console.log(`πŸ“‚ Distinct files: ${distinctFiles}`);
139
- }
140
- catch (err) {
141
- console.error('❌ Error accessing functions table:', err.message);
142
- }
143
- // === Example Functions ===
144
- console.log('\nπŸ§ͺ Example extracted functions:');
145
- try {
146
- const sampleFunctions = db.prepare(`
147
- SELECT id, name, start_line, end_line, substr(content, 1, 100) || '...' AS short_body
148
- FROM functions
149
- ORDER BY id DESC
150
- LIMIT 5
151
- `).all();
152
- sampleFunctions.forEach(fn => {
153
- console.log(`πŸ”Ή ID: ${fn.id}`);
154
- console.log(` Name: ${fn.name}`);
155
- console.log(` Lines: ${fn.start_line}-${fn.end_line}`);
156
- console.log(` Body: ${fn.short_body}\n`);
157
- });
158
- }
159
- catch (err) {
160
- console.error('❌ Error printing function examples:', err.message);
161
- }
162
- // === Function Calls Table Stats ===
163
- console.log('\nπŸ“Š Stats for Table: function_calls');
164
- console.log('-------------------------------------------');
165
- try {
166
- const callCount = db.prepare(`SELECT COUNT(*) AS count FROM function_calls`).get().count;
167
- const topCallers = db.prepare(`
168
- SELECT caller_id, COUNT(*) AS num_calls
169
- FROM function_calls
170
- GROUP BY caller_id
171
- ORDER BY num_calls DESC
172
- LIMIT 5
173
- `).all();
174
- console.log(`πŸ” Total function calls: ${callCount}`);
175
- console.log('πŸ“ž Top callers:');
176
- topCallers.forEach(row => {
177
- console.log(` - Caller ${row.caller_id} made ${row.num_calls} calls`);
178
- });
179
- }
180
- catch (err) {
181
- console.error('❌ Error accessing function_calls table:', err.message);
182
- }
183
- // === Random Summary Samples ===
184
- console.log('\n🧾 Random Summaries (ID + Preview):');
185
- console.log('-------------------------------------------');
186
- const randomSummaries = db.prepare(`
187
- SELECT id, filename, substr(summary, 1, 1000) || '...' AS preview
188
- FROM files
189
- WHERE summary IS NOT NULL AND summary != ''
73
+ sampleClasses.forEach(c => {
74
+ console.log(` [${c.id}] ${c.name} (file ${c.file_id}): ${c.preview}`);
75
+ });
76
+ // === Graph Edges Table ===
77
+ console.log("\nπŸ”— Table: graph_edges");
78
+ tableStats("graph_edges", "relation");
79
+ // Dynamically get column names
80
+ const columns = db.prepare(`PRAGMA table_info(graph_edges)`).all();
81
+ const colNames = columns.map(c => c.name);
82
+ // Determine source/target ID columns
83
+ const sourceCol = colNames.includes("source_id") ? "source_id" : "source_unique_id";
84
+ const targetCol = colNames.includes("target_id") ? "target_id" : "target_unique_id";
85
+ const sampleEdges = db.prepare(`
86
+ SELECT id, source_type, ${sourceCol} AS source_id,
87
+ target_type, ${targetCol} AS target_id,
88
+ relation
89
+ FROM graph_edges
190
90
  ORDER BY RANDOM()
191
91
  LIMIT 5
192
92
  `).all();
193
- randomSummaries.forEach(row => {
194
- console.log(`πŸ“„ [${row.id}] ${row.filename}: ${row.preview}`);
93
+ sampleEdges.forEach(e => {
94
+ console.log(` [${e.id}] ${e.source_type}(${e.source_id}) -[${e.relation}]-> ${e.target_type}(${e.target_id})`);
195
95
  });
196
- // === Random Functions Samples ===
197
- console.log('\nπŸ§‘β€πŸ’» 20 Random Functions (ID, name, body):');
198
- console.log('-------------------------------------------');
199
- const randomFunctions = db.prepare(`
200
- SELECT id, name, file_id, substr(content, 1, 100) || '...' AS preview
201
- FROM functions
96
+ // === Tags Tables ===
97
+ console.log("\n🏷 Table: graph_tags_master");
98
+ tableStats("graph_tags_master");
99
+ const sampleTags = db.prepare(`
100
+ SELECT id, name
101
+ FROM graph_tags_master
202
102
  ORDER BY RANDOM()
203
103
  LIMIT 5
204
104
  `).all();
205
- randomFunctions.forEach(row => {
206
- console.log(`πŸ”Ή [${row.id}] ${row.name} (file_id: ${row.file_id})`);
207
- console.log(` ${row.preview}\n`);
105
+ sampleTags.forEach(t => {
106
+ console.log(` [${t.id}] ${t.name}`);
208
107
  });
209
- // === Column View of Files ===
210
- console.log('\nπŸ“Š Table View: Files');
211
- console.log('-------------------------------------------');
212
- const fileRows = db.prepare(`
213
- SELECT id, filename, type, processing_status, functions_extracted_at, length(summary) AS summary_len
214
- FROM files
215
- LIMIT 50
108
+ console.log("\nπŸ”– Table: graph_entity_tags");
109
+ tableStats("graph_entity_tags");
110
+ const sampleEntityTags = db.prepare(`
111
+ SELECT id, entity_type, entity_unique_id AS entity_id, tag_id
112
+ FROM graph_entity_tags
113
+ ORDER BY RANDOM()
114
+ LIMIT 5
216
115
  `).all();
217
- console.table(fileRows);
218
- // === Column View of Functions ===
219
- console.log('\nπŸ“Š Table View: Functions');
220
- console.log('-------------------------------------------');
221
- const functionRows = db.prepare(`
222
- SELECT id, file_id, name, start_line, end_line, length(content) AS length
223
- FROM functions
224
- LIMIT 50
116
+ sampleEntityTags.forEach(et => {
117
+ console.log(` [${et.id}] ${et.entity_type}(${et.entity_id}) -> tag ${et.tag_id}`);
118
+ });
119
+ // === Function β†’ Edges Check ===
120
+ console.log("\nπŸ•Έ Function Calls / CalledBy consistency");
121
+ // 1. Check for edges pointing to missing functions
122
+ const missingFuncs = db.prepare(`
123
+ SELECT e.id, e.source_unique_id, e.target_unique_id
124
+ FROM graph_edges e
125
+ WHERE e.source_type = 'function'
126
+ AND NOT EXISTS (SELECT 1 FROM functions f WHERE f.unique_id = e.source_unique_id)
127
+ UNION
128
+ SELECT e.id, e.source_unique_id, e.target_unique_id
129
+ FROM graph_edges e
130
+ WHERE e.target_type = 'function'
131
+ AND NOT EXISTS (SELECT 1 FROM functions f WHERE f.unique_id = e.target_unique_id)
132
+ LIMIT 10
225
133
  `).all();
226
- console.table(functionRows);
227
- // === Class Table Stats ===
228
- console.log('\nπŸ“Š Stats for Table: classes');
229
- console.log('-------------------------------------------');
230
- try {
231
- const classCount = db.prepare(`SELECT COUNT(*) AS count FROM classes`).get().count;
232
- const distinctClassFiles = db.prepare(`SELECT COUNT(DISTINCT file_id) AS count FROM classes`).get().count;
233
- console.log(`🏷 Total classes: ${classCount}`);
234
- console.log(`πŸ“‚ Distinct files: ${distinctClassFiles}`);
235
- }
236
- catch (err) {
237
- console.error('❌ Error accessing classes table:', err.message);
134
+ if (missingFuncs.length === 0) {
135
+ console.log("βœ… All edges reference valid functions.");
238
136
  }
239
- // === Example Classes ===
240
- console.log('\nπŸ§ͺ Example extracted classes:');
241
- try {
242
- const sampleClasses = db.prepare(`
243
- SELECT id, name, file_id, start_line, end_line, substr(content, 1, 100) || '...' AS short_body
244
- FROM classes
245
- ORDER BY id DESC
246
- LIMIT 5
247
- `).all();
248
- sampleClasses.forEach(cls => {
249
- console.log(`🏷 ID: ${cls.id}`);
250
- console.log(` Name: ${cls.name}`);
251
- console.log(` File: ${cls.file_id}`);
252
- console.log(` Lines: ${cls.start_line}-${cls.end_line}`);
253
- console.log(` Body: ${cls.short_body}\n`);
137
+ else {
138
+ console.log("❌ Found edges pointing to missing functions:");
139
+ missingFuncs.forEach(e => {
140
+ console.log(` Edge ${e.id}: ${e.source_unique_id} -> ${e.target_unique_id}`);
254
141
  });
255
142
  }
256
- catch (err) {
257
- console.error('❌ Error printing class examples:', err.message);
143
+ // 2. Functions with outgoing calls
144
+ const funcWithCalls = db.prepare(`
145
+ SELECT f.id, f.name, COUNT(e.id) AS callCount
146
+ FROM functions f
147
+ JOIN graph_edges e
148
+ ON e.source_type = 'function'
149
+ AND e.source_unique_id = f.unique_id
150
+ GROUP BY f.id
151
+ HAVING callCount > 0
152
+ ORDER BY callCount DESC
153
+ LIMIT 5
154
+ `).all();
155
+ funcWithCalls.forEach(f => {
156
+ console.log(` πŸ”Ή Function [${f.id}] ${f.name} has ${f.callCount} outgoing calls`);
157
+ });
158
+ // 3. Functions with incoming calls
159
+ const funcWithCalledBy = db.prepare(`
160
+ SELECT f.id, f.name, COUNT(e.id) AS calledByCount
161
+ FROM functions f
162
+ JOIN graph_edges e
163
+ ON e.target_type = 'function'
164
+ AND e.target_unique_id = f.unique_id
165
+ GROUP BY f.id
166
+ HAVING calledByCount > 0
167
+ ORDER BY calledByCount DESC
168
+ LIMIT 5
169
+ `).all();
170
+ funcWithCalledBy.forEach(f => {
171
+ console.log(` πŸ”Έ Function [${f.id}] ${f.name} is called by ${f.calledByCount} functions`);
172
+ });
173
+ // 4. Check for duplicate edges (same source→target)
174
+ const duplicateEdges = db.prepare(`
175
+ SELECT source_unique_id, target_unique_id, COUNT(*) as dupCount
176
+ FROM graph_edges
177
+ WHERE source_type = 'function' AND target_type = 'function'
178
+ GROUP BY source_unique_id, target_unique_id
179
+ HAVING dupCount > 1
180
+ LIMIT 5
181
+ `).all();
182
+ if (duplicateEdges.length > 0) {
183
+ console.log("⚠️ Duplicate function call edges found:");
184
+ duplicateEdges.forEach(d => {
185
+ console.log(` ${d.source_unique_id} -> ${d.target_unique_id} (x${d.dupCount})`);
186
+ });
258
187
  }
259
- // === Edge Table Stats ===
260
- console.log('\nπŸ“Š Stats for Table: edges');
261
- console.log('-------------------------------------------');
262
- try {
263
- const edgeCount = db.prepare(`SELECT COUNT(*) AS count FROM edges`).get().count;
264
- const distinctRelations = db.prepare(`SELECT COUNT(DISTINCT relation) AS count FROM edges`).get().count;
265
- console.log(`πŸ”— Total edges: ${edgeCount}`);
266
- console.log(`🧩 Distinct relations: ${distinctRelations}`);
188
+ else {
189
+ console.log("βœ… No duplicate function call edges.");
267
190
  }
268
- catch (err) {
269
- console.error('❌ Error accessing edges table:', err.message);
191
+ // === File-specific check (AskCmd.ts) ===
192
+ const targetPath = "/Users/rzs/dev/repos/scai/cli/src/commands/AskCmd.ts";
193
+ // --- MUST KEEP: find the file row ---
194
+ const targetFile = db.prepare(`
195
+ SELECT id, path, filename, processing_status
196
+ FROM files
197
+ WHERE path = ?
198
+ `).get(targetPath);
199
+ if (!targetFile) {
200
+ console.log(`❌ File not found in DB: ${targetPath}`);
270
201
  }
271
- // === Example Edges ===
272
- console.log('\nπŸ§ͺ Example edges:');
273
- try {
274
- const sampleEdges = db.prepare(`
275
- SELECT id, source_id, target_id, relation
276
- FROM edges
277
- ORDER BY id DESC
278
- LIMIT 10
279
- `).all();
280
- sampleEdges.forEach(e => {
281
- console.log(`πŸ”— Edge ${e.id}: ${e.source_id} -[${e.relation}]-> ${e.target_id}`);
202
+ else {
203
+ console.log(`\nπŸ“‚ File found: [${targetFile.id}] ${targetFile.filename} (${targetFile.processing_status})`);
204
+ // --- MUST KEEP: list functions in this file ---
205
+ const funcs = db.prepare(`
206
+ SELECT id, name, unique_id, start_line, end_line
207
+ FROM functions
208
+ WHERE file_id = ?
209
+ ORDER BY start_line
210
+ `).all(targetFile.id);
211
+ console.log(` Functions (${funcs.length}):`);
212
+ funcs.forEach((f) => {
213
+ console.log(` [${f.id}] ${f.name} (${f.unique_id}) lines ${f.start_line}-${f.end_line}`);
282
214
  });
283
- }
284
- catch (err) {
285
- console.error('❌ Error printing edge examples:', err.message);
286
- }
287
- // === Tags Master Stats ===
288
- console.log('\nπŸ“Š Stats for Table: tags_master');
289
- console.log('-------------------------------------------');
290
- try {
291
- const tagCount = db.prepare(`SELECT COUNT(*) AS count FROM tags_master`).get().count;
292
- console.log(`🏷 Total tags: ${tagCount}`);
293
- const sampleTags = db.prepare(`
294
- SELECT id, name
295
- FROM tags_master
296
- ORDER BY id DESC
297
- LIMIT 5
298
- `).all();
299
- sampleTags.forEach(tag => {
300
- console.log(`🏷 Tag ${tag.id}: ${tag.name}`);
215
+ // --- OPTIONAL: outgoing calls from this file’s functions ---
216
+ const outgoing = db.prepare(`
217
+ SELECT f.name AS source_name, e.target_unique_id, e.relation
218
+ FROM functions f
219
+ JOIN graph_edges e
220
+ ON e.source_unique_id = f.unique_id
221
+ AND e.source_type = 'function'
222
+ WHERE f.file_id = ?
223
+ `).all(targetFile.id);
224
+ console.log(` Outgoing calls (${outgoing.length}):`);
225
+ outgoing.forEach((o) => {
226
+ console.log(` ${o.source_name} -[${o.relation}]-> ${o.target_unique_id}`);
301
227
  });
302
- }
303
- catch (err) {
304
- console.error('❌ Error accessing tags_master table:', err.message);
305
- }
306
- // === Entity Tags Stats ===
307
- console.log('\nπŸ“Š Stats for Table: entity_tags');
308
- console.log('-------------------------------------------');
309
- try {
310
- const entityTagCount = db.prepare(`SELECT COUNT(*) AS count FROM entity_tags`).get().count;
311
- console.log(`πŸ”— Total entity-tags: ${entityTagCount}`);
312
- const sampleEntityTags = db.prepare(`
313
- SELECT id, entity_type, entity_id, tag_id
314
- FROM entity_tags
315
- ORDER BY id DESC
316
- LIMIT 10
317
- `).all();
318
- sampleEntityTags.forEach(et => {
319
- console.log(`πŸ”— EntityTag ${et.id}: ${et.entity_type} ${et.entity_id} -> tag ${et.tag_id}`);
228
+ // --- OPTIONAL: incoming calls to this file’s functions ---
229
+ const incoming = db.prepare(`
230
+ SELECT f.name AS target_name, e.source_unique_id, e.relation
231
+ FROM functions f
232
+ JOIN graph_edges e
233
+ ON e.target_unique_id = f.unique_id
234
+ AND e.target_type = 'function'
235
+ WHERE f.file_id = ?
236
+ `).all(targetFile.id);
237
+ console.log(` Incoming calls (${incoming.length}):`);
238
+ incoming.forEach((i) => {
239
+ console.log(` ${i.source_unique_id} -[${i.relation}]-> ${i.target_name}`);
320
240
  });
241
+ // --- NICE TO HAVE: dangling edges check ---
242
+ const dangling = db.prepare(`
243
+ SELECT e.id, e.source_unique_id, e.target_unique_id, e.relation
244
+ FROM graph_edges e
245
+ WHERE e.source_unique_id IN (SELECT unique_id FROM functions WHERE file_id = ?)
246
+ OR e.target_unique_id IN (SELECT unique_id FROM functions WHERE file_id = ?)
247
+ `).all(targetFile.id, targetFile.id);
248
+ console.log(` Edges referencing this file's functions (dangling check): ${dangling.length}`);
249
+ dangling.forEach((d) => {
250
+ console.log(` Edge ${d.id}: ${d.source_unique_id} -[${d.relation}]-> ${d.target_unique_id}`);
251
+ });
252
+ // --- OPTIONAL: consistency check summary ---
253
+ if (funcs.length > 0 && outgoing.length === 0 && incoming.length === 0 && dangling.length === 0) {
254
+ console.log("⚠️ This file has functions but no graph edges. Possible causes:");
255
+ console.log(" - Edges were never extracted for this file, OR");
256
+ console.log(" - unique_id mismatch between functions and edges.");
257
+ }
258
+ else {
259
+ console.log("βœ… Edges and functions are consistent for this file.");
260
+ }
261
+ const funcsDebug = db.prepare(`
262
+ SELECT id, name, unique_id
263
+ FROM functions
264
+ WHERE file_id = ?
265
+ `).all(targetFile.id);
266
+ console.log("Funcsdebug:\n");
267
+ console.log(funcsDebug);
321
268
  }
322
- catch (err) {
323
- console.error('❌ Error accessing entity_tags table:', err.message);
324
- }
269
+ console.log("\nβœ… DB check completed.\n");