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.
Files changed (95) hide show
  1. package/dist/agents/MainAgent.js +255 -0
  2. package/dist/agents/contextReviewStep.js +104 -0
  3. package/dist/agents/finalPlanGenStep.js +123 -0
  4. package/dist/agents/infoPlanGenStep.js +126 -0
  5. package/dist/agents/planGeneratorStep.js +118 -0
  6. package/dist/agents/planResolverStep.js +95 -0
  7. package/dist/agents/planTargetFilesStep.js +48 -0
  8. package/dist/agents/preFileSearchCheckStep.js +95 -0
  9. package/dist/agents/selectRelevantSourcesStep.js +100 -0
  10. package/dist/agents/semanticAnalysisStep.js +144 -0
  11. package/dist/agents/structuralAnalysisStep.js +46 -0
  12. package/dist/agents/transformPlanGenStep.js +107 -0
  13. package/dist/agents/understandIntentStep.js +72 -0
  14. package/dist/agents/validationAnalysisStep.js +87 -0
  15. package/dist/commands/AskCmd.js +47 -116
  16. package/dist/commands/ChangeLogUpdateCmd.js +11 -5
  17. package/dist/commands/CommitSuggesterCmd.js +50 -75
  18. package/dist/commands/DaemonCmd.js +119 -29
  19. package/dist/commands/IndexCmd.js +41 -24
  20. package/dist/commands/InspectCmd.js +0 -1
  21. package/dist/commands/ReadlineSingleton.js +18 -0
  22. package/dist/commands/ResetDbCmd.js +20 -21
  23. package/dist/commands/ReviewCmd.js +89 -54
  24. package/dist/commands/SummaryCmd.js +12 -18
  25. package/dist/commands/WorkflowCmd.js +41 -0
  26. package/dist/commands/factory.js +254 -0
  27. package/dist/config.js +67 -15
  28. package/dist/constants.js +20 -4
  29. package/dist/context.js +10 -11
  30. package/dist/daemon/daemonQueues.js +63 -0
  31. package/dist/daemon/daemonWorker.js +40 -63
  32. package/dist/daemon/generateSummaries.js +58 -0
  33. package/dist/daemon/runFolderCapsuleBatch.js +247 -0
  34. package/dist/daemon/runIndexingBatch.js +147 -0
  35. package/dist/daemon/runKgBatch.js +104 -0
  36. package/dist/db/fileIndex.js +168 -63
  37. package/dist/db/functionExtractors/extractFromJava.js +210 -6
  38. package/dist/db/functionExtractors/extractFromJs.js +173 -214
  39. package/dist/db/functionExtractors/extractFromTs.js +159 -160
  40. package/dist/db/functionExtractors/index.js +7 -5
  41. package/dist/db/schema.js +55 -20
  42. package/dist/db/sqlTemplates.js +50 -19
  43. package/dist/fileRules/builtins.js +31 -14
  44. package/dist/fileRules/codeAllowedExtensions.js +4 -0
  45. package/dist/fileRules/fileExceptions.js +0 -13
  46. package/dist/fileRules/ignoredExtensions.js +10 -0
  47. package/dist/index.js +128 -325
  48. package/dist/lib/generate.js +37 -14
  49. package/dist/lib/generateFolderCapsules.js +109 -0
  50. package/dist/lib/spinner.js +12 -5
  51. package/dist/modelSetup.js +0 -10
  52. package/dist/pipeline/modules/changeLogModule.js +16 -19
  53. package/dist/pipeline/modules/chunkManagerModule.js +24 -0
  54. package/dist/pipeline/modules/cleanupModule.js +96 -91
  55. package/dist/pipeline/modules/codeTransformModule.js +208 -0
  56. package/dist/pipeline/modules/commentModule.js +20 -11
  57. package/dist/pipeline/modules/commitSuggesterModule.js +36 -14
  58. package/dist/pipeline/modules/contextReviewModule.js +52 -0
  59. package/dist/pipeline/modules/fileReaderModule.js +72 -0
  60. package/dist/pipeline/modules/fileSearchModule.js +136 -0
  61. package/dist/pipeline/modules/finalAnswerModule.js +53 -0
  62. package/dist/pipeline/modules/gatherInfoModule.js +176 -0
  63. package/dist/pipeline/modules/generateTestsModule.js +63 -54
  64. package/dist/pipeline/modules/kgModule.js +26 -11
  65. package/dist/pipeline/modules/preserveCodeModule.js +91 -49
  66. package/dist/pipeline/modules/refactorModule.js +19 -7
  67. package/dist/pipeline/modules/repairTestsModule.js +44 -36
  68. package/dist/pipeline/modules/reviewModule.js +23 -13
  69. package/dist/pipeline/modules/summaryModule.js +27 -35
  70. package/dist/pipeline/modules/writeFileModule.js +86 -0
  71. package/dist/pipeline/registry/moduleRegistry.js +38 -93
  72. package/dist/pipeline/runModulePipeline.js +22 -19
  73. package/dist/scripts/dbcheck.js +143 -228
  74. package/dist/utils/buildContextualPrompt.js +245 -172
  75. package/dist/utils/debugContext.js +24 -0
  76. package/dist/utils/fileTree.js +16 -6
  77. package/dist/utils/loadRelevantFolderCapsules.js +64 -0
  78. package/dist/utils/log.js +2 -0
  79. package/dist/utils/normalizeData.js +23 -0
  80. package/dist/utils/planActions.js +60 -0
  81. package/dist/utils/promptBuilderHelper.js +67 -0
  82. package/dist/utils/promptLogHelper.js +52 -0
  83. package/dist/utils/sanitizeQuery.js +20 -8
  84. package/dist/utils/sleep.js +3 -0
  85. package/dist/utils/splitCodeIntoChunk.js +65 -32
  86. package/dist/utils/vscode.js +49 -0
  87. package/dist/workflow/workflowResolver.js +14 -0
  88. package/dist/workflow/workflowRunner.js +103 -0
  89. package/package.json +6 -5
  90. package/dist/agent/agentManager.js +0 -39
  91. package/dist/agent/workflowManager.js +0 -95
  92. package/dist/commands/ModulePipelineCmd.js +0 -31
  93. package/dist/daemon/daemonBatch.js +0 -186
  94. package/dist/fileRules/scoreFiles.js +0 -71
  95. 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 all function AST nodes ---
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
- db.prepare(markFileAsSkippedTemplate).run({ id: fileId });
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
- // --- LLM tagging ---
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 > 0) {
41
- const insertTag = db.prepare(insertGraphTagTemplate);
42
- const getTagId = db.prepare(selectGraphTagIdTemplate);
43
- const insertEntityTag = db.prepare(insertGraphEntityTagTemplate);
44
- for (const entity of kgResult.entities) {
45
- if (!entity.type || !Array.isArray(entity.tags) || entity.tags.length === 0)
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
- for (const tag of entity.tags) {
48
- if (!tag || typeof tag !== 'string')
49
- continue;
50
- try {
51
- insertTag.run({ name: tag });
52
- const tagRow = getTagId.get({ name: tag });
53
- if (!tagRow)
54
- continue;
55
- const matchedUniqueId = functions.find(f => f.name === entity.name)?.unique_id ||
56
- classes.find(c => c.name === entity.name)?.unique_id ||
57
- `${entity.name}@${filePath}`;
58
- insertEntityTag.run({
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
- log(`🏷 Persisted LLM-generated tags for ${filePath}`);
70
- }
82
+ };
83
+ kgResult.entities.forEach(persistEntityTags);
84
+ log(`🏷 Persisted LLM-generated tags for ${filePath}`);
71
85
  }
72
86
  catch (kgErr) {
73
- console.warn(`⚠️ KG tagging failed for ${filePath}:`, kgErr instanceof Error ? kgErr.message : kgErr);
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
- // --- Process functions ---
94
+ // --- Collect functions ---
95
+ const tsBuiltins = BUILTINS.ts;
76
96
  for (const funcNode of allFuncNodes) {
77
- const symbolName = funcNode.getSymbol()?.getName();
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
- calleeName = undefined;
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 (err) {
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 (err) {
148
- console.warn(`⚠️ Failed to inspect call expressions for function ${name} in ${filePath}:`, err);
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
- // --- Process classes ---
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
- const superClass = clsNode.getExtends()?.getText() ?? null;
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
- const embedding = await generateEmbedding(code);
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 (err) {
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
- // --- Imports ---
207
- try {
208
- const importDecls = sourceFile.getDescendantsOfKind(SyntaxKind.ImportDeclaration);
209
- for (const imp of importDecls) {
210
- const moduleSpecifier = imp.getModuleSpecifierValue();
211
- if (!moduleSpecifier)
212
- continue;
213
- const targetUniqueId = `file@${moduleSpecifier}`;
214
- try {
215
- db.prepare(insertEdgeTemplate).run({
216
- source_type: 'file',
217
- source_unique_id: normalizedPath,
218
- target_type: 'file',
219
- target_unique_id: targetUniqueId,
220
- relation: 'imports',
221
- });
222
- }
223
- catch (err) {
224
- console.error('❌ Failed to persist import edge', { filePath, moduleSpecifier, error: err });
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
- catch (err) {
229
- console.warn(`⚠️ Import extraction failed for ${filePath}:`, err);
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
- // --- Exports ---
232
- try {
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 targetUniqueId = `file@${moduleSpecifier}`;
239
- try {
240
- db.prepare(insertEdgeTemplate).run({
241
- source_type: 'file',
242
- source_unique_id: normalizedPath,
243
- target_type: 'file',
244
- target_unique_id: targetUniqueId,
245
- relation: 'exports',
246
- });
247
- }
248
- catch (err) {
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
- catch (err) {
254
- console.warn(`⚠️ Export extraction failed for ${filePath}:`, err);
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(` ↳ ${String(err.message)}`);
264
- db.prepare(markFileAsFailedTemplate).run({ id: fileId });
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(`⚠️ Java extraction not implemented for ${filePath}`);
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, -- full path
8
+ path TEXT UNIQUE, -- full path
9
9
  filename TEXT,
10
- summary TEXT,
11
- type TEXT,
12
- indexed_at TEXT,
13
- last_modified TEXT,
14
- embedding TEXT,
15
- processing_status TEXT NOT NULL DEFAULT 'unprocessed',
16
- functions_extracted_at TEXT
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(filename, summary, path, content='files', content_rowid='id');
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, -- e.g. "UserService@src/services/UserService.ts"
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, -- 'function' | 'class' | 'file' | 'test'
60
- source_unique_id TEXT NOT NULL, -- full unique_id (e.g., function@filePath, filePath)
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 -- e.g., 'calls', 'imports', 'exports', 'tests'
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, -- 'function' | 'class' | 'file'
80
- entity_unique_id TEXT NOT NULL, -- match against functions.unique_id, classes.unique_id, or files.path
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
- console.log("✅ Graph schema initialized (files, functions, classes, edges, tags with unique_ids)");
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
  }