@lisa.ai/agent 2.9.6 → 2.9.7
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/index.js +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var jt=Object.create;var _e=Object.defineProperty;var Et=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var At=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var It=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Tt=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ft(t))!Pt.call(e,o)&&o!==s&&_e(e,o,{get:()=>t[o],enumerable:!(n=Et(t,o))||n.enumerable});return e};var b=(e,t,s)=>(s=e!=null?jt(At(e)):{},Tt(t||!e||!e.__esModule?_e(s,"default",{value:e,enumerable:!0}):s,e));var Lt=It((tn,Kt)=>{Kt.exports={name:"@lisa.ai/agent",version:"2.9.
|
|
2
|
+
"use strict";var jt=Object.create;var _e=Object.defineProperty;var Et=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var At=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var It=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Tt=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ft(t))!Pt.call(e,o)&&o!==s&&_e(e,o,{get:()=>t[o],enumerable:!(n=Et(t,o))||n.enumerable});return e};var b=(e,t,s)=>(s=e!=null?jt(At(e)):{},Tt(t||!e||!e.__esModule?_e(s,"default",{value:e,enumerable:!0}):s,e));var Lt=It((tn,Kt)=>{Kt.exports={name:"@lisa.ai/agent",version:"2.9.7",description:"Lisa.ai Autonomous CI/CD Worker Agent",main:"dist/index.js",bin:{"lisa-agent":"dist/index.js"},files:["dist/"],scripts:{build:"tsup",typecheck:"tsc --noEmit",start:"node dist/index.js",dev:"ts-node src/index.ts",prepublishOnly:"npm run typecheck && npm run build"},keywords:["lisa","ci","cd","agent"],author:"Lisa.ai",license:"ISC",dependencies:{"@ai-sdk/anthropic":"^3.0.46","@ai-sdk/google":"^3.0.30","@ai-sdk/openai":"^3.0.30","@octokit/rest":"^22.0.1",ai:"^6.0.94",commander:"^11.1.0",dotenv:"^17.3.1","simple-git":"^3.31.1"},devDependencies:{"@types/jest":"^30.0.0","@types/node":"^20.0.0","ts-node":"^10.9.1",tsup:"^8.5.1",typescript:"^5.0.0"}}});var kt=require("commander"),X=b(require("fs")),he=b(require("path")),Ct=b(require("readline"));var Oe=b(require("dotenv"));Oe.config({quiet:!0});async function ye(e){let t=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{let s=`${t}/api/v1/lisa/config/${e}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${s}...`);let n=await fetch(s);if(!n.ok){let i=n.status===404?"not_found":"unreachable";return console.warn(i==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${e}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${n.status}. Falling back to local defaults.`),{ok:!1,reason:i}}return{ok:!0,config:await n.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${t}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var rt=require("child_process"),H=b(require("fs")),Z=b(require("path"));var S=b(require("path")),R=b(require("fs"));function we(e){return e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function Y(e){let t=we(e),s=[...t.matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(s.length>0){let g=[...s].reverse().find(f=>f[3]!==void 0)??s[s.length-1],d=parseInt(g[2]),x=g[3]?parseInt(g[3]):0,h=parseInt(g[1])-x;return{total:d,passed:h,failed:x}}let n=t.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+passed,?\s*)?(\d+)\s+total/);if(n){let g=parseInt(n[3]),d=n[1]?parseInt(n[1]):0,x=n[2]?parseInt(n[2]):0;return{total:g,passed:x,failed:d}}let o=t.match(/(\d+)\s+failed/),i=t.match(/(\d+)\s+passed/);if(i||o){let g=o?parseInt(o[1]):0,d=i?parseInt(i[1]):0,x=t.match(/(\d+)\s+skipped/),h=x?parseInt(x[1]):0;return{total:d+g+h,passed:d,failed:g}}let r=t.match(/Tests\s+(?:(\d+)\s+failed\s*\|?\s*)?(\d+)\s+passed\s*\((\d+)\)/);if(r){let g=parseInt(r[3]),d=r[1]?parseInt(r[1]):0,x=parseInt(r[2]);return{total:g,passed:x,failed:d}}let a=t.match(/(\d+)\s+passing/),p=t.match(/(\d+)\s+failing/);if(a){let g=parseInt(a[1]),d=p?parseInt(p[1]):0;return{total:g+d,passed:g,failed:d}}return null}function Fe(e,t=process.cwd(),s=[]){let n=e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=s.map(l=>S.resolve(t,l)),i=new Map,r=new Set,a=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,p;for(;(p=a.exec(n))!==null;){let u=p[1].trim().split(" ");for(let c=1;c<Math.min(u.length,6);c++){let L=u.slice(0,c).join(" ");if(r.has(L))continue;r.add(L);let $=Ae(L,t,o);if($){let m=S.resolve($);i.has(m)||i.set(m,S.relative(t,$));break}}}let g=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,d;for(;(d=g.exec(n))!==null;){let l=d[1],u=S.isAbsolute(l)?l:S.resolve(t,l);!o.includes(u)&&R.existsSync(u)&&!i.has(u)&&i.set(u,S.relative(t,u))}let x=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,h;for(;(h=x.exec(n))!==null;){let l=h[1],u=S.isAbsolute(l)?l:S.resolve(t,l);!o.includes(u)&&R.existsSync(u)&&!i.has(u)&&i.set(u,S.relative(t,u))}let f=/Running:\s+([^\s]+\.(?:cy|spec|test)\.[tj]sx?)/g,w;for(;(w=f.exec(n))!==null;){let l=w[1],u=S.isAbsolute(l)?l:S.resolve(t,l);if(!o.includes(u)&&R.existsSync(u)&&!i.has(u)){let c=l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");new RegExp(c+"\\s+\\d+\\s+\\d+\\s+([1-9]\\d*)").test(n)&&i.set(u,S.relative(t,u))}}return[...i.values()]}function ve(e,t=[],s=process.cwd()){let n=e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=t.map(l=>S.resolve(l));{let l=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,u=new Set,c;for(;(c=l.exec(n))!==null;){let $=c[1].trim().split(" ");for(let m=1;m<Math.min($.length,5);m++){let y=$.slice(0,m).join(" ");if(u.has(y))continue;u.add(y);let v=Ae(y,s,o);if(v)return S.relative(s,v)}}}let i=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))(?:\s*[:(])/g,r;for(;(r=i.exec(n))!==null;){let l=r[1];if(l){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(l))continue;let u=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(u)&&R.existsSync(u))return l}}let a=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,p;for(;(p=a.exec(n))!==null;){let l=p[1],u=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(u)&&R.existsSync(u))return l}{let l=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,u;for(;(u=l.exec(n))!==null;){let c=u[1],L=S.isAbsolute(c)?c:S.resolve(s,c);if(!o.includes(L)&&R.existsSync(L))return c}}let g=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,d;for(;(d=g.exec(n))!==null;){let l=d[1];if(l){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(l))continue;let u=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(u)&&R.existsSync(u))return l}}let x=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,h,f=new Set,w=["Error","TypeError","SyntaxError","ReferenceError","RangeError","Object","Boolean","String","Number","Array","NullInjectorError","NullInjector","R3Injector","ChainedInjector","Module","Component","Standalone","Application","App2","TestBed","UserContext","Chrome","ChromeHeadless","Karma","Launching","Starting","Headless","Connected","Executed","INFO","SUCCESS","FAILED","Building","Initial","Names","Lazy","Source","Find","NotFound","NG0201","Windows","Linux","Macintosh","Users","AppData","Local","Temp","Process","Unexpected","Expected","Validation","Directory","Configuration","Documentation"];for(;(h=x.exec(n))!==null;){let l=h[1];if(!l||w.includes(l)||f.has(l)||/^[A-Z][A-Z0-9]{5,11}$/.test(l)||/^[A-Za-z0-9]{16,}$/.test(l))continue;f.add(l);let u=Ge(l,s,o);if(u)return S.relative(s,u)}return null}function Ae(e,t,s){if(!R.existsSync(t))return null;let n=R.readdirSync(t);for(let o of n){let i=S.join(t,o);if(["node_modules","dist","build",".git",".angular"].includes(o))continue;let r;try{r=R.statSync(i)}catch{continue}if(r.isDirectory()){let a=Ae(e,i,s);if(a)return a}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(o)){if(s.includes(S.resolve(i)))continue;try{let a=R.readFileSync(i,"utf8");if(a.includes(`describe('${e}'`)||a.includes(`describe("${e}"`))return i}catch{continue}}}return null}function Ge(e,t,s){if(!R.existsSync(t))return null;let n=R.readdirSync(t);for(let o of n){let i=S.join(t,o);if(o==="node_modules"||o==="dist"||o==="build"||o===".git"||o===".angular")continue;let r;try{r=R.statSync(i)}catch{continue}if(r.isDirectory()){let a=Ge(e,i,s);if(a)return a}else if(o.match(/\.(ts|tsx|js|jsx|vue)$/)){let a=R.readFileSync(i,"utf8");if(a.includes(`class ${e}`)||a.includes(`function ${e}`)||a.includes(`const ${e}`)||a.includes(`let ${e}`)||a.includes(`exports.${e}`)||a.includes(`module.exports.${e}`)){let p=i,g=S.extname(i),d=i.slice(0,-g.length);if(!o.includes(".spec.")&&!o.includes(".test.")){let x=[`${d}.spec${g}`,`${d}.test${g}`,`${d}.spec.js`,`${d}.test.js`];for(let h of x)if(R.existsSync(h)){p=h;break}}if(!s.includes(S.resolve(p)))return p}}}return null}var pe=require("ai"),He=require("@ai-sdk/openai"),qe=require("@ai-sdk/anthropic"),Be=require("@ai-sdk/google"),Ye=b(require("dotenv"));Ye.config({quiet:!0});var Pe=15e3;function Ke(e,t){return e.length<=Pe?e:(console.warn(`[Lisa.ai LLM] ${t} is ${e.length} chars \u2014 truncating to ${Pe} to stay within context window.`),e.slice(0,Pe)+`
|
|
3
3
|
|
|
4
4
|
// ... (truncated)`)}function Ve(e,t){if(!/\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/.test(e))throw new Error(`LLM returned a non-code response for ${t} (possible context overflow). Skipping to prevent file corruption.`)}function We(e){if(!e||e.length===0)return"";let t={unit:"unit tests \u2014 test every function/method in complete isolation, mocking ALL external dependencies, services, and I/O",integration:"integration tests \u2014 test how modules work together using real service/repository layers; for HTTP routes use supertest or equivalent",e2e:"end-to-end tests \u2014 simulate complete user flows using the configured e2e framework (Playwright/Cypress); cover the full path from HTTP request to response or UI action to assertion"};return`5. Test scope \u2014 generate ALL of the following test types for this file:
|
|
5
5
|
${e.map(n=>` \u2022 ${t[n]??n}`).join(`
|
|
@@ -302,8 +302,8 @@ ${"\u2500".repeat(50)}`),console.log(" Lisa.ai Audit Complete"),console.log(`
|
|
|
302
302
|
\x1B[38;2;99;102;241m\u255A\u2550\u255D\x1B[0m \x1B[2mheal \xB7 unit \xB7 e2e \xB7 integration \xB7 audit\x1B[0m
|
|
303
303
|
`)}async function Ee(e){let t=5,s=e.model,n,o=P.load(process.cwd()),i=e.projectId||o?.projectId||"local";if(i!=="local"){let r=await ye(i);if(!r.ok)r.reason==="not_found"?(console.error(`
|
|
304
304
|
[Lisa.ai Agent Error] Project '${i}' does not exist on the Control Plane. Please create it in the Dashboard first or run locally without a project ID.`),process.exit(1)):console.warn(`
|
|
305
|
-
[Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${s}, maxRetries=${t}).`);else{let a=r.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${a.modelProvider}, MaxRetries=${a.maxRetries}`),a.maxRetries<5&&console.warn(`
|
|
306
|
-
[Lisa.ai Warning] maxRetries is ${
|
|
305
|
+
[Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${s}, maxRetries=${t}).`);else{let a=r.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${a.modelProvider}, MaxRetries=${a.maxRetries}`),s=a.modelProvider,t=a.maxRetries,n=a.apiKey,a.agentEnabled===!1&&(console.log("[Lisa.ai Agent] Agent is disabled by Control Plane for this project."),process.exit(1))}}return o&&(P.applyEnvDefaults(o),o.maxRetries!==void 0&&(t=o.maxRetries),o.provider&&e.model==="gemini"&&(s=o.provider),P.printSummary(o)),t<5&&console.warn(`
|
|
306
|
+
[Lisa.ai Warning] maxRetries is ${t}. Consider increasing to 5+ for complex projects.`),{model:s,maxRetries:t,apiKey:n,projectId:i}}var z=new kt.Command;z.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(St.version);z.command("heal").description("Run tests and autonomously heal all failures via LLM + Memory Engine").option("-c, --command <type>","Test command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-t, --type <scope>","Test type to heal: unit (default), e2e, integration","unit").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").option("--ci","CI mode: commit healed files, open PR, write GitHub Actions step summary").action(async e=>{ne();let t=["unit","e2e","integration"],s=e.type;t.includes(s)||(console.error(`
|
|
307
307
|
[Lisa.ai Error] Invalid heal type '${e.type}'. Valid types: ${t.join(", ")}`),process.exit(1));let n=e.files?e.files.split(",").map(r=>r.trim()):void 0,o=e.ci===!0,i=await Ee(e);await ce(e.command,i.model,1,i.maxRetries,i.projectId,void 0,i.apiKey,s,n,o)});z.command("unit").description("Generate missing unit test specs to reach 100% coverage (auto-detects framework)").option("-c, --command <type>","Test+coverage command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await Ee(e);await pt(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});z.command("e2e").description("Generate E2E tests via Playwright (auto-installs if none detected)").option("-c, --command <type>","E2E command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await Ee(e);await ft(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});z.command("integration").description("Generate integration tests for module seams (component+service, API+DB)").option("-c, --command <type>","Test command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await Ee(e);await ht(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});z.command("diagnose").description("Test LLM connectivity and API key health without running the full agent").option("-m, --model <provider>","LLM provider to test (gemini, claude, openai)","claude").option("-p, --project-id <id>","Control Plane Project ID to fetch API key from").action(async e=>{ne();let t=e.model,s,n=P.load(process.cwd()),o=e.projectId||n?.projectId||"local";if(o!=="local"){let a=await ye(o);a.ok?(t=a.config.modelProvider,s=a.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${t}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${a.reason}. Using local env for API key.`)}let r={claude:process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5",openai:process.env.LISA_OPENAI_MODEL||"gpt-4o-mini",gemini:process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash"}[t]||t;console.log(`
|
|
308
308
|
[Lisa.ai Diagnose] Testing ${t} \u2192 model ID: ${r}`);try{let a=await ie("Reply with exactly: LISA_OK",t,s);console.log(`
|
|
309
309
|
[Lisa.ai Diagnose] ${t} is working correctly.`),console.log(` Model response: "${a}"`)}catch(a){console.error(`
|