scai 0.1.117 → 0.1.118
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.
- package/dist/agents/MainAgent.js +255 -0
- package/dist/agents/contextReviewStep.js +104 -0
- package/dist/agents/finalPlanGenStep.js +123 -0
- package/dist/agents/infoPlanGenStep.js +126 -0
- package/dist/agents/planGeneratorStep.js +118 -0
- package/dist/agents/planResolverStep.js +95 -0
- package/dist/agents/planTargetFilesStep.js +48 -0
- package/dist/agents/preFileSearchCheckStep.js +95 -0
- package/dist/agents/selectRelevantSourcesStep.js +100 -0
- package/dist/agents/semanticAnalysisStep.js +144 -0
- package/dist/agents/structuralAnalysisStep.js +46 -0
- package/dist/agents/transformPlanGenStep.js +107 -0
- package/dist/agents/understandIntentStep.js +72 -0
- package/dist/agents/validationAnalysisStep.js +87 -0
- package/dist/commands/AskCmd.js +47 -116
- package/dist/commands/ChangeLogUpdateCmd.js +11 -5
- package/dist/commands/CommitSuggesterCmd.js +50 -75
- package/dist/commands/DaemonCmd.js +119 -29
- package/dist/commands/IndexCmd.js +41 -24
- package/dist/commands/InspectCmd.js +0 -1
- package/dist/commands/ReadlineSingleton.js +18 -0
- package/dist/commands/ResetDbCmd.js +20 -21
- package/dist/commands/ReviewCmd.js +89 -54
- package/dist/commands/SummaryCmd.js +12 -18
- package/dist/commands/WorkflowCmd.js +41 -0
- package/dist/commands/factory.js +254 -0
- package/dist/config.js +67 -15
- package/dist/constants.js +20 -4
- package/dist/context.js +10 -11
- package/dist/daemon/daemonQueues.js +63 -0
- package/dist/daemon/daemonWorker.js +40 -63
- package/dist/daemon/generateSummaries.js +58 -0
- package/dist/daemon/runFolderCapsuleBatch.js +247 -0
- package/dist/daemon/runIndexingBatch.js +147 -0
- package/dist/daemon/runKgBatch.js +104 -0
- package/dist/db/fileIndex.js +168 -63
- package/dist/db/functionExtractors/extractFromJava.js +210 -6
- package/dist/db/functionExtractors/extractFromJs.js +173 -214
- package/dist/db/functionExtractors/extractFromTs.js +159 -160
- package/dist/db/functionExtractors/index.js +7 -5
- package/dist/db/schema.js +55 -20
- package/dist/db/sqlTemplates.js +50 -19
- package/dist/fileRules/builtins.js +31 -14
- package/dist/fileRules/codeAllowedExtensions.js +4 -0
- package/dist/fileRules/fileExceptions.js +0 -13
- package/dist/fileRules/ignoredExtensions.js +10 -0
- package/dist/index.js +128 -325
- package/dist/lib/generate.js +37 -14
- package/dist/lib/generateFolderCapsules.js +109 -0
- package/dist/lib/spinner.js +12 -5
- package/dist/modelSetup.js +0 -10
- package/dist/pipeline/modules/changeLogModule.js +16 -19
- package/dist/pipeline/modules/chunkManagerModule.js +24 -0
- package/dist/pipeline/modules/cleanupModule.js +96 -91
- package/dist/pipeline/modules/codeTransformModule.js +208 -0
- package/dist/pipeline/modules/commentModule.js +20 -11
- package/dist/pipeline/modules/commitSuggesterModule.js +36 -14
- package/dist/pipeline/modules/contextReviewModule.js +52 -0
- package/dist/pipeline/modules/fileReaderModule.js +72 -0
- package/dist/pipeline/modules/fileSearchModule.js +136 -0
- package/dist/pipeline/modules/finalAnswerModule.js +53 -0
- package/dist/pipeline/modules/gatherInfoModule.js +176 -0
- package/dist/pipeline/modules/generateTestsModule.js +63 -54
- package/dist/pipeline/modules/kgModule.js +26 -11
- package/dist/pipeline/modules/preserveCodeModule.js +91 -49
- package/dist/pipeline/modules/refactorModule.js +19 -7
- package/dist/pipeline/modules/repairTestsModule.js +44 -36
- package/dist/pipeline/modules/reviewModule.js +23 -13
- package/dist/pipeline/modules/summaryModule.js +27 -35
- package/dist/pipeline/modules/writeFileModule.js +86 -0
- package/dist/pipeline/registry/moduleRegistry.js +38 -93
- package/dist/pipeline/runModulePipeline.js +22 -19
- package/dist/scripts/dbcheck.js +143 -228
- package/dist/utils/buildContextualPrompt.js +245 -172
- package/dist/utils/debugContext.js +24 -0
- package/dist/utils/fileTree.js +16 -6
- package/dist/utils/loadRelevantFolderCapsules.js +64 -0
- package/dist/utils/log.js +2 -0
- package/dist/utils/normalizeData.js +23 -0
- package/dist/utils/planActions.js +60 -0
- package/dist/utils/promptBuilderHelper.js +67 -0
- package/dist/utils/promptLogHelper.js +52 -0
- package/dist/utils/sanitizeQuery.js +20 -8
- package/dist/utils/sleep.js +3 -0
- package/dist/utils/splitCodeIntoChunk.js +65 -32
- package/dist/utils/vscode.js +49 -0
- package/dist/workflow/workflowResolver.js +14 -0
- package/dist/workflow/workflowRunner.js +103 -0
- package/package.json +6 -5
- package/dist/agent/agentManager.js +0 -39
- package/dist/agent/workflowManager.js +0 -95
- package/dist/commands/ModulePipelineCmd.js +0 -31
- package/dist/daemon/daemonBatch.js +0 -186
- package/dist/fileRules/scoreFiles.js +0 -71
- package/dist/lib/generateEmbedding.js +0 -22
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Project, SyntaxKind, } from 'ts-morph';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { generateEmbedding } from '../../lib/generateEmbedding.js';
|
|
4
3
|
import { log } from '../../utils/log.js';
|
|
5
4
|
import { getDbForRepo } from '../client.js';
|
|
6
5
|
import { markFileAsSkippedTemplate, markFileAsExtractedTemplate, markFileAsFailedTemplate, insertFunctionTemplate, insertGraphClassTemplate, insertEdgeTemplate, insertGraphEntityTagTemplate, insertGraphTagTemplate, selectGraphTagIdTemplate, } from '../sqlTemplates.js';
|
|
@@ -13,104 +12,94 @@ export async function extractFromTS(filePath, content, fileId) {
|
|
|
13
12
|
try {
|
|
14
13
|
const project = new Project({ useInMemoryFileSystem: true });
|
|
15
14
|
const sourceFile = project.createSourceFile(filePath, content);
|
|
16
|
-
// DTO arrays used to store into functions / graph_classes later (FTS index)
|
|
17
15
|
const functions = [];
|
|
18
16
|
const classes = [];
|
|
19
|
-
// --- Gather
|
|
17
|
+
// --- Gather AST nodes ---
|
|
20
18
|
const allFuncNodes = [
|
|
21
19
|
...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration),
|
|
22
20
|
...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionExpression),
|
|
23
21
|
...sourceFile.getDescendantsOfKind(SyntaxKind.ArrowFunction),
|
|
24
22
|
];
|
|
25
|
-
// --- Gather all class AST nodes ---
|
|
26
23
|
const allClassNodes = [
|
|
27
24
|
...sourceFile.getDescendantsOfKind(SyntaxKind.ClassDeclaration),
|
|
28
25
|
...sourceFile.getDescendantsOfKind(SyntaxKind.ClassExpression),
|
|
29
26
|
];
|
|
30
27
|
if (allFuncNodes.length === 0 && allClassNodes.length === 0) {
|
|
31
28
|
log(`⚠️ No functions/classes found in TS file: ${filePath}`);
|
|
32
|
-
|
|
29
|
+
try {
|
|
30
|
+
db.prepare(markFileAsSkippedTemplate).run({ id: fileId });
|
|
31
|
+
}
|
|
32
|
+
catch { }
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
35
|
log(`🔍 Found ${allFuncNodes.length} functions and ${allClassNodes.length} classes in ${filePath}`);
|
|
36
|
-
// ---
|
|
36
|
+
// --- Knowledge Graph tagging ---
|
|
37
37
|
try {
|
|
38
38
|
const kgInput = { fileId, filepath: filePath, summary: undefined };
|
|
39
39
|
const kgResult = await kgModule.run(kgInput, content);
|
|
40
|
-
if (kgResult.entities?.length
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
if (!kgResult.entities?.length) {
|
|
41
|
+
log(`⚠️ KG returned no entities for ${filePath}`);
|
|
42
|
+
try {
|
|
43
|
+
db.prepare(markFileAsFailedTemplate).run({ id: fileId });
|
|
44
|
+
}
|
|
45
|
+
catch { }
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const insertTagStmt = db.prepare(insertGraphTagTemplate);
|
|
49
|
+
const getTagIdStmt = db.prepare(selectGraphTagIdTemplate);
|
|
50
|
+
const insertEntityTagStmt = db.prepare(insertGraphEntityTagTemplate);
|
|
51
|
+
const persistTag = (tag) => {
|
|
52
|
+
try {
|
|
53
|
+
insertTagStmt.run({ name: tag });
|
|
54
|
+
const tagRow = getTagIdStmt.get({ name: tag });
|
|
55
|
+
return tagRow?.id;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const persistEntityTags = (entity) => {
|
|
62
|
+
if (!entity.type || !Array.isArray(entity.tags) || entity.tags.length === 0)
|
|
63
|
+
return;
|
|
64
|
+
for (const tag of entity.tags) {
|
|
65
|
+
if (!tag || typeof tag !== 'string')
|
|
46
66
|
continue;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
entity_type: entity.type,
|
|
60
|
-
entity_unique_id: matchedUniqueId,
|
|
61
|
-
tag_id: tagRow.id,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
catch (err) {
|
|
65
|
-
console.error('❌ Failed to persist entity/tag', { entity, tag, error: err });
|
|
66
|
-
}
|
|
67
|
+
const tagId = persistTag(tag);
|
|
68
|
+
if (!tagId)
|
|
69
|
+
continue;
|
|
70
|
+
const matchedUniqueId = functions.find(f => f.name === entity.name)?.unique_id ||
|
|
71
|
+
classes.find(c => c.name === entity.name)?.unique_id ||
|
|
72
|
+
`${entity.name}@${filePath}`;
|
|
73
|
+
try {
|
|
74
|
+
insertEntityTagStmt.run({
|
|
75
|
+
entity_type: entity.type,
|
|
76
|
+
entity_unique_id: matchedUniqueId,
|
|
77
|
+
tag_id: tagId,
|
|
78
|
+
});
|
|
67
79
|
}
|
|
80
|
+
catch { }
|
|
68
81
|
}
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
};
|
|
83
|
+
kgResult.entities.forEach(persistEntityTags);
|
|
84
|
+
log(`🏷 Persisted LLM-generated tags for ${filePath}`);
|
|
71
85
|
}
|
|
72
86
|
catch (kgErr) {
|
|
73
|
-
|
|
87
|
+
log(`⚠️ KG tagging failed for ${filePath}: ${kgErr.message}`);
|
|
88
|
+
try {
|
|
89
|
+
db.prepare(markFileAsFailedTemplate).run({ id: fileId });
|
|
90
|
+
}
|
|
91
|
+
catch { }
|
|
92
|
+
return false;
|
|
74
93
|
}
|
|
75
|
-
// ---
|
|
94
|
+
// --- Collect functions ---
|
|
95
|
+
const tsBuiltins = BUILTINS.ts;
|
|
76
96
|
for (const funcNode of allFuncNodes) {
|
|
77
|
-
const
|
|
78
|
-
const name = symbolName ?? '<anon>';
|
|
97
|
+
const name = funcNode.getSymbol()?.getName() ?? '<anon>';
|
|
79
98
|
const start = funcNode.getStartLineNumber();
|
|
80
99
|
const end = funcNode.getEndLineNumber();
|
|
81
100
|
const code = funcNode.getText();
|
|
82
101
|
const unique_id = getUniqueId(name, filePath, start, funcNode.getStart(), code);
|
|
83
102
|
functions.push({ name, start_line: start, end_line: end, content: code, unique_id });
|
|
84
|
-
try {
|
|
85
|
-
const embedding = await generateEmbedding(code);
|
|
86
|
-
db.prepare(insertFunctionTemplate).run({
|
|
87
|
-
file_id: fileId,
|
|
88
|
-
name,
|
|
89
|
-
start_line: start,
|
|
90
|
-
end_line: end,
|
|
91
|
-
content: code,
|
|
92
|
-
embedding: JSON.stringify(embedding),
|
|
93
|
-
lang: 'ts',
|
|
94
|
-
unique_id,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
console.error('❌ Failed to insert function row', { filePath, name, error: err });
|
|
99
|
-
}
|
|
100
|
-
// File -> Function 'contains' edge
|
|
101
|
-
try {
|
|
102
|
-
db.prepare(insertEdgeTemplate).run({
|
|
103
|
-
source_type: 'file',
|
|
104
|
-
source_unique_id: normalizedPath,
|
|
105
|
-
target_type: 'function',
|
|
106
|
-
target_unique_id: unique_id,
|
|
107
|
-
relation: 'contains',
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
console.error('❌ Failed to persist file->function edge', { filePath, name, error: err });
|
|
112
|
-
}
|
|
113
|
-
// AST-based calls
|
|
114
103
|
try {
|
|
115
104
|
const callExprs = funcNode.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
116
105
|
const edgeSet = new Set();
|
|
@@ -120,10 +109,8 @@ export async function extractFromTS(filePath, content, fileId) {
|
|
|
120
109
|
const expr = callExpr.getExpression();
|
|
121
110
|
calleeName = expr.getSymbol()?.getName() ?? expr.getText();
|
|
122
111
|
}
|
|
123
|
-
catch {
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
if (!calleeName || BUILTINS.has(calleeName))
|
|
112
|
+
catch { /* ignore symbol resolution errors */ }
|
|
113
|
+
if (!calleeName || tsBuiltins.has(calleeName))
|
|
127
114
|
continue;
|
|
128
115
|
const targetUniqueId = `${calleeName}@${normalizedPath}`;
|
|
129
116
|
const edgeKey = `${unique_id}->${targetUniqueId}`;
|
|
@@ -138,54 +125,27 @@ export async function extractFromTS(filePath, content, fileId) {
|
|
|
138
125
|
relation: 'calls',
|
|
139
126
|
});
|
|
140
127
|
}
|
|
141
|
-
catch
|
|
142
|
-
console.error('❌ Failed to persist call edge', { filePath, name, calleeName, error: err });
|
|
143
|
-
}
|
|
128
|
+
catch { /* ignore DB insert errors */ }
|
|
144
129
|
}
|
|
145
130
|
}
|
|
146
131
|
}
|
|
147
|
-
catch (
|
|
148
|
-
|
|
132
|
+
catch (funcErr) {
|
|
133
|
+
log(`⚠️ Failed to process call expressions in function ${name} of ${filePath}: ${funcErr.message}`);
|
|
149
134
|
}
|
|
150
|
-
log(`📌 Indexed TS function: ${name} (unique_id=${unique_id})`);
|
|
151
135
|
}
|
|
152
|
-
// ---
|
|
136
|
+
// --- Collect classes ---
|
|
153
137
|
for (const clsNode of allClassNodes) {
|
|
154
138
|
const name = clsNode.getName() ?? `${path.basename(filePath)}:<anon-class>`;
|
|
155
139
|
const start = clsNode.getStartLineNumber();
|
|
156
140
|
const end = clsNode.getEndLineNumber();
|
|
157
141
|
const code = clsNode.getText();
|
|
158
|
-
|
|
159
|
-
const unique_id = getUniqueId(name, filePath, start, clsNode.getStart(), code);
|
|
160
|
-
classes.push({ name, start_line: start, end_line: end, content: code, superClass, unique_id });
|
|
142
|
+
let superClass = null;
|
|
161
143
|
try {
|
|
162
|
-
|
|
163
|
-
db.prepare(insertGraphClassTemplate).run({
|
|
164
|
-
file_id: fileId,
|
|
165
|
-
name,
|
|
166
|
-
start_line: start,
|
|
167
|
-
end_line: end,
|
|
168
|
-
content: code,
|
|
169
|
-
embedding: JSON.stringify(embedding),
|
|
170
|
-
lang: 'ts',
|
|
171
|
-
unique_id,
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
catch (err) {
|
|
175
|
-
console.error('❌ Failed to insert graph class row', { filePath, name, error: err });
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
db.prepare(insertEdgeTemplate).run({
|
|
179
|
-
source_type: 'file',
|
|
180
|
-
source_unique_id: normalizedPath,
|
|
181
|
-
target_type: 'class',
|
|
182
|
-
target_unique_id: unique_id,
|
|
183
|
-
relation: 'contains',
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
catch (err) {
|
|
187
|
-
console.error('❌ Failed to persist file->class edge', { filePath, name, error: err });
|
|
144
|
+
superClass = clsNode.getExtends()?.getText() ?? null;
|
|
188
145
|
}
|
|
146
|
+
catch { /* ignore */ }
|
|
147
|
+
const unique_id = getUniqueId(name, filePath, start, clsNode.getStart(), code);
|
|
148
|
+
classes.push({ name, start_line: start, end_line: end, content: code, superClass, unique_id });
|
|
189
149
|
if (superClass) {
|
|
190
150
|
try {
|
|
191
151
|
db.prepare(insertEdgeTemplate).run({
|
|
@@ -196,72 +156,111 @@ export async function extractFromTS(filePath, content, fileId) {
|
|
|
196
156
|
relation: 'inherits',
|
|
197
157
|
});
|
|
198
158
|
}
|
|
199
|
-
catch
|
|
200
|
-
console.error('❌ Failed to persist inherits edge', { filePath, name, superClass, error: err });
|
|
201
|
-
}
|
|
202
|
-
log(`🔗 Class ${name} extends ${superClass} (edge stored for later resolution)`);
|
|
159
|
+
catch { /* ignore DB insert errors */ }
|
|
203
160
|
}
|
|
204
|
-
log(`🏷 Indexed TS class: ${name} (unique_id=${unique_id})`);
|
|
205
161
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
162
|
+
const seenEdges = new Set();
|
|
163
|
+
// --- Insert functions ---
|
|
164
|
+
for (const fn of functions) {
|
|
165
|
+
db.prepare(insertFunctionTemplate).run({
|
|
166
|
+
file_id: fileId,
|
|
167
|
+
name: fn.name ?? '<anon>',
|
|
168
|
+
start_line: fn.start_line ?? -1,
|
|
169
|
+
end_line: fn.end_line ?? -1,
|
|
170
|
+
content: fn.content ?? '',
|
|
171
|
+
embedding: null,
|
|
172
|
+
lang: 'ts',
|
|
173
|
+
unique_id: fn.unique_id,
|
|
174
|
+
});
|
|
175
|
+
const containsEdgeKey = `file->${fn.unique_id}`;
|
|
176
|
+
if (!seenEdges.has(containsEdgeKey)) {
|
|
177
|
+
db.prepare(insertEdgeTemplate).run({
|
|
178
|
+
source_type: 'file',
|
|
179
|
+
source_unique_id: normalizedPath,
|
|
180
|
+
target_type: 'function',
|
|
181
|
+
target_unique_id: fn.unique_id,
|
|
182
|
+
relation: 'contains',
|
|
183
|
+
});
|
|
184
|
+
seenEdges.add(containsEdgeKey);
|
|
226
185
|
}
|
|
227
186
|
}
|
|
228
|
-
|
|
229
|
-
|
|
187
|
+
// --- Insert classes ---
|
|
188
|
+
for (const cls of classes) {
|
|
189
|
+
db.prepare(insertGraphClassTemplate).run({
|
|
190
|
+
file_id: fileId,
|
|
191
|
+
name: cls.name,
|
|
192
|
+
start_line: cls.start_line ?? -1,
|
|
193
|
+
end_line: cls.end_line ?? -1,
|
|
194
|
+
content: cls.content ?? '',
|
|
195
|
+
embedding: null,
|
|
196
|
+
lang: 'ts',
|
|
197
|
+
unique_id: cls.unique_id,
|
|
198
|
+
});
|
|
199
|
+
const containsEdgeKey = `file->${cls.unique_id}`;
|
|
200
|
+
if (!seenEdges.has(containsEdgeKey)) {
|
|
201
|
+
db.prepare(insertEdgeTemplate).run({
|
|
202
|
+
source_type: 'file',
|
|
203
|
+
source_unique_id: normalizedPath,
|
|
204
|
+
target_type: 'class',
|
|
205
|
+
target_unique_id: cls.unique_id,
|
|
206
|
+
relation: 'contains',
|
|
207
|
+
});
|
|
208
|
+
seenEdges.add(containsEdgeKey);
|
|
209
|
+
}
|
|
230
210
|
}
|
|
231
|
-
// ---
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.error('❌ Failed to persist export edge', { filePath, moduleSpecifier, error: err });
|
|
250
|
-
}
|
|
211
|
+
// --- Imports ---
|
|
212
|
+
const importDecls = sourceFile.getDescendantsOfKind(SyntaxKind.ImportDeclaration);
|
|
213
|
+
for (const imp of importDecls) {
|
|
214
|
+
const moduleSpecifier = imp.getModuleSpecifierValue();
|
|
215
|
+
if (!moduleSpecifier)
|
|
216
|
+
continue;
|
|
217
|
+
const resolvedPath = moduleSpecifier.startsWith('.')
|
|
218
|
+
? path.resolve(path.dirname(filePath), moduleSpecifier)
|
|
219
|
+
: moduleSpecifier;
|
|
220
|
+
const normalizedTarget = path.normalize(resolvedPath).replace(/\\/g, '/');
|
|
221
|
+
try {
|
|
222
|
+
db.prepare(insertEdgeTemplate).run({
|
|
223
|
+
source_type: 'file',
|
|
224
|
+
source_unique_id: normalizedPath,
|
|
225
|
+
target_type: 'file',
|
|
226
|
+
target_unique_id: normalizedTarget,
|
|
227
|
+
relation: 'imports',
|
|
228
|
+
});
|
|
251
229
|
}
|
|
230
|
+
catch { /* ignore */ }
|
|
252
231
|
}
|
|
253
|
-
|
|
254
|
-
|
|
232
|
+
// --- Exports ---
|
|
233
|
+
const exportDecls = sourceFile.getDescendantsOfKind(SyntaxKind.ExportDeclaration);
|
|
234
|
+
for (const exp of exportDecls) {
|
|
235
|
+
const moduleSpecifier = exp.getModuleSpecifierValue();
|
|
236
|
+
if (!moduleSpecifier)
|
|
237
|
+
continue;
|
|
238
|
+
const resolvedPath = moduleSpecifier.startsWith('.')
|
|
239
|
+
? path.resolve(path.dirname(filePath), moduleSpecifier)
|
|
240
|
+
: moduleSpecifier;
|
|
241
|
+
const normalizedTarget = path.normalize(resolvedPath).replace(/\\/g, '/');
|
|
242
|
+
try {
|
|
243
|
+
db.prepare(insertEdgeTemplate).run({
|
|
244
|
+
source_type: 'file',
|
|
245
|
+
source_unique_id: normalizedPath,
|
|
246
|
+
target_type: 'file',
|
|
247
|
+
target_unique_id: normalizedTarget,
|
|
248
|
+
relation: 'exports',
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
catch { /* ignore */ }
|
|
255
252
|
}
|
|
256
253
|
db.prepare(markFileAsExtractedTemplate).run({ id: fileId });
|
|
257
254
|
log(`📊 Extraction summary for ${filePath}: ${functions.length} functions, ${classes.length} classes`);
|
|
258
|
-
log(`✅ Marked TS functions/classes as extracted for ${filePath}`);
|
|
259
255
|
return true;
|
|
260
256
|
}
|
|
261
257
|
catch (err) {
|
|
262
258
|
log(`❌ Failed to extract from TS file: ${filePath}`);
|
|
263
|
-
log(` ↳ ${
|
|
264
|
-
|
|
259
|
+
log(` ↳ ${err.message}`);
|
|
260
|
+
try {
|
|
261
|
+
db.prepare(markFileAsFailedTemplate).run({ id: fileId });
|
|
262
|
+
}
|
|
263
|
+
catch { }
|
|
265
264
|
return false;
|
|
266
265
|
}
|
|
267
266
|
}
|
|
@@ -6,9 +6,15 @@ import { extractFromTS } from "./extractFromTs.js";
|
|
|
6
6
|
import { extractFromXML } from "./extractFromXML.js";
|
|
7
7
|
import { detectFileType } from "../../fileRules/detectFileType.js";
|
|
8
8
|
import { log } from "../../utils/log.js";
|
|
9
|
+
import { CODE_ALLOWED_EXTENSIONS } from "../../fileRules/codeAllowedExtensions.js";
|
|
9
10
|
export async function extractFunctionsFromFile(filePath, content, fileId) {
|
|
10
11
|
const type = detectFileType(filePath).trim().toLowerCase();
|
|
11
12
|
const db = getDbForRepo();
|
|
13
|
+
if (!CODE_ALLOWED_EXTENSIONS.includes(type)) {
|
|
14
|
+
log(`⚠️ File type not allowed for code extraction: ${type}. Skipping ${filePath}`);
|
|
15
|
+
db.prepare(markFileAsSkippedByPath).run({ path: filePath });
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
12
18
|
try {
|
|
13
19
|
let success = false;
|
|
14
20
|
switch (type) {
|
|
@@ -23,17 +29,13 @@ export async function extractFunctionsFromFile(filePath, content, fileId) {
|
|
|
23
29
|
success = await extractFromTS(filePath, content, fileId);
|
|
24
30
|
break;
|
|
25
31
|
case 'java':
|
|
26
|
-
log(
|
|
32
|
+
log(`📘 Extracting Java code from ${filePath}`);
|
|
27
33
|
await extractFromJava(filePath, content, fileId);
|
|
28
34
|
return false;
|
|
29
35
|
case 'xml':
|
|
30
36
|
log(`⚠️ XML extraction not implemented for ${filePath}`);
|
|
31
37
|
await extractFromXML(filePath, content, fileId);
|
|
32
38
|
return false;
|
|
33
|
-
default:
|
|
34
|
-
log(`⚠️ Unsupported file type: ${type}. Skipping ${filePath}`);
|
|
35
|
-
db.prepare(markFileAsSkippedByPath).run({ path: filePath });
|
|
36
|
-
return false;
|
|
37
39
|
}
|
|
38
40
|
return success;
|
|
39
41
|
}
|
package/dist/db/schema.js
CHANGED
|
@@ -5,20 +5,46 @@ export function initSchema() {
|
|
|
5
5
|
db.exec(`
|
|
6
6
|
CREATE TABLE IF NOT EXISTS files (
|
|
7
7
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
-
path TEXT UNIQUE,
|
|
8
|
+
path TEXT UNIQUE, -- full path
|
|
9
9
|
filename TEXT,
|
|
10
|
-
summary TEXT,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
last_modified TEXT,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
summary TEXT, -- optional, can be generated later
|
|
11
|
+
content_text TEXT, -- actual file content
|
|
12
|
+
type TEXT, -- file type
|
|
13
|
+
last_modified TEXT, -- file system last modified
|
|
14
|
+
indexed_at TEXT, -- timestamp when indexed
|
|
15
|
+
functions_extracted_at TEXT, -- timestamp when functions/classes extracted
|
|
16
|
+
processing_status TEXT NOT NULL DEFAULT 'unprocessed' -- tracks pipeline stage
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
CREATE VIRTUAL TABLE IF NOT EXISTS files_fts
|
|
20
|
-
USING fts5(
|
|
20
|
+
USING fts5(
|
|
21
|
+
filename,
|
|
22
|
+
summary,
|
|
23
|
+
path,
|
|
24
|
+
content_text,
|
|
25
|
+
content='files',
|
|
26
|
+
content_rowid='id'
|
|
27
|
+
);
|
|
21
28
|
`);
|
|
29
|
+
// --- Folder capsules ---
|
|
30
|
+
db.exec(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS folder_capsules (
|
|
32
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
|
+
path TEXT UNIQUE NOT NULL,
|
|
34
|
+
depth INTEGER NOT NULL,
|
|
35
|
+
capsule_json TEXT NOT NULL,
|
|
36
|
+
confidence REAL,
|
|
37
|
+
last_generated TEXT,
|
|
38
|
+
source_file_count INTEGER
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_folder_capsules_path
|
|
42
|
+
ON folder_capsules(path);
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_folder_capsules_depth
|
|
45
|
+
ON folder_capsules(depth);
|
|
46
|
+
`);
|
|
47
|
+
// --- Functions table ---
|
|
22
48
|
db.exec(`
|
|
23
49
|
CREATE TABLE IF NOT EXISTS functions (
|
|
24
50
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -28,7 +54,6 @@ export function initSchema() {
|
|
|
28
54
|
start_line INTEGER,
|
|
29
55
|
end_line INTEGER,
|
|
30
56
|
content TEXT,
|
|
31
|
-
embedding TEXT,
|
|
32
57
|
lang TEXT
|
|
33
58
|
);
|
|
34
59
|
|
|
@@ -41,33 +66,30 @@ export function initSchema() {
|
|
|
41
66
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
42
67
|
file_id INTEGER REFERENCES files(id),
|
|
43
68
|
name TEXT,
|
|
44
|
-
unique_id TEXT UNIQUE,
|
|
69
|
+
unique_id TEXT UNIQUE,
|
|
45
70
|
start_line INTEGER,
|
|
46
71
|
end_line INTEGER,
|
|
47
72
|
content TEXT,
|
|
48
|
-
embedding TEXT,
|
|
49
73
|
lang TEXT
|
|
50
74
|
);
|
|
51
75
|
|
|
52
76
|
CREATE INDEX IF NOT EXISTS idx_graph_classes_file_id ON graph_classes(file_id);
|
|
53
77
|
CREATE INDEX IF NOT EXISTS idx_graph_classes_unique_id ON graph_classes(unique_id);
|
|
54
78
|
`);
|
|
55
|
-
// Edges table (all relationships live here: calls, inherits, contains, imports, exports, tests, etc.)
|
|
56
79
|
db.exec(`
|
|
57
80
|
CREATE TABLE IF NOT EXISTS graph_edges (
|
|
58
81
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
59
|
-
source_type TEXT NOT NULL,
|
|
60
|
-
source_unique_id TEXT NOT NULL,
|
|
82
|
+
source_type TEXT NOT NULL,
|
|
83
|
+
source_unique_id TEXT NOT NULL,
|
|
61
84
|
target_type TEXT NOT NULL,
|
|
62
85
|
target_unique_id TEXT NOT NULL,
|
|
63
|
-
relation TEXT NOT NULL
|
|
86
|
+
relation TEXT NOT NULL
|
|
64
87
|
);
|
|
65
88
|
|
|
66
89
|
CREATE INDEX IF NOT EXISTS idx_graph_edges_source ON graph_edges(source_type, source_unique_id);
|
|
67
90
|
CREATE INDEX IF NOT EXISTS idx_graph_edges_target ON graph_edges(target_type, target_unique_id);
|
|
68
91
|
CREATE INDEX IF NOT EXISTS idx_graph_edges_relation ON graph_edges(relation);
|
|
69
92
|
`);
|
|
70
|
-
// Tags setup
|
|
71
93
|
db.exec(`
|
|
72
94
|
CREATE TABLE IF NOT EXISTS graph_tags_master (
|
|
73
95
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -76,8 +98,8 @@ export function initSchema() {
|
|
|
76
98
|
|
|
77
99
|
CREATE TABLE IF NOT EXISTS graph_entity_tags (
|
|
78
100
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
79
|
-
entity_type TEXT NOT NULL,
|
|
80
|
-
entity_unique_id TEXT NOT NULL,
|
|
101
|
+
entity_type TEXT NOT NULL,
|
|
102
|
+
entity_unique_id TEXT NOT NULL,
|
|
81
103
|
tag_id INTEGER NOT NULL REFERENCES graph_tags_master(id),
|
|
82
104
|
UNIQUE(entity_type, entity_unique_id, tag_id)
|
|
83
105
|
);
|
|
@@ -85,5 +107,18 @@ export function initSchema() {
|
|
|
85
107
|
CREATE INDEX IF NOT EXISTS idx_graph_entity_tags_entity ON graph_entity_tags(entity_type, entity_unique_id);
|
|
86
108
|
CREATE INDEX IF NOT EXISTS idx_graph_entity_tags_tag ON graph_entity_tags(tag_id);
|
|
87
109
|
`);
|
|
88
|
-
|
|
110
|
+
db.exec(`
|
|
111
|
+
CREATE TABLE IF NOT EXISTS summaries (
|
|
112
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
113
|
+
path TEXT UNIQUE,
|
|
114
|
+
type TEXT NOT NULL CHECK (type IN ('folder','project')),
|
|
115
|
+
summary TEXT,
|
|
116
|
+
last_generated TEXT,
|
|
117
|
+
child_latest_modified TEXT
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
CREATE INDEX IF NOT EXISTS idx_summaries_type ON summaries(type);
|
|
121
|
+
CREATE INDEX IF NOT EXISTS idx_summaries_path ON summaries(path);
|
|
122
|
+
`);
|
|
123
|
+
console.log("✅ Graph schema initialized (files, functions, classes, edges, tags, summaries, FTS content_text)");
|
|
89
124
|
}
|