@lisa.ai/agent 2.7.2 → 2.8.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.
Files changed (2) hide show
  1. package/dist/index.js +149 -147
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var xt=Object.create;var Re=Object.defineProperty;var Lt=Object.getOwnPropertyDescriptor;var $t=Object.getOwnPropertyNames;var kt=Object.getPrototypeOf,St=Object.prototype.hasOwnProperty;var jt=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Ct=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of $t(e))!St.call(t,i)&&i!==n&&Re(t,i,{get:()=>e[i],enumerable:!(s=Lt(e,i))||s.enumerable});return t};var j=(t,e,n)=>(n=t!=null?xt(kt(t)):{},Ct(e||!t||!t.__esModule?Re(n,"default",{value:t,enumerable:!0}):n,t));var ft=jt((qs,_t)=>{_t.exports={name:"@lisa.ai/agent",version:"2.7.2",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 mt=require("commander"),$e=j(require("fs")),ht=j(require("path")),yt=j(require("readline"));var Me=j(require("dotenv"));Me.config({quiet:!0});async function pe(t){let e=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let n=`${e}/api/config/${t}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${n}...`);let s=await fetch(n);if(!s.ok){let o=s.status===404?"not_found":"unreachable";return console.warn(o==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${t}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${s.status}. Falling back to local defaults.`),{ok:!1,reason:o}}return{ok:!0,config:await s.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${e}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var et=require("child_process"),U=j(require("fs")),W=j(require("path"));var A=j(require("path")),R=j(require("fs"));function ge(t){return t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function K(t){let e=ge(t),n=[...e.matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length>0){let c=[...n].reverse().find(f=>f[3]!==void 0)??n[n.length-1],u=parseInt(c[2]),g=c[3]?parseInt(c[3]):0,l=parseInt(c[1])-g;return{total:u,passed:l,failed:g}}let s=e.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+passed,?\s*)?(\d+)\s+total/);if(s){let c=parseInt(s[3]),u=s[1]?parseInt(s[1]):0,g=s[2]?parseInt(s[2]):0;return{total:c,passed:g,failed:u}}let i=e.match(/(\d+)\s+failed/),o=e.match(/(\d+)\s+passed/);if(o||i){let c=i?parseInt(i[1]):0,u=o?parseInt(o[1]):0,g=e.match(/(\d+)\s+skipped/),l=g?parseInt(g[1]):0;return{total:u+c+l,passed:u,failed:c}}let r=e.match(/Tests\s+(?:(\d+)\s+failed\s*\|?\s*)?(\d+)\s+passed\s*\((\d+)\)/);if(r){let c=parseInt(r[3]),u=r[1]?parseInt(r[1]):0,g=parseInt(r[2]);return{total:c,passed:g,failed:u}}let a=e.match(/(\d+)\s+passing/),d=e.match(/(\d+)\s+failing/);if(a){let c=parseInt(a[1]),u=d?parseInt(d[1]):0;return{total:c+u,passed:c,failed:u}}return null}function Se(t,e=process.cwd(),n=[]){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),i=n.map(g=>A.resolve(e,g)),o=new Map,r=new Set,a=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,d;for(;(d=a.exec(s))!==null;){let l=d[1].trim().split(" ");for(let f=1;f<Math.min(l.length,6);f++){let h=l.slice(0,f).join(" ");if(r.has(h))continue;r.add(h);let m=je(h,e,i);if(m){let y=A.resolve(m);o.has(y)||o.set(y,A.relative(e,m));break}}}let c=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,u;for(;(u=c.exec(s))!==null;){let g=u[1],l=A.isAbsolute(g)?g:A.resolve(e,g);!i.includes(l)&&R.existsSync(l)&&!o.has(l)&&o.set(l,A.relative(e,l))}return[...o.values()]}function fe(t,e=[],n=process.cwd()){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),i=e.map(m=>A.resolve(m));{let m=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,y=new Set,v;for(;(v=m.exec(s))!==null;){let p=v[1].trim().split(" ");for(let k=1;k<Math.min(p.length,5);k++){let w=p.slice(0,k).join(" ");if(y.has(w))continue;y.add(w);let L=je(w,n,i);if(L)return A.relative(n,L)}}}let o=/([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=o.exec(s))!==null;){let m=r[1];if(m){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(m))continue;let y=A.isAbsolute(m)?m:A.resolve(n,m);if(!i.includes(y)&&R.existsSync(y))return m}}let a=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,d;for(;(d=a.exec(s))!==null;){let m=d[1],y=A.isAbsolute(m)?m:A.resolve(n,m);if(!i.includes(y)&&R.existsSync(y))return m}let c=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,u;for(;(u=c.exec(s))!==null;){let m=u[1];if(m){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(m))continue;let y=A.isAbsolute(m)?m:A.resolve(n,m);if(!i.includes(y)&&R.existsSync(y))return m}}let g=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,l,f=new Set,h=["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(;(l=g.exec(s))!==null;){let m=l[1];if(!m||h.includes(m)||f.has(m)||/^[A-Z][A-Z0-9]{5,11}$/.test(m)||/^[A-Za-z0-9]{16,}$/.test(m))continue;f.add(m);let y=De(m,n,i);if(y)return A.relative(n,y)}return null}function je(t,e,n){if(!R.existsSync(e))return null;let s=R.readdirSync(e);for(let i of s){let o=A.join(e,i);if(["node_modules","dist","build",".git",".angular"].includes(i))continue;let r;try{r=R.statSync(o)}catch{continue}if(r.isDirectory()){let a=je(t,o,n);if(a)return a}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(i)){if(n.includes(A.resolve(o)))continue;try{let a=R.readFileSync(o,"utf8");if(a.includes(`describe('${t}'`)||a.includes(`describe("${t}"`))return o}catch{continue}}}return null}function De(t,e,n){if(!R.existsSync(e))return null;let s=R.readdirSync(e);for(let i of s){let o=A.join(e,i);if(i==="node_modules"||i==="dist"||i==="build"||i===".git"||i===".angular")continue;let r;try{r=R.statSync(o)}catch{continue}if(r.isDirectory()){let a=De(t,o,n);if(a)return a}else if(i.match(/\.(ts|tsx|js|jsx|vue)$/)){let a=R.readFileSync(o,"utf8");if(a.includes(`class ${t}`)||a.includes(`function ${t}`)||a.includes(`const ${t}`)||a.includes(`let ${t}`)||a.includes(`exports.${t}`)||a.includes(`module.exports.${t}`)){let d=o,c=A.extname(o),u=o.slice(0,-c.length);if(!i.includes(".spec.")&&!i.includes(".test.")){let g=[`${u}.spec${c}`,`${u}.test${c}`,`${u}.spec.js`,`${u}.test.js`];for(let l of g)if(R.existsSync(l)){d=l;break}}if(!n.includes(A.resolve(d)))return d}}}return null}var ae=require("ai"),Ne=require("@ai-sdk/openai"),Oe=require("@ai-sdk/anthropic"),Ue=require("@ai-sdk/google"),_e=j(require("dotenv"));_e.config({quiet:!0});var Ce=15e3;function Ge(t,e){return t.length<=Ce?t:(console.warn(`[Lisa.ai LLM] ${e} is ${t.length} chars \u2014 truncating to ${Ce} to stay within context window.`),t.slice(0,Ce)+`
2
+ "use strict";var jt=Object.create;var Oe=Object.defineProperty;var Ct=Object.getOwnPropertyDescriptor;var bt=Object.getOwnPropertyNames;var Et=Object.getPrototypeOf,At=Object.prototype.hasOwnProperty;var Ft=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Pt=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of bt(e))!At.call(t,i)&&i!==n&&Oe(t,i,{get:()=>e[i],enumerable:!(s=Ct(e,i))||s.enumerable});return t};var j=(t,e,n)=>(n=t!=null?jt(Et(t)):{},Pt(e||!t||!t.__esModule?Oe(n,"default",{value:t,enumerable:!0}):n,t));var vt=Ft((Zs,Bt)=>{Bt.exports={name:"@lisa.ai/agent",version:"2.8.0",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 xt=require("commander"),je=j(require("fs")),Lt=j(require("path")),$t=j(require("readline"));var Ue=j(require("dotenv"));Ue.config({quiet:!0});async function ge(t){let e=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let n=`${e}/api/config/${t}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${n}...`);let s=await fetch(n);if(!s.ok){let o=s.status===404?"not_found":"unreachable";return console.warn(o==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${t}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${s.status}. Falling back to local defaults.`),{ok:!1,reason:o}}return{ok:!0,config:await s.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${e}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var ot=require("child_process"),G=j(require("fs")),Y=j(require("path"));var S=j(require("path")),P=j(require("fs"));function fe(t){return t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function V(t){let e=fe(t),n=[...e.matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length>0){let d=[...n].reverse().find(m=>m[3]!==void 0)??n[n.length-1],g=parseInt(d[2]),y=d[3]?parseInt(d[3]):0,c=parseInt(d[1])-y;return{total:g,passed:c,failed:y}}let s=e.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+passed,?\s*)?(\d+)\s+total/);if(s){let d=parseInt(s[3]),g=s[1]?parseInt(s[1]):0,y=s[2]?parseInt(s[2]):0;return{total:d,passed:y,failed:g}}let i=e.match(/(\d+)\s+failed/),o=e.match(/(\d+)\s+passed/);if(o||i){let d=i?parseInt(i[1]):0,g=o?parseInt(o[1]):0,y=e.match(/(\d+)\s+skipped/),c=y?parseInt(y[1]):0;return{total:g+d+c,passed:g,failed:d}}let r=e.match(/Tests\s+(?:(\d+)\s+failed\s*\|?\s*)?(\d+)\s+passed\s*\((\d+)\)/);if(r){let d=parseInt(r[3]),g=r[1]?parseInt(r[1]):0,y=parseInt(r[2]);return{total:d,passed:y,failed:g}}let a=e.match(/(\d+)\s+passing/),p=e.match(/(\d+)\s+failing/);if(a){let d=parseInt(a[1]),g=p?parseInt(p[1]):0;return{total:d+g,passed:d,failed:g}}return null}function be(t,e=process.cwd(),n=[]){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),i=n.map(f=>S.resolve(e,f)),o=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(s))!==null;){let u=p[1].trim().split(" ");for(let k=1;k<Math.min(u.length,6);k++){let $=u.slice(0,k).join(" ");if(r.has($))continue;r.add($);let l=Ee($,e,i);if(l){let v=S.resolve(l);o.has(v)||o.set(v,S.relative(e,l));break}}}let d=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,g;for(;(g=d.exec(s))!==null;){let f=g[1],u=S.isAbsolute(f)?f:S.resolve(e,f);!i.includes(u)&&P.existsSync(u)&&!o.has(u)&&o.set(u,S.relative(e,u))}let y=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,c;for(;(c=y.exec(s))!==null;){let f=c[1],u=S.isAbsolute(f)?f:S.resolve(e,f);!i.includes(u)&&P.existsSync(u)&&!o.has(u)&&o.set(u,S.relative(e,u))}let m=/Running:\s+([^\s]+\.(?:cy|spec|test)\.[tj]sx?)/g,h;for(;(h=m.exec(s))!==null;){let f=h[1],u=S.isAbsolute(f)?f:S.resolve(e,f);if(!i.includes(u)&&P.existsSync(u)&&!o.has(u)){let k=f.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");new RegExp(k+"\\s+\\d+\\s+\\d+\\s+([1-9]\\d*)").test(s)&&o.set(u,S.relative(e,u))}}return[...o.values()]}function me(t,e=[],n=process.cwd()){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),i=e.map(f=>S.resolve(f));{let f=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,u=new Set,k;for(;(k=f.exec(s))!==null;){let l=k[1].trim().split(" ");for(let v=1;v<Math.min(l.length,5);v++){let w=l.slice(0,v).join(" ");if(u.has(w))continue;u.add(w);let L=Ee(w,n,i);if(L)return S.relative(n,L)}}}let o=/([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=o.exec(s))!==null;){let f=r[1];if(f){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(f))continue;let u=S.isAbsolute(f)?f:S.resolve(n,f);if(!i.includes(u)&&P.existsSync(u))return f}}let a=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,p;for(;(p=a.exec(s))!==null;){let f=p[1],u=S.isAbsolute(f)?f:S.resolve(n,f);if(!i.includes(u)&&P.existsSync(u))return f}{let f=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,u;for(;(u=f.exec(s))!==null;){let k=u[1],$=S.isAbsolute(k)?k:S.resolve(n,k);if(!i.includes($)&&P.existsSync($))return k}}let d=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,g;for(;(g=d.exec(s))!==null;){let f=g[1];if(f){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(f))continue;let u=S.isAbsolute(f)?f:S.resolve(n,f);if(!i.includes(u)&&P.existsSync(u))return f}}let y=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,c,m=new Set,h=["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(;(c=y.exec(s))!==null;){let f=c[1];if(!f||h.includes(f)||m.has(f)||/^[A-Z][A-Z0-9]{5,11}$/.test(f)||/^[A-Za-z0-9]{16,}$/.test(f))continue;m.add(f);let u=_e(f,n,i);if(u)return S.relative(n,u)}return null}function Ee(t,e,n){if(!P.existsSync(e))return null;let s=P.readdirSync(e);for(let i of s){let o=S.join(e,i);if(["node_modules","dist","build",".git",".angular"].includes(i))continue;let r;try{r=P.statSync(o)}catch{continue}if(r.isDirectory()){let a=Ee(t,o,n);if(a)return a}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(i)){if(n.includes(S.resolve(o)))continue;try{let a=P.readFileSync(o,"utf8");if(a.includes(`describe('${t}'`)||a.includes(`describe("${t}"`))return o}catch{continue}}}return null}function _e(t,e,n){if(!P.existsSync(e))return null;let s=P.readdirSync(e);for(let i of s){let o=S.join(e,i);if(i==="node_modules"||i==="dist"||i==="build"||i===".git"||i===".angular")continue;let r;try{r=P.statSync(o)}catch{continue}if(r.isDirectory()){let a=_e(t,o,n);if(a)return a}else if(i.match(/\.(ts|tsx|js|jsx|vue)$/)){let a=P.readFileSync(o,"utf8");if(a.includes(`class ${t}`)||a.includes(`function ${t}`)||a.includes(`const ${t}`)||a.includes(`let ${t}`)||a.includes(`exports.${t}`)||a.includes(`module.exports.${t}`)){let p=o,d=S.extname(o),g=o.slice(0,-d.length);if(!i.includes(".spec.")&&!i.includes(".test.")){let y=[`${g}.spec${d}`,`${g}.test${d}`,`${g}.spec.js`,`${g}.test.js`];for(let c of y)if(P.existsSync(c)){p=c;break}}if(!n.includes(S.resolve(p)))return p}}}return null}var ce=require("ai"),Ge=require("@ai-sdk/openai"),He=require("@ai-sdk/anthropic"),Be=require("@ai-sdk/google"),qe=j(require("dotenv"));qe.config({quiet:!0});var Ae=15e3;function We(t,e){return t.length<=Ae?t:(console.warn(`[Lisa.ai LLM] ${e} is ${t.length} chars \u2014 truncating to ${Ae} to stay within context window.`),t.slice(0,Ae)+`
3
3
 
4
- // ... (truncated)`)}function He(t,e){if(!/\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/.test(t))throw new Error(`LLM returned a non-code response for ${e} (possible context overflow). Skipping to prevent file corruption.`)}function Be(t){if(!t||t.length===0)return"";let e={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:
4
+ // ... (truncated)`)}function Ye(t,e){if(!/\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/.test(t))throw new Error(`LLM returned a non-code response for ${e} (possible context overflow). Skipping to prevent file corruption.`)}function Ke(t){if(!t||t.length===0)return"";let e={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
  ${t.map(s=>` \u2022 ${e[s]??s}`).join(`
6
6
  `)}
7
- `}function me(t,e){if(t==="claude"){let i=e||process.env.ANTHROPIC_API_KEY;if(!i)throw new Error("No Anthropic API key provided by local ENV or Control Plane");let o=process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5";return(0,Oe.createAnthropic)({apiKey:i})(o)}if(t==="openai"){let i=e||process.env.OPENAI_API_KEY;if(!i)throw new Error("No OpenAI API key provided by local ENV or Control Plane");let o=process.env.LISA_OPENAI_MODEL||"gpt-4o-mini";return(0,Ne.createOpenAI)({apiKey:i})(o)}let n=e||process.env.GOOGLE_GENERATIVE_AI_API_KEY;if(!n)throw new Error("No Google API key provided by local ENV or Control Plane");let s=process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash";return(0,Ue.createGoogleGenerativeAI)({apiKey:n})(s)}async function qe(t,e,n,s,i,o,r,a){console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${s} for ${t}...`);let d=me(s,i),c=`You are Lisa.ai, an autonomous CI/CD expert platform.
7
+ `}function he(t,e){if(t==="claude"){let i=e||process.env.ANTHROPIC_API_KEY;if(!i)throw new Error("No Anthropic API key provided by local ENV or Control Plane");let o=process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5";return(0,He.createAnthropic)({apiKey:i})(o)}if(t==="openai"){let i=e||process.env.OPENAI_API_KEY;if(!i)throw new Error("No OpenAI API key provided by local ENV or Control Plane");let o=process.env.LISA_OPENAI_MODEL||"gpt-4o-mini";return(0,Ge.createOpenAI)({apiKey:i})(o)}let n=e||process.env.GOOGLE_GENERATIVE_AI_API_KEY;if(!n)throw new Error("No Google API key provided by local ENV or Control Plane");let s=process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash";return(0,Be.createGoogleGenerativeAI)({apiKey:n})(s)}async function Ve(t,e,n,s,i,o,r,a){console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${s} for ${t}...`);let p=he(s,i),d=`You are Lisa.ai, an autonomous CI/CD expert platform.
8
8
  A build/compilation error occurred. Your task is to fix the provided file so that the error resolves.
9
9
 
10
10
  --- Error Log ---
@@ -21,58 +21,58 @@ A build/compilation error occurred. Your task is to fix the provided file so tha
21
21
  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.
22
22
  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'.
23
23
  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'.
24
- 8. Return the code wrapped in a markdown code block (\`\`\`typescript ... \`\`\`). Do not include any explanation or intro text.`;if(r){if(/standalone\s*:\s*true/.test(r)){let f=r.match(/export class (\w+)/),h=f?f[1]:"the component";c+=`
24
+ 8. Return the code wrapped in a markdown code block (\`\`\`typescript ... \`\`\`). Do not include any explanation or intro text.`;if(r){if(/standalone\s*:\s*true/.test(r)){let m=r.match(/export class (\w+)/),h=m?m[1]:"the component";d+=`
25
25
 
26
26
  --- CRITICAL ARCHITECTURAL REQUIREMENT ---
27
27
  The component `+h+` is marked as STANDALONE (standalone: true).
28
28
  You MUST add `+h+` to the 'imports' array within 'TestBed.configureTestingModule'.
29
- DO NOT add it to the 'declarations' array. If you omit `+h+" from 'imports', the test will fail."}c+=`
29
+ DO NOT add it to the 'declarations' array. If you omit `+h+" from 'imports', the test will fail."}d+=`
30
30
 
31
31
  --- Sibling Component / Service Context ---
32
32
  You are fixing a '.spec' test file. Here is the actual implementation code for the component you are testing.
33
33
  Use this to identify EXACTLY which imports, Services, and Variables need to be mocked inside your 'TestBed'.
34
- `+r}a&&a.length>0&&(c+=`
34
+ `+r}a&&a.length>0&&(d+=`
35
35
 
36
36
  --- MEMORY ENGINE: PROVEN FIX PATTERNS ---
37
37
  The following fix patterns were SUCCESSFULLY used to resolve identical errors in past runs. Prioritise these approaches before trying anything novel:
38
- `+a.map((l,f)=>`
39
- [Pattern ${f+1}]
40
- ${l}`).join(`
41
- `)),o&&(console.log(`[Lisa.ai Auto-Heal] Warning! Agent is looping on ${t}. Injecting previous failed context...`),c+=`
38
+ `+a.map((c,m)=>`
39
+ [Pattern ${m+1}]
40
+ ${c}`).join(`
41
+ `)),o&&(console.log(`[Lisa.ai Auto-Heal] Warning! Agent is looping on ${t}. Injecting previous failed context...`),d+=`
42
42
 
43
43
  --- CRITICAL WARNING ---
44
44
  You previously attempted to fix this file but the compiler REJECTED your fix!
45
45
  Here is the previous analysis and failed fix you attempted:
46
46
  `+o+`
47
47
 
48
- DO NOT repeat the identical code changes. Try a completely different programming approach, fix syntax typos, or check for missing imports.`);let{text:u}=await(0,ae.generateText)({model:d,prompt:c}),g=u.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return g?g[1].trim():u.trim()}async function Q(t,e,n,s,i,o){console.log(`[Lisa.ai Coverage] Requesting test generation from ${n} for ${t}...`);let r=me(n,s),a=i?`3. You MUST use the '${i}' testing framework exclusively. All imports, describe/it/test blocks, and mock utilities must follow '${i}' conventions.
48
+ DO NOT repeat the identical code changes. Try a completely different programming approach, fix syntax typos, or check for missing imports.`);let{text:g}=await(0,ce.generateText)({model:p,prompt:d}),y=g.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return y?y[1].trim():g.trim()}async function X(t,e,n,s,i,o){console.log(`[Lisa.ai Coverage] Requesting test generation from ${n} for ${t}...`);let r=he(n,s),a=i?`3. You MUST use the '${i}' testing framework exclusively. All imports, describe/it/test blocks, and mock utilities must follow '${i}' conventions.
49
49
  `:`3. Include all necessary imports assuming a standard testing framework (Jest/Karma/Vitest) is available.
50
- `,d=Be(o),c=`You are Lisa.ai, an autonomous CI/CD expert platform.
50
+ `,p=Ke(o),d=`You are Lisa.ai, an autonomous CI/CD expert platform.
51
51
  A source file lacks 100% test coverage. Your task is to generate a comprehensive testing suite covering all branches, lines, and functions.
52
52
 
53
53
  --- Target File Content (`+t+`) ---
54
- `+Ge(e,t)+"\n\n--- Constraints ---\n1. Return the generated test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+a+`4. Aim for 100% logic coverage.
55
- `+d,{text:u}=await(0,ae.generateText)({model:r,prompt:c}),g=u.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),l=g?g[1].trim():u.trim();return He(l,t),l}async function We(t,e,n,s,i,o,r,a){console.log(`[Lisa.ai Coverage] Requesting test update from ${i} for ${t}...`);let d=me(i,o),c=r?`3. You MUST use the '${r}' testing framework exclusively. All new tests must follow '${r}' conventions and integrate cleanly with the existing suite.
54
+ `+We(e,t)+"\n\n--- Constraints ---\n1. Return the generated test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+a+`4. Aim for 100% logic coverage.
55
+ `+p,{text:g}=await(0,ce.generateText)({model:r,prompt:d}),y=g.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),c=y?y[1].trim():g.trim();return Ye(c,t),c}async function ze(t,e,n,s,i,o,r,a){console.log(`[Lisa.ai Coverage] Requesting test update from ${i} for ${t}...`);let p=he(i,o),d=r?`3. You MUST use the '${r}' testing framework exclusively. All new tests must follow '${r}' conventions and integrate cleanly with the existing suite.
56
56
  `:`3. Append missing tests to the existing suite. Do not delete existing passing tests unless they are fundamentally broken.
57
- `,u=Be(a),g=`You are Lisa.ai, an autonomous CI/CD expert platform.
57
+ `,g=Ke(a),y=`You are Lisa.ai, an autonomous CI/CD expert platform.
58
58
  A source file lacks 100% test coverage. You must update its existing test suite to achieve full coverage.
59
59
 
60
60
  --- Target File Content (`+t+`) ---
61
- `+Ge(e,t)+`
61
+ `+We(e,t)+`
62
62
 
63
63
  --- Existing Test Suite (`+n+`) ---
64
- `+s+"\n\n--- Constraints ---\n1. Return the updated complete test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+c+`4. Aim for 100% logic coverage across branches, lines, and functions.
65
- `+u,{text:l}=await(0,ae.generateText)({model:d,prompt:g}),f=l.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),h=f?f[1].trim():l.trim();return He(h,t),h}async function X(t,e,n){let s=me(e,n),{text:i}=await(0,ae.generateText)({model:s,prompt:t}),o=i.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return o?o[1].trim():i.trim()}var Ye=j(require("simple-git")),Ke=require("@octokit/rest"),Yt=require("dotenv/config");async function be(t){console.log(`
66
- [Lisa.ai PR Engine] Initializing Pull Request for ${t}...`);let e=(0,Ye.default)(),s=`lisa-fix/build-error-${new Date().getTime()}`,i=`fix: automated auto-heal by Lisa.ai for ${t}`,o="main";try{o=(await e.revparse(["--abbrev-ref","HEAD"])).trim()}catch{}try{await e.addConfig("user.name","Lisa.ai"),await e.addConfig("user.email","lisa@lisa.ai"),await e.checkoutLocalBranch(s),await e.add(t),await e.commit(i),console.log(`[Lisa.ai PR Engine] Committed changes to branch ${s}`),console.log("[Lisa.ai PR Engine] Pushing branch to remote origin..."),await e.push("origin",s,{"--set-upstream":null});let r=new Ke.Octokit({auth:process.env.GITHUB_TOKEN}),a=process.env.GITHUB_REPOSITORY;if(a&&process.env.GITHUB_TOKEN){let[d,c]=a.split("/");console.log(`[Lisa.ai PR Engine] Opening Pull Request against ${d}/${c}...`);let u=await r.rest.pulls.create({owner:d,repo:c,title:i,body:`### Lisa.ai Auto-Healed Pull Request
64
+ `+s+"\n\n--- Constraints ---\n1. Return the updated complete test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+d+`4. Aim for 100% logic coverage across branches, lines, and functions.
65
+ `+g,{text:c}=await(0,ce.generateText)({model:p,prompt:y}),m=c.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),h=m?m[1].trim():c.trim();return Ye(h,t),h}async function ee(t,e,n){let s=he(e,n),{text:i}=await(0,ce.generateText)({model:s,prompt:t}),o=i.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return o?o[1].trim():i.trim()}var Ze=j(require("simple-git")),Je=require("@octokit/rest"),zt=require("dotenv/config");async function Fe(t){console.log(`
66
+ [Lisa.ai PR Engine] Initializing Pull Request for ${t}...`);let e=(0,Ze.default)(),s=`lisa-fix/build-error-${new Date().getTime()}`,i=`fix: automated auto-heal by Lisa.ai for ${t}`,o="main";try{o=(await e.revparse(["--abbrev-ref","HEAD"])).trim()}catch{}try{await e.addConfig("user.name","Lisa.ai"),await e.addConfig("user.email","lisa@lisa.ai"),await e.checkoutLocalBranch(s),await e.add(t),await e.commit(i),console.log(`[Lisa.ai PR Engine] Committed changes to branch ${s}`),console.log("[Lisa.ai PR Engine] Pushing branch to remote origin..."),await e.push("origin",s,{"--set-upstream":null});let r=new Je.Octokit({auth:process.env.GITHUB_TOKEN}),a=process.env.GITHUB_REPOSITORY;if(a&&process.env.GITHUB_TOKEN){let[p,d]=a.split("/");console.log(`[Lisa.ai PR Engine] Opening Pull Request against ${p}/${d}...`);let g=await r.rest.pulls.create({owner:p,repo:d,title:i,body:`### Lisa.ai Auto-Healed Pull Request
67
67
  This PR was automatically generated by Lisa.ai to resolve a failing compilation/build step.
68
68
 
69
69
  **Healed File:** \`${t}\`
70
70
 
71
- Please review the changes.`,head:s,base:o});console.log(`\u2705 [Lisa.ai PR Engine] Pull Request created successfully: ${u.data.html_url}`)}else console.log("\u26A0\uFE0F [Lisa.ai PR Engine] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping GitHub Pull Request creation.")}catch(r){console.error(`
72
- \u{1F6A8} [Lisa.ai PR Engine Error] Failed to create Pull Request:`,r.message)}finally{try{await e.checkout(o)}catch{}}}var Ve=j(require("dotenv"));Ve.config({quiet:!0});async function T(t){let n=`${process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000"}/api/telemetry`;fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).catch(s=>{console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${s.message}`)})}var H=j(require("fs")),N=j(require("path"));var he=j(require("fs")),ze=j(require("path")),Z=".lisai.json",P=class{static _config=null;static _loaded=!1;static load(e=process.cwd()){if(this._loaded)return this._config;this._loaded=!0;let n=ze.resolve(e,Z);if(!he.existsSync(n))return null;try{let s=he.readFileSync(n,"utf-8");return this._config=JSON.parse(s),console.log(`[Lisa.ai Config] Loaded project config from ${Z}`),this._config}catch(s){return console.warn(`[Lisa.ai Config] Warning: ${Z} found but failed to parse \u2014 ${s.message}. Using defaults.`),null}}static get(){return this._config}static applyEnvDefaults(e){if(!e.model)return;let n={claude:"LISA_CLAUDE_MODEL",openai:"LISA_OPENAI_MODEL",gemini:"LISA_GOOGLE_MODEL"},s=e.provider;s&&n[s]&&!process.env[n[s]]&&(process.env[n[s]]=e.model,console.log(`[Lisa.ai Config] Model override applied: ${s} \u2192 ${e.model}`))}static printSummary(e){let n=[];e.provider&&n.push(`provider=${e.provider}`),e.model&&n.push(`model=${e.model}`),e.testingFramework&&n.push(`testingFramework=${e.testingFramework}`),e.testTypes?.length&&n.push(`testTypes=[${e.testTypes.join(",")}]`),e.maxRetries!==void 0&&n.push(`maxRetries=${e.maxRetries}`),e.testCommand&&n.push(`testCommand="${e.testCommand}"`),e.e2eFramework&&n.push(`e2eFramework=${e.e2eFramework}`),e.e2eCommand&&n.push(`e2eCommand="${e.e2eCommand}"`),n.length&&console.log(`[Lisa.ai Config] Settings: ${n.join(", ")}`),e.skipFiles?.length&&console.log(`[Lisa.ai Config] Extra skip files : ${e.skipFiles.join(", ")}`),e.skipDirs?.length&&console.log(`[Lisa.ai Config] Extra skip dirs : ${e.skipDirs.join(", ")}`),e.skipPaths?.length&&console.log(`[Lisa.ai Config] Extra skip paths : ${e.skipPaths.join(", ")}`)}};var q=class{static scanRepository(e=process.cwd()){let n=N.resolve(e,"package.json"),s={type:"unknown",testingFramework:"none"};if(!H.existsSync(n))return console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${n}. Defaulting to Generic Node.`),s.type="node",s;let i=JSON.parse(H.readFileSync(n,"utf8")),o={...i.dependencies||{},...i.devDependencies||{}},r=i.scripts||{};return o["@angular/core"]?s.type="angular":o.react?s.type="react":o.vue?s.type="vue":s.type="node",o.jest||r.test?.includes("jest")?s.testingFramework="jest":o.karma||r.test?.includes("karma")||r.test?.includes("ng test")?s.testingFramework="karma":(o.vitest||r.test?.includes("vitest"))&&(s.testingFramework="vitest"),s.testingFramework!=="none"&&(s.testingFramework==="karma"?s.type==="angular"?s.suggestedTestCommand="npx ng test --no-watch --browsers=ChromeHeadless":s.suggestedTestCommand="npx karma start --single-run --browsers=ChromeHeadless":r.test?s.suggestedTestCommand="npm run test":s.testingFramework==="jest"?s.suggestedTestCommand="npx jest --coverage":s.testingFramework==="vitest"&&(s.suggestedTestCommand="npx vitest run --coverage")),s}static findUntestedFiles(e,n=[]){let s=[];if(!H.existsSync(e))return s;let i=H.readdirSync(e),o=P.get(),r=o?.skipDirs??[],a=o?.skipFiles??[],d=o?.skipPaths??[],c=["node_modules","dist","build",".git",".angular","coverage","public","assets",...r],u=["main.ts","index.ts","index.js","index.jsx","app.config.ts","app.routes.ts","styles.css","styles.scss","tailwind.config.js","tailwind.config.ts","eslint.config.js","eslint.config.ts","jest.config.js","jest.config.ts","jest.config.mjs","jest.setup.js","jest.setup.ts","webpack.config.js","webpack.config.ts","babel.config.js","babel.config.ts","rollup.config.js","rollup.config.ts","vite.config.js","vite.config.ts","vitest.config.js","vitest.config.ts","karma.conf.js","karma.config.js","prettier.config.js","prettier.config.ts","postcss.config.js","postcss.config.ts","gulpfile.js","Gulpfile.js",".eslintrc.js",".eslintrc.ts",".babelrc.js"],g=[/^\./,/\.config\.(js|ts|mjs|cjs)$/,/\.conf\.(js|ts|mjs|cjs)$/];for(let l of i){let f=N.join(e,l);if(c.includes(l))continue;let h;try{h=H.statSync(f)}catch{continue}if(h.isDirectory())s.push(...this.findUntestedFiles(f,n));else if(l.match(/\.(ts|tsx|js|jsx|vue)$/)&&!l.includes(".spec.")&&!l.includes(".test.")){if(u.includes(l)||a.includes(l)||g.some(p=>p.test(l)))continue;let m=N.extname(l),y=l.slice(0,-m.length);if(![N.join(e,`${y}.spec${m}`),N.join(e,`${y}.test${m}`),N.join(e,`${y}.spec.js`),N.join(e,`${y}.test.js`),N.join(e,`${y}.spec.ts`),N.join(e,`${y}.test.ts`)].some(p=>H.existsSync(p))){let p=N.relative(process.cwd(),f);if(d.some(k=>p.startsWith(k)))continue;n.includes(p)||s.push(p)}}}return s}};var Ze=require("child_process"),ee=class{static async installMissingFramework(e,n=process.cwd()){if(e.testingFramework!=="none")return e;console.log(`
73
- [Lisa.ai Auto-Installer] \u{1F6A8} No testing framework detected for ${e.type} architecture.`),console.log("[Lisa.ai Auto-Installer] \u{1FA84} Initiating Zero-Config Installation Protocol...");let s="",i="none";switch(e.type){case"angular":console.log("[Lisa.ai Auto-Installer] Provisioning Angular TestBed environment..."),s="npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine jasmine-core @types/jasmine",i="karma",e.suggestedTestCommand="npm run test";break;case"react":case"node":default:console.log("[Lisa.ai Auto-Installer] Provisioning Universal Jest environment..."),s="npm install --save-dev jest @types/jest ts-jest",i="jest",e.suggestedTestCommand="npx jest --coverage";break;case"vue":console.log("[Lisa.ai Auto-Installer] Provisioning Vue Vitest environment..."),s="npm install --save-dev vitest @vue/test-utils jsdom",i="vitest",e.suggestedTestCommand="npx vitest run --coverage";break}if(s){console.log(`[Lisa.ai Executing] ${s}`);let o=s.split(" "),r=process.platform==="win32"?`${o[0]}.cmd`:o[0];return(0,Ze.spawnSync)(r,o.slice(1),{cwd:n,stdio:"inherit"}).status!==0&&(console.error(`
74
- \u274C [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`),process.exit(1)),console.log("\u2705 [Lisa.ai Auto-Installer] Framework successfully injected."),e.testingFramework=i,e}return e}};var ye=j(require("fs")),Ae=j(require("path"));var te=class{static async provisionConfigurationFiles(e,n,s,i=process.cwd()){if(e.testingFramework==="none")return;if(console.log(`
75
- [Lisa.ai Auto-Generator] \u{1FA84} Analyzing ${e.type} architecture to generate ${e.testingFramework} configuration specs...`),["jest.config.js","jest.config.ts","karma.conf.js","vitest.config.ts","vitest.config.js"].some(d=>ye.existsSync(Ae.join(i,d)))){console.log("[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.");return}let a=`You are an expert ${e.type} architect.
71
+ Please review the changes.`,head:s,base:o});console.log(`\u2705 [Lisa.ai PR Engine] Pull Request created successfully: ${g.data.html_url}`)}else console.log("\u26A0\uFE0F [Lisa.ai PR Engine] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping GitHub Pull Request creation.")}catch(r){console.error(`
72
+ \u{1F6A8} [Lisa.ai PR Engine Error] Failed to create Pull Request:`,r.message)}finally{try{await e.checkout(o)}catch{}}}var Qe=j(require("dotenv"));Qe.config({quiet:!0});async function I(t){let n=`${process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000"}/api/telemetry`;fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).catch(s=>{console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${s.message}`)})}var B=j(require("fs")),O=j(require("path"));var ye=j(require("fs")),Xe=j(require("path")),J=".lisai.json",T=class{static _config=null;static _loaded=!1;static load(e=process.cwd()){if(this._loaded)return this._config;this._loaded=!0;let n=Xe.resolve(e,J);if(!ye.existsSync(n))return null;try{let s=ye.readFileSync(n,"utf-8");return this._config=JSON.parse(s),console.log(`[Lisa.ai Config] Loaded project config from ${J}`),this._config}catch(s){return console.warn(`[Lisa.ai Config] Warning: ${J} found but failed to parse \u2014 ${s.message}. Using defaults.`),null}}static get(){return this._config}static applyEnvDefaults(e){if(!e.model)return;let n={claude:"LISA_CLAUDE_MODEL",openai:"LISA_OPENAI_MODEL",gemini:"LISA_GOOGLE_MODEL"},s=e.provider;s&&n[s]&&!process.env[n[s]]&&(process.env[n[s]]=e.model,console.log(`[Lisa.ai Config] Model override applied: ${s} \u2192 ${e.model}`))}static printSummary(e){let n=[];e.provider&&n.push(`provider=${e.provider}`),e.model&&n.push(`model=${e.model}`),e.testingFramework&&n.push(`testingFramework=${e.testingFramework}`),e.testTypes?.length&&n.push(`testTypes=[${e.testTypes.join(",")}]`),e.maxRetries!==void 0&&n.push(`maxRetries=${e.maxRetries}`),e.testCommand&&n.push(`testCommand="${e.testCommand}"`),e.e2eFramework&&n.push(`e2eFramework=${e.e2eFramework}`),e.e2eCommand&&n.push(`e2eCommand="${e.e2eCommand}"`),n.length&&console.log(`[Lisa.ai Config] Settings: ${n.join(", ")}`),e.skipFiles?.length&&console.log(`[Lisa.ai Config] Extra skip files : ${e.skipFiles.join(", ")}`),e.skipDirs?.length&&console.log(`[Lisa.ai Config] Extra skip dirs : ${e.skipDirs.join(", ")}`),e.skipPaths?.length&&console.log(`[Lisa.ai Config] Extra skip paths : ${e.skipPaths.join(", ")}`)}};var W=class{static scanRepository(e=process.cwd()){let n=O.resolve(e,"package.json"),s={type:"unknown",testingFramework:"none"};if(!B.existsSync(n))return console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${n}. Defaulting to Generic Node.`),s.type="node",s;let i=JSON.parse(B.readFileSync(n,"utf8")),o={...i.dependencies||{},...i.devDependencies||{}},r=i.scripts||{};return o["@angular/core"]?s.type="angular":o.react?s.type="react":o.vue?s.type="vue":s.type="node",o.jest||r.test?.includes("jest")?s.testingFramework="jest":o.karma||r.test?.includes("karma")||r.test?.includes("ng test")?s.testingFramework="karma":(o.vitest||r.test?.includes("vitest"))&&(s.testingFramework="vitest"),s.testingFramework!=="none"&&(s.testingFramework==="karma"?s.type==="angular"?s.suggestedTestCommand="npx ng test --no-watch --browsers=ChromeHeadless":s.suggestedTestCommand="npx karma start --single-run --browsers=ChromeHeadless":r.test?s.suggestedTestCommand="npm run test":s.testingFramework==="jest"?s.suggestedTestCommand="npx jest --coverage":s.testingFramework==="vitest"&&(s.suggestedTestCommand="npx vitest run --coverage")),s}static findUntestedFiles(e,n=[]){let s=[];if(!B.existsSync(e))return s;let i=B.readdirSync(e),o=T.get(),r=o?.skipDirs??[],a=o?.skipFiles??[],p=o?.skipPaths??[],d=["node_modules","dist","build",".git",".angular","coverage","public","assets",...r],g=["main.ts","index.ts","index.js","index.jsx","app.config.ts","app.routes.ts","styles.css","styles.scss","tailwind.config.js","tailwind.config.ts","eslint.config.js","eslint.config.ts","jest.config.js","jest.config.ts","jest.config.mjs","jest.setup.js","jest.setup.ts","webpack.config.js","webpack.config.ts","babel.config.js","babel.config.ts","rollup.config.js","rollup.config.ts","vite.config.js","vite.config.ts","vitest.config.js","vitest.config.ts","karma.conf.js","karma.config.js","prettier.config.js","prettier.config.ts","postcss.config.js","postcss.config.ts","gulpfile.js","Gulpfile.js",".eslintrc.js",".eslintrc.ts",".babelrc.js"],y=[/^\./,/\.config\.(js|ts|mjs|cjs)$/,/\.conf\.(js|ts|mjs|cjs)$/];for(let c of i){let m=O.join(e,c);if(d.includes(c))continue;let h;try{h=B.statSync(m)}catch{continue}if(h.isDirectory())s.push(...this.findUntestedFiles(m,n));else if(c.match(/\.(ts|tsx|js|jsx|vue)$/)&&!c.includes(".spec.")&&!c.includes(".test.")){if(g.includes(c)||a.includes(c)||y.some(l=>l.test(c)))continue;let f=O.extname(c),u=c.slice(0,-f.length);if(![O.join(e,`${u}.spec${f}`),O.join(e,`${u}.test${f}`),O.join(e,`${u}.spec.js`),O.join(e,`${u}.test.js`),O.join(e,`${u}.spec.ts`),O.join(e,`${u}.test.ts`)].some(l=>B.existsSync(l))){let l=O.relative(process.cwd(),m);if(p.some(v=>l.startsWith(v)))continue;n.includes(l)||s.push(l)}}}return s}};var et=require("child_process"),te=class{static async installMissingFramework(e,n=process.cwd()){if(e.testingFramework!=="none")return e;console.log(`
73
+ [Lisa.ai Auto-Installer] \u{1F6A8} No testing framework detected for ${e.type} architecture.`),console.log("[Lisa.ai Auto-Installer] \u{1FA84} Initiating Zero-Config Installation Protocol...");let s="",i="none";switch(e.type){case"angular":console.log("[Lisa.ai Auto-Installer] Provisioning Angular TestBed environment..."),s="npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine jasmine-core @types/jasmine",i="karma",e.suggestedTestCommand="npm run test";break;case"react":case"node":default:console.log("[Lisa.ai Auto-Installer] Provisioning Universal Jest environment..."),s="npm install --save-dev jest @types/jest ts-jest",i="jest",e.suggestedTestCommand="npx jest --coverage";break;case"vue":console.log("[Lisa.ai Auto-Installer] Provisioning Vue Vitest environment..."),s="npm install --save-dev vitest @vue/test-utils jsdom",i="vitest",e.suggestedTestCommand="npx vitest run --coverage";break}if(s){console.log(`[Lisa.ai Executing] ${s}`);let o=s.split(" "),r=process.platform==="win32"?`${o[0]}.cmd`:o[0];return(0,et.spawnSync)(r,o.slice(1),{cwd:n,stdio:"inherit"}).status!==0&&(console.error(`
74
+ \u274C [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`),process.exit(1)),console.log("\u2705 [Lisa.ai Auto-Installer] Framework successfully injected."),e.testingFramework=i,e}return e}};var we=j(require("fs")),Pe=j(require("path"));var se=class{static async provisionConfigurationFiles(e,n,s,i=process.cwd()){if(e.testingFramework==="none")return;if(console.log(`
75
+ [Lisa.ai Auto-Generator] \u{1FA84} Analyzing ${e.type} architecture to generate ${e.testingFramework} configuration specs...`),["jest.config.js","jest.config.ts","karma.conf.js","vitest.config.ts","vitest.config.js"].some(p=>we.existsSync(Pe.join(i,p)))){console.log("[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.");return}let a=`You are an expert ${e.type} architect.
76
76
  Write a production-ready '${e.testingFramework}' configuration file for a standard '${e.type}' application.
77
77
  The application resides in the root directory.
78
78
 
@@ -80,101 +80,102 @@ Requirements:
80
80
  1. Ensure it specifically instruments code coverage.
81
81
  2. Ensure standard transpilation (ts-jest for jest, or standard karma-webpack/karma-typescript implementations).
82
82
  3. Do NOT wrap your response in markdown formatting (no \`\`\`javascript).
83
- 4. Return ONLY the raw code string block.`;try{let d=await X(a,n,s),c="";e.testingFramework==="jest"&&(c="jest.config.js"),e.testingFramework==="karma"&&(c="karma.conf.js"),e.testingFramework==="vitest"&&(c="vitest.config.ts");let u=Ae.join(i,c);ye.writeFileSync(u,d,"utf-8"),console.log(`\u2705 [Lisa.ai Auto-Generator] Natively wrote ${c} to repository root.`)}catch(d){console.error(`
84
- \u274C [Lisa.ai Auto-Generator] Failed to author configuration file: ${d.message}`),process.exit(1)}}};var Je=j(require("dotenv"));Je.config({quiet:!0});function se(t){let e=t.toLowerCase();return e.includes("karma")||e.includes("ng test")?"karma":e.includes("jest")?"jest":e.includes("vitest")?"vitest":e.includes("playwright")?"playwright":e.includes("cypress")?"cypress":e.includes("mocha")?"mocha":"unknown"}async function Qe(t,e,n){if(n==="local")return[];let s=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let i=new URLSearchParams({projectId:n,errorLog:t.slice(0,1e3),framework:e}),o=await fetch(`${s}/api/memory/lookup?${i}`);return o.ok?await o.json():[]}catch{return[]}}async function Xe(t,e,n,s){if(s==="local")return;let i=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{await fetch(`${i}/api/memory/record`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:s,errorLog:t.slice(0,1e3),fixHint:e.slice(0,2e3),framework:n})}),console.log("[Lisa.ai Memory] Fix pattern recorded to Control Plane.")}catch(o){console.debug(`[Lisa.ai Agent Debug] Failed to record memory pattern: ${o.message}`)}}var ne=0,we=0,Ee=new Set;function Fe(t){let n=[...ge(t).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length===0)return null;let s=[...n].reverse().find(c=>c[3]!==void 0)??n[n.length-1],i=parseInt(s[2]),o=s[3]?parseInt(s[3]):0,r=parseInt(s[1])-o,a=i>0?Math.round(r/i*100):0;return` [${"\u2588".repeat(Math.round(a/5))+"\u2591".repeat(20-Math.round(a/5))}] ${a}% ${r} passed ${o} failed ${i} total`}function tt(t,e=10){let n=[];for(let s of ge(t).split(`
85
- `)){let i=s.trim();if(/^FAILED/.test(i)||/ FAILED$/.test(i)){let r=i.replace(/^(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:[\s.]\d+)*\s+\([^)]+\)\s+/,"").replace(/\s+FAILED$/,"").trim();if(n.push(r||i),n.length>=e)break}}return n}function bt(t){let e=t.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/,".$2");if(e!==t&&U.existsSync(e))try{return console.log(` [Lisa.ai] \u{1F9E0} Sibling source found: ${W.basename(e)}`),U.readFileSync(e,"utf-8")}catch{return}}function At(t,e){let n=t.toLowerCase(),s=W.parse(e);if(n.includes("ng test")||n.includes("karma"))return`${t} --include **/${s.base}`;if(n.includes("jest")||n.includes("vitest")||n.includes("playwright"))return`${t} ${e}`;if(n.includes("cypress"))return`${t} --spec ${e}`;if(n.includes("npm")||n.includes("yarn")||n.includes("pnpm")){try{let o=JSON.parse(U.readFileSync(W.resolve(process.cwd(),"package.json"),"utf8")),r="test";n.includes("npm run ")?r=n.split("npm run ")[1].split(" ")[0]:n.includes("yarn ")?r=n.split("yarn ")[1].split(" ")[0]:n.includes("pnpm ")&&(r=n.split("pnpm ")[1].split(" ")[0]);let a=o.scripts?.[r]?.toLowerCase()||"",d=n.includes("npm")?" --":"";if(a.includes("ng test")||a.includes("karma"))return`${t}${d} --include **/${s.base}`;if(a.includes("jest")||a.includes("vitest")||a.includes("playwright"))return`${t}${d} ${e}`}catch{}let i=n.includes("npm")?" --":"";return`${t}${i} ${e}`}return t}function Pe(t,e=!1){return new Promise((n,s)=>{let i=(0,et.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),o="",r="";i.stdout?.on("data",a=>{let d=a.toString();if(o+=d,e)for(let c of d.split(`
86
- `)){let u=c.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"").trim();u&&(/Executed\s+\d+\s+of\s+\d+/.test(u)?process.stdout.write(`\r ${u.padEnd(72)}`):/^\s*FAILED\b/.test(u)&&(process.stdout.write(`
87
- `),console.log(` \u2717 ${u.trim()}`)))}}),i.stderr?.on("data",a=>{r+=a.toString()}),i.on("close",a=>{a===0?n({stdout:o,stderr:r}):s({message:`Process exited with code ${a}`,stdout:o,stderr:r})})})}function Et(t,e,n){if(!e.match(/\.(spec|test)\.(ts|js|tsx|jsx|vue)$/))return;if((n||"").toLowerCase().includes("ng test")||(n||"").toLowerCase().includes("karma"))try{U.writeFileSync(t,`// Quarantined by Lisa.ai \u2014 could not be automatically healed
83
+ 4. Return ONLY the raw code string block.`;try{let p=await ee(a,n,s),d="";e.testingFramework==="jest"&&(d="jest.config.js"),e.testingFramework==="karma"&&(d="karma.conf.js"),e.testingFramework==="vitest"&&(d="vitest.config.ts");let g=Pe.join(i,d);we.writeFileSync(g,p,"utf-8"),console.log(`\u2705 [Lisa.ai Auto-Generator] Natively wrote ${d} to repository root.`)}catch(p){console.error(`
84
+ \u274C [Lisa.ai Auto-Generator] Failed to author configuration file: ${p.message}`),process.exit(1)}}};var tt=j(require("dotenv"));tt.config({quiet:!0});function ne(t){let e=t.toLowerCase();return e.includes("karma")||e.includes("ng test")?"karma":e.includes("jest")?"jest":e.includes("vitest")?"vitest":e.includes("playwright")?"playwright":e.includes("cypress")?"cypress":e.includes("mocha")?"mocha":"unknown"}async function st(t,e,n){if(n==="local")return[];let s=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let i=new URLSearchParams({projectId:n,errorLog:t.slice(0,1e3),framework:e}),o=await fetch(`${s}/api/memory/lookup?${i}`);return o.ok?await o.json():[]}catch{return[]}}async function nt(t,e,n,s){if(s==="local")return;let i=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{await fetch(`${i}/api/memory/record`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:s,errorLog:t.slice(0,1e3),fixHint:e.slice(0,2e3),framework:n})}),console.log("[Lisa.ai Memory] Fix pattern recorded to Control Plane.")}catch(o){console.debug(`[Lisa.ai Agent Debug] Failed to record memory pattern: ${o.message}`)}}var R=j(require("fs")),_=j(require("path")),Te=require("child_process");function ve(t){if(R.existsSync(_.join(t,"playwright.config.ts"))||R.existsSync(_.join(t,"playwright.config.js")))return{framework:"playwright",configFile:R.existsSync(_.join(t,"playwright.config.ts"))?"playwright.config.ts":"playwright.config.js",command:"npx playwright test",installed:!0};if(R.existsSync(_.join(t,"cypress.config.ts"))||R.existsSync(_.join(t,"cypress.config.js"))||R.existsSync(_.join(t,"cypress.json")))return{framework:"cypress",configFile:R.existsSync(_.join(t,"cypress.config.ts"))?"cypress.config.ts":R.existsSync(_.join(t,"cypress.config.js"))?"cypress.config.js":"cypress.json",command:"npx cypress run",installed:!0};let e=_.join(t,"package.json");if(R.existsSync(e)){let n=JSON.parse(R.readFileSync(e,"utf-8")),s={...n.dependencies||{},...n.devDependencies||{}};if(s["@playwright/test"])return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!0};if(s.cypress)return{framework:"cypress",configFile:null,command:"npx cypress run",installed:!0}}return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!1}}function xe(t){console.log("[Lisa.ai E2E] No E2E framework detected. Installing Playwright...");try{(0,Te.execSync)("npm install -D @playwright/test",{cwd:t,stdio:"pipe"}),console.log("[Lisa.ai E2E] Playwright installed.")}catch(n){throw console.error(`[Lisa.ai E2E] Failed to install Playwright: ${n.message}`),new Error("Could not install @playwright/test. Please install it manually.")}try{console.log("[Lisa.ai E2E] Installing Playwright browsers..."),(0,Te.execSync)("npx playwright install --with-deps chromium",{cwd:t,stdio:"pipe"}),console.log("[Lisa.ai E2E] Chromium browser installed.")}catch{console.warn("[Lisa.ai E2E Warning] Browser install failed. You may need to run 'npx playwright install' manually.")}R.existsSync(_.join(t,"playwright.config.ts"))||(R.writeFileSync(_.join(t,"playwright.config.ts"),`import { defineConfig } from '@playwright/test';
85
+
86
+ export default defineConfig({
87
+ testDir: './e2e',
88
+ fullyParallel: true,
89
+ forbidOnly: !!process.env.CI,
90
+ retries: process.env.CI ? 2 : 0,
91
+ workers: process.env.CI ? 1 : undefined,
92
+ reporter: 'html',
93
+ use: {
94
+ baseURL: 'http://localhost:4200',
95
+ trace: 'on-first-retry',
96
+ },
97
+ projects: [
98
+ { name: 'chromium', use: { browserName: 'chromium' } },
99
+ ],
100
+ });
101
+ `,"utf-8"),console.log("[Lisa.ai E2E] Generated playwright.config.ts"));let e=_.join(t,"e2e");R.existsSync(e)||(R.mkdirSync(e,{recursive:!0}),console.log("[Lisa.ai E2E] Created e2e/ directory"))}var oe=0,Le=0,Ie=new Set;function Re(t){let n=[...fe(t).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length===0)return null;let s=[...n].reverse().find(d=>d[3]!==void 0)??n[n.length-1],i=parseInt(s[2]),o=s[3]?parseInt(s[3]):0,r=parseInt(s[1])-o,a=i>0?Math.round(r/i*100):0;return` [${"\u2588".repeat(Math.round(a/5))+"\u2591".repeat(20-Math.round(a/5))}] ${a}% ${r} passed ${o} failed ${i} total`}function it(t,e=10){let n=[];for(let s of fe(t).split(`
102
+ `)){let i=s.trim();if(/^FAILED/.test(i)||/ FAILED$/.test(i)){let r=i.replace(/^(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:[\s.]\d+)*\s+\([^)]+\)\s+/,"").replace(/\s+FAILED$/,"").trim();if(n.push(r||i),n.length>=e)break}}return n}function Tt(t){let e=t.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/,".$2");if(e!==t&&G.existsSync(e))try{return console.log(` [Lisa.ai] \u{1F9E0} Sibling source found: ${Y.basename(e)}`),G.readFileSync(e,"utf-8")}catch{return}}function It(t,e){let n=t.toLowerCase(),s=Y.parse(e);if(n.includes("ng test")||n.includes("karma"))return`${t} --include **/${s.base}`;if(n.includes("jest")||n.includes("vitest")||n.includes("playwright"))return`${t} ${e}`;if(n.includes("cypress"))return`${t} --spec ${e}`;if(n.includes("npm")||n.includes("yarn")||n.includes("pnpm")){try{let o=JSON.parse(G.readFileSync(Y.resolve(process.cwd(),"package.json"),"utf8")),r="test";n.includes("npm run ")?r=n.split("npm run ")[1].split(" ")[0]:n.includes("yarn ")?r=n.split("yarn ")[1].split(" ")[0]:n.includes("pnpm ")&&(r=n.split("pnpm ")[1].split(" ")[0]);let a=o.scripts?.[r]?.toLowerCase()||"",p=n.includes("npm")?" --":"";if(a.includes("ng test")||a.includes("karma"))return`${t}${p} --include **/${s.base}`;if(a.includes("jest")||a.includes("vitest")||a.includes("playwright"))return`${t}${p} ${e}`}catch{}let i=n.includes("npm")?" --":"";return`${t}${i} ${e}`}return t}function Me(t,e=!1){return new Promise((n,s)=>{let i=(0,ot.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),o="",r="";i.stdout?.on("data",a=>{let p=a.toString();if(o+=p,e)for(let d of p.split(`
103
+ `)){let g=d.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"").trim();g&&(/Executed\s+\d+\s+of\s+\d+/.test(g)?process.stdout.write(`\r ${g.padEnd(72)}`):/^\s*FAILED\b/.test(g)&&(process.stdout.write(`
104
+ `),console.log(` \u2717 ${g.trim()}`)))}}),i.stderr?.on("data",a=>{r+=a.toString()}),i.on("close",a=>{a===0?n({stdout:o,stderr:r}):s({message:`Process exited with code ${a}`,stdout:o,stderr:r})})})}function Rt(t,e,n){if(!e.match(/\.(spec|test)\.(ts|js|tsx|jsx|vue)$/))return;if((n||"").toLowerCase().includes("ng test")||(n||"").toLowerCase().includes("karma"))try{G.writeFileSync(t,`// Quarantined by Lisa.ai \u2014 could not be automatically healed
88
105
  describe('', () => {});
89
- `,"utf-8"),console.log(" \u{1F6A8} Replaced with empty stub (Angular requires valid TS).")}catch{}else try{U.renameSync(t,t+".broken"),console.log(` \u{1F6A8} Renamed to ${W.basename(t)}.broken to skip in test runner.`)}catch{}}async function Ft(t,e,n,s,i,o,r,a,d,c){let u=1,g=!1,l=n,f,h="",m="",y=bt(e),$=(await Qe(n,o,d)).filter(p=>p.confidence>=.5).map(p=>p.fixHint);for($.length>0&&console.log(` [Memory] ${$.length} proven pattern(s) found \u2014 injecting as LLM hint.`);u<=a&&!g;){console.log(` [Attempt ${u}/${a}] Requesting fix from ${r}...`);let p=U.readFileSync(e,"utf-8"),k;for(let w=0;w<=3;w++)try{k=await qe(t,p,l,r,c,f,y,$);break}catch(L){let x=(L?.lastError??L)?.statusCode;if((x===529||x===500)&&w<3){let F=30*(w+1);console.warn(` \u26A0\uFE0F LLM overloaded (HTTP ${x}). Waiting ${F}s...`),await new Promise(_=>setTimeout(_,F*1e3))}else{console.error(` \u{1F6A8} LLM API failed: ${L?.message??String(L)}`);break}}if(k===void 0)break;U.writeFileSync(e,k,"utf-8"),h=`### Auto-Heal Analysis
106
+ `,"utf-8"),console.log(" \u{1F6A8} Replaced with empty stub (Angular requires valid TS).")}catch{}else try{G.renameSync(t,t+".broken"),console.log(` \u{1F6A8} Renamed to ${Y.basename(t)}.broken to skip in test runner.`)}catch{}}async function Mt(t,e,n,s,i,o,r,a,p,d){let g=1,y=!1,c=n,m,h="",f="",u=Tt(e),$=(await st(n,o,p)).filter(l=>l.confidence>=.5).map(l=>l.fixHint);for($.length>0&&console.log(` [Memory] ${$.length} proven pattern(s) found \u2014 injecting as LLM hint.`);g<=a&&!y;){console.log(` [Attempt ${g}/${a}] Requesting fix from ${r}...`);let l=G.readFileSync(e,"utf-8"),v;for(let w=0;w<=3;w++)try{v=await Ve(t,l,c,r,d,m,u,$);break}catch(L){let x=(L?.lastError??L)?.statusCode;if((x===529||x===500)&&w<3){let A=30*(w+1);console.warn(` \u26A0\uFE0F LLM overloaded (HTTP ${x}). Waiting ${A}s...`),await new Promise(F=>setTimeout(F,A*1e3))}else{console.error(` \u{1F6A8} LLM API failed: ${L?.message??String(L)}`);break}}if(v===void 0)break;G.writeFileSync(e,v,"utf-8"),h=`### Auto-Heal Analysis
90
107
  **Error:**
91
108
  \`\`\`bash
92
- ${l.slice(0,2e3)}
109
+ ${c.slice(0,2e3)}
93
110
  \`\`\`
94
111
 
95
112
  **Fix (${r}):**
96
113
  \`\`\`typescript
97
- ${k}
98
- \`\`\``;try{await Pe(i,!1),console.log(" \u2705 Isolated verification passed."),g=!0,m=k}catch(w){let L=w.stdout?w.stdout.toString():"";l=(w.stderr?w.stderr.toString():"")+`
114
+ ${v}
115
+ \`\`\``;try{await Me(i,!1),console.log(" \u2705 Isolated verification passed."),y=!0,f=v}catch(w){let L=w.stdout?w.stdout.toString():"";c=(w.stderr?w.stderr.toString():"")+`
99
116
  `+L+`
100
- `+(w.message||""),console.log(" \u274C Isolated verification failed.");let F=Fe(l);if(F&&console.log(F),tt(l,3).forEach(_=>console.log(` \u2717 ${_}`)),(s||"").toLowerCase().includes("ng test")||(s||"").toLowerCase().includes("karma")){let _=l.includes(W.basename(t)+":"),O=/ FAILED/.test(l);if(!_&&!O){console.log(" \u2705 Fix verified (build error is from other spec files, not this one)."),g=!0,m=k;continue}}f=`### Attempt ${u} Failed
117
+ `+(w.message||""),console.log(" \u274C Isolated verification failed.");let A=Re(c);if(A&&console.log(A),it(c,3).forEach(F=>console.log(` \u2717 ${F}`)),(s||"").toLowerCase().includes("ng test")||(s||"").toLowerCase().includes("karma")){let F=c.includes(Y.basename(t)+":"),U=/ FAILED/.test(c);if(!F&&!U){console.log(" \u2705 Fix verified (build error is from other spec files, not this one)."),y=!0,f=v;continue}}m=`### Attempt ${g} Failed
101
118
  \`\`\`typescript
102
- ${k}
119
+ ${v}
103
120
  \`\`\`
104
121
 
105
122
  **New Error:**
106
- ${l}`,u++}}return{status:g?"healed":"quarantined",details:h,lastCode:m}}async function ve(t,e,n=1,s=null,i=3,o="local",r,a){let d=P.load(process.cwd());if(d&&(P.applyEnvDefaults(d),!t&&d.testCommand&&(t=d.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`))),!t){console.log(`
107
- [Lisa.ai Auto-Discovery] No --command provided. Scanning framework...`);let v=q.scanRepository();v.testingFramework==="none"&&(v=await ee.installMissingFramework(v),await te.provisionConfigurationFiles(v,e,a)),v.suggestedTestCommand?(t=v.suggestedTestCommand,console.log(`[Lisa.ai Auto-Discovery] Discovered command: ${t}`)):(console.error(`
108
- \u{1F6A8} [Lisa.ai] Could not discover a test command. Pass --command explicitly.`),process.exit(1))}let c=se(t),u=[];console.log(`
109
- [Lisa.ai] Running test suite (discovery pass)...`),console.log(`[Lisa.ai Executing] ${t} Model: ${e}`);let g;try{await Pe(t,!0),process.stdout.write(`
123
+ ${c}`,g++}}return{status:y?"healed":"quarantined",details:h,lastCode:f}}async function $e(t,e,n=1,s=null,i=3,o="local",r,a,p="unit"){let d=p==="unit"?"":` (${p})`,g=T.load(process.cwd());if(g&&T.applyEnvDefaults(g),p==="e2e"){if(!t&&g?.e2eCommand&&(t=g.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${t}`)),!t){console.log(`
124
+ [Lisa.ai Heal${d}] Auto-detecting E2E framework...`);let l=ve(process.cwd());!l.installed&&l.framework==="playwright"&&xe(process.cwd()),t=l.command,console.log(`[Lisa.ai Heal${d}] E2E command: ${t}`)}}else if(!t&&g?.testCommand&&(t=g.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)),!t){console.log(`
125
+ [Lisa.ai Auto-Discovery] No --command provided. Scanning framework...`);let l=W.scanRepository();l.testingFramework==="none"&&(l=await te.installMissingFramework(l),await se.provisionConfigurationFiles(l,e,a)),l.suggestedTestCommand?(t=l.suggestedTestCommand,console.log(`[Lisa.ai Auto-Discovery] Discovered command: ${t}`)):(console.error(`
126
+ \u{1F6A8} [Lisa.ai] Could not discover a test command. Pass --command explicitly.`),process.exit(1))}let y=ne(t),c=[];console.log(`
127
+ [Lisa.ai Heal${d}] Running test suite (discovery pass)...`),console.log(`[Lisa.ai Executing] ${t} Model: ${e}`);let m;try{await Me(t,!0),process.stdout.write(`
110
128
  `),console.log(`
111
- \u2705 [Lisa.ai] All tests passing. Nothing to heal!`),s&&await be(s);return}catch(v){process.stdout.write(`
112
- `),g=(v.stderr||"")+`
113
- `+(v.stdout||"")+`
114
- `+(v.message||"")}let l=K(g),f=Fe(g);if(f){console.log(`
115
- ${f}`);let v=tt(g,10);if(v.length>0){let $=l?.failed??v.length;console.log(` Failing (${$}):`),v.forEach(p=>console.log(` \u2717 ${p}`)),$>v.length&&console.log(` ... and ${$-v.length} more`)}}let h=Se(g,process.cwd(),u);if(h.length===0){let v=fe(g,u,process.cwd());v||(console.error(`
116
- \u{1F6A8} [Lisa.ai] Could not identify any failing spec files. Output format may be unsupported.`),process.exit(1)),h=[v]}let m=h.length;console.log(`
117
- [Lisa.ai] Found ${m} failing spec(s). Healing each in isolation...`),console.log(`${"\u2500".repeat(60)}`);for(let v of h)T({projectId:o,type:"heal",filePath:v,modelUsed:e,status:"running",details:"Queued for isolated healing.",...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:c});for(let v=0;v<h.length;v++){let $=h[v],p=W.resolve(process.cwd(),$);if(console.log(`
118
- [${v+1}/${m}] ${$}`),!U.existsSync(p)){console.warn(" \u26A0\uFE0F File not found \u2014 skipping.");continue}if(/[\\/](node_modules|dist|build)[\\/]/.test(p)){console.warn(" \u26A0\uFE0F Library file \u2014 refusing to modify.");continue}let k=At(t,$),w=await Ft($,p,g,t,k,c,e,i,o,a);w.status==="healed"?(ne++,Ee.add($),console.log(` \u2705 Healed [${ne} healed ${we} quarantined so far]`),T({projectId:o,type:"heal",filePath:$,modelUsed:e,status:"success",details:w.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:c}),await Xe(g,w.lastCode,c,o)):(we++,u.push($),console.warn(` \u{1F6A8} Quarantined [${ne} healed ${we} quarantined so far]`),T({projectId:o,type:"heal",filePath:$,modelUsed:e,status:"error",details:`Exhausted all ${i} attempts.
119
- `+w.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:c}),Et(p,$,t))}if(console.log(`
120
- ${"\u2500".repeat(60)}`),ne>0){console.log("[Lisa.ai] Final verification run...");try{await Pe(t,!0),process.stdout.write(`
129
+ \u2705 [Lisa.ai] All tests passing. Nothing to heal!`),s&&await Fe(s);return}catch(l){process.stdout.write(`
130
+ `),m=(l.stderr||"")+`
131
+ `+(l.stdout||"")+`
132
+ `+(l.message||"")}let h=V(m),f=Re(m);if(f){console.log(`
133
+ ${f}`);let l=it(m,10);if(l.length>0){let v=h?.failed??l.length;console.log(` Failing (${v}):`),l.forEach(w=>console.log(` \u2717 ${w}`)),v>l.length&&console.log(` ... and ${v-l.length} more`)}}let u=be(m,process.cwd(),c);if(u.length===0){let l=me(m,c,process.cwd());l||(console.error(`
134
+ \u{1F6A8} [Lisa.ai] Could not identify any failing spec files. Output format may be unsupported.`),process.exit(1)),u=[l]}let k=u.length;console.log(`
135
+ [Lisa.ai] Found ${k} failing spec(s). Healing each in isolation...`),console.log(`${"\u2500".repeat(60)}`);for(let l of u)I({projectId:o,type:"heal",filePath:l,modelUsed:e,status:"running",details:"Queued for isolated healing.",...h&&{testTotal:h.total,testPassed:h.passed,testFailed:h.failed},testFramework:y});for(let l=0;l<u.length;l++){let v=u[l],w=Y.resolve(process.cwd(),v);if(console.log(`
136
+ [${l+1}/${k}] ${v}`),!G.existsSync(w)){console.warn(" \u26A0\uFE0F File not found \u2014 skipping.");continue}if(/[\\/](node_modules|dist|build)[\\/]/.test(w)){console.warn(" \u26A0\uFE0F Library file \u2014 refusing to modify.");continue}let L=It(t,v),x=await Mt(v,w,m,t,L,y,e,i,o,a);x.status==="healed"?(oe++,Ie.add(v),console.log(` \u2705 Healed [${oe} healed ${Le} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:e,status:"success",details:x.details,...h&&{testTotal:h.total,testPassed:h.passed,testFailed:h.failed},testFramework:y}),await nt(m,x.lastCode,y,o)):(Le++,c.push(v),console.warn(` \u{1F6A8} Quarantined [${oe} healed ${Le} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:e,status:"error",details:`Exhausted all ${i} attempts.
137
+ `+x.details,...h&&{testTotal:h.total,testPassed:h.passed,testFailed:h.failed},testFramework:y}),Rt(w,v,t))}if(console.log(`
138
+ ${"\u2500".repeat(60)}`),oe>0){console.log("[Lisa.ai] Final verification run...");try{await Me(t,!0),process.stdout.write(`
121
139
  `),console.log(`
122
- \u2705 All tests passing!`)}catch(v){process.stdout.write(`
123
- `);let $=(v.stderr||"")+`
124
- `+(v.stdout||"")+`
125
- `+(v.message||""),p=Fe($);p&&console.log(`
126
- ${p}`);let k=Se($,process.cwd(),[]),w=k.filter(x=>Ee.has(x)),L=k.filter(x=>!Ee.has(x)&&!u.includes(x));w.length>0&&(console.warn(`
127
- \u26A0\uFE0F ${w.length} spec(s) passed isolated verification but still fail globally:`),w.forEach(x=>console.warn(` \u2717 ${x}`)),console.warn(" These likely have cross-test shared state. Try higher maxRetries or fix manually.")),L.length>0&&(console.warn(`
128
- \u2139\uFE0F ${L.length} additional failing spec(s) not in this run's queue:`),L.forEach(x=>console.warn(` \u2717 ${x}`)),console.warn(" Run lisa-agent heal again to address these."))}}let y=(l?.passed??0)+ne;console.log(`
129
- \u2705 Healed: ${ne} / ${m}`),console.log(` \u{1F6A8} Quarantined: ${we}`),l&&console.log(` \u{1F4CA} Suite: ${l.passed} passing \u2192 ~${y} passing (est.)`),console.log(`${"\u2500".repeat(60)}
130
- `),s&&await be(s)}var it=require("child_process"),B=j(require("fs")),M=j(require("path"));var xe=j(require("fs")),st=j(require("path"));function nt(t){let e=st.resolve(process.cwd(),t);if(!xe.existsSync(e))throw new Error(`[Lisa.ai Coverage Error] Coverage file not found at ${e}`);let n=xe.readFileSync(e,"utf-8"),s=JSON.parse(n),i=[];for(let[o,r]of Object.entries(s))o!=="total"&&(r.lines.pct<100||r.statements.pct<100||r.functions.pct<100||r.branches.pct<100)&&i.push(o);return i}var ot=new Set,Le=0,Te=3;function Pt(t){let e=t.testingFramework,n=process.cwd();return B.existsSync(M.join(n,"angular.json"))?"npx ng test --no-watch --code-coverage --browsers=ChromeHeadless":e==="jest"?"npx jest --coverage --coverageReporters=json-summary":e==="vitest"?"npx vitest run --coverage":[".mocharc.yml",".mocharc.yaml",".mocharc.json",".mocharc.js"].some(i=>B.existsSync(M.join(n,i)))?"npx nyc --reporter=json-summary mocha":null}async function le(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
131
- [Lisa.ai Unit] Reached maximum retries (${s}). Stopping.`);return}let r=P.load(process.cwd());r&&(P.applyEnvDefaults(r),!t&&r.testCommand&&(t=r.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let a=q.scanRepository(),d=r?.testingFramework||(a.testingFramework!=="none"?a.testingFramework:void 0),c=r?.testTypes;if(!t){console.log(`
132
- [Lisa.ai Auto-Discovery] No explicit --command provided. Auto-detecting coverage command...`);let l=Pt(a);if(l)t=l,console.log(`[Lisa.ai Auto-Discovery] Detected coverage command: ${t}`);else{let f=a;if(f.testingFramework==="none"&&(f=await ee.installMissingFramework(f),await te.provisionConfigurationFiles(f,e,o)),f.suggestedTestCommand){t=f.suggestedTestCommand;let h=f.testingFramework;(h==="jest"||h==="vitest")&&!t.includes("--coverage")&&(t=t.includes("npm run")?`${t} -- --coverage`:`${t} --coverage`,console.log(`[Lisa.ai Unit] Coverage flag appended: ${t}`)),console.log(`[Lisa.ai Auto-Discovery] Bootstrapping with discovered command: ${t}`)}else console.error(`
133
- [Lisa.ai Fatal Error] Could not auto-detect a test framework. Please pass --command explicitly or add a .lisai.json config.`),process.exit(1)}}console.log(`
134
- [Lisa.ai Unit] ${t} (Attempt ${n}/${s}) Using Model: ${e}`);let u=se(t);await T({projectId:i,type:"unit",filePath:"global-test-suite",modelUsed:e,status:"running",details:"Agent is executing unit test suite and validating coverage...",testFramework:u});let g=(l,f=!1)=>new Promise((h,m)=>{let y=(0,it.spawn)(l,{shell:!0,stdio:["ignore","pipe","pipe"]}),v="",$="";y.stdout?.on("data",p=>{let k=p.toString();if(v+=k,f){let w=k.split(`
135
- `);for(let L of w){let x=L.match(/Executed\s+(\d+)\s+of\s+(\d+)/);if(x){let F=L.match(/(\d+)\s+FAILED/),_=F?F[1]:0,O=`\r[Lisa.ai Testing] Executed ${x[1]} of ${x[2]} (${_} FAILED) `;process.stdout.write(O)}}}}),y.stderr?.on("data",p=>{$+=p.toString()}),y.on("close",p=>{p===0?h({stdout:v,stderr:$}):m({message:`Test process exited with code ${p}`,stdout:v,stderr:$})})});try{console.log("[Lisa.ai Unit] Running tests with coverage. This may take a moment...");let l=await g(t,!0),f=l.stdout+`
136
- `+l.stderr,h=K(f);h&&await T({projectId:i,type:"unit",filePath:"global-test-suite",modelUsed:e,status:"success",details:`Tests passed on attempt ${n}.`,testTotal:h.total,testPassed:h.passed,testFailed:h.failed,testFramework:u}),console.log(`
137
- [Lisa.ai Unit] Tests passed on attempt ${n}.`)}catch(l){let f=(l.stderr||"")+`
140
+ \u2705 All tests passing!`)}catch(l){process.stdout.write(`
141
+ `);let v=(l.stderr||"")+`
138
142
  `+(l.stdout||"")+`
139
- `+(l.message||"");if(fe(f,[],process.cwd())!==null){console.log(`
140
- [Lisa.ai Unit] Tests failed. Delegating to Auto-Heal...`),await ve(t,e,1,null,s,i,void 0,o),console.log(`
141
- [Lisa.ai Unit] Auto-Heal complete. Restarting unit analysis...`),await le(t,e,n+1,s,i,o);return}console.log(`
142
- [Lisa.ai Unit] No failing spec detected. Tests may not exist yet \u2014 initiating Cold-Start Discovery...`)}try{let l=M.resolve(process.cwd(),"coverage/coverage-summary.json"),f=[];if(B.existsSync(l))console.log("[Lisa.ai Unit] Evaluating coverage summary..."),f=nt("coverage/coverage-summary.json");else{if(console.log(`
143
- [Lisa.ai Unit] No coverage-summary.json found. Initiating Cold-Start Discovery...`),f=q.findUntestedFiles(process.cwd(),[...ot]),f.length===0){console.log("[Lisa.ai Unit] No untested source files discovered.");return}console.log(`[Lisa.ai Unit] Discovered ${f.length} untested file(s). Generating specs...`)}if(f.length===0){console.log("[Lisa.ai Unit] 100% coverage achieved. No uncovered files remaining.");return}console.log(`[Lisa.ai Unit] Found ${f.length} file(s) below threshold:`,f);let h=f[0],m=M.resolve(process.cwd(),h),y=M.parse(m),v=[M.join(y.dir,`${y.name}.spec${y.ext}`),M.join(y.dir,`${y.name}.test${y.ext}`),M.join(y.dir,`${y.name}.spec.js`),M.join(y.dir,`${y.name}.test.js`),M.join(y.dir,`${y.name}.spec.ts`),M.join(y.dir,`${y.name}.test.ts`)],$=null,p=M.join(y.dir,`${y.name}.spec${y.ext}`);for(let x of v)if(B.existsSync(x)){p=x,$=B.readFileSync(x,"utf-8");break}let k="",w=!1,L=B.readFileSync(m,"utf-8");try{$?(console.log(`[Lisa.ai Unit] Existing spec found for ${h}. Requesting coverage append...`),k=await We(h,L,M.relative(process.cwd(),p),$,e,o,d,c)):(console.log(`[Lisa.ai Unit] Generating new spec for ${h}...`),k=await Q(h,L,e,o,d,c)),Le=0,w=!0}catch(x){Le++,ot.add(h);let F=x.cause?.message?`${x.message} (cause: ${x.cause.message})`:x.message;if(console.error(`
144
- [Lisa.ai Unit] LLM call failed for ${h} \u2014 consecutive failure #${Le}/${Te}`),console.error(` Error: ${F}`),Le>=Te)throw new Error(`Systematic LLM failure: ${Te} consecutive API calls failed.
143
+ `+(l.message||""),w=Re(v);w&&console.log(`
144
+ ${w}`);let L=be(v,process.cwd(),[]),x=L.filter(F=>Ie.has(F)),A=L.filter(F=>!Ie.has(F)&&!c.includes(F));x.length>0&&(console.warn(`
145
+ \u26A0\uFE0F ${x.length} spec(s) passed isolated verification but still fail globally:`),x.forEach(F=>console.warn(` \u2717 ${F}`)),console.warn(" These likely have cross-test shared state. Try higher maxRetries or fix manually.")),A.length>0&&(console.warn(`
146
+ \u2139\uFE0F ${A.length} additional failing spec(s) not in this run's queue:`),A.forEach(F=>console.warn(` \u2717 ${F}`)),console.warn(" Run lisa-agent heal again to address these."))}}let $=(h?.passed??0)+oe;console.log(`
147
+ \u2705 Healed: ${oe} / ${k}`),console.log(` \u{1F6A8} Quarantined: ${Le}`),h&&console.log(` \u{1F4CA} Suite: ${h.passed} passing \u2192 ~${$} passing (est.)`),console.log(`${"\u2500".repeat(60)}
148
+ `),s&&await Fe(s)}var ct=require("child_process"),q=j(require("fs")),M=j(require("path"));var ke=j(require("fs")),rt=j(require("path"));function at(t){let e=rt.resolve(process.cwd(),t);if(!ke.existsSync(e))throw new Error(`[Lisa.ai Coverage Error] Coverage file not found at ${e}`);let n=ke.readFileSync(e,"utf-8"),s=JSON.parse(n),i=[];for(let[o,r]of Object.entries(s))o!=="total"&&(r.lines.pct<100||r.statements.pct<100||r.functions.pct<100||r.branches.pct<100)&&i.push(o);return i}var lt=new Set,Se=0,De=3;function Dt(t){let e=t.testingFramework,n=process.cwd();return q.existsSync(M.join(n,"angular.json"))?"npx ng test --no-watch --code-coverage --browsers=ChromeHeadless":e==="jest"?"npx jest --coverage --coverageReporters=json-summary":e==="vitest"?"npx vitest run --coverage":[".mocharc.yml",".mocharc.yaml",".mocharc.json",".mocharc.js"].some(i=>q.existsSync(M.join(n,i)))?"npx nyc --reporter=json-summary mocha":null}async function de(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
149
+ [Lisa.ai Unit] Reached maximum retries (${s}). Stopping.`);return}let r=T.load(process.cwd());r&&(T.applyEnvDefaults(r),!t&&r.testCommand&&(t=r.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let a=W.scanRepository(),p=r?.testingFramework||(a.testingFramework!=="none"?a.testingFramework:void 0),d=r?.testTypes;if(!t){console.log(`
150
+ [Lisa.ai Auto-Discovery] No explicit --command provided. Auto-detecting coverage command...`);let c=Dt(a);if(c)t=c,console.log(`[Lisa.ai Auto-Discovery] Detected coverage command: ${t}`);else{let m=a;if(m.testingFramework==="none"&&(m=await te.installMissingFramework(m),await se.provisionConfigurationFiles(m,e,o)),m.suggestedTestCommand){t=m.suggestedTestCommand;let h=m.testingFramework;(h==="jest"||h==="vitest")&&!t.includes("--coverage")&&(t=t.includes("npm run")?`${t} -- --coverage`:`${t} --coverage`,console.log(`[Lisa.ai Unit] Coverage flag appended: ${t}`)),console.log(`[Lisa.ai Auto-Discovery] Bootstrapping with discovered command: ${t}`)}else console.error(`
151
+ [Lisa.ai Fatal Error] Could not auto-detect a test framework. Please pass --command explicitly or add a .lisai.json config.`),process.exit(1)}}console.log(`
152
+ [Lisa.ai Unit] ${t} (Attempt ${n}/${s}) Using Model: ${e}`);let g=ne(t);await I({projectId:i,type:"unit",filePath:"global-test-suite",modelUsed:e,status:"running",details:"Agent is executing unit test suite and validating coverage...",testFramework:g});let y=(c,m=!1)=>new Promise((h,f)=>{let u=(0,ct.spawn)(c,{shell:!0,stdio:["ignore","pipe","pipe"]}),k="",$="";u.stdout?.on("data",l=>{let v=l.toString();if(k+=v,m){let w=v.split(`
153
+ `);for(let L of w){let x=L.match(/Executed\s+(\d+)\s+of\s+(\d+)/);if(x){let A=L.match(/(\d+)\s+FAILED/),F=A?A[1]:0,U=`\r[Lisa.ai Testing] Executed ${x[1]} of ${x[2]} (${F} FAILED) `;process.stdout.write(U)}}}}),u.stderr?.on("data",l=>{$+=l.toString()}),u.on("close",l=>{l===0?h({stdout:k,stderr:$}):f({message:`Test process exited with code ${l}`,stdout:k,stderr:$})})});try{console.log("[Lisa.ai Unit] Running tests with coverage. This may take a moment...");let c=await y(t,!0),m=c.stdout+`
154
+ `+c.stderr,h=V(m);h&&await I({projectId:i,type:"unit",filePath:"global-test-suite",modelUsed:e,status:"success",details:`Tests passed on attempt ${n}.`,testTotal:h.total,testPassed:h.passed,testFailed:h.failed,testFramework:g}),console.log(`
155
+ [Lisa.ai Unit] Tests passed on attempt ${n}.`)}catch(c){let m=(c.stderr||"")+`
156
+ `+(c.stdout||"")+`
157
+ `+(c.message||"");if(me(m,[],process.cwd())!==null){console.log(`
158
+ [Lisa.ai Unit] Tests failed. Delegating to Auto-Heal...`),await $e(t,e,1,null,s,i,void 0,o),console.log(`
159
+ [Lisa.ai Unit] Auto-Heal complete. Restarting unit analysis...`),await de(t,e,n+1,s,i,o);return}console.log(`
160
+ [Lisa.ai Unit] No failing spec detected. Tests may not exist yet \u2014 initiating Cold-Start Discovery...`)}try{let c=M.resolve(process.cwd(),"coverage/coverage-summary.json"),m=[];if(q.existsSync(c))console.log("[Lisa.ai Unit] Evaluating coverage summary..."),m=at("coverage/coverage-summary.json");else{if(console.log(`
161
+ [Lisa.ai Unit] No coverage-summary.json found. Initiating Cold-Start Discovery...`),m=W.findUntestedFiles(process.cwd(),[...lt]),m.length===0){console.log("[Lisa.ai Unit] No untested source files discovered.");return}console.log(`[Lisa.ai Unit] Discovered ${m.length} untested file(s). Generating specs...`)}if(m.length===0){console.log("[Lisa.ai Unit] 100% coverage achieved. No uncovered files remaining.");return}console.log(`[Lisa.ai Unit] Found ${m.length} file(s) below threshold:`,m);let h=m[0],f=M.resolve(process.cwd(),h),u=M.parse(f),k=[M.join(u.dir,`${u.name}.spec${u.ext}`),M.join(u.dir,`${u.name}.test${u.ext}`),M.join(u.dir,`${u.name}.spec.js`),M.join(u.dir,`${u.name}.test.js`),M.join(u.dir,`${u.name}.spec.ts`),M.join(u.dir,`${u.name}.test.ts`)],$=null,l=M.join(u.dir,`${u.name}.spec${u.ext}`);for(let x of k)if(q.existsSync(x)){l=x,$=q.readFileSync(x,"utf-8");break}let v="",w=!1,L=q.readFileSync(f,"utf-8");try{$?(console.log(`[Lisa.ai Unit] Existing spec found for ${h}. Requesting coverage append...`),v=await ze(h,L,M.relative(process.cwd(),l),$,e,o,p,d)):(console.log(`[Lisa.ai Unit] Generating new spec for ${h}...`),v=await X(h,L,e,o,p,d)),Se=0,w=!0}catch(x){Se++,lt.add(h);let A=x.cause?.message?`${x.message} (cause: ${x.cause.message})`:x.message;if(console.error(`
162
+ [Lisa.ai Unit] LLM call failed for ${h} \u2014 consecutive failure #${Se}/${De}`),console.error(` Error: ${A}`),Se>=De)throw new Error(`Systematic LLM failure: ${De} consecutive API calls failed.
145
163
  This usually means your API key has insufficient credits, hit a rate limit, or the model is unavailable.
146
- Last error: ${F}
147
- Tip: Check your API key, account credits, and rate-limit quota for provider '${e}'.`)}if(!w){await le(t,e,n+1,s,i,o);return}B.writeFileSync(p,k,"utf-8"),console.log(`[Lisa.ai Unit] Wrote spec to ${p}`),await T({projectId:i,type:"unit",filePath:h,modelUsed:e,status:"success",details:`### Unit Test Generated
164
+ Last error: ${A}
165
+ Tip: Check your API key, account credits, and rate-limit quota for provider '${e}'.`)}if(!w){await de(t,e,n+1,s,i,o);return}q.writeFileSync(l,v,"utf-8"),console.log(`[Lisa.ai Unit] Wrote spec to ${l}`),await I({projectId:i,type:"unit",filePath:h,modelUsed:e,status:"success",details:`### Unit Test Generated
148
166
  **Auto-Generated Spec (${e}):**
149
167
  \`\`\`typescript
150
- ${k}
151
- \`\`\``,testFramework:u}),await le(t,e,n+1,s,i,o)}catch(l){console.error("[Lisa.ai Unit loop failure]:",l.message),await T({projectId:i,type:"unit",filePath:"unit-loop",modelUsed:e,status:"error",details:`Unit test generation encountered an unrecoverable error: ${l.message}`,testFramework:u})}}var ce=require("child_process"),C=j(require("fs")),I=j(require("path"));function Tt(t){if(C.existsSync(I.join(t,"playwright.config.ts"))||C.existsSync(I.join(t,"playwright.config.js")))return{framework:"playwright",configFile:C.existsSync(I.join(t,"playwright.config.ts"))?"playwright.config.ts":"playwright.config.js",command:"npx playwright test",installed:!0};if(C.existsSync(I.join(t,"cypress.config.ts"))||C.existsSync(I.join(t,"cypress.config.js"))||C.existsSync(I.join(t,"cypress.json")))return{framework:"cypress",configFile:C.existsSync(I.join(t,"cypress.config.ts"))?"cypress.config.ts":C.existsSync(I.join(t,"cypress.config.js"))?"cypress.config.js":"cypress.json",command:"npx cypress run",installed:!0};let e=I.join(t,"package.json");if(C.existsSync(e)){let n=JSON.parse(C.readFileSync(e,"utf-8")),s={...n.dependencies||{},...n.devDependencies||{}};if(s["@playwright/test"])return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!0};if(s.cypress)return{framework:"cypress",configFile:null,command:"npx cypress run",installed:!0}}return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!1}}function It(t){console.log("[Lisa.ai E2E] No E2E framework detected. Installing Playwright...");try{(0,ce.execSync)("npm install -D @playwright/test",{cwd:t,stdio:"pipe"}),console.log("[Lisa.ai E2E] Playwright installed.")}catch(n){throw console.error(`[Lisa.ai E2E] Failed to install Playwright: ${n.message}`),new Error("Could not install @playwright/test. Please install it manually.")}try{console.log("[Lisa.ai E2E] Installing Playwright browsers..."),(0,ce.execSync)("npx playwright install --with-deps chromium",{cwd:t,stdio:"pipe"}),console.log("[Lisa.ai E2E] Chromium browser installed.")}catch{console.warn("[Lisa.ai E2E Warning] Browser install failed. You may need to run 'npx playwright install' manually.")}C.existsSync(I.join(t,"playwright.config.ts"))||(C.writeFileSync(I.join(t,"playwright.config.ts"),`import { defineConfig } from '@playwright/test';
152
-
153
- export default defineConfig({
154
- testDir: './e2e',
155
- fullyParallel: true,
156
- forbidOnly: !!process.env.CI,
157
- retries: process.env.CI ? 2 : 0,
158
- workers: process.env.CI ? 1 : undefined,
159
- reporter: 'html',
160
- use: {
161
- baseURL: 'http://localhost:4200',
162
- trace: 'on-first-retry',
163
- },
164
- projects: [
165
- { name: 'chromium', use: { browserName: 'chromium' } },
166
- ],
167
- });
168
- `,"utf-8"),console.log("[Lisa.ai E2E] Generated playwright.config.ts"));let e=I.join(t,"e2e");C.existsSync(e)||(C.mkdirSync(e,{recursive:!0}),console.log("[Lisa.ai E2E] Created e2e/ directory"))}function Rt(t){let e=[],n=["src/app/app.routes.ts","src/app/app-routing.module.ts"];for(let i of n){let o=I.join(t,i);if(C.existsSync(o)){let a=C.readFileSync(o,"utf-8").matchAll(/path:\s*['"`]([^'"`]+)['"`]/g);for(let d of a)d[1]&&d[1]!=="**"&&e.push(d[1])}}let s=["src/App.tsx","src/App.jsx","src/routes.tsx","src/routes.jsx"];for(let i of s){let o=I.join(t,i);if(C.existsSync(o)){let a=C.readFileSync(o,"utf-8").matchAll(/path=["']([^"']+)["']/g);for(let d of a)d[1]&&e.push(d[1])}}return[...new Set(e)].sort()}async function rt(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
169
- [Lisa.ai E2E] Reached maximum retries (${s}). Stopping.`);return}let r=process.cwd(),a=P.load(r);a&&(P.applyEnvDefaults(a),!t&&a.e2eCommand&&(t=a.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${t}`)));let d=Tt(r),c=a?.e2eFramework||d.framework;console.log(`
170
- [Lisa.ai E2E] Framework: ${c} (Attempt ${n}/${s}) Model: ${e}`),!d.installed&&c==="playwright"&&It(r),t||(t=d.command,console.log(`[Lisa.ai E2E] Using auto-detected command: ${t}`)),await T({projectId:i,type:"e2e",filePath:"e2e-suite",modelUsed:e,status:"running",details:`E2E test generation started with ${c}`,testFramework:c});let u=Rt(r);u.length===0?(console.log("[Lisa.ai E2E] No routes discovered. Will generate basic smoke test."),u.push("")):console.log(`[Lisa.ai E2E] Discovered ${u.length} route(s):`,u);let g=I.join(r,"e2e");C.existsSync(g)||C.mkdirSync(g,{recursive:!0});let l=C.existsSync(g)?C.readdirSync(g).filter(p=>p.endsWith(".spec.ts")||p.endsWith(".test.ts")):[],f=0;for(let p of u){let w=`${(p||"home").replace(/\//g,"-")}.spec.ts`,L=I.join(g,w);if(l.includes(w)){console.log(`[Lisa.ai E2E] Spec already exists for /${p} \u2014 skipping.`);continue}console.log(`[Lisa.ai E2E] Generating E2E spec for /${p}...`);try{let x=`
168
+ ${v}
169
+ \`\`\``,testFramework:g}),await de(t,e,n+1,s,i,o)}catch(c){console.error("[Lisa.ai Unit loop failure]:",c.message),await I({projectId:i,type:"unit",filePath:"unit-loop",modelUsed:e,status:"error",details:`Unit test generation encountered an unrecoverable error: ${c.message}`,testFramework:g})}}var dt=require("child_process"),D=j(require("fs")),ie=j(require("path"));function Nt(t){let e=[],n=["src/app/app.routes.ts","src/app/app-routing.module.ts"];for(let i of n){let o=ie.join(t,i);if(D.existsSync(o)){let a=D.readFileSync(o,"utf-8").matchAll(/path:\s*['"`]([^'"`]+)['"`]/g);for(let p of a)p[1]&&p[1]!=="**"&&e.push(p[1])}}let s=["src/App.tsx","src/App.jsx","src/routes.tsx","src/routes.jsx"];for(let i of s){let o=ie.join(t,i);if(D.existsSync(o)){let a=D.readFileSync(o,"utf-8").matchAll(/path=["']([^"']+)["']/g);for(let p of a)p[1]&&e.push(p[1])}}return[...new Set(e)].sort()}async function ut(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
170
+ [Lisa.ai E2E] Reached maximum retries (${s}). Stopping.`);return}let r=process.cwd(),a=T.load(r);a&&(T.applyEnvDefaults(a),!t&&a.e2eCommand&&(t=a.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${t}`)));let p=ve(r),d=a?.e2eFramework||p.framework;console.log(`
171
+ [Lisa.ai E2E] Framework: ${d} (Attempt ${n}/${s}) Model: ${e}`),!p.installed&&d==="playwright"&&xe(r),t||(t=p.command,console.log(`[Lisa.ai E2E] Using auto-detected command: ${t}`)),await I({projectId:i,type:"e2e",filePath:"e2e-suite",modelUsed:e,status:"running",details:`E2E test generation started with ${d}`,testFramework:d});let g=Nt(r);g.length===0?(console.log("[Lisa.ai E2E] No routes discovered. Will generate basic smoke test."),g.push("")):console.log(`[Lisa.ai E2E] Discovered ${g.length} route(s):`,g);let y=ie.join(r,"e2e");D.existsSync(y)||D.mkdirSync(y,{recursive:!0});let c=D.existsSync(y)?D.readdirSync(y).filter(l=>l.endsWith(".spec.ts")||l.endsWith(".test.ts")):[],m=0;for(let l of g){let w=`${(l||"home").replace(/\//g,"-")}.spec.ts`,L=ie.join(y,w);if(c.includes(w)){console.log(`[Lisa.ai E2E] Spec already exists for /${l} \u2014 skipping.`);continue}console.log(`[Lisa.ai E2E] Generating E2E spec for /${l}...`);try{let x=`
171
172
  E2E Test Generation Context:
172
- - Framework: ${c}
173
- - Route: /${p}
174
- - App Type: ${C.existsSync(I.join(r,"angular.json"))?"Angular":"Web App"}
173
+ - Framework: ${d}
174
+ - Route: /${l}
175
+ - App Type: ${D.existsSync(ie.join(r,"angular.json"))?"Angular":"Web App"}
175
176
  - Base URL: http://localhost:4200
176
177
 
177
- Generate a ${c} E2E test spec for the route "/${p}".
178
+ Generate a ${d} E2E test spec for the route "/${l}".
178
179
  The test should:
179
180
  1. Navigate to the route
180
181
  2. Verify the page loads correctly
@@ -182,26 +183,26 @@ The test should:
182
183
  4. Assert critical UI elements are visible
183
184
 
184
185
  Use @playwright/test imports. Keep it concise and practical.
185
- `,F=await Q(`e2e/${w}`,x,e,o,c,["e2e"]);C.writeFileSync(L,F,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${w}`),f++,await T({projectId:i,type:"e2e",filePath:`e2e/${w}`,modelUsed:e,status:"success",details:`Generated E2E spec for route /${p}`,testFramework:c})}catch(x){console.error(`[Lisa.ai E2E] LLM failed for /${p}: ${x.message}`),await T({projectId:i,type:"e2e",filePath:`e2e/${w}`,modelUsed:e,status:"error",details:`LLM failed to generate E2E spec: ${x.message}`,testFramework:c})}}if(f===0&&l.length===0){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}console.log(`
186
- [Lisa.ai E2E] Running E2E tests: ${t}`);let h="",m="",y=!1;try{await new Promise((p,k)=>{let w=(0,ce.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:r});w.stdout?.on("data",L=>{let x=L.toString();h+=x,process.stdout.write(x)}),w.stderr?.on("data",L=>{let x=L.toString();m+=x,process.stderr.write(x)}),w.on("close",L=>{L===0?p():k(new Error(`E2E tests exited with code ${L}`))})}),y=!0,console.log(`
186
+ `,A=await X(`e2e/${w}`,x,e,o,d,["e2e"]);D.writeFileSync(L,A,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${w}`),m++,await I({projectId:i,type:"e2e",filePath:`e2e/${w}`,modelUsed:e,status:"success",details:`Generated E2E spec for route /${l}`,testFramework:d})}catch(x){console.error(`[Lisa.ai E2E] LLM failed for /${l}: ${x.message}`),await I({projectId:i,type:"e2e",filePath:`e2e/${w}`,modelUsed:e,status:"error",details:`LLM failed to generate E2E spec: ${x.message}`,testFramework:d})}}if(m===0&&c.length===0){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}console.log(`
187
+ [Lisa.ai E2E] Running E2E tests: ${t}`);let h="",f="",u=!1;try{await new Promise((l,v)=>{let w=(0,dt.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:r});w.stdout?.on("data",L=>{let x=L.toString();h+=x,process.stdout.write(x)}),w.stderr?.on("data",L=>{let x=L.toString();f+=x,process.stderr.write(x)}),w.on("close",L=>{L===0?l():v(new Error(`E2E tests exited with code ${L}`))})}),u=!0,console.log(`
187
188
  [Lisa.ai E2E] All E2E tests passed.`)}catch{console.log(`
188
- [Lisa.ai E2E] Some E2E tests failed. Run 'lisa-agent heal --command "${t}"' to auto-fix.`)}let v=h+`
189
- `+m,$=K(v);await T({projectId:i,type:"e2e",filePath:"e2e-suite",modelUsed:e,status:y?"success":"error",details:`E2E generation complete. ${f} new spec(s) generated, ${l.length} existing.`,...$&&{testTotal:$.total,testPassed:$.passed,testFailed:$.failed},testFramework:c})}var at=require("child_process"),E=j(require("fs")),b=j(require("path"));function Mt(t){let e=b.join(t,"package.json");if(!E.existsSync(e))return"node";let n=JSON.parse(E.readFileSync(e,"utf-8")),s={...n.dependencies||{},...n.devDependencies||{}};return s["@angular/core"]?"angular":s.react?"react":s.vue?"vue":s["@nestjs/core"]?"nestjs":s.express?"express":"node"}function Dt(t,e){let n=[];if(e==="angular"){let s=b.join(t,"src","app");if(!E.existsSync(s))return n;let i=de(s,/\.(ts)$/).filter(o=>!o.includes(".spec.")&&!o.includes(".test.")&&!o.includes("node_modules"));for(let o of i){let r=E.readFileSync(o,"utf-8");if(r.includes("@Component")&&r.includes("inject(")){let a=b.relative(t,o),d=a.replace(/\.ts$/,".integration.spec.ts");if(E.existsSync(b.join(t,d)))continue;let u=[...r.matchAll(/inject\((\w+)\)/g)].map(l=>l[1]),g=[];for(let l of u){let f=de(s,new RegExp(`${Nt(l)}\\.ts$`));g.push(...f.map(h=>b.relative(t,h)))}n.push({filePath:a,relatedFiles:g,description:`Angular component+service integration: ${b.basename(o)} injects ${u.join(", ")}`})}}}else if(e==="express"||e==="nestjs"){let s=["src","server","api","routes","controllers"];for(let i of s){let o=b.join(t,i);if(!E.existsSync(o))continue;let r=de(o,/\.(controller|route|router)\.(ts|js)$/).filter(a=>!a.includes(".spec.")&&!a.includes(".test.")&&!a.includes("node_modules"));for(let a of r){let d=b.relative(t,a),c=d.replace(/\.(ts|js)$/,".integration.spec.$1");E.existsSync(b.join(t,c))||n.push({filePath:d,relatedFiles:[],description:`API endpoint integration test for ${b.basename(a)} \u2014 test with supertest against real middleware chain`})}}}else{let s=b.join(t,"src");if(E.existsSync(s)){let i=de(s,/\.(ts|js|tsx|jsx)$/).filter(o=>!o.includes(".spec.")&&!o.includes(".test.")&&!o.includes("node_modules"));for(let o of i){let a=[...E.readFileSync(o,"utf-8").matchAll(/from\s+['"]\.\.?\//g)];if(a.length>=2){let d=b.relative(t,o),c=d.replace(/\.(ts|js|tsx|jsx)$/,".integration.spec.$1");if(E.existsSync(b.join(t,c)))continue;n.push({filePath:d,relatedFiles:[],description:`Module integration: ${b.basename(o)} imports ${a.length} local modules`})}}}}return n}function de(t,e){let n=[],s=["node_modules","dist","build",".git",".angular","coverage"];if(!E.existsSync(t))return n;let i=E.readdirSync(t);for(let o of i){if(s.includes(o))continue;let r=b.join(t,o);try{E.statSync(r).isDirectory()?n.push(...de(r,e)):e.test(o)&&n.push(r)}catch{continue}}return n}function Nt(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}async function lt(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
190
- [Lisa.ai Integration] Reached maximum retries (${s}). Stopping.`);return}let r=process.cwd(),a=P.load(r);a&&(P.applyEnvDefaults(a),!t&&a.testCommand&&(t=a.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let d=Mt(r),c=q.scanRepository(),u=a?.testingFramework||(c.testingFramework!=="none"?c.testingFramework:void 0);console.log(`
191
- [Lisa.ai Integration] App: ${d}, Framework: ${u||"auto"} (Attempt ${n}/${s}) Model: ${e}`),t||(c.suggestedTestCommand?t=c.suggestedTestCommand:E.existsSync(b.join(r,"angular.json"))?t="npx ng test --no-watch --browsers=ChromeHeadless":(console.error(`
192
- [Lisa.ai Fatal Error] Could not auto-detect a test command. Please pass --command explicitly.`),process.exit(1)),console.log(`[Lisa.ai Integration] Auto-detected command: ${t}`));let g=se(t);await T({projectId:i,type:"integration",filePath:"integration-suite",modelUsed:e,status:"running",details:`Integration test generation started for ${d} app`,testFramework:g});let l=Dt(r,d);if(l.length===0){console.log("[Lisa.ai Integration] No integration targets discovered. The project may already have full integration coverage.");return}console.log(`[Lisa.ai Integration] Found ${l.length} integration target(s):`),l.forEach(p=>console.log(` - ${p.filePath}: ${p.description}`));let f=0;for(let p of l){let k=b.resolve(r,p.filePath);if(!E.existsSync(k))continue;let w=b.parse(k),L=b.join(w.dir,`${w.name}.integration.spec${w.ext}`);if(E.existsSync(L)){console.log(`[Lisa.ai Integration] Spec exists for ${p.filePath} \u2014 skipping.`);continue}console.log(`[Lisa.ai Integration] Generating integration spec for ${p.filePath}...`);let x=E.readFileSync(k,"utf-8"),F="";for(let O of p.relatedFiles.slice(0,3)){let ue=b.resolve(r,O);if(E.existsSync(ue)){let S=E.readFileSync(ue,"utf-8");F+=`
189
+ [Lisa.ai E2E] Some E2E tests failed. Run 'lisa-agent heal e2e' to auto-fix.`)}let k=h+`
190
+ `+f,$=V(k);await I({projectId:i,type:"e2e",filePath:"e2e-suite",modelUsed:e,status:u?"success":"error",details:`E2E generation complete. ${m} new spec(s) generated, ${c.length} existing.`,...$&&{testTotal:$.total,testPassed:$.passed,testFailed:$.failed},testFramework:d})}var pt=require("child_process"),E=j(require("fs")),b=j(require("path"));function Ot(t){let e=b.join(t,"package.json");if(!E.existsSync(e))return"node";let n=JSON.parse(E.readFileSync(e,"utf-8")),s={...n.dependencies||{},...n.devDependencies||{}};return s["@angular/core"]?"angular":s.react?"react":s.vue?"vue":s["@nestjs/core"]?"nestjs":s.express?"express":"node"}function Ut(t,e){let n=[];if(e==="angular"){let s=b.join(t,"src","app");if(!E.existsSync(s))return n;let i=ue(s,/\.(ts)$/).filter(o=>!o.includes(".spec.")&&!o.includes(".test.")&&!o.includes("node_modules"));for(let o of i){let r=E.readFileSync(o,"utf-8");if(r.includes("@Component")&&r.includes("inject(")){let a=b.relative(t,o),p=a.replace(/\.ts$/,".integration.spec.ts");if(E.existsSync(b.join(t,p)))continue;let g=[...r.matchAll(/inject\((\w+)\)/g)].map(c=>c[1]),y=[];for(let c of g){let m=ue(s,new RegExp(`${_t(c)}\\.ts$`));y.push(...m.map(h=>b.relative(t,h)))}n.push({filePath:a,relatedFiles:y,description:`Angular component+service integration: ${b.basename(o)} injects ${g.join(", ")}`})}}}else if(e==="express"||e==="nestjs"){let s=["src","server","api","routes","controllers"];for(let i of s){let o=b.join(t,i);if(!E.existsSync(o))continue;let r=ue(o,/\.(controller|route|router)\.(ts|js)$/).filter(a=>!a.includes(".spec.")&&!a.includes(".test.")&&!a.includes("node_modules"));for(let a of r){let p=b.relative(t,a),d=p.replace(/\.(ts|js)$/,".integration.spec.$1");E.existsSync(b.join(t,d))||n.push({filePath:p,relatedFiles:[],description:`API endpoint integration test for ${b.basename(a)} \u2014 test with supertest against real middleware chain`})}}}else{let s=b.join(t,"src");if(E.existsSync(s)){let i=ue(s,/\.(ts|js|tsx|jsx)$/).filter(o=>!o.includes(".spec.")&&!o.includes(".test.")&&!o.includes("node_modules"));for(let o of i){let a=[...E.readFileSync(o,"utf-8").matchAll(/from\s+['"]\.\.?\//g)];if(a.length>=2){let p=b.relative(t,o),d=p.replace(/\.(ts|js|tsx|jsx)$/,".integration.spec.$1");if(E.existsSync(b.join(t,d)))continue;n.push({filePath:p,relatedFiles:[],description:`Module integration: ${b.basename(o)} imports ${a.length} local modules`})}}}}return n}function ue(t,e){let n=[],s=["node_modules","dist","build",".git",".angular","coverage"];if(!E.existsSync(t))return n;let i=E.readdirSync(t);for(let o of i){if(s.includes(o))continue;let r=b.join(t,o);try{E.statSync(r).isDirectory()?n.push(...ue(r,e)):e.test(o)&&n.push(r)}catch{continue}}return n}function _t(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}async function gt(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
191
+ [Lisa.ai Integration] Reached maximum retries (${s}). Stopping.`);return}let r=process.cwd(),a=T.load(r);a&&(T.applyEnvDefaults(a),!t&&a.testCommand&&(t=a.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let p=Ot(r),d=W.scanRepository(),g=a?.testingFramework||(d.testingFramework!=="none"?d.testingFramework:void 0);console.log(`
192
+ [Lisa.ai Integration] App: ${p}, Framework: ${g||"auto"} (Attempt ${n}/${s}) Model: ${e}`),t||(d.suggestedTestCommand?t=d.suggestedTestCommand:E.existsSync(b.join(r,"angular.json"))?t="npx ng test --no-watch --browsers=ChromeHeadless":(console.error(`
193
+ [Lisa.ai Fatal Error] Could not auto-detect a test command. Please pass --command explicitly.`),process.exit(1)),console.log(`[Lisa.ai Integration] Auto-detected command: ${t}`));let y=ne(t);await I({projectId:i,type:"integration",filePath:"integration-suite",modelUsed:e,status:"running",details:`Integration test generation started for ${p} app`,testFramework:y});let c=Ut(r,p);if(c.length===0){console.log("[Lisa.ai Integration] No integration targets discovered. The project may already have full integration coverage.");return}console.log(`[Lisa.ai Integration] Found ${c.length} integration target(s):`),c.forEach(l=>console.log(` - ${l.filePath}: ${l.description}`));let m=0;for(let l of c){let v=b.resolve(r,l.filePath);if(!E.existsSync(v))continue;let w=b.parse(v),L=b.join(w.dir,`${w.name}.integration.spec${w.ext}`);if(E.existsSync(L)){console.log(`[Lisa.ai Integration] Spec exists for ${l.filePath} \u2014 skipping.`);continue}console.log(`[Lisa.ai Integration] Generating integration spec for ${l.filePath}...`);let x=E.readFileSync(v,"utf-8"),A="";for(let U of l.relatedFiles.slice(0,3)){let pe=b.resolve(r,U);if(E.existsSync(pe)){let C=E.readFileSync(pe,"utf-8");A+=`
193
194
 
194
- // --- Related file: ${O} ---
195
- ${S.slice(0,5e3)}`}}let _=`
196
- INTEGRATION TEST \u2014 ${p.description}
195
+ // --- Related file: ${U} ---
196
+ ${C.slice(0,5e3)}`}}let F=`
197
+ INTEGRATION TEST \u2014 ${l.description}
197
198
 
198
199
  Generate an integration test that exercises real module interactions (NOT mocked).
199
- ${d==="angular"?`
200
+ ${p==="angular"?`
200
201
  - Use TestBed with real service providers (not jasmine.createSpyObj)
201
202
  - Import the actual component and its real dependencies
202
203
  - Test that the component and service work together correctly
203
204
  - Use HttpClientTestingModule for HTTP calls
204
- `:d==="express"||d==="nestjs"?`
205
+ `:p==="express"||p==="nestjs"?`
205
206
  - Use supertest to make real HTTP requests against the app
206
207
  - Test the full middleware chain (auth, validation, handler)
207
208
  - Use a test database or in-memory mock for data layer
@@ -214,30 +215,30 @@ ${d==="angular"?`
214
215
  Source file:
215
216
  ${x.slice(0,1e4)}
216
217
 
217
- ${F?`Related modules:
218
- ${F}`:""}
219
- `;try{let O=await Q(p.filePath,_,e,o,u,["integration"]);E.writeFileSync(L,O,"utf-8"),console.log(`[Lisa.ai Integration] Wrote ${b.relative(r,L)}`),f++,await T({projectId:i,type:"integration",filePath:p.filePath,modelUsed:e,status:"success",details:`Generated integration spec: ${p.description}`,testFramework:g})}catch(O){console.error(`[Lisa.ai Integration] LLM failed for ${p.filePath}: ${O.message}`)}}if(f===0){console.log("[Lisa.ai Integration] No new integration specs generated.");return}console.log(`
220
- [Lisa.ai Integration] Running tests to verify generated specs: ${t}`);let h="",m="",y=!1;try{await new Promise((p,k)=>{let w=(0,at.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:r});w.stdout?.on("data",L=>{let x=L.toString();h+=x,process.stdout.write(x)}),w.stderr?.on("data",L=>{let x=L.toString();m+=x,process.stderr.write(x)}),w.on("close",L=>{L===0?p():k(new Error(`Tests exited with code ${L}`))})}),y=!0,console.log(`
218
+ ${A?`Related modules:
219
+ ${A}`:""}
220
+ `;try{let U=await X(l.filePath,F,e,o,g,["integration"]);E.writeFileSync(L,U,"utf-8"),console.log(`[Lisa.ai Integration] Wrote ${b.relative(r,L)}`),m++,await I({projectId:i,type:"integration",filePath:l.filePath,modelUsed:e,status:"success",details:`Generated integration spec: ${l.description}`,testFramework:y})}catch(U){console.error(`[Lisa.ai Integration] LLM failed for ${l.filePath}: ${U.message}`)}}if(m===0){console.log("[Lisa.ai Integration] No new integration specs generated.");return}console.log(`
221
+ [Lisa.ai Integration] Running tests to verify generated specs: ${t}`);let h="",f="",u=!1;try{await new Promise((l,v)=>{let w=(0,pt.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:r});w.stdout?.on("data",L=>{let x=L.toString();h+=x,process.stdout.write(x)}),w.stderr?.on("data",L=>{let x=L.toString();f+=x,process.stderr.write(x)}),w.on("close",L=>{L===0?l():v(new Error(`Tests exited with code ${L}`))})}),u=!0,console.log(`
221
222
  [Lisa.ai Integration] All tests passed including integration specs.`)}catch{console.log(`
222
- [Lisa.ai Integration] Some tests failed. Run 'lisa-agent heal' to auto-fix.`)}let v=h+`
223
- `+m,$=K(v);await T({projectId:i,type:"integration",filePath:"integration-suite",modelUsed:e,status:y?"success":"error",details:`Integration test generation complete. ${f} new spec(s) generated.`,...$&&{testTotal:$.total,testPassed:$.passed,testFailed:$.failed},testFramework:g})}var ut=j(require("dotenv")),pt=require("child_process"),z=j(require("fs")),V=j(require("path"));ut.config({quiet:!0});function oe(t){return new Promise(e=>{let n=(0,pt.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),s="",i="";n.stdout?.on("data",o=>{s+=o.toString()}),n.stderr?.on("data",o=>{i+=o.toString()}),n.on("close",o=>e({stdout:s,stderr:i,code:o??1}))})}function Ot(){return z.existsSync(V.resolve(process.cwd(),"pnpm-lock.yaml"))?"pnpm":z.existsSync(V.resolve(process.cwd(),"yarn.lock"))?"yarn":"npm"}var Ut={critical:"\u{1F534}",high:"\u{1F7E0}",moderate:"\u{1F7E1}",low:"\u{1F535}",info:"\u26AA"},ct={critical:5,high:4,moderate:3,low:2,info:1};function dt(t){let e=["critical","high","moderate","low","info"];for(let n of e){let s=t[n]??0;s>0&&console.log(` ${Ut[n]} ${n.padEnd(10)} ${s}`)}console.log(` ${"\u2500".repeat(22)}`),console.log(` ${"Total".padEnd(10)} ${t.total}`)}async function Ie(t){try{return JSON.parse(t)}catch{return null}}async function gt(t,e="local",n){z.existsSync(V.resolve(process.cwd(),"package.json"))||(console.error(`
224
- \u{1F6A8} [Lisa.ai Audit] No package.json found in ${process.cwd()}.`),console.error(" The audit command currently supports Node.js / npm projects only."),process.exit(1));let s=Ot();console.log(`[Lisa.ai Audit] Package manager: ${s}`),console.log(`
225
- [Lisa.ai Audit] Scanning for vulnerabilities...`);let{stdout:i,code:o}=await oe(s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json");if(o===0){console.log(`
226
- \u2705 [Lisa.ai Audit] No vulnerabilities found! Repository is clean.`);return}let r=await Ie(i);r||(console.error("[Lisa.ai Audit] Could not parse audit output. Run 'npm audit' manually to investigate."),process.exit(1));let a=r.metadata.vulnerabilities;console.log(`
227
- Vulnerabilities found:`),dt(a),console.log(`
228
- [Lisa.ai Audit] Applying safe automatic fixes (npm audit fix)...`);let{stdout:d}=await oe(s==="npm"?"npm audit fix":s==="yarn"?"yarn upgrade":"pnpm audit fix");for(let S of d.split(`
229
- `)){let D=S.trim();D&&!D.startsWith("npm warn")&&!D.startsWith("npm notice")&&console.log(` ${D}`)}let c=s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json",{stdout:u,code:g}=await oe(c);if(g===0){console.log(`
230
- \u2705 [Lisa.ai Audit] All vulnerabilities fixed by safe auto-fix!`);return}let l=await Ie(u);if(!l){console.warn("[Lisa.ai Audit] Could not parse post-fix audit output.");return}let f=Object.values(l.vulnerabilities),h=l.metadata.vulnerabilities,m=a.total-h.total;console.log(`
231
- [Lisa.ai Audit] Safe auto-fix resolved ${m} vulnerability(-ies).`),h.total>0&&(console.log(" Remaining:"),dt(h));let y=f.filter(S=>typeof S.fixAvailable=="object"&&!S.fixAvailable.isSemVerMajor).map(S=>S.fixAvailable),v=[...new Map(y.map(S=>[S.name,S])).values()];if(v.length>0){console.log(`
232
- [Lisa.ai Audit] Applying ${v.length} non-breaking targeted upgrade(s)...`);for(let J of v){let G=`npm install ${J.name}@${J.version}`;console.log(` \u2192 ${G}`);let{stderr:re}=await oe(G);re&&!re.includes("npm warn")&&console.warn(` ${re.trim()}`)}let{stdout:S,code:D}=await oe(c);if(D===0){console.log(`
233
- \u2705 [Lisa.ai Audit] All vulnerabilities resolved!`);return}}let{stdout:$}=await oe(c),p=await Ie($)??l,w=Object.values(p.vulnerabilities).sort((S,D)=>(ct[D.severity]??0)-(ct[S.severity]??0)).slice(0,10).filter(S=>S.fixAvailable===!1?!0:typeof S.fixAvailable=="object"?S.fixAvailable.isSemVerMajor:!1);if(w.length===0){console.log(`
223
+ [Lisa.ai Integration] Some tests failed. Run 'lisa-agent heal integration' to auto-fix.`)}let k=h+`
224
+ `+f,$=V(k);await I({projectId:i,type:"integration",filePath:"integration-suite",modelUsed:e,status:u?"success":"error",details:`Integration test generation complete. ${m} new spec(s) generated.`,...$&&{testTotal:$.total,testPassed:$.passed,testFailed:$.failed},testFramework:y})}var ht=j(require("dotenv")),yt=require("child_process"),Z=j(require("fs")),z=j(require("path"));ht.config({quiet:!0});function re(t){return new Promise(e=>{let n=(0,yt.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),s="",i="";n.stdout?.on("data",o=>{s+=o.toString()}),n.stderr?.on("data",o=>{i+=o.toString()}),n.on("close",o=>e({stdout:s,stderr:i,code:o??1}))})}function Gt(){return Z.existsSync(z.resolve(process.cwd(),"pnpm-lock.yaml"))?"pnpm":Z.existsSync(z.resolve(process.cwd(),"yarn.lock"))?"yarn":"npm"}var Ht={critical:"\u{1F534}",high:"\u{1F7E0}",moderate:"\u{1F7E1}",low:"\u{1F535}",info:"\u26AA"},ft={critical:5,high:4,moderate:3,low:2,info:1};function mt(t){let e=["critical","high","moderate","low","info"];for(let n of e){let s=t[n]??0;s>0&&console.log(` ${Ht[n]} ${n.padEnd(10)} ${s}`)}console.log(` ${"\u2500".repeat(22)}`),console.log(` ${"Total".padEnd(10)} ${t.total}`)}async function Ne(t){try{return JSON.parse(t)}catch{return null}}async function wt(t,e="local",n){Z.existsSync(z.resolve(process.cwd(),"package.json"))||(console.error(`
225
+ \u{1F6A8} [Lisa.ai Audit] No package.json found in ${process.cwd()}.`),console.error(" The audit command currently supports Node.js / npm projects only."),process.exit(1));let s=Gt();console.log(`[Lisa.ai Audit] Package manager: ${s}`),console.log(`
226
+ [Lisa.ai Audit] Scanning for vulnerabilities...`);let{stdout:i,code:o}=await re(s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json");if(o===0){console.log(`
227
+ \u2705 [Lisa.ai Audit] No vulnerabilities found! Repository is clean.`);return}let r=await Ne(i);r||(console.error("[Lisa.ai Audit] Could not parse audit output. Run 'npm audit' manually to investigate."),process.exit(1));let a=r.metadata.vulnerabilities;console.log(`
228
+ Vulnerabilities found:`),mt(a),console.log(`
229
+ [Lisa.ai Audit] Applying safe automatic fixes (npm audit fix)...`);let{stdout:p}=await re(s==="npm"?"npm audit fix":s==="yarn"?"yarn upgrade":"pnpm audit fix");for(let C of p.split(`
230
+ `)){let N=C.trim();N&&!N.startsWith("npm warn")&&!N.startsWith("npm notice")&&console.log(` ${N}`)}let d=s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json",{stdout:g,code:y}=await re(d);if(y===0){console.log(`
231
+ \u2705 [Lisa.ai Audit] All vulnerabilities fixed by safe auto-fix!`);return}let c=await Ne(g);if(!c){console.warn("[Lisa.ai Audit] Could not parse post-fix audit output.");return}let m=Object.values(c.vulnerabilities),h=c.metadata.vulnerabilities,f=a.total-h.total;console.log(`
232
+ [Lisa.ai Audit] Safe auto-fix resolved ${f} vulnerability(-ies).`),h.total>0&&(console.log(" Remaining:"),mt(h));let u=m.filter(C=>typeof C.fixAvailable=="object"&&!C.fixAvailable.isSemVerMajor).map(C=>C.fixAvailable),k=[...new Map(u.map(C=>[C.name,C])).values()];if(k.length>0){console.log(`
233
+ [Lisa.ai Audit] Applying ${k.length} non-breaking targeted upgrade(s)...`);for(let Q of k){let H=`npm install ${Q.name}@${Q.version}`;console.log(` \u2192 ${H}`);let{stderr:le}=await re(H);le&&!le.includes("npm warn")&&console.warn(` ${le.trim()}`)}let{stdout:C,code:N}=await re(d);if(N===0){console.log(`
234
+ \u2705 [Lisa.ai Audit] All vulnerabilities resolved!`);return}}let{stdout:$}=await re(d),l=await Ne($)??c,w=Object.values(l.vulnerabilities).sort((C,N)=>(ft[N.severity]??0)-(ft[C.severity]??0)).slice(0,10).filter(C=>C.fixAvailable===!1?!0:typeof C.fixAvailable=="object"?C.fixAvailable.isSemVerMajor:!1);if(w.length===0){console.log(`
234
235
  \u2705 [Lisa.ai Audit] No breaking-change or unfixable vulnerabilities remain.`);return}console.log(`
235
- [Lisa.ai Audit] ${w.length} vulnerability(-ies) require manual attention.`),console.log(`[Lisa.ai Audit] Consulting ${t} for remediation guidance...`);let L={};try{L=JSON.parse(z.readFileSync(V.resolve(process.cwd(),"package.json"),"utf8"))}catch{}let x={...L.dependencies??{},...L.devDependencies??{}},F=w.map(S=>{let D=S.fixAvailable,J=D===!1?"no fix available yet":`upgrade to ${D.name}@${D.version} (BREAKING \u2014 major version bump)`,G=x[S.name]?`current: ${x[S.name]}`:"transitive dependency";return`\u2022 ${S.name} (${S.severity}) \u2014 ${G} \u2014 ${J}`}).join(`
236
- `),_=`You are a Node.js security expert helping a developer fix npm vulnerabilities.
236
+ [Lisa.ai Audit] ${w.length} vulnerability(-ies) require manual attention.`),console.log(`[Lisa.ai Audit] Consulting ${t} for remediation guidance...`);let L={};try{L=JSON.parse(Z.readFileSync(z.resolve(process.cwd(),"package.json"),"utf8"))}catch{}let x={...L.dependencies??{},...L.devDependencies??{}},A=w.map(C=>{let N=C.fixAvailable,Q=N===!1?"no fix available yet":`upgrade to ${N.name}@${N.version} (BREAKING \u2014 major version bump)`,H=x[C.name]?`current: ${x[C.name]}`:"transitive dependency";return`\u2022 ${C.name} (${C.severity}) \u2014 ${H} \u2014 ${Q}`}).join(`
237
+ `),F=`You are a Node.js security expert helping a developer fix npm vulnerabilities.
237
238
 
238
239
  These vulnerabilities remain after safe auto-fixes were applied. Each requires either a breaking upgrade or has no automated fix:
239
240
 
240
- ${F}
241
+ ${A}
241
242
 
242
243
  For each vulnerability:
243
244
  1. Briefly explain the security risk (1 sentence).
@@ -245,29 +246,30 @@ For each vulnerability:
245
246
  3. If the upgrade is breaking (major version), note the most likely code change needed (e.g. renamed API, changed import path).
246
247
  4. If no fix exists, suggest a workaround or safe alternative package.
247
248
 
248
- Be concrete. Use numbered items. If a vulnerability is a transitive dependency, explain how to force a resolution override in package.json.`;try{let S=await X(_,t,n);console.log(`
249
+ Be concrete. Use numbered items. If a vulnerability is a transitive dependency, explain how to force a resolution override in package.json.`;try{let C=await ee(F,t,n);console.log(`
249
250
  Remediation guidance:
250
- `);for(let G of S.split(`
251
- `))console.log(` ${G}`);let D=V.resolve(process.cwd(),"lisa-audit-report.md"),J=["# Lisa.ai Security Audit Report","",`Generated: ${new Date().toISOString()}`,`Project: ${L.name??V.basename(process.cwd())}`,"","## Summary","","| Severity | Initial | Remaining |","|----------|---------|-----------|",...["critical","high","moderate","low"].map(G=>{let re=a[G]??0,vt=p.metadata.vulnerabilities[G]??0;return`| ${G} | ${re} | ${vt} |`}),"","## Vulnerabilities Requiring Manual Action","",F,"",`## Remediation Guidance (${t})`,"",S].join(`
252
- `);z.writeFileSync(D,J,"utf-8"),console.log(`
253
- [Lisa.ai Audit] Full report saved to: lisa-audit-report.md`)}catch(S){console.error(`
254
- [Lisa.ai Audit] LLM guidance failed: ${S.message}`),console.log(" Run 'npm audit' manually and address the remaining vulnerabilities.")}let O=p.metadata.vulnerabilities,ue=a.total-O.total;console.log(`
255
- ${"\u2500".repeat(50)}`),console.log(" Lisa.ai Audit Complete"),console.log(` \u2705 Fixed: ${ue} / ${a.total}`),console.log(` \u26A0\uFE0F Remaining: ${O.total} (see lisa-audit-report.md)`),console.log(`${"\u2500".repeat(50)}
256
- `)}var wt=ft();function ie(){console.log(`
257
- ======================================================`),console.log(` Lisa.ai Agent v${wt.version}`),console.log(" Autonomous CI/CD Platform Worker"),console.log(`======================================================
258
- `)}async function ke(t){let e=5,n=t.model,s;if(t.projectId){let o=await pe(t.projectId);if(!o.ok)o.reason==="not_found"?(console.error(`
251
+ `);for(let H of C.split(`
252
+ `))console.log(` ${H}`);let N=z.resolve(process.cwd(),"lisa-audit-report.md"),Q=["# Lisa.ai Security Audit Report","",`Generated: ${new Date().toISOString()}`,`Project: ${L.name??z.basename(process.cwd())}`,"","## Summary","","| Severity | Initial | Remaining |","|----------|---------|-----------|",...["critical","high","moderate","low"].map(H=>{let le=a[H]??0,St=l.metadata.vulnerabilities[H]??0;return`| ${H} | ${le} | ${St} |`}),"","## Vulnerabilities Requiring Manual Action","",A,"",`## Remediation Guidance (${t})`,"",C].join(`
253
+ `);Z.writeFileSync(N,Q,"utf-8"),console.log(`
254
+ [Lisa.ai Audit] Full report saved to: lisa-audit-report.md`)}catch(C){console.error(`
255
+ [Lisa.ai Audit] LLM guidance failed: ${C.message}`),console.log(" Run 'npm audit' manually and address the remaining vulnerabilities.")}let U=l.metadata.vulnerabilities,pe=a.total-U.total;console.log(`
256
+ ${"\u2500".repeat(50)}`),console.log(" Lisa.ai Audit Complete"),console.log(` \u2705 Fixed: ${pe} / ${a.total}`),console.log(` \u26A0\uFE0F Remaining: ${U.total} (see lisa-audit-report.md)`),console.log(`${"\u2500".repeat(50)}
257
+ `)}var kt=vt();function ae(){console.log(`
258
+ ======================================================`),console.log(` Lisa.ai Agent v${kt.version}`),console.log(" Autonomous CI/CD Platform Worker"),console.log(`======================================================
259
+ `)}async function Ce(t){let e=5,n=t.model,s;if(t.projectId){let o=await ge(t.projectId);if(!o.ok)o.reason==="not_found"?(console.error(`
259
260
  [Lisa.ai Agent Error] Project '${t.projectId}' 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(`
260
261
  [Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${n}, maxRetries=${e}).`);else{let r=o.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${r.modelProvider}, MaxRetries=${r.maxRetries}`),r.maxRetries<5&&console.warn(`
261
- [Lisa.ai Warning] maxRetries is ${r.maxRetries}. Consider increasing to 5+ for complex projects.`),n=r.modelProvider,e=r.maxRetries,s=r.apiKey,r.agentEnabled===!1&&(console.log("[Lisa.ai Agent] Agent is disabled by Control Plane for this project."),process.exit(1))}}let i=P.load(process.cwd());return i&&(P.applyEnvDefaults(i),!t.projectId&&i.maxRetries!==void 0&&(e=i.maxRetries),!t.projectId&&i.provider&&t.model==="gemini"&&(n=i.provider),P.printSummary(i)),{model:n,maxRetries:e,apiKey:s,projectId:t.projectId||"local"}}var Y=new mt.Command;Y.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(wt.version);Y.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").action(async t=>{ie();let e=await ke(t);await ve(t.command,e.model,1,null,e.maxRetries,e.projectId,void 0,e.apiKey)});Y.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").action(async t=>{ie();let e=await ke(t);await le(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});Y.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").action(async t=>{ie();let e=await ke(t);await rt(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});Y.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").action(async t=>{ie();let e=await ke(t);await lt(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});Y.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 t=>{ie();let e=t.model,n;if(t.projectId){let o=await pe(t.projectId);o.ok?(e=o.config.modelProvider,n=o.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${o.reason}. Using local env for API key.`)}let i={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"}[e]||e;console.log(`
262
- [Lisa.ai Diagnose] Testing ${e} \u2192 model ID: ${i}`);try{let o=await X("Reply with exactly: LISA_OK",e,n);console.log(`
262
+ [Lisa.ai Warning] maxRetries is ${r.maxRetries}. Consider increasing to 5+ for complex projects.`),n=r.modelProvider,e=r.maxRetries,s=r.apiKey,r.agentEnabled===!1&&(console.log("[Lisa.ai Agent] Agent is disabled by Control Plane for this project."),process.exit(1))}}let i=T.load(process.cwd());return i&&(T.applyEnvDefaults(i),!t.projectId&&i.maxRetries!==void 0&&(e=i.maxRetries),!t.projectId&&i.provider&&t.model==="gemini"&&(n=i.provider),T.printSummary(i)),{model:n,maxRetries:e,apiKey:s,projectId:t.projectId||"local"}}var K=new xt.Command;K.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(kt.version);K.command("heal [scope]").description("Run tests and autonomously heal all failures via LLM + Memory Engine. Scope: unit (default), e2e, integration").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").action(async(t,e)=>{ae();let n=["unit","e2e","integration"],s=t||"unit";n.includes(s)||(console.error(`
263
+ [Lisa.ai Error] Invalid heal scope '${t}'. Valid scopes: ${n.join(", ")}`),process.exit(1));let i=await Ce(e);await $e(e.command,i.model,1,null,i.maxRetries,i.projectId,void 0,i.apiKey,s)});K.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").action(async t=>{ae();let e=await Ce(t);await de(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});K.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").action(async t=>{ae();let e=await Ce(t);await ut(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});K.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").action(async t=>{ae();let e=await Ce(t);await gt(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});K.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 t=>{ae();let e=t.model,n;if(t.projectId){let o=await ge(t.projectId);o.ok?(e=o.config.modelProvider,n=o.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${o.reason}. Using local env for API key.`)}let i={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"}[e]||e;console.log(`
264
+ [Lisa.ai Diagnose] Testing ${e} \u2192 model ID: ${i}`);try{let o=await ee("Reply with exactly: LISA_OK",e,n);console.log(`
263
265
  [Lisa.ai Diagnose] ${e} is working correctly.`),console.log(` Model response: "${o}"`)}catch(o){console.error(`
264
266
  [Lisa.ai Diagnose] ${e} call FAILED.`),console.error(` Error: ${o.message}`),o.cause&&console.error(` Cause: ${o.cause?.message??o.cause}`),console.error(`
265
- Common causes:`),console.error(" - API key is invalid, expired, or has no credits"),console.error(" - Model ID is deprecated (current: claude-sonnet-4-6, gemini-2.0-flash, gpt-4o-mini)"),console.error(" - Rate limit exceeded \u2014 wait a minute and retry"),console.error(" - Network/proxy issue blocking api.anthropic.com"),process.exit(1)}});Y.command("init").description("Interactively create a .lisai.json config file in the current project").option("--force","Overwrite existing .lisai.json if it exists").action(async t=>{let e=ht.resolve(process.cwd(),Z);$e.existsSync(e)&&!t.force&&(console.error(`
266
- [Lisa.ai Init] ${Z} already exists. Use --force to overwrite.`),process.exit(1));let n=yt.createInterface({input:process.stdin,output:process.stdout}),s=(l,f="")=>new Promise(h=>n.question(f?`${l} [${f}]: `:`${l}: `,m=>h(m.trim()||f)));console.log(`
267
+ Common causes:`),console.error(" - API key is invalid, expired, or has no credits"),console.error(" - Model ID is deprecated (current: claude-sonnet-4-6, gemini-2.0-flash, gpt-4o-mini)"),console.error(" - Rate limit exceeded \u2014 wait a minute and retry"),console.error(" - Network/proxy issue blocking api.anthropic.com"),process.exit(1)}});K.command("init").description("Interactively create a .lisai.json config file in the current project").option("--force","Overwrite existing .lisai.json if it exists").action(async t=>{let e=Lt.resolve(process.cwd(),J);je.existsSync(e)&&!t.force&&(console.error(`
268
+ [Lisa.ai Init] ${J} already exists. Use --force to overwrite.`),process.exit(1));let n=$t.createInterface({input:process.stdin,output:process.stdout}),s=(c,m="")=>new Promise(h=>n.question(m?`${c} [${m}]: `:`${c}: `,f=>h(f.trim()||m)));console.log(`
267
269
  Lisa.ai Project Setup \u2014 press Enter to accept the default shown in [ ]
268
- `);let i=await s("LLM provider (gemini / claude / openai)","gemini"),o=await s("Testing framework (jest / vitest / mocha / karma / jasmine \u2014 leave empty to auto-detect)",""),r=await s("E2E framework (playwright / cypress \u2014 leave empty for Playwright default)",""),a=await s("Test types to generate (unit / integration / e2e \u2014 comma-separated)","unit"),d=await s("Test command (leave empty for auto-discovery)",""),c=await s("E2E command (leave empty for auto-discovery)",""),u=await s("Max heal retries","5");n.close();let g={provider:i,testTypes:a.split(",").map(l=>l.trim()).filter(Boolean),maxRetries:parseInt(u,10)||5,skipFiles:[],skipDirs:[],skipPaths:[]};o&&(g.testingFramework=o),r&&(g.e2eFramework=r),d&&(g.testCommand=d),c&&(g.e2eCommand=c),$e.writeFileSync(e,JSON.stringify(g,null,2)+`
270
+ `);let i=await s("LLM provider (gemini / claude / openai)","gemini"),o=await s("Testing framework (jest / vitest / mocha / karma / jasmine \u2014 leave empty to auto-detect)",""),r=await s("E2E framework (playwright / cypress \u2014 leave empty for Playwright default)",""),a=await s("Test types to generate (unit / integration / e2e \u2014 comma-separated)","unit"),p=await s("Test command (leave empty for auto-discovery)",""),d=await s("E2E command (leave empty for auto-discovery)",""),g=await s("Max heal retries","5");n.close();let y={provider:i,testTypes:a.split(",").map(c=>c.trim()).filter(Boolean),maxRetries:parseInt(g,10)||5,skipFiles:[],skipDirs:[],skipPaths:[]};o&&(y.testingFramework=o),r&&(y.e2eFramework=r),p&&(y.testCommand=p),d&&(y.e2eCommand=d),je.writeFileSync(e,JSON.stringify(y,null,2)+`
269
271
  `,"utf-8"),console.log(`
270
- Created ${Z}:
271
- `),console.log(JSON.stringify(g,null,2)),console.log(`
272
+ Created ${J}:
273
+ `),console.log(JSON.stringify(y,null,2)),console.log(`
272
274
  Tip: add "model" to pin a specific model ID (e.g. "claude-sonnet-4-6").`),console.log(` Edit skipFiles / skipDirs / skipPaths to exclude files from test analysis.
273
- `)});Y.command("audit").description("Scan for npm vulnerabilities and auto-fix where safe; consult LLM for manual fixes").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").action(async t=>{ie();let e=t.model,n;if(t.projectId){let s=await pe(t.projectId);s.ok?(e=s.config.modelProvider,n=s.config.apiKey,console.log(`[Lisa.ai Audit] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Audit] Control Plane ${s.reason}. Using local env for API key.`)}await gt(e,t.projectId||"local",n)});Y.parse(process.argv);
275
+ `)});K.command("audit").description("Scan for npm vulnerabilities and auto-fix where safe; consult LLM for manual fixes").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").action(async t=>{ae();let e=t.model,n;if(t.projectId){let s=await ge(t.projectId);s.ok?(e=s.config.modelProvider,n=s.config.apiKey,console.log(`[Lisa.ai Audit] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Audit] Control Plane ${s.reason}. Using local env for API key.`)}await wt(e,t.projectId||"local",n)});K.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lisa.ai/agent",
3
- "version": "2.7.2",
3
+ "version": "2.8.0",
4
4
  "description": "Lisa.ai Autonomous CI/CD Worker Agent",
5
5
  "main": "dist/index.js",
6
6
  "bin": {