@lisa.ai/agent 2.9.5 → 2.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +73 -73
  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 jt=Object.create;var _e=Object.defineProperty;var Et=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var At=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var It=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Tt=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ft(t))!Pt.call(e,o)&&o!==s&&_e(e,o,{get:()=>t[o],enumerable:!(n=Et(t,o))||n.enumerable});return e};var b=(e,t,s)=>(s=e!=null?jt(At(e)):{},Tt(t||!e||!e.__esModule?_e(s,"default",{value:e,enumerable:!0}):s,e));var Lt=It((tn,Kt)=>{Kt.exports={name:"@lisa.ai/agent",version:"2.9.5",description:"Lisa.ai Autonomous CI/CD Worker Agent",main:"dist/index.js",bin:{"lisa-agent":"dist/index.js"},files:["dist/"],scripts:{build:"tsup",typecheck:"tsc --noEmit",start:"node dist/index.js",dev:"ts-node src/index.ts",prepublishOnly:"npm run typecheck && npm run build"},keywords:["lisa","ci","cd","agent"],author:"Lisa.ai",license:"ISC",dependencies:{"@ai-sdk/anthropic":"^3.0.46","@ai-sdk/google":"^3.0.30","@ai-sdk/openai":"^3.0.30","@octokit/rest":"^22.0.1",ai:"^6.0.94",commander:"^11.1.0",dotenv:"^17.3.1","simple-git":"^3.31.1"},devDependencies:{"@types/jest":"^30.0.0","@types/node":"^20.0.0","ts-node":"^10.9.1",tsup:"^8.5.1",typescript:"^5.0.0"}}});var kt=require("commander"),X=b(require("fs")),he=b(require("path")),Ct=b(require("readline"));var Oe=b(require("dotenv"));Oe.config({quiet:!0});async function ye(e){let t=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{let s=`${t}/api/v1/lisa/config/${e}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${s}...`);let n=await fetch(s);if(!n.ok){let i=n.status===404?"not_found":"unreachable";return console.warn(i==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${e}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${n.status}. Falling back to local defaults.`),{ok:!1,reason:i}}return{ok:!0,config:await n.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${t}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var rt=require("child_process"),H=b(require("fs")),Z=b(require("path"));var S=b(require("path")),R=b(require("fs"));function we(e){return e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function Y(e){let t=we(e),s=[...t.matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(s.length>0){let g=[...s].reverse().find(f=>f[3]!==void 0)??s[s.length-1],d=parseInt(g[2]),x=g[3]?parseInt(g[3]):0,h=parseInt(g[1])-x;return{total:d,passed:h,failed:x}}let n=t.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+passed,?\s*)?(\d+)\s+total/);if(n){let g=parseInt(n[3]),d=n[1]?parseInt(n[1]):0,x=n[2]?parseInt(n[2]):0;return{total:g,passed:x,failed:d}}let o=t.match(/(\d+)\s+failed/),i=t.match(/(\d+)\s+passed/);if(i||o){let g=o?parseInt(o[1]):0,d=i?parseInt(i[1]):0,x=t.match(/(\d+)\s+skipped/),h=x?parseInt(x[1]):0;return{total:d+g+h,passed:d,failed:g}}let r=t.match(/Tests\s+(?:(\d+)\s+failed\s*\|?\s*)?(\d+)\s+passed\s*\((\d+)\)/);if(r){let g=parseInt(r[3]),d=r[1]?parseInt(r[1]):0,x=parseInt(r[2]);return{total:g,passed:x,failed:d}}let a=t.match(/(\d+)\s+passing/),u=t.match(/(\d+)\s+failing/);if(a){let g=parseInt(a[1]),d=u?parseInt(u[1]):0;return{total:g+d,passed:g,failed:d}}return null}function Ee(e,t=process.cwd(),s=[]){let n=e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=s.map(l=>S.resolve(t,l)),i=new Map,r=new Set,a=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,u;for(;(u=a.exec(n))!==null;){let p=u[1].trim().split(" ");for(let c=1;c<Math.min(p.length,6);c++){let k=p.slice(0,c).join(" ");if(r.has(k))continue;r.add(k);let $=Fe(k,t,o);if($){let m=S.resolve($);i.has(m)||i.set(m,S.relative(t,$));break}}}let g=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,d;for(;(d=g.exec(n))!==null;){let l=d[1],p=S.isAbsolute(l)?l:S.resolve(t,l);!o.includes(p)&&R.existsSync(p)&&!i.has(p)&&i.set(p,S.relative(t,p))}let x=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,h;for(;(h=x.exec(n))!==null;){let l=h[1],p=S.isAbsolute(l)?l:S.resolve(t,l);!o.includes(p)&&R.existsSync(p)&&!i.has(p)&&i.set(p,S.relative(t,p))}let f=/Running:\s+([^\s]+\.(?:cy|spec|test)\.[tj]sx?)/g,w;for(;(w=f.exec(n))!==null;){let l=w[1],p=S.isAbsolute(l)?l:S.resolve(t,l);if(!o.includes(p)&&R.existsSync(p)&&!i.has(p)){let c=l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");new RegExp(c+"\\s+\\d+\\s+\\d+\\s+([1-9]\\d*)").test(n)&&i.set(p,S.relative(t,p))}}return[...i.values()]}function ve(e,t=[],s=process.cwd()){let n=e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=t.map(l=>S.resolve(l));{let l=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,p=new Set,c;for(;(c=l.exec(n))!==null;){let $=c[1].trim().split(" ");for(let m=1;m<Math.min($.length,5);m++){let y=$.slice(0,m).join(" ");if(p.has(y))continue;p.add(y);let v=Fe(y,s,o);if(v)return S.relative(s,v)}}}let i=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))(?:\s*[:(])/g,r;for(;(r=i.exec(n))!==null;){let l=r[1];if(l){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(l))continue;let p=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(p)&&R.existsSync(p))return l}}let a=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,u;for(;(u=a.exec(n))!==null;){let l=u[1],p=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(p)&&R.existsSync(p))return l}{let l=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,p;for(;(p=l.exec(n))!==null;){let c=p[1],k=S.isAbsolute(c)?c:S.resolve(s,c);if(!o.includes(k)&&R.existsSync(k))return c}}let g=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,d;for(;(d=g.exec(n))!==null;){let l=d[1];if(l){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(l))continue;let p=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(p)&&R.existsSync(p))return l}}let x=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,h,f=new Set,w=["Error","TypeError","SyntaxError","ReferenceError","RangeError","Object","Boolean","String","Number","Array","NullInjectorError","NullInjector","R3Injector","ChainedInjector","Module","Component","Standalone","Application","App2","TestBed","UserContext","Chrome","ChromeHeadless","Karma","Launching","Starting","Headless","Connected","Executed","INFO","SUCCESS","FAILED","Building","Initial","Names","Lazy","Source","Find","NotFound","NG0201","Windows","Linux","Macintosh","Users","AppData","Local","Temp","Process","Unexpected","Expected","Validation","Directory","Configuration","Documentation"];for(;(h=x.exec(n))!==null;){let l=h[1];if(!l||w.includes(l)||f.has(l)||/^[A-Z][A-Z0-9]{5,11}$/.test(l)||/^[A-Za-z0-9]{16,}$/.test(l))continue;f.add(l);let p=Ge(l,s,o);if(p)return S.relative(s,p)}return null}function Fe(e,t,s){if(!R.existsSync(t))return null;let n=R.readdirSync(t);for(let o of n){let i=S.join(t,o);if(["node_modules","dist","build",".git",".angular"].includes(o))continue;let r;try{r=R.statSync(i)}catch{continue}if(r.isDirectory()){let a=Fe(e,i,s);if(a)return a}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(o)){if(s.includes(S.resolve(i)))continue;try{let a=R.readFileSync(i,"utf8");if(a.includes(`describe('${e}'`)||a.includes(`describe("${e}"`))return i}catch{continue}}}return null}function Ge(e,t,s){if(!R.existsSync(t))return null;let n=R.readdirSync(t);for(let o of n){let i=S.join(t,o);if(o==="node_modules"||o==="dist"||o==="build"||o===".git"||o===".angular")continue;let r;try{r=R.statSync(i)}catch{continue}if(r.isDirectory()){let a=Ge(e,i,s);if(a)return a}else if(o.match(/\.(ts|tsx|js|jsx|vue)$/)){let a=R.readFileSync(i,"utf8");if(a.includes(`class ${e}`)||a.includes(`function ${e}`)||a.includes(`const ${e}`)||a.includes(`let ${e}`)||a.includes(`exports.${e}`)||a.includes(`module.exports.${e}`)){let u=i,g=S.extname(i),d=i.slice(0,-g.length);if(!o.includes(".spec.")&&!o.includes(".test.")){let x=[`${d}.spec${g}`,`${d}.test${g}`,`${d}.spec.js`,`${d}.test.js`];for(let h of x)if(R.existsSync(h)){u=h;break}}if(!s.includes(S.resolve(u)))return u}}}return null}var pe=require("ai"),He=require("@ai-sdk/openai"),qe=require("@ai-sdk/anthropic"),Be=require("@ai-sdk/google"),Ye=b(require("dotenv"));Ye.config({quiet:!0});var Ae=15e3;function Ke(e,t){return e.length<=Ae?e:(console.warn(`[Lisa.ai LLM] ${t} is ${e.length} chars \u2014 truncating to ${Ae} to stay within context window.`),e.slice(0,Ae)+`
2
+ "use strict";var jt=Object.create;var _e=Object.defineProperty;var Et=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var At=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var It=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Tt=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ft(t))!Pt.call(e,o)&&o!==s&&_e(e,o,{get:()=>t[o],enumerable:!(n=Et(t,o))||n.enumerable});return e};var b=(e,t,s)=>(s=e!=null?jt(At(e)):{},Tt(t||!e||!e.__esModule?_e(s,"default",{value:e,enumerable:!0}):s,e));var Lt=It((tn,Kt)=>{Kt.exports={name:"@lisa.ai/agent",version:"2.9.6",description:"Lisa.ai Autonomous CI/CD Worker Agent",main:"dist/index.js",bin:{"lisa-agent":"dist/index.js"},files:["dist/"],scripts:{build:"tsup",typecheck:"tsc --noEmit",start:"node dist/index.js",dev:"ts-node src/index.ts",prepublishOnly:"npm run typecheck && npm run build"},keywords:["lisa","ci","cd","agent"],author:"Lisa.ai",license:"ISC",dependencies:{"@ai-sdk/anthropic":"^3.0.46","@ai-sdk/google":"^3.0.30","@ai-sdk/openai":"^3.0.30","@octokit/rest":"^22.0.1",ai:"^6.0.94",commander:"^11.1.0",dotenv:"^17.3.1","simple-git":"^3.31.1"},devDependencies:{"@types/jest":"^30.0.0","@types/node":"^20.0.0","ts-node":"^10.9.1",tsup:"^8.5.1",typescript:"^5.0.0"}}});var kt=require("commander"),X=b(require("fs")),he=b(require("path")),Ct=b(require("readline"));var Oe=b(require("dotenv"));Oe.config({quiet:!0});async function ye(e){let t=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{let s=`${t}/api/v1/lisa/config/${e}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${s}...`);let n=await fetch(s);if(!n.ok){let i=n.status===404?"not_found":"unreachable";return console.warn(i==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${e}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${n.status}. Falling back to local defaults.`),{ok:!1,reason:i}}return{ok:!0,config:await n.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${t}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var rt=require("child_process"),H=b(require("fs")),Z=b(require("path"));var S=b(require("path")),R=b(require("fs"));function we(e){return e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function Y(e){let t=we(e),s=[...t.matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(s.length>0){let g=[...s].reverse().find(f=>f[3]!==void 0)??s[s.length-1],d=parseInt(g[2]),x=g[3]?parseInt(g[3]):0,h=parseInt(g[1])-x;return{total:d,passed:h,failed:x}}let n=t.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+passed,?\s*)?(\d+)\s+total/);if(n){let g=parseInt(n[3]),d=n[1]?parseInt(n[1]):0,x=n[2]?parseInt(n[2]):0;return{total:g,passed:x,failed:d}}let o=t.match(/(\d+)\s+failed/),i=t.match(/(\d+)\s+passed/);if(i||o){let g=o?parseInt(o[1]):0,d=i?parseInt(i[1]):0,x=t.match(/(\d+)\s+skipped/),h=x?parseInt(x[1]):0;return{total:d+g+h,passed:d,failed:g}}let r=t.match(/Tests\s+(?:(\d+)\s+failed\s*\|?\s*)?(\d+)\s+passed\s*\((\d+)\)/);if(r){let g=parseInt(r[3]),d=r[1]?parseInt(r[1]):0,x=parseInt(r[2]);return{total:g,passed:x,failed:d}}let a=t.match(/(\d+)\s+passing/),p=t.match(/(\d+)\s+failing/);if(a){let g=parseInt(a[1]),d=p?parseInt(p[1]):0;return{total:g+d,passed:g,failed:d}}return null}function Fe(e,t=process.cwd(),s=[]){let n=e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=s.map(l=>S.resolve(t,l)),i=new Map,r=new Set,a=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,p;for(;(p=a.exec(n))!==null;){let u=p[1].trim().split(" ");for(let c=1;c<Math.min(u.length,6);c++){let L=u.slice(0,c).join(" ");if(r.has(L))continue;r.add(L);let $=Ae(L,t,o);if($){let m=S.resolve($);i.has(m)||i.set(m,S.relative(t,$));break}}}let g=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,d;for(;(d=g.exec(n))!==null;){let l=d[1],u=S.isAbsolute(l)?l:S.resolve(t,l);!o.includes(u)&&R.existsSync(u)&&!i.has(u)&&i.set(u,S.relative(t,u))}let x=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,h;for(;(h=x.exec(n))!==null;){let l=h[1],u=S.isAbsolute(l)?l:S.resolve(t,l);!o.includes(u)&&R.existsSync(u)&&!i.has(u)&&i.set(u,S.relative(t,u))}let f=/Running:\s+([^\s]+\.(?:cy|spec|test)\.[tj]sx?)/g,w;for(;(w=f.exec(n))!==null;){let l=w[1],u=S.isAbsolute(l)?l:S.resolve(t,l);if(!o.includes(u)&&R.existsSync(u)&&!i.has(u)){let c=l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");new RegExp(c+"\\s+\\d+\\s+\\d+\\s+([1-9]\\d*)").test(n)&&i.set(u,S.relative(t,u))}}return[...i.values()]}function ve(e,t=[],s=process.cwd()){let n=e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=t.map(l=>S.resolve(l));{let l=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,u=new Set,c;for(;(c=l.exec(n))!==null;){let $=c[1].trim().split(" ");for(let m=1;m<Math.min($.length,5);m++){let y=$.slice(0,m).join(" ");if(u.has(y))continue;u.add(y);let v=Ae(y,s,o);if(v)return S.relative(s,v)}}}let i=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))(?:\s*[:(])/g,r;for(;(r=i.exec(n))!==null;){let l=r[1];if(l){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(l))continue;let u=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(u)&&R.existsSync(u))return l}}let a=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,p;for(;(p=a.exec(n))!==null;){let l=p[1],u=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(u)&&R.existsSync(u))return l}{let l=/\[(?:chromium|firefox|webkit)\]\s+[>›]\s+([^\s:]+\.(?:spec|test)\.[tj]sx?):\d+:\d+\s+[>›]/g,u;for(;(u=l.exec(n))!==null;){let c=u[1],L=S.isAbsolute(c)?c:S.resolve(s,c);if(!o.includes(L)&&R.existsSync(L))return c}}let g=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,d;for(;(d=g.exec(n))!==null;){let l=d[1];if(l){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(l))continue;let u=S.isAbsolute(l)?l:S.resolve(s,l);if(!o.includes(u)&&R.existsSync(u))return l}}let x=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,h,f=new Set,w=["Error","TypeError","SyntaxError","ReferenceError","RangeError","Object","Boolean","String","Number","Array","NullInjectorError","NullInjector","R3Injector","ChainedInjector","Module","Component","Standalone","Application","App2","TestBed","UserContext","Chrome","ChromeHeadless","Karma","Launching","Starting","Headless","Connected","Executed","INFO","SUCCESS","FAILED","Building","Initial","Names","Lazy","Source","Find","NotFound","NG0201","Windows","Linux","Macintosh","Users","AppData","Local","Temp","Process","Unexpected","Expected","Validation","Directory","Configuration","Documentation"];for(;(h=x.exec(n))!==null;){let l=h[1];if(!l||w.includes(l)||f.has(l)||/^[A-Z][A-Z0-9]{5,11}$/.test(l)||/^[A-Za-z0-9]{16,}$/.test(l))continue;f.add(l);let u=Ge(l,s,o);if(u)return S.relative(s,u)}return null}function Ae(e,t,s){if(!R.existsSync(t))return null;let n=R.readdirSync(t);for(let o of n){let i=S.join(t,o);if(["node_modules","dist","build",".git",".angular"].includes(o))continue;let r;try{r=R.statSync(i)}catch{continue}if(r.isDirectory()){let a=Ae(e,i,s);if(a)return a}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(o)){if(s.includes(S.resolve(i)))continue;try{let a=R.readFileSync(i,"utf8");if(a.includes(`describe('${e}'`)||a.includes(`describe("${e}"`))return i}catch{continue}}}return null}function Ge(e,t,s){if(!R.existsSync(t))return null;let n=R.readdirSync(t);for(let o of n){let i=S.join(t,o);if(o==="node_modules"||o==="dist"||o==="build"||o===".git"||o===".angular")continue;let r;try{r=R.statSync(i)}catch{continue}if(r.isDirectory()){let a=Ge(e,i,s);if(a)return a}else if(o.match(/\.(ts|tsx|js|jsx|vue)$/)){let a=R.readFileSync(i,"utf8");if(a.includes(`class ${e}`)||a.includes(`function ${e}`)||a.includes(`const ${e}`)||a.includes(`let ${e}`)||a.includes(`exports.${e}`)||a.includes(`module.exports.${e}`)){let p=i,g=S.extname(i),d=i.slice(0,-g.length);if(!o.includes(".spec.")&&!o.includes(".test.")){let x=[`${d}.spec${g}`,`${d}.test${g}`,`${d}.spec.js`,`${d}.test.js`];for(let h of x)if(R.existsSync(h)){p=h;break}}if(!s.includes(S.resolve(p)))return p}}}return null}var pe=require("ai"),He=require("@ai-sdk/openai"),qe=require("@ai-sdk/anthropic"),Be=require("@ai-sdk/google"),Ye=b(require("dotenv"));Ye.config({quiet:!0});var Pe=15e3;function Ke(e,t){return e.length<=Pe?e:(console.warn(`[Lisa.ai LLM] ${t} is ${e.length} chars \u2014 truncating to ${Pe} to stay within context window.`),e.slice(0,Pe)+`
3
3
 
4
4
  // ... (truncated)`)}function Ve(e,t){if(!/\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/.test(e))throw new Error(`LLM returned a non-code response for ${t} (possible context overflow). Skipping to prevent file corruption.`)}function We(e){if(!e||e.length===0)return"";let t={unit:"unit tests \u2014 test every function/method in complete isolation, mocking ALL external dependencies, services, and I/O",integration:"integration tests \u2014 test how modules work together using real service/repository layers; for HTTP routes use supertest or equivalent",e2e:"end-to-end tests \u2014 simulate complete user flows using the configured e2e framework (Playwright/Cypress); cover the full path from HTTP request to response or UI action to assertion"};return`5. Test scope \u2014 generate ALL of the following test types for this file:
5
5
  ${e.map(n=>` \u2022 ${t[n]??n}`).join(`
6
6
  `)}
7
- `}function xe(e,t){if(e==="claude"){let o=t||process.env.ANTHROPIC_API_KEY;if(!o)throw new Error("No Anthropic API key provided by local ENV or Control Plane");let i=process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5";return(0,qe.createAnthropic)({apiKey:o})(i)}if(e==="openai"){let o=t||process.env.OPENAI_API_KEY;if(!o)throw new Error("No OpenAI API key provided by local ENV or Control Plane");let i=process.env.LISA_OPENAI_MODEL||"gpt-4o-mini";return(0,He.createOpenAI)({apiKey:o})(i)}let s=t||process.env.GOOGLE_GENERATIVE_AI_API_KEY;if(!s)throw new Error("No Google API key provided by local ENV or Control Plane");let n=process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash";return(0,Be.createGoogleGenerativeAI)({apiKey:s})(n)}async function ze(e,t,s,n,o,i,r,a){console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${n} for ${e}...`);let u=xe(n,o),g=`You are Lisa.ai, an autonomous CI/CD expert platform.
7
+ `}function xe(e,t){if(e==="claude"){let o=t||process.env.ANTHROPIC_API_KEY;if(!o)throw new Error("No Anthropic API key provided by local ENV or Control Plane");let i=process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5";return(0,qe.createAnthropic)({apiKey:o})(i)}if(e==="openai"){let o=t||process.env.OPENAI_API_KEY;if(!o)throw new Error("No OpenAI API key provided by local ENV or Control Plane");let i=process.env.LISA_OPENAI_MODEL||"gpt-4o-mini";return(0,He.createOpenAI)({apiKey:o})(i)}let s=t||process.env.GOOGLE_GENERATIVE_AI_API_KEY;if(!s)throw new Error("No Google API key provided by local ENV or Control Plane");let n=process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash";return(0,Be.createGoogleGenerativeAI)({apiKey:s})(n)}async function ze(e,t,s,n,o,i,r,a){console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${n} for ${e}...`);let p=xe(n,o),g=`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 ---
@@ -45,14 +45,14 @@ 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
  `+i+`
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:d}=await(0,pe.generateText)({model:u,prompt:g}),x=d.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return x?x[1].trim():d.trim()}async function ee(e,t,s,n,o,i){console.log(`[Lisa.ai Coverage] Requesting test generation from ${s} for ${e}...`);let r=xe(s,n),a=o?`3. You MUST use the '${o}' testing framework exclusively. All imports, describe/it/test blocks, and mock utilities must follow '${o}' 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:d}=await(0,pe.generateText)({model:p,prompt:g}),x=d.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return x?x[1].trim():d.trim()}async function ee(e,t,s,n,o,i){console.log(`[Lisa.ai Coverage] Requesting test generation from ${s} for ${e}...`);let r=xe(s,n),a=o?`3. You MUST use the '${o}' testing framework exclusively. All imports, describe/it/test blocks, and mock utilities must follow '${o}' conventions.
49
49
  `:`3. Include all necessary imports assuming a standard testing framework (Jest/Karma/Vitest) is available.
50
- `,u=We(i),g=`You are Lisa.ai, an autonomous CI/CD expert platform.
50
+ `,p=We(i),g=`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 (`+e+`) ---
54
54
  `+Ke(t,e)+"\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
- `+u,{text:d}=await(0,pe.generateText)({model:r,prompt:g}),x=d.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),h=x?x[1].trim():d.trim();return Ve(h,e),h}async function Ze(e,t,s,n,o,i,r,a){console.log(`[Lisa.ai Coverage] Requesting test update from ${o} for ${e}...`);let u=xe(o,i),g=r?`3. You MUST use the '${r}' testing framework exclusively. All new tests must follow '${r}' conventions and integrate cleanly with the existing suite.
55
+ `+p,{text:d}=await(0,pe.generateText)({model:r,prompt:g}),x=d.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),h=x?x[1].trim():d.trim();return Ve(h,e),h}async function Ze(e,t,s,n,o,i,r,a){console.log(`[Lisa.ai Coverage] Requesting test update from ${o} for ${e}...`);let p=xe(o,i),g=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
57
  `,d=We(a),x=`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.
@@ -62,7 +62,7 @@ A source file lacks 100% test coverage. You must update its existing test suite
62
62
 
63
63
  --- Existing Test Suite (`+s+`) ---
64
64
  `+n+"\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"+g+`4. Aim for 100% logic coverage across branches, lines, and functions.
65
- `+d,{text:h}=await(0,pe.generateText)({model:u,prompt:x}),f=h.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),w=f?f[1].trim():h.trim();return Ve(w,e),w}async function ie(e,t,s){let n=xe(t,s),{text:o}=await(0,pe.generateText)({model:n,prompt:e}),i=o.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return i?i[1].trim():o.trim()}var Je=b(require("fs")),Qe=b(require("simple-git")),Xe=require("@octokit/rest"),Xt=require("dotenv/config");function Rt(e){let t=e.healedFiles.map(o=>`- \`${o}\``).join(`
65
+ `+d,{text:h}=await(0,pe.generateText)({model:p,prompt:x}),f=h.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),w=f?f[1].trim():h.trim();return Ve(w,e),w}async function ie(e,t,s){let n=xe(t,s),{text:o}=await(0,pe.generateText)({model:n,prompt:e}),i=o.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return i?i[1].trim():o.trim()}var Je=b(require("fs")),Qe=b(require("simple-git")),Xe=require("@octokit/rest"),Xt=require("dotenv/config");function Rt(e){let t=e.healedFiles.map(o=>`- \`${o}\``).join(`
66
66
  `),s=e.quarantinedFiles.length>0?e.quarantinedFiles.map(o=>`- \`${o}\``).join(`
67
67
  `):"_None \u2014 all failures healed successfully._",n=e.testCounts?["| Metric | Before | After (est.) |","|---|---|---|",`| Passing | ${e.testCounts.passed} | ~${e.testCounts.passed+e.healedFiles.length} |`,`| Failing | ${e.testCounts.failed} | ~${Math.max(0,e.testCounts.failed-e.healedFiles.length)} |`,`| Total | ${e.testCounts.total} | ${e.testCounts.total} |`].join(`
68
68
  `):"_Test counts not available._";return`## Lisa.ai Auto-Heal Report
@@ -82,12 +82,12 @@ ${n}
82
82
  ---
83
83
 
84
84
  > This PR was generated automatically by [Lisa.ai](https://www.npmjs.com/package/@lisa.ai/agent).
85
- > Please review the changes before merging.`}async function et(e){if(e.healedFiles.length===0)return console.log("[Lisa.ai CI] No files were healed. Skipping PR creation."),null;let t=process.env.GITHUB_TOKEN,s=process.env.GITHUB_REPOSITORY;if(!t||!s)return console.log("[Lisa.ai CI] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping PR creation."),null;let n=(0,Qe.default)(),i=`lisa-fix/auto-heal-${Date.now()}`,r=process.env.GITHUB_REF_NAME||"main";try{await n.addConfig("user.name","Lisa.ai"),await n.addConfig("user.email","lisa@lisa.ai"),await n.checkoutLocalBranch(i),await n.add(e.healedFiles);let a=e.healedFiles.length===1?`fix: Lisa.ai auto-healed ${e.healedFiles[0]}`:`fix: Lisa.ai auto-healed ${e.healedFiles.length} failing test specs`;await n.commit(a),console.log(`[Lisa.ai CI] Committed ${e.healedFiles.length} file(s) to branch ${i}`),await n.push("origin",i,{"--set-upstream":null}),console.log("[Lisa.ai CI] Pushed branch to origin.");let[u,g]=s.split("/"),x=await new Xe.Octokit({auth:t}).rest.pulls.create({owner:u,repo:g,title:a,body:Rt(e),head:i,base:r});return console.log(`[Lisa.ai CI] Pull Request created: ${x.data.html_url}`),x.data.html_url}catch(a){return console.error(`[Lisa.ai CI] Failed to create PR: ${a.message}`),null}}function Pe(e,t){let s=process.env.GITHUB_STEP_SUMMARY;if(!s)return;let n=["## Lisa.ai Heal Results","","| Metric | Value |","|---|---|",`| Files Healed | ${e.healedFiles.length} |`,`| Files Quarantined | ${e.quarantinedFiles.length} |`,`| Model | ${e.modelProvider} |`,`| Framework | ${e.framework} |`,`| Scope | ${e.scope} |`];e.testCounts&&n.push(`| Tests Passing (before) | ${e.testCounts.passed} |`,`| Tests Failing (before) | ${e.testCounts.failed} |`),t&&n.push("",`**Pull Request:** ${t}`),e.healedFiles.length>0&&(n.push("","### Healed Files"),e.healedFiles.forEach(o=>n.push(`- \`${o}\``))),e.quarantinedFiles.length>0&&(n.push("","### Quarantined Files"),e.quarantinedFiles.forEach(o=>n.push(`- \`${o}\``)));try{Je.appendFileSync(s,n.join(`
85
+ > Please review the changes before merging.`}async function et(e){if(e.healedFiles.length===0)return console.log("[Lisa.ai CI] No files were healed. Skipping PR creation."),null;let t=process.env.GITHUB_TOKEN,s=process.env.GITHUB_REPOSITORY;if(!t||!s)return console.log("[Lisa.ai CI] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping PR creation."),null;let n=(0,Qe.default)(),i=`lisa-fix/auto-heal-${Date.now()}`,r=process.env.GITHUB_REF_NAME||"main";try{await n.addConfig("user.name","Lisa.ai"),await n.addConfig("user.email","lisa@lisa.ai"),await n.checkoutLocalBranch(i),await n.add(e.healedFiles);let a=e.healedFiles.length===1?`fix: Lisa.ai auto-healed ${e.healedFiles[0]}`:`fix: Lisa.ai auto-healed ${e.healedFiles.length} failing test specs`;await n.commit(a),console.log(`[Lisa.ai CI] Committed ${e.healedFiles.length} file(s) to branch ${i}`),await n.push("origin",i,{"--set-upstream":null}),console.log("[Lisa.ai CI] Pushed branch to origin.");let[p,g]=s.split("/"),x=await new Xe.Octokit({auth:t}).rest.pulls.create({owner:p,repo:g,title:a,body:Rt(e),head:i,base:r});return console.log(`[Lisa.ai CI] Pull Request created: ${x.data.html_url}`),x.data.html_url}catch(a){return console.error(`[Lisa.ai CI] Failed to create PR: ${a.message}`),null}}function Ie(e,t){let s=process.env.GITHUB_STEP_SUMMARY;if(!s)return;let n=["## Lisa.ai Heal Results","","| Metric | Value |","|---|---|",`| Files Healed | ${e.healedFiles.length} |`,`| Files Quarantined | ${e.quarantinedFiles.length} |`,`| Model | ${e.modelProvider} |`,`| Framework | ${e.framework} |`,`| Scope | ${e.scope} |`];e.testCounts&&n.push(`| Tests Passing (before) | ${e.testCounts.passed} |`,`| Tests Failing (before) | ${e.testCounts.failed} |`),t&&n.push("",`**Pull Request:** ${t}`),e.healedFiles.length>0&&(n.push("","### Healed Files"),e.healedFiles.forEach(o=>n.push(`- \`${o}\``))),e.quarantinedFiles.length>0&&(n.push("","### Quarantined Files"),e.quarantinedFiles.forEach(o=>n.push(`- \`${o}\``)));try{Je.appendFileSync(s,n.join(`
86
86
  `)+`
87
- `)}catch{}}var tt=b(require("dotenv"));tt.config({quiet:!0});async function I(e){let s=`${process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088"}/api/v1/lisa/telemetry`;fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).catch(n=>{console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${n.message}`)})}var K=b(require("fs")),_=b(require("path"));var $e=b(require("fs")),st=b(require("path")),te=".lisai.json",P=class{static _config=null;static _loaded=!1;static load(t=process.cwd()){if(this._loaded)return this._config;this._loaded=!0;let s=st.resolve(t,te);if(!$e.existsSync(s))return null;try{let n=$e.readFileSync(s,"utf-8");return this._config=JSON.parse(n),console.log(`[Lisa.ai Config] Loaded project config from ${te}`),this._config}catch(n){return console.warn(`[Lisa.ai Config] Warning: ${te} found but failed to parse \u2014 ${n.message}. Using defaults.`),null}}static get(){return this._config}static applyEnvDefaults(t){if(!t.model)return;let s={claude:"LISA_CLAUDE_MODEL",openai:"LISA_OPENAI_MODEL",gemini:"LISA_GOOGLE_MODEL"},n=t.provider;n&&s[n]&&!process.env[s[n]]&&(process.env[s[n]]=t.model,console.log(`[Lisa.ai Config] Model override applied: ${n} \u2192 ${t.model}`))}static printSummary(t){let s=[];t.projectId&&s.push(`projectId=${t.projectId}`),t.provider&&s.push(`provider=${t.provider}`),t.model&&s.push(`model=${t.model}`),t.testingFramework&&s.push(`testingFramework=${t.testingFramework}`),t.testTypes?.length&&s.push(`testTypes=[${t.testTypes.join(",")}]`),t.maxRetries!==void 0&&s.push(`maxRetries=${t.maxRetries}`),t.testCommand&&s.push(`testCommand="${t.testCommand}"`),t.e2eFramework&&s.push(`e2eFramework=${t.e2eFramework}`),t.e2eCommand&&s.push(`e2eCommand="${t.e2eCommand}"`),s.length&&console.log(`[Lisa.ai Config] Settings: ${s.join(", ")}`),t.skipFiles?.length&&console.log(`[Lisa.ai Config] Extra skip files : ${t.skipFiles.join(", ")}`),t.skipDirs?.length&&console.log(`[Lisa.ai Config] Extra skip dirs : ${t.skipDirs.join(", ")}`),t.skipPaths?.length&&console.log(`[Lisa.ai Config] Extra skip paths : ${t.skipPaths.join(", ")}`)}};var z=class{static scanRepository(t=process.cwd()){let s=_.resolve(t,"package.json"),n={type:"unknown",testingFramework:"none"};if(!K.existsSync(s))return console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${s}. Defaulting to Generic Node.`),n.type="node",n;let o=JSON.parse(K.readFileSync(s,"utf8")),i={...o.dependencies||{},...o.devDependencies||{}},r=o.scripts||{};return i["@angular/core"]?n.type="angular":i.react?n.type="react":i.vue?n.type="vue":n.type="node",i.jest||r.test?.includes("jest")?n.testingFramework="jest":i.karma||r.test?.includes("karma")||r.test?.includes("ng test")?n.testingFramework="karma":(i.vitest||r.test?.includes("vitest"))&&(n.testingFramework="vitest"),n.testingFramework!=="none"&&(n.testingFramework==="karma"?n.type==="angular"?n.suggestedTestCommand="npx ng test --no-watch --browsers=ChromeHeadless":n.suggestedTestCommand="npx karma start --single-run --browsers=ChromeHeadless":r.test?n.suggestedTestCommand="npm run test":n.testingFramework==="jest"?n.suggestedTestCommand="npx jest --coverage":n.testingFramework==="vitest"&&(n.suggestedTestCommand="npx vitest run --coverage")),n}static findUntestedFiles(t,s=[]){let n=[];if(!K.existsSync(t))return n;let o=K.readdirSync(t),i=P.get(),r=i?.skipDirs??[],a=i?.skipFiles??[],u=i?.skipPaths??[],g=["node_modules","dist","build",".git",".angular","coverage","public","assets",...r],d=["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"],x=[/^\./,/\.config\.(js|ts|mjs|cjs)$/,/\.conf\.(js|ts|mjs|cjs)$/];for(let h of o){let f=_.join(t,h);if(g.includes(h))continue;let w;try{w=K.statSync(f)}catch{continue}if(w.isDirectory())n.push(...this.findUntestedFiles(f,s));else if(h.match(/\.(ts|tsx|js|jsx|vue)$/)&&!h.includes(".spec.")&&!h.includes(".test.")){if(d.includes(h)||a.includes(h)||x.some($=>$.test(h)))continue;let l=_.extname(h),p=h.slice(0,-l.length);if(![_.join(t,`${p}.spec${l}`),_.join(t,`${p}.test${l}`),_.join(t,`${p}.spec.js`),_.join(t,`${p}.test.js`),_.join(t,`${p}.spec.ts`),_.join(t,`${p}.test.ts`)].some($=>K.existsSync($))){let $=_.relative(process.cwd(),f);if(u.some(m=>$.startsWith(m)))continue;s.includes($)||n.push($)}}}return n}};var nt=require("child_process"),ae=class{static async installMissingFramework(t,s=process.cwd()){if(t.testingFramework!=="none")return t;console.log(`
87
+ `)}catch{}}var tt=b(require("dotenv"));tt.config({quiet:!0});async function I(e){let s=`${process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088"}/api/v1/lisa/telemetry`;fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).catch(n=>{console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${n.message}`)})}var K=b(require("fs")),_=b(require("path"));var $e=b(require("fs")),st=b(require("path")),te=".lisai.json",P=class{static _config=null;static _loaded=!1;static load(t=process.cwd()){if(this._loaded)return this._config;this._loaded=!0;let s=st.resolve(t,te);if(!$e.existsSync(s))return null;try{let n=$e.readFileSync(s,"utf-8");return this._config=JSON.parse(n),console.log(`[Lisa.ai Config] Loaded project config from ${te}`),this._config}catch(n){return console.warn(`[Lisa.ai Config] Warning: ${te} found but failed to parse \u2014 ${n.message}. Using defaults.`),null}}static get(){return this._config}static applyEnvDefaults(t){if(!t.model)return;let s={claude:"LISA_CLAUDE_MODEL",openai:"LISA_OPENAI_MODEL",gemini:"LISA_GOOGLE_MODEL"},n=t.provider;n&&s[n]&&!process.env[s[n]]&&(process.env[s[n]]=t.model,console.log(`[Lisa.ai Config] Model override applied: ${n} \u2192 ${t.model}`))}static printSummary(t){let s=[];t.projectId&&s.push(`projectId=${t.projectId}`),t.provider&&s.push(`provider=${t.provider}`),t.model&&s.push(`model=${t.model}`),t.testingFramework&&s.push(`testingFramework=${t.testingFramework}`),t.testTypes?.length&&s.push(`testTypes=[${t.testTypes.join(",")}]`),t.maxRetries!==void 0&&s.push(`maxRetries=${t.maxRetries}`),t.testCommand&&s.push(`testCommand="${t.testCommand}"`),t.e2eFramework&&s.push(`e2eFramework=${t.e2eFramework}`),t.e2eCommand&&s.push(`e2eCommand="${t.e2eCommand}"`),s.length&&console.log(`[Lisa.ai Config] Settings: ${s.join(", ")}`),t.skipFiles?.length&&console.log(`[Lisa.ai Config] Extra skip files : ${t.skipFiles.join(", ")}`),t.skipDirs?.length&&console.log(`[Lisa.ai Config] Extra skip dirs : ${t.skipDirs.join(", ")}`),t.skipPaths?.length&&console.log(`[Lisa.ai Config] Extra skip paths : ${t.skipPaths.join(", ")}`)}};var V=class{static scanRepository(t=process.cwd()){let s=_.resolve(t,"package.json"),n={type:"unknown",testingFramework:"none"};if(!K.existsSync(s))return console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${s}. Defaulting to Generic Node.`),n.type="node",n;let o=JSON.parse(K.readFileSync(s,"utf8")),i={...o.dependencies||{},...o.devDependencies||{}},r=o.scripts||{};return i["@angular/core"]?n.type="angular":i.react?n.type="react":i.vue?n.type="vue":n.type="node",i.jest||r.test?.includes("jest")?n.testingFramework="jest":i.karma||r.test?.includes("karma")||r.test?.includes("ng test")?n.testingFramework="karma":(i.vitest||r.test?.includes("vitest"))&&(n.testingFramework="vitest"),n.testingFramework!=="none"&&(n.testingFramework==="karma"?n.type==="angular"?n.suggestedTestCommand="npx ng test --no-watch --browsers=ChromeHeadless":n.suggestedTestCommand="npx karma start --single-run --browsers=ChromeHeadless":r.test?n.suggestedTestCommand="npm run test":n.testingFramework==="jest"?n.suggestedTestCommand="npx jest --coverage":n.testingFramework==="vitest"&&(n.suggestedTestCommand="npx vitest run --coverage")),n}static findUntestedFiles(t,s=[]){let n=[];if(!K.existsSync(t))return n;let o=K.readdirSync(t),i=P.get(),r=i?.skipDirs??[],a=i?.skipFiles??[],p=i?.skipPaths??[],g=["node_modules","dist","build",".git",".angular","coverage","public","assets",...r],d=["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"],x=[/^\./,/\.config\.(js|ts|mjs|cjs)$/,/\.conf\.(js|ts|mjs|cjs)$/];for(let h of o){let f=_.join(t,h);if(g.includes(h))continue;let w;try{w=K.statSync(f)}catch{continue}if(w.isDirectory())n.push(...this.findUntestedFiles(f,s));else if(h.match(/\.(ts|tsx|js|jsx|vue)$/)&&!h.includes(".spec.")&&!h.includes(".test.")){if(d.includes(h)||a.includes(h)||x.some($=>$.test(h)))continue;let l=_.extname(h),u=h.slice(0,-l.length);if(![_.join(t,`${u}.spec${l}`),_.join(t,`${u}.test${l}`),_.join(t,`${u}.spec.js`),_.join(t,`${u}.test.js`),_.join(t,`${u}.spec.ts`),_.join(t,`${u}.test.ts`)].some($=>K.existsSync($))){let $=_.relative(process.cwd(),f);if(p.some(m=>$.startsWith(m)))continue;s.includes($)||n.push($)}}}return n}};var nt=require("child_process"),ae=class{static async installMissingFramework(t,s=process.cwd()){if(t.testingFramework!=="none")return t;console.log(`
88
88
  [Lisa.ai Auto-Installer] \u{1F6A8} No testing framework detected for ${t.type} architecture.`),console.log("[Lisa.ai Auto-Installer] \u{1FA84} Initiating Zero-Config Installation Protocol...");let n="",o="none";switch(t.type){case"angular":console.log("[Lisa.ai Auto-Installer] Provisioning Angular TestBed environment..."),n="npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine jasmine-core @types/jasmine",o="karma",t.suggestedTestCommand="npm run test";break;case"react":case"node":default:console.log("[Lisa.ai Auto-Installer] Provisioning Universal Jest environment..."),n="npm install --save-dev jest @types/jest ts-jest",o="jest",t.suggestedTestCommand="npx jest --coverage";break;case"vue":console.log("[Lisa.ai Auto-Installer] Provisioning Vue Vitest environment..."),n="npm install --save-dev vitest @vue/test-utils jsdom",o="vitest",t.suggestedTestCommand="npx vitest run --coverage";break}if(n){console.log(`[Lisa.ai Executing] ${n}`);let i=n.split(" "),r=process.platform==="win32"?`${i[0]}.cmd`:i[0];return(0,nt.spawnSync)(r,i.slice(1),{cwd:s,stdio:"inherit"}).status!==0&&(console.error(`
89
- \u274C [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`),process.exit(1)),console.log("\u2705 [Lisa.ai Auto-Installer] Framework successfully injected."),t.testingFramework=o,t}return t}};var Le=b(require("fs")),Ie=b(require("path"));var re=class{static async provisionConfigurationFiles(t,s,n,o=process.cwd()){if(t.testingFramework==="none")return;if(console.log(`
90
- [Lisa.ai Auto-Generator] \u{1FA84} Analyzing ${t.type} architecture to generate ${t.testingFramework} configuration specs...`),["jest.config.js","jest.config.ts","karma.conf.js","vitest.config.ts","vitest.config.js"].some(u=>Le.existsSync(Ie.join(o,u)))){console.log("[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.");return}let a=`You are an expert ${t.type} architect.
89
+ \u274C [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`),process.exit(1)),console.log("\u2705 [Lisa.ai Auto-Installer] Framework successfully injected."),t.testingFramework=o,t}return t}};var Le=b(require("fs")),Te=b(require("path"));var re=class{static async provisionConfigurationFiles(t,s,n,o=process.cwd()){if(t.testingFramework==="none")return;if(console.log(`
90
+ [Lisa.ai Auto-Generator] \u{1FA84} Analyzing ${t.type} architecture to generate ${t.testingFramework} configuration specs...`),["jest.config.js","jest.config.ts","karma.conf.js","vitest.config.ts","vitest.config.js"].some(p=>Le.existsSync(Te.join(o,p)))){console.log("[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.");return}let a=`You are an expert ${t.type} architect.
91
91
  Write a production-ready '${t.testingFramework}' configuration file for a standard '${t.type}' application.
92
92
  The application resides in the root directory.
93
93
 
@@ -95,8 +95,8 @@ Requirements:
95
95
  1. Ensure it specifically instruments code coverage.
96
96
  2. Ensure standard transpilation (ts-jest for jest, or standard karma-webpack/karma-typescript implementations).
97
97
  3. Do NOT wrap your response in markdown formatting (no \`\`\`javascript).
98
- 4. Return ONLY the raw code string block.`;try{let u=await ie(a,s,n),g="";t.testingFramework==="jest"&&(g="jest.config.js"),t.testingFramework==="karma"&&(g="karma.conf.js"),t.testingFramework==="vitest"&&(g="vitest.config.ts");let d=Ie.join(o,g);Le.writeFileSync(d,u,"utf-8"),console.log(`\u2705 [Lisa.ai Auto-Generator] Natively wrote ${g} to repository root.`)}catch(u){console.error(`
99
- \u274C [Lisa.ai Auto-Generator] Failed to author configuration file: ${u.message}`),process.exit(1)}}};var ot=b(require("dotenv"));ot.config({quiet:!0});function le(e){let t=e.toLowerCase();return t.includes("karma")||t.includes("ng test")?"karma":t.includes("jest")?"jest":t.includes("vitest")?"vitest":t.includes("playwright")?"playwright":t.includes("cypress")?"cypress":t.includes("mocha")?"mocha":"unknown"}async function it(e,t,s){if(s==="local")return[];let n=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{let o=new URLSearchParams({projectId:s,errorLog:e.slice(0,1e3),framework:t}),i=await fetch(`${n}/api/v1/lisa/memory/lookup?${o}`);if(!i.ok)return[];let r=await i.json();return r.data??r}catch{return[]}}async function at(e,t,s,n){if(n==="local")return;let o=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{await fetch(`${o}/api/v1/lisa/memory/record`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:n,errorLog:e.slice(0,1e3),fixHint:t.slice(0,2e3),framework:s})}),console.log("[Lisa.ai Memory] Fix pattern recorded to Control Plane.")}catch(i){console.debug(`[Lisa.ai Agent Debug] Failed to record memory pattern: ${i.message}`)}}var N=b(require("fs")),O=b(require("path")),Te=require("child_process");function ke(e){if(N.existsSync(O.join(e,"playwright.config.ts"))||N.existsSync(O.join(e,"playwright.config.js")))return{framework:"playwright",configFile:N.existsSync(O.join(e,"playwright.config.ts"))?"playwright.config.ts":"playwright.config.js",command:"npx playwright test",installed:!0};if(N.existsSync(O.join(e,"cypress.config.ts"))||N.existsSync(O.join(e,"cypress.config.js"))||N.existsSync(O.join(e,"cypress.json")))return{framework:"cypress",configFile:N.existsSync(O.join(e,"cypress.config.ts"))?"cypress.config.ts":N.existsSync(O.join(e,"cypress.config.js"))?"cypress.config.js":"cypress.json",command:"npx cypress run",installed:!0};let t=O.join(e,"package.json");if(N.existsSync(t)){let s=JSON.parse(N.readFileSync(t,"utf-8")),n={...s.dependencies||{},...s.devDependencies||{}};if(n["@playwright/test"])return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!0};if(n.cypress)return{framework:"cypress",configFile:null,command:"npx cypress run",installed:!0}}return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!1}}function Ce(e){console.log("[Lisa.ai E2E] No E2E framework detected. Installing Playwright...");try{(0,Te.execSync)("npm install -D @playwright/test",{cwd:e,stdio:"pipe"}),console.log("[Lisa.ai E2E] Playwright installed.")}catch(s){throw console.error(`[Lisa.ai E2E] Failed to install Playwright: ${s.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:e,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.")}N.existsSync(O.join(e,"playwright.config.ts"))||(N.writeFileSync(O.join(e,"playwright.config.ts"),`import { defineConfig } from '@playwright/test';
98
+ 4. Return ONLY the raw code string block.`;try{let p=await ie(a,s,n),g="";t.testingFramework==="jest"&&(g="jest.config.js"),t.testingFramework==="karma"&&(g="karma.conf.js"),t.testingFramework==="vitest"&&(g="vitest.config.ts");let d=Te.join(o,g);Le.writeFileSync(d,p,"utf-8"),console.log(`\u2705 [Lisa.ai Auto-Generator] Natively wrote ${g} to repository root.`)}catch(p){console.error(`
99
+ \u274C [Lisa.ai Auto-Generator] Failed to author configuration file: ${p.message}`),process.exit(1)}}};var ot=b(require("dotenv"));ot.config({quiet:!0});function le(e){let t=e.toLowerCase();return t.includes("karma")||t.includes("ng test")?"karma":t.includes("jest")?"jest":t.includes("vitest")?"vitest":t.includes("playwright")?"playwright":t.includes("cypress")?"cypress":t.includes("mocha")?"mocha":"unknown"}async function it(e,t,s){if(s==="local")return[];let n=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{let o=new URLSearchParams({projectId:s,errorLog:e.slice(0,1e3),framework:t}),i=await fetch(`${n}/api/v1/lisa/memory/lookup?${o}`);if(!i.ok)return[];let r=await i.json();return r.data??r}catch{return[]}}async function at(e,t,s,n){if(n==="local")return;let o=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3088";try{await fetch(`${o}/api/v1/lisa/memory/record`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:n,errorLog:e.slice(0,1e3),fixHint:t.slice(0,2e3),framework:s})}),console.log("[Lisa.ai Memory] Fix pattern recorded to Control Plane.")}catch(i){console.debug(`[Lisa.ai Agent Debug] Failed to record memory pattern: ${i.message}`)}}var D=b(require("fs")),O=b(require("path")),Re=require("child_process");function ke(e){if(D.existsSync(O.join(e,"playwright.config.ts"))||D.existsSync(O.join(e,"playwright.config.js")))return{framework:"playwright",configFile:D.existsSync(O.join(e,"playwright.config.ts"))?"playwright.config.ts":"playwright.config.js",command:"npx playwright test",installed:!0};if(D.existsSync(O.join(e,"cypress.config.ts"))||D.existsSync(O.join(e,"cypress.config.js"))||D.existsSync(O.join(e,"cypress.json")))return{framework:"cypress",configFile:D.existsSync(O.join(e,"cypress.config.ts"))?"cypress.config.ts":D.existsSync(O.join(e,"cypress.config.js"))?"cypress.config.js":"cypress.json",command:"npx cypress run",installed:!0};let t=O.join(e,"package.json");if(D.existsSync(t)){let s=JSON.parse(D.readFileSync(t,"utf-8")),n={...s.dependencies||{},...s.devDependencies||{}};if(n["@playwright/test"])return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!0};if(n.cypress)return{framework:"cypress",configFile:null,command:"npx cypress run",installed:!0}}return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!1}}function Ce(e){console.log("[Lisa.ai E2E] No E2E framework detected. Installing Playwright...");try{(0,Re.execSync)("npm install -D @playwright/test",{cwd:e,stdio:"pipe"}),console.log("[Lisa.ai E2E] Playwright installed.")}catch(s){throw console.error(`[Lisa.ai E2E] Failed to install Playwright: ${s.message}`),new Error("Could not install @playwright/test. Please install it manually.")}try{console.log("[Lisa.ai E2E] Installing Playwright browsers..."),(0,Re.execSync)("npx playwright install --with-deps chromium",{cwd:e,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.")}D.existsSync(O.join(e,"playwright.config.ts"))||(D.writeFileSync(O.join(e,"playwright.config.ts"),`import { defineConfig } from '@playwright/test';
100
100
 
101
101
  export default defineConfig({
102
102
  testDir: './e2e',
@@ -113,12 +113,12 @@ export default defineConfig({
113
113
  { name: 'chromium', use: { browserName: 'chromium' } },
114
114
  ],
115
115
  });
116
- `,"utf-8"),console.log("[Lisa.ai E2E] Generated playwright.config.ts"));let t=O.join(e,"e2e");N.existsSync(t)||(N.mkdirSync(t,{recursive:!0}),console.log("[Lisa.ai E2E] Created e2e/ directory"))}var se=0,ge=0,fe=new Set;function Re(e){let s=[...we(e).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(s.length===0)return null;let n=[...s].reverse().find(g=>g[3]!==void 0)??s[s.length-1],o=parseInt(n[2]),i=n[3]?parseInt(n[3]):0,r=parseInt(n[1])-i,a=o>0?Math.round(r/o*100):0;return` [${"\u2588".repeat(Math.round(a/5))+"\u2591".repeat(20-Math.round(a/5))}] ${a}% ${r} passed ${i} failed ${o} total`}function lt(e,t=10){let s=[];for(let n of we(e).split(`
117
- `)){let o=n.trim();if(/^FAILED/.test(o)||/ FAILED$/.test(o)){let r=o.replace(/^(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:[\s.]\d+)*\s+\([^)]+\)\s+/,"").replace(/\s+FAILED$/,"").trim();if(s.push(r||o),s.length>=t)break}}return s}function Mt(e){let t=e.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/,".$2");if(t!==e&&H.existsSync(t))try{return console.log(` [Lisa.ai] \u{1F9E0} Sibling source found: ${Z.basename(t)}`),H.readFileSync(t,"utf-8")}catch{return}}function Nt(e,t){let s=e.toLowerCase(),n=Z.parse(t);if(s.includes("ng test")||s.includes("karma"))return`${e} --include **/${n.base}`;if(s.includes("jest")||s.includes("vitest")||s.includes("playwright"))return`${e} ${t}`;if(s.includes("cypress"))return`${e} --spec ${t}`;if(s.includes("npm")||s.includes("yarn")||s.includes("pnpm")){try{let i=JSON.parse(H.readFileSync(Z.resolve(process.cwd(),"package.json"),"utf8")),r="test";s.includes("npm run ")?r=s.split("npm run ")[1].split(" ")[0]:s.includes("yarn ")?r=s.split("yarn ")[1].split(" ")[0]:s.includes("pnpm ")&&(r=s.split("pnpm ")[1].split(" ")[0]);let a=i.scripts?.[r]?.toLowerCase()||"",u=s.includes("npm")?" --":"";if(a.includes("ng test")||a.includes("karma"))return`${e}${u} --include **/${n.base}`;if(a.includes("jest")||a.includes("vitest")||a.includes("playwright"))return`${e}${u} ${t}`}catch{}let o=s.includes("npm")?" --":"";return`${e}${o} ${t}`}return e}function Me(e,t=!1){return new Promise((s,n)=>{let o=(0,rt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"]}),i="",r="";o.stdout?.on("data",a=>{let u=a.toString();if(i+=u,t)for(let g of u.split(`
116
+ `,"utf-8"),console.log("[Lisa.ai E2E] Generated playwright.config.ts"));let t=O.join(e,"e2e");D.existsSync(t)||(D.mkdirSync(t,{recursive:!0}),console.log("[Lisa.ai E2E] Created e2e/ directory"))}var se=0,ge=0,fe=new Set;function Me(e){let s=[...we(e).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(s.length===0)return null;let n=[...s].reverse().find(g=>g[3]!==void 0)??s[s.length-1],o=parseInt(n[2]),i=n[3]?parseInt(n[3]):0,r=parseInt(n[1])-i,a=o>0?Math.round(r/o*100):0;return` [${"\u2588".repeat(Math.round(a/5))+"\u2591".repeat(20-Math.round(a/5))}] ${a}% ${r} passed ${i} failed ${o} total`}function lt(e,t=10){let s=[];for(let n of we(e).split(`
117
+ `)){let o=n.trim();if(/^FAILED/.test(o)||/ FAILED$/.test(o)){let r=o.replace(/^(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:[\s.]\d+)*\s+\([^)]+\)\s+/,"").replace(/\s+FAILED$/,"").trim();if(s.push(r||o),s.length>=t)break}}return s}function Mt(e){let t=e.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/,".$2");if(t!==e&&H.existsSync(t))try{return console.log(` [Lisa.ai] \u{1F9E0} Sibling source found: ${Z.basename(t)}`),H.readFileSync(t,"utf-8")}catch{return}}function Nt(e,t){let s=e.toLowerCase(),n=Z.parse(t);if(s.includes("ng test")||s.includes("karma"))return`${e} --include **/${n.base}`;if(s.includes("jest")||s.includes("vitest")||s.includes("playwright"))return`${e} ${t}`;if(s.includes("cypress"))return`${e} --spec ${t}`;if(s.includes("npm")||s.includes("yarn")||s.includes("pnpm")){try{let i=JSON.parse(H.readFileSync(Z.resolve(process.cwd(),"package.json"),"utf8")),r="test";s.includes("npm run ")?r=s.split("npm run ")[1].split(" ")[0]:s.includes("yarn ")?r=s.split("yarn ")[1].split(" ")[0]:s.includes("pnpm ")&&(r=s.split("pnpm ")[1].split(" ")[0]);let a=i.scripts?.[r]?.toLowerCase()||"",p=s.includes("npm")?" --":"";if(a.includes("ng test")||a.includes("karma"))return`${e}${p} --include **/${n.base}`;if(a.includes("jest")||a.includes("vitest")||a.includes("playwright"))return`${e}${p} ${t}`}catch{}let o=s.includes("npm")?" --":"";return`${e}${o} ${t}`}return e}function Ne(e,t=!1){return new Promise((s,n)=>{let o=(0,rt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"]}),i="",r="";o.stdout?.on("data",a=>{let p=a.toString();if(i+=p,t)for(let g of p.split(`
118
118
  `)){let d=g.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"").trim();d&&(/Executed\s+\d+\s+of\s+\d+/.test(d)?process.stdout.write(`\r ${d.padEnd(72)}`):/^\s*FAILED\b/.test(d)&&(process.stdout.write(`
119
119
  `),console.log(` \u2717 ${d.trim()}`)))}}),o.stderr?.on("data",a=>{r+=a.toString()}),o.on("close",a=>{a===0?s({stdout:i,stderr:r}):n({message:`Process exited with code ${a}`,stdout:i,stderr:r})})})}function Dt(e,t,s){if(!t.match(/\.(spec|test)\.(ts|js|tsx|jsx|vue)$/))return;if((s||"").toLowerCase().includes("ng test")||(s||"").toLowerCase().includes("karma"))try{H.writeFileSync(e,`// Quarantined by Lisa.ai \u2014 could not be automatically healed
120
120
  describe('', () => {});
121
- `,"utf-8"),console.log(" \u{1F6A8} Replaced with empty stub (Angular requires valid TS).")}catch{}else try{H.renameSync(e,e+".broken"),console.log(` \u{1F6A8} Renamed to ${Z.basename(e)}.broken to skip in test runner.`)}catch{}}async function Ut(e,t,s,n,o,i,r,a,u,g){let d=1,x=!1,h=s,f,w="",l="",p=Mt(t),k=(await it(s,i,u)).filter($=>$.confidence>=.5).map($=>$.fixHint);for(k.length>0&&console.log(` [Memory] ${k.length} proven pattern(s) found \u2014 injecting as LLM hint.`);d<=a&&!x;){console.log(` [Attempt ${d}/${a}] Requesting fix from ${r}...`);let $=H.readFileSync(t,"utf-8"),m;for(let y=0;y<=3;y++)try{m=await ze(e,$,h,r,g,f,p,k);break}catch(v){let C=(v?.lastError??v)?.statusCode;if((C===529||C===500)&&y<3){let L=30*(y+1);console.warn(` \u26A0\uFE0F LLM overloaded (HTTP ${C}). Waiting ${L}s...`),await new Promise(E=>setTimeout(E,L*1e3))}else{console.error(` \u{1F6A8} LLM API failed: ${v?.message??String(v)}`);break}}if(m===void 0)break;H.writeFileSync(t,m,"utf-8"),w=`### Auto-Heal Analysis
121
+ `,"utf-8"),console.log(" \u{1F6A8} Replaced with empty stub (Angular requires valid TS).")}catch{}else try{H.renameSync(e,e+".broken"),console.log(` \u{1F6A8} Renamed to ${Z.basename(e)}.broken to skip in test runner.`)}catch{}}async function Ut(e,t,s,n,o,i,r,a,p,g){let d=1,x=!1,h=s,f,w="",l="",u=Mt(t),L=(await it(s,i,p)).filter($=>$.confidence>=.5).map($=>$.fixHint);for(L.length>0&&console.log(` [Memory] ${L.length} proven pattern(s) found \u2014 injecting as LLM hint.`);d<=a&&!x;){console.log(` [Attempt ${d}/${a}] Requesting fix from ${r}...`);let $=H.readFileSync(t,"utf-8"),m;for(let y=0;y<=3;y++)try{m=await ze(e,$,h,r,g,f,u,L);break}catch(v){let C=(v?.lastError??v)?.statusCode;if((C===529||C===500)&&y<3){let k=30*(y+1);console.warn(` \u26A0\uFE0F LLM overloaded (HTTP ${C}). Waiting ${k}s...`),await new Promise(E=>setTimeout(E,k*1e3))}else{console.error(` \u{1F6A8} LLM API failed: ${v?.message??String(v)}`);break}}if(m===void 0)break;H.writeFileSync(t,m,"utf-8"),w=`### Auto-Heal Analysis
122
122
  **Error:**
123
123
  \`\`\`bash
124
124
  ${h.slice(0,2e3)}
@@ -127,45 +127,45 @@ ${h.slice(0,2e3)}
127
127
  **Fix (${r}):**
128
128
  \`\`\`typescript
129
129
  ${m}
130
- \`\`\``;try{await Me(o,!1),console.log(" \u2705 Isolated verification passed."),x=!0,l=m}catch(y){let v=y.stdout?y.stdout.toString():"";h=(y.stderr?y.stderr.toString():"")+`
130
+ \`\`\``;try{await Ne(o,!1),console.log(" \u2705 Isolated verification passed."),x=!0,l=m}catch(y){let v=y.stdout?y.stdout.toString():"";h=(y.stderr?y.stderr.toString():"")+`
131
131
  `+v+`
132
- `+(y.message||""),console.log(" \u274C Isolated verification failed.");let L=Re(h);if(L&&console.log(L),lt(h,3).forEach(E=>console.log(` \u2717 ${E}`)),(n||"").toLowerCase().includes("ng test")||(n||"").toLowerCase().includes("karma")){let E=h.includes(Z.basename(e)+":"),G=/ FAILED/.test(h);if(!E&&!G){console.log(" \u2705 Fix verified (build error is from other spec files, not this one)."),x=!0,l=m;continue}}f=`### Attempt ${d} Failed
132
+ `+(y.message||""),console.log(" \u274C Isolated verification failed.");let k=Me(h);if(k&&console.log(k),lt(h,3).forEach(E=>console.log(` \u2717 ${E}`)),(n||"").toLowerCase().includes("ng test")||(n||"").toLowerCase().includes("karma")){let E=h.includes(Z.basename(e)+":"),G=/ FAILED/.test(h);if(!E&&!G){console.log(" \u2705 Fix verified (build error is from other spec files, not this one)."),x=!0,l=m;continue}}f=`### Attempt ${d} Failed
133
133
  \`\`\`typescript
134
134
  ${m}
135
135
  \`\`\`
136
136
 
137
137
  **New Error:**
138
- ${h}`,d++}}return{status:x?"healed":"quarantined",details:w,lastCode:l}}async function ce(e,t,s=1,n=3,o="local",i,r,a="unit",u,g=!1){se=0,ge=0,fe.clear();let d=a==="unit"?"":` (${a})`,x=P.load(process.cwd());if(x&&P.applyEnvDefaults(x),a==="e2e"){if(!e&&x?.e2eCommand&&(e=x.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${e}`)),!e){console.log(`
138
+ ${h}`,d++}}return{status:x?"healed":"quarantined",details:w,lastCode:l}}async function ce(e,t,s=1,n=3,o="local",i,r,a="unit",p,g=!1){se=0,ge=0,fe.clear();let d=a==="unit"?"":` (${a})`,x=P.load(process.cwd());if(x&&P.applyEnvDefaults(x),a==="e2e"){if(!e&&x?.e2eCommand&&(e=x.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${e}`)),!e){console.log(`
139
139
  [Lisa.ai Heal${d}] Auto-detecting E2E framework...`);let y=ke(process.cwd());!y.installed&&y.framework==="playwright"&&Ce(process.cwd()),e=y.command,console.log(`[Lisa.ai Heal${d}] E2E command: ${e}`)}}else if(!e&&x?.testCommand&&(e=x.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${e}`)),!e){console.log(`
140
- [Lisa.ai Auto-Discovery] No --command provided. Scanning framework...`);let y=z.scanRepository();y.testingFramework==="none"&&(y=await ae.installMissingFramework(y),await re.provisionConfigurationFiles(y,t,r)),y.suggestedTestCommand?(e=y.suggestedTestCommand,console.log(`[Lisa.ai Auto-Discovery] Discovered command: ${e}`)):(console.error(`
141
- \u{1F6A8} [Lisa.ai] Could not discover a test command. Pass --command explicitly.`),process.exit(1))}let h=le(e),f=[],w="",l=null,p;if(u&&u.length>0)p=u,console.log(`
142
- [Lisa.ai Heal${d}] Targeting ${u.length} file(s) from --files`),p.forEach(y=>console.log(` - ${y}`));else{console.log(`
143
- [Lisa.ai Heal${d}] Running test suite (discovery pass)...`),console.log(`[Lisa.ai Executing] ${e} Model: ${t}`);try{await Me(e,!0),process.stdout.write(`
140
+ [Lisa.ai Auto-Discovery] No --command provided. Scanning framework...`);let y=V.scanRepository();y.testingFramework==="none"&&(y=await ae.installMissingFramework(y),await re.provisionConfigurationFiles(y,t,r)),y.suggestedTestCommand?(e=y.suggestedTestCommand,console.log(`[Lisa.ai Auto-Discovery] Discovered command: ${e}`)):(console.error(`
141
+ \u{1F6A8} [Lisa.ai] Could not discover a test command. Pass --command explicitly.`),process.exit(1))}let h=le(e),f=[],w="",l=null,u;if(p&&p.length>0)u=p,console.log(`
142
+ [Lisa.ai Heal${d}] Targeting ${p.length} file(s) from --files`),u.forEach(y=>console.log(` - ${y}`));else{console.log(`
143
+ [Lisa.ai Heal${d}] Running test suite (discovery pass)...`),console.log(`[Lisa.ai Executing] ${e} Model: ${t}`);try{await Ne(e,!0),process.stdout.write(`
144
144
  `),console.log(`
145
- \u2705 [Lisa.ai] All tests passing. Nothing to heal!`);let v={healedFiles:[],quarantinedFiles:[],testCounts:null,allPassing:!0};return g&&Pe({healedFiles:[],quarantinedFiles:[],testCounts:null,modelProvider:t,framework:"unknown",scope:a},null),v}catch(v){process.stdout.write(`
145
+ \u2705 [Lisa.ai] All tests passing. Nothing to heal!`);let v={healedFiles:[],quarantinedFiles:[],testCounts:null,allPassing:!0};return g&&Ie({healedFiles:[],quarantinedFiles:[],testCounts:null,modelProvider:t,framework:"unknown",scope:a},null),v}catch(v){process.stdout.write(`
146
146
  `),w=(v.stderr||"")+`
147
147
  `+(v.stdout||"")+`
148
- `+(v.message||"")}l=Y(w);let y=Re(w);if(y){console.log(`
149
- ${y}`);let v=lt(w,10);if(v.length>0){let C=l?.failed??v.length;console.log(` Failing (${C}):`),v.forEach(L=>console.log(` \u2717 ${L}`)),C>v.length&&console.log(` ... and ${C-v.length} more`)}}if(p=Ee(w,process.cwd(),f),p.length===0){let v=ve(w,f,process.cwd());v||(console.error(`
150
- \u{1F6A8} [Lisa.ai] Could not identify any failing spec files. Output format may be unsupported.`),process.exit(1)),p=[v]}}let c=p.length;console.log(`
151
- [Lisa.ai] Found ${c} failing spec(s). Healing each in isolation...`),console.log(`${"\u2500".repeat(60)}`);for(let y of p)I({projectId:o,type:"heal",filePath:y,modelUsed:t,status:"running",details:"Queued for isolated healing.",...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:h});for(let y=0;y<p.length;y++){let v=p[y],C=Z.resolve(process.cwd(),v);if(console.log(`
152
- [${y+1}/${c}] ${v}`),!H.existsSync(C)){console.warn(" \u26A0\uFE0F File not found \u2014 skipping.");continue}if(/[\\/](node_modules|dist|build)[\\/]/.test(C)){console.warn(" \u26A0\uFE0F Library file \u2014 refusing to modify.");continue}let L=Nt(e,v),E=await Ut(v,C,w,e,L,h,t,n,o,r);E.status==="healed"?(se++,fe.add(v),console.log(` \u2705 Healed [${se} healed ${ge} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:t,status:"success",details:E.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:h}),await at(w,E.lastCode,h,o)):(ge++,f.push(v),console.warn(` \u{1F6A8} Quarantined [${se} healed ${ge} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:t,status:"error",details:`Exhausted all ${n} attempts.
148
+ `+(v.message||"")}l=Y(w);let y=Me(w);if(y){console.log(`
149
+ ${y}`);let v=lt(w,10);if(v.length>0){let C=l?.failed??v.length;console.log(` Failing (${C}):`),v.forEach(k=>console.log(` \u2717 ${k}`)),C>v.length&&console.log(` ... and ${C-v.length} more`)}}if(u=Fe(w,process.cwd(),f),u.length===0){let v=ve(w,f,process.cwd());v||(console.error(`
150
+ \u{1F6A8} [Lisa.ai] Could not identify any failing spec files. Output format may be unsupported.`),process.exit(1)),u=[v]}}let c=u.length;console.log(`
151
+ [Lisa.ai] Found ${c} failing spec(s). Healing each in isolation...`),console.log(`${"\u2500".repeat(60)}`);for(let y of u)I({projectId:o,type:"heal",filePath:y,modelUsed:t,status:"running",details:"Queued for isolated healing.",...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:h});for(let y=0;y<u.length;y++){let v=u[y],C=Z.resolve(process.cwd(),v);if(console.log(`
152
+ [${y+1}/${c}] ${v}`),!H.existsSync(C)){console.warn(" \u26A0\uFE0F File not found \u2014 skipping.");continue}if(/[\\/](node_modules|dist|build)[\\/]/.test(C)){console.warn(" \u26A0\uFE0F Library file \u2014 refusing to modify.");continue}let k=Nt(e,v),E=await Ut(v,C,w,e,k,h,t,n,o,r);E.status==="healed"?(se++,fe.add(v),console.log(` \u2705 Healed [${se} healed ${ge} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:t,status:"success",details:E.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:h}),await at(w,E.lastCode,h,o)):(ge++,f.push(v),console.warn(` \u{1F6A8} Quarantined [${se} healed ${ge} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:t,status:"error",details:`Exhausted all ${n} attempts.
153
153
  `+E.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:h}),Dt(C,v,e))}console.log(`
154
- ${"\u2500".repeat(60)}`);let k=!1;if(se>0){console.log("[Lisa.ai] Final verification run...");try{await Me(e,!0),process.stdout.write(`
154
+ ${"\u2500".repeat(60)}`);let L=!1;if(se>0){console.log("[Lisa.ai] Final verification run...");try{await Ne(e,!0),process.stdout.write(`
155
155
  `),console.log(`
156
- \u2705 All tests passing!`),k=!0}catch(y){process.stdout.write(`
156
+ \u2705 All tests passing!`),L=!0}catch(y){process.stdout.write(`
157
157
  `);let v=(y.stderr||"")+`
158
158
  `+(y.stdout||"")+`
159
- `+(y.message||""),C=Re(v);C&&console.log(`
160
- ${C}`);let L=Ee(v,process.cwd(),[]),E=L.filter(M=>fe.has(M)),G=L.filter(M=>!fe.has(M)&&!f.includes(M));E.length>0&&(console.warn(`
159
+ `+(y.message||""),C=Me(v);C&&console.log(`
160
+ ${C}`);let k=Fe(v,process.cwd(),[]),E=k.filter(M=>fe.has(M)),G=k.filter(M=>!fe.has(M)&&!f.includes(M));E.length>0&&(console.warn(`
161
161
  \u26A0\uFE0F ${E.length} spec(s) passed isolated verification but still fail globally:`),E.forEach(M=>console.warn(` \u2717 ${M}`)),console.warn(" These likely have cross-test shared state. Try higher maxRetries or fix manually.")),G.length>0&&(console.warn(`
162
162
  \u2139\uFE0F ${G.length} additional failing spec(s) not in this run's queue:`),G.forEach(M=>console.warn(` \u2717 ${M}`)),console.warn(" Run lisa-agent heal again to address these."))}}let $=(l?.passed??0)+se;console.log(`
163
163
  \u2705 Healed: ${se} / ${c}`),console.log(` \u{1F6A8} Quarantined: ${ge}`),l&&console.log(` \u{1F4CA} Suite: ${l.passed} passing \u2192 ~${$} passing (est.)`),console.log(`${"\u2500".repeat(60)}
164
- `);let m={healedFiles:[...fe],quarantinedFiles:[...f],testCounts:l,allPassing:k};if(g){let y={healedFiles:m.healedFiles,quarantinedFiles:m.quarantinedFiles,testCounts:m.testCounts,modelProvider:t,framework:h,scope:a},v=await et(y);Pe(y,v),m.allPassing||(process.exitCode=1)}return m}var ut=require("child_process"),V=b(require("fs")),D=b(require("path"));var Se=b(require("fs")),ct=b(require("path"));function dt(e){let t=ct.resolve(process.cwd(),e);if(!Se.existsSync(t))throw new Error(`[Lisa.ai Coverage Error] Coverage file not found at ${t}`);let s=Se.readFileSync(t,"utf-8"),n=JSON.parse(s),o=[];for(let[i,r]of Object.entries(n))i!=="total"&&(r.lines.pct<100||r.statements.pct<100||r.functions.pct<100||r.branches.pct<100)&&o.push(i);return o}var Ne=new Set,be=0,De=3;function _t(e){let t=e.testingFramework,s=process.cwd();return V.existsSync(D.join(s,"angular.json"))?"npx ng test --no-watch --code-coverage --browsers=ChromeHeadless":t==="jest"?"npx jest --coverage --coverageReporters=json-summary":t==="vitest"?"npx vitest run --coverage":[".mocharc.yml",".mocharc.yaml",".mocharc.json",".mocharc.js"].some(o=>V.existsSync(D.join(s,o)))?"npx nyc --reporter=json-summary mocha":null}async function pt(e,t,s=1,n=3,o="local",i,r){let a=P.load(process.cwd());a&&(P.applyEnvDefaults(a),!e&&a.testCommand&&(e=a.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${e}`)));let u=z.scanRepository(),g=a?.testingFramework||(u.testingFramework!=="none"?u.testingFramework:void 0),d=a?.testTypes;if(!e){console.log(`
165
- [Lisa.ai Auto-Discovery] No explicit --command provided. Auto-detecting coverage command...`);let f=_t(u);if(f)e=f,console.log(`[Lisa.ai Auto-Discovery] Detected coverage command: ${e}`);else{let w=u;if(w.testingFramework==="none"&&(w=await ae.installMissingFramework(w),await re.provisionConfigurationFiles(w,t,i)),w.suggestedTestCommand){e=w.suggestedTestCommand;let l=w.testingFramework;(l==="jest"||l==="vitest")&&!e.includes("--coverage")&&(e=e.includes("npm run")?`${e} -- --coverage`:`${e} --coverage`,console.log(`[Lisa.ai Unit] Coverage flag appended: ${e}`)),console.log(`[Lisa.ai Auto-Discovery] Bootstrapping with discovered command: ${e}`)}else console.error(`
164
+ `);let m={healedFiles:[...fe],quarantinedFiles:[...f],testCounts:l,allPassing:L};if(g){let y={healedFiles:m.healedFiles,quarantinedFiles:m.quarantinedFiles,testCounts:m.testCounts,modelProvider:t,framework:h,scope:a},v=await et(y);Ie(y,v),m.allPassing||(process.exitCode=1)}return m}var ut=require("child_process"),W=b(require("fs")),N=b(require("path"));var Se=b(require("fs")),ct=b(require("path"));function dt(e){let t=ct.resolve(process.cwd(),e);if(!Se.existsSync(t))throw new Error(`[Lisa.ai Coverage Error] Coverage file not found at ${t}`);let s=Se.readFileSync(t,"utf-8"),n=JSON.parse(s),o=[];for(let[i,r]of Object.entries(n))i!=="total"&&(r.lines.pct<100||r.statements.pct<100||r.functions.pct<100||r.branches.pct<100)&&o.push(i);return o}var be=new Set,je=0,De=3;function _t(e){let t=e.testingFramework,s=process.cwd();return W.existsSync(N.join(s,"angular.json"))?"npx ng test --no-watch --code-coverage --browsers=ChromeHeadless":t==="jest"?"npx jest --coverage --coverageReporters=json-summary":t==="vitest"?"npx vitest run --coverage":[".mocharc.yml",".mocharc.yaml",".mocharc.json",".mocharc.js"].some(o=>W.existsSync(N.join(s,o)))?"npx nyc --reporter=json-summary mocha":null}async function pt(e,t,s=1,n=3,o="local",i,r){let a=P.load(process.cwd());a&&(P.applyEnvDefaults(a),!e&&a.testCommand&&(e=a.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${e}`)));let p=V.scanRepository(),g=a?.testingFramework||(p.testingFramework!=="none"?p.testingFramework:void 0),d=a?.testTypes;if(!e){console.log(`
165
+ [Lisa.ai Auto-Discovery] No explicit --command provided. Auto-detecting coverage command...`);let f=_t(p);if(f)e=f,console.log(`[Lisa.ai Auto-Discovery] Detected coverage command: ${e}`);else{let w=p;if(w.testingFramework==="none"&&(w=await ae.installMissingFramework(w),await re.provisionConfigurationFiles(w,t,i)),w.suggestedTestCommand){e=w.suggestedTestCommand;let l=w.testingFramework;(l==="jest"||l==="vitest")&&!e.includes("--coverage")&&(e=e.includes("npm run")?`${e} -- --coverage`:`${e} --coverage`,console.log(`[Lisa.ai Unit] Coverage flag appended: ${e}`)),console.log(`[Lisa.ai Auto-Discovery] Bootstrapping with discovered command: ${e}`)}else console.error(`
166
166
  [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(`
167
- [Lisa.ai Unit] ${e} (Attempt ${s}/${n}) Using Model: ${t}`);let x=le(e);await I({projectId:o,type:"unit",filePath:"global-test-suite",modelUsed:t,status:"running",details:"Agent is executing unit test suite and validating coverage...",testFramework:x});let h=(f,w=!1)=>new Promise((l,p)=>{let c=(0,ut.spawn)(f,{shell:!0,stdio:["ignore","pipe","pipe"]}),k="",$="";c.stdout?.on("data",m=>{let y=m.toString();if(k+=y,w){let v=y.split(`
168
- `);for(let C of v){let L=C.match(/Executed\s+(\d+)\s+of\s+(\d+)/);if(L){let E=C.match(/(\d+)\s+FAILED/),G=E?E[1]:0,M=`\r[Lisa.ai Testing] Executed ${L[1]} of ${L[2]} (${G} FAILED) `;process.stdout.write(M)}}}}),c.stderr?.on("data",m=>{$+=m.toString()}),c.on("close",m=>{m===0?l({stdout:k,stderr:$}):p({message:`Test process exited with code ${m}`,stdout:k,stderr:$})})});try{console.log("[Lisa.ai Unit] Running tests with coverage. This may take a moment...");let f=await h(e,!0),w=f.stdout+`
167
+ [Lisa.ai Unit] ${e} (Attempt ${s}/${n}) Using Model: ${t}`);let x=le(e);await I({projectId:o,type:"unit",filePath:"global-test-suite",modelUsed:t,status:"running",details:"Agent is executing unit test suite and validating coverage...",testFramework:x});let h=(f,w=!1)=>new Promise((l,u)=>{let c=(0,ut.spawn)(f,{shell:!0,stdio:["ignore","pipe","pipe"]}),L="",$="";c.stdout?.on("data",m=>{let y=m.toString();if(L+=y,w){let v=y.split(`
168
+ `);for(let C of v){let k=C.match(/Executed\s+(\d+)\s+of\s+(\d+)/);if(k){let E=C.match(/(\d+)\s+FAILED/),G=E?E[1]:0,M=`\r[Lisa.ai Testing] Executed ${k[1]} of ${k[2]} (${G} FAILED) `;process.stdout.write(M)}}}}),c.stderr?.on("data",m=>{$+=m.toString()}),c.on("close",m=>{m===0?l({stdout:L,stderr:$}):u({message:`Test process exited with code ${m}`,stdout:L,stderr:$})})});try{console.log("[Lisa.ai Unit] Running tests with coverage. This may take a moment...");let f=await h(e,!0),w=f.stdout+`
169
169
  `+f.stderr,l=Y(w);l&&await I({projectId:o,type:"unit",filePath:"global-test-suite",modelUsed:t,status:"success",details:`Tests passed on attempt ${s}.`,testTotal:l.total,testPassed:l.passed,testFailed:l.failed,testFramework:x}),console.log(`
170
170
  [Lisa.ai Unit] Tests passed on attempt ${s}.`)}catch(f){let w=(f.stderr||"")+`
171
171
  `+(f.stdout||"")+`
@@ -173,28 +173,28 @@ ${C}`);let L=Ee(v,process.cwd(),[]),E=L.filter(M=>fe.has(M)),G=L.filter(M=>!fe.h
173
173
  [Lisa.ai Unit] Tests failed. Delegating to Auto-Heal...`),await ce(e,t,1,n,o,void 0,i),console.log(`
174
174
  [Lisa.ai Unit] Auto-Heal complete. Continuing to test generation...`)):console.log(`
175
175
  [Lisa.ai Unit] No failing spec detected. Tests may not exist yet \u2014 initiating Cold-Start Discovery...`)}try{let f=[];if(r&&r.length>0)f=r,console.log(`
176
- [Lisa.ai Unit] Targeting ${r.length} file(s) from --files`),f.forEach(l=>console.log(` - ${l}`));else{let l=D.resolve(process.cwd(),"coverage/coverage-summary.json");if(V.existsSync(l))console.log("[Lisa.ai Unit] Evaluating coverage summary..."),f=dt("coverage/coverage-summary.json");else{if(console.log(`
177
- [Lisa.ai Unit] No coverage-summary.json found. Initiating Cold-Start Discovery...`),f=z.findUntestedFiles(process.cwd(),[...Ne]),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 w=0;for(let l of f){if(Ne.has(l))continue;let p=D.resolve(process.cwd(),l),c=D.parse(p),k=[D.join(c.dir,`${c.name}.spec${c.ext}`),D.join(c.dir,`${c.name}.test${c.ext}`),D.join(c.dir,`${c.name}.spec.js`),D.join(c.dir,`${c.name}.test.js`),D.join(c.dir,`${c.name}.spec.ts`),D.join(c.dir,`${c.name}.test.ts`)],$=null,m=D.join(c.dir,`${c.name}.spec${c.ext}`);for(let L of k)if(V.existsSync(L)){m=L,$=V.readFileSync(L,"utf-8");break}let y="",v=!1,C=V.readFileSync(p,"utf-8");try{$?(console.log(`
178
- [Lisa.ai Unit] [${w+1}/${f.length}] Existing spec found for ${l}. Requesting coverage append...`),y=await Ze(l,C,D.relative(process.cwd(),m),$,t,i,g,d)):(console.log(`
179
- [Lisa.ai Unit] [${w+1}/${f.length}] Generating new spec for ${l}...`),y=await ee(l,C,t,i,g,d)),be=0,v=!0}catch(L){be++,Ne.add(l);let E=L.cause?.message?`${L.message} (cause: ${L.cause.message})`:L.message;if(console.error(`
180
- [Lisa.ai Unit] LLM call failed for ${l} \u2014 consecutive failure #${be}/${De}`),console.error(` Error: ${E}`),be>=De)throw new Error(`Systematic LLM failure: ${De} consecutive API calls failed.
176
+ [Lisa.ai Unit] Targeting ${r.length} file(s) from --files`),f.forEach(l=>console.log(` - ${l}`));else{let l=N.resolve(process.cwd(),"coverage/coverage-summary.json");if(W.existsSync(l))console.log("[Lisa.ai Unit] Evaluating coverage summary..."),f=dt("coverage/coverage-summary.json");else{if(console.log(`
177
+ [Lisa.ai Unit] No coverage-summary.json found. Initiating Cold-Start Discovery...`),f=V.findUntestedFiles(process.cwd(),[...be]),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...`)}let u=V.findUntestedFiles(process.cwd(),[...be]);if(u.length>0){let c=new Set(f.map($=>N.resolve(process.cwd(),$))),L=u.filter($=>!c.has(N.resolve(process.cwd(),$)));L.length>0&&(console.log(`[Lisa.ai Unit] Discovered ${L.length} additional source file(s) with no tests.`),f.push(...L))}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 w=0;for(let l of f){if(be.has(l))continue;let u=N.resolve(process.cwd(),l),c=N.parse(u),L=[N.join(c.dir,`${c.name}.spec${c.ext}`),N.join(c.dir,`${c.name}.test${c.ext}`),N.join(c.dir,`${c.name}.spec.js`),N.join(c.dir,`${c.name}.test.js`),N.join(c.dir,`${c.name}.spec.ts`),N.join(c.dir,`${c.name}.test.ts`)],$=null,m=N.join(c.dir,`${c.name}.spec${c.ext}`);for(let k of L)if(W.existsSync(k)){m=k,$=W.readFileSync(k,"utf-8");break}let y="",v=!1,C=W.readFileSync(u,"utf-8");try{$?(console.log(`
178
+ [Lisa.ai Unit] [${w+1}/${f.length}] Existing spec found for ${l}. Requesting coverage append...`),y=await Ze(l,C,N.relative(process.cwd(),m),$,t,i,g,d)):(console.log(`
179
+ [Lisa.ai Unit] [${w+1}/${f.length}] Generating new spec for ${l}...`),y=await ee(l,C,t,i,g,d)),je=0,v=!0}catch(k){je++,be.add(l);let E=k.cause?.message?`${k.message} (cause: ${k.cause.message})`:k.message;if(console.error(`
180
+ [Lisa.ai Unit] LLM call failed for ${l} \u2014 consecutive failure #${je}/${De}`),console.error(` Error: ${E}`),je>=De)throw new Error(`Systematic LLM failure: ${De} consecutive API calls failed.
181
181
  This usually means your API key has insufficient credits, hit a rate limit, or the model is unavailable.
182
182
  Last error: ${E}
183
- Tip: Check your API key, account credits, and rate-limit quota for provider '${t}'.`)}v&&(V.writeFileSync(m,y,"utf-8"),w++,console.log(`[Lisa.ai Unit] Wrote spec to ${m}`),await I({projectId:o,type:"unit",filePath:l,modelUsed:t,status:"success",details:`### Unit Test Generated
183
+ Tip: Check your API key, account credits, and rate-limit quota for provider '${t}'.`)}v&&(W.writeFileSync(m,y,"utf-8"),w++,console.log(`[Lisa.ai Unit] Wrote spec to ${m}`),await I({projectId:o,type:"unit",filePath:l,modelUsed:t,status:"success",details:`### Unit Test Generated
184
184
  **Auto-Generated Spec (${t}):**
185
185
  \`\`\`typescript
186
186
  ${y}
187
187
  \`\`\``,testFramework:x}))}if(console.log(`
188
- [Lisa.ai Unit] Generated ${w} spec file(s).`),w>0){console.log("[Lisa.ai Unit] Running verification pass...");try{let l=await h(e,!0),p=l.stdout+`
189
- `+l.stderr,c=Y(p);console.log(`
188
+ [Lisa.ai Unit] Generated ${w} spec file(s).`),w>0){console.log("[Lisa.ai Unit] Running verification pass...");try{let l=await h(e,!0),u=l.stdout+`
189
+ `+l.stderr,c=Y(u);console.log(`
190
190
  [Lisa.ai Unit] Verification passed.`),c&&(console.log(`[Lisa.ai Unit] Final: ${c.passed}/${c.total} passing, ${c.failed} failing.`),await I({projectId:o,type:"unit",filePath:"global-test-suite",modelUsed:t,status:c.failed===0?"success":"error",details:`Verification after generating ${w} specs.`,testTotal:c.total,testPassed:c.passed,testFailed:c.failed,testFramework:x})),c&&c.failed>0&&s<n&&(console.log(`
191
- [Lisa.ai Unit] ${c.failed} generated test(s) failing. Delegating to Auto-Heal...`),await ce(e,t,1,n,o,void 0,i))}catch(l){let p=(l.stderr||"")+`
192
- `+(l.stdout||""),c=Y(p);c&&c.failed>0&&s<n?(console.log(`
191
+ [Lisa.ai Unit] ${c.failed} generated test(s) failing. Delegating to Auto-Heal...`),await ce(e,t,1,n,o,void 0,i))}catch(l){let u=(l.stderr||"")+`
192
+ `+(l.stdout||""),c=Y(u);c&&c.failed>0&&s<n?(console.log(`
193
193
  [Lisa.ai Unit] ${c.failed} generated test(s) failing. Delegating to Auto-Heal...`),await ce(e,t,1,n,o,void 0,i)):console.log(`
194
- [Lisa.ai Unit] Some generated tests failed. Run 'lisa-agent heal' to fix them.`)}}}catch(f){console.error("[Lisa.ai Unit loop failure]:",f.message),await I({projectId:o,type:"unit",filePath:"unit-loop",modelUsed:t,status:"error",details:`Unit test generation encountered an unrecoverable error: ${f.message}`,testFramework:x})}}var gt=require("child_process"),T=b(require("fs")),q=b(require("path"));function Ot(e){let t=[],s=["src/app/app.routes.ts","src/app/app-routing.module.ts"];for(let o of s){let i=q.join(e,o);if(T.existsSync(i)){let a=T.readFileSync(i,"utf-8").matchAll(/path:\s*['"`]([^'"`]+)['"`]/g);for(let u of a)u[1]&&u[1]!=="**"&&t.push(u[1])}}let n=["src/App.tsx","src/App.jsx","src/routes.tsx","src/routes.jsx"];for(let o of n){let i=q.join(e,o);if(T.existsSync(i)){let a=T.readFileSync(i,"utf-8").matchAll(/path=["']([^"']+)["']/g);for(let u of a)u[1]&&t.push(u[1])}}return[...new Set(t)].sort()}async function ft(e,t,s=1,n=3,o="local",i,r){if(s>n){console.log(`
195
- [Lisa.ai E2E] Reached maximum retries (${n}). Stopping.`);return}let a=process.cwd(),u=P.load(a);u&&(P.applyEnvDefaults(u),!e&&u.e2eCommand&&(e=u.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${e}`)));let g=ke(a),d=u?.e2eFramework||g.framework;console.log(`
194
+ [Lisa.ai Unit] Some generated tests failed. Run 'lisa-agent heal' to fix them.`)}}}catch(f){console.error("[Lisa.ai Unit loop failure]:",f.message),await I({projectId:o,type:"unit",filePath:"unit-loop",modelUsed:t,status:"error",details:`Unit test generation encountered an unrecoverable error: ${f.message}`,testFramework:x})}}var gt=require("child_process"),T=b(require("fs")),q=b(require("path"));function Ot(e){let t=[],s=["src/app/app.routes.ts","src/app/app-routing.module.ts"];for(let o of s){let i=q.join(e,o);if(T.existsSync(i)){let a=T.readFileSync(i,"utf-8").matchAll(/path:\s*['"`]([^'"`]+)['"`]/g);for(let p of a)p[1]&&p[1]!=="**"&&t.push(p[1])}}let n=["src/App.tsx","src/App.jsx","src/routes.tsx","src/routes.jsx"];for(let o of n){let i=q.join(e,o);if(T.existsSync(i)){let a=T.readFileSync(i,"utf-8").matchAll(/path=["']([^"']+)["']/g);for(let p of a)p[1]&&t.push(p[1])}}return[...new Set(t)].sort()}async function ft(e,t,s=1,n=3,o="local",i,r){if(s>n){console.log(`
195
+ [Lisa.ai E2E] Reached maximum retries (${n}). Stopping.`);return}let a=process.cwd(),p=P.load(a);p&&(P.applyEnvDefaults(p),!e&&p.e2eCommand&&(e=p.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${e}`)));let g=ke(a),d=p?.e2eFramework||g.framework;console.log(`
196
196
  [Lisa.ai E2E] Framework: ${d} (Attempt ${s}/${n}) Model: ${t}`),!g.installed&&d==="playwright"&&Ce(a),e||(e=g.command,console.log(`[Lisa.ai E2E] Using auto-detected command: ${e}`)),await I({projectId:o,type:"e2e",filePath:"e2e-suite",modelUsed:t,status:"running",details:`E2E test generation started with ${d}`,testFramework:d});let x=0;if(r&&r.length>0){console.log(`
197
- [Lisa.ai E2E] Targeting ${r.length} file(s) from --files`),r.forEach(c=>console.log(` - ${c}`));for(let c of r){let k=q.resolve(a,c);if(T.existsSync(k)){console.log(`[Lisa.ai E2E] Spec already exists: ${c} \u2014 will run as-is.`);continue}let $=q.dirname(k);T.existsSync($)||T.mkdirSync($,{recursive:!0}),console.log(`[Lisa.ai E2E] Generating E2E spec: ${c}...`);let m=`
197
+ [Lisa.ai E2E] Targeting ${r.length} file(s) from --files`),r.forEach(c=>console.log(` - ${c}`));for(let c of r){let L=q.resolve(a,c);if(T.existsSync(L)){console.log(`[Lisa.ai E2E] Spec already exists: ${c} \u2014 will run as-is.`);continue}let $=q.dirname(L);T.existsSync($)||T.mkdirSync($,{recursive:!0}),console.log(`[Lisa.ai E2E] Generating E2E spec: ${c}...`);let m=`
198
198
  E2E Test Generation Context:
199
199
  - Framework: ${d}
200
200
  - Target file: ${c}
@@ -209,7 +209,7 @@ The test should:
209
209
  4. Assert critical UI elements are visible
210
210
 
211
211
  Use @playwright/test imports. Keep it concise and practical.
212
- `;try{let y=await ee(c,m,t,i,d,["e2e"]);T.writeFileSync(k,y,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${c}`),x++,await I({projectId:o,type:"e2e",filePath:c,modelUsed:t,status:"success",details:`Generated E2E spec: ${c}`,testFramework:d})}catch(y){console.error(`[Lisa.ai E2E] LLM failed for ${c}: ${y.message}`),await I({projectId:o,type:"e2e",filePath:c,modelUsed:t,status:"error",details:`LLM failed to generate E2E spec: ${y.message}`,testFramework:d})}}if(x===0&&r.every(c=>!T.existsSync(q.resolve(a,c)))){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}}else{let c=Ot(a);c.length===0?(console.log("[Lisa.ai E2E] No routes discovered. Will generate basic smoke test."),c.push("")):console.log(`[Lisa.ai E2E] Discovered ${c.length} route(s):`,c);let k=q.join(a,"e2e");T.existsSync(k)||T.mkdirSync(k,{recursive:!0});let $=T.existsSync(k)?T.readdirSync(k).filter(m=>m.endsWith(".spec.ts")||m.endsWith(".test.ts")):[];for(let m of c){let v=`${(m||"home").replace(/\//g,"-")}.spec.ts`,C=q.join(k,v);if($.includes(v)){console.log(`[Lisa.ai E2E] Spec already exists for /${m} \u2014 skipping.`);continue}console.log(`[Lisa.ai E2E] Generating E2E spec for /${m}...`);try{let L=`
212
+ `;try{let y=await ee(c,m,t,i,d,["e2e"]);T.writeFileSync(L,y,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${c}`),x++,await I({projectId:o,type:"e2e",filePath:c,modelUsed:t,status:"success",details:`Generated E2E spec: ${c}`,testFramework:d})}catch(y){console.error(`[Lisa.ai E2E] LLM failed for ${c}: ${y.message}`),await I({projectId:o,type:"e2e",filePath:c,modelUsed:t,status:"error",details:`LLM failed to generate E2E spec: ${y.message}`,testFramework:d})}}if(x===0&&r.every(c=>!T.existsSync(q.resolve(a,c)))){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}}else{let c=Ot(a);c.length===0?(console.log("[Lisa.ai E2E] No routes discovered. Will generate basic smoke test."),c.push("")):console.log(`[Lisa.ai E2E] Discovered ${c.length} route(s):`,c);let L=q.join(a,"e2e");T.existsSync(L)||T.mkdirSync(L,{recursive:!0});let $=T.existsSync(L)?T.readdirSync(L).filter(m=>m.endsWith(".spec.ts")||m.endsWith(".test.ts")):[];for(let m of c){let v=`${(m||"home").replace(/\//g,"-")}.spec.ts`,C=q.join(L,v);if($.includes(v)){console.log(`[Lisa.ai E2E] Spec already exists for /${m} \u2014 skipping.`);continue}console.log(`[Lisa.ai E2E] Generating E2E spec for /${m}...`);try{let k=`
213
213
  E2E Test Generation Context:
214
214
  - Framework: ${d}
215
215
  - Route: /${m}
@@ -224,15 +224,15 @@ The test should:
224
224
  4. Assert critical UI elements are visible
225
225
 
226
226
  Use @playwright/test imports. Keep it concise and practical.
227
- `,E=await ee(`e2e/${v}`,L,t,i,d,["e2e"]);T.writeFileSync(C,E,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${v}`),x++,await I({projectId:o,type:"e2e",filePath:`e2e/${v}`,modelUsed:t,status:"success",details:`Generated E2E spec for route /${m}`,testFramework:d})}catch(L){console.error(`[Lisa.ai E2E] LLM failed for /${m}: ${L.message}`),await I({projectId:o,type:"e2e",filePath:`e2e/${v}`,modelUsed:t,status:"error",details:`LLM failed to generate E2E spec: ${L.message}`,testFramework:d})}}if(x===0&&$.length===0){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}}console.log(`
228
- [Lisa.ai E2E] Running E2E tests: ${e}`);let h="",f="",w=!1;try{await new Promise((c,k)=>{let $=(0,gt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:a});$.stdout?.on("data",m=>{let y=m.toString();h+=y,process.stdout.write(y)}),$.stderr?.on("data",m=>{let y=m.toString();f+=y,process.stderr.write(y)}),$.on("close",m=>{m===0?c():k(new Error(`E2E tests exited with code ${m}`))})}),w=!0,console.log(`
227
+ `,E=await ee(`e2e/${v}`,k,t,i,d,["e2e"]);T.writeFileSync(C,E,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${v}`),x++,await I({projectId:o,type:"e2e",filePath:`e2e/${v}`,modelUsed:t,status:"success",details:`Generated E2E spec for route /${m}`,testFramework:d})}catch(k){console.error(`[Lisa.ai E2E] LLM failed for /${m}: ${k.message}`),await I({projectId:o,type:"e2e",filePath:`e2e/${v}`,modelUsed:t,status:"error",details:`LLM failed to generate E2E spec: ${k.message}`,testFramework:d})}}if(x===0&&$.length===0){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}}console.log(`
228
+ [Lisa.ai E2E] Running E2E tests: ${e}`);let h="",f="",w=!1;try{await new Promise((c,L)=>{let $=(0,gt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:a});$.stdout?.on("data",m=>{let y=m.toString();h+=y,process.stdout.write(y)}),$.stderr?.on("data",m=>{let y=m.toString();f+=y,process.stderr.write(y)}),$.on("close",m=>{m===0?c():L(new Error(`E2E tests exited with code ${m}`))})}),w=!0,console.log(`
229
229
  [Lisa.ai E2E] All E2E tests passed.`)}catch{console.log(`
230
230
  [Lisa.ai E2E] Some E2E tests failed. Run 'lisa-agent heal --type e2e' to auto-fix.`)}let l=h+`
231
- `+f,p=Y(l);await I({projectId:o,type:"e2e",filePath:"e2e-suite",modelUsed:t,status:w?"success":"error",details:`E2E generation complete. ${x} new spec(s) generated.`,...p&&{testTotal:p.total,testPassed:p.passed,testFailed:p.failed},testFramework:d})}var mt=require("child_process"),A=b(require("fs")),F=b(require("path"));function Gt(e){let t=F.join(e,"package.json");if(!A.existsSync(t))return"node";let s=JSON.parse(A.readFileSync(t,"utf-8")),n={...s.dependencies||{},...s.devDependencies||{}};return n["@angular/core"]?"angular":n.react?"react":n.vue?"vue":n["@nestjs/core"]?"nestjs":n.express?"express":"node"}function Ht(e,t){let s=[];if(t==="angular"){let n=F.join(e,"src","app");if(!A.existsSync(n))return s;let o=me(n,/\.(ts)$/).filter(i=>!i.includes(".spec.")&&!i.includes(".test.")&&!i.includes("node_modules"));for(let i of o){let r=A.readFileSync(i,"utf-8");if(r.includes("@Component")&&r.includes("inject(")){let a=F.relative(e,i),u=a.replace(/\.ts$/,".integration.spec.ts");if(A.existsSync(F.join(e,u)))continue;let d=[...r.matchAll(/inject\((\w+)\)/g)].map(h=>h[1]),x=[];for(let h of d){let f=me(n,new RegExp(`${qt(h)}\\.ts$`));x.push(...f.map(w=>F.relative(e,w)))}s.push({filePath:a,relatedFiles:x,description:`Angular component+service integration: ${F.basename(i)} injects ${d.join(", ")}`})}}}else if(t==="express"||t==="nestjs"){let n=["src","server","api","routes","controllers"];for(let o of n){let i=F.join(e,o);if(!A.existsSync(i))continue;let r=me(i,/\.(controller|route|router)\.(ts|js)$/).filter(a=>!a.includes(".spec.")&&!a.includes(".test.")&&!a.includes("node_modules"));for(let a of r){let u=F.relative(e,a),g=u.replace(/\.(ts|js)$/,".integration.spec.$1");A.existsSync(F.join(e,g))||s.push({filePath:u,relatedFiles:[],description:`API endpoint integration test for ${F.basename(a)} \u2014 test with supertest against real middleware chain`})}}}else{let n=F.join(e,"src");if(A.existsSync(n)){let o=me(n,/\.(ts|js|tsx|jsx)$/).filter(i=>!i.includes(".spec.")&&!i.includes(".test.")&&!i.includes("node_modules"));for(let i of o){let a=[...A.readFileSync(i,"utf-8").matchAll(/from\s+['"]\.\.?\//g)];if(a.length>=2){let u=F.relative(e,i),g=u.replace(/\.(ts|js|tsx|jsx)$/,".integration.spec.$1");if(A.existsSync(F.join(e,g)))continue;s.push({filePath:u,relatedFiles:[],description:`Module integration: ${F.basename(i)} imports ${a.length} local modules`})}}}}return s}function me(e,t){let s=[],n=["node_modules","dist","build",".git",".angular","coverage"];if(!A.existsSync(e))return s;let o=A.readdirSync(e);for(let i of o){if(n.includes(i))continue;let r=F.join(e,i);try{A.statSync(r).isDirectory()?s.push(...me(r,t)):t.test(i)&&s.push(r)}catch{continue}}return s}function qt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}async function ht(e,t,s=1,n=3,o="local",i,r){if(s>n){console.log(`
232
- [Lisa.ai Integration] Reached maximum retries (${n}). Stopping.`);return}let a=process.cwd(),u=P.load(a);u&&(P.applyEnvDefaults(u),!e&&u.testCommand&&(e=u.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${e}`)));let g=Gt(a),d=z.scanRepository(),x=u?.testingFramework||(d.testingFramework!=="none"?d.testingFramework:void 0);console.log(`
231
+ `+f,u=Y(l);await I({projectId:o,type:"e2e",filePath:"e2e-suite",modelUsed:t,status:w?"success":"error",details:`E2E generation complete. ${x} new spec(s) generated.`,...u&&{testTotal:u.total,testPassed:u.passed,testFailed:u.failed},testFramework:d})}var mt=require("child_process"),A=b(require("fs")),F=b(require("path"));function Gt(e){let t=F.join(e,"package.json");if(!A.existsSync(t))return"node";let s=JSON.parse(A.readFileSync(t,"utf-8")),n={...s.dependencies||{},...s.devDependencies||{}};return n["@angular/core"]?"angular":n.react?"react":n.vue?"vue":n["@nestjs/core"]?"nestjs":n.express?"express":"node"}function Ht(e,t){let s=[];if(t==="angular"){let n=F.join(e,"src","app");if(!A.existsSync(n))return s;let o=me(n,/\.(ts)$/).filter(i=>!i.includes(".spec.")&&!i.includes(".test.")&&!i.includes("node_modules"));for(let i of o){let r=A.readFileSync(i,"utf-8");if(r.includes("@Component")&&r.includes("inject(")){let a=F.relative(e,i),p=a.replace(/\.ts$/,".integration.spec.ts");if(A.existsSync(F.join(e,p)))continue;let d=[...r.matchAll(/inject\((\w+)\)/g)].map(h=>h[1]),x=[];for(let h of d){let f=me(n,new RegExp(`${qt(h)}\\.ts$`));x.push(...f.map(w=>F.relative(e,w)))}s.push({filePath:a,relatedFiles:x,description:`Angular component+service integration: ${F.basename(i)} injects ${d.join(", ")}`})}}}else if(t==="express"||t==="nestjs"){let n=["src","server","api","routes","controllers"];for(let o of n){let i=F.join(e,o);if(!A.existsSync(i))continue;let r=me(i,/\.(controller|route|router)\.(ts|js)$/).filter(a=>!a.includes(".spec.")&&!a.includes(".test.")&&!a.includes("node_modules"));for(let a of r){let p=F.relative(e,a),g=p.replace(/\.(ts|js)$/,".integration.spec.$1");A.existsSync(F.join(e,g))||s.push({filePath:p,relatedFiles:[],description:`API endpoint integration test for ${F.basename(a)} \u2014 test with supertest against real middleware chain`})}}}else{let n=F.join(e,"src");if(A.existsSync(n)){let o=me(n,/\.(ts|js|tsx|jsx)$/).filter(i=>!i.includes(".spec.")&&!i.includes(".test.")&&!i.includes("node_modules"));for(let i of o){let a=[...A.readFileSync(i,"utf-8").matchAll(/from\s+['"]\.\.?\//g)];if(a.length>=2){let p=F.relative(e,i),g=p.replace(/\.(ts|js|tsx|jsx)$/,".integration.spec.$1");if(A.existsSync(F.join(e,g)))continue;s.push({filePath:p,relatedFiles:[],description:`Module integration: ${F.basename(i)} imports ${a.length} local modules`})}}}}return s}function me(e,t){let s=[],n=["node_modules","dist","build",".git",".angular","coverage"];if(!A.existsSync(e))return s;let o=A.readdirSync(e);for(let i of o){if(n.includes(i))continue;let r=F.join(e,i);try{A.statSync(r).isDirectory()?s.push(...me(r,t)):t.test(i)&&s.push(r)}catch{continue}}return s}function qt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}async function ht(e,t,s=1,n=3,o="local",i,r){if(s>n){console.log(`
232
+ [Lisa.ai Integration] Reached maximum retries (${n}). Stopping.`);return}let a=process.cwd(),p=P.load(a);p&&(P.applyEnvDefaults(p),!e&&p.testCommand&&(e=p.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${e}`)));let g=Gt(a),d=V.scanRepository(),x=p?.testingFramework||(d.testingFramework!=="none"?d.testingFramework:void 0);console.log(`
233
233
  [Lisa.ai Integration] App: ${g}, Framework: ${x||"auto"} (Attempt ${s}/${n}) Model: ${t}`),e||(d.suggestedTestCommand?e=d.suggestedTestCommand:A.existsSync(F.join(a,"angular.json"))?e="npx ng test --no-watch --browsers=ChromeHeadless":(console.error(`
234
234
  [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: ${e}`));let h=le(e);await I({projectId:o,type:"integration",filePath:"integration-suite",modelUsed:t,status:"running",details:`Integration test generation started for ${g} app`,testFramework:h});let f;if(r&&r.length>0)f=r.map(m=>({filePath:m,relatedFiles:[],description:"User-specified"})),console.log(`
235
- [Lisa.ai Integration] Targeting ${r.length} file(s) from --files`),f.forEach(m=>console.log(` - ${m.filePath}`));else{if(f=Ht(a,g),f.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 ${f.length} integration target(s):`),f.forEach(m=>console.log(` - ${m.filePath}: ${m.description}`))}let w=0;for(let m of f){let y=F.resolve(a,m.filePath);if(!A.existsSync(y))continue;let v=F.parse(y),C=F.join(v.dir,`${v.name}.integration.spec${v.ext}`);if(A.existsSync(C)){console.log(`[Lisa.ai Integration] Spec exists for ${m.filePath} \u2014 skipping.`);continue}console.log(`[Lisa.ai Integration] Generating integration spec for ${m.filePath}...`);let L=A.readFileSync(y,"utf-8"),E="";for(let M of m.relatedFiles.slice(0,3)){let j=F.resolve(a,M);if(A.existsSync(j)){let U=A.readFileSync(j,"utf-8");E+=`
235
+ [Lisa.ai Integration] Targeting ${r.length} file(s) from --files`),f.forEach(m=>console.log(` - ${m.filePath}`));else{if(f=Ht(a,g),f.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 ${f.length} integration target(s):`),f.forEach(m=>console.log(` - ${m.filePath}: ${m.description}`))}let w=0;for(let m of f){let y=F.resolve(a,m.filePath);if(!A.existsSync(y))continue;let v=F.parse(y),C=F.join(v.dir,`${v.name}.integration.spec${v.ext}`);if(A.existsSync(C)){console.log(`[Lisa.ai Integration] Spec exists for ${m.filePath} \u2014 skipping.`);continue}console.log(`[Lisa.ai Integration] Generating integration spec for ${m.filePath}...`);let k=A.readFileSync(y,"utf-8"),E="";for(let M of m.relatedFiles.slice(0,3)){let j=F.resolve(a,M);if(A.existsSync(j)){let U=A.readFileSync(j,"utf-8");E+=`
236
236
 
237
237
  // --- Related file: ${M} ---
238
238
  ${U.slice(0,5e3)}`}}let G=`
@@ -255,32 +255,32 @@ ${g==="angular"?`
255
255
  `}
256
256
 
257
257
  Source file:
258
- ${L.slice(0,1e4)}
258
+ ${k.slice(0,1e4)}
259
259
 
260
260
  ${E?`Related modules:
261
261
  ${E}`:""}
262
262
  `;try{let M=await ee(m.filePath,G,t,i,x,["integration"]);A.writeFileSync(C,M,"utf-8"),console.log(`[Lisa.ai Integration] Wrote ${F.relative(a,C)}`),w++,await I({projectId:o,type:"integration",filePath:m.filePath,modelUsed:t,status:"success",details:`Generated integration spec: ${m.description}`,testFramework:h})}catch(M){console.error(`[Lisa.ai Integration] LLM failed for ${m.filePath}: ${M.message}`)}}if(w===0){console.log("[Lisa.ai Integration] No new integration specs generated.");return}console.log(`
263
- [Lisa.ai Integration] Running tests to verify generated specs: ${e}`);let l="",p="",c=!1;try{await new Promise((m,y)=>{let v=(0,mt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:a});v.stdout?.on("data",C=>{let L=C.toString();l+=L,process.stdout.write(L)}),v.stderr?.on("data",C=>{let L=C.toString();p+=L,process.stderr.write(L)}),v.on("close",C=>{C===0?m():y(new Error(`Tests exited with code ${C}`))})}),c=!0,console.log(`
263
+ [Lisa.ai Integration] Running tests to verify generated specs: ${e}`);let l="",u="",c=!1;try{await new Promise((m,y)=>{let v=(0,mt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"],cwd:a});v.stdout?.on("data",C=>{let k=C.toString();l+=k,process.stdout.write(k)}),v.stderr?.on("data",C=>{let k=C.toString();u+=k,process.stderr.write(k)}),v.on("close",C=>{C===0?m():y(new Error(`Tests exited with code ${C}`))})}),c=!0,console.log(`
264
264
  [Lisa.ai Integration] All tests passed including integration specs.`)}catch{console.log(`
265
- [Lisa.ai Integration] Some tests failed. Run 'lisa-agent heal --type integration' to auto-fix.`)}let k=l+`
266
- `+p,$=Y(k);await I({projectId:o,type:"integration",filePath:"integration-suite",modelUsed:t,status:c?"success":"error",details:`Integration test generation complete. ${w} new spec(s) generated.`,...$&&{testTotal:$.total,testPassed:$.passed,testFailed:$.failed},testFramework:h})}var vt=b(require("dotenv")),xt=require("child_process"),Q=b(require("fs")),J=b(require("path"));vt.config({quiet:!0});function de(e){return new Promise(t=>{let s=(0,xt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"]}),n="",o="";s.stdout?.on("data",i=>{n+=i.toString()}),s.stderr?.on("data",i=>{o+=i.toString()}),s.on("close",i=>t({stdout:n,stderr:o,code:i??1}))})}function Bt(){return Q.existsSync(J.resolve(process.cwd(),"pnpm-lock.yaml"))?"pnpm":Q.existsSync(J.resolve(process.cwd(),"yarn.lock"))?"yarn":"npm"}var Yt={critical:"\u{1F534}",high:"\u{1F7E0}",moderate:"\u{1F7E1}",low:"\u{1F535}",info:"\u26AA"},yt={critical:5,high:4,moderate:3,low:2,info:1};function wt(e){let t=["critical","high","moderate","low","info"];for(let s of t){let n=e[s]??0;n>0&&console.log(` ${Yt[s]} ${s.padEnd(10)} ${n}`)}console.log(` ${"\u2500".repeat(22)}`),console.log(` ${"Total".padEnd(10)} ${e.total}`)}async function Ue(e){try{return JSON.parse(e)}catch{return null}}async function $t(e,t="local",s){Q.existsSync(J.resolve(process.cwd(),"package.json"))||(console.error(`
265
+ [Lisa.ai Integration] Some tests failed. Run 'lisa-agent heal --type integration' to auto-fix.`)}let L=l+`
266
+ `+u,$=Y(L);await I({projectId:o,type:"integration",filePath:"integration-suite",modelUsed:t,status:c?"success":"error",details:`Integration test generation complete. ${w} new spec(s) generated.`,...$&&{testTotal:$.total,testPassed:$.passed,testFailed:$.failed},testFramework:h})}var vt=b(require("dotenv")),xt=require("child_process"),Q=b(require("fs")),J=b(require("path"));vt.config({quiet:!0});function de(e){return new Promise(t=>{let s=(0,xt.spawn)(e,{shell:!0,stdio:["ignore","pipe","pipe"]}),n="",o="";s.stdout?.on("data",i=>{n+=i.toString()}),s.stderr?.on("data",i=>{o+=i.toString()}),s.on("close",i=>t({stdout:n,stderr:o,code:i??1}))})}function Bt(){return Q.existsSync(J.resolve(process.cwd(),"pnpm-lock.yaml"))?"pnpm":Q.existsSync(J.resolve(process.cwd(),"yarn.lock"))?"yarn":"npm"}var Yt={critical:"\u{1F534}",high:"\u{1F7E0}",moderate:"\u{1F7E1}",low:"\u{1F535}",info:"\u26AA"},yt={critical:5,high:4,moderate:3,low:2,info:1};function wt(e){let t=["critical","high","moderate","low","info"];for(let s of t){let n=e[s]??0;n>0&&console.log(` ${Yt[s]} ${s.padEnd(10)} ${n}`)}console.log(` ${"\u2500".repeat(22)}`),console.log(` ${"Total".padEnd(10)} ${e.total}`)}async function Ue(e){try{return JSON.parse(e)}catch{return null}}async function $t(e,t="local",s){Q.existsSync(J.resolve(process.cwd(),"package.json"))||(console.error(`
267
267
  \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 n=Bt();console.log(`[Lisa.ai Audit] Package manager: ${n}`),console.log(`
268
268
  [Lisa.ai Audit] Scanning for vulnerabilities...`);let{stdout:o,code:i}=await de(n==="npm"?"npm audit --json":n==="yarn"?"yarn audit --json":"pnpm audit --json");if(i===0){console.log(`
269
269
  \u2705 [Lisa.ai Audit] No vulnerabilities found! Repository is clean.`);return}let r=await Ue(o);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(`
270
270
  Vulnerabilities found:`),wt(a),console.log(`
271
- [Lisa.ai Audit] Applying safe automatic fixes (npm audit fix)...`);let{stdout:u}=await de(n==="npm"?"npm audit fix":n==="yarn"?"yarn upgrade":"pnpm audit fix");for(let j of u.split(`
271
+ [Lisa.ai Audit] Applying safe automatic fixes (npm audit fix)...`);let{stdout:p}=await de(n==="npm"?"npm audit fix":n==="yarn"?"yarn upgrade":"pnpm audit fix");for(let j of p.split(`
272
272
  `)){let U=j.trim();U&&!U.startsWith("npm warn")&&!U.startsWith("npm notice")&&console.log(` ${U}`)}let g=n==="npm"?"npm audit --json":n==="yarn"?"yarn audit --json":"pnpm audit --json",{stdout:d,code:x}=await de(g);if(x===0){console.log(`
273
273
  \u2705 [Lisa.ai Audit] All vulnerabilities fixed by safe auto-fix!`);return}let h=await Ue(d);if(!h){console.warn("[Lisa.ai Audit] Could not parse post-fix audit output.");return}let f=Object.values(h.vulnerabilities),w=h.metadata.vulnerabilities,l=a.total-w.total;console.log(`
274
- [Lisa.ai Audit] Safe auto-fix resolved ${l} vulnerability(-ies).`),w.total>0&&(console.log(" Remaining:"),wt(w));let p=f.filter(j=>typeof j.fixAvailable=="object"&&!j.fixAvailable.isSemVerMajor).map(j=>j.fixAvailable),c=[...new Map(p.map(j=>[j.name,j])).values()];if(c.length>0){console.log(`
274
+ [Lisa.ai Audit] Safe auto-fix resolved ${l} vulnerability(-ies).`),w.total>0&&(console.log(" Remaining:"),wt(w));let u=f.filter(j=>typeof j.fixAvailable=="object"&&!j.fixAvailable.isSemVerMajor).map(j=>j.fixAvailable),c=[...new Map(u.map(j=>[j.name,j])).values()];if(c.length>0){console.log(`
275
275
  [Lisa.ai Audit] Applying ${c.length} non-breaking targeted upgrade(s)...`);for(let oe of c){let B=`npm install ${oe.name}@${oe.version}`;console.log(` \u2192 ${B}`);let{stderr:ue}=await de(B);ue&&!ue.includes("npm warn")&&console.warn(` ${ue.trim()}`)}let{stdout:j,code:U}=await de(g);if(U===0){console.log(`
276
- \u2705 [Lisa.ai Audit] All vulnerabilities resolved!`);return}}let{stdout:k}=await de(g),$=await Ue(k)??h,y=Object.values($.vulnerabilities).sort((j,U)=>(yt[U.severity]??0)-(yt[j.severity]??0)).slice(0,10).filter(j=>j.fixAvailable===!1?!0:typeof j.fixAvailable=="object"?j.fixAvailable.isSemVerMajor:!1);if(y.length===0){console.log(`
276
+ \u2705 [Lisa.ai Audit] All vulnerabilities resolved!`);return}}let{stdout:L}=await de(g),$=await Ue(L)??h,y=Object.values($.vulnerabilities).sort((j,U)=>(yt[U.severity]??0)-(yt[j.severity]??0)).slice(0,10).filter(j=>j.fixAvailable===!1?!0:typeof j.fixAvailable=="object"?j.fixAvailable.isSemVerMajor:!1);if(y.length===0){console.log(`
277
277
  \u2705 [Lisa.ai Audit] No breaking-change or unfixable vulnerabilities remain.`);return}console.log(`
278
- [Lisa.ai Audit] ${y.length} vulnerability(-ies) require manual attention.`),console.log(`[Lisa.ai Audit] Consulting ${e} for remediation guidance...`);let v={};try{v=JSON.parse(Q.readFileSync(J.resolve(process.cwd(),"package.json"),"utf8"))}catch{}let C={...v.dependencies??{},...v.devDependencies??{}},L=y.map(j=>{let U=j.fixAvailable,oe=U===!1?"no fix available yet":`upgrade to ${U.name}@${U.version} (BREAKING \u2014 major version bump)`,B=C[j.name]?`current: ${C[j.name]}`:"transitive dependency";return`\u2022 ${j.name} (${j.severity}) \u2014 ${B} \u2014 ${oe}`}).join(`
278
+ [Lisa.ai Audit] ${y.length} vulnerability(-ies) require manual attention.`),console.log(`[Lisa.ai Audit] Consulting ${e} for remediation guidance...`);let v={};try{v=JSON.parse(Q.readFileSync(J.resolve(process.cwd(),"package.json"),"utf8"))}catch{}let C={...v.dependencies??{},...v.devDependencies??{}},k=y.map(j=>{let U=j.fixAvailable,oe=U===!1?"no fix available yet":`upgrade to ${U.name}@${U.version} (BREAKING \u2014 major version bump)`,B=C[j.name]?`current: ${C[j.name]}`:"transitive dependency";return`\u2022 ${j.name} (${j.severity}) \u2014 ${B} \u2014 ${oe}`}).join(`
279
279
  `),E=`You are a Node.js security expert helping a developer fix npm vulnerabilities.
280
280
 
281
281
  These vulnerabilities remain after safe auto-fixes were applied. Each requires either a breaking upgrade or has no automated fix:
282
282
 
283
- ${L}
283
+ ${k}
284
284
 
285
285
  For each vulnerability:
286
286
  1. Briefly explain the security risk (1 sentence).
@@ -291,7 +291,7 @@ For each vulnerability:
291
291
  Be concrete. Use numbered items. If a vulnerability is a transitive dependency, explain how to force a resolution override in package.json.`;try{let j=await ie(E,e,s);console.log(`
292
292
  Remediation guidance:
293
293
  `);for(let B of j.split(`
294
- `))console.log(` ${B}`);let U=J.resolve(process.cwd(),"lisa-audit-report.md"),oe=["# Lisa.ai Security Audit Report","",`Generated: ${new Date().toISOString()}`,`Project: ${v.name??J.basename(process.cwd())}`,"","## Summary","","| Severity | Initial | Remaining |","|----------|---------|-----------|",...["critical","high","moderate","low"].map(B=>{let ue=a[B]??0,bt=$.metadata.vulnerabilities[B]??0;return`| ${B} | ${ue} | ${bt} |`}),"","## Vulnerabilities Requiring Manual Action","",L,"",`## Remediation Guidance (${e})`,"",j].join(`
294
+ `))console.log(` ${B}`);let U=J.resolve(process.cwd(),"lisa-audit-report.md"),oe=["# Lisa.ai Security Audit Report","",`Generated: ${new Date().toISOString()}`,`Project: ${v.name??J.basename(process.cwd())}`,"","## Summary","","| Severity | Initial | Remaining |","|----------|---------|-----------|",...["critical","high","moderate","low"].map(B=>{let ue=a[B]??0,bt=$.metadata.vulnerabilities[B]??0;return`| ${B} | ${ue} | ${bt} |`}),"","## Vulnerabilities Requiring Manual Action","",k,"",`## Remediation Guidance (${e})`,"",j].join(`
295
295
  `);Q.writeFileSync(U,oe,"utf-8"),console.log(`
296
296
  [Lisa.ai Audit] Full report saved to: lisa-audit-report.md`)}catch(j){console.error(`
297
297
  [Lisa.ai Audit] LLM guidance failed: ${j.message}`),console.log(" Run 'npm audit' manually and address the remaining vulnerabilities.")}let G=$.metadata.vulnerabilities,M=a.total-G.total;console.log(`
@@ -300,18 +300,18 @@ ${"\u2500".repeat(50)}`),console.log(" Lisa.ai Audit Complete"),console.log(`
300
300
  \x1B[38;2;99;102;241m\u2554\u2550\u2557\x1B[0m \x1B[1mLisa.ai Agent\x1B[0m v${e}
301
301
  \x1B[38;2;99;102;241m\u2551\x1B[38;2;129;140;248m\u26A1\x1B[38;2;99;102;241m\u2551\x1B[0m Autonomous CI/CD Platform
302
302
  \x1B[38;2;99;102;241m\u255A\u2550\u255D\x1B[0m \x1B[2mheal \xB7 unit \xB7 e2e \xB7 integration \xB7 audit\x1B[0m
303
- `)}async function je(e){let t=5,s=e.model,n,o=P.load(process.cwd()),i=e.projectId||o?.projectId||"local";if(i!=="local"){let r=await ye(i);if(!r.ok)r.reason==="not_found"?(console.error(`
303
+ `)}async function Ee(e){let t=5,s=e.model,n,o=P.load(process.cwd()),i=e.projectId||o?.projectId||"local";if(i!=="local"){let r=await ye(i);if(!r.ok)r.reason==="not_found"?(console.error(`
304
304
  [Lisa.ai Agent Error] Project '${i}' does not exist on the Control Plane. Please create it in the Dashboard first or run locally without a project ID.`),process.exit(1)):console.warn(`
305
305
  [Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${s}, maxRetries=${t}).`);else{let a=r.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${a.modelProvider}, MaxRetries=${a.maxRetries}`),a.maxRetries<5&&console.warn(`
306
- [Lisa.ai Warning] maxRetries is ${a.maxRetries}. Consider increasing to 5+ for complex projects.`),s=a.modelProvider,t=a.maxRetries,n=a.apiKey,a.agentEnabled===!1&&(console.log("[Lisa.ai Agent] Agent is disabled by Control Plane for this project."),process.exit(1))}}return o&&(P.applyEnvDefaults(o),!e.projectId&&!o.projectId&&o.maxRetries!==void 0&&(t=o.maxRetries),!e.projectId&&!o.projectId&&o.provider&&e.model==="gemini"&&(s=o.provider),P.printSummary(o)),{model:s,maxRetries:t,apiKey:n,projectId:i}}var W=new kt.Command;W.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(St.version);W.command("heal").description("Run tests and autonomously heal all failures via LLM + Memory Engine").option("-c, --command <type>","Test command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-t, --type <scope>","Test type to heal: unit (default), e2e, integration","unit").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").option("--ci","CI mode: commit healed files, open PR, write GitHub Actions step summary").action(async e=>{ne();let t=["unit","e2e","integration"],s=e.type;t.includes(s)||(console.error(`
307
- [Lisa.ai Error] Invalid heal type '${e.type}'. Valid types: ${t.join(", ")}`),process.exit(1));let n=e.files?e.files.split(",").map(r=>r.trim()):void 0,o=e.ci===!0,i=await je(e);await ce(e.command,i.model,1,i.maxRetries,i.projectId,void 0,i.apiKey,s,n,o)});W.command("unit").description("Generate missing unit test specs to reach 100% coverage (auto-detects framework)").option("-c, --command <type>","Test+coverage command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await je(e);await pt(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});W.command("e2e").description("Generate E2E tests via Playwright (auto-installs if none detected)").option("-c, --command <type>","E2E command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await je(e);await ft(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});W.command("integration").description("Generate integration tests for module seams (component+service, API+DB)").option("-c, --command <type>","Test command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await je(e);await ht(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});W.command("diagnose").description("Test LLM connectivity and API key health without running the full agent").option("-m, --model <provider>","LLM provider to test (gemini, claude, openai)","claude").option("-p, --project-id <id>","Control Plane Project ID to fetch API key from").action(async e=>{ne();let t=e.model,s,n=P.load(process.cwd()),o=e.projectId||n?.projectId||"local";if(o!=="local"){let a=await ye(o);a.ok?(t=a.config.modelProvider,s=a.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${t}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${a.reason}. Using local env for API key.`)}let r={claude:process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5",openai:process.env.LISA_OPENAI_MODEL||"gpt-4o-mini",gemini:process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash"}[t]||t;console.log(`
306
+ [Lisa.ai Warning] maxRetries is ${a.maxRetries}. Consider increasing to 5+ for complex projects.`),s=a.modelProvider,t=a.maxRetries,n=a.apiKey,a.agentEnabled===!1&&(console.log("[Lisa.ai Agent] Agent is disabled by Control Plane for this project."),process.exit(1))}}return o&&(P.applyEnvDefaults(o),!e.projectId&&!o.projectId&&o.maxRetries!==void 0&&(t=o.maxRetries),!e.projectId&&!o.projectId&&o.provider&&e.model==="gemini"&&(s=o.provider),P.printSummary(o)),{model:s,maxRetries:t,apiKey:n,projectId:i}}var z=new kt.Command;z.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(St.version);z.command("heal").description("Run tests and autonomously heal all failures via LLM + Memory Engine").option("-c, --command <type>","Test command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-t, --type <scope>","Test type to heal: unit (default), e2e, integration","unit").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").option("--ci","CI mode: commit healed files, open PR, write GitHub Actions step summary").action(async e=>{ne();let t=["unit","e2e","integration"],s=e.type;t.includes(s)||(console.error(`
307
+ [Lisa.ai Error] Invalid heal type '${e.type}'. Valid types: ${t.join(", ")}`),process.exit(1));let n=e.files?e.files.split(",").map(r=>r.trim()):void 0,o=e.ci===!0,i=await Ee(e);await ce(e.command,i.model,1,i.maxRetries,i.projectId,void 0,i.apiKey,s,n,o)});z.command("unit").description("Generate missing unit test specs to reach 100% coverage (auto-detects framework)").option("-c, --command <type>","Test+coverage command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await Ee(e);await pt(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});z.command("e2e").description("Generate E2E tests via Playwright (auto-installs if none detected)").option("-c, --command <type>","E2E command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await Ee(e);await ft(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});z.command("integration").description("Generate integration tests for module seams (component+service, API+DB)").option("-c, --command <type>","Test command to execute (auto-detected if omitted)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").option("-f, --files <paths>","Target specific files (comma-separated, bypasses discovery)").action(async e=>{ne();let t=e.files?e.files.split(",").map(n=>n.trim()):void 0,s=await Ee(e);await ht(e.command,s.model,1,s.maxRetries,s.projectId,s.apiKey,t)});z.command("diagnose").description("Test LLM connectivity and API key health without running the full agent").option("-m, --model <provider>","LLM provider to test (gemini, claude, openai)","claude").option("-p, --project-id <id>","Control Plane Project ID to fetch API key from").action(async e=>{ne();let t=e.model,s,n=P.load(process.cwd()),o=e.projectId||n?.projectId||"local";if(o!=="local"){let a=await ye(o);a.ok?(t=a.config.modelProvider,s=a.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${t}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${a.reason}. Using local env for API key.`)}let r={claude:process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5",openai:process.env.LISA_OPENAI_MODEL||"gpt-4o-mini",gemini:process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash"}[t]||t;console.log(`
308
308
  [Lisa.ai Diagnose] Testing ${t} \u2192 model ID: ${r}`);try{let a=await ie("Reply with exactly: LISA_OK",t,s);console.log(`
309
309
  [Lisa.ai Diagnose] ${t} is working correctly.`),console.log(` Model response: "${a}"`)}catch(a){console.error(`
310
310
  [Lisa.ai Diagnose] ${t} call FAILED.`),console.error(` Error: ${a.message}`),a.cause&&console.error(` Cause: ${a.cause?.message??a.cause}`),console.error(`
311
- 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)}});W.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 e=>{let t=he.resolve(process.cwd(),te);X.existsSync(t)&&!e.force&&(console.error(`
312
- [Lisa.ai Init] ${te} already exists. Use --force to overwrite.`),process.exit(1));let s=Ct.createInterface({input:process.stdin,output:process.stdout}),n=(f,w="")=>new Promise(l=>s.question(w?`${f} [${w}]: `:`${f}: `,p=>l(p.trim()||w)));console.log(`
311
+ 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)}});z.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 e=>{let t=he.resolve(process.cwd(),te);X.existsSync(t)&&!e.force&&(console.error(`
312
+ [Lisa.ai Init] ${te} already exists. Use --force to overwrite.`),process.exit(1));let s=Ct.createInterface({input:process.stdin,output:process.stdout}),n=(f,w="")=>new Promise(l=>s.question(w?`${f} [${w}]: `:`${f}: `,u=>l(u.trim()||w)));console.log(`
313
313
  Lisa.ai Project Setup \u2014 press Enter to accept the default shown in [ ]
314
- `);let o=await n("Control Plane project ID (leave empty for local-only mode)",""),i=await n("LLM provider (gemini / claude / openai)","gemini"),r=await n("Testing framework (jest / vitest / mocha / karma / jasmine \u2014 leave empty to auto-detect)",""),a=await n("E2E framework (playwright / cypress \u2014 leave empty for Playwright default)",""),u=await n("Test types to generate (unit / integration / e2e \u2014 comma-separated)","unit"),g=await n("Test command (leave empty for auto-discovery)",""),d=await n("E2E command (leave empty for auto-discovery)",""),x=await n("Max heal retries","5");s.close();let h={...o?{projectId:o}:{},provider:i,testTypes:u.split(",").map(f=>f.trim()).filter(Boolean),maxRetries:parseInt(x,10)||5,skipFiles:[],skipDirs:[],skipPaths:[]};r&&(h.testingFramework=r),a&&(h.e2eFramework=a),g&&(h.testCommand=g),d&&(h.e2eCommand=d),X.writeFileSync(t,JSON.stringify(h,null,2)+`
314
+ `);let o=await n("Control Plane project ID (leave empty for local-only mode)",""),i=await n("LLM provider (gemini / claude / openai)","gemini"),r=await n("Testing framework (jest / vitest / mocha / karma / jasmine \u2014 leave empty to auto-detect)",""),a=await n("E2E framework (playwright / cypress \u2014 leave empty for Playwright default)",""),p=await n("Test types to generate (unit / integration / e2e \u2014 comma-separated)","unit"),g=await n("Test command (leave empty for auto-discovery)",""),d=await n("E2E command (leave empty for auto-discovery)",""),x=await n("Max heal retries","5");s.close();let h={...o?{projectId:o}:{},provider:i,testTypes:p.split(",").map(f=>f.trim()).filter(Boolean),maxRetries:parseInt(x,10)||5,skipFiles:[],skipDirs:[],skipPaths:[]};r&&(h.testingFramework=r),a&&(h.e2eFramework=a),g&&(h.testCommand=g),d&&(h.e2eCommand=d),X.writeFileSync(t,JSON.stringify(h,null,2)+`
315
315
  `,"utf-8"),console.log(`
316
316
  Created ${te}:
317
317
  `),console.log(JSON.stringify(h,null,2)),console.log(`
@@ -357,9 +357,9 @@ jobs:
357
357
  ${t}: \${{ secrets.${t} }}
358
358
  GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
359
359
  run: lisa-agent heal --model ${e} --ci
360
- `}W.command("init-ci").description("Generate a GitHub Actions workflow file for Lisa.ai CI/CD healing").option("--force","Overwrite existing workflow file").option("-m, --model <provider>","LLM provider for the workflow (gemini, claude, openai)","gemini").action(async e=>{ne();let t=he.resolve(process.cwd(),".github","workflows"),s=he.join(t,"lisa-heal.yml");X.existsSync(s)&&!e.force&&(console.error(`
360
+ `}z.command("init-ci").description("Generate a GitHub Actions workflow file for Lisa.ai CI/CD healing").option("--force","Overwrite existing workflow file").option("-m, --model <provider>","LLM provider for the workflow (gemini, claude, openai)","gemini").action(async e=>{ne();let t=he.resolve(process.cwd(),".github","workflows"),s=he.join(t,"lisa-heal.yml");X.existsSync(s)&&!e.force&&(console.error(`
361
361
  [Lisa.ai Init-CI] .github/workflows/lisa-heal.yml already exists. Use --force to overwrite.`),process.exit(1));let n={gemini:"GOOGLE_GENERATIVE_AI_API_KEY",claude:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY"},o=e.model||"gemini",i=n[o]||"GOOGLE_GENERATIVE_AI_API_KEY",r=Vt(o,i);X.mkdirSync(t,{recursive:!0}),X.writeFileSync(s,r,"utf-8"),console.log(`
362
362
  Created: .github/workflows/lisa-heal.yml`),console.log(`
363
363
  Required repository secret: ${i}`),console.log(" Set it in: GitHub repo > Settings > Secrets and variables > Actions"),console.log(`
364
364
  The workflow will:`),console.log(" 1. Run on every push to main/master/develop"),console.log(" 2. Install dependencies + run lisa-agent heal --ci"),console.log(" 3. If tests fail and Lisa heals them, open a PR automatically"),console.log(` 4. If all tests pass or nothing can be healed, report status
365
- `)});W.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 e=>{ne();let t=e.model,s,n=P.load(process.cwd()),o=e.projectId||n?.projectId||"local";if(o!=="local"){let i=await ye(o);i.ok?(t=i.config.modelProvider,s=i.config.apiKey,console.log(`[Lisa.ai Audit] Config fetched from Control Plane. Provider=${t}`)):console.warn(`[Lisa.ai Audit] Control Plane ${i.reason}. Using local env for API key.`)}await $t(t,o,s)});W.parse(process.argv);
365
+ `)});z.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 e=>{ne();let t=e.model,s,n=P.load(process.cwd()),o=e.projectId||n?.projectId||"local";if(o!=="local"){let i=await ye(o);i.ok?(t=i.config.modelProvider,s=i.config.apiKey,console.log(`[Lisa.ai Audit] Config fetched from Control Plane. Provider=${t}`)):console.warn(`[Lisa.ai Audit] Control Plane ${i.reason}. Using local env for API key.`)}await $t(t,o,s)});z.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lisa.ai/agent",
3
- "version": "2.9.5",
3
+ "version": "2.9.6",
4
4
  "description": "Lisa.ai Autonomous CI/CD Worker Agent",
5
5
  "main": "dist/index.js",
6
6
  "bin": {