@lisa.ai/agent 2.2.1 → 2.3.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.
@@ -1,277 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.healCommand = healCommand;
37
- const child_process_1 = require("child_process");
38
- const fs = __importStar(require("fs"));
39
- const path = __importStar(require("path"));
40
- const parser_1 = require("../utils/parser");
41
- const llm_service_1 = require("../services/llm.service");
42
- const git_service_1 = require("../services/git.service");
43
- const telemetry_service_1 = require("../services/telemetry.service");
44
- const discovery_service_1 = require("../services/discovery.service");
45
- const installer_service_1 = require("../services/installer.service");
46
- const generator_service_1 = require("../services/generator.service");
47
- // Bug 6 fix: threshold for the failTracker — how many times a file is allowed to exhaust
48
- // all local retries across the entire global run before being permanently abandoned.
49
- // This is the "3-strike skip" described in the context architecture doc.
50
- const GLOBAL_FAIL_THRESHOLD = 3;
51
- function fetchSiblingContext(specPath) {
52
- // Drop the .spec or .test extensions to find the actual Component / Service logic
53
- const baseSiblingPath = specPath.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/, '.$2');
54
- if (baseSiblingPath !== specPath && fs.existsSync(baseSiblingPath)) {
55
- try {
56
- console.log(`[Lisa.ai Context Engine] 🧠 Located sibling logic structure at ${baseSiblingPath}`);
57
- return fs.readFileSync(baseSiblingPath, 'utf-8');
58
- }
59
- catch (e) {
60
- return undefined;
61
- }
62
- }
63
- return undefined;
64
- }
65
- function isolateTestCommand(globalCommand, targetFile) {
66
- const cmd = globalCommand.toLowerCase();
67
- const parsed = path.parse(targetFile);
68
- // 1. Explicit Frameworks
69
- if (cmd.includes('ng test') || cmd.includes('karma')) {
70
- return `${globalCommand} --include **/${parsed.base}`;
71
- }
72
- if (cmd.includes('jest') || cmd.includes('vitest') || cmd.includes('playwright')) {
73
- return `${globalCommand} ${targetFile}`;
74
- }
75
- if (cmd.includes('cypress')) {
76
- return `${globalCommand} --spec ${targetFile}`;
77
- }
78
- // 2. Generic Package Manager Scripts (npm run test, yarn test)
79
- if (cmd.includes('npm') || cmd.includes('yarn') || cmd.includes('pnpm')) {
80
- try {
81
- const packageJsonPath = path.resolve(process.cwd(), 'package.json');
82
- if (fs.existsSync(packageJsonPath)) {
83
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
84
- let scriptName = 'test';
85
- if (cmd.includes('npm run ')) {
86
- scriptName = cmd.split('npm run ')[1].split(' ')[0];
87
- }
88
- else if (cmd.includes('yarn ')) {
89
- scriptName = cmd.split('yarn ')[1].split(' ')[0];
90
- }
91
- else if (cmd.includes('pnpm ')) {
92
- scriptName = cmd.split('pnpm ')[1].split(' ')[0];
93
- }
94
- const testScript = pkg.scripts?.[scriptName]?.toLowerCase() || '';
95
- const dashDash = cmd.includes('npm') ? ' --' : '';
96
- // Deducing underlying framework from package manager translation
97
- if (testScript.includes('ng test') || testScript.includes('karma')) {
98
- return `${globalCommand}${dashDash} --include **/${parsed.base}`;
99
- }
100
- if (testScript.includes('jest') || testScript.includes('vitest') || testScript.includes('playwright')) {
101
- return `${globalCommand}${dashDash} ${targetFile}`;
102
- }
103
- }
104
- }
105
- catch (e) {
106
- // Silently fallback if package.json is inaccessible
107
- }
108
- // 3. Ultimate Fallback: Assume it behaves like standard generic node environments
109
- const dashDash = cmd.includes('npm') ? ' --' : '';
110
- return `${globalCommand}${dashDash} ${targetFile}`;
111
- }
112
- return globalCommand;
113
- }
114
- async function healCommand(command, modelProvider, attempt = 1, healedFilePath = null, maxRetries = 3, projectId = 'local', lastFixDetails, apiKey, skipLedger = [], consecutiveFails = 0, failTracker = {}) {
115
- // [Lisa.ai V2 Zero-Config Engine]
116
- if (!command) {
117
- console.log(`\n[Lisa.ai Auto-Discovery] No explicit --command provided. Initiating Autonomous Framework Fingerprinting...`);
118
- let fingerprint = discovery_service_1.AutoDiscoveryService.scanRepository();
119
- if (fingerprint.testingFramework === 'none') {
120
- fingerprint = await installer_service_1.AutoInstallerService.installMissingFramework(fingerprint);
121
- await generator_service_1.AutoGeneratorService.provisionConfigurationFiles(fingerprint, modelProvider, apiKey);
122
- }
123
- if (fingerprint.suggestedTestCommand) {
124
- command = fingerprint.suggestedTestCommand;
125
- console.log(`[Lisa.ai Auto-Discovery] Bootstrapping execution with natively discovered command: ${command}`);
126
- }
127
- else {
128
- console.error(`\n🚨 [Lisa.ai Fatal Error] Agent could not dynamically extrapolate a testing command for a Generic Node Environment. Please pass --command explicitly.`);
129
- process.exit(1);
130
- }
131
- }
132
- console.log(`\n[Lisa.ai Executing] ${command} (Global Engine) Using Model: ${modelProvider}`);
133
- const runSilentlyAndIntercept = (cmd, printProgress = false) => {
134
- return new Promise((resolve, reject) => {
135
- // Node 21+ Deprecation Fix: When shell is true, pass the entire raw command string
136
- // rather than explicitly escaping array arguments to bypass DEP0190.
137
- const child = (0, child_process_1.spawn)(cmd, { shell: true, stdio: ['ignore', 'pipe', 'pipe'] });
138
- let stdoutData = '';
139
- let stderrData = '';
140
- child.stdout?.on('data', (data) => {
141
- const text = data.toString();
142
- stdoutData += text;
143
- // [Lisa.ai Stream Interceptor]
144
- // The user explicitly requested to see a single clean loading line instead of
145
- // thousands of milliseconds of Redundant 'Executed' loops.
146
- // Output is fully swallowed, and instead we log a spinner on boot.
147
- });
148
- child.stderr?.on('data', (data) => {
149
- stderrData += data.toString();
150
- });
151
- child.on('close', (code) => {
152
- if (code === 0) {
153
- resolve({ stdout: stdoutData, stderr: stderrData });
154
- }
155
- else {
156
- reject({ message: `Process exited with code ${code}`, stdout: stdoutData, stderr: stderrData });
157
- }
158
- });
159
- });
160
- };
161
- try {
162
- console.log(`ā³ [Lisa.ai Testing] Booting Headless Test Suite in background...`);
163
- await runSilentlyAndIntercept(command, false); // False = output is suppressed natively
164
- console.log(`\nāœ… [Lisa.ai Success] Global Command executed successfully.`);
165
- if (healedFilePath) {
166
- await (0, git_service_1.createPullRequestForHeal)(healedFilePath);
167
- }
168
- return; // Successfully finished without throwing
169
- }
170
- catch (error) {
171
- console.log(`\nāŒ [Lisa.ai Failure] Global Command failed.`);
172
- const errorLog = (error.stderr || '') + '\n' + (error.stdout || '') + '\n' + (error.message || '');
173
- // console.error(errorLog); // Suppressed to keep "Pure Magic" CLI clean. Error is parsed abstractly.
174
- console.log(`\n[Lisa.ai Auto-Heal] Analyzing errors...`);
175
- const filePath = (0, parser_1.extractFilePath)(errorLog, skipLedger, process.cwd());
176
- if (!filePath) {
177
- console.error(`\n🚨 [Lisa.ai Error] Could not parse a valid failing file path from the logs (or all were explicitly skipped).`);
178
- process.exit(1);
179
- }
180
- const absolutePath = path.resolve(process.cwd(), filePath);
181
- if (!fs.existsSync(absolutePath)) {
182
- console.error(`\n🚨 [Lisa.ai Error] Extracted file path does not exist: ${absolutePath}`);
183
- process.exit(1);
184
- }
185
- // Bug 6 fix: implement the "3-strike global skip" described in the architecture doc.
186
- // If this file has already exhausted all local retries GLOBAL_FAIL_THRESHOLD times
187
- // across the entire run, it is a persistently broken file. Skip it immediately
188
- // instead of wasting more LLM calls on it.
189
- const globalFailCount = failTracker[filePath] || 0;
190
- if (globalFailCount >= GLOBAL_FAIL_THRESHOLD) {
191
- console.warn(`\n[Lisa.ai Auto-Heal] āš ļø ${filePath} has failed globally ${globalFailCount} time(s) — exceeds threshold of ${GLOBAL_FAIL_THRESHOLD}. Permanently skipping.`);
192
- skipLedger.push(filePath);
193
- await healCommand(command, modelProvider, 1, null, maxRetries, projectId, undefined, apiKey, skipLedger, 0, failTracker);
194
- return;
195
- }
196
- console.log(`[Lisa.ai Auto-Heal] Identified bleeding file: ${filePath} (global fail count: ${globalFailCount}/${GLOBAL_FAIL_THRESHOLD})`);
197
- // [Lisa.ai V2 Micro-Targeted Healing Loop]
198
- // Instead of restarting the global CI engine (e.g. `npm run test`) and waiting for all 400 specs
199
- // to run just to fetch the error for this one file, we trap it locally with its native CLI frame isolation arguments!
200
- let localAttempt = 1;
201
- let isFixed = false;
202
- let currentErrorLog = errorLog;
203
- let previousContext = undefined;
204
- let generatedDetails = '';
205
- const isolatedCommand = isolateTestCommand(command, filePath);
206
- const siblingContext = fetchSiblingContext(absolutePath);
207
- await (0, telemetry_service_1.reportTelemetry)({
208
- projectId,
209
- type: 'heal',
210
- filePath: filePath,
211
- modelUsed: modelProvider,
212
- status: 'running',
213
- details: 'Agent is currently analyzing and applying patches...'
214
- });
215
- while (localAttempt <= maxRetries && !isFixed) {
216
- console.log(`\n[Lisa.ai Micro-Heal] Isolating ${filePath} (Attempt ${localAttempt}/${maxRetries})`);
217
- const fileContent = fs.readFileSync(absolutePath, 'utf-8');
218
- const fixedCode = await (0, llm_service_1.askLisaForFix)(filePath, fileContent, currentErrorLog, modelProvider, apiKey, previousContext, siblingContext);
219
- fs.writeFileSync(absolutePath, fixedCode, 'utf-8');
220
- console.log(`[Lisa.ai Micro-Heal] Applied isolated patch to ${filePath}`);
221
- generatedDetails = `### Auto-Heal Analysis Triggered\n**Caught Error:**\n\`\`\`bash\n${currentErrorLog}\n\`\`\`\n\n**Applied Fix (${modelProvider}):**\n\`\`\`typescript\n${fixedCode}\n\`\`\``;
222
- try {
223
- // Verify the isolated file silently without exploding the Global terminal with 400 other spec errors
224
- console.log(`[Lisa.ai Micro-Heal] Verifying fix with isolated command: ${isolatedCommand}`);
225
- await runSilentlyAndIntercept(isolatedCommand, false); // False = completely invisible isolated healing
226
- console.log(`āœ… [Lisa.ai Micro-Heal] Isolated verification passed for ${filePath}!`);
227
- isFixed = true;
228
- }
229
- catch (isolatedError) {
230
- console.log(`āŒ [Lisa.ai Micro-Heal] Isolated verification failed.`);
231
- // CRITICAL FIX: Ensure `stdout` is aggressively extracted because Karma/Jest pump compiler failures into stdout, not stderr.
232
- const fallbackStdout = isolatedError.stdout ? isolatedError.stdout.toString() : '';
233
- const fallbackStderr = isolatedError.stderr ? isolatedError.stderr.toString() : '';
234
- currentErrorLog = fallbackStderr + '\n' + fallbackStdout + '\n' + (isolatedError.message || '');
235
- previousContext = `### Attempt ${localAttempt} Failed\n\`\`\`typescript\n${fixedCode}\n\`\`\`\n\n**New Error:**\n${currentErrorLog}`;
236
- localAttempt++;
237
- }
238
- }
239
- if (isFixed) {
240
- await (0, telemetry_service_1.reportTelemetry)({
241
- projectId,
242
- type: 'heal',
243
- filePath: filePath,
244
- modelUsed: modelProvider,
245
- status: 'success',
246
- details: generatedDetails
247
- });
248
- }
249
- else {
250
- console.warn(`\n[Lisa.ai Auto-Heal] āš ļø Agent failed to locally heal ${filePath} after ${maxRetries} isolated attempts. Marking as Skipped to avoid infinite Loop.`);
251
- await (0, telemetry_service_1.reportTelemetry)({
252
- projectId,
253
- type: 'heal',
254
- filePath: filePath,
255
- modelUsed: modelProvider,
256
- status: 'error',
257
- details: `Agent exhausted all ${maxRetries} attempts without success.\n\n` + generatedDetails
258
- });
259
- // Bug 6 fix: increment the global fail counter for this file so the 3-strike
260
- // check at the top of the next iteration can catch it and skip it early.
261
- failTracker[filePath] = (failTracker[filePath] || 0) + 1;
262
- console.log(`[Lisa.ai Auto-Heal] Global fail counter for ${filePath}: ${failTracker[filePath]}/${GLOBAL_FAIL_THRESHOLD}`);
263
- skipLedger.push(filePath);
264
- // Advanced Path Neutralization for generic JS tests across the V2 Ecosystem Architecture
265
- if (filePath.match(/\.(spec|test)\.(ts|js|tsx|jsx|vue)$/)) {
266
- const brokenPath = absolutePath + '.broken';
267
- try {
268
- fs.renameSync(absolutePath, brokenPath);
269
- console.log(`[Lisa.ai Auto-Heal] 🚨 Renamed unhealable spec to ${filePath}.broken to force the test runner to bypass it!`);
270
- }
271
- catch (e) { }
272
- }
273
- }
274
- // Return to the Global Macro CI Engine to find the next error implicitly or gracefully green-light
275
- await healCommand(command, modelProvider, 1, isFixed ? filePath : null, maxRetries, projectId, undefined, apiKey, skipLedger, 0, failTracker);
276
- }
277
- }
@@ -1,69 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.fetchRemoteConfig = fetchRemoteConfig;
37
- const path = __importStar(require("path"));
38
- const dotenv = __importStar(require("dotenv"));
39
- // CP Bug 3 fix: load .env explicitly so LISA_CONTROL_PLANE_URL is always available
40
- // regardless of module import order. Previously this relied on llm.service.ts being
41
- // imported first (a fragile side-effect dependency).
42
- dotenv.config({ path: path.resolve(__dirname, '../../.env'), quiet: true });
43
- async function fetchRemoteConfig(projectId) {
44
- const MASTER_CONTROL_URL = process.env.LISA_CONTROL_PLANE_URL || 'http://localhost:3000';
45
- try {
46
- const url = `${MASTER_CONTROL_URL}/api/config/${projectId}`;
47
- console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${url}...`);
48
- const response = await fetch(url);
49
- if (!response.ok) {
50
- // 404 means the project was never created on the control plane.
51
- // Other 4xx/5xx errors are treated as unreachable so the agent can fallback.
52
- const reason = response.status === 404 ? 'not_found' : 'unreachable';
53
- if (reason === 'not_found') {
54
- console.warn(`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${projectId}' not found.`);
55
- }
56
- else {
57
- console.warn(`[Lisa.ai Agent Warning] Control Plane returned ${response.status}. Falling back to local defaults.`);
58
- }
59
- return { ok: false, reason };
60
- }
61
- const config = await response.json();
62
- return { ok: true, config };
63
- }
64
- catch (error) {
65
- // Network-level failure — the control plane is unreachable, not "project not found".
66
- console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${MASTER_CONTROL_URL}). Using local fallback configuration.`);
67
- return { ok: false, reason: 'unreachable' };
68
- }
69
- }
@@ -1,152 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.AutoDiscoveryService = void 0;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- class AutoDiscoveryService {
40
- /**
41
- * Statically analyzes the repository's package.json to generate an architectural fingerprint.
42
- */
43
- static scanRepository(projectPath = process.cwd()) {
44
- const pkgPath = path.resolve(projectPath, 'package.json');
45
- const result = {
46
- type: 'unknown',
47
- testingFramework: 'none'
48
- };
49
- if (!fs.existsSync(pkgPath)) {
50
- console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${pkgPath}. Defaulting to Generic Node.`);
51
- result.type = 'node';
52
- return result;
53
- }
54
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
55
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
56
- const scripts = pkg.scripts || {};
57
- // 1. Detect Core Framework
58
- if (deps['@angular/core']) {
59
- result.type = 'angular';
60
- }
61
- else if (deps['react']) {
62
- result.type = 'react';
63
- }
64
- else if (deps['vue']) {
65
- result.type = 'vue';
66
- }
67
- else {
68
- result.type = 'node';
69
- }
70
- // 2. Detect Existing Testing Libraries
71
- if (deps['jest'] || scripts['test']?.includes('jest')) {
72
- result.testingFramework = 'jest';
73
- }
74
- else if (deps['karma'] || scripts['test']?.includes('karma') || scripts['test']?.includes('ng test')) {
75
- result.testingFramework = 'karma';
76
- }
77
- else if (deps['vitest'] || scripts['test']?.includes('vitest')) {
78
- result.testingFramework = 'vitest';
79
- }
80
- // 3. Extrapolate Commands
81
- if (result.testingFramework !== 'none') {
82
- if (scripts['test']) {
83
- result.suggestedTestCommand = 'npm run test';
84
- }
85
- else {
86
- // They have the library but no script; execute the binary directly.
87
- // Include --coverage for jest/vitest so coverage-summary.json is produced.
88
- // Without it the coverage command has no report to evaluate and gets permanently
89
- // stuck in cold-start discovery mode.
90
- if (result.testingFramework === 'karma') {
91
- result.suggestedTestCommand = 'npx karma start';
92
- }
93
- else if (result.testingFramework === 'jest') {
94
- result.suggestedTestCommand = 'npx jest --coverage';
95
- }
96
- else if (result.testingFramework === 'vitest') {
97
- result.suggestedTestCommand = 'npx vitest run --coverage';
98
- }
99
- }
100
- }
101
- return result;
102
- }
103
- /**
104
- * Recursively crawls the project to find source files that lack any corresponding test/spec files.
105
- */
106
- static findUntestedFiles(dir, skipList = []) {
107
- const untested = [];
108
- if (!fs.existsSync(dir))
109
- return untested;
110
- const files = fs.readdirSync(dir);
111
- const ignoreDirs = ['node_modules', 'dist', 'build', '.git', '.angular', 'coverage', 'public', 'assets'];
112
- const ignoreFiles = ['main.ts', 'index.ts', 'app.config.ts', 'app.routes.ts', 'styles.css', 'styles.scss', 'tailwind.config.js', 'eslint.config.js'];
113
- for (const file of files) {
114
- const fullPath = path.join(dir, file);
115
- if (ignoreDirs.includes(file))
116
- continue;
117
- let stat;
118
- try {
119
- stat = fs.statSync(fullPath);
120
- }
121
- catch (e) {
122
- continue;
123
- }
124
- if (stat.isDirectory()) {
125
- untested.push(...this.findUntestedFiles(fullPath, skipList));
126
- }
127
- else if (file.match(/\.(ts|tsx|js|jsx|vue)$/) && !file.includes('.spec.') && !file.includes('.test.')) {
128
- if (ignoreFiles.includes(file))
129
- continue;
130
- const ext = path.extname(file);
131
- const base = file.slice(0, -ext.length);
132
- const possibleSpecs = [
133
- path.join(dir, `${base}.spec${ext}`),
134
- path.join(dir, `${base}.test${ext}`),
135
- path.join(dir, `${base}.spec.js`),
136
- path.join(dir, `${base}.test.js`),
137
- path.join(dir, `${base}.spec.ts`),
138
- path.join(dir, `${base}.test.ts`)
139
- ];
140
- const hasTest = possibleSpecs.some(p => fs.existsSync(p));
141
- if (!hasTest) {
142
- const relativePath = path.relative(process.cwd(), fullPath);
143
- if (!skipList.includes(relativePath)) {
144
- untested.push(relativePath);
145
- }
146
- }
147
- }
148
- }
149
- return untested;
150
- }
151
- }
152
- exports.AutoDiscoveryService = AutoDiscoveryService;
@@ -1,84 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.AutoGeneratorService = void 0;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const llm_service_1 = require("./llm.service");
40
- class AutoGeneratorService {
41
- /**
42
- * Asks the LLM to write the environment-specific setup files (jest.config.js, setupTests.ts)
43
- * if the user's framework is missing them.
44
- */
45
- static async provisionConfigurationFiles(fingerprint, modelProvider, apiKey, projectPath = process.cwd()) {
46
- if (fingerprint.testingFramework === 'none')
47
- return;
48
- console.log(`\n[Lisa.ai Auto-Generator] šŸŖ„ Analyzing ${fingerprint.type} architecture to generate ${fingerprint.testingFramework} configuration specs...`);
49
- // Check if config already exists so we don't nuke it maliciously
50
- const commonConfigs = ['jest.config.js', 'jest.config.ts', 'karma.conf.js', 'vitest.config.ts', 'vitest.config.js'];
51
- const hasExistingConfig = commonConfigs.some(cfg => fs.existsSync(path.join(projectPath, cfg)));
52
- if (hasExistingConfig) {
53
- console.log(`[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.`);
54
- return;
55
- }
56
- const prompt = `You are an expert ${fingerprint.type} architect.
57
- Write a production-ready '${fingerprint.testingFramework}' configuration file for a standard '${fingerprint.type}' application.
58
- The application resides in the root directory.
59
-
60
- Requirements:
61
- 1. Ensure it specifically instruments code coverage.
62
- 2. Ensure standard transpilation (ts-jest for jest, or standard karma-webpack/karma-typescript implementations).
63
- 3. Do NOT wrap your response in markdown formatting (no \`\`\`javascript).
64
- 4. Return ONLY the raw code string block.`;
65
- try {
66
- const generatedConfigString = await (0, llm_service_1.askLisaGeneral)(prompt, modelProvider, apiKey);
67
- let targetFileName = '';
68
- if (fingerprint.testingFramework === 'jest')
69
- targetFileName = 'jest.config.js';
70
- if (fingerprint.testingFramework === 'karma')
71
- targetFileName = 'karma.conf.js';
72
- if (fingerprint.testingFramework === 'vitest')
73
- targetFileName = 'vitest.config.ts';
74
- const targetFilePath = path.join(projectPath, targetFileName);
75
- fs.writeFileSync(targetFilePath, generatedConfigString, 'utf-8');
76
- console.log(`āœ… [Lisa.ai Auto-Generator] Natively wrote ${targetFileName} to repository root.`);
77
- }
78
- catch (error) {
79
- console.error(`\nāŒ [Lisa.ai Auto-Generator] Failed to author configuration file: ${error.message}`);
80
- process.exit(1);
81
- }
82
- }
83
- }
84
- exports.AutoGeneratorService = AutoGeneratorService;
@@ -1,78 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createPullRequestForHeal = createPullRequestForHeal;
7
- const simple_git_1 = __importDefault(require("simple-git"));
8
- const rest_1 = require("@octokit/rest");
9
- require("dotenv/config");
10
- async function createPullRequestForHeal(filePath) {
11
- console.log(`\n[Lisa.ai PR Engine] Initializing Pull Request for ${filePath}...`);
12
- const git = (0, simple_git_1.default)();
13
- const timestamp = new Date().getTime();
14
- const branchName = `lisa-fix/build-error-${timestamp}`;
15
- const commitMsg = `fix: automated auto-heal by Lisa.ai for ${filePath}`;
16
- // Bug 7 fix: capture the current branch BEFORE making any changes so we can reliably
17
- // restore it in the finally block. Hardcoding 'main' would leave the repo stuck on a
18
- // lisa-fix/ branch for any project that uses 'master' or a custom default branch.
19
- let originalBranch = 'main'; // safe fallback
20
- try {
21
- originalBranch = (await git.revparse(['--abbrev-ref', 'HEAD'])).trim();
22
- }
23
- catch (e) {
24
- // If we can't determine the branch (e.g. detached HEAD), keep the fallback
25
- }
26
- try {
27
- // 1. Git Config Setup
28
- await git.addConfig('user.name', 'Lisa.ai');
29
- await git.addConfig('user.email', 'lisa@lisa.ai');
30
- // 2. Branch and Commit
31
- await git.checkoutLocalBranch(branchName);
32
- await git.add(filePath);
33
- await git.commit(commitMsg);
34
- console.log(`[Lisa.ai PR Engine] Committed changes to branch ${branchName}`);
35
- // 3. Optional Push to origin. We need a remote to open a PR.
36
- // If no remote exists, this will fail gracefully or we catch it.
37
- console.log(`[Lisa.ai PR Engine] Pushing branch to remote origin...`);
38
- await git.push('origin', branchName, { '--set-upstream': null });
39
- // 4. Open PR via Octokit
40
- const octokit = new rest_1.Octokit({ auth: process.env.GITHUB_TOKEN });
41
- const repoInfoStr = process.env.GITHUB_REPOSITORY; // e.g., "owner/repo"
42
- if (repoInfoStr && process.env.GITHUB_TOKEN) {
43
- const [owner, repo] = repoInfoStr.split('/');
44
- console.log(`[Lisa.ai PR Engine] Opening Pull Request against ${owner}/${repo}...`);
45
- const pr = await octokit.rest.pulls.create({
46
- owner,
47
- repo,
48
- title: commitMsg,
49
- body: `### Lisa.ai Auto-Healed Pull Request
50
- This PR was automatically generated by Lisa.ai to resolve a failing compilation/build step.
51
-
52
- **Healed File:** \`${filePath}\`
53
-
54
- Please review the changes.`,
55
- head: branchName,
56
- // Bug 7 fix: use the branch that was active before we created the heal branch
57
- // rather than the hardcoded 'main' string.
58
- base: originalBranch,
59
- });
60
- console.log(`āœ… [Lisa.ai PR Engine] Pull Request created successfully: ${pr.data.html_url}`);
61
- }
62
- else {
63
- console.log(`āš ļø [Lisa.ai PR Engine] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping GitHub Pull Request creation.`);
64
- }
65
- }
66
- catch (error) {
67
- console.error(`\n🚨 [Lisa.ai PR Engine Error] Failed to create Pull Request:`, error.message);
68
- }
69
- finally {
70
- // Bug 7 fix: restore to the originally detected branch, not a hardcoded 'main'.
71
- try {
72
- await git.checkout(originalBranch);
73
- }
74
- catch (e) {
75
- // Ignore checkout cleanup error
76
- }
77
- }
78
- }