@principal-ai/quality-lens-cli 0.1.33 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +1 -1
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -790,7 +790,7 @@ Additional information: BADCLIENT: Bad error code, ${A} not found in range ${u}.
790
790
  `)[0].substring(0,150);return`Test "${c}" failed: ${S}`}getEmptyResults(){return{numFailedTestSuites:0,numFailedTests:0,numPassedTestSuites:0,numPassedTests:0,numPendingTestSuites:0,numPendingTests:0,numRuntimeErrorTestSuites:0,numTodoTests:0,numTotalTestSuites:0,numTotalTests:0,openHandles:[],snapshot:{added:0,didUpdate:!1,failure:!1,filesAdded:0,filesRemoved:0,filesRemovedList:[],filesUnmatched:0,filesUpdated:0,matched:0,total:0,unchecked:0,uncheckedKeysByFile:[],unmatched:0,updated:0},startTime:Date.now(),success:!0,testResults:[],wasInterrupted:!1}}normalizeResults(c){let f=this.getEmptyResults(),g=c;return{...f,...g,testResults:(g.testResults||[]).map(S=>({...S,assertionResults:S.assertionResults||[],perfStats:S.perfStats||{}}))}}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new plr.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(g=>g==="--json")||this.addArgsToNpmScript(["--json"]),c.some(g=>g.includes("--no-colors")||g.includes("--colors=false"))||this.addArgsToNpmScript(["--no-colors"])}return super.execute()}};Ioe.JestLens=$ke});var K_t=jt(YR=>{"use strict";Object.defineProperty(YR,"__esModule",{value:!0});YR.KnipLens=YR.SOURCE_EXTENSIONS=void 0;var dlr=wk(),mlr=Pk();YR.SOURCE_EXTENSIONS=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]);var Hke=class _ extends dlr.BaseLens{name="knip";description="Find unused files, exports, and dependencies";languages=["javascript","typescript"];supportedTools=["knip"];pathMapper;injectedSourceFiles;constructor(c,f={}){super(c,f),this.injectedSourceFiles=f.sourceFiles}static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f?.custom)return 100;let g=f.custom,S=(g.unlistedDependencies||0)*15,I=(g.unresolvedImports||0)*10,J=(g.unusedFiles||0)*5,re=(g.unusedDependencies||0)*2,fe=(g.unusedDevDependencies||0)*1,ve=(g.unusedExports||0)*1,Ce=(g.unusedTypes||0)*.5,we=S+I+J+re+fe+ve+Ce,X=Math.max(0,Math.min(100,100-we));return Math.round(X*100)/100}parse(c){let f=c.stderr||c.stdout;if(!f)return this.getEmptyOutput();try{let g=JSON.parse(f);return this.normalizeOutput(g)}catch(g){this.debug("Failed to parse Knip output as JSON, trying to extract from npm wrapper:",g);let S=f.split(`
791
791
  `);for(let I of S){let J=I.trim();if(J.startsWith("{"))try{let re=JSON.parse(J);return this.debug("Successfully extracted JSON from npm wrapper output"),this.normalizeOutput(re)}catch{this.debug("Line started with { but was not valid JSON:",J.substring(0,50));continue}}if(c.stderr&&!c.stderr.trim().startsWith("{"))throw new Error(`Knip execution error: ${c.stderr}`);return this.debug("No valid JSON found in output, returning empty results"),this.getEmptyOutput()}}format(c){let f=[],g=this.getPathMapper();for(let[X,at]of Object.entries(c.files||{})){let Ue=g.toRelative(X);f.push({file:Ue,line:1,column:1,severity:"warning",message:`Unused file: ${at.join(", ")||"file not referenced"}`,rule:"unused-file",source:this.name,category:"files"})}for(let[X,at]of c.dependencies||[])f.push({file:g.toRelative(X+"/package.json"),line:1,column:1,severity:"warning",message:`Unused dependency: ${at}`,rule:"unused-dependency",source:this.name,category:"dependencies"});for(let[X,at]of c.devDependencies||[])f.push({file:g.toRelative(X+"/package.json"),line:1,column:1,severity:"info",message:`Unused devDependency: ${at}`,rule:"unused-devDependency",source:this.name,category:"dependencies"});for(let[X,at]of Object.entries(c.unlisted||{})){let Ue=g.toRelative(X);for(let Ve of at)f.push({file:Ue,line:1,column:1,severity:"error",message:`Unlisted dependency: ${Ve}`,rule:"unlisted-dependency",source:this.name,category:"dependencies"})}for(let[X,at]of Object.entries(c.unresolved||{})){let Ue=g.toRelative(X);for(let Ve of at)f.push({file:Ue,line:1,column:1,severity:"error",message:`Unresolved import: ${Ve}`,rule:"unresolved-import",source:this.name,category:"imports"})}for(let[X,at]of Object.entries(c.exports||{})){let Ue=g.toRelative(X);for(let Ve of at){let{line:wt,col:$t,name:Pr}=this.parseExportInfo(Ve);f.push({file:Ue,line:wt||1,column:$t||1,severity:"warning",message:`Unused export: ${Pr}`,rule:"unused-export",source:this.name,category:"exports"})}}for(let[X,at]of Object.entries(c.nsExports||{})){let Ue=g.toRelative(X);for(let Ve of at){let{line:wt,col:$t,name:Pr}=this.parseExportInfo(Ve);f.push({file:Ue,line:wt||1,column:$t||1,severity:"warning",message:`Unused namespace export: ${Pr}`,rule:"unused-ns-export",source:this.name,category:"exports"})}}for(let[X,at]of Object.entries(c.types||{})){let Ue=g.toRelative(X);for(let Ve of at){let{line:wt,col:$t,name:Pr}=this.parseExportInfo(Ve);f.push({file:Ue,line:wt||1,column:$t||1,severity:"info",message:`Unused type: ${Pr}`,rule:"unused-type",source:this.name,category:"types"})}}for(let[X,at]of Object.entries(c.classMembers||{})){let Ue=g.toRelative(X);for(let Ve of at){let{line:wt,col:$t,name:Pr}=this.parseExportInfo(Ve);f.push({file:Ue,line:wt||1,column:$t||1,severity:"info",message:`Unused class member: ${Pr}`,rule:"unused-class-member",source:this.name,category:"class-members"})}}for(let[X,at]of Object.entries(c.enumMembers||{})){let Ue=g.toRelative(X);for(let Ve of at){let{line:wt,col:$t,name:Pr}=this.parseExportInfo(Ve);f.push({file:Ue,line:wt||1,column:$t||1,severity:"info",message:`Unused enum member: ${Pr}`,rule:"unused-enum-member",source:this.name,category:"enum-members"})}}for(let[X,at]of Object.entries(c.duplicates||{})){let Ue=g.toRelative(X);for(let[Ve,wt]of at)f.push({file:Ue,line:1,column:1,severity:"warning",message:`Duplicate export: ${wt} (original: ${Ve})`,rule:"duplicate-export",source:this.name,category:"duplicates"})}let S=this.findAllSourceFiles(),I=new Set([...Object.keys(c.files||{}),...Object.keys(c.exports||{}),...Object.keys(c.nsExports||{}),...Object.keys(c.types||{}),...Object.keys(c.nsTypes||{}),...Object.keys(c.classMembers||{}),...Object.keys(c.enumMembers||{}),...Object.keys(c.unlisted||{}),...Object.keys(c.unresolved||{}),...Object.keys(c.duplicates||{})].map(X=>g.toRelative(X))),J=[...new Set([...S,...I])],re=J.length,fe={error:f.filter(X=>X.severity==="error").length,warning:f.filter(X=>X.severity==="warning").length,info:f.filter(X=>X.severity==="info").length,hint:f.filter(X=>X.severity==="hint").length},ve={};for(let X of f){let at=X.category||"uncategorized";ve[at]=(ve[at]||0)+1}let Ce=this.buildFileMetrics(J,f),we={lensName:this.name,tool:this.config?.tool.name||"knip",timestamp:Date.now(),success:!0,issues:f,fileMetrics:Ce,metrics:{filesAnalyzed:re,totalIssues:f.length,issuesBySeverity:fe,executionTime:0,custom:{unusedFiles:Object.keys(c.files||{}).length,unusedDependencies:(c.dependencies||[]).length,unusedDevDependencies:(c.devDependencies||[]).length,unlistedDependencies:Object.values(c.unlisted||{}).flat().length,unresolvedImports:Object.values(c.unresolved||{}).flat().length,unusedExports:Object.values(c.exports||{}).flat().length,unusedTypes:Object.values(c.types||{}).flat().length,issuesByCategory:ve}}};return we.qualityScore=_.calculateQualityScore(we),we}parseExportInfo(c){let f=c.match(/^(.+?)\s*\((\d+):(\d+)\)$/);return f?{name:f[1].trim(),line:parseInt(f[2],10),col:parseInt(f[3],10)}:{name:c}}getEmptyOutput(){return{files:{},dependencies:[],devDependencies:[],optionalPeerDependencies:[],unlisted:{},binaries:{},unresolved:{},exports:{},nsExports:{},classMembers:{},types:{},nsTypes:{},enumMembers:{},duplicates:{}}}isV5Format(c){let f=Array.isArray(c.files),g=Array.isArray(c.issues);return f||g}convertV5ToV4(c){let f=this.getEmptyOutput();if(c.files&&Array.isArray(c.files))for(let g of c.files)f.files[g]=[];if(c.issues&&Array.isArray(c.issues))for(let g of c.issues){let{file:S}=g;if(g.dependencies&&Array.isArray(g.dependencies))for(let I of g.dependencies)f.dependencies.push(["",I]);if(g.devDependencies&&Array.isArray(g.devDependencies))for(let I of g.devDependencies)f.devDependencies.push(["",I]);if(g.optionalPeerDependencies&&Array.isArray(g.optionalPeerDependencies))for(let I of g.optionalPeerDependencies)f.optionalPeerDependencies.push(["",I]);if(g.unlisted&&Array.isArray(g.unlisted)&&(f.unlisted[S]||(f.unlisted[S]=[]),f.unlisted[S].push(...g.unlisted)),g.binaries&&Array.isArray(g.binaries)&&(f.binaries[S]||(f.binaries[S]=[]),f.binaries[S].push(...g.binaries)),g.unresolved&&Array.isArray(g.unresolved)&&(f.unresolved[S]||(f.unresolved[S]=[]),f.unresolved[S].push(...g.unresolved)),g.exports&&Array.isArray(g.exports)){f.exports[S]||(f.exports[S]=[]);for(let I of g.exports)f.exports[S].push(`${I.name} (${I.line}:${I.col})`)}if(g.nsExports&&Array.isArray(g.nsExports)){f.nsExports[S]||(f.nsExports[S]=[]);for(let I of g.nsExports)f.nsExports[S].push(`${I.name} (${I.line}:${I.col})`)}if(g.types&&Array.isArray(g.types)){f.types[S]||(f.types[S]=[]);for(let I of g.types)f.types[S].push(`${I.name} (${I.line}:${I.col})`)}if(g.nsTypes&&Array.isArray(g.nsTypes)){f.nsTypes[S]||(f.nsTypes[S]=[]);for(let I of g.nsTypes)f.nsTypes[S].push(`${I.name} (${I.line}:${I.col})`)}if(g.classMembers&&Array.isArray(g.classMembers)){f.classMembers[S]||(f.classMembers[S]=[]);for(let I of g.classMembers)f.classMembers[S].push(`${I.name} (${I.line}:${I.col})`)}if(g.enumMembers&&Array.isArray(g.enumMembers)){f.enumMembers[S]||(f.enumMembers[S]=[]);for(let I of g.enumMembers)f.enumMembers[S].push(`${I.name} (${I.line}:${I.col})`)}if(g.duplicates&&Array.isArray(g.duplicates)){f.duplicates[S]||(f.duplicates[S]=[]);for(let I of g.duplicates)f.duplicates[S].push([I.name,I.name])}}return f}normalizeOutput(c){return this.isV5Format(c)?(this.debug("Detected Knip v5+ format, converting to v4 format"),this.convertV5ToV4(c)):{...this.getEmptyOutput(),...c}}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new mlr.PathMapper(c)}return this.pathMapper}findAllSourceFiles(){return this.injectedSourceFiles?this.injectedSourceFiles:(this.debug("No source files injected, file metrics will only include files with issues"),[])}async execute(){return this.config?.tool&&((this.config.tool.args||[]).some(g=>g.includes("--reporter")||g==="-r")||this.addArgsToNpmScript(["--reporter","json"])),super.execute()}};YR.KnipLens=Hke});var Q_t=jt(woe=>{"use strict";Object.defineProperty(woe,"__esModule",{value:!0});woe.PrettierLens=void 0;var hlr=wk(),glr=Pk(),Kke=class _ extends hlr.BaseLens{name="prettier";description="Code formatter";languages=["javascript","typescript","json","css","html","markdown"];supportedTools=["prettier"];pathMapper;static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f)return 100;let g=Math.max(f.filesAnalyzed,1),S=f.issuesBySeverity.error;if(S===0)return 100;let I=Math.max(0,100-S/g*100);return Math.round(I*100)/100}parse(c){let f=[],g=[],S=c.stderr||c.stdout||"";if(!S)return{filesNeedingFormatting:f,filesChecked:0,analyzedFilePaths:g};let I=S.split(`
792
792
  `).map(fe=>fe.trim()).filter(Boolean),J=/^\[debug\] resolve config from ["'](.+?)["']$/;for(let fe of I){let ve=fe.match(J);if(ve){g.push(ve[1]);continue}if(fe.startsWith("Checking formatting...")||fe.startsWith("All matched files")||fe.startsWith("Code style issues found")||fe.startsWith("Code style issues")||fe.includes("prettier --write")||fe.startsWith(">")||fe.startsWith("$")||fe.startsWith("[debug]")||fe.match(/^(npm|yarn|pnpm|bun)\s+/)||fe==="")continue;let Ce=fe.replace(/^\[warn\]\s*/,"");Ce&&!Ce.match(/^\d+.*files?.*checked/i)&&!Ce.match(/Code style issues/)&&f.push(Ce)}let re=g.length;if(re===0){let fe=S.match(/Code style issues found in (\d+) file/i);if(fe){let we=parseInt(fe[1],10);we===f.length&&(re=we)}let Ce=(c.stderr||"").match(/Checked (\d+) files/i)||S.match(/Checked (\d+) files/i);Ce&&(re=parseInt(Ce[1],10))}return{filesNeedingFormatting:f,filesChecked:re,analyzedFilePaths:g}}format(c){let f=[],g=[],S=this.getPathMapper(),I=c.analyzedFilePaths.map(Ce=>S.toRelative(Ce)),J=new Set(c.filesNeedingFormatting.map(Ce=>S.toRelative(Ce)));for(let Ce of I){let we=J.has(Ce);g.push({path:Ce,hasIssues:we})}for(let Ce of c.filesNeedingFormatting){let we=S.toRelative(Ce);f.push({file:we,line:1,column:1,severity:"error",message:"File is not formatted according to Prettier rules",rule:"prettier",source:this.name,category:"formatting"})}let re=c.filesChecked||c.filesNeedingFormatting.length,fe=this.buildFileMetrics(I,f),ve={lensName:this.name,tool:this.config?.tool.name||"prettier",timestamp:Date.now(),success:!0,issues:f,analyzedFiles:g,fileMetrics:fe,metrics:{filesAnalyzed:re,totalIssues:f.length,issuesBySeverity:{error:f.length,warning:0,info:0,hint:0},executionTime:0,custom:{filesNeedingFormatting:c.filesNeedingFormatting.length,formattingCompliance:re>0?Math.round((1-c.filesNeedingFormatting.length/re)*100*100)/100:100}}};return ve.qualityScore=_.calculateQualityScore(ve),ve}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new glr.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(I=>I==="--check"||I==="-c")||this.addArgsToNpmScript(["--check"]),c.some(I=>I==="--no-error-on-unmatched-pattern")||this.addArgsToNpmScript(["--no-error-on-unmatched-pattern"]),c.some(I=>I.startsWith("--log-level"))||this.addArgsToNpmScript(["--log-level","debug"])}return super.execute()}};woe.PrettierLens=Kke});var X_t=jt(ZR=>{"use strict";Object.defineProperty(ZR,"__esModule",{value:!0});ZR.TypeScriptLens=ZR.TS_SOURCE_EXTENSIONS=void 0;var ylr=wk(),vlr=Pk();ZR.TS_SOURCE_EXTENSIONS=new Set([".ts",".tsx",".js",".jsx",".mts",".mjs",".cts",".cjs"]);var I2;(function(_){_[_.Warning=0]="Warning",_[_.Error=1]="Error",_[_.Suggestion=2]="Suggestion",_[_.Message=3]="Message"})(I2||(I2={}));var Qke=class _ extends ylr.BaseLens{name="typescript";description="TypeScript type checking";languages=["typescript","javascript"];supportedTools=["tsc","typescript"];pathMapper;injectedSourceFiles;constructor(c,f={}){super(c,f),this.injectedSourceFiles=f.sourceFiles}static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f)return 100;let g=Math.max(f.custom?.filesWithErrors||f.filesAnalyzed,1),{error:S,warning:I,info:J}=f.issuesBySeverity;if(S===0&&I===0&&J===0)return 100;let re=S/g*8,fe=I/g*2,ve=J/g*.5,Ce=re+fe+ve,we=Math.max(0,Math.min(100,100-Ce));return Math.round(we*100)/100}parse(c){let f=[],g=[];if(c.stdout){let ve=c.stdout.split(`
793
- `).filter(Ce=>Ce.trim().length>0);for(let Ce of ve){let we=Ce.trim();(we.endsWith(".ts")||we.endsWith(".tsx"))&&!we.includes("/node_modules/")&&g.push(we)}}let S=g.length,I=c.stderr||"";if(!I)return{errors:f,filesAnalyzed:S,analyzedFilePaths:g};let J=/^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm,re;for(;(re=J.exec(I))!==null;){let[,ve,Ce,we,X,at,Ue]=re;f.push({file:ve,line:parseInt(Ce,10),column:parseInt(we,10),code:at,message:Ue,category:X==="error"?I2.Error:I2.Warning})}let fe=/^([^:]+):(\d+):(\d+)\s+-\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm;for(;(re=fe.exec(I))!==null;){let[,ve,Ce,we,X,at,Ue]=re;f.some(wt=>wt.file===ve&&wt.line===parseInt(Ce,10)&&wt.column===parseInt(we,10)&&wt.code===at)||f.push({file:ve,line:parseInt(Ce,10),column:parseInt(we,10),code:at,message:Ue,category:X==="error"?I2.Error:I2.Warning})}return{errors:f,filesAnalyzed:S,analyzedFilePaths:g}}format(c){let f=[],g=this.getPathMapper(),S;c.analyzedFilePaths.length>0?S=c.analyzedFilePaths.map(Ue=>g.toRelative(Ue)):S=this.findAllSourceFiles();for(let Ue of c.errors){let Ve=g.toRelative(Ue.file);f.push({file:Ve,line:Ue.line,column:Ue.column,severity:this.mapTSSeverity(Ue.category),message:Ue.message,rule:Ue.code,source:this.name,category:this.categorizeError(Ue.code)})}let I=new Set(c.errors.map(Ue=>Ue.file)).size,J=c.errors.filter(Ue=>Ue.category===I2.Error).length,re=c.errors.filter(Ue=>Ue.category===I2.Warning).length,fe=c.errors.filter(Ue=>Ue.category===I2.Suggestion).length,ve={};for(let Ue of c.errors)ve[Ue.code]=(ve[Ue.code]||0)+1;let Ce=Object.entries(ve).sort((Ue,Ve)=>Ve[1]-Ue[1]).slice(0,5),we=this.buildFileMetrics(S,f),X=S.length,at={lensName:this.name,tool:this.config?.tool.name||"tsc",timestamp:Date.now(),success:!0,issues:f,fileMetrics:we,metrics:{filesAnalyzed:X,totalIssues:f.length,issuesBySeverity:{error:J,warning:re,info:fe,hint:0},executionTime:0,custom:{filesWithErrors:I,totalErrors:J,totalWarnings:re,totalSuggestions:fe,uniqueErrorCodes:Object.keys(ve).length,topErrors:Ce.map(([Ue,Ve])=>({code:Ue,count:Ve}))}}};return at.qualityScore=_.calculateQualityScore(at),at}mapTSSeverity(c){switch(c){case I2.Error:return"error";case I2.Warning:return"warning";case I2.Suggestion:return"info";case I2.Message:default:return"info"}}categorizeError(c){switch(c){case"TS2307":case"TS2304":case"TS2552":return"resolution";case"TS2322":case"TS2345":case"TS2769":return"type-mismatch";case"TS2339":case"TS2551":return"property-access";case"TS7006":case"TS7031":return"implicit-any"}let f=parseInt(c.replace("TS",""),10);return f>=1e3&&f<2e3?"syntax":f>=2e3&&f<3e3?"semantic":f>=3e3&&f<4e3?"declaration":f>=4e3&&f<5e3?"signature":f>=5e3&&f<6e3?"jsx":f>=6e3&&f<7e3?"messages":f>=7e3&&f<8e3?"noImplicitAny":f>=8e3&&f<9e3?"decorators":f>=17e3&&f<18e3?"jsx-attributes":f>=18e3&&f<19e3?"async":"general"}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new vlr.PathMapper(c)}return this.pathMapper}findAllSourceFiles(){return this.injectedSourceFiles?this.injectedSourceFiles:(this.debug("No source files injected, file metrics will only include files from tsc output"),[])}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];!c.some(g=>g==="--noEmit")&&!c.some(g=>g==="--build"||g==="-b")&&this.addArgsToNpmScript(["--noEmit"]),c.some(g=>g.includes("--pretty"))||this.addArgsToNpmScript(["--pretty","false"]),c.some(g=>g==="--listFiles")||this.addArgsToNpmScript(["--listFiles"])}return super.execute()}};ZR.TypeScriptLens=Qke});var Y_t=jt(Poe=>{"use strict";Object.defineProperty(Poe,"__esModule",{value:!0});Poe.GitLens=void 0;var Dlr=wk(),blr=Pk(),Xke=class _ extends Dlr.BaseLens{name="git";description="Version control insights from Git";languages=["*"];supportedTools=["git"];pathMapper;includeCommitDetails=!1;static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f?.custom)return 100;let g=f.custom;if(!g.hasUncommittedChanges)return 100;let S=(g.modified||0)*2,I=(g.deleted||0)*2,J=(g.untracked||0)*1,re=S+I+J,fe=Math.max(0,Math.min(100,100-re));return Math.round(fe*100)/100}configure(c){super.configure(c),this.includeCommitDetails=c.includeCommitDetails??!1}async execute(){if(!this.config)throw new Error(`Lens ${this.name} is not configured`);if(!this.executor)throw new Error(`Lens ${this.name} has no executor`);let c=this.config.tool.cwd||this.config.cwd,f=this.config.tool.command||"git",g={},S=[];try{let I=await this.executor.execute(f,["rev-parse","--abbrev-ref","HEAD"],{cwd:c});I.error?(this.debug("Branch command error:",I.error),S.push("branch retrieval failed")):I.exitCode===0?g.branch=I.stdout.trim():(this.debug("Branch command failed with exit code:",I.exitCode),S.push("branch retrieval failed"))}catch(I){this.debug("Failed to get branch:",I),S.push("branch retrieval failed")}try{let I=await this.executor.execute(f,["rev-parse","HEAD"],{cwd:c});I.error?(this.debug("Commit command error:",I.error),S.push("commit retrieval failed")):I.exitCode===0?g.commit=I.stdout.trim():(this.debug("Commit command failed with exit code:",I.exitCode),S.push("commit retrieval failed"))}catch(I){this.debug("Failed to get commit:",I),S.push("commit retrieval failed")}try{let I=await this.executor.execute(f,["status","--porcelain"],{cwd:c});if(I.error)throw new Error(`Git command not found or failed to execute: ${I.error.message}`);if(I.exitCode===0)g.status=I.stdout;else throw new Error(`Git status failed with exit code ${I.exitCode}: ${I.stderr}`)}catch(I){throw this.debug("Failed to get status:",I),S.push("status retrieval failed"),new Error(`Git status failed: ${I}`)}if(this.includeCommitDetails&&g.commit)try{let I=await this.executor.execute(f,["log","-1",'--format="%H|%h|%an|%ae|%ad|%B"',"--date=iso"],{cwd:c});I.exitCode===0&&(g.commitDetails=I.stdout.trim());let J=await this.executor.execute(f,["show","--stat","--format=","HEAD"],{cwd:c});J.exitCode===0&&(g.commitStats=J.stdout.trim())}catch(I){this.debug("Failed to get commit details:",I)}return{stdout:JSON.stringify(g),stderr:S.join(`
793
+ `).filter(Ce=>Ce.trim().length>0);for(let Ce of ve){let we=Ce.trim();(we.endsWith(".ts")||we.endsWith(".tsx"))&&!we.includes("/node_modules/")&&g.push(we)}}let S=g.length,I=c.stderr||"";if(!I)return{errors:f,filesAnalyzed:S,analyzedFilePaths:g};let J=/^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm,re;for(;(re=J.exec(I))!==null;){let[,ve,Ce,we,X,at,Ue]=re;f.push({file:ve,line:parseInt(Ce,10),column:parseInt(we,10),code:at,message:Ue,category:X==="error"?I2.Error:I2.Warning})}let fe=/^([^:]+):(\d+):(\d+)\s+-\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm;for(;(re=fe.exec(I))!==null;){let[,ve,Ce,we,X,at,Ue]=re;f.some(wt=>wt.file===ve&&wt.line===parseInt(Ce,10)&&wt.column===parseInt(we,10)&&wt.code===at)||f.push({file:ve,line:parseInt(Ce,10),column:parseInt(we,10),code:at,message:Ue,category:X==="error"?I2.Error:I2.Warning})}return{errors:f,filesAnalyzed:S,analyzedFilePaths:g}}format(c){let f=[],g=this.getPathMapper(),S;if(c.analyzedFilePaths.length>0)S=c.analyzedFilePaths.map(Ue=>g.toRelative(Ue));else if(S=this.findAllSourceFiles(),S.length===0&&c.errors.length>0){let Ue=[...new Set(c.errors.map(Ve=>g.toRelative(Ve.file)))];S=Ue,this.debug(`Using ${Ue.length} files extracted from errors as fallback`)}for(let Ue of c.errors){let Ve=g.toRelative(Ue.file);f.push({file:Ve,line:Ue.line,column:Ue.column,severity:this.mapTSSeverity(Ue.category),message:Ue.message,rule:Ue.code,source:this.name,category:this.categorizeError(Ue.code)})}let I=new Set(c.errors.map(Ue=>Ue.file)).size,J=c.errors.filter(Ue=>Ue.category===I2.Error).length,re=c.errors.filter(Ue=>Ue.category===I2.Warning).length,fe=c.errors.filter(Ue=>Ue.category===I2.Suggestion).length,ve={};for(let Ue of c.errors)ve[Ue.code]=(ve[Ue.code]||0)+1;let Ce=Object.entries(ve).sort((Ue,Ve)=>Ve[1]-Ue[1]).slice(0,5),we=this.buildFileMetrics(S,f),X=S.length,at={lensName:this.name,tool:this.config?.tool.name||"tsc",timestamp:Date.now(),success:!0,issues:f,fileMetrics:we,metrics:{filesAnalyzed:X,totalIssues:f.length,issuesBySeverity:{error:J,warning:re,info:fe,hint:0},executionTime:0,custom:{filesWithErrors:I,totalErrors:J,totalWarnings:re,totalSuggestions:fe,uniqueErrorCodes:Object.keys(ve).length,topErrors:Ce.map(([Ue,Ve])=>({code:Ue,count:Ve}))}}};return at.qualityScore=_.calculateQualityScore(at),at}mapTSSeverity(c){switch(c){case I2.Error:return"error";case I2.Warning:return"warning";case I2.Suggestion:return"info";case I2.Message:default:return"info"}}categorizeError(c){switch(c){case"TS2307":case"TS2304":case"TS2552":return"resolution";case"TS2322":case"TS2345":case"TS2769":return"type-mismatch";case"TS2339":case"TS2551":return"property-access";case"TS7006":case"TS7031":return"implicit-any"}let f=parseInt(c.replace("TS",""),10);return f>=1e3&&f<2e3?"syntax":f>=2e3&&f<3e3?"semantic":f>=3e3&&f<4e3?"declaration":f>=4e3&&f<5e3?"signature":f>=5e3&&f<6e3?"jsx":f>=6e3&&f<7e3?"messages":f>=7e3&&f<8e3?"noImplicitAny":f>=8e3&&f<9e3?"decorators":f>=17e3&&f<18e3?"jsx-attributes":f>=18e3&&f<19e3?"async":"general"}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new vlr.PathMapper(c)}return this.pathMapper}findAllSourceFiles(){return this.injectedSourceFiles&&this.injectedSourceFiles.length>0?this.injectedSourceFiles:(this.debug("No source files injected, file metrics will only include files from tsc output"),[])}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];!c.some(g=>g==="--noEmit")&&!c.some(g=>g==="--build"||g==="-b")&&this.addArgsToNpmScript(["--noEmit"]),c.some(g=>g.includes("--pretty"))||this.addArgsToNpmScript(["--pretty","false"]),c.some(g=>g==="--listFiles")||this.addArgsToNpmScript(["--listFiles"])}return super.execute()}};ZR.TypeScriptLens=Qke});var Y_t=jt(Poe=>{"use strict";Object.defineProperty(Poe,"__esModule",{value:!0});Poe.GitLens=void 0;var Dlr=wk(),blr=Pk(),Xke=class _ extends Dlr.BaseLens{name="git";description="Version control insights from Git";languages=["*"];supportedTools=["git"];pathMapper;includeCommitDetails=!1;static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f?.custom)return 100;let g=f.custom;if(!g.hasUncommittedChanges)return 100;let S=(g.modified||0)*2,I=(g.deleted||0)*2,J=(g.untracked||0)*1,re=S+I+J,fe=Math.max(0,Math.min(100,100-re));return Math.round(fe*100)/100}configure(c){super.configure(c),this.includeCommitDetails=c.includeCommitDetails??!1}async execute(){if(!this.config)throw new Error(`Lens ${this.name} is not configured`);if(!this.executor)throw new Error(`Lens ${this.name} has no executor`);let c=this.config.tool.cwd||this.config.cwd,f=this.config.tool.command||"git",g={},S=[];try{let I=await this.executor.execute(f,["rev-parse","--abbrev-ref","HEAD"],{cwd:c});I.error?(this.debug("Branch command error:",I.error),S.push("branch retrieval failed")):I.exitCode===0?g.branch=I.stdout.trim():(this.debug("Branch command failed with exit code:",I.exitCode),S.push("branch retrieval failed"))}catch(I){this.debug("Failed to get branch:",I),S.push("branch retrieval failed")}try{let I=await this.executor.execute(f,["rev-parse","HEAD"],{cwd:c});I.error?(this.debug("Commit command error:",I.error),S.push("commit retrieval failed")):I.exitCode===0?g.commit=I.stdout.trim():(this.debug("Commit command failed with exit code:",I.exitCode),S.push("commit retrieval failed"))}catch(I){this.debug("Failed to get commit:",I),S.push("commit retrieval failed")}try{let I=await this.executor.execute(f,["status","--porcelain"],{cwd:c});if(I.error)throw new Error(`Git command not found or failed to execute: ${I.error.message}`);if(I.exitCode===0)g.status=I.stdout;else throw new Error(`Git status failed with exit code ${I.exitCode}: ${I.stderr}`)}catch(I){throw this.debug("Failed to get status:",I),S.push("status retrieval failed"),new Error(`Git status failed: ${I}`)}if(this.includeCommitDetails&&g.commit)try{let I=await this.executor.execute(f,["log","-1",'--format="%H|%h|%an|%ae|%ad|%B"',"--date=iso"],{cwd:c});I.exitCode===0&&(g.commitDetails=I.stdout.trim());let J=await this.executor.execute(f,["show","--stat","--format=","HEAD"],{cwd:c});J.exitCode===0&&(g.commitStats=J.stdout.trim())}catch(I){this.debug("Failed to get commit details:",I)}return{stdout:JSON.stringify(g),stderr:S.join(`
794
794
  `),exitCode:S.length>0?1:0,duration:0}}parse(c){let f;try{f=JSON.parse(c.stdout)}catch{f={status:c.stdout}}let g=this.parseStatus(f.status||""),S=[],I=[],J=[],re=[],fe=[];for(let Ce of g)Ce.status==="??"&&S.push(Ce.file),(Ce.unstagedStatus==="M"||Ce.stagedStatus==="M")&&I.push(Ce.file),Ce.stagedStatus!==" "&&Ce.stagedStatus!=="?"&&J.push(Ce.file),(Ce.stagedStatus==="D"||Ce.unstagedStatus==="D")&&re.push(Ce.file),Ce.stagedStatus==="R"&&Ce.originalFile&&fe.push({from:Ce.originalFile,to:Ce.file});let ve;if(f.commitDetails){let Ce=f.commitDetails.split("|");if(Ce.length>=6){let we=Ce.slice(5).join("|");if(ve={hash:Ce[0],shortHash:Ce[1],author:Ce[2],authorEmail:Ce[3],date:Ce[4],message:we},f.commitStats){let X=f.commitStats.match(/(\d+)\s+file[s]?\s+changed(?:,\s+(\d+)\s+insertion)?(?:.*,\s+(\d+)\s+deletion)?/);X&&(ve.files=parseInt(X[1],10),ve.insertions=X[2]?parseInt(X[2],10):0,ve.deletions=X[3]?parseInt(X[3],10):0)}}}return{branch:f.branch,commit:f.commit?.substring(0,8),commitDetails:ve,status:g,untracked:S,modified:I,staged:J,deleted:re,renamed:fe}}parseStatus(c){let f=c.split(`
795
795
  `).filter(S=>S.trim()),g=[];for(let S of f){if(S.length<3)continue;let I=S.substring(0,2),J=I[0]||" ",re=I[1]||" ",fe=S.substring(3),ve=fe,Ce;if(J==="R"&&fe.includes(" -> ")){let we=fe.split(" -> ");Ce=we[0],ve=we[1]}g.push({status:I,stagedStatus:J,unstagedStatus:re,file:ve,originalFile:Ce})}return g}format(c){let f=[],g=this.getPathMapper();for(let re of c.untracked)f.push({file:g.toRelative(re),line:1,column:1,severity:"info",message:"Untracked file",source:this.name,category:"vcs"});for(let re of c.modified)c.staged.includes(re)||f.push({file:g.toRelative(re),line:1,column:1,severity:"warning",message:"Modified file with unstaged changes",source:this.name,category:"vcs"});for(let re of c.deleted)f.push({file:g.toRelative(re),line:1,column:1,severity:"warning",message:"Deleted file",source:this.name,category:"vcs"});let S=c.status.length,I=S>0,J={lensName:this.name,tool:this.config?.tool.name||"git",timestamp:Date.now(),success:!0,issues:f,metrics:{filesAnalyzed:c.status.length,totalIssues:f.length,issuesBySeverity:{error:0,warning:c.modified.length+c.deleted.length,info:c.untracked.length,hint:0},executionTime:0,custom:{branch:c.branch||"unknown",commit:c.commit||"unknown",untracked:c.untracked.length,modified:c.modified.length,staged:c.staged.length,deleted:c.deleted.length,renamed:c.renamed.length,hasUncommittedChanges:I?1:0,totalChanges:S,...c.commitDetails&&{commitAuthor:c.commitDetails.author,commitDate:c.commitDetails.date,commitMessage:c.commitDetails.message,commitFiles:c.commitDetails.files||0,commitInsertions:c.commitDetails.insertions||0,commitDeletions:c.commitDetails.deletions||0}}}};return J.qualityScore=_.calculateQualityScore(J),J}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new blr.PathMapper(c)}return this.pathMapper}canHandle(c){return c.name==="git"&&c.available}};Poe.GitLens=Xke});var Z_t=jt(Noe=>{"use strict";Object.defineProperty(Noe,"__esModule",{value:!0});Noe.AlexandriaLens=void 0;var Clr=wk(),Slr=Pk(),Yke=class extends Clr.BaseLens{name="alexandria";description="Documentation coverage metrics";languages=["markdown","documentation"];supportedTools=["alexandria"];pathMapper;parse(c){if(c.stderr&&!c.stdout)throw new Error(`Alexandria execution error: ${c.stderr}`);if(!c.stdout)return{totalFiles:0,coveredFiles:0,coveredFilesList:[],uncoveredFiles:[],coveragePercentage:0,filesByExtension:[]};try{let f=c.stdout,g=f.search(/^\s*[{[]/m);return g>0&&(this.debug("Stripping npm script preamble from output"),f=f.substring(g)),JSON.parse(f)}catch(f){if(this.debug("Failed to parse Alexandria output as JSON:",f),c.stderr)throw new Error(`Alexandria execution error: ${c.stderr}`);return{totalFiles:0,coveredFiles:0,coveredFilesList:[],uncoveredFiles:[],coveragePercentage:0,filesByExtension:[]}}}format(c){let f=[],g=[],S=this.getPathMapper(),I=[];for(let fe of c.coveredFilesList||[]){let ve=S.toRelative(fe);I.push(ve),g.push({path:ve,hasIssues:!1})}for(let fe of c.uncoveredFiles||[]){let ve=S.toRelative(fe);I.push(ve),g.push({path:ve,hasIssues:!0}),f.push({file:ve,line:1,column:void 0,severity:"info",message:"File is not covered by any Alexandria codebase view",rule:"coverage",source:this.name,category:"documentation-coverage"})}let J=this.buildFileMetrics(I,f);return{lensName:this.name,tool:this.config?.tool.name||"alexandria",timestamp:Date.now(),success:!0,issues:f,analyzedFiles:g,fileMetrics:J,metrics:{filesAnalyzed:c.totalFiles||0,totalIssues:f.length,issuesBySeverity:{error:0,warning:0,info:f.length,hint:0},executionTime:0,custom:{totalFiles:c.totalFiles||0,coveredFiles:c.coveredFiles||0,uncoveredFiles:c.uncoveredFiles?.length||0,coveragePercentage:c.coveragePercentage||0}},qualityScore:Math.round((c.coveragePercentage||0)*100)/100}}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new Slr.PathMapper(c)}return this.pathMapper}async execute(){this.config?.tool&&((this.config.tool.args||[]).includes("--json")||this.addArgsToNpmScript(["--json"]));try{return await super.execute()}catch(c){let f=c instanceof Error?c.message:String(c);if(f.includes("command not found")||f.includes("ENOENT")||f.includes("not found"))return{stdout:"",stderr:"Alexandria CLI not installed",exitCode:-1,duration:0,error:new Error("Alexandria CLI not installed. Install with: npm install -g @principal-ai/alexandria-cli")};throw c}}};Noe.AlexandriaLens=Yke});var ept=jt(Ooe=>{"use strict";Object.defineProperty(Ooe,"__esModule",{value:!0});Ooe.NodeExecutor=void 0;var Zke=require("child_process"),e6e=class{type="node";async execute(c,f=[],g={}){let S=Date.now();return new Promise(I=>{let{cwd:J=process.cwd(),env:re=process.env,timeout:fe=12e4,maxBuffer:ve=10*1024*1024,encoding:Ce="utf8",shell:we=!1}=g,X="",at="",Ue=!1,Ve,wt=(0,Zke.spawn)(c,f,{cwd:J,env:re,shell:we});fe>0&&(Ve=setTimeout(()=>{Ue=!0,wt.kill("SIGTERM"),setTimeout(()=>{wt.killed||wt.kill("SIGKILL")},5e3)},fe)),wt.stdout?.on("data",$t=>{let Pr=$t.toString(Ce);X.length+Pr.length<=ve&&(X+=Pr)}),wt.stderr?.on("data",$t=>{let Pr=$t.toString(Ce);at.length+Pr.length<=ve&&(at+=Pr)}),wt.on("close",$t=>{Ve&&clearTimeout(Ve);let Pr=Date.now()-S;I({stdout:X,stderr:at,exitCode:$t??-1,duration:Pr,timedOut:Ue,command:c,args:f})}),wt.on("error",$t=>{Ve&&clearTimeout(Ve);let Pr=Date.now()-S;I({stdout:X,stderr:at,exitCode:-1,duration:Pr,error:$t,command:c,args:f})})})}stream(c,f=[],g={}){let{cwd:S=process.cwd(),env:I=process.env,timeout:J=12e4,shell:re=!1,onStdout:fe,onStderr:ve}=g,Ce=Date.now(),we=!1,X,at=(0,Zke.spawn)(c,f,{cwd:S,env:I,shell:re});J>0&&(X=setTimeout(()=>{we=!0,at.kill("SIGTERM"),setTimeout(()=>{at.killed||at.kill("SIGKILL")},5e3)},J)),fe&&at.stdout&&at.stdout.on("data",Ve=>{fe(Ve.toString())}),ve&&at.stderr&&at.stderr.on("data",Ve=>{ve(Ve.toString())});let Ue=new Promise(Ve=>{let wt="",$t="";at.stdout?.on("data",Pr=>{wt+=Pr.toString()}),at.stderr?.on("data",Pr=>{$t+=Pr.toString()}),at.on("close",Pr=>{X&&clearTimeout(X),Ve({stdout:wt,stderr:$t,exitCode:Pr??-1,duration:Date.now()-Ce,timedOut:we,command:c,args:f})}),at.on("error",Pr=>{X&&clearTimeout(X),Ve({stdout:wt,stderr:$t,exitCode:-1,duration:Date.now()-Ce,error:Pr,command:c,args:f})})});return{stdout:at.stdout,stderr:at.stderr,exitPromise:Ue,kill:()=>{at.kill()}}}async isAvailable(c){try{let f=process.platform==="win32"?"where":"which";return new Promise(g=>{(0,Zke.exec)(`${f} ${c}`,S=>{g(!S)})})}catch{return!1}}async kill(c){try{process.kill(Number(c),"SIGTERM"),await new Promise(f=>setTimeout(f,1e3));try{process.kill(Number(c),0),process.kill(Number(c),"SIGKILL")}catch{}}catch(f){if(f instanceof Error&&"code"in f&&f.code!=="ESRCH")throw f}}};Ooe.NodeExecutor=e6e});var rpt=jt(Loe=>{"use strict";Object.defineProperty(Loe,"__esModule",{value:!0});Loe.MockExecutor=void 0;var tpt=require("stream"),t6e=class{type="mock";responses=new Map;sequentialResponses=new Map;callCounts=new Map;defaultResponse={stdout:"",stderr:"",exitCode:0,duration:10};setResponse(c,f){this.responses.set(c,f)}setMockResponse(c,f,g){if(g!==void 0){this.sequentialResponses.has(c)||this.sequentialResponses.set(c,[]);let S=this.sequentialResponses.get(c);for(;S.length<=g;)S.push(this.defaultResponse);S[g]=f}else this.setResponse(c,f)}setDefaultResponse(c){this.defaultResponse={...this.defaultResponse,...c}}clear(){this.responses.clear(),this.sequentialResponses.clear(),this.callCounts.clear()}async execute(c,f=[],g={}){await new Promise(I=>setTimeout(I,10));let S;if(this.sequentialResponses.has(c)){let I=this.callCounts.get(c)||0;S=this.sequentialResponses.get(c)[I]||this.defaultResponse,this.callCounts.set(c,I+1)}else S=this.responses.get(c)||this.defaultResponse;return S.error?{stdout:S.stdout||"",stderr:S.stderr||S.error.message,exitCode:S.exitCode??-1,duration:S.duration||10,error:S.error,command:c,args:f}:{stdout:S.stdout||"",stderr:S.stderr||"",exitCode:S.exitCode??0,duration:S.duration||10,command:c,args:f}}stream(c,f=[],g={}){let S=this.responses.get(c)||this.defaultResponse,I=new tpt.Readable({read(){this.push(S.stdout||""),this.push(null)}}),J=new tpt.Readable({read(){this.push(S.stderr||""),this.push(null)}});g.onStdout&&S.stdout&&setTimeout(()=>g.onStdout(S.stdout),10),g.onStderr&&S.stderr&&setTimeout(()=>g.onStderr(S.stderr),10);let re=new Promise(fe=>{setTimeout(()=>{fe({stdout:S.stdout||"",stderr:S.stderr||"",exitCode:S.exitCode??0,duration:S.duration||10,command:c,args:f})},S.duration||10)});return{stdout:I,stderr:J,exitPromise:re,kill:()=>{}}}async isAvailable(c){return!0}async kill(c){}setupCommonTools(){this.setResponse("eslint",{stdout:JSON.stringify([{filePath:"src/index.js",messages:[{ruleId:"no-unused-vars",severity:2,message:"'unused' is defined but never used.",line:10,column:7,nodeType:"Identifier"}],errorCount:1,warningCount:0}]),stderr:"",exitCode:1}),this.setResponse("tsc",{stdout:"",stderr:"src/index.ts(5,10): error TS2339: Property 'foo' does not exist on type 'Bar'.",exitCode:1}),this.setResponse("jest",{stdout:JSON.stringify({success:!1,numFailedTests:1,numPassedTests:5,numPendingTests:0,testResults:[{name:"src/utils.test.ts",status:"failed",message:"Expected value to be 5, received 4"}]}),stderr:"",exitCode:1}),this.setResponse("git",{stdout:`On branch main
796
796
  Changes not staged for commit:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/quality-lens-cli",
3
- "version": "0.1.33",
3
+ "version": "0.1.34",
4
4
  "description": "CLI tool for running quality lenses on codebases in CI/CD pipelines",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -43,7 +43,7 @@
43
43
  "license": "MIT",
44
44
  "devDependencies": {
45
45
  "@principal-ai/codebase-composition": "^0.2.9",
46
- "@principal-ai/codebase-quality-lenses": "^0.1.29",
46
+ "@principal-ai/codebase-quality-lenses": "^0.1.30",
47
47
  "@principal-ai/repository-abstraction": "^0.2.0",
48
48
  "@types/jest": "^30.0.0",
49
49
  "@types/node": "^20.0.0",