@lisa.ai/agent 2.2.2 → 2.3.1

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,180 +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 = [
113
- // Angular / framework entry points
114
- 'main.ts', 'index.ts', 'app.config.ts', 'app.routes.ts',
115
- 'styles.css', 'styles.scss',
116
- // Common config files (exact names)
117
- 'tailwind.config.js', 'tailwind.config.ts',
118
- 'eslint.config.js', 'eslint.config.ts',
119
- 'jest.config.js', 'jest.config.ts', 'jest.config.mjs',
120
- 'jest.setup.js', 'jest.setup.ts',
121
- 'webpack.config.js', 'webpack.config.ts',
122
- 'babel.config.js', 'babel.config.ts',
123
- 'rollup.config.js', 'rollup.config.ts',
124
- 'vite.config.js', 'vite.config.ts',
125
- 'vitest.config.js', 'vitest.config.ts',
126
- 'karma.conf.js', 'karma.config.js',
127
- 'prettier.config.js', 'prettier.config.ts',
128
- 'postcss.config.js', 'postcss.config.ts',
129
- 'gulpfile.js', 'Gulpfile.js',
130
- // Dotfile configs often present in Node projects
131
- '.eslintrc.js', '.eslintrc.ts', '.babelrc.js',
132
- ];
133
- // Pattern-based exclusions: dotfiles and *.config.* files not in the list above
134
- const ignorePatterns = [
135
- /^\./, // any dotfile (e.g. .eslintrc.js, .prettierrc.js)
136
- /\.config\.(js|ts|mjs|cjs)$/, // foo.config.js / foo.config.ts
137
- /\.conf\.(js|ts|mjs|cjs)$/, // foo.conf.js
138
- ];
139
- for (const file of files) {
140
- const fullPath = path.join(dir, file);
141
- if (ignoreDirs.includes(file))
142
- continue;
143
- let stat;
144
- try {
145
- stat = fs.statSync(fullPath);
146
- }
147
- catch (e) {
148
- continue;
149
- }
150
- if (stat.isDirectory()) {
151
- untested.push(...this.findUntestedFiles(fullPath, skipList));
152
- }
153
- else if (file.match(/\.(ts|tsx|js|jsx|vue)$/) && !file.includes('.spec.') && !file.includes('.test.')) {
154
- if (ignoreFiles.includes(file))
155
- continue;
156
- if (ignorePatterns.some(p => p.test(file)))
157
- continue;
158
- const ext = path.extname(file);
159
- const base = file.slice(0, -ext.length);
160
- const possibleSpecs = [
161
- path.join(dir, `${base}.spec${ext}`),
162
- path.join(dir, `${base}.test${ext}`),
163
- path.join(dir, `${base}.spec.js`),
164
- path.join(dir, `${base}.test.js`),
165
- path.join(dir, `${base}.spec.ts`),
166
- path.join(dir, `${base}.test.ts`)
167
- ];
168
- const hasTest = possibleSpecs.some(p => fs.existsSync(p));
169
- if (!hasTest) {
170
- const relativePath = path.relative(process.cwd(), fullPath);
171
- if (!skipList.includes(relativePath)) {
172
- untested.push(relativePath);
173
- }
174
- }
175
- }
176
- }
177
- return untested;
178
- }
179
- }
180
- 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
- }
@@ -1,60 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AutoInstallerService = void 0;
4
- const child_process_1 = require("child_process");
5
- class AutoInstallerService {
6
- /**
7
- * Natively executes NPM installation commands if a framework is completely devoid of testing tooling.
8
- */
9
- static async installMissingFramework(fingerprint, projectPath = process.cwd()) {
10
- if (fingerprint.testingFramework !== 'none') {
11
- return fingerprint; // Already fully equipped
12
- }
13
- console.log(`\n[Lisa.ai Auto-Installer] 🚨 No testing framework detected for ${fingerprint.type} architecture.`);
14
- console.log(`[Lisa.ai Auto-Installer] 🪄 Initiating Zero-Config Installation Protocol...`);
15
- let installCmd = '';
16
- let testingTarget = 'none';
17
- switch (fingerprint.type) {
18
- case 'angular':
19
- // Angular historically uses Karma/Jasmine natively, though modern might prefer Jest.
20
- // We'll provision standard Jasmine/Karma to align with standard Angular builders.
21
- console.log(`[Lisa.ai Auto-Installer] Provisioning Angular TestBed environment...`);
22
- installCmd = 'npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine jasmine-core @types/jasmine';
23
- testingTarget = 'karma';
24
- fingerprint.suggestedTestCommand = 'npm run test';
25
- break;
26
- case 'react':
27
- case 'node':
28
- default:
29
- // Jest is the safest, most ubiquitous generic fallback for React and Node JS.
30
- console.log(`[Lisa.ai Auto-Installer] Provisioning Universal Jest environment...`);
31
- installCmd = 'npm install --save-dev jest @types/jest ts-jest';
32
- testingTarget = 'jest';
33
- fingerprint.suggestedTestCommand = 'npx jest --coverage';
34
- break;
35
- case 'vue':
36
- // Vitest is the modern standard for Vue 3 / Vite ecosystems
37
- console.log(`[Lisa.ai Auto-Installer] Provisioning Vue Vitest environment...`);
38
- installCmd = 'npm install --save-dev vitest @vue/test-utils jsdom';
39
- testingTarget = 'vitest';
40
- fingerprint.suggestedTestCommand = 'npx vitest run --coverage';
41
- break;
42
- }
43
- if (installCmd) {
44
- console.log(`[Lisa.ai Executing] ${installCmd}`);
45
- const parts = installCmd.split(' ');
46
- const childTarget = process.platform === 'win32' ? `${parts[0]}.cmd` : parts[0];
47
- // Execute natively blocking so the repository is fully built before the agent tries to test it
48
- const result = (0, child_process_1.spawnSync)(childTarget, parts.slice(1), { cwd: projectPath, stdio: 'inherit' });
49
- if (result.status !== 0) {
50
- console.error(`\n❌ [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`);
51
- process.exit(1);
52
- }
53
- console.log(`✅ [Lisa.ai Auto-Installer] Framework successfully injected.`);
54
- fingerprint.testingFramework = testingTarget;
55
- return fingerprint;
56
- }
57
- return fingerprint;
58
- }
59
- }
60
- exports.AutoInstallerService = AutoInstallerService;
@@ -1,197 +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.askLisaForFix = askLisaForFix;
37
- exports.generateTestForFile = generateTestForFile;
38
- exports.updateTestForFile = updateTestForFile;
39
- exports.askLisaGeneral = askLisaGeneral;
40
- const ai_1 = require("ai");
41
- const openai_1 = require("@ai-sdk/openai");
42
- const anthropic_1 = require("@ai-sdk/anthropic");
43
- const google_1 = require("@ai-sdk/google");
44
- const path = __importStar(require("path"));
45
- const dotenv = __importStar(require("dotenv"));
46
- dotenv.config({ path: path.resolve(__dirname, '../../.env'), quiet: true });
47
- // Context-window guard: large files cause the LLM to hit its input limit and return
48
- // its internal context-compression prompt instead of code, corrupting the spec file.
49
- // 15 000 chars ≈ ~4 000 tokens — safe for all supported models.
50
- const MAX_SOURCE_CHARS = 15000;
51
- function truncateSource(content, label) {
52
- if (content.length <= MAX_SOURCE_CHARS)
53
- return content;
54
- console.warn(`[Lisa.ai LLM] ${label} is ${content.length} chars — truncating to ${MAX_SOURCE_CHARS} to stay within context window.`);
55
- return content.slice(0, MAX_SOURCE_CHARS) + '\n\n// ... (truncated)';
56
- }
57
- // Sanity-check the LLM response before it gets written to disk.
58
- // If the response contains none of the standard test primitives it is almost certainly
59
- // a meta-prompt leak or hallucination — throw so the caller can write a placeholder
60
- // instead of permanently corrupting the spec file.
61
- function assertLooksLikeTestCode(text, filePath) {
62
- const testKeywords = /\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/;
63
- if (!testKeywords.test(text)) {
64
- throw new Error(`LLM returned a non-code response for ${filePath} (possible context overflow). Skipping to prevent file corruption.`);
65
- }
66
- }
67
- function getProvider(provider, apiKey) {
68
- if (provider === 'claude') {
69
- const key = apiKey || process.env.ANTHROPIC_API_KEY;
70
- if (!key)
71
- throw new Error('No Anthropic API key provided by local ENV or Control Plane');
72
- // Bug 2 fix: claude-3-haiku is too weak for complex DI/module fixes.
73
- // claude-3-5-sonnet is significantly better at understanding Angular/React test scaffolding.
74
- return (0, anthropic_1.createAnthropic)({ apiKey: key })('claude-3-5-sonnet-20241022');
75
- }
76
- if (provider === 'openai') {
77
- const key = apiKey || process.env.OPENAI_API_KEY;
78
- if (!key)
79
- throw new Error('No OpenAI API key provided by local ENV or Control Plane');
80
- // Bug 2 fix: gpt-3.5-turbo is deprecated and produces low-quality code fixes.
81
- return (0, openai_1.createOpenAI)({ apiKey: key })('gpt-4o-mini');
82
- }
83
- const key = apiKey || process.env.GOOGLE_GENERATIVE_AI_API_KEY;
84
- if (!key)
85
- throw new Error('No Google API key provided by local ENV or Control Plane');
86
- return (0, google_1.createGoogleGenerativeAI)({ apiKey: key })('gemini-1.5-pro-latest');
87
- }
88
- async function askLisaForFix(filePath, fileContent, errorLog, modelProvider, apiKey, previousFixAttempt, siblingContext) {
89
- console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${modelProvider} for ${filePath}...`);
90
- const model = getProvider(modelProvider, apiKey);
91
- let prompt = "You are Lisa.ai, an autonomous CI/CD expert platform.\n" +
92
- "A build/compilation error occurred. Your task is to fix the provided file so that the error resolves.\n\n" +
93
- "--- Error Log ---\n" + errorLog + "\n\n" +
94
- "--- Target File Content (" + filePath + ") ---\n" + fileContent + "\n\n" +
95
- "--- Constraints ---\n" +
96
- "1. Do not delete business logic unless absolutely necessary to resolve a missing dependency.\n" +
97
- "2. Do not suppress TypeScript errors with @ts-ignore or any type assertions unless absolutely unavoidable.\n" +
98
- "3. Fix the underlying type or logic issue.\n" +
99
- "4. CRITICAL AGILE RULE: If the error is 'Cannot find module' or 'Property DOES NOT EXIST' and you do NOT know the correct import path or cannot resolve it from the context, you MUST silently comment out the failing import and completely comment out/stub the code that relies on it. Your ultimate goal is to make the file compile successfully so the Agent can proceed to the next file.\n" +
100
- "5. FRAMEWORK TEST RULE: If fixing a testing file ('.spec' or '.test') and an Angular error happens like 'NullInjectorError: No provider for X', you MUST add X to the 'providers' array in 'TestBed.configureTestingModule' or import the required testing module. If a React testing library error arises, fix the render context.\n" +
101
- "6. CRITICAL ANGULAR RULE: If an Angular component imports 'RouterLink' or uses '[routerLink]' in its template, you MUST provide 'ActivatedRoute' in the providers array or import 'RouterTestingModule'. If it uses HTTP, import 'HttpClientTestingModule'.\n" +
102
- "7. CRITICAL STANDALONE RULE: If a component has 'standalone: true' in its decorator (check the Sibling Context!), you MUST NOT add it to the 'declarations' array. Instead, you MUST add it to the 'imports' array within 'TestBed.configureTestingModule'.\n" +
103
- "8. Return the code wrapped in a markdown code block (```typescript ... ```). Do not include any explanation or intro text.";
104
- if (siblingContext) {
105
- const isStandalone = /standalone\s*:\s*true/.test(siblingContext);
106
- if (isStandalone) {
107
- const classMatch = siblingContext.match(/export class (\w+)/);
108
- const className = classMatch ? classMatch[1] : 'the component';
109
- prompt += "\n\n--- CRITICAL ARCHITECTURAL REQUIREMENT ---\n" +
110
- "The component " + className + " is marked as STANDALONE (standalone: true).\n" +
111
- "You MUST add " + className + " to the 'imports' array within 'TestBed.configureTestingModule'.\n" +
112
- "DO NOT add it to the 'declarations' array. If you omit " + className + " from 'imports', the test will fail.";
113
- }
114
- prompt += "\n\n--- Sibling Component / Service Context ---\n" +
115
- "You are fixing a '.spec' test file. Here is the actual implementation code for the component you are testing.\n" +
116
- "Use this to identify EXACTLY which imports, Services, and Variables need to be mocked inside your 'TestBed'.\n" +
117
- siblingContext;
118
- }
119
- if (previousFixAttempt) {
120
- console.log(`[Lisa.ai Auto-Heal] Warning! Agent is looping on ${filePath}. Injecting previous failed context...`);
121
- prompt += "\n\n--- CRITICAL WARNING ---\n" +
122
- "You previously attempted to fix this file but the compiler REJECTED your fix!\n" +
123
- "Here is the previous analysis and failed fix you attempted:\n" +
124
- previousFixAttempt + "\n\n" +
125
- "DO NOT repeat the identical code changes. Try a completely different programming approach, fix syntax typos, or check for missing imports.";
126
- }
127
- const { text } = await (0, ai_1.generateText)({
128
- model,
129
- prompt,
130
- });
131
- // Bug 1 fix: handle javascript/js code blocks in addition to typescript/ts.
132
- // Without this, JS file fixes from the LLM using ```javascript blocks are not extracted —
133
- // the raw markdown (including ``` markers) gets written to disk, permanently corrupting the file.
134
- const match = text.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
135
- return match ? match[1].trim() : text.trim();
136
- }
137
- async function generateTestForFile(sourceFilePath, sourceFileContent, modelProvider, apiKey, framework) {
138
- console.log(`[Lisa.ai Coverage] Requesting test generation from ${modelProvider} for ${sourceFilePath}...`);
139
- const model = getProvider(modelProvider, apiKey);
140
- // Bug 3 fix: include the detected testing framework in the prompt so the LLM doesn't
141
- // randomly pick Jest syntax for a Karma project (or vice-versa), causing immediate
142
- // compile failures that trigger an unnecessary heal loop.
143
- const frameworkInstruction = framework
144
- ? `3. You MUST use the '${framework}' testing framework exclusively. All imports, describe/it/test blocks, and mock utilities must follow '${framework}' conventions.\n`
145
- : "3. Include all necessary imports assuming a standard testing framework (Jest/Karma/Vitest) is available.\n";
146
- const prompt = "You are Lisa.ai, an autonomous CI/CD expert platform.\n" +
147
- "A source file lacks 100% test coverage. Your task is to generate a comprehensive testing suite covering all branches, lines, and functions.\n\n" +
148
- "--- Target File Content (" + sourceFilePath + ") ---\n" + truncateSource(sourceFileContent, sourceFilePath) + "\n\n" +
149
- "--- Constraints ---\n" +
150
- "1. Return the generated test code wrapped in a markdown code block (```typescript ... ```).\n" +
151
- "2. Do not include any explanation or intro text.\n" +
152
- frameworkInstruction +
153
- "4. Aim for 100% logic coverage.";
154
- const { text } = await (0, ai_1.generateText)({
155
- model,
156
- prompt,
157
- });
158
- const match = text.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
159
- const result = match ? match[1].trim() : text.trim();
160
- assertLooksLikeTestCode(result, sourceFilePath);
161
- return result;
162
- }
163
- async function updateTestForFile(sourceFilePath, sourceFileContent, testFilePath, existingTestContent, modelProvider, apiKey, framework) {
164
- console.log(`[Lisa.ai Coverage] Requesting test update from ${modelProvider} for ${sourceFilePath}...`);
165
- const model = getProvider(modelProvider, apiKey);
166
- // Bug 3 fix: same as generateTestForFile — specify the framework so updates
167
- // don't introduce incompatible syntax into an existing test suite.
168
- const frameworkInstruction = framework
169
- ? `3. You MUST use the '${framework}' testing framework exclusively. All new tests must follow '${framework}' conventions and integrate cleanly with the existing suite.\n`
170
- : "3. Append missing tests to the existing suite. Do not delete existing passing tests unless they are fundamentally broken.\n";
171
- const prompt = "You are Lisa.ai, an autonomous CI/CD expert platform.\n" +
172
- "A source file lacks 100% test coverage. You must update its existing test suite to achieve full coverage.\n\n" +
173
- "--- Target File Content (" + sourceFilePath + ") ---\n" + truncateSource(sourceFileContent, sourceFilePath) + "\n\n" +
174
- "--- Existing Test Suite (" + testFilePath + ") ---\n" + existingTestContent + "\n\n" +
175
- "--- Constraints ---\n" +
176
- "1. Return the updated complete test code wrapped in a markdown code block (```typescript ... ```).\n" +
177
- "2. Do not include any explanation or intro text.\n" +
178
- frameworkInstruction +
179
- "4. Aim for 100% logic coverage across branches, lines, and functions.";
180
- const { text } = await (0, ai_1.generateText)({
181
- model,
182
- prompt,
183
- });
184
- const match = text.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
185
- const result = match ? match[1].trim() : text.trim();
186
- assertLooksLikeTestCode(result, sourceFilePath);
187
- return result;
188
- }
189
- async function askLisaGeneral(promptStr, modelProvider, apiKey) {
190
- const model = getProvider(modelProvider, apiKey);
191
- const { text } = await (0, ai_1.generateText)({
192
- model,
193
- prompt: promptStr,
194
- });
195
- const match = text.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
196
- return match ? match[1].trim() : text.trim();
197
- }
@@ -1,60 +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.reportTelemetry = reportTelemetry;
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
- dotenv.config({ path: path.resolve(__dirname, '../../.env'), quiet: true });
41
- async function reportTelemetry(event) {
42
- const MASTER_CONTROL_URL = process.env.LISA_CONTROL_PLANE_URL || 'http://localhost:3000';
43
- const url = `${MASTER_CONTROL_URL}/api/telemetry`;
44
- // Telemetry Bug 1 fix: true fire-and-forget — attach a .catch() handler and return immediately.
45
- // The previous `await fetch(...)` contradicted the "don't block" comment: with 3 telemetry
46
- // calls per file and 50+ files in a large project, the heal loop was silently waiting for
47
- // 150+ network round-trips before doing any actual work.
48
- // Keeping the function signature as async+Promise<void> means existing `await reportTelemetry()`
49
- // callsites continue to compile without change — they just resolve instantly now.
50
- fetch(url, {
51
- method: 'POST',
52
- headers: {
53
- 'Content-Type': 'application/json'
54
- },
55
- body: JSON.stringify(event)
56
- }).catch((error) => {
57
- // Silently fail if control plane is down so agent can still work detached
58
- console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${error.message}`);
59
- });
60
- }