@lisa.ai/agent 1.1.4 → 1.1.6
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 +14 -0
- package/dist/utils/parser.js +15 -9
- package/package.json +1 -1
package/dist/commands/heal.js
CHANGED
|
@@ -85,6 +85,20 @@ async function healCommand(command, modelProvider, attempt = 1, healedFilePath =
|
|
|
85
85
|
if (totalFails >= 3) {
|
|
86
86
|
console.warn(`\n[Lisa.ai Auto-Heal] ⚠️ Warning: Agent failed to heal ${filePath} after 3 overall attempts in this session. Marking as Skipped to avoid infinite Loop.`);
|
|
87
87
|
skipLedger.push(filePath);
|
|
88
|
+
// [Lisa.ai Advanced Path Neutralization]
|
|
89
|
+
// If the LLM failed to heal a spec file 3 times, we MUST mathematically eliminate it from the glob path
|
|
90
|
+
// otherwise Karma will STILL execute the broken spec, exit with Code 1, and eventually trap the Agent
|
|
91
|
+
// when the parser exhausts all files. We rename it to .broken to physically bypass the test runner.
|
|
92
|
+
if (filePath.endsWith('.spec.ts')) {
|
|
93
|
+
const brokenPath = absolutePath + '.broken';
|
|
94
|
+
try {
|
|
95
|
+
fs.renameSync(absolutePath, brokenPath);
|
|
96
|
+
console.log(`[Lisa.ai Auto-Heal] 🚨 Renamed unhealable spec to ${filePath}.broken to force the test runner to skip it!`);
|
|
97
|
+
}
|
|
98
|
+
catch (renameErr) {
|
|
99
|
+
console.error(`[Lisa.ai Warning] Could not rename ${filePath}: ${renameErr.message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
88
102
|
// Immediately retry the loop but force the parser to skip this broken file
|
|
89
103
|
await healCommand(command, modelProvider, attempt + 1, healedFilePath, maxRetries, projectId, lastFixDetails, apiKey, skipLedger, 0, failTracker);
|
|
90
104
|
return;
|
package/dist/utils/parser.js
CHANGED
|
@@ -72,8 +72,8 @@ function extractFilePath(errorLog, skipFiles = [], searchDir = process.cwd()) {
|
|
|
72
72
|
const className = classMatch[1];
|
|
73
73
|
if (className) {
|
|
74
74
|
console.log(`[Lisa.ai Parser] Discovered abstract class failure: ${className}. Scanning 'src/' tree...`);
|
|
75
|
-
const matchedFile = findFileByClassName(className, path.join(searchDir, 'src'));
|
|
76
|
-
if (matchedFile
|
|
75
|
+
const matchedFile = findFileByClassName(className, path.join(searchDir, 'src'), normalizedSkips);
|
|
76
|
+
if (matchedFile) {
|
|
77
77
|
// Return path relative to project root
|
|
78
78
|
return path.relative(searchDir, matchedFile);
|
|
79
79
|
}
|
|
@@ -85,8 +85,9 @@ function extractFilePath(errorLog, skipFiles = [], searchDir = process.cwd()) {
|
|
|
85
85
|
/**
|
|
86
86
|
* Recursively walks a directory looking for a `.ts` file that exports the target class.
|
|
87
87
|
* Designed to bypass Karma's frustrating habit of omitting absolute script paths in Spec exceptions.
|
|
88
|
+
* We pass normalizedSkips to ensure we do not return a file that the Agent has explicitly blacklisted this session.
|
|
88
89
|
*/
|
|
89
|
-
function findFileByClassName(className, dir) {
|
|
90
|
+
function findFileByClassName(className, dir, skipLedgerAbs) {
|
|
90
91
|
if (!fs.existsSync(dir))
|
|
91
92
|
return null;
|
|
92
93
|
const files = fs.readdirSync(dir);
|
|
@@ -96,25 +97,30 @@ function findFileByClassName(className, dir) {
|
|
|
96
97
|
if (stat.isDirectory()) {
|
|
97
98
|
// Recurse into subdirectories (ignore node_modules just in case)
|
|
98
99
|
if (file !== 'node_modules') {
|
|
99
|
-
const found = findFileByClassName(className, fullPath);
|
|
100
|
+
const found = findFileByClassName(className, fullPath, skipLedgerAbs);
|
|
100
101
|
if (found)
|
|
101
102
|
return found;
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
else if (file.endsWith('.ts')) {
|
|
105
|
-
//
|
|
106
|
+
// We ONLY care if the file natively exports the class declaration.
|
|
107
|
+
// We MUST NOT match files that merely `import` the class.
|
|
106
108
|
const content = fs.readFileSync(fullPath, 'utf8');
|
|
107
|
-
|
|
108
|
-
if (content.includes(`class ${className}`) || content.includes(className)) {
|
|
109
|
+
if (content.includes(`class ${className}`)) {
|
|
109
110
|
// For tests, if a spec fails, we want to heal the spec file first!
|
|
110
111
|
// If the class is found in a non-spec file, and a spec file exists next to it, favor the spec.
|
|
112
|
+
let targetPath = fullPath;
|
|
111
113
|
if (!file.endsWith('.spec.ts')) {
|
|
112
114
|
const hypotheticalSpec = fullPath.replace('.ts', '.spec.ts');
|
|
113
115
|
if (fs.existsSync(hypotheticalSpec)) {
|
|
114
|
-
|
|
116
|
+
targetPath = hypotheticalSpec;
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
|
-
return
|
|
119
|
+
// If the decided file is NOT in the skip ledger, return it.
|
|
120
|
+
// Otherwise, safely ignore it and keep looping for other matches in the directory tree.
|
|
121
|
+
if (!skipLedgerAbs.includes(path.resolve(targetPath))) {
|
|
122
|
+
return targetPath;
|
|
123
|
+
}
|
|
118
124
|
}
|
|
119
125
|
}
|
|
120
126
|
}
|