@lisa.ai/agent 2.6.5 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +192 -12
  2. package/dist/index.js +183 -115
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,33 +1,213 @@
1
1
  # @lisa.ai/agent
2
2
 
3
- The **Lisa.ai Worker Agent** is an autonomous CI/CD sidecar that hooks into your standard build and test scripts. Powered by a configurable OODA loop (Observe, Orient, Decide, Act), it detects compile failures and logic coverage gaps and acts on them.
3
+ The **Lisa.ai Agent** is an autonomous CI/CD CLI that heals failing tests, generates missing test coverage, and remediates npm vulnerabilities all powered by LLMs. Drop it into any JavaScript/TypeScript project and let it fix your build.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install -g @lisa.ai/agent
9
- # or
9
+ # or as a dev dependency
10
10
  npm install --save-dev @lisa.ai/agent
11
11
  ```
12
12
 
13
- ## Quick Start
13
+ You need at least one LLM API key set as an environment variable:
14
14
 
15
- ### Auto-Heal a Failing Build
16
- Wrap your existing broken build script with `lisa-agent heal` and pass your Project ID. The agent will execute your script, pipe the runtime errors securely to an LLM provider (like Claude or Gemini), apply the patch, and recursively verify!
15
+ | Provider | Env var | Default model |
16
+ |---|---|---|
17
+ | Google Gemini | `GOOGLE_GENERATIVE_AI_API_KEY` | `gemini-2.0-flash` |
18
+ | Anthropic Claude | `ANTHROPIC_API_KEY` | `claude-haiku-4-5` |
19
+ | OpenAI | `OPENAI_API_KEY` | `gpt-4o-mini` |
20
+
21
+ Override the default model per provider with `LISA_GOOGLE_MODEL`, `LISA_CLAUDE_MODEL`, or `LISA_OPENAI_MODEL`.
22
+
23
+ ## Commands
24
+
25
+ ### `heal` — Auto-Heal Failing Tests
26
+
27
+ Runs your test command, identifies every failing spec, and autonomously fixes them using LLM-generated patches. Each fix is verified in isolation before moving on.
28
+
29
+ ```bash
30
+ lisa-agent heal --command "npm test" --model gemini
31
+ ```
32
+
33
+ **How it works:**
34
+ 1. Runs a single global test pass to discover all failures
35
+ 2. Extracts every failing spec file (Karma suite-name matching, Jest `FAIL` header parsing)
36
+ 3. For each file: queries the Memory Engine for proven fix patterns, sends context + error log to the LLM, writes the fix, verifies in isolation
37
+ 4. Runs a single final global test pass to confirm all fixes together
38
+ 5. Files that regress are quarantined after 3 strikes
39
+
40
+ **Supported frameworks:** Jest, Vitest, Mocha, Karma/Jasmine (Angular), Cypress, Playwright
41
+
42
+ **Options:**
43
+
44
+ | Flag | Description | Default |
45
+ |---|---|---|
46
+ | `-c, --command <cmd>` | Test command to run | Auto-discovered |
47
+ | `-m, --model <provider>` | `gemini`, `claude`, or `openai` | `gemini` |
48
+ | `-p, --project-id <id>` | Control Plane project for remote config + telemetry | `local` |
49
+
50
+ ### `coverage` — Generate Missing Test Specs
51
+
52
+ Runs your test suite with coverage enabled, identifies files below 100% coverage, and generates new test specs or updates existing ones to close the gaps.
53
+
54
+ ```bash
55
+ lisa-agent coverage --command "npm run test:coverage" --model claude
56
+ ```
57
+
58
+ **How it works:**
59
+ 1. Runs your coverage command and parses the Istanbul/Jest JSON summary
60
+ 2. Identifies uncovered lines per source file
61
+ 3. Generates or updates spec files targeting the uncovered code
62
+ 4. Re-runs coverage to verify improvement
63
+ 5. Repeats until 100% or max retries exhausted
64
+
65
+ **Options:** Same as `heal`.
66
+
67
+ ### `audit` — Vulnerability Scanning & Remediation
68
+
69
+ Scans your project for npm vulnerabilities, applies safe fixes automatically, and consults an LLM for breaking changes that need manual intervention.
17
70
 
18
71
  ```bash
19
- npx lisa-agent heal --command="npm run build" --model="claude" --project-id="demo-123"
72
+ lisa-agent audit --model gemini
20
73
  ```
21
74
 
22
- ### Continuous 100% Test Generation
23
- Wrap your testing script with `lisa-agent coverage` (assuming it generates Istanbul/Jest JSON summaries). The agent will query the AST of files lacking coverage and autonomously generate functioning unit tests.
75
+ **How it works:**
76
+ 1. **Scan** runs `npm audit --json` (auto-detects npm/yarn/pnpm via lockfile)
77
+ 2. **Safe auto-fix** — runs `npm audit fix` (semver-compatible patches only)
78
+ 3. **Re-scan** — checks if vulnerabilities remain
79
+ 4. **Targeted upgrades** — applies non-breaking semver-minor fixes
80
+ 5. **LLM guidance** — for remaining breaking/unfixable vulnerabilities, consults the LLM and saves a remediation report to `lisa-audit-report.md`
81
+
82
+ **Options:**
83
+
84
+ | Flag | Description | Default |
85
+ |---|---|---|
86
+ | `-m, --model <provider>` | `gemini`, `claude`, or `openai` | `gemini` |
87
+ | `-p, --project-id <id>` | Control Plane project ID | `local` |
88
+
89
+ ### `diagnose` — Test LLM Connectivity
90
+
91
+ Sends a simple probe to your configured LLM provider to verify your API key works and the model is reachable. Useful for debugging setup issues.
24
92
 
25
93
  ```bash
26
- npx lisa-agent coverage --command="npm run test" --model="gemini" --project-id="demo-123"
94
+ lisa-agent diagnose --model claude
95
+ ```
96
+
97
+ ### `init` — Create Project Config
98
+
99
+ Interactively generates a `.lisai.json` config file in your project root.
100
+
101
+ ```bash
102
+ lisa-agent init # interactive wizard
103
+ lisa-agent init --force # overwrite existing config
104
+ ```
105
+
106
+ ## Configuration
107
+
108
+ ### `.lisai.json`
109
+
110
+ Place a `.lisai.json` in your project root to configure the agent without CLI flags:
111
+
112
+ ```json
113
+ {
114
+ "provider": "gemini",
115
+ "model": "gemini-2.0-flash",
116
+ "testCommand": "npm run test:coverage",
117
+ "testingFramework": "jest",
118
+ "testTypes": ["unit", "integration", "e2e"],
119
+ "maxRetries": 5,
120
+ "skipFiles": ["server.js", "app.js"],
121
+ "skipDirs": ["scripts", "migrations"],
122
+ "skipPaths": ["src/generated", "src/fixtures"]
123
+ }
27
124
  ```
28
125
 
29
- ## Dashboard Telemetry
30
- This agent natively links to the Lisa.ai Control Plane and Telemetry UI via your `--project-id`.
126
+ | Field | Type | Description |
127
+ |---|---|---|
128
+ | `provider` | `gemini \| claude \| openai` | LLM provider |
129
+ | `model` | `string` | Pin a specific model ID (e.g. `claude-sonnet-4-6`) |
130
+ | `testCommand` | `string` | Explicit test command (skips auto-discovery) |
131
+ | `testingFramework` | `string` | Override framework detection. One of: `jest`, `vitest`, `mocha`, `karma`, `jasmine`, `cypress`, `playwright` |
132
+ | `testTypes` | `string[]` | Types of tests to generate: `unit`, `integration`, `e2e` |
133
+ | `maxRetries` | `number` | Max heal retries per session (default 5) |
134
+ | `skipFiles` | `string[]` | Filenames to exclude from coverage analysis |
135
+ | `skipDirs` | `string[]` | Directory names to exclude |
136
+ | `skipPaths` | `string[]` | Path prefixes to exclude |
137
+
138
+ ### Config Priority
139
+
140
+ Settings are resolved in this order (highest wins):
141
+
142
+ ```
143
+ Shell env var > Control Plane > CLI flag > .lisai.json > built-in default
144
+ ```
145
+
146
+ ## Control Plane Integration
147
+
148
+ Connect the agent to the Lisa.ai Dashboard for remote configuration, telemetry, and the Memory Engine:
149
+
150
+ ```bash
151
+ lisa-agent heal --command "npm test" --project-id "my-project-123"
152
+ ```
153
+
154
+ With a project ID, the agent will:
155
+ - **Fetch remote config** (model provider, max retries, auto-heal toggle) from the Dashboard
156
+ - **Report telemetry** (heal/coverage events, pass/fail counts) for the Dashboard charts
157
+ - **Use the Memory Engine** — successful fix patterns are stored and reused across runs, so the agent gets smarter over time
158
+
159
+ Without a project ID, the agent runs fully offline using local config and env vars.
160
+
161
+ ## Memory Engine
162
+
163
+ The Memory Engine stores proven fix patterns from previous heal runs. When the agent encounters an error it has fixed before, it injects the known-good solution into the LLM prompt — dramatically improving fix accuracy and speed.
164
+
165
+ - Patterns are keyed by normalized error shape + framework + project
166
+ - Only patterns with confidence >= 50% are injected
167
+ - Confidence = `successCount / totalAttempts`, updated after each heal attempt
168
+ - Memory is project-scoped and stored on the Control Plane (requires `--project-id`)
169
+
170
+ ## Auto-Discovery
171
+
172
+ If no `--command` is provided, the agent scans your project to detect:
173
+ - **Test framework** — from `package.json` dependencies (jest, vitest, karma, mocha, cypress, playwright)
174
+ - **Test command** — from `package.json` scripts (`test`, `test:coverage`, etc.)
175
+ - **Framework config** — generates missing config files (e.g. `jest.config.js`) if needed
176
+ - **Missing dependencies** — auto-installs test frameworks that are referenced but not installed
177
+
178
+ ## Examples
179
+
180
+ ### Heal a broken Angular project
181
+ ```bash
182
+ export GOOGLE_GENERATIVE_AI_API_KEY="your-key"
183
+ lisa-agent heal --command "ng test --watch=false" --model gemini
184
+ ```
185
+
186
+ ### Generate Jest coverage for a Node.js API
187
+ ```bash
188
+ export ANTHROPIC_API_KEY="your-key"
189
+ lisa-agent coverage --command "npx jest --coverage --coverageReporters=json-summary" --model claude
190
+ ```
191
+
192
+ ### Fix npm vulnerabilities with LLM guidance
193
+ ```bash
194
+ export GOOGLE_GENERATIVE_AI_API_KEY="your-key"
195
+ lisa-agent audit --model gemini
196
+ ```
197
+
198
+ ### Full CI/CD pipeline with Control Plane
199
+ ```bash
200
+ lisa-agent heal --command "npm test" --model gemini --project-id "prod-api"
201
+ lisa-agent coverage --command "npm run test:coverage" --model gemini --project-id "prod-api"
202
+ lisa-agent audit --model gemini --project-id "prod-api"
203
+ ```
204
+
205
+ ## Requirements
206
+
207
+ - Node.js 18+
208
+ - At least one LLM API key (Gemini, Claude, or OpenAI)
209
+ - A JavaScript/TypeScript project with a test suite
31
210
 
32
211
  ---
33
- *Created by the Lisa.ai Platform team.*
212
+
213
+ *Built by the Lisa.ai Platform team.*
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var ct=Object.create;var Ce=Object.defineProperty;var ut=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames;var pt=Object.getPrototypeOf,gt=Object.prototype.hasOwnProperty;var ft=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var mt=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of dt(e))!gt.call(t,o)&&o!==n&&Ce(t,o,{get:()=>e[o],enumerable:!(s=ut(e,o))||s.enumerable});return t};var C=(t,e,n)=>(n=t!=null?ct(pt(t)):{},mt(e||!t||!t.__esModule?Ce(n,"default",{value:t,enumerable:!0}):n,t));var st=ft((ps,Ct)=>{Ct.exports={name:"@lisa.ai/agent",version:"2.6.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 nt=require("commander"),ue=C(require("fs")),ot=C(require("path")),it=C(require("readline"));var ke=C(require("dotenv"));ke.config({quiet:!0});async function Q(t){let e=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let n=`${e}/api/config/${t}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${n}...`);let s=await fetch(n);if(!s.ok){let i=s.status===404?"not_found":"unreachable";return console.warn(i==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${t}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${s.status}. Falling back to local defaults.`),{ok:!1,reason:i}}return{ok:!0,config:await s.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${e}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var Ye=require("child_process"),P=C(require("fs")),N=C(require("path"));var k=C(require("path")),S=C(require("fs"));function pe(t,e=process.cwd(),n=[]){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=n.map(u=>k.resolve(e,u)),i=new Map,r=new Set,l=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,g;for(;(g=l.exec(s))!==null;){let a=g[1].trim().split(" ");for(let m=1;m<Math.min(a.length,6);m++){let w=a.slice(0,m).join(" ");if(r.has(w))continue;r.add(w);let c=ge(w,e,o);if(c){let v=k.resolve(c);i.has(v)||i.set(v,k.relative(e,c));break}}}let d=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,p;for(;(p=d.exec(s))!==null;){let u=p[1],a=k.isAbsolute(u)?u:k.resolve(e,u);!o.includes(a)&&S.existsSync(a)&&!i.has(a)&&i.set(a,k.relative(e,a))}return[...i.values()]}function se(t,e=[],n=process.cwd()){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),o=e.map(c=>k.resolve(c));{let c=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,v=new Set,f;for(;(f=c.exec(s))!==null;){let h=f[1].trim().split(" ");for(let A=1;A<Math.min(h.length,5);A++){let x=h.slice(0,A).join(" ");if(v.has(x))continue;v.add(x);let L=ge(x,n,o);if(L)return k.relative(n,L)}}}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(s))!==null;){let c=r[1];if(c){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(c))continue;let v=k.isAbsolute(c)?c:k.resolve(n,c);if(!o.includes(v)&&S.existsSync(v))return c}}let l=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,g;for(;(g=l.exec(s))!==null;){let c=g[1],v=k.isAbsolute(c)?c:k.resolve(n,c);if(!o.includes(v)&&S.existsSync(v))return c}let d=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,p;for(;(p=d.exec(s))!==null;){let c=p[1];if(c){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(c))continue;let v=k.isAbsolute(c)?c:k.resolve(n,c);if(!o.includes(v)&&S.existsSync(v))return c}}let u=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,a,m=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(;(a=u.exec(s))!==null;){let c=a[1];if(!c||w.includes(c)||m.has(c)||/^[A-Z][A-Z0-9]{5,11}$/.test(c)||/^[A-Za-z0-9]{16,}$/.test(c))continue;m.add(c);let v=Ae(c,n,o);if(v)return k.relative(n,v)}return null}function ge(t,e,n){if(!S.existsSync(e))return null;let s=S.readdirSync(e);for(let o of s){let i=k.join(e,o);if(["node_modules","dist","build",".git",".angular"].includes(o))continue;let r;try{r=S.statSync(i)}catch{continue}if(r.isDirectory()){let l=ge(t,i,n);if(l)return l}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(o)){if(n.includes(k.resolve(i)))continue;try{let l=S.readFileSync(i,"utf8");if(l.includes(`describe('${t}'`)||l.includes(`describe("${t}"`))return i}catch{continue}}}return null}function Ae(t,e,n){if(!S.existsSync(e))return null;let s=S.readdirSync(e);for(let o of s){let i=k.join(e,o);if(o==="node_modules"||o==="dist"||o==="build"||o===".git"||o===".angular")continue;let r;try{r=S.statSync(i)}catch{continue}if(r.isDirectory()){let l=Ae(t,i,n);if(l)return l}else if(o.match(/\.(ts|tsx|js|jsx|vue)$/)){let l=S.readFileSync(i,"utf8");if(l.includes(`class ${t}`)||l.includes(`function ${t}`)||l.includes(`const ${t}`)||l.includes(`let ${t}`)||l.includes(`exports.${t}`)||l.includes(`module.exports.${t}`)){let g=i,d=k.extname(i),p=i.slice(0,-d.length);if(!o.includes(".spec.")&&!o.includes(".test.")){let u=[`${p}.spec${d}`,`${p}.test${d}`,`${p}.spec.js`,`${p}.test.js`];for(let a of u)if(S.existsSync(a)){g=a;break}}if(!n.includes(k.resolve(g)))return g}}}return null}var X=require("ai"),be=require("@ai-sdk/openai"),Se=require("@ai-sdk/anthropic"),je=require("@ai-sdk/google"),Fe=C(require("dotenv"));Fe.config({quiet:!0});var fe=15e3;function Ie(t,e){return t.length<=fe?t:(console.warn(`[Lisa.ai LLM] ${e} is ${t.length} chars \u2014 truncating to ${fe} to stay within context window.`),t.slice(0,fe)+`
2
+ "use strict";var wt=Object.create;var Pe=Object.defineProperty;var xt=Object.getOwnPropertyDescriptor;var Lt=Object.getOwnPropertyNames;var $t=Object.getPrototypeOf,kt=Object.prototype.hasOwnProperty;var jt=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var St=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Lt(e))!kt.call(t,i)&&i!==n&&Pe(t,i,{get:()=>e[i],enumerable:!(s=xt(e,i))||s.enumerable});return t};var k=(t,e,n)=>(n=t!=null?wt($t(t)):{},St(e||!t||!t.__esModule?Pe(n,"default",{value:t,enumerable:!0}):n,t));var pt=jt((_s,_t)=>{_t.exports={name:"@lisa.ai/agent",version:"2.7.0",description:"Lisa.ai Autonomous CI/CD Worker Agent",main:"dist/index.js",bin:{"lisa-agent":"dist/index.js"},files:["dist/"],scripts:{build:"tsup",typecheck:"tsc --noEmit",start:"node dist/index.js",dev:"ts-node src/index.ts",prepublishOnly:"npm run typecheck && npm run build"},keywords:["lisa","ci","cd","agent"],author:"Lisa.ai",license:"ISC",dependencies:{"@ai-sdk/anthropic":"^3.0.46","@ai-sdk/google":"^3.0.30","@ai-sdk/openai":"^3.0.30","@octokit/rest":"^22.0.1",ai:"^6.0.94",commander:"^11.1.0",dotenv:"^17.3.1","simple-git":"^3.31.1"},devDependencies:{"@types/jest":"^30.0.0","@types/node":"^20.0.0","ts-node":"^10.9.1",tsup:"^8.5.1",typescript:"^5.0.0"}}});var gt=require("commander"),ve=k(require("fs")),ft=k(require("path")),mt=k(require("readline"));var Te=k(require("dotenv"));Te.config({quiet:!0});async function ce(t){let e=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let n=`${e}/api/config/${t}`;console.log(`[Lisa.ai Agent] Fetching dynamic configuration from ${n}...`);let s=await fetch(n);if(!s.ok){let o=s.status===404?"not_found":"unreachable";return console.warn(o==="not_found"?`[Lisa.ai Agent Warning] Control Plane returned 404. Project '${t}' not found.`:`[Lisa.ai Agent Warning] Control Plane returned ${s.status}. Falling back to local defaults.`),{ok:!1,reason:o}}return{ok:!0,config:await s.json()}}catch{return console.warn(`[Lisa.ai Agent Warning] Failed to reach Control Plane (${e}). Using local fallback configuration.`),{ok:!1,reason:"unreachable"}}}var Qe=require("child_process"),N=k(require("fs")),q=k(require("path"));var A=k(require("path")),T=k(require("fs"));function xe(t,e=process.cwd(),n=[]){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),i=n.map(d=>A.resolve(e,d)),o=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(s))!==null;){let l=u[1].trim().split(" ");for(let g=1;g<Math.min(l.length,6);g++){let m=l.slice(0,g).join(" ");if(r.has(m))continue;r.add(m);let c=Le(m,e,i);if(c){let y=A.resolve(c);o.has(y)||o.set(y,A.relative(e,c));break}}}let p=/^FAIL\s+([a-zA-Z0-9_./-\\]+\.(?:spec|test)\.(ts|tsx|js|jsx))/gm,f;for(;(f=p.exec(s))!==null;){let d=f[1],l=A.isAbsolute(d)?d:A.resolve(e,d);!i.includes(l)&&T.existsSync(l)&&!o.has(l)&&o.set(l,A.relative(e,l))}return[...o.values()]}function ue(t,e=[],n=process.cwd()){let s=t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,""),i=e.map(c=>A.resolve(c));{let c=/(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:\s+[\d.]+)*\s+\([^)]+\)\s+(.+?)\s+FAILED/g,y=new Set,h;for(;(h=c.exec(s))!==null;){let w=h[1].trim().split(" ");for(let $=1;$<Math.min(w.length,5);$++){let x=w.slice(0,$).join(" ");if(y.has(x))continue;y.add(x);let L=Le(x,n,i);if(L)return A.relative(n,L)}}}let o=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))(?:\s*[:(])/g,r;for(;(r=o.exec(s))!==null;){let c=r[1];if(c){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(c))continue;let y=A.isAbsolute(c)?c:A.resolve(n,c);if(!i.includes(y)&&T.existsSync(y))return c}}let a=/FAIL\s+([a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/gi,u;for(;(u=a.exec(s))!==null;){let c=u[1],y=A.isAbsolute(c)?c:A.resolve(n,c);if(!i.includes(y)&&T.existsSync(y))return c}let p=/([a-zA-Z]:[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue)|[a-zA-Z0-9_.\-\/\\]+\.(?:ts|tsx|js|jsx|vue))/g,f;for(;(f=p.exec(s))!==null;){let c=f[1];if(c){if(/(?:^|[/\\])(node_modules|dist|build)[/\\]/.test(c))continue;let y=A.isAbsolute(c)?c:A.resolve(n,c);if(!i.includes(y)&&T.existsSync(y))return c}}let d=/\b([A-Z][a-zA-Z0-9]{3,})\b/g,l,g=new Set,m=["Error","TypeError","SyntaxError","ReferenceError","RangeError","Object","Boolean","String","Number","Array","NullInjectorError","NullInjector","R3Injector","ChainedInjector","Module","Component","Standalone","Application","App2","TestBed","UserContext","Chrome","ChromeHeadless","Karma","Launching","Starting","Headless","Connected","Executed","INFO","SUCCESS","FAILED","Building","Initial","Names","Lazy","Source","Find","NotFound","NG0201","Windows","Linux","Macintosh","Users","AppData","Local","Temp","Process","Unexpected","Expected","Validation","Directory","Configuration","Documentation"];for(;(l=d.exec(s))!==null;){let c=l[1];if(!c||m.includes(c)||g.has(c)||/^[A-Z][A-Z0-9]{5,11}$/.test(c)||/^[A-Za-z0-9]{16,}$/.test(c))continue;g.add(c);let y=Ie(c,n,i);if(y)return A.relative(n,y)}return null}function Le(t,e,n){if(!T.existsSync(e))return null;let s=T.readdirSync(e);for(let i of s){let o=A.join(e,i);if(["node_modules","dist","build",".git",".angular"].includes(i))continue;let r;try{r=T.statSync(o)}catch{continue}if(r.isDirectory()){let a=Le(t,o,n);if(a)return a}else if(/\.(spec|test)\.(ts|tsx|js|jsx)$/.test(i)){if(n.includes(A.resolve(o)))continue;try{let a=T.readFileSync(o,"utf8");if(a.includes(`describe('${t}'`)||a.includes(`describe("${t}"`))return o}catch{continue}}}return null}function Ie(t,e,n){if(!T.existsSync(e))return null;let s=T.readdirSync(e);for(let i of s){let o=A.join(e,i);if(i==="node_modules"||i==="dist"||i==="build"||i===".git"||i===".angular")continue;let r;try{r=T.statSync(o)}catch{continue}if(r.isDirectory()){let a=Ie(t,o,n);if(a)return a}else if(i.match(/\.(ts|tsx|js|jsx|vue)$/)){let a=T.readFileSync(o,"utf8");if(a.includes(`class ${t}`)||a.includes(`function ${t}`)||a.includes(`const ${t}`)||a.includes(`let ${t}`)||a.includes(`exports.${t}`)||a.includes(`module.exports.${t}`)){let u=o,p=A.extname(o),f=o.slice(0,-p.length);if(!i.includes(".spec.")&&!i.includes(".test.")){let d=[`${f}.spec${p}`,`${f}.test${p}`,`${f}.spec.js`,`${f}.test.js`];for(let l of d)if(T.existsSync(l)){u=l;break}}if(!n.includes(A.resolve(u)))return u}}}return null}var oe=require("ai"),Re=require("@ai-sdk/openai"),Me=require("@ai-sdk/anthropic"),De=require("@ai-sdk/google"),Ne=k(require("dotenv"));Ne.config({quiet:!0});var $e=15e3;function Oe(t,e){return t.length<=$e?t:(console.warn(`[Lisa.ai LLM] ${e} is ${t.length} chars \u2014 truncating to ${$e} to stay within context window.`),t.slice(0,$e)+`
3
3
 
4
- // ... (truncated)`)}function Ee(t,e){if(!/\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/.test(t))throw new Error(`LLM returned a non-code response for ${e} (possible context overflow). Skipping to prevent file corruption.`)}function Pe(t){if(!t||t.length===0)return"";let e={unit:"unit tests \u2014 test every function/method in complete isolation, mocking ALL external dependencies, services, and I/O",integration:"integration tests \u2014 test how modules work together using real service/repository layers; for HTTP routes use supertest or equivalent",e2e:"end-to-end tests \u2014 simulate complete user flows using the configured e2e framework (Playwright/Cypress); cover the full path from HTTP request to response or UI action to assertion"};return`5. Test scope \u2014 generate ALL of the following test types for this file:
4
+ // ... (truncated)`)}function Ue(t,e){if(!/\b(describe|it\(|test\(|expect\(|beforeEach|afterEach|suite|assert\.|cy\.)\b/.test(t))throw new Error(`LLM returned a non-code response for ${e} (possible context overflow). Skipping to prevent file corruption.`)}function _e(t){if(!t||t.length===0)return"";let e={unit:"unit tests \u2014 test every function/method in complete isolation, mocking ALL external dependencies, services, and I/O",integration:"integration tests \u2014 test how modules work together using real service/repository layers; for HTTP routes use supertest or equivalent",e2e:"end-to-end tests \u2014 simulate complete user flows using the configured e2e framework (Playwright/Cypress); cover the full path from HTTP request to response or UI action to assertion"};return`5. Test scope \u2014 generate ALL of the following test types for this file:
5
5
  ${t.map(s=>` \u2022 ${e[s]??s}`).join(`
6
6
  `)}
7
- `}function ne(t,e){if(t==="claude"){let o=e||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,Se.createAnthropic)({apiKey:o})(i)}if(t==="openai"){let o=e||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,be.createOpenAI)({apiKey:o})(i)}let n=e||process.env.GOOGLE_GENERATIVE_AI_API_KEY;if(!n)throw new Error("No Google API key provided by local ENV or Control Plane");let s=process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash";return(0,je.createGoogleGenerativeAI)({apiKey:n})(s)}async function Te(t,e,n,s,o,i,r,l){console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${s} for ${t}...`);let g=ne(s,o),d=`You are Lisa.ai, an autonomous CI/CD expert platform.
7
+ `}function de(t,e){if(t==="claude"){let i=e||process.env.ANTHROPIC_API_KEY;if(!i)throw new Error("No Anthropic API key provided by local ENV or Control Plane");let o=process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5";return(0,Me.createAnthropic)({apiKey:i})(o)}if(t==="openai"){let i=e||process.env.OPENAI_API_KEY;if(!i)throw new Error("No OpenAI API key provided by local ENV or Control Plane");let o=process.env.LISA_OPENAI_MODEL||"gpt-4o-mini";return(0,Re.createOpenAI)({apiKey:i})(o)}let n=e||process.env.GOOGLE_GENERATIVE_AI_API_KEY;if(!n)throw new Error("No Google API key provided by local ENV or Control Plane");let s=process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash";return(0,De.createGoogleGenerativeAI)({apiKey:n})(s)}async function Ge(t,e,n,s,i,o,r,a){console.log(`[Lisa.ai Auto-Heal] Requesting fix from ${s} for ${t}...`);let u=de(s,i),p=`You are Lisa.ai, an autonomous CI/CD expert platform.
8
8
  A build/compilation error occurred. Your task is to fix the provided file so that the error resolves.
9
9
 
10
10
  --- Error Log ---
@@ -21,58 +21,58 @@ A build/compilation error occurred. Your task is to fix the provided file so tha
21
21
  5. FRAMEWORK TEST RULE: If fixing a testing file ('.spec' or '.test') and an Angular error happens like 'NullInjectorError: No provider for X', you MUST add X to the 'providers' array in 'TestBed.configureTestingModule' or import the required testing module. If a React testing library error arises, fix the render context.
22
22
  6. CRITICAL ANGULAR RULE: If an Angular component imports 'RouterLink' or uses '[routerLink]' in its template, you MUST provide 'ActivatedRoute' in the providers array or import 'RouterTestingModule'. If it uses HTTP, import 'HttpClientTestingModule'.
23
23
  7. CRITICAL STANDALONE RULE: If a component has 'standalone: true' in its decorator (check the Sibling Context!), you MUST NOT add it to the 'declarations' array. Instead, you MUST add it to the 'imports' array within 'TestBed.configureTestingModule'.
24
- 8. Return the code wrapped in a markdown code block (\`\`\`typescript ... \`\`\`). Do not include any explanation or intro text.`;if(r){if(/standalone\s*:\s*true/.test(r)){let m=r.match(/export class (\w+)/),w=m?m[1]:"the component";d+=`
24
+ 8. Return the code wrapped in a markdown code block (\`\`\`typescript ... \`\`\`). Do not include any explanation or intro text.`;if(r){if(/standalone\s*:\s*true/.test(r)){let g=r.match(/export class (\w+)/),m=g?g[1]:"the component";p+=`
25
25
 
26
26
  --- CRITICAL ARCHITECTURAL REQUIREMENT ---
27
- The component `+w+` is marked as STANDALONE (standalone: true).
28
- You MUST add `+w+` to the 'imports' array within 'TestBed.configureTestingModule'.
29
- DO NOT add it to the 'declarations' array. If you omit `+w+" from 'imports', the test will fail."}d+=`
27
+ The component `+m+` is marked as STANDALONE (standalone: true).
28
+ You MUST add `+m+` to the 'imports' array within 'TestBed.configureTestingModule'.
29
+ DO NOT add it to the 'declarations' array. If you omit `+m+" from 'imports', the test will fail."}p+=`
30
30
 
31
31
  --- Sibling Component / Service Context ---
32
32
  You are fixing a '.spec' test file. Here is the actual implementation code for the component you are testing.
33
33
  Use this to identify EXACTLY which imports, Services, and Variables need to be mocked inside your 'TestBed'.
34
- `+r}l&&l.length>0&&(d+=`
34
+ `+r}a&&a.length>0&&(p+=`
35
35
 
36
36
  --- MEMORY ENGINE: PROVEN FIX PATTERNS ---
37
37
  The following fix patterns were SUCCESSFULLY used to resolve identical errors in past runs. Prioritise these approaches before trying anything novel:
38
- `+l.map((a,m)=>`
39
- [Pattern ${m+1}]
40
- ${a}`).join(`
41
- `)),i&&(console.log(`[Lisa.ai Auto-Heal] Warning! Agent is looping on ${t}. Injecting previous failed context...`),d+=`
38
+ `+a.map((l,g)=>`
39
+ [Pattern ${g+1}]
40
+ ${l}`).join(`
41
+ `)),o&&(console.log(`[Lisa.ai Auto-Heal] Warning! Agent is looping on ${t}. Injecting previous failed context...`),p+=`
42
42
 
43
43
  --- CRITICAL WARNING ---
44
44
  You previously attempted to fix this file but the compiler REJECTED your fix!
45
45
  Here is the previous analysis and failed fix you attempted:
46
- `+i+`
46
+ `+o+`
47
47
 
48
- DO NOT repeat the identical code changes. Try a completely different programming approach, fix syntax typos, or check for missing imports.`);let{text:p}=await(0,X.generateText)({model:g,prompt:d}),u=p.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return u?u[1].trim():p.trim()}async function Re(t,e,n,s,o,i){console.log(`[Lisa.ai Coverage] Requesting test generation from ${n} for ${t}...`);let r=ne(n,s),l=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:f}=await(0,oe.generateText)({model:u,prompt:p}),d=f.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return d?d[1].trim():f.trim()}async function Z(t,e,n,s,i,o){console.log(`[Lisa.ai Coverage] Requesting test generation from ${n} for ${t}...`);let r=de(n,s),a=i?`3. You MUST use the '${i}' testing framework exclusively. All imports, describe/it/test blocks, and mock utilities must follow '${i}' conventions.
49
49
  `:`3. Include all necessary imports assuming a standard testing framework (Jest/Karma/Vitest) is available.
50
- `,g=Pe(i),d=`You are Lisa.ai, an autonomous CI/CD expert platform.
50
+ `,u=_e(o),p=`You are Lisa.ai, an autonomous CI/CD expert platform.
51
51
  A source file lacks 100% test coverage. Your task is to generate a comprehensive testing suite covering all branches, lines, and functions.
52
52
 
53
53
  --- Target File Content (`+t+`) ---
54
- `+Ie(e,t)+"\n\n--- Constraints ---\n1. Return the generated test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+l+`4. Aim for 100% logic coverage.
55
- `+g,{text:p}=await(0,X.generateText)({model:r,prompt:d}),u=p.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),a=u?u[1].trim():p.trim();return Ee(a,t),a}async function De(t,e,n,s,o,i,r,l){console.log(`[Lisa.ai Coverage] Requesting test update from ${o} for ${t}...`);let g=ne(o,i),d=r?`3. You MUST use the '${r}' testing framework exclusively. All new tests must follow '${r}' conventions and integrate cleanly with the existing suite.
54
+ `+Oe(e,t)+"\n\n--- Constraints ---\n1. Return the generated test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+a+`4. Aim for 100% logic coverage.
55
+ `+u,{text:f}=await(0,oe.generateText)({model:r,prompt:p}),d=f.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),l=d?d[1].trim():f.trim();return Ue(l,t),l}async function He(t,e,n,s,i,o,r,a){console.log(`[Lisa.ai Coverage] Requesting test update from ${i} for ${t}...`);let u=de(i,o),p=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
- `,p=Pe(l),u=`You are Lisa.ai, an autonomous CI/CD expert platform.
57
+ `,f=_e(a),d=`You are Lisa.ai, an autonomous CI/CD expert platform.
58
58
  A source file lacks 100% test coverage. You must update its existing test suite to achieve full coverage.
59
59
 
60
60
  --- Target File Content (`+t+`) ---
61
- `+Ie(e,t)+`
61
+ `+Oe(e,t)+`
62
62
 
63
63
  --- Existing Test Suite (`+n+`) ---
64
- `+s+"\n\n--- Constraints ---\n1. Return the updated complete test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+d+`4. Aim for 100% logic coverage across branches, lines, and functions.
65
- `+p,{text:a}=await(0,X.generateText)({model:g,prompt:u}),m=a.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),w=m?m[1].trim():a.trim();return Ee(w,t),w}async function W(t,e,n){let s=ne(e,n),{text:o}=await(0,X.generateText)({model:s,prompt:t}),i=o.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return i?i[1].trim():o.trim()}var Me=C(require("simple-git")),Ne=require("@octokit/rest"),Ft=require("dotenv/config");async function me(t){console.log(`
66
- [Lisa.ai PR Engine] Initializing Pull Request for ${t}...`);let e=(0,Me.default)(),s=`lisa-fix/build-error-${new Date().getTime()}`,o=`fix: automated auto-heal by Lisa.ai for ${t}`,i="main";try{i=(await e.revparse(["--abbrev-ref","HEAD"])).trim()}catch{}try{await e.addConfig("user.name","Lisa.ai"),await e.addConfig("user.email","lisa@lisa.ai"),await e.checkoutLocalBranch(s),await e.add(t),await e.commit(o),console.log(`[Lisa.ai PR Engine] Committed changes to branch ${s}`),console.log("[Lisa.ai PR Engine] Pushing branch to remote origin..."),await e.push("origin",s,{"--set-upstream":null});let r=new Ne.Octokit({auth:process.env.GITHUB_TOKEN}),l=process.env.GITHUB_REPOSITORY;if(l&&process.env.GITHUB_TOKEN){let[g,d]=l.split("/");console.log(`[Lisa.ai PR Engine] Opening Pull Request against ${g}/${d}...`);let p=await r.rest.pulls.create({owner:g,repo:d,title:o,body:`### Lisa.ai Auto-Healed Pull Request
64
+ `+s+"\n\n--- Constraints ---\n1. Return the updated complete test code wrapped in a markdown code block (```typescript ... ```).\n2. Do not include any explanation or intro text.\n"+p+`4. Aim for 100% logic coverage across branches, lines, and functions.
65
+ `+f,{text:l}=await(0,oe.generateText)({model:u,prompt:d}),g=l.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/),m=g?g[1].trim():l.trim();return Ue(m,t),m}async function J(t,e,n){let s=de(e,n),{text:i}=await(0,oe.generateText)({model:s,prompt:t}),o=i.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);return o?o[1].trim():i.trim()}var Be=k(require("simple-git")),qe=require("@octokit/rest"),Yt=require("dotenv/config");async function ke(t){console.log(`
66
+ [Lisa.ai PR Engine] Initializing Pull Request for ${t}...`);let e=(0,Be.default)(),s=`lisa-fix/build-error-${new Date().getTime()}`,i=`fix: automated auto-heal by Lisa.ai for ${t}`,o="main";try{o=(await e.revparse(["--abbrev-ref","HEAD"])).trim()}catch{}try{await e.addConfig("user.name","Lisa.ai"),await e.addConfig("user.email","lisa@lisa.ai"),await e.checkoutLocalBranch(s),await e.add(t),await e.commit(i),console.log(`[Lisa.ai PR Engine] Committed changes to branch ${s}`),console.log("[Lisa.ai PR Engine] Pushing branch to remote origin..."),await e.push("origin",s,{"--set-upstream":null});let r=new qe.Octokit({auth:process.env.GITHUB_TOKEN}),a=process.env.GITHUB_REPOSITORY;if(a&&process.env.GITHUB_TOKEN){let[u,p]=a.split("/");console.log(`[Lisa.ai PR Engine] Opening Pull Request against ${u}/${p}...`);let f=await r.rest.pulls.create({owner:u,repo:p,title:i,body:`### Lisa.ai Auto-Healed Pull Request
67
67
  This PR was automatically generated by Lisa.ai to resolve a failing compilation/build step.
68
68
 
69
69
  **Healed File:** \`${t}\`
70
70
 
71
- Please review the changes.`,head:s,base:i});console.log(`\u2705 [Lisa.ai PR Engine] Pull Request created successfully: ${p.data.html_url}`)}else console.log("\u26A0\uFE0F [Lisa.ai PR Engine] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping GitHub Pull Request creation.")}catch(r){console.error(`
72
- \u{1F6A8} [Lisa.ai PR Engine Error] Failed to create Pull Request:`,r.message)}finally{try{await e.checkout(i)}catch{}}}var Oe=C(require("dotenv"));Oe.config({quiet:!0});async function O(t){let n=`${process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000"}/api/telemetry`;fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).catch(s=>{console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${s.message}`)})}var D=C(require("fs")),E=C(require("path"));var oe=C(require("fs")),_e=C(require("path")),H=".lisai.json",j=class{static _config=null;static _loaded=!1;static load(e=process.cwd()){if(this._loaded)return this._config;this._loaded=!0;let n=_e.resolve(e,H);if(!oe.existsSync(n))return null;try{let s=oe.readFileSync(n,"utf-8");return this._config=JSON.parse(s),console.log(`[Lisa.ai Config] Loaded project config from ${H}`),this._config}catch(s){return console.warn(`[Lisa.ai Config] Warning: ${H} found but failed to parse \u2014 ${s.message}. Using defaults.`),null}}static get(){return this._config}static applyEnvDefaults(e){if(!e.model)return;let n={claude:"LISA_CLAUDE_MODEL",openai:"LISA_OPENAI_MODEL",gemini:"LISA_GOOGLE_MODEL"},s=e.provider;s&&n[s]&&!process.env[n[s]]&&(process.env[n[s]]=e.model,console.log(`[Lisa.ai Config] Model override applied: ${s} \u2192 ${e.model}`))}static printSummary(e){let n=[];e.provider&&n.push(`provider=${e.provider}`),e.model&&n.push(`model=${e.model}`),e.testingFramework&&n.push(`testingFramework=${e.testingFramework}`),e.testTypes?.length&&n.push(`testTypes=[${e.testTypes.join(",")}]`),e.maxRetries!==void 0&&n.push(`maxRetries=${e.maxRetries}`),e.testCommand&&n.push(`testCommand="${e.testCommand}"`),n.length&&console.log(`[Lisa.ai Config] Settings: ${n.join(", ")}`),e.skipFiles?.length&&console.log(`[Lisa.ai Config] Extra skip files : ${e.skipFiles.join(", ")}`),e.skipDirs?.length&&console.log(`[Lisa.ai Config] Extra skip dirs : ${e.skipDirs.join(", ")}`),e.skipPaths?.length&&console.log(`[Lisa.ai Config] Extra skip paths : ${e.skipPaths.join(", ")}`)}};var q=class{static scanRepository(e=process.cwd()){let n=E.resolve(e,"package.json"),s={type:"unknown",testingFramework:"none"};if(!D.existsSync(n))return console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${n}. Defaulting to Generic Node.`),s.type="node",s;let o=JSON.parse(D.readFileSync(n,"utf8")),i={...o.dependencies||{},...o.devDependencies||{}},r=o.scripts||{};return i["@angular/core"]?s.type="angular":i.react?s.type="react":i.vue?s.type="vue":s.type="node",i.jest||r.test?.includes("jest")?s.testingFramework="jest":i.karma||r.test?.includes("karma")||r.test?.includes("ng test")?s.testingFramework="karma":(i.vitest||r.test?.includes("vitest"))&&(s.testingFramework="vitest"),s.testingFramework!=="none"&&(r.test?s.suggestedTestCommand="npm run test":s.testingFramework==="karma"?s.suggestedTestCommand="npx karma start":s.testingFramework==="jest"?s.suggestedTestCommand="npx jest --coverage":s.testingFramework==="vitest"&&(s.suggestedTestCommand="npx vitest run --coverage")),s}static findUntestedFiles(e,n=[]){let s=[];if(!D.existsSync(e))return s;let o=D.readdirSync(e),i=j.get(),r=i?.skipDirs??[],l=i?.skipFiles??[],g=i?.skipPaths??[],d=["node_modules","dist","build",".git",".angular","coverage","public","assets",...r],p=["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"],u=[/^\./,/\.config\.(js|ts|mjs|cjs)$/,/\.conf\.(js|ts|mjs|cjs)$/];for(let a of o){let m=E.join(e,a);if(d.includes(a))continue;let w;try{w=D.statSync(m)}catch{continue}if(w.isDirectory())s.push(...this.findUntestedFiles(m,n));else if(a.match(/\.(ts|tsx|js|jsx|vue)$/)&&!a.includes(".spec.")&&!a.includes(".test.")){if(p.includes(a)||l.includes(a)||u.some(h=>h.test(a)))continue;let c=E.extname(a),v=a.slice(0,-c.length);if(![E.join(e,`${v}.spec${c}`),E.join(e,`${v}.test${c}`),E.join(e,`${v}.spec.js`),E.join(e,`${v}.test.js`),E.join(e,`${v}.spec.ts`),E.join(e,`${v}.test.ts`)].some(h=>D.existsSync(h))){let h=E.relative(process.cwd(),m);if(g.some(A=>h.startsWith(A)))continue;n.includes(h)||s.push(h)}}}return s}};var Ue=require("child_process"),V=class{static async installMissingFramework(e,n=process.cwd()){if(e.testingFramework!=="none")return e;console.log(`
73
- [Lisa.ai Auto-Installer] \u{1F6A8} No testing framework detected for ${e.type} architecture.`),console.log("[Lisa.ai Auto-Installer] \u{1FA84} Initiating Zero-Config Installation Protocol...");let s="",o="none";switch(e.type){case"angular":console.log("[Lisa.ai Auto-Installer] Provisioning Angular TestBed environment..."),s="npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine jasmine-core @types/jasmine",o="karma",e.suggestedTestCommand="npm run test";break;case"react":case"node":default:console.log("[Lisa.ai Auto-Installer] Provisioning Universal Jest environment..."),s="npm install --save-dev jest @types/jest ts-jest",o="jest",e.suggestedTestCommand="npx jest --coverage";break;case"vue":console.log("[Lisa.ai Auto-Installer] Provisioning Vue Vitest environment..."),s="npm install --save-dev vitest @vue/test-utils jsdom",o="vitest",e.suggestedTestCommand="npx vitest run --coverage";break}if(s){console.log(`[Lisa.ai Executing] ${s}`);let i=s.split(" "),r=process.platform==="win32"?`${i[0]}.cmd`:i[0];return(0,Ue.spawnSync)(r,i.slice(1),{cwd:n,stdio:"inherit"}).status!==0&&(console.error(`
74
- \u274C [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`),process.exit(1)),console.log("\u2705 [Lisa.ai Auto-Installer] Framework successfully injected."),e.testingFramework=o,e}return e}};var ie=C(require("fs")),he=C(require("path"));var z=class{static async provisionConfigurationFiles(e,n,s,o=process.cwd()){if(e.testingFramework==="none")return;if(console.log(`
75
- [Lisa.ai Auto-Generator] \u{1FA84} Analyzing ${e.type} architecture to generate ${e.testingFramework} configuration specs...`),["jest.config.js","jest.config.ts","karma.conf.js","vitest.config.ts","vitest.config.js"].some(g=>ie.existsSync(he.join(o,g)))){console.log("[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.");return}let l=`You are an expert ${e.type} architect.
71
+ Please review the changes.`,head:s,base:o});console.log(`\u2705 [Lisa.ai PR Engine] Pull Request created successfully: ${f.data.html_url}`)}else console.log("\u26A0\uFE0F [Lisa.ai PR Engine] GITHUB_TOKEN or GITHUB_REPOSITORY not set. Skipping GitHub Pull Request creation.")}catch(r){console.error(`
72
+ \u{1F6A8} [Lisa.ai PR Engine Error] Failed to create Pull Request:`,r.message)}finally{try{await e.checkout(o)}catch{}}}var We=k(require("dotenv"));We.config({quiet:!0});async function I(t){let n=`${process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000"}/api/telemetry`;fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).catch(s=>{console.debug(`[Lisa.ai Agent Debug] Failed to report telemetry: ${s.message}`)})}var _=k(require("fs")),D=k(require("path"));var pe=k(require("fs")),Ye=k(require("path")),V=".lisai.json",F=class{static _config=null;static _loaded=!1;static load(e=process.cwd()){if(this._loaded)return this._config;this._loaded=!0;let n=Ye.resolve(e,V);if(!pe.existsSync(n))return null;try{let s=pe.readFileSync(n,"utf-8");return this._config=JSON.parse(s),console.log(`[Lisa.ai Config] Loaded project config from ${V}`),this._config}catch(s){return console.warn(`[Lisa.ai Config] Warning: ${V} found but failed to parse \u2014 ${s.message}. Using defaults.`),null}}static get(){return this._config}static applyEnvDefaults(e){if(!e.model)return;let n={claude:"LISA_CLAUDE_MODEL",openai:"LISA_OPENAI_MODEL",gemini:"LISA_GOOGLE_MODEL"},s=e.provider;s&&n[s]&&!process.env[n[s]]&&(process.env[n[s]]=e.model,console.log(`[Lisa.ai Config] Model override applied: ${s} \u2192 ${e.model}`))}static printSummary(e){let n=[];e.provider&&n.push(`provider=${e.provider}`),e.model&&n.push(`model=${e.model}`),e.testingFramework&&n.push(`testingFramework=${e.testingFramework}`),e.testTypes?.length&&n.push(`testTypes=[${e.testTypes.join(",")}]`),e.maxRetries!==void 0&&n.push(`maxRetries=${e.maxRetries}`),e.testCommand&&n.push(`testCommand="${e.testCommand}"`),e.e2eFramework&&n.push(`e2eFramework=${e.e2eFramework}`),e.e2eCommand&&n.push(`e2eCommand="${e.e2eCommand}"`),n.length&&console.log(`[Lisa.ai Config] Settings: ${n.join(", ")}`),e.skipFiles?.length&&console.log(`[Lisa.ai Config] Extra skip files : ${e.skipFiles.join(", ")}`),e.skipDirs?.length&&console.log(`[Lisa.ai Config] Extra skip dirs : ${e.skipDirs.join(", ")}`),e.skipPaths?.length&&console.log(`[Lisa.ai Config] Extra skip paths : ${e.skipPaths.join(", ")}`)}};var B=class{static scanRepository(e=process.cwd()){let n=D.resolve(e,"package.json"),s={type:"unknown",testingFramework:"none"};if(!_.existsSync(n))return console.warn(`[Lisa.ai AutoDiscovery] No package.json found at ${n}. Defaulting to Generic Node.`),s.type="node",s;let i=JSON.parse(_.readFileSync(n,"utf8")),o={...i.dependencies||{},...i.devDependencies||{}},r=i.scripts||{};return o["@angular/core"]?s.type="angular":o.react?s.type="react":o.vue?s.type="vue":s.type="node",o.jest||r.test?.includes("jest")?s.testingFramework="jest":o.karma||r.test?.includes("karma")||r.test?.includes("ng test")?s.testingFramework="karma":(o.vitest||r.test?.includes("vitest"))&&(s.testingFramework="vitest"),s.testingFramework!=="none"&&(r.test?s.suggestedTestCommand="npm run test":s.testingFramework==="karma"?s.suggestedTestCommand="npx karma start":s.testingFramework==="jest"?s.suggestedTestCommand="npx jest --coverage":s.testingFramework==="vitest"&&(s.suggestedTestCommand="npx vitest run --coverage")),s}static findUntestedFiles(e,n=[]){let s=[];if(!_.existsSync(e))return s;let i=_.readdirSync(e),o=F.get(),r=o?.skipDirs??[],a=o?.skipFiles??[],u=o?.skipPaths??[],p=["node_modules","dist","build",".git",".angular","coverage","public","assets",...r],f=["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"],d=[/^\./,/\.config\.(js|ts|mjs|cjs)$/,/\.conf\.(js|ts|mjs|cjs)$/];for(let l of i){let g=D.join(e,l);if(p.includes(l))continue;let m;try{m=_.statSync(g)}catch{continue}if(m.isDirectory())s.push(...this.findUntestedFiles(g,n));else if(l.match(/\.(ts|tsx|js|jsx|vue)$/)&&!l.includes(".spec.")&&!l.includes(".test.")){if(f.includes(l)||a.includes(l)||d.some(w=>w.test(l)))continue;let c=D.extname(l),y=l.slice(0,-c.length);if(![D.join(e,`${y}.spec${c}`),D.join(e,`${y}.test${c}`),D.join(e,`${y}.spec.js`),D.join(e,`${y}.test.js`),D.join(e,`${y}.spec.ts`),D.join(e,`${y}.test.ts`)].some(w=>_.existsSync(w))){let w=D.relative(process.cwd(),g);if(u.some($=>w.startsWith($)))continue;n.includes(w)||s.push(w)}}}return s}};var Ke=require("child_process"),Q=class{static async installMissingFramework(e,n=process.cwd()){if(e.testingFramework!=="none")return e;console.log(`
73
+ [Lisa.ai Auto-Installer] \u{1F6A8} No testing framework detected for ${e.type} architecture.`),console.log("[Lisa.ai Auto-Installer] \u{1FA84} Initiating Zero-Config Installation Protocol...");let s="",i="none";switch(e.type){case"angular":console.log("[Lisa.ai Auto-Installer] Provisioning Angular TestBed environment..."),s="npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine jasmine-core @types/jasmine",i="karma",e.suggestedTestCommand="npm run test";break;case"react":case"node":default:console.log("[Lisa.ai Auto-Installer] Provisioning Universal Jest environment..."),s="npm install --save-dev jest @types/jest ts-jest",i="jest",e.suggestedTestCommand="npx jest --coverage";break;case"vue":console.log("[Lisa.ai Auto-Installer] Provisioning Vue Vitest environment..."),s="npm install --save-dev vitest @vue/test-utils jsdom",i="vitest",e.suggestedTestCommand="npx vitest run --coverage";break}if(s){console.log(`[Lisa.ai Executing] ${s}`);let o=s.split(" "),r=process.platform==="win32"?`${o[0]}.cmd`:o[0];return(0,Ke.spawnSync)(r,o.slice(1),{cwd:n,stdio:"inherit"}).status!==0&&(console.error(`
74
+ \u274C [Lisa.ai Auto-Installer] Failed to construct dynamic testing environment.`),process.exit(1)),console.log("\u2705 [Lisa.ai Auto-Installer] Framework successfully injected."),e.testingFramework=i,e}return e}};var ge=k(require("fs")),je=k(require("path"));var X=class{static async provisionConfigurationFiles(e,n,s,i=process.cwd()){if(e.testingFramework==="none")return;if(console.log(`
75
+ [Lisa.ai Auto-Generator] \u{1FA84} Analyzing ${e.type} architecture to generate ${e.testingFramework} configuration specs...`),["jest.config.js","jest.config.ts","karma.conf.js","vitest.config.ts","vitest.config.js"].some(u=>ge.existsSync(je.join(i,u)))){console.log("[Lisa.ai Auto-Generator] Setup file detected. Bypassing initialization.");return}let a=`You are an expert ${e.type} architect.
76
76
  Write a production-ready '${e.testingFramework}' configuration file for a standard '${e.type}' application.
77
77
  The application resides in the root directory.
78
78
 
@@ -80,90 +80,161 @@ Requirements:
80
80
  1. Ensure it specifically instruments code coverage.
81
81
  2. Ensure standard transpilation (ts-jest for jest, or standard karma-webpack/karma-typescript implementations).
82
82
  3. Do NOT wrap your response in markdown formatting (no \`\`\`javascript).
83
- 4. Return ONLY the raw code string block.`;try{let g=await W(l,n,s),d="";e.testingFramework==="jest"&&(d="jest.config.js"),e.testingFramework==="karma"&&(d="karma.conf.js"),e.testingFramework==="vitest"&&(d="vitest.config.ts");let p=he.join(o,d);ie.writeFileSync(p,g,"utf-8"),console.log(`\u2705 [Lisa.ai Auto-Generator] Natively wrote ${d} to repository root.`)}catch(g){console.error(`
84
- \u274C [Lisa.ai Auto-Generator] Failed to author configuration file: ${g.message}`),process.exit(1)}}};var Ge=C(require("dotenv"));Ge.config({quiet:!0});function He(t){let e=t.toLowerCase();return e.includes("karma")||e.includes("ng test")?"karma":e.includes("jest")?"jest":e.includes("vitest")?"vitest":e.includes("playwright")?"playwright":e.includes("cypress")?"cypress":e.includes("mocha")?"mocha":"unknown"}async function qe(t,e,n){if(n==="local")return[];let s=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let o=new URLSearchParams({projectId:n,errorLog:t.slice(0,1e3),framework:e}),i=await fetch(`${s}/api/memory/lookup?${o}`);return i.ok?await i.json():[]}catch{return[]}}async function Be(t,e,n,s){if(s==="local")return;let o=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{await fetch(`${o}/api/memory/record`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:s,errorLog:t.slice(0,1e3),fixHint:e.slice(0,2e3),framework:n})}),console.log("[Lisa.ai Memory] Fix pattern recorded to Control Plane.")}catch(i){console.debug(`[Lisa.ai Agent Debug] Failed to record memory pattern: ${i.message}`)}}var K=0,re=0,ye=new Set;function xe(t){return t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function ht(t){let n=[...xe(t).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length===0)return null;let s=[...n].reverse().find(l=>l[3]!==void 0)??n[n.length-1],o=parseInt(s[2]),i=s[3]?parseInt(s[3]):0,r=parseInt(s[1])-i;return{total:o,passed:r,failed:i}}function ve(t){let n=[...xe(t).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length===0)return null;let s=[...n].reverse().find(d=>d[3]!==void 0)??n[n.length-1],o=parseInt(s[2]),i=s[3]?parseInt(s[3]):0,r=parseInt(s[1])-i,l=o>0?Math.round(r/o*100):0;return` [${"\u2588".repeat(Math.round(l/5))+"\u2591".repeat(20-Math.round(l/5))}] ${l}% ${r} passed ${i} failed ${o} total`}function We(t,e=10){let n=[];for(let s of xe(t).split(`
85
- `)){let o=s.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(n.push(r||o),n.length>=e)break}}return n}function yt(t){let e=t.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/,".$2");if(e!==t&&P.existsSync(e))try{return console.log(` [Lisa.ai] \u{1F9E0} Sibling source found: ${N.basename(e)}`),P.readFileSync(e,"utf-8")}catch{return}}function vt(t,e){let n=t.toLowerCase(),s=N.parse(e);if(n.includes("ng test")||n.includes("karma"))return`${t} --include **/${s.base}`;if(n.includes("jest")||n.includes("vitest")||n.includes("playwright"))return`${t} ${e}`;if(n.includes("cypress"))return`${t} --spec ${e}`;if(n.includes("npm")||n.includes("yarn")||n.includes("pnpm")){try{let i=JSON.parse(P.readFileSync(N.resolve(process.cwd(),"package.json"),"utf8")),r="test";n.includes("npm run ")?r=n.split("npm run ")[1].split(" ")[0]:n.includes("yarn ")?r=n.split("yarn ")[1].split(" ")[0]:n.includes("pnpm ")&&(r=n.split("pnpm ")[1].split(" ")[0]);let l=i.scripts?.[r]?.toLowerCase()||"",g=n.includes("npm")?" --":"";if(l.includes("ng test")||l.includes("karma"))return`${t}${g} --include **/${s.base}`;if(l.includes("jest")||l.includes("vitest")||l.includes("playwright"))return`${t}${g} ${e}`}catch{}let o=n.includes("npm")?" --":"";return`${t}${o} ${e}`}return t}function we(t,e=!1){return new Promise((n,s)=>{let o=(0,Ye.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),i="",r="";o.stdout?.on("data",l=>{let g=l.toString();if(i+=g,e)for(let d of g.split(`
86
- `)){let p=d.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"").trim();p&&(/Executed\s+\d+\s+of\s+\d+/.test(p)?process.stdout.write(`\r ${p.padEnd(72)}`):/^\s*FAILED\b/.test(p)&&(process.stdout.write(`
87
- `),console.log(` \u2717 ${p.trim()}`)))}}),o.stderr?.on("data",l=>{r+=l.toString()}),o.on("close",l=>{l===0?n({stdout:i,stderr:r}):s({message:`Process exited with code ${l}`,stdout:i,stderr:r})})})}function wt(t,e,n){if(!e.match(/\.(spec|test)\.(ts|js|tsx|jsx|vue)$/))return;if((n||"").toLowerCase().includes("ng test")||(n||"").toLowerCase().includes("karma"))try{P.writeFileSync(t,`// Quarantined by Lisa.ai \u2014 could not be automatically healed
83
+ 4. Return ONLY the raw code string block.`;try{let u=await J(a,n,s),p="";e.testingFramework==="jest"&&(p="jest.config.js"),e.testingFramework==="karma"&&(p="karma.conf.js"),e.testingFramework==="vitest"&&(p="vitest.config.ts");let f=je.join(i,p);ge.writeFileSync(f,u,"utf-8"),console.log(`\u2705 [Lisa.ai Auto-Generator] Natively wrote ${p} to repository root.`)}catch(u){console.error(`
84
+ \u274C [Lisa.ai Auto-Generator] Failed to author configuration file: ${u.message}`),process.exit(1)}}};var Ve=k(require("dotenv"));Ve.config({quiet:!0});function ze(t){let e=t.toLowerCase();return e.includes("karma")||e.includes("ng test")?"karma":e.includes("jest")?"jest":e.includes("vitest")?"vitest":e.includes("playwright")?"playwright":e.includes("cypress")?"cypress":e.includes("mocha")?"mocha":"unknown"}async function Ze(t,e,n){if(n==="local")return[];let s=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{let i=new URLSearchParams({projectId:n,errorLog:t.slice(0,1e3),framework:e}),o=await fetch(`${s}/api/memory/lookup?${i}`);return o.ok?await o.json():[]}catch{return[]}}async function Je(t,e,n,s){if(s==="local")return;let i=process.env.LISA_CONTROL_PLANE_URL||"http://localhost:3000";try{await fetch(`${i}/api/memory/record`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:s,errorLog:t.slice(0,1e3),fixHint:e.slice(0,2e3),framework:n})}),console.log("[Lisa.ai Memory] Fix pattern recorded to Control Plane.")}catch(o){console.debug(`[Lisa.ai Agent Debug] Failed to record memory pattern: ${o.message}`)}}var ee=0,fe=0,Se=new Set;function Ee(t){return t.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function Ct(t){let n=[...Ee(t).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length===0)return null;let s=[...n].reverse().find(a=>a[3]!==void 0)??n[n.length-1],i=parseInt(s[2]),o=s[3]?parseInt(s[3]):0,r=parseInt(s[1])-o;return{total:i,passed:r,failed:o}}function Ce(t){let n=[...Ee(t).matchAll(/Executed\s+(\d+)\s+of\s+(\d+)(?:\s+\((\d+)\s+FAILED\))?/g)];if(n.length===0)return null;let s=[...n].reverse().find(p=>p[3]!==void 0)??n[n.length-1],i=parseInt(s[2]),o=s[3]?parseInt(s[3]):0,r=parseInt(s[1])-o,a=i>0?Math.round(r/i*100):0;return` [${"\u2588".repeat(Math.round(a/5))+"\u2591".repeat(20-Math.round(a/5))}] ${a}% ${r} passed ${o} failed ${i} total`}function Xe(t,e=10){let n=[];for(let s of Ee(t).split(`
85
+ `)){let i=s.trim();if(/^FAILED/.test(i)||/ FAILED$/.test(i)){let r=i.replace(/^(?:Chrome|Firefox|Safari)(?:\s+Headless)?\s+[\d.]+(?:[\s.]\d+)*\s+\([^)]+\)\s+/,"").replace(/\s+FAILED$/,"").trim();if(n.push(r||i),n.length>=e)break}}return n}function At(t){let e=t.replace(/\.(spec|test)\.(ts|js|jsx|tsx)$/,".$2");if(e!==t&&N.existsSync(e))try{return console.log(` [Lisa.ai] \u{1F9E0} Sibling source found: ${q.basename(e)}`),N.readFileSync(e,"utf-8")}catch{return}}function Et(t,e){let n=t.toLowerCase(),s=q.parse(e);if(n.includes("ng test")||n.includes("karma"))return`${t} --include **/${s.base}`;if(n.includes("jest")||n.includes("vitest")||n.includes("playwright"))return`${t} ${e}`;if(n.includes("cypress"))return`${t} --spec ${e}`;if(n.includes("npm")||n.includes("yarn")||n.includes("pnpm")){try{let o=JSON.parse(N.readFileSync(q.resolve(process.cwd(),"package.json"),"utf8")),r="test";n.includes("npm run ")?r=n.split("npm run ")[1].split(" ")[0]:n.includes("yarn ")?r=n.split("yarn ")[1].split(" ")[0]:n.includes("pnpm ")&&(r=n.split("pnpm ")[1].split(" ")[0]);let a=o.scripts?.[r]?.toLowerCase()||"",u=n.includes("npm")?" --":"";if(a.includes("ng test")||a.includes("karma"))return`${t}${u} --include **/${s.base}`;if(a.includes("jest")||a.includes("vitest")||a.includes("playwright"))return`${t}${u} ${e}`}catch{}let i=n.includes("npm")?" --":"";return`${t}${i} ${e}`}return t}function Ae(t,e=!1){return new Promise((n,s)=>{let i=(0,Qe.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),o="",r="";i.stdout?.on("data",a=>{let u=a.toString();if(o+=u,e)for(let p of u.split(`
86
+ `)){let f=p.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"").trim();f&&(/Executed\s+\d+\s+of\s+\d+/.test(f)?process.stdout.write(`\r ${f.padEnd(72)}`):/^\s*FAILED\b/.test(f)&&(process.stdout.write(`
87
+ `),console.log(` \u2717 ${f.trim()}`)))}}),i.stderr?.on("data",a=>{r+=a.toString()}),i.on("close",a=>{a===0?n({stdout:o,stderr:r}):s({message:`Process exited with code ${a}`,stdout:o,stderr:r})})})}function bt(t,e,n){if(!e.match(/\.(spec|test)\.(ts|js|tsx|jsx|vue)$/))return;if((n||"").toLowerCase().includes("ng test")||(n||"").toLowerCase().includes("karma"))try{N.writeFileSync(t,`// Quarantined by Lisa.ai \u2014 could not be automatically healed
88
88
  describe('', () => {});
89
- `,"utf-8"),console.log(" \u{1F6A8} Replaced with empty stub (Angular requires valid TS).")}catch{}else try{P.renameSync(t,t+".broken"),console.log(` \u{1F6A8} Renamed to ${N.basename(t)}.broken to skip in test runner.`)}catch{}}async function xt(t,e,n,s,o,i,r,l,g,d){let p=1,u=!1,a=n,m,w="",c="",v=yt(e),y=(await qe(n,i,g)).filter(h=>h.confidence>=.5).map(h=>h.fixHint);for(y.length>0&&console.log(` [Memory] ${y.length} proven pattern(s) found \u2014 injecting as LLM hint.`);p<=l&&!u;){console.log(` [Attempt ${p}/${l}] Requesting fix from ${r}...`);let h=P.readFileSync(e,"utf-8"),A;for(let x=0;x<=3;x++)try{A=await Te(t,h,a,r,d,m,v,y);break}catch(L){let b=(L?.lastError??L)?.statusCode;if((b===529||b===500)&&x<3){let T=30*(x+1);console.warn(` \u26A0\uFE0F LLM overloaded (HTTP ${b}). Waiting ${T}s...`),await new Promise(M=>setTimeout(M,T*1e3))}else{console.error(` \u{1F6A8} LLM API failed: ${L?.message??String(L)}`);break}}if(A===void 0)break;P.writeFileSync(e,A,"utf-8"),w=`### Auto-Heal Analysis
89
+ `,"utf-8"),console.log(" \u{1F6A8} Replaced with empty stub (Angular requires valid TS).")}catch{}else try{N.renameSync(t,t+".broken"),console.log(` \u{1F6A8} Renamed to ${q.basename(t)}.broken to skip in test runner.`)}catch{}}async function Ft(t,e,n,s,i,o,r,a,u,p){let f=1,d=!1,l=n,g,m="",c="",y=At(e),v=(await Ze(n,o,u)).filter(w=>w.confidence>=.5).map(w=>w.fixHint);for(v.length>0&&console.log(` [Memory] ${v.length} proven pattern(s) found \u2014 injecting as LLM hint.`);f<=a&&!d;){console.log(` [Attempt ${f}/${a}] Requesting fix from ${r}...`);let w=N.readFileSync(e,"utf-8"),$;for(let x=0;x<=3;x++)try{$=await Ge(t,w,l,r,p,g,y,v);break}catch(L){let b=(L?.lastError??L)?.statusCode;if((b===529||b===500)&&x<3){let O=30*(x+1);console.warn(` \u26A0\uFE0F LLM overloaded (HTTP ${b}). Waiting ${O}s...`),await new Promise(H=>setTimeout(H,O*1e3))}else{console.error(` \u{1F6A8} LLM API failed: ${L?.message??String(L)}`);break}}if($===void 0)break;N.writeFileSync(e,$,"utf-8"),m=`### Auto-Heal Analysis
90
90
  **Error:**
91
91
  \`\`\`bash
92
- ${a.slice(0,2e3)}
92
+ ${l.slice(0,2e3)}
93
93
  \`\`\`
94
94
 
95
95
  **Fix (${r}):**
96
96
  \`\`\`typescript
97
- ${A}
98
- \`\`\``;try{await we(o,!1),console.log(" \u2705 Isolated verification passed."),u=!0,c=A}catch(x){let L=x.stdout?x.stdout.toString():"";a=(x.stderr?x.stderr.toString():"")+`
97
+ ${$}
98
+ \`\`\``;try{await Ae(i,!1),console.log(" \u2705 Isolated verification passed."),d=!0,c=$}catch(x){let L=x.stdout?x.stdout.toString():"";l=(x.stderr?x.stderr.toString():"")+`
99
99
  `+L+`
100
- `+(x.message||""),console.log(" \u274C Isolated verification failed.");let T=ve(a);if(T&&console.log(T),We(a,3).forEach(M=>console.log(` \u2717 ${M}`)),(s||"").toLowerCase().includes("ng test")||(s||"").toLowerCase().includes("karma")){let M=a.includes(N.basename(t)+":"),te=/ FAILED/.test(a);if(!M&&!te){console.log(" \u2705 Fix verified (build error is from other spec files, not this one)."),u=!0,c=A;continue}}m=`### Attempt ${p} Failed
100
+ `+(x.message||""),console.log(" \u274C Isolated verification failed.");let O=Ce(l);if(O&&console.log(O),Xe(l,3).forEach(H=>console.log(` \u2717 ${H}`)),(s||"").toLowerCase().includes("ng test")||(s||"").toLowerCase().includes("karma")){let H=l.includes(q.basename(t)+":"),le=/ FAILED/.test(l);if(!H&&!le){console.log(" \u2705 Fix verified (build error is from other spec files, not this one)."),d=!0,c=$;continue}}g=`### Attempt ${f} Failed
101
101
  \`\`\`typescript
102
- ${A}
102
+ ${$}
103
103
  \`\`\`
104
104
 
105
105
  **New Error:**
106
- ${a}`,p++}}return{status:u?"healed":"quarantined",details:w,lastCode:c}}async function ae(t,e,n=1,s=null,o=3,i="local",r,l){let g=j.load(process.cwd());if(g&&(j.applyEnvDefaults(g),!t&&g.testCommand&&(t=g.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`))),!t){console.log(`
107
- [Lisa.ai Auto-Discovery] No --command provided. Scanning framework...`);let f=q.scanRepository();f.testingFramework==="none"&&(f=await V.installMissingFramework(f),await z.provisionConfigurationFiles(f,e,l)),f.suggestedTestCommand?(t=f.suggestedTestCommand,console.log(`[Lisa.ai Auto-Discovery] Discovered command: ${t}`)):(console.error(`
108
- \u{1F6A8} [Lisa.ai] Could not discover a test command. Pass --command explicitly.`),process.exit(1))}let d=He(t),p=[];console.log(`
109
- [Lisa.ai] Running test suite (discovery pass)...`),console.log(`[Lisa.ai Executing] ${t} Model: ${e}`);let u;try{await we(t,!0),process.stdout.write(`
106
+ ${l}`,f++}}return{status:d?"healed":"quarantined",details:m,lastCode:c}}async function me(t,e,n=1,s=null,i=3,o="local",r,a){let u=F.load(process.cwd());if(u&&(F.applyEnvDefaults(u),!t&&u.testCommand&&(t=u.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`))),!t){console.log(`
107
+ [Lisa.ai Auto-Discovery] No --command provided. Scanning framework...`);let h=B.scanRepository();h.testingFramework==="none"&&(h=await Q.installMissingFramework(h),await X.provisionConfigurationFiles(h,e,a)),h.suggestedTestCommand?(t=h.suggestedTestCommand,console.log(`[Lisa.ai Auto-Discovery] Discovered command: ${t}`)):(console.error(`
108
+ \u{1F6A8} [Lisa.ai] Could not discover a test command. Pass --command explicitly.`),process.exit(1))}let p=ze(t),f=[];console.log(`
109
+ [Lisa.ai] Running test suite (discovery pass)...`),console.log(`[Lisa.ai Executing] ${t} Model: ${e}`);let d;try{await Ae(t,!0),process.stdout.write(`
110
110
  `),console.log(`
111
- \u2705 [Lisa.ai] All tests passing. Nothing to heal!`),s&&await me(s);return}catch(f){process.stdout.write(`
112
- `),u=(f.stderr||"")+`
113
- `+(f.stdout||"")+`
114
- `+(f.message||"")}let a=ht(u),m=ve(u);if(m){console.log(`
115
- ${m}`);let f=We(u,10);if(f.length>0){let y=a?.failed??f.length;console.log(` Failing (${y}):`),f.forEach(h=>console.log(` \u2717 ${h}`)),y>f.length&&console.log(` ... and ${y-f.length} more`)}}let w=pe(u,process.cwd(),p);if(w.length===0){let f=se(u,p,process.cwd());f||(console.error(`
116
- \u{1F6A8} [Lisa.ai] Could not identify any failing spec files. Output format may be unsupported.`),process.exit(1)),w=[f]}let c=w.length;console.log(`
117
- [Lisa.ai] Found ${c} failing spec(s). Healing each in isolation...`),console.log(`${"\u2500".repeat(60)}`);for(let f of w)O({projectId:i,type:"heal",filePath:f,modelUsed:e,status:"running",details:"Queued for isolated healing.",...a&&{testTotal:a.total,testPassed:a.passed,testFailed:a.failed},testFramework:d});for(let f=0;f<w.length;f++){let y=w[f],h=N.resolve(process.cwd(),y);if(console.log(`
118
- [${f+1}/${c}] ${y}`),!P.existsSync(h)){console.warn(" \u26A0\uFE0F File not found \u2014 skipping.");continue}if(/[\\/](node_modules|dist|build)[\\/]/.test(h)){console.warn(" \u26A0\uFE0F Library file \u2014 refusing to modify.");continue}let A=vt(t,y),x=await xt(y,h,u,t,A,d,e,o,i,l);x.status==="healed"?(K++,ye.add(y),console.log(` \u2705 Healed [${K} healed ${re} quarantined so far]`),O({projectId:i,type:"heal",filePath:y,modelUsed:e,status:"success",details:x.details,...a&&{testTotal:a.total,testPassed:a.passed,testFailed:a.failed},testFramework:d}),await Be(u,x.lastCode,d,i)):(re++,p.push(y),console.warn(` \u{1F6A8} Quarantined [${K} healed ${re} quarantined so far]`),O({projectId:i,type:"heal",filePath:y,modelUsed:e,status:"error",details:`Exhausted all ${o} attempts.
119
- `+x.details,...a&&{testTotal:a.total,testPassed:a.passed,testFailed:a.failed},testFramework:d}),wt(h,y,t))}if(console.log(`
120
- ${"\u2500".repeat(60)}`),K>0){console.log("[Lisa.ai] Final verification run...");try{await we(t,!0),process.stdout.write(`
111
+ \u2705 [Lisa.ai] All tests passing. Nothing to heal!`),s&&await ke(s);return}catch(h){process.stdout.write(`
112
+ `),d=(h.stderr||"")+`
113
+ `+(h.stdout||"")+`
114
+ `+(h.message||"")}let l=Ct(d),g=Ce(d);if(g){console.log(`
115
+ ${g}`);let h=Xe(d,10);if(h.length>0){let v=l?.failed??h.length;console.log(` Failing (${v}):`),h.forEach(w=>console.log(` \u2717 ${w}`)),v>h.length&&console.log(` ... and ${v-h.length} more`)}}let m=xe(d,process.cwd(),f);if(m.length===0){let h=ue(d,f,process.cwd());h||(console.error(`
116
+ \u{1F6A8} [Lisa.ai] Could not identify any failing spec files. Output format may be unsupported.`),process.exit(1)),m=[h]}let c=m.length;console.log(`
117
+ [Lisa.ai] Found ${c} failing spec(s). Healing each in isolation...`),console.log(`${"\u2500".repeat(60)}`);for(let h of m)I({projectId:o,type:"heal",filePath:h,modelUsed:e,status:"running",details:"Queued for isolated healing.",...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:p});for(let h=0;h<m.length;h++){let v=m[h],w=q.resolve(process.cwd(),v);if(console.log(`
118
+ [${h+1}/${c}] ${v}`),!N.existsSync(w)){console.warn(" \u26A0\uFE0F File not found \u2014 skipping.");continue}if(/[\\/](node_modules|dist|build)[\\/]/.test(w)){console.warn(" \u26A0\uFE0F Library file \u2014 refusing to modify.");continue}let $=Et(t,v),x=await Ft(v,w,d,t,$,p,e,i,o,a);x.status==="healed"?(ee++,Se.add(v),console.log(` \u2705 Healed [${ee} healed ${fe} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:e,status:"success",details:x.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:p}),await Je(d,x.lastCode,p,o)):(fe++,f.push(v),console.warn(` \u{1F6A8} Quarantined [${ee} healed ${fe} quarantined so far]`),I({projectId:o,type:"heal",filePath:v,modelUsed:e,status:"error",details:`Exhausted all ${i} attempts.
119
+ `+x.details,...l&&{testTotal:l.total,testPassed:l.passed,testFailed:l.failed},testFramework:p}),bt(w,v,t))}if(console.log(`
120
+ ${"\u2500".repeat(60)}`),ee>0){console.log("[Lisa.ai] Final verification run...");try{await Ae(t,!0),process.stdout.write(`
121
121
  `),console.log(`
122
- \u2705 All tests passing!`)}catch(f){process.stdout.write(`
123
- `);let y=(f.stderr||"")+`
124
- `+(f.stdout||"")+`
125
- `+(f.message||""),h=ve(y);h&&console.log(`
126
- ${h}`);let A=pe(y,process.cwd(),[]),x=A.filter(b=>ye.has(b)),L=A.filter(b=>!ye.has(b)&&!p.includes(b));x.length>0&&(console.warn(`
122
+ \u2705 All tests passing!`)}catch(h){process.stdout.write(`
123
+ `);let v=(h.stderr||"")+`
124
+ `+(h.stdout||"")+`
125
+ `+(h.message||""),w=Ce(v);w&&console.log(`
126
+ ${w}`);let $=xe(v,process.cwd(),[]),x=$.filter(b=>Se.has(b)),L=$.filter(b=>!Se.has(b)&&!f.includes(b));x.length>0&&(console.warn(`
127
127
  \u26A0\uFE0F ${x.length} spec(s) passed isolated verification but still fail globally:`),x.forEach(b=>console.warn(` \u2717 ${b}`)),console.warn(" These likely have cross-test shared state. Try higher maxRetries or fix manually.")),L.length>0&&(console.warn(`
128
- \u2139\uFE0F ${L.length} additional failing spec(s) not in this run's queue:`),L.forEach(b=>console.warn(` \u2717 ${b}`)),console.warn(" Run lisa-agent heal again to address these."))}}let v=(a?.passed??0)+K;console.log(`
129
- \u2705 Healed: ${K} / ${c}`),console.log(` \u{1F6A8} Quarantined: ${re}`),a&&console.log(` \u{1F4CA} Suite: ${a.passed} passing \u2192 ~${v} passing (est.)`),console.log(`${"\u2500".repeat(60)}
130
- `),s&&await me(s)}var Ze=require("child_process"),_=C(require("fs")),F=C(require("path"));var le=C(require("fs")),Ve=C(require("path"));function ze(t){let e=Ve.resolve(process.cwd(),t);if(!le.existsSync(e))throw new Error(`[Lisa.ai Coverage Error] Coverage file not found at ${e}`);let n=le.readFileSync(e,"utf-8"),s=JSON.parse(n),o=[];for(let[i,r]of Object.entries(s))i!=="total"&&(r.lines.pct<100||r.statements.pct<100||r.functions.pct<100||r.branches.pct<100)&&o.push(i);return o}var Ke=new Set,ce=0,Le=3;async function ee(t,e,n=1,s=3,o="local",i){let r=j.load(process.cwd());r&&(j.applyEnvDefaults(r),!t&&r.testCommand&&(t=r.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let l=q.scanRepository(),g=r?.testingFramework||(l.testingFramework!=="none"?l.testingFramework:void 0),d=r?.testTypes;if(!t){console.log(`
131
- [Lisa.ai Auto-Discovery] No explicit --command provided. Initiating Autonomous Framework Fingerprinting...`);let u=l;if(u.testingFramework==="none"&&(u=await V.installMissingFramework(u),await z.provisionConfigurationFiles(u,e,i)),u.suggestedTestCommand){t=u.suggestedTestCommand;let a=u.testingFramework;(a==="jest"||a==="vitest")&&!t.includes("--coverage")&&(t=t.includes("npm run")?`${t} -- --coverage`:`${t} --coverage`,console.log(`[Lisa.ai Coverage] Coverage flag appended: ${t}`)),console.log(`[Lisa.ai Auto-Discovery] Bootstrapping execution with natively discovered command: ${t}`)}else console.error(`
132
- \u{1F6A8} [Lisa.ai Fatal Error] Agent could not dynamically extrapolate a testing command for a Generic Node Environment. Please pass --command explicitly.`),process.exit(1)}console.log(`
133
- [Lisa.ai Coverage] ${t} (Attempt ${n}/${s}) Using Model: ${e}`),await O({projectId:o,type:"coverage",filePath:"global-test-suite",modelUsed:e,status:"running",details:"Agent is currently executing testing suite and validating coverage drops..."});let p=(u,a=!1)=>new Promise((m,w)=>{let c=(0,Ze.spawn)(u,{shell:!0,stdio:["ignore","pipe","pipe"]}),v="",f="";c.stdout?.on("data",y=>{let h=y.toString();if(v+=h,a){let A=h.split(`
134
- `);for(let x of A){let L=x.match(/Executed\s+(\d+)\s+of\s+(\d+)/);if(L){let b=x.match(/(\d+)\s+FAILED/),T=b?b[1]:0,M=`\r\u23F3 [Lisa.ai Testing] Executed ${L[1]} of ${L[2]} (${T} FAILED) `;process.stdout.write(M)}}}}),c.stderr?.on("data",y=>{f+=y.toString()}),c.on("close",y=>{y===0?m():w({message:`Test process exited with code ${y}`,stdout:v,stderr:f})})});try{console.log("[Lisa.ai Coverage] Booting testing framework in the background. This may take a moment..."),await p(t,!0),console.log(`
135
- \u2705 [Lisa.ai Coverage] Tests passed successfully on attempt ${n}.`)}catch(u){let a=(u.stderr||"")+`
136
- `+(u.stdout||"")+`
137
- `+(u.message||"");if(se(a,[],process.cwd())!==null){console.log(`
138
- \u274C [Lisa.ai Coverage] Tests failed. Delegating to Auto-Heal...`),await ae(t,e,1,null,s,o,void 0,i),console.log(`
139
- \u{1F504} [Lisa.ai Coverage] Auto-Heal successful. Restarting coverage analysis...`),await ee(t,e,n+1,s,o,i);return}console.log(`
140
- [Lisa.ai Coverage] No failing spec file detected in error output. Tests may not exist yet \u2014 initiating Cold-Start Discovery...`)}try{let u=F.resolve(process.cwd(),"coverage/coverage-summary.json"),a=[];if(_.existsSync(u))console.log("[Lisa.ai Coverage] Evaluating summary..."),a=ze("coverage/coverage-summary.json");else{if(console.log(`
141
- [Lisa.ai Coverage] No coverage-summary.json found. Initiating Cold-Start Project Crawler...`),a=q.findUntestedFiles(process.cwd(),[...Ke]),a.length===0){console.log("\u2705 [Lisa.ai Coverage] Zero-Test scan complete. No untested source files discovered.");return}console.log(`[Lisa.ai Coverage] Discovered ${a.length} untested file(s). Seeding first test suite...`)}if(a.length===0){console.log("\u2705 [Lisa.ai Coverage] 100% Logic Coverage Verified! No un-covered files remaining.");return}console.log(`[Lisa.ai Coverage] Found ${a.length} file(s) below 100% threshold:`,a);let m=a[0],w=F.resolve(process.cwd(),m),c=F.parse(w),v=[F.join(c.dir,`${c.name}.spec${c.ext}`),F.join(c.dir,`${c.name}.test${c.ext}`),F.join(c.dir,`${c.name}.spec.js`),F.join(c.dir,`${c.name}.test.js`),F.join(c.dir,`${c.name}.spec.ts`),F.join(c.dir,`${c.name}.test.ts`)],f=null,y=F.join(c.dir,`${c.name}.spec${c.ext}`);for(let L of v)if(_.existsSync(L)){y=L,f=_.readFileSync(L,"utf-8");break}let h="",A=!1,x=_.readFileSync(w,"utf-8");try{f?(console.log(`[Lisa.ai Coverage] Existing test suite discovered for ${m}. Requesting single-pass logic coverage append...`),h=await De(m,x,F.relative(process.cwd(),y),f,e,i,g,d)):(console.log(`[Lisa.ai Coverage] Requesting newly generated test suite for ${m}...`),h=await Re(m,x,e,i,g,d)),ce=0,A=!0}catch(L){ce++,Ke.add(m);let b=L.cause?.message?`${L.message} (cause: ${L.cause.message})`:L.message;if(console.error(`
142
- \u274C [Lisa.ai Coverage] LLM call failed for ${m} \u2014 consecutive failure #${ce}/${Le}`),console.error(` Error: ${b}`),ce>=Le)throw new Error(`Systematic LLM failure: ${Le} consecutive API calls failed.
128
+ \u2139\uFE0F ${L.length} additional failing spec(s) not in this run's queue:`),L.forEach(b=>console.warn(` \u2717 ${b}`)),console.warn(" Run lisa-agent heal again to address these."))}}let y=(l?.passed??0)+ee;console.log(`
129
+ \u2705 Healed: ${ee} / ${c}`),console.log(` \u{1F6A8} Quarantined: ${fe}`),l&&console.log(` \u{1F4CA} Suite: ${l.passed} passing \u2192 ~${y} passing (est.)`),console.log(`${"\u2500".repeat(60)}
130
+ `),s&&await ke(s)}var nt=require("child_process"),G=k(require("fs")),R=k(require("path"));var he=k(require("fs")),et=k(require("path"));function tt(t){let e=et.resolve(process.cwd(),t);if(!he.existsSync(e))throw new Error(`[Lisa.ai Coverage Error] Coverage file not found at ${e}`);let n=he.readFileSync(e,"utf-8"),s=JSON.parse(n),i=[];for(let[o,r]of Object.entries(s))o!=="total"&&(r.lines.pct<100||r.statements.pct<100||r.functions.pct<100||r.branches.pct<100)&&i.push(o);return i}var st=new Set,ye=0,be=3;function Pt(t){let e=t.testingFramework,n=process.cwd();return G.existsSync(R.join(n,"angular.json"))?"npx ng test --no-watch --code-coverage --browsers=ChromeHeadless":e==="jest"?"npx jest --coverage --coverageReporters=json-summary":e==="vitest"?"npx vitest run --coverage":[".mocharc.yml",".mocharc.yaml",".mocharc.json",".mocharc.js"].some(i=>G.existsSync(R.join(n,i)))?"npx nyc --reporter=json-summary mocha":null}async function ie(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
131
+ [Lisa.ai Unit] Reached maximum retries (${s}). Stopping.`);return}let r=F.load(process.cwd());r&&(F.applyEnvDefaults(r),!t&&r.testCommand&&(t=r.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let a=B.scanRepository(),u=r?.testingFramework||(a.testingFramework!=="none"?a.testingFramework:void 0),p=r?.testTypes;if(!t){console.log(`
132
+ [Lisa.ai Auto-Discovery] No explicit --command provided. Auto-detecting coverage command...`);let d=Pt(a);if(d)t=d,console.log(`[Lisa.ai Auto-Discovery] Detected coverage command: ${t}`);else{let l=a;if(l.testingFramework==="none"&&(l=await Q.installMissingFramework(l),await X.provisionConfigurationFiles(l,e,o)),l.suggestedTestCommand){t=l.suggestedTestCommand;let g=l.testingFramework;(g==="jest"||g==="vitest")&&!t.includes("--coverage")&&(t=t.includes("npm run")?`${t} -- --coverage`:`${t} --coverage`,console.log(`[Lisa.ai Unit] Coverage flag appended: ${t}`)),console.log(`[Lisa.ai Auto-Discovery] Bootstrapping with discovered command: ${t}`)}else console.error(`
133
+ [Lisa.ai Fatal Error] Could not auto-detect a test framework. Please pass --command explicitly or add a .lisai.json config.`),process.exit(1)}}console.log(`
134
+ [Lisa.ai Unit] ${t} (Attempt ${n}/${s}) Using Model: ${e}`),await I({projectId:i,type:"unit",filePath:"global-test-suite",modelUsed:e,status:"running",details:"Agent is executing unit test suite and validating coverage..."});let f=(d,l=!1)=>new Promise((g,m)=>{let c=(0,nt.spawn)(d,{shell:!0,stdio:["ignore","pipe","pipe"]}),y="",h="";c.stdout?.on("data",v=>{let w=v.toString();if(y+=w,l){let $=w.split(`
135
+ `);for(let x of $){let L=x.match(/Executed\s+(\d+)\s+of\s+(\d+)/);if(L){let b=x.match(/(\d+)\s+FAILED/),O=b?b[1]:0,H=`\r[Lisa.ai Testing] Executed ${L[1]} of ${L[2]} (${O} FAILED) `;process.stdout.write(H)}}}}),c.stderr?.on("data",v=>{h+=v.toString()}),c.on("close",v=>{v===0?g():m({message:`Test process exited with code ${v}`,stdout:y,stderr:h})})});try{console.log("[Lisa.ai Unit] Running tests with coverage. This may take a moment..."),await f(t,!0),console.log(`
136
+ [Lisa.ai Unit] Tests passed on attempt ${n}.`)}catch(d){let l=(d.stderr||"")+`
137
+ `+(d.stdout||"")+`
138
+ `+(d.message||"");if(ue(l,[],process.cwd())!==null){console.log(`
139
+ [Lisa.ai Unit] Tests failed. Delegating to Auto-Heal...`),await me(t,e,1,null,s,i,void 0,o),console.log(`
140
+ [Lisa.ai Unit] Auto-Heal complete. Restarting unit analysis...`),await ie(t,e,n+1,s,i,o);return}console.log(`
141
+ [Lisa.ai Unit] No failing spec detected. Tests may not exist yet \u2014 initiating Cold-Start Discovery...`)}try{let d=R.resolve(process.cwd(),"coverage/coverage-summary.json"),l=[];if(G.existsSync(d))console.log("[Lisa.ai Unit] Evaluating coverage summary..."),l=tt("coverage/coverage-summary.json");else{if(console.log(`
142
+ [Lisa.ai Unit] No coverage-summary.json found. Initiating Cold-Start Discovery...`),l=B.findUntestedFiles(process.cwd(),[...st]),l.length===0){console.log("[Lisa.ai Unit] No untested source files discovered.");return}console.log(`[Lisa.ai Unit] Discovered ${l.length} untested file(s). Generating specs...`)}if(l.length===0){console.log("[Lisa.ai Unit] 100% coverage achieved. No uncovered files remaining.");return}console.log(`[Lisa.ai Unit] Found ${l.length} file(s) below threshold:`,l);let g=l[0],m=R.resolve(process.cwd(),g),c=R.parse(m),y=[R.join(c.dir,`${c.name}.spec${c.ext}`),R.join(c.dir,`${c.name}.test${c.ext}`),R.join(c.dir,`${c.name}.spec.js`),R.join(c.dir,`${c.name}.test.js`),R.join(c.dir,`${c.name}.spec.ts`),R.join(c.dir,`${c.name}.test.ts`)],h=null,v=R.join(c.dir,`${c.name}.spec${c.ext}`);for(let L of y)if(G.existsSync(L)){v=L,h=G.readFileSync(L,"utf-8");break}let w="",$=!1,x=G.readFileSync(m,"utf-8");try{h?(console.log(`[Lisa.ai Unit] Existing spec found for ${g}. Requesting coverage append...`),w=await He(g,x,R.relative(process.cwd(),v),h,e,o,u,p)):(console.log(`[Lisa.ai Unit] Generating new spec for ${g}...`),w=await Z(g,x,e,o,u,p)),ye=0,$=!0}catch(L){ye++,st.add(g);let b=L.cause?.message?`${L.message} (cause: ${L.cause.message})`:L.message;if(console.error(`
143
+ [Lisa.ai Unit] LLM call failed for ${g} \u2014 consecutive failure #${ye}/${be}`),console.error(` Error: ${b}`),ye>=be)throw new Error(`Systematic LLM failure: ${be} consecutive API calls failed.
143
144
  This usually means your API key has insufficient credits, hit a rate limit, or the model is unavailable.
144
145
  Last error: ${b}
145
- Tip: Check your API key, account credits, and rate-limit quota for provider '${e}'.`)}if(!A){await ee(t,e,n+1,s,o,i);return}_.writeFileSync(y,h,"utf-8"),console.log(`[Lisa.ai Coverage] Wrote Spec File to ${y}`),await O({projectId:o,type:"coverage",filePath:m,modelUsed:e,status:"success",details:`### Logic Coverage Action Detected
146
- **Auto-Generated Specification Append (${e}):**
146
+ Tip: Check your API key, account credits, and rate-limit quota for provider '${e}'.`)}if(!$){await ie(t,e,n+1,s,i,o);return}G.writeFileSync(v,w,"utf-8"),console.log(`[Lisa.ai Unit] Wrote spec to ${v}`),await I({projectId:i,type:"unit",filePath:g,modelUsed:e,status:"success",details:`### Unit Test Generated
147
+ **Auto-Generated Spec (${e}):**
147
148
  \`\`\`typescript
148
- ${h}
149
- \`\`\``}),await ee(t,e,n+1,s,o,i)}catch(u){console.error("[Lisa.ai Coverage loop failure]:",u.message),await O({projectId:o,type:"coverage",filePath:"coverage-loop",modelUsed:e,status:"error",details:`Coverage loop encountered an unrecoverable error: ${u.message}`})}}var Xe=C(require("dotenv")),et=require("child_process"),G=C(require("fs")),U=C(require("path"));Xe.config({quiet:!0});function Z(t){return new Promise(e=>{let n=(0,et.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),s="",o="";n.stdout?.on("data",i=>{s+=i.toString()}),n.stderr?.on("data",i=>{o+=i.toString()}),n.on("close",i=>e({stdout:s,stderr:o,code:i??1}))})}function Lt(){return G.existsSync(U.resolve(process.cwd(),"pnpm-lock.yaml"))?"pnpm":G.existsSync(U.resolve(process.cwd(),"yarn.lock"))?"yarn":"npm"}var $t={critical:"\u{1F534}",high:"\u{1F7E0}",moderate:"\u{1F7E1}",low:"\u{1F535}",info:"\u26AA"},Je={critical:5,high:4,moderate:3,low:2,info:1};function Qe(t){let e=["critical","high","moderate","low","info"];for(let n of e){let s=t[n]??0;s>0&&console.log(` ${$t[n]} ${n.padEnd(10)} ${s}`)}console.log(` ${"\u2500".repeat(22)}`),console.log(` ${"Total".padEnd(10)} ${t.total}`)}async function $e(t){try{return JSON.parse(t)}catch{return null}}async function tt(t,e="local",n){G.existsSync(U.resolve(process.cwd(),"package.json"))||(console.error(`
150
- \u{1F6A8} [Lisa.ai Audit] No package.json found in ${process.cwd()}.`),console.error(" The audit command currently supports Node.js / npm projects only."),process.exit(1));let s=Lt();console.log(`[Lisa.ai Audit] Package manager: ${s}`),console.log(`
151
- [Lisa.ai Audit] Scanning for vulnerabilities...`);let{stdout:o,code:i}=await Z(s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json");if(i===0){console.log(`
152
- \u2705 [Lisa.ai Audit] No vulnerabilities found! Repository is clean.`);return}let r=await $e(o);r||(console.error("[Lisa.ai Audit] Could not parse audit output. Run 'npm audit' manually to investigate."),process.exit(1));let l=r.metadata.vulnerabilities;console.log(`
153
- Vulnerabilities found:`),Qe(l),console.log(`
154
- [Lisa.ai Audit] Applying safe automatic fixes (npm audit fix)...`);let{stdout:g}=await Z(s==="npm"?"npm audit fix":s==="yarn"?"yarn upgrade":"pnpm audit fix");for(let $ of g.split(`
155
- `)){let I=$.trim();I&&!I.startsWith("npm warn")&&!I.startsWith("npm notice")&&console.log(` ${I}`)}let d=s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json",{stdout:p,code:u}=await Z(d);if(u===0){console.log(`
156
- \u2705 [Lisa.ai Audit] All vulnerabilities fixed by safe auto-fix!`);return}let a=await $e(p);if(!a){console.warn("[Lisa.ai Audit] Could not parse post-fix audit output.");return}let m=Object.values(a.vulnerabilities),w=a.metadata.vulnerabilities,c=l.total-w.total;console.log(`
157
- [Lisa.ai Audit] Safe auto-fix resolved ${c} vulnerability(-ies).`),w.total>0&&(console.log(" Remaining:"),Qe(w));let v=m.filter($=>typeof $.fixAvailable=="object"&&!$.fixAvailable.isSemVerMajor).map($=>$.fixAvailable),f=[...new Map(v.map($=>[$.name,$])).values()];if(f.length>0){console.log(`
158
- [Lisa.ai Audit] Applying ${f.length} non-breaking targeted upgrade(s)...`);for(let Y of f){let R=`npm install ${Y.name}@${Y.version}`;console.log(` \u2192 ${R}`);let{stderr:J}=await Z(R);J&&!J.includes("npm warn")&&console.warn(` ${J.trim()}`)}let{stdout:$,code:I}=await Z(d);if(I===0){console.log(`
159
- \u2705 [Lisa.ai Audit] All vulnerabilities resolved!`);return}}let{stdout:y}=await Z(d),h=await $e(y)??a,x=Object.values(h.vulnerabilities).sort(($,I)=>(Je[I.severity]??0)-(Je[$.severity]??0)).slice(0,10).filter($=>$.fixAvailable===!1?!0:typeof $.fixAvailable=="object"?$.fixAvailable.isSemVerMajor:!1);if(x.length===0){console.log(`
149
+ ${w}
150
+ \`\`\``}),await ie(t,e,n+1,s,i,o)}catch(d){console.error("[Lisa.ai Unit loop failure]:",d.message),await I({projectId:i,type:"unit",filePath:"unit-loop",modelUsed:e,status:"error",details:`Unit test generation encountered an unrecoverable error: ${d.message}`})}}var re=require("child_process"),j=k(require("fs")),P=k(require("path"));function Tt(t){if(j.existsSync(P.join(t,"playwright.config.ts"))||j.existsSync(P.join(t,"playwright.config.js")))return{framework:"playwright",configFile:j.existsSync(P.join(t,"playwright.config.ts"))?"playwright.config.ts":"playwright.config.js",command:"npx playwright test",installed:!0};if(j.existsSync(P.join(t,"cypress.config.ts"))||j.existsSync(P.join(t,"cypress.config.js"))||j.existsSync(P.join(t,"cypress.json")))return{framework:"cypress",configFile:j.existsSync(P.join(t,"cypress.config.ts"))?"cypress.config.ts":j.existsSync(P.join(t,"cypress.config.js"))?"cypress.config.js":"cypress.json",command:"npx cypress run",installed:!0};let e=P.join(t,"package.json");if(j.existsSync(e)){let n=JSON.parse(j.readFileSync(e,"utf-8")),s={...n.dependencies||{},...n.devDependencies||{}};if(s["@playwright/test"])return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!0};if(s.cypress)return{framework:"cypress",configFile:null,command:"npx cypress run",installed:!0}}return{framework:"playwright",configFile:null,command:"npx playwright test",installed:!1}}function It(t){console.log("[Lisa.ai E2E] No E2E framework detected. Installing Playwright...");try{(0,re.execSync)("npm install -D @playwright/test",{cwd:t,stdio:"pipe"}),console.log("[Lisa.ai E2E] Playwright installed.")}catch(n){throw console.error(`[Lisa.ai E2E] Failed to install Playwright: ${n.message}`),new Error("Could not install @playwright/test. Please install it manually.")}try{console.log("[Lisa.ai E2E] Installing Playwright browsers..."),(0,re.execSync)("npx playwright install --with-deps chromium",{cwd:t,stdio:"pipe"}),console.log("[Lisa.ai E2E] Chromium browser installed.")}catch{console.warn("[Lisa.ai E2E Warning] Browser install failed. You may need to run 'npx playwright install' manually.")}j.existsSync(P.join(t,"playwright.config.ts"))||(j.writeFileSync(P.join(t,"playwright.config.ts"),`import { defineConfig } from '@playwright/test';
151
+
152
+ export default defineConfig({
153
+ testDir: './e2e',
154
+ fullyParallel: true,
155
+ forbidOnly: !!process.env.CI,
156
+ retries: process.env.CI ? 2 : 0,
157
+ workers: process.env.CI ? 1 : undefined,
158
+ reporter: 'html',
159
+ use: {
160
+ baseURL: 'http://localhost:4200',
161
+ trace: 'on-first-retry',
162
+ },
163
+ projects: [
164
+ { name: 'chromium', use: { browserName: 'chromium' } },
165
+ ],
166
+ });
167
+ `,"utf-8"),console.log("[Lisa.ai E2E] Generated playwright.config.ts"));let e=P.join(t,"e2e");j.existsSync(e)||(j.mkdirSync(e,{recursive:!0}),console.log("[Lisa.ai E2E] Created e2e/ directory"))}function Rt(t){let e=[],n=["src/app/app.routes.ts","src/app/app-routing.module.ts"];for(let i of n){let o=P.join(t,i);if(j.existsSync(o)){let a=j.readFileSync(o,"utf-8").matchAll(/path:\s*['"`]([^'"`]+)['"`]/g);for(let u of a)u[1]&&u[1]!=="**"&&e.push(u[1])}}let s=["src/App.tsx","src/App.jsx","src/routes.tsx","src/routes.jsx"];for(let i of s){let o=P.join(t,i);if(j.existsSync(o)){let a=j.readFileSync(o,"utf-8").matchAll(/path=["']([^"']+)["']/g);for(let u of a)u[1]&&e.push(u[1])}}return[...new Set(e)].sort()}async function ot(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
168
+ [Lisa.ai E2E] Reached maximum retries (${s}). Stopping.`);return}let r=process.cwd(),a=F.load(r);a&&(F.applyEnvDefaults(a),!t&&a.e2eCommand&&(t=a.e2eCommand,console.log(`[Lisa.ai Config] Using e2eCommand from .lisai.json: ${t}`)));let u=Tt(r),p=a?.e2eFramework||u.framework;console.log(`
169
+ [Lisa.ai E2E] Framework: ${p} (Attempt ${n}/${s}) Model: ${e}`),!u.installed&&p==="playwright"&&It(r),t||(t=u.command,console.log(`[Lisa.ai E2E] Using auto-detected command: ${t}`)),await I({projectId:i,type:"e2e",filePath:"e2e-suite",modelUsed:e,status:"running",details:`E2E test generation started with ${p}`});let f=Rt(r);f.length===0?(console.log("[Lisa.ai E2E] No routes discovered. Will generate basic smoke test."),f.push("")):console.log(`[Lisa.ai E2E] Discovered ${f.length} route(s):`,f);let d=P.join(r,"e2e");j.existsSync(d)||j.mkdirSync(d,{recursive:!0});let l=j.existsSync(d)?j.readdirSync(d).filter(m=>m.endsWith(".spec.ts")||m.endsWith(".test.ts")):[],g=0;for(let m of f){let y=`${(m||"home").replace(/\//g,"-")}.spec.ts`,h=P.join(d,y);if(l.includes(y)){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 v=`
170
+ E2E Test Generation Context:
171
+ - Framework: ${p}
172
+ - Route: /${m}
173
+ - App Type: ${j.existsSync(P.join(r,"angular.json"))?"Angular":"Web App"}
174
+ - Base URL: http://localhost:4200
175
+
176
+ Generate a ${p} E2E test spec for the route "/${m}".
177
+ The test should:
178
+ 1. Navigate to the route
179
+ 2. Verify the page loads correctly
180
+ 3. Test key user interactions on this page
181
+ 4. Assert critical UI elements are visible
182
+
183
+ Use @playwright/test imports. Keep it concise and practical.
184
+ `,w=await Z(`e2e/${y}`,v,e,o,p,["e2e"]);j.writeFileSync(h,w,"utf-8"),console.log(`[Lisa.ai E2E] Wrote ${y}`),g++,await I({projectId:i,type:"e2e",filePath:`e2e/${y}`,modelUsed:e,status:"success",details:`Generated E2E spec for route /${m}`})}catch(v){console.error(`[Lisa.ai E2E] LLM failed for /${m}: ${v.message}`),await I({projectId:i,type:"e2e",filePath:`e2e/${y}`,modelUsed:e,status:"error",details:`LLM failed to generate E2E spec: ${v.message}`})}}if(g===0&&l.length===0){console.log("[Lisa.ai E2E] No specs generated. Check LLM connectivity with 'lisa-agent diagnose'.");return}console.log(`
185
+ [Lisa.ai E2E] Running E2E tests: ${t}`);try{let m=(0,re.spawn)(t,{shell:!0,stdio:"inherit",cwd:r});await new Promise((c,y)=>{m.on("close",h=>{h===0?c():y(new Error(`E2E tests exited with code ${h}`))})}),console.log(`
186
+ [Lisa.ai E2E] All E2E tests passed.`)}catch{console.log(`
187
+ [Lisa.ai E2E] Some E2E tests failed. Run 'lisa-agent heal --command "${t}"' to auto-fix.`)}await I({projectId:i,type:"e2e",filePath:"e2e-suite",modelUsed:e,status:"success",details:`E2E generation complete. ${g} new spec(s) generated, ${l.length} existing.`})}var it=require("child_process"),E=k(require("fs")),C=k(require("path"));function Mt(t){let e=C.join(t,"package.json");if(!E.existsSync(e))return"node";let n=JSON.parse(E.readFileSync(e,"utf-8")),s={...n.dependencies||{},...n.devDependencies||{}};return s["@angular/core"]?"angular":s.react?"react":s.vue?"vue":s["@nestjs/core"]?"nestjs":s.express?"express":"node"}function Dt(t,e){let n=[];if(e==="angular"){let s=C.join(t,"src","app");if(!E.existsSync(s))return n;let i=ae(s,/\.(ts)$/).filter(o=>!o.includes(".spec.")&&!o.includes(".test.")&&!o.includes("node_modules"));for(let o of i){let r=E.readFileSync(o,"utf-8");if(r.includes("@Component")&&r.includes("inject(")){let a=C.relative(t,o),u=a.replace(/\.ts$/,".integration.spec.ts");if(E.existsSync(C.join(t,u)))continue;let f=[...r.matchAll(/inject\((\w+)\)/g)].map(l=>l[1]),d=[];for(let l of f){let g=ae(s,new RegExp(`${Nt(l)}\\.ts$`));d.push(...g.map(m=>C.relative(t,m)))}n.push({filePath:a,relatedFiles:d,description:`Angular component+service integration: ${C.basename(o)} injects ${f.join(", ")}`})}}}else if(e==="express"||e==="nestjs"){let s=["src","server","api","routes","controllers"];for(let i of s){let o=C.join(t,i);if(!E.existsSync(o))continue;let r=ae(o,/\.(controller|route|router)\.(ts|js)$/).filter(a=>!a.includes(".spec.")&&!a.includes(".test.")&&!a.includes("node_modules"));for(let a of r){let u=C.relative(t,a),p=u.replace(/\.(ts|js)$/,".integration.spec.$1");E.existsSync(C.join(t,p))||n.push({filePath:u,relatedFiles:[],description:`API endpoint integration test for ${C.basename(a)} \u2014 test with supertest against real middleware chain`})}}}else{let s=C.join(t,"src");if(E.existsSync(s)){let i=ae(s,/\.(ts|js|tsx|jsx)$/).filter(o=>!o.includes(".spec.")&&!o.includes(".test.")&&!o.includes("node_modules"));for(let o of i){let a=[...E.readFileSync(o,"utf-8").matchAll(/from\s+['"]\.\.?\//g)];if(a.length>=2){let u=C.relative(t,o),p=u.replace(/\.(ts|js|tsx|jsx)$/,".integration.spec.$1");if(E.existsSync(C.join(t,p)))continue;n.push({filePath:u,relatedFiles:[],description:`Module integration: ${C.basename(o)} imports ${a.length} local modules`})}}}}return n}function ae(t,e){let n=[],s=["node_modules","dist","build",".git",".angular","coverage"];if(!E.existsSync(t))return n;let i=E.readdirSync(t);for(let o of i){if(s.includes(o))continue;let r=C.join(t,o);try{E.statSync(r).isDirectory()?n.push(...ae(r,e)):e.test(o)&&n.push(r)}catch{continue}}return n}function Nt(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}async function rt(t,e,n=1,s=3,i="local",o){if(n>s){console.log(`
188
+ [Lisa.ai Integration] Reached maximum retries (${s}). Stopping.`);return}let r=process.cwd(),a=F.load(r);a&&(F.applyEnvDefaults(a),!t&&a.testCommand&&(t=a.testCommand,console.log(`[Lisa.ai Config] Using testCommand from .lisai.json: ${t}`)));let u=Mt(r),p=B.scanRepository(),f=a?.testingFramework||(p.testingFramework!=="none"?p.testingFramework:void 0);console.log(`
189
+ [Lisa.ai Integration] App: ${u}, Framework: ${f||"auto"} (Attempt ${n}/${s}) Model: ${e}`),t||(p.suggestedTestCommand?t=p.suggestedTestCommand:E.existsSync(C.join(r,"angular.json"))?t="npx ng test --no-watch --browsers=ChromeHeadless":(console.error(`
190
+ [Lisa.ai Fatal Error] Could not auto-detect a test command. Please pass --command explicitly.`),process.exit(1)),console.log(`[Lisa.ai Integration] Auto-detected command: ${t}`)),await I({projectId:i,type:"integration",filePath:"integration-suite",modelUsed:e,status:"running",details:`Integration test generation started for ${u} app`});let d=Dt(r,u);if(d.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 ${d.length} integration target(s):`),d.forEach(g=>console.log(` - ${g.filePath}: ${g.description}`));let l=0;for(let g of d){let m=C.resolve(r,g.filePath);if(!E.existsSync(m))continue;let c=C.parse(m),y=C.join(c.dir,`${c.name}.integration.spec${c.ext}`);if(E.existsSync(y)){console.log(`[Lisa.ai Integration] Spec exists for ${g.filePath} \u2014 skipping.`);continue}console.log(`[Lisa.ai Integration] Generating integration spec for ${g.filePath}...`);let h=E.readFileSync(m,"utf-8"),v="";for(let $ of g.relatedFiles.slice(0,3)){let x=C.resolve(r,$);if(E.existsSync(x)){let L=E.readFileSync(x,"utf-8");v+=`
191
+
192
+ // --- Related file: ${$} ---
193
+ ${L.slice(0,5e3)}`}}let w=`
194
+ INTEGRATION TEST \u2014 ${g.description}
195
+
196
+ Generate an integration test that exercises real module interactions (NOT mocked).
197
+ ${u==="angular"?`
198
+ - Use TestBed with real service providers (not jasmine.createSpyObj)
199
+ - Import the actual component and its real dependencies
200
+ - Test that the component and service work together correctly
201
+ - Use HttpClientTestingModule for HTTP calls
202
+ `:u==="express"||u==="nestjs"?`
203
+ - Use supertest to make real HTTP requests against the app
204
+ - Test the full middleware chain (auth, validation, handler)
205
+ - Use a test database or in-memory mock for data layer
206
+ `:`
207
+ - Import real modules, not mocks
208
+ - Test that 2+ modules work together correctly
209
+ - Focus on the integration boundary, not individual unit behavior
210
+ `}
211
+
212
+ Source file:
213
+ ${h.slice(0,1e4)}
214
+
215
+ ${v?`Related modules:
216
+ ${v}`:""}
217
+ `;try{let $=await Z(g.filePath,w,e,o,f,["integration"]);E.writeFileSync(y,$,"utf-8"),console.log(`[Lisa.ai Integration] Wrote ${C.relative(r,y)}`),l++,await I({projectId:i,type:"integration",filePath:g.filePath,modelUsed:e,status:"success",details:`Generated integration spec: ${g.description}`})}catch($){console.error(`[Lisa.ai Integration] LLM failed for ${g.filePath}: ${$.message}`)}}if(l===0){console.log("[Lisa.ai Integration] No new integration specs generated.");return}console.log(`
218
+ [Lisa.ai Integration] Running tests to verify generated specs: ${t}`);try{let g=(0,it.spawn)(t,{shell:!0,stdio:"inherit",cwd:r});await new Promise((m,c)=>{g.on("close",y=>{y===0?m():c(new Error(`Tests exited with code ${y}`))})}),console.log(`
219
+ [Lisa.ai Integration] All tests passed including integration specs.`)}catch{console.log(`
220
+ [Lisa.ai Integration] Some tests failed. Run 'lisa-agent heal' to auto-fix.`)}await I({projectId:i,type:"integration",filePath:"integration-suite",modelUsed:e,status:"success",details:`Integration test generation complete. ${l} new spec(s) generated.`})}var ct=k(require("dotenv")),ut=require("child_process"),K=k(require("fs")),Y=k(require("path"));ct.config({quiet:!0});function te(t){return new Promise(e=>{let n=(0,ut.spawn)(t,{shell:!0,stdio:["ignore","pipe","pipe"]}),s="",i="";n.stdout?.on("data",o=>{s+=o.toString()}),n.stderr?.on("data",o=>{i+=o.toString()}),n.on("close",o=>e({stdout:s,stderr:i,code:o??1}))})}function Ot(){return K.existsSync(Y.resolve(process.cwd(),"pnpm-lock.yaml"))?"pnpm":K.existsSync(Y.resolve(process.cwd(),"yarn.lock"))?"yarn":"npm"}var Ut={critical:"\u{1F534}",high:"\u{1F7E0}",moderate:"\u{1F7E1}",low:"\u{1F535}",info:"\u26AA"},at={critical:5,high:4,moderate:3,low:2,info:1};function lt(t){let e=["critical","high","moderate","low","info"];for(let n of e){let s=t[n]??0;s>0&&console.log(` ${Ut[n]} ${n.padEnd(10)} ${s}`)}console.log(` ${"\u2500".repeat(22)}`),console.log(` ${"Total".padEnd(10)} ${t.total}`)}async function Fe(t){try{return JSON.parse(t)}catch{return null}}async function dt(t,e="local",n){K.existsSync(Y.resolve(process.cwd(),"package.json"))||(console.error(`
221
+ \u{1F6A8} [Lisa.ai Audit] No package.json found in ${process.cwd()}.`),console.error(" The audit command currently supports Node.js / npm projects only."),process.exit(1));let s=Ot();console.log(`[Lisa.ai Audit] Package manager: ${s}`),console.log(`
222
+ [Lisa.ai Audit] Scanning for vulnerabilities...`);let{stdout:i,code:o}=await te(s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json");if(o===0){console.log(`
223
+ \u2705 [Lisa.ai Audit] No vulnerabilities found! Repository is clean.`);return}let r=await Fe(i);r||(console.error("[Lisa.ai Audit] Could not parse audit output. Run 'npm audit' manually to investigate."),process.exit(1));let a=r.metadata.vulnerabilities;console.log(`
224
+ Vulnerabilities found:`),lt(a),console.log(`
225
+ [Lisa.ai Audit] Applying safe automatic fixes (npm audit fix)...`);let{stdout:u}=await te(s==="npm"?"npm audit fix":s==="yarn"?"yarn upgrade":"pnpm audit fix");for(let S of u.split(`
226
+ `)){let M=S.trim();M&&!M.startsWith("npm warn")&&!M.startsWith("npm notice")&&console.log(` ${M}`)}let p=s==="npm"?"npm audit --json":s==="yarn"?"yarn audit --json":"pnpm audit --json",{stdout:f,code:d}=await te(p);if(d===0){console.log(`
227
+ \u2705 [Lisa.ai Audit] All vulnerabilities fixed by safe auto-fix!`);return}let l=await Fe(f);if(!l){console.warn("[Lisa.ai Audit] Could not parse post-fix audit output.");return}let g=Object.values(l.vulnerabilities),m=l.metadata.vulnerabilities,c=a.total-m.total;console.log(`
228
+ [Lisa.ai Audit] Safe auto-fix resolved ${c} vulnerability(-ies).`),m.total>0&&(console.log(" Remaining:"),lt(m));let y=g.filter(S=>typeof S.fixAvailable=="object"&&!S.fixAvailable.isSemVerMajor).map(S=>S.fixAvailable),h=[...new Map(y.map(S=>[S.name,S])).values()];if(h.length>0){console.log(`
229
+ [Lisa.ai Audit] Applying ${h.length} non-breaking targeted upgrade(s)...`);for(let z of h){let U=`npm install ${z.name}@${z.version}`;console.log(` \u2192 ${U}`);let{stderr:ne}=await te(U);ne&&!ne.includes("npm warn")&&console.warn(` ${ne.trim()}`)}let{stdout:S,code:M}=await te(p);if(M===0){console.log(`
230
+ \u2705 [Lisa.ai Audit] All vulnerabilities resolved!`);return}}let{stdout:v}=await te(p),w=await Fe(v)??l,x=Object.values(w.vulnerabilities).sort((S,M)=>(at[M.severity]??0)-(at[S.severity]??0)).slice(0,10).filter(S=>S.fixAvailable===!1?!0:typeof S.fixAvailable=="object"?S.fixAvailable.isSemVerMajor:!1);if(x.length===0){console.log(`
160
231
  \u2705 [Lisa.ai Audit] No breaking-change or unfixable vulnerabilities remain.`);return}console.log(`
161
- [Lisa.ai Audit] ${x.length} vulnerability(-ies) require manual attention.`),console.log(`[Lisa.ai Audit] Consulting ${t} for remediation guidance...`);let L={};try{L=JSON.parse(G.readFileSync(U.resolve(process.cwd(),"package.json"),"utf8"))}catch{}let b={...L.dependencies??{},...L.devDependencies??{}},T=x.map($=>{let I=$.fixAvailable,Y=I===!1?"no fix available yet":`upgrade to ${I.name}@${I.version} (BREAKING \u2014 major version bump)`,R=b[$.name]?`current: ${b[$.name]}`:"transitive dependency";return`\u2022 ${$.name} (${$.severity}) \u2014 ${R} \u2014 ${Y}`}).join(`
162
- `),M=`You are a Node.js security expert helping a developer fix npm vulnerabilities.
232
+ [Lisa.ai Audit] ${x.length} vulnerability(-ies) require manual attention.`),console.log(`[Lisa.ai Audit] Consulting ${t} for remediation guidance...`);let L={};try{L=JSON.parse(K.readFileSync(Y.resolve(process.cwd(),"package.json"),"utf8"))}catch{}let b={...L.dependencies??{},...L.devDependencies??{}},O=x.map(S=>{let M=S.fixAvailable,z=M===!1?"no fix available yet":`upgrade to ${M.name}@${M.version} (BREAKING \u2014 major version bump)`,U=b[S.name]?`current: ${b[S.name]}`:"transitive dependency";return`\u2022 ${S.name} (${S.severity}) \u2014 ${U} \u2014 ${z}`}).join(`
233
+ `),H=`You are a Node.js security expert helping a developer fix npm vulnerabilities.
163
234
 
164
235
  These vulnerabilities remain after safe auto-fixes were applied. Each requires either a breaking upgrade or has no automated fix:
165
236
 
166
- ${T}
237
+ ${O}
167
238
 
168
239
  For each vulnerability:
169
240
  1. Briefly explain the security risk (1 sentence).
@@ -171,32 +242,29 @@ For each vulnerability:
171
242
  3. If the upgrade is breaking (major version), note the most likely code change needed (e.g. renamed API, changed import path).
172
243
  4. If no fix exists, suggest a workaround or safe alternative package.
173
244
 
174
- Be concrete. Use numbered items. If a vulnerability is a transitive dependency, explain how to force a resolution override in package.json.`;try{let $=await W(M,t,n);console.log(`
245
+ Be concrete. Use numbered items. If a vulnerability is a transitive dependency, explain how to force a resolution override in package.json.`;try{let S=await J(H,t,n);console.log(`
175
246
  Remediation guidance:
176
- `);for(let R of $.split(`
177
- `))console.log(` ${R}`);let I=U.resolve(process.cwd(),"lisa-audit-report.md"),Y=["# Lisa.ai Security Audit Report","",`Generated: ${new Date().toISOString()}`,`Project: ${L.name??U.basename(process.cwd())}`,"","## Summary","","| Severity | Initial | Remaining |","|----------|---------|-----------|",...["critical","high","moderate","low"].map(R=>{let J=l[R]??0,lt=h.metadata.vulnerabilities[R]??0;return`| ${R} | ${J} | ${lt} |`}),"","## Vulnerabilities Requiring Manual Action","",T,"",`## Remediation Guidance (${t})`,"",$].join(`
178
- `);G.writeFileSync(I,Y,"utf-8"),console.log(`
179
- [Lisa.ai Audit] Full report saved to: lisa-audit-report.md`)}catch($){console.error(`
180
- [Lisa.ai Audit] LLM guidance failed: ${$.message}`),console.log(" Run 'npm audit' manually and address the remaining vulnerabilities.")}let te=h.metadata.vulnerabilities,at=l.total-te.total;console.log(`
181
- ${"\u2500".repeat(50)}`),console.log(" Lisa.ai Audit Complete"),console.log(` \u2705 Fixed: ${at} / ${l.total}`),console.log(` \u26A0\uFE0F Remaining: ${te.total} (see lisa-audit-report.md)`),console.log(`${"\u2500".repeat(50)}
182
- `)}var rt=st();function de(){console.log(`
183
- ======================================================`),console.log(`\u2728 Lisa.ai Agent v${rt.version} Running... `),console.log(" Where pure magic happens! \u{1FA84}"),console.log(`======================================================
184
- `)}var B=new nt.Command;B.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(rt.version);B.command("heal").description("Run a command and autonomously heal errors").option("-c, --command <type>","Command to execute (Optional for Auto-Discovery)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID to fetch dynamic config").action(async t=>{de();let e=5,n=t.model,s;if(t.projectId){let i=await Q(t.projectId);if(!i.ok)i.reason==="not_found"?(console.error(`
185
- \u{1F6A8} [Lisa.ai Agent Error] Project '${t.projectId}' does not exist on the Control Plane. Please create it in the Dashboard first or run locally without a project ID.`),process.exit(1)):console.warn(`
186
- \u26A0\uFE0F [Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${n}, maxRetries=${e}).`);else{let r=i.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${r.modelProvider}, MaxRetries=${r.maxRetries}`),r.maxRetries<5&&console.warn(`
187
- \u26A0\uFE0F [Lisa.ai Warning] Your Dashboard Analytics Config has maxRetries set to ${r.maxRetries}. Consider increasing this to 5+ in the WEB UI for complex Angular Healing!`),n=r.modelProvider,e=r.maxRetries,s=r.apiKey,r.autoHealEnabled===!1&&(console.log("[Lisa.ai Agent] Auto-heal is disabled by Control Plane."),process.exit(1))}}let o=j.load(process.cwd());o&&(j.applyEnvDefaults(o),!t.projectId&&o.maxRetries!==void 0&&(e=o.maxRetries),!t.projectId&&o.provider&&t.model==="gemini"&&(n=o.provider),j.printSummary(o)),await ae(t.command,n,1,null,e,t.projectId||"local",void 0,s)});B.command("coverage").description("Run test command dynamically generating missing specs for 100% coverage").option("-c, --command <type>","Test command to execute (Optional for Auto-Discovery)").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID to fetch dynamic config").action(async t=>{de();let e=5,n=t.model,s;if(t.projectId){let i=await Q(t.projectId);if(!i.ok)i.reason==="not_found"?(console.error(`
188
- \u{1F6A8} [Lisa.ai Agent Error] Project '${t.projectId}' does not exist on the Control Plane. Please create it in the Dashboard first or run locally without a project ID.`),process.exit(1)):console.warn(`
189
- \u26A0\uFE0F [Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${n}, maxRetries=${e}).`);else{let r=i.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${r.modelProvider}, MaxRetries=${r.maxRetries}`),r.maxRetries<5&&console.warn(`
190
- \u26A0\uFE0F [Lisa.ai Warning] Your Dashboard Analytics Config has maxRetries set to ${r.maxRetries}. Consider increasing this to 5+ in the WEB UI for complex Angular Healing!`),n=r.modelProvider,e=r.maxRetries,s=r.apiKey,r.autoHealEnabled===!1&&(console.log("[Lisa.ai Agent] Auto-heal is disabled by Control Plane."),process.exit(1))}}let o=j.load(process.cwd());o&&(j.applyEnvDefaults(o),!t.projectId&&o.maxRetries!==void 0&&(e=o.maxRetries),!t.projectId&&o.provider&&t.model==="gemini"&&(n=o.provider),j.printSummary(o)),await ee(t.command,n,1,e,t.projectId||"local",s)});B.command("diagnose").description("Test LLM connectivity and API key health without running the full agent").option("-m, --model <provider>","LLM provider to test (gemini, claude, openai)","claude").option("-p, --project-id <id>","Control Plane Project ID to fetch API key from").action(async t=>{de();let e=t.model,n;if(t.projectId){let i=await Q(t.projectId);i.ok?(e=i.config.modelProvider,n=i.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${i.reason}. Using local env for API key.`)}let o={claude:process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5",openai:process.env.LISA_OPENAI_MODEL||"gpt-4o-mini",gemini:process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash"}[e]||e;console.log(`
191
- [Lisa.ai Diagnose] Testing ${e} \u2192 model ID: ${o}`);try{let i=await W("Reply with exactly: LISA_OK",e,n);console.log(`
192
- \u2705 [Lisa.ai Diagnose] ${e} is working correctly.`),console.log(` Model response: "${i}"`)}catch(i){console.error(`
193
- \u274C [Lisa.ai Diagnose] ${e} call FAILED.`),console.error(` Error: ${i.message}`),i.cause&&console.error(` Cause: ${i.cause?.message??i.cause}`),console.error(`
194
- Common causes:`),console.error(" \u2022 API key is invalid, expired, or has no credits"),console.error(" \u2022 Model ID is deprecated (current: claude-sonnet-4-6, gemini-2.0-flash, gpt-4o-mini)"),console.error(" \u2022 Rate limit exceeded \u2014 wait a minute and retry"),console.error(" \u2022 Network/proxy issue blocking api.anthropic.com"),process.exit(1)}});B.command("init").description("Interactively create a .lisai.json config file in the current project").option("--force","Overwrite existing .lisai.json if it exists").action(async t=>{let e=ot.resolve(process.cwd(),H);ue.existsSync(e)&&!t.force&&(console.error(`
195
- \u274C [Lisa.ai Init] ${H} already exists. Use --force to overwrite.`),process.exit(1));let n=it.createInterface({input:process.stdin,output:process.stdout}),s=(p,u="")=>new Promise(a=>n.question(u?`${p} [${u}]: `:`${p}: `,m=>a(m.trim()||u)));console.log(`
196
- \u{1F680} Lisa.ai Project Setup \u2014 press Enter to accept the default shown in [ ]
197
- `);let o=await s("LLM provider (gemini / claude / openai)","gemini"),i=await s("Testing framework (jest / vitest / mocha / karma / cypress / playwright \u2014 leave empty to auto-detect)",""),r=await s("Test types to generate (unit / integration / e2e \u2014 comma-separated)","unit"),l=await s("Test command (leave empty for auto-discovery)",""),g=await s("Max heal retries","5");n.close();let d={provider:o,testTypes:r.split(",").map(p=>p.trim()).filter(Boolean),maxRetries:parseInt(g,10)||5,skipFiles:[],skipDirs:[],skipPaths:[]};i&&(d.testingFramework=i),l&&(d.testCommand=l),ue.writeFileSync(e,JSON.stringify(d,null,2)+`
247
+ `);for(let U of S.split(`
248
+ `))console.log(` ${U}`);let M=Y.resolve(process.cwd(),"lisa-audit-report.md"),z=["# Lisa.ai Security Audit Report","",`Generated: ${new Date().toISOString()}`,`Project: ${L.name??Y.basename(process.cwd())}`,"","## Summary","","| Severity | Initial | Remaining |","|----------|---------|-----------|",...["critical","high","moderate","low"].map(U=>{let ne=a[U]??0,vt=w.metadata.vulnerabilities[U]??0;return`| ${U} | ${ne} | ${vt} |`}),"","## Vulnerabilities Requiring Manual Action","",O,"",`## Remediation Guidance (${t})`,"",S].join(`
249
+ `);K.writeFileSync(M,z,"utf-8"),console.log(`
250
+ [Lisa.ai Audit] Full report saved to: lisa-audit-report.md`)}catch(S){console.error(`
251
+ [Lisa.ai Audit] LLM guidance failed: ${S.message}`),console.log(" Run 'npm audit' manually and address the remaining vulnerabilities.")}let le=w.metadata.vulnerabilities,yt=a.total-le.total;console.log(`
252
+ ${"\u2500".repeat(50)}`),console.log(" Lisa.ai Audit Complete"),console.log(` \u2705 Fixed: ${yt} / ${a.total}`),console.log(` \u26A0\uFE0F Remaining: ${le.total} (see lisa-audit-report.md)`),console.log(`${"\u2500".repeat(50)}
253
+ `)}var ht=pt();function se(){console.log(`
254
+ ======================================================`),console.log(` Lisa.ai Agent v${ht.version}`),console.log(" Autonomous CI/CD Platform Worker"),console.log(`======================================================
255
+ `)}async function we(t){let e=5,n=t.model,s;if(t.projectId){let o=await ce(t.projectId);if(!o.ok)o.reason==="not_found"?(console.error(`
256
+ [Lisa.ai Agent Error] Project '${t.projectId}' does not exist on the Control Plane. Please create it in the Dashboard first or run locally without a project ID.`),process.exit(1)):console.warn(`
257
+ [Lisa.ai Warning] Control Plane is unreachable. Continuing with local CLI defaults (model=${n}, maxRetries=${e}).`);else{let r=o.config;console.log(`[Lisa.ai Agent] Dynamic Config Loaded: Provider=${r.modelProvider}, MaxRetries=${r.maxRetries}`),r.maxRetries<5&&console.warn(`
258
+ [Lisa.ai Warning] maxRetries is ${r.maxRetries}. Consider increasing to 5+ for complex projects.`),n=r.modelProvider,e=r.maxRetries,s=r.apiKey,r.agentEnabled===!1&&(console.log("[Lisa.ai Agent] Agent is disabled by Control Plane for this project."),process.exit(1))}}let i=F.load(process.cwd());return i&&(F.applyEnvDefaults(i),!t.projectId&&i.maxRetries!==void 0&&(e=i.maxRetries),!t.projectId&&i.provider&&t.model==="gemini"&&(n=i.provider),F.printSummary(i)),{model:n,maxRetries:e,apiKey:s,projectId:t.projectId||"local"}}var W=new gt.Command;W.name("lisa-agent").description("Lisa.ai - Autonomous CI/CD Platform Worker Agent").version(ht.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").action(async t=>{se();let e=await we(t);await me(t.command,e.model,1,null,e.maxRetries,e.projectId,void 0,e.apiKey)});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").action(async t=>{se();let e=await we(t);await ie(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});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").action(async t=>{se();let e=await we(t);await ot(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});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").action(async t=>{se();let e=await we(t);await rt(t.command,e.model,1,e.maxRetries,e.projectId,e.apiKey)});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 t=>{se();let e=t.model,n;if(t.projectId){let o=await ce(t.projectId);o.ok?(e=o.config.modelProvider,n=o.config.apiKey,console.log(`[Lisa.ai Diagnose] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Diagnose] Control Plane ${o.reason}. Using local env for API key.`)}let i={claude:process.env.LISA_CLAUDE_MODEL||"claude-haiku-4-5",openai:process.env.LISA_OPENAI_MODEL||"gpt-4o-mini",gemini:process.env.LISA_GOOGLE_MODEL||"gemini-2.0-flash"}[e]||e;console.log(`
259
+ [Lisa.ai Diagnose] Testing ${e} \u2192 model ID: ${i}`);try{let o=await J("Reply with exactly: LISA_OK",e,n);console.log(`
260
+ [Lisa.ai Diagnose] ${e} is working correctly.`),console.log(` Model response: "${o}"`)}catch(o){console.error(`
261
+ [Lisa.ai Diagnose] ${e} call FAILED.`),console.error(` Error: ${o.message}`),o.cause&&console.error(` Cause: ${o.cause?.message??o.cause}`),console.error(`
262
+ 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 t=>{let e=ft.resolve(process.cwd(),V);ve.existsSync(e)&&!t.force&&(console.error(`
263
+ [Lisa.ai Init] ${V} already exists. Use --force to overwrite.`),process.exit(1));let n=mt.createInterface({input:process.stdin,output:process.stdout}),s=(l,g="")=>new Promise(m=>n.question(g?`${l} [${g}]: `:`${l}: `,c=>m(c.trim()||g)));console.log(`
264
+ Lisa.ai Project Setup \u2014 press Enter to accept the default shown in [ ]
265
+ `);let i=await s("LLM provider (gemini / claude / openai)","gemini"),o=await s("Testing framework (jest / vitest / mocha / karma / jasmine \u2014 leave empty to auto-detect)",""),r=await s("E2E framework (playwright / cypress \u2014 leave empty for Playwright default)",""),a=await s("Test types to generate (unit / integration / e2e \u2014 comma-separated)","unit"),u=await s("Test command (leave empty for auto-discovery)",""),p=await s("E2E command (leave empty for auto-discovery)",""),f=await s("Max heal retries","5");n.close();let d={provider:i,testTypes:a.split(",").map(l=>l.trim()).filter(Boolean),maxRetries:parseInt(f,10)||5,skipFiles:[],skipDirs:[],skipPaths:[]};o&&(d.testingFramework=o),r&&(d.e2eFramework=r),u&&(d.testCommand=u),p&&(d.e2eCommand=p),ve.writeFileSync(e,JSON.stringify(d,null,2)+`
198
266
  `,"utf-8"),console.log(`
199
- \u2705 Created ${H}:
267
+ Created ${V}:
200
268
  `),console.log(JSON.stringify(d,null,2)),console.log(`
201
- Tip: add "model" to pin a specific model ID (e.g. "claude-sonnet-4-6").`),console.log(` Edit skipFiles / skipDirs / skipPaths to exclude files from coverage analysis.
202
- `)});B.command("audit").description("Scan for npm vulnerabilities and auto-fix where safe; consult LLM for manual fixes").option("-m, --model <provider>","LLM provider to use (gemini, claude, openai)","gemini").option("-p, --project-id <id>","Control Plane Project ID").action(async t=>{de();let e=t.model,n;if(t.projectId){let s=await Q(t.projectId);s.ok?(e=s.config.modelProvider,n=s.config.apiKey,console.log(`[Lisa.ai Audit] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Audit] Control Plane ${s.reason}. Using local env for API key.`)}await tt(e,t.projectId||"local",n)});B.parse(process.argv);
269
+ Tip: add "model" to pin a specific model ID (e.g. "claude-sonnet-4-6").`),console.log(` Edit skipFiles / skipDirs / skipPaths to exclude files from test analysis.
270
+ `)});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 t=>{se();let e=t.model,n;if(t.projectId){let s=await ce(t.projectId);s.ok?(e=s.config.modelProvider,n=s.config.apiKey,console.log(`[Lisa.ai Audit] Config fetched from Control Plane. Provider=${e}`)):console.warn(`[Lisa.ai Audit] Control Plane ${s.reason}. Using local env for API key.`)}await dt(e,t.projectId||"local",n)});W.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lisa.ai/agent",
3
- "version": "2.6.5",
3
+ "version": "2.7.0",
4
4
  "description": "Lisa.ai Autonomous CI/CD Worker Agent",
5
5
  "main": "dist/index.js",
6
6
  "bin": {