@lisa.ai/agent 1.0.4 → 1.0.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.
@@ -41,7 +41,7 @@ const coverage_parser_1 = require("../utils/coverage.parser");
41
41
  const llm_service_1 = require("../services/llm.service");
42
42
  const heal_1 = require("./heal");
43
43
  const telemetry_service_1 = require("../services/telemetry.service");
44
- async function coverageCommand(command, modelProvider, attempt = 1, maxRetries = 3, projectId = 'local') {
44
+ async function coverageCommand(command, modelProvider, attempt = 1, maxRetries = 3, projectId = 'local', apiKey) {
45
45
  console.log(`\n[Lisa.ai Coverage] ${command} (Attempt ${attempt}/${maxRetries}) Using Model: ${modelProvider}`);
46
46
  let executionPassed = true;
47
47
  try {
@@ -53,11 +53,11 @@ async function coverageCommand(command, modelProvider, attempt = 1, maxRetries =
53
53
  catch (error) {
54
54
  console.log(`\nāŒ [Lisa.ai Coverage] Tests failed. Delegating to Auto-Heal...`);
55
55
  // If tests themselves fail to compile or run, we fallback exactly to auto-heal
56
- await (0, heal_1.healCommand)(command, modelProvider, 1, null, maxRetries, projectId);
56
+ await (0, heal_1.healCommand)(command, modelProvider, 1, null, maxRetries, projectId, undefined, apiKey);
57
57
  // Once the auto-heal engine successfully returns, compilation errors are fixed!
58
58
  // We gracefully restart the coverage engine to evaluate the newly working tests.
59
59
  console.log(`\nšŸ”„ [Lisa.ai Coverage] Auto-Heal successful. Restarting coverage analysis...`);
60
- await coverageCommand(command, modelProvider, attempt + 1, maxRetries, projectId);
60
+ await coverageCommand(command, modelProvider, attempt + 1, maxRetries, projectId, apiKey);
61
61
  return;
62
62
  }
63
63
  // 2. If it passed without compile/runtime errors, evaluate coverage
@@ -85,7 +85,7 @@ async function coverageCommand(command, modelProvider, attempt = 1, maxRetries =
85
85
  const absoluteTarget = path.resolve(process.cwd(), targetFilePath);
86
86
  console.log(`[Lisa.ai Coverage] Requesting generated test suite for ${targetFilePath}...`);
87
87
  const fileContent = fs.readFileSync(absoluteTarget, 'utf-8');
88
- const testCode = await (0, llm_service_1.generateTestForFile)(targetFilePath, fileContent, modelProvider);
88
+ const testCode = await (0, llm_service_1.generateTestForFile)(targetFilePath, fileContent, modelProvider, apiKey);
89
89
  // Derive spec name from original file name (e.g. app.component.ts -> app.component.spec.ts)
90
90
  const parsedPath = path.parse(absoluteTarget);
91
91
  const specPath = path.join(parsedPath.dir, `${parsedPath.name}.spec${parsedPath.ext}`);
@@ -100,7 +100,7 @@ async function coverageCommand(command, modelProvider, attempt = 1, maxRetries =
100
100
  details: `### Missing Logic Coverage Detected\n**Auto-Generated Specification Suite (${modelProvider}):**\n\`\`\`typescript\n${testCode}\n\`\`\``
101
101
  });
102
102
  // 4. Recursive iteration to verify newly written test and hunt for next gap
103
- await coverageCommand(command, modelProvider, attempt + 1, maxRetries, projectId);
103
+ await coverageCommand(command, modelProvider, attempt + 1, maxRetries, projectId, apiKey);
104
104
  }
105
105
  catch (e) {
106
106
  console.error(`[Lisa.ai Coverage loop failure]:`, e.message);
@@ -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) {
44
+ async function healCommand(command, modelProvider, attempt = 1, healedFilePath = null, maxRetries = 3, projectId = 'local', lastFixDetails, apiKey) {
45
45
  console.log(`\n[Lisa.ai Executing] ${command} (Attempt ${attempt}/${maxRetries}) Using Model: ${modelProvider}`);
46
46
  try {
47
47
  // Execute command synchronously
@@ -88,12 +88,12 @@ async function healCommand(command, modelProvider, attempt = 1, healedFilePath =
88
88
  // Read file contents to send to LLM
89
89
  const fileContent = fs.readFileSync(absolutePath, 'utf-8');
90
90
  // Call LLM for a fix
91
- const fixedCode = await (0, llm_service_1.askLisaForFix)(filePath, fileContent, errorLog, modelProvider);
91
+ const fixedCode = await (0, llm_service_1.askLisaForFix)(filePath, fileContent, errorLog, modelProvider, apiKey);
92
92
  // Write the fix to the file
93
93
  fs.writeFileSync(absolutePath, fixedCode, 'utf-8');
94
94
  console.log(`[Lisa.ai Auto-Heal] Applied patch to ${filePath}`);
95
95
  // Recursive retry, passing the healed file path state
96
96
  const generatedDetails = `### Auto-Heal Analysis Triggered\n**Caught Error:**\n\`\`\`bash\n${errorLog}\n\`\`\`\n\n**Applied Fix (${modelProvider}):**\n\`\`\`typescript\n${fixedCode}\n\`\`\``;
97
- await healCommand(command, modelProvider, attempt + 1, filePath, maxRetries, projectId, generatedDetails);
97
+ await healCommand(command, modelProvider, attempt + 1, filePath, maxRetries, projectId, generatedDetails, apiKey);
98
98
  }
99
99
  }
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ program
19
19
  .action(async (options) => {
20
20
  let maxRetries = 3;
21
21
  let model = options.model;
22
+ let apiKey = undefined;
22
23
  if (options.projectId) {
23
24
  const config = await (0, config_service_1.fetchRemoteConfig)(options.projectId);
24
25
  if (!config) {
@@ -28,12 +29,13 @@ program
28
29
  console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${config.modelProvider}, MaxRetries=${config.maxRetries}`);
29
30
  model = config.modelProvider;
30
31
  maxRetries = config.maxRetries;
32
+ apiKey = config.apiKey;
31
33
  if (config.autoHealEnabled === false) {
32
34
  console.log(`[Lisa.ai Agent] Auto-heal is disabled by Control Plane.`);
33
35
  process.exit(1);
34
36
  }
35
37
  }
36
- await (0, heal_1.healCommand)(options.command, model, 1, null, maxRetries, options.projectId || 'local');
38
+ await (0, heal_1.healCommand)(options.command, model, 1, null, maxRetries, options.projectId || 'local', undefined, apiKey);
37
39
  });
38
40
  program
39
41
  .command('coverage')
@@ -44,6 +46,7 @@ program
44
46
  .action(async (options) => {
45
47
  let maxRetries = 3;
46
48
  let model = options.model;
49
+ let apiKey = undefined;
47
50
  if (options.projectId) {
48
51
  const config = await (0, config_service_1.fetchRemoteConfig)(options.projectId);
49
52
  if (!config) {
@@ -53,7 +56,8 @@ program
53
56
  console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${config.modelProvider}, MaxRetries=${config.maxRetries}`);
54
57
  model = config.modelProvider;
55
58
  maxRetries = config.maxRetries;
59
+ apiKey = config.apiKey;
56
60
  }
57
- await (0, coverage_1.coverageCommand)(options.command, model, 1, maxRetries, options.projectId || 'local');
61
+ await (0, coverage_1.coverageCommand)(options.command, model, 1, maxRetries, options.projectId || 'local', apiKey);
58
62
  });
59
63
  program.parse(process.argv);
@@ -44,24 +44,27 @@ const dotenv = __importStar(require("dotenv"));
44
44
  // Force dotenv to load the `.env` file from the agent's root directory
45
45
  // regardless of which folder the user is currently running the CLI inside.
46
46
  dotenv.config({ path: path.resolve(__dirname, '../../.env') });
47
- async function askLisaForFix(filePath, fileContent, errorLog, modelProvider) {
48
- console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${modelProvider} for ${filePath}...`);
49
- let model;
50
- switch (modelProvider) {
51
- case 'openai':
52
- model = (0, openai_1.openai)('gpt-4o');
53
- break;
54
- case 'claude':
55
- model = (0, anthropic_1.anthropic)('claude-3-haiku-20240307');
56
- break;
57
- case 'gemini':
58
- model = (0, google_1.google)('gemini-1.5-pro-latest');
59
- break;
60
- default:
61
- console.warn(`[Lisa.ai Warning] Unrecognized modelProvider '${modelProvider}', defaulting to 'gemini'`);
62
- model = (0, google_1.google)('gemini-1.5-pro-latest');
63
- break;
47
+ function getProvider(provider, apiKey) {
48
+ if (provider === 'claude') {
49
+ const key = apiKey || process.env.ANTHROPIC_API_KEY;
50
+ if (!key)
51
+ throw new Error('No Anthropic API key provided by local ENV or Control Plane');
52
+ return (0, anthropic_1.createAnthropic)({ apiKey: key })('claude-3-haiku-20240307');
53
+ }
54
+ if (provider === 'openai') {
55
+ const key = apiKey || process.env.OPENAI_API_KEY;
56
+ if (!key)
57
+ throw new Error('No OpenAI API key provided by local ENV or Control Plane');
58
+ return (0, openai_1.createOpenAI)({ apiKey: key })('gpt-3.5-turbo');
64
59
  }
60
+ const key = apiKey || process.env.GOOGLE_GENERATIVE_AI_API_KEY;
61
+ if (!key)
62
+ throw new Error('No Google API key provided by local ENV or Control Plane');
63
+ return (0, google_1.createGoogleGenerativeAI)({ apiKey: key })('gemini-1.5-pro-latest');
64
+ }
65
+ async function askLisaForFix(filePath, fileContent, errorLog, modelProvider, apiKey) {
66
+ console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${modelProvider} for ${filePath}...`);
67
+ const model = getProvider(modelProvider, apiKey);
65
68
  const prompt = `You are Lisa.ai, an autonomous CI/CD expert platform.
66
69
  A build/compilation error occurred. Your task is to fix the provided file so that the error resolves.
67
70
 
@@ -88,23 +91,9 @@ ${fileContent}
88
91
  const match = text.match(/```(?:typescript|ts)?\n([\s\S]*?)```/);
89
92
  return match ? match[1].trim() : text.trim();
90
93
  }
91
- async function generateTestForFile(sourceFilePath, sourceFileContent, modelProvider) {
94
+ async function generateTestForFile(sourceFilePath, sourceFileContent, modelProvider, apiKey) {
92
95
  console.log(`[Lisa.ai Coverage] Requesting test generation from ${modelProvider} for ${sourceFilePath}...`);
93
- let model;
94
- switch (modelProvider) {
95
- case 'openai':
96
- model = (0, openai_1.openai)('gpt-4o');
97
- break;
98
- case 'claude':
99
- model = (0, anthropic_1.anthropic)('claude-3-haiku-20240307');
100
- break;
101
- case 'gemini':
102
- model = (0, google_1.google)('gemini-1.5-pro-latest');
103
- break;
104
- default:
105
- model = (0, google_1.google)('gemini-1.5-pro-latest');
106
- break;
107
- }
96
+ const model = getProvider(modelProvider, apiKey);
108
97
  const prompt = `You are Lisa.ai, an autonomous CI/CD expert platform.
109
98
  A TypeScript/Angular file lacks 100% test coverage. Your task is to generate a comprehensive Jest unit test file (.spec.ts) covering all branches, lines, and functions.
110
99
 
@@ -2,17 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractFilePath = extractFilePath;
4
4
  function extractFilePath(errorLog) {
5
+ // Sanitize invisible ANSI color codes (e.g. \x1b[96m) from CLI output logs
6
+ const cleanLog = errorLog.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
5
7
  // Matches typical TS/Angular error patterns:
6
8
  // e.g., "src/app/app.component.ts:12:3 - error TS2322:"
7
9
  // e.g., "Error: src/app/app.component.ts:12:3"
8
10
  // Try to match path near an error
9
11
  const tsErrorRegex = /([a-zA-Z0-9_.\-\/\\]+\.ts)(?:[:(])/;
10
- const match = tsErrorRegex.exec(errorLog);
12
+ const match = tsErrorRegex.exec(cleanLog);
11
13
  if (match && match[1]) {
12
14
  return match[1];
13
15
  }
14
16
  // Fallback: Just try to find anything that looks like a .ts file path
15
17
  const fallbackRegex = /([a-zA-Z0-9_.\-\/\\]+\.ts)/;
16
- const fallbackMatch = fallbackRegex.exec(errorLog);
18
+ const fallbackMatch = fallbackRegex.exec(cleanLog);
17
19
  return fallbackMatch ? fallbackMatch[1] : null;
18
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lisa.ai/agent",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Lisa.ai Autonomous CI/CD Worker Agent",
5
5
  "main": "dist/index.js",
6
6
  "bin": {