@lisa.ai/agent 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/heal.js +15 -6
- package/dist/utils/parser.js +23 -12
- package/package.json +1 -1
package/dist/commands/heal.js
CHANGED
|
@@ -41,7 +41,7 @@ const parser_1 = require("../utils/parser");
|
|
|
41
41
|
const llm_service_1 = require("../services/llm.service");
|
|
42
42
|
const git_service_1 = require("../services/git.service");
|
|
43
43
|
const telemetry_service_1 = require("../services/telemetry.service");
|
|
44
|
-
async function healCommand(command, modelProvider, attempt = 1, healedFilePath = null, maxRetries = 3, projectId = 'local', lastFixDetails, apiKey) {
|
|
44
|
+
async function healCommand(command, modelProvider, attempt = 1, healedFilePath = null, maxRetries = 3, projectId = 'local', lastFixDetails, apiKey, skipLedger = [], consecutiveFails = 0) {
|
|
45
45
|
console.log(`\n[Lisa.ai Executing] ${command} (Attempt ${attempt}/${maxRetries}) Using Model: ${modelProvider}`);
|
|
46
46
|
try {
|
|
47
47
|
// Execute command synchronously
|
|
@@ -66,9 +66,9 @@ async function healCommand(command, modelProvider, attempt = 1, healedFilePath =
|
|
|
66
66
|
process.exit(1);
|
|
67
67
|
}
|
|
68
68
|
console.log(`\n[Lisa.ai Auto-Heal] Analyzing errors...`);
|
|
69
|
-
const filePath = (0, parser_1.extractFilePath)(errorLog);
|
|
69
|
+
const filePath = (0, parser_1.extractFilePath)(errorLog, skipLedger);
|
|
70
70
|
if (!filePath) {
|
|
71
|
-
console.error(`\n🚨 [Lisa.ai Error] Could not parse a valid failing file path from the logs.`);
|
|
71
|
+
console.error(`\n🚨 [Lisa.ai Error] Could not parse a valid failing file path from the logs (or all were explicitly skipped).`);
|
|
72
72
|
process.exit(1);
|
|
73
73
|
}
|
|
74
74
|
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
@@ -79,8 +79,17 @@ async function healCommand(command, modelProvider, attempt = 1, healedFilePath =
|
|
|
79
79
|
console.log(`[Lisa.ai Auto-Heal] Identified failing file: ${filePath}`);
|
|
80
80
|
// Read file contents to send to LLM
|
|
81
81
|
const fileContent = fs.readFileSync(absolutePath, 'utf-8');
|
|
82
|
+
// Increment consecutive fail tracker if this is the exact same file as last time
|
|
83
|
+
let currentFails = (filePath === healedFilePath) ? consecutiveFails + 1 : 1;
|
|
84
|
+
if (currentFails >= 3) {
|
|
85
|
+
console.warn(`\n[Lisa.ai Auto-Heal] ⚠️ Warning: Agent failed to heal ${filePath} after 3 consecutive attempts. It may be missing dependencies. Marking as Skipped.`);
|
|
86
|
+
skipLedger.push(filePath);
|
|
87
|
+
// Immediately retry the loop but force the parser to skip this broken file
|
|
88
|
+
await healCommand(command, modelProvider, attempt + 1, healedFilePath, maxRetries, projectId, lastFixDetails, apiKey, skipLedger, 0);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
82
91
|
// Pass previous attempted fix if we are stuck in a loop on the same file
|
|
83
|
-
const previousContext = (
|
|
92
|
+
const previousContext = (currentFails > 1) ? lastFixDetails : undefined;
|
|
84
93
|
// Call LLM for a fix
|
|
85
94
|
const fixedCode = await (0, llm_service_1.askLisaForFix)(filePath, fileContent, errorLog, modelProvider, apiKey, previousContext);
|
|
86
95
|
// Write the fix to the file
|
|
@@ -96,7 +105,7 @@ async function healCommand(command, modelProvider, attempt = 1, healedFilePath =
|
|
|
96
105
|
status: 'success',
|
|
97
106
|
details: generatedDetails
|
|
98
107
|
});
|
|
99
|
-
// Recursive retry, passing the healed file path state
|
|
100
|
-
await healCommand(command, modelProvider, attempt + 1, filePath, maxRetries, projectId, generatedDetails, apiKey);
|
|
108
|
+
// Recursive retry, passing the healed file path state and updated limits
|
|
109
|
+
await healCommand(command, modelProvider, attempt + 1, filePath, maxRetries, projectId, generatedDetails, apiKey, skipLedger, currentFails);
|
|
101
110
|
}
|
|
102
111
|
}
|
package/dist/utils/parser.js
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractFilePath = extractFilePath;
|
|
4
|
-
function extractFilePath(errorLog) {
|
|
4
|
+
function extractFilePath(errorLog, skipFiles = []) {
|
|
5
5
|
// Sanitize invisible ANSI color codes (e.g. \x1b[96m) from CLI output logs
|
|
6
6
|
const cleanLog = errorLog.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
7
|
-
//
|
|
7
|
+
// 1. First Pass: Try to match typical TS/Angular error patterns
|
|
8
8
|
// e.g., "src/app/app.component.ts:12:3 - error TS2322:"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return
|
|
9
|
+
const tsErrorRegex = /([a-zA-Z0-9_.\-\/\\]+\.ts)(?:[:(])/g;
|
|
10
|
+
let match;
|
|
11
|
+
// Loop through all matches in the error log
|
|
12
|
+
while ((match = tsErrorRegex.exec(cleanLog)) !== null) {
|
|
13
|
+
const foundPath = match[1];
|
|
14
|
+
// If this path is NOT in our skip ledger, we return it as the target
|
|
15
|
+
if (foundPath && !skipFiles.includes(foundPath)) {
|
|
16
|
+
return foundPath;
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
19
|
+
// 2. Second Pass (Fallback): Find anything that looks like a .ts file
|
|
20
|
+
// Note: We use the 'g' flag so we can iterate through multiple matches if the first is skipped
|
|
21
|
+
const fallbackRegex = /([a-zA-Z0-9_.\-\/\\]+\.ts)/g;
|
|
22
|
+
let fallbackMatch;
|
|
23
|
+
while ((fallbackMatch = fallbackRegex.exec(cleanLog)) !== null) {
|
|
24
|
+
const foundPath = fallbackMatch[1];
|
|
25
|
+
if (foundPath && !skipFiles.includes(foundPath)) {
|
|
26
|
+
return foundPath;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Exhausted all options and couldn't find an un-skipped file
|
|
30
|
+
return null;
|
|
20
31
|
}
|