scai 0.1.117 → 0.1.119

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 (96) hide show
  1. package/README.md +88 -503
  2. package/dist/agents/MainAgent.js +255 -0
  3. package/dist/agents/contextReviewStep.js +104 -0
  4. package/dist/agents/finalPlanGenStep.js +123 -0
  5. package/dist/agents/infoPlanGenStep.js +126 -0
  6. package/dist/agents/planGeneratorStep.js +118 -0
  7. package/dist/agents/planResolverStep.js +95 -0
  8. package/dist/agents/planTargetFilesStep.js +48 -0
  9. package/dist/agents/preFileSearchCheckStep.js +95 -0
  10. package/dist/agents/selectRelevantSourcesStep.js +100 -0
  11. package/dist/agents/semanticAnalysisStep.js +144 -0
  12. package/dist/agents/structuralAnalysisStep.js +46 -0
  13. package/dist/agents/transformPlanGenStep.js +107 -0
  14. package/dist/agents/understandIntentStep.js +72 -0
  15. package/dist/agents/validationAnalysisStep.js +87 -0
  16. package/dist/commands/AskCmd.js +47 -116
  17. package/dist/commands/ChangeLogUpdateCmd.js +11 -5
  18. package/dist/commands/CommitSuggesterCmd.js +50 -75
  19. package/dist/commands/DaemonCmd.js +119 -29
  20. package/dist/commands/IndexCmd.js +41 -24
  21. package/dist/commands/InspectCmd.js +0 -1
  22. package/dist/commands/ReadlineSingleton.js +18 -0
  23. package/dist/commands/ResetDbCmd.js +20 -21
  24. package/dist/commands/ReviewCmd.js +89 -54
  25. package/dist/commands/SummaryCmd.js +12 -18
  26. package/dist/commands/WorkflowCmd.js +41 -0
  27. package/dist/commands/factory.js +254 -0
  28. package/dist/config.js +67 -15
  29. package/dist/constants.js +20 -4
  30. package/dist/context.js +10 -11
  31. package/dist/daemon/daemonQueues.js +63 -0
  32. package/dist/daemon/daemonWorker.js +40 -63
  33. package/dist/daemon/generateSummaries.js +58 -0
  34. package/dist/daemon/runFolderCapsuleBatch.js +247 -0
  35. package/dist/daemon/runIndexingBatch.js +147 -0
  36. package/dist/daemon/runKgBatch.js +104 -0
  37. package/dist/db/fileIndex.js +168 -63
  38. package/dist/db/functionExtractors/extractFromJava.js +210 -6
  39. package/dist/db/functionExtractors/extractFromJs.js +173 -214
  40. package/dist/db/functionExtractors/extractFromTs.js +159 -160
  41. package/dist/db/functionExtractors/index.js +7 -5
  42. package/dist/db/schema.js +55 -20
  43. package/dist/db/sqlTemplates.js +50 -19
  44. package/dist/fileRules/builtins.js +31 -14
  45. package/dist/fileRules/codeAllowedExtensions.js +4 -0
  46. package/dist/fileRules/fileExceptions.js +0 -13
  47. package/dist/fileRules/ignoredExtensions.js +10 -0
  48. package/dist/index.js +128 -325
  49. package/dist/lib/generate.js +37 -14
  50. package/dist/lib/generateFolderCapsules.js +109 -0
  51. package/dist/lib/spinner.js +12 -5
  52. package/dist/modelSetup.js +1 -11
  53. package/dist/pipeline/modules/changeLogModule.js +16 -19
  54. package/dist/pipeline/modules/chunkManagerModule.js +24 -0
  55. package/dist/pipeline/modules/cleanupModule.js +95 -91
  56. package/dist/pipeline/modules/codeTransformModule.js +208 -0
  57. package/dist/pipeline/modules/commentModule.js +20 -11
  58. package/dist/pipeline/modules/commitSuggesterModule.js +36 -14
  59. package/dist/pipeline/modules/contextReviewModule.js +52 -0
  60. package/dist/pipeline/modules/fileReaderModule.js +72 -0
  61. package/dist/pipeline/modules/fileSearchModule.js +136 -0
  62. package/dist/pipeline/modules/finalAnswerModule.js +53 -0
  63. package/dist/pipeline/modules/gatherInfoModule.js +176 -0
  64. package/dist/pipeline/modules/generateTestsModule.js +63 -54
  65. package/dist/pipeline/modules/kgModule.js +26 -11
  66. package/dist/pipeline/modules/preserveCodeModule.js +91 -49
  67. package/dist/pipeline/modules/refactorModule.js +19 -7
  68. package/dist/pipeline/modules/repairTestsModule.js +44 -36
  69. package/dist/pipeline/modules/reviewModule.js +23 -13
  70. package/dist/pipeline/modules/summaryModule.js +27 -35
  71. package/dist/pipeline/modules/writeFileModule.js +86 -0
  72. package/dist/pipeline/registry/moduleRegistry.js +38 -93
  73. package/dist/pipeline/runModulePipeline.js +22 -19
  74. package/dist/scripts/dbcheck.js +143 -228
  75. package/dist/utils/buildContextualPrompt.js +245 -172
  76. package/dist/utils/debugContext.js +24 -0
  77. package/dist/utils/fileTree.js +16 -6
  78. package/dist/utils/loadRelevantFolderCapsules.js +64 -0
  79. package/dist/utils/log.js +2 -0
  80. package/dist/utils/normalizeData.js +23 -0
  81. package/dist/utils/planActions.js +60 -0
  82. package/dist/utils/promptBuilderHelper.js +67 -0
  83. package/dist/utils/promptLogHelper.js +52 -0
  84. package/dist/utils/sanitizeQuery.js +20 -8
  85. package/dist/utils/sleep.js +3 -0
  86. package/dist/utils/splitCodeIntoChunk.js +65 -32
  87. package/dist/utils/vscode.js +49 -0
  88. package/dist/workflow/workflowResolver.js +14 -0
  89. package/dist/workflow/workflowRunner.js +103 -0
  90. package/package.json +6 -5
  91. package/dist/agent/agentManager.js +0 -39
  92. package/dist/agent/workflowManager.js +0 -95
  93. package/dist/commands/ModulePipelineCmd.js +0 -31
  94. package/dist/daemon/daemonBatch.js +0 -186
  95. package/dist/fileRules/scoreFiles.js +0 -71
  96. package/dist/lib/generateEmbedding.js +0 -22
@@ -1,186 +0,0 @@
1
- import { indexCodeForFile } from '../db/functionIndex.js';
2
- import fs from 'fs/promises';
3
- import fsSync from 'fs';
4
- import { generateEmbedding } from '../lib/generateEmbedding.js';
5
- import { log } from '../utils/log.js';
6
- import lockfile from 'proper-lockfile';
7
- import { summaryModule } from '../pipeline/modules/summaryModule.js';
8
- import { classifyFile } from '../fileRules/classifyFile.js';
9
- import { getDbForRepo, getDbPathForRepo } from '../db/client.js';
10
- import { markFileAsSkippedByPath, selectUnprocessedFiles, updateFileWithSummaryAndEmbedding, insertGraphTagTemplate, selectGraphTagIdTemplate, insertGraphEntityTagTemplate, } from '../db/sqlTemplates.js';
11
- import { kgModule } from '../pipeline/modules/kgModule.js';
12
- const MAX_FILES_PER_BATCH = 5;
13
- /**
14
- * Acquire a lock on the DB so only one daemon batch modifies it at a time
15
- */
16
- async function lockDb() {
17
- try {
18
- return await lockfile.lock(getDbPathForRepo());
19
- }
20
- catch (err) {
21
- log('❌ Failed to acquire DB lock: ' + err);
22
- throw err;
23
- }
24
- }
25
- /**
26
- * Run a daemon batch to process up to MAX_FILES_PER_BATCH files.
27
- * - Generates summaries & embeddings
28
- * - Extracts functions
29
- * - Builds Knowledge Graph (persisting entities, tags, and edges)
30
- */
31
- export async function runDaemonBatch() {
32
- log('🟡 Starting daemon batch...');
33
- const db = getDbForRepo();
34
- const rows = db.prepare(selectUnprocessedFiles).all(MAX_FILES_PER_BATCH);
35
- if (rows.length === 0) {
36
- log('✅ No files left to process.');
37
- return false;
38
- }
39
- const release = await lockDb();
40
- for (const row of rows) {
41
- log(`📂 Processing file: ${row.path}`);
42
- if (!fsSync.existsSync(row.path)) {
43
- log(`⚠️ Skipped missing file: ${row.path}`);
44
- db.prepare(markFileAsSkippedByPath).run({ path: row.path });
45
- continue;
46
- }
47
- const classification = classifyFile(row.path);
48
- if (classification !== 'valid') {
49
- log(`⏭️ Skipping (${classification}): ${row.path}`);
50
- db.prepare(markFileAsSkippedByPath).run({ path: row.path });
51
- continue;
52
- }
53
- try {
54
- const content = await fs.readFile(row.path, 'utf-8');
55
- const needsResummary = !row.summary ||
56
- !row.indexed_at ||
57
- (row.last_modified && new Date(row.last_modified) > new Date(row.indexed_at));
58
- if (needsResummary) {
59
- log(`📝 Generating summary for ${row.path}...`);
60
- const summaryResult = await summaryModule.run({ content, filepath: row.path });
61
- const summary = summaryResult?.summary?.trim() || null;
62
- let embedding = null;
63
- if (summary) {
64
- const vector = await generateEmbedding(summary);
65
- if (vector) {
66
- embedding = JSON.stringify(vector);
67
- }
68
- }
69
- db.prepare(updateFileWithSummaryAndEmbedding).run({
70
- summary,
71
- embedding,
72
- path: row.path,
73
- });
74
- log(`✅ Updated summary & embedding for ${row.path}`);
75
- }
76
- else {
77
- log(`⚡ Skipped summary (up-to-date) for ${row.path}`);
78
- }
79
- const success = await indexCodeForFile(row.path, row.id);
80
- if (success) {
81
- log(`✅ Indexed code for ${row.path}`);
82
- try {
83
- log(`🔗 Building Knowledge Graph for ${row.path}...`);
84
- const kgInput = {
85
- fileId: row.id,
86
- filepath: row.path,
87
- summary: row.summary || undefined,
88
- };
89
- const kgResult = await kgModule.run(kgInput, content);
90
- log(`✅ Knowledge Graph built for ${row.path}`);
91
- log(`Entities: ${kgResult.entities.length}, Edges: ${kgResult.edges.length}`);
92
- // Persist KG entities + tags
93
- if (kgResult.entities.length > 0) {
94
- const insertTag = db.prepare(insertGraphTagTemplate);
95
- const getTagId = db.prepare(selectGraphTagIdTemplate);
96
- const insertEntityTag = db.prepare(insertGraphEntityTagTemplate);
97
- for (const entity of kgResult.entities) {
98
- if (!entity.type || !Array.isArray(entity.tags) || entity.tags.length === 0) {
99
- console.warn(`⚠ Skipping entity due to missing type or tags:`, entity);
100
- continue;
101
- }
102
- for (const tag of entity.tags) {
103
- if (!tag || typeof tag !== 'string') {
104
- console.warn(`⚠ Skipping invalid tag for entity ${entity.type}:`, tag);
105
- continue;
106
- }
107
- try {
108
- insertTag.run({ name: tag });
109
- const tagRow = getTagId.get({ name: tag });
110
- if (!tagRow) {
111
- console.warn(`⚠ Could not find tag ID for: ${tag}`);
112
- continue;
113
- }
114
- insertEntityTag.run({
115
- entity_type: entity.type,
116
- entity_unique_id: `${entity.name}@${row.path}`,
117
- tag_id: tagRow.id,
118
- });
119
- }
120
- catch (err) {
121
- console.error(`❌ Failed to persist entity/tag:`, { entity, tag, error: err });
122
- }
123
- }
124
- }
125
- log(`✅ Persisted entities + tags for ${row.path}`);
126
- }
127
- else {
128
- log(`⚠️ No entities found for ${row.path}, skipping DB inserts`);
129
- }
130
- // Persist KG entities + tags (from LLM)
131
- if (kgResult.entities.length > 0) {
132
- const insertTag = db.prepare(insertGraphTagTemplate);
133
- const getTagId = db.prepare(selectGraphTagIdTemplate);
134
- const insertEntityTag = db.prepare(insertGraphEntityTagTemplate);
135
- for (const entity of kgResult.entities) {
136
- if (!entity.type || !Array.isArray(entity.tags) || entity.tags.length === 0) {
137
- console.warn(`⚠ Skipping entity due to missing type or tags:`, entity);
138
- continue;
139
- }
140
- for (const tag of entity.tags) {
141
- if (!tag || typeof tag !== 'string') {
142
- console.warn(`⚠ Skipping invalid tag for entity ${entity.type}:`, tag);
143
- continue;
144
- }
145
- try {
146
- insertTag.run({ name: tag });
147
- const tagRow = getTagId.get({ name: tag });
148
- if (!tagRow) {
149
- console.warn(`⚠ Could not find tag ID for: ${tag}`);
150
- continue;
151
- }
152
- insertEntityTag.run({
153
- entity_type: entity.type,
154
- entity_unique_id: `${entity.name}@${row.path}`,
155
- tag_id: tagRow.id,
156
- });
157
- }
158
- catch (err) {
159
- console.error(`❌ Failed to persist entity/tag:`, { entity, tag, error: err });
160
- }
161
- }
162
- }
163
- log(`✅ Persisted entities + tags for ${row.path}`);
164
- }
165
- else {
166
- log(`⚠️ No entities found for ${row.path}, skipping DB inserts`);
167
- }
168
- }
169
- catch (kgErr) {
170
- log(`❌ KG build failed for ${row.path}: ${kgErr instanceof Error ? kgErr.message : String(kgErr)}`);
171
- }
172
- }
173
- else {
174
- log(`ℹ️ No code elements extracted for ${row.path}`);
175
- }
176
- }
177
- catch (err) {
178
- log(`❌ Failed: ${row.path}: ${err instanceof Error ? err.message : String(err)}\n`);
179
- }
180
- // Short delay between files
181
- await new Promise((resolve) => setTimeout(resolve, 200));
182
- }
183
- await release();
184
- log('✅ Finished daemon batch.\n\n');
185
- return true;
186
- }
@@ -1,71 +0,0 @@
1
- import { stringSimilarity } from 'string-similarity-js';
2
- export function scoreFiles(query, embedding, candidates) {
3
- const terms = query.toLowerCase().split(/\s+/);
4
- const bm25Min = Math.min(...candidates.map(r => r.bm25Score));
5
- const bm25Max = Math.max(...candidates.map(r => r.bm25Score));
6
- return candidates.map(result => {
7
- let finalScore = 0;
8
- let sim = 0;
9
- const path = result.path.toLowerCase();
10
- const filename = result.filename.toLowerCase();
11
- const summary = (result.summary || '').toLowerCase();
12
- // 🎯 Normalize BM25
13
- const normalizedBm25 = 1 - ((result.bm25Score - bm25Min) / (bm25Max - bm25Min + 1e-5));
14
- // 🧠 Embedding similarity
15
- if (result.embedding) {
16
- try {
17
- const vector = JSON.parse(result.embedding);
18
- sim = cosineSimilarity(embedding, vector);
19
- }
20
- catch {
21
- sim = 0;
22
- }
23
- }
24
- // 🧩 Match ratio
25
- let matchRatio = 0;
26
- let matchedTerms = 0;
27
- for (const term of terms) {
28
- if (path.includes(term) || summary.includes(term))
29
- matchedTerms++;
30
- }
31
- matchRatio = matchedTerms / terms.length;
32
- const termBoost = matchRatio >= 1 ? 1.0 : matchRatio >= 0.5 ? 0.5 : 0;
33
- // 🪜 Path heuristics
34
- const isHtml = path.endsWith('.html');
35
- const isSrc = path.includes('/src/') || path.includes('/controls/');
36
- const isDoc = path.includes('/docs/') || path.includes('/mvndist/');
37
- const isExactMatch = filename === `${terms[0]}.js`;
38
- let weight = 1;
39
- if (isHtml)
40
- weight *= 0.85;
41
- if (isDoc)
42
- weight *= 0.8;
43
- if (isSrc)
44
- weight *= 1.2;
45
- if (isExactMatch)
46
- weight *= 1.5;
47
- // 🧪 Fuzzy score
48
- const fuzzyScore = stringSimilarity(query, `${path} ${summary}`);
49
- // 🧮 Final composite score
50
- finalScore =
51
- (0.4 * normalizedBm25) +
52
- (0.4 * sim) +
53
- (0.2 * termBoost) +
54
- (fuzzyScore * 0.5); // scale fuzzy match moderately
55
- finalScore *= weight;
56
- return {
57
- id: result.id,
58
- path: result.path,
59
- summary: result.summary,
60
- score: finalScore,
61
- sim,
62
- bm25: result.bm25Score,
63
- };
64
- }).sort((a, b) => b.score - a.score);
65
- }
66
- function cosineSimilarity(a, b) {
67
- const dot = a.reduce((sum, ai, i) => sum + ai * b[i], 0);
68
- const magA = Math.sqrt(a.reduce((sum, ai) => sum + ai * ai, 0));
69
- const magB = Math.sqrt(b.reduce((sum, bi) => sum + bi * bi, 0));
70
- return dot / (magA * magB);
71
- }
@@ -1,22 +0,0 @@
1
- export async function generateEmbedding(text) {
2
- try {
3
- const res = await fetch('http://localhost:11434/api/embeddings', {
4
- method: 'POST',
5
- headers: { 'Content-Type': 'application/json' },
6
- body: JSON.stringify({
7
- model: 'mistral', // or 'llama3' — whatever works best
8
- prompt: text,
9
- }),
10
- });
11
- if (!res.ok) {
12
- console.error('❌ Failed to generate embedding:', await res.text());
13
- return null;
14
- }
15
- const data = await res.json();
16
- return data.embedding;
17
- }
18
- catch (err) {
19
- console.error('❌ Embedding error:', err instanceof Error ? err.message : err);
20
- return null;
21
- }
22
- }