@lisa.ai/agent 1.1.3 → 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/coverage.js +1 -1
- package/dist/commands/heal.js +15 -1
- package/dist/utils/parser.js +62 -1
- package/package.json +1 -1
|
@@ -95,7 +95,7 @@ async function coverageCommand(command, modelProvider, attempt = 1, maxRetries =
|
|
|
95
95
|
await (0, telemetry_service_1.reportTelemetry)({
|
|
96
96
|
projectId,
|
|
97
97
|
type: 'coverage',
|
|
98
|
-
filePath: targetFilePath,
|
|
98
|
+
filePath: targetFilePath, // Keeping original as the provided edit was syntactically incorrect for an object literal
|
|
99
99
|
modelUsed: modelProvider,
|
|
100
100
|
status: 'success',
|
|
101
101
|
details: `### Missing Logic Coverage Detected\n**Auto-Generated Specification Suite (${modelProvider}):**\n\`\`\`typescript\n${testCode}\n\`\`\``
|
package/dist/commands/heal.js
CHANGED
|
@@ -66,7 +66,7 @@ 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, skipLedger);
|
|
69
|
+
const filePath = (0, parser_1.extractFilePath)(errorLog, skipLedger, process.cwd());
|
|
70
70
|
if (!filePath) {
|
|
71
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);
|
|
@@ -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
|
@@ -35,7 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.extractFilePath = extractFilePath;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
-
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
function extractFilePath(errorLog, skipFiles = [], searchDir = process.cwd()) {
|
|
39
40
|
// Sanitize invisible ANSI color codes (e.g. \x1b[96m) from CLI output logs
|
|
40
41
|
const cleanLog = errorLog.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
41
42
|
// Normalize skip files for reliable absolute path comparison
|
|
@@ -62,6 +63,66 @@ function extractFilePath(errorLog, skipFiles = []) {
|
|
|
62
63
|
return foundPath;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
// 3. Third Pass (Karma/Jasmine Abstract Fallback): Match Angular Class names
|
|
67
|
+
// Example: "Chrome 145.0.0.0 (Windows 10) ConfigureNotificationComponent should create FAILED"
|
|
68
|
+
// Example: "NullInjectorError: R3InjectorError(Standalone[RegisterComponent])"
|
|
69
|
+
const classRegex = /([A-Z][a-zA-Z0-9]+(?:Component|Service|Module|Directive|Pipe|Guard|Interceptor))/g;
|
|
70
|
+
let classMatch;
|
|
71
|
+
while ((classMatch = classRegex.exec(cleanLog)) !== null) {
|
|
72
|
+
const className = classMatch[1];
|
|
73
|
+
if (className) {
|
|
74
|
+
console.log(`[Lisa.ai Parser] Discovered abstract class failure: ${className}. Scanning 'src/' tree...`);
|
|
75
|
+
const matchedFile = findFileByClassName(className, path.join(searchDir, 'src'), normalizedSkips);
|
|
76
|
+
if (matchedFile) {
|
|
77
|
+
// Return path relative to project root
|
|
78
|
+
return path.relative(searchDir, matchedFile);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
65
82
|
// Exhausted all options and couldn't find an un-skipped file
|
|
66
83
|
return null;
|
|
67
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Recursively walks a directory looking for a `.ts` file that exports the target class.
|
|
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.
|
|
89
|
+
*/
|
|
90
|
+
function findFileByClassName(className, dir, skipLedgerAbs) {
|
|
91
|
+
if (!fs.existsSync(dir))
|
|
92
|
+
return null;
|
|
93
|
+
const files = fs.readdirSync(dir);
|
|
94
|
+
for (const file of files) {
|
|
95
|
+
const fullPath = path.join(dir, file);
|
|
96
|
+
const stat = fs.statSync(fullPath);
|
|
97
|
+
if (stat.isDirectory()) {
|
|
98
|
+
// Recurse into subdirectories (ignore node_modules just in case)
|
|
99
|
+
if (file !== 'node_modules') {
|
|
100
|
+
const found = findFileByClassName(className, fullPath, skipLedgerAbs);
|
|
101
|
+
if (found)
|
|
102
|
+
return found;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (file.endsWith('.ts')) {
|
|
106
|
+
// We ONLY care if the file natively exports the class declaration.
|
|
107
|
+
// We MUST NOT match files that merely `import` the class.
|
|
108
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
109
|
+
if (content.includes(`class ${className}`)) {
|
|
110
|
+
// For tests, if a spec fails, we want to heal the spec file first!
|
|
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;
|
|
113
|
+
if (!file.endsWith('.spec.ts')) {
|
|
114
|
+
const hypotheticalSpec = fullPath.replace('.ts', '.spec.ts');
|
|
115
|
+
if (fs.existsSync(hypotheticalSpec)) {
|
|
116
|
+
targetPath = hypotheticalSpec;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
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
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|