@principal-ai/quality-lens-cli 0.1.29 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -789,7 +789,7 @@ Additional information: BADCLIENT: Bad error code, ${A} not found in range ${u}.
|
|
|
789
789
|
`)[0];return g.length>200?g.substring(0,197)+"...":g}formatTestFailureMessage(c,f){let S=f.replace(/\u001b\[[0-9;]*m/g,"").split(`
|
|
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 clr.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()}};Eoe.JestLens=zke});var W_t=jt(xoe=>{"use strict";Object.defineProperty(xoe,"__esModule",{value:!0});xoe.KnipLens=void 0;var ulr=require("node:fs"),Wke=require("node:path"),llr=Ik(),flr=wk(),_lr=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),plr=new Set(["node_modules",".git","dist","build","coverage",".next",".nuxt","out",".turbo",".cache"]),Uke=class _ extends llr.BaseLens{name="knip";description="Find unused files, exports, and dependencies";languages=["javascript","typescript"];supportedTools=["knip"];pathMapper;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,w=(g.unresolvedImports||0)*10,J=(g.unusedFiles||0)*5,re=(g.unusedDependencies||0)*2,_e=(g.unusedDevDependencies||0)*1,be=(g.unusedExports||0)*1,Ee=(g.unusedTypes||0)*.5,Ne=S+w+J+re+_e+be+Ee,Y=Math.max(0,Math.min(100,100-Ne));return Math.round(Y*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 w of S){let J=w.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[Y,st]of Object.entries(c.files||{})){let Ve=g.toRelative(Y);f.push({file:Ve,line:1,column:1,severity:"warning",message:`Unused file: ${st.join(", ")||"file not referenced"}`,rule:"unused-file",source:this.name,category:"files"})}for(let[Y,st]of c.dependencies||[])f.push({file:g.toRelative(Y+"/package.json"),line:1,column:1,severity:"warning",message:`Unused dependency: ${st}`,rule:"unused-dependency",source:this.name,category:"dependencies"});for(let[Y,st]of c.devDependencies||[])f.push({file:g.toRelative(Y+"/package.json"),line:1,column:1,severity:"info",message:`Unused devDependency: ${st}`,rule:"unused-devDependency",source:this.name,category:"dependencies"});for(let[Y,st]of Object.entries(c.unlisted||{})){let Ve=g.toRelative(Y);for(let We of st)f.push({file:Ve,line:1,column:1,severity:"error",message:`Unlisted dependency: ${We}`,rule:"unlisted-dependency",source:this.name,category:"dependencies"})}for(let[Y,st]of Object.entries(c.unresolved||{})){let Ve=g.toRelative(Y);for(let We of st)f.push({file:Ve,line:1,column:1,severity:"error",message:`Unresolved import: ${We}`,rule:"unresolved-import",source:this.name,category:"imports"})}for(let[Y,st]of Object.entries(c.exports||{})){let Ve=g.toRelative(Y);for(let We of st){let{line:kt,col:sr,name:Br}=this.parseExportInfo(We);f.push({file:Ve,line:kt||1,column:sr||1,severity:"warning",message:`Unused export: ${Br}`,rule:"unused-export",source:this.name,category:"exports"})}}for(let[Y,st]of Object.entries(c.nsExports||{})){let Ve=g.toRelative(Y);for(let We of st){let{line:kt,col:sr,name:Br}=this.parseExportInfo(We);f.push({file:Ve,line:kt||1,column:sr||1,severity:"warning",message:`Unused namespace export: ${Br}`,rule:"unused-ns-export",source:this.name,category:"exports"})}}for(let[Y,st]of Object.entries(c.types||{})){let Ve=g.toRelative(Y);for(let We of st){let{line:kt,col:sr,name:Br}=this.parseExportInfo(We);f.push({file:Ve,line:kt||1,column:sr||1,severity:"info",message:`Unused type: ${Br}`,rule:"unused-type",source:this.name,category:"types"})}}for(let[Y,st]of Object.entries(c.classMembers||{})){let Ve=g.toRelative(Y);for(let We of st){let{line:kt,col:sr,name:Br}=this.parseExportInfo(We);f.push({file:Ve,line:kt||1,column:sr||1,severity:"info",message:`Unused class member: ${Br}`,rule:"unused-class-member",source:this.name,category:"class-members"})}}for(let[Y,st]of Object.entries(c.enumMembers||{})){let Ve=g.toRelative(Y);for(let We of st){let{line:kt,col:sr,name:Br}=this.parseExportInfo(We);f.push({file:Ve,line:kt||1,column:sr||1,severity:"info",message:`Unused enum member: ${Br}`,rule:"unused-enum-member",source:this.name,category:"enum-members"})}}for(let[Y,st]of Object.entries(c.duplicates||{})){let Ve=g.toRelative(Y);for(let[We,kt]of st)f.push({file:Ve,line:1,column:1,severity:"warning",message:`Duplicate export: ${kt} (original: ${We})`,rule:"duplicate-export",source:this.name,category:"duplicates"})}let S=this.findAllSourceFiles(),w=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(Y=>g.toRelative(Y))),J=[...new Set([...S,...w])],re=J.length,_e={error:f.filter(Y=>Y.severity==="error").length,warning:f.filter(Y=>Y.severity==="warning").length,info:f.filter(Y=>Y.severity==="info").length,hint:f.filter(Y=>Y.severity==="hint").length},be={};for(let Y of f){let st=Y.category||"uncategorized";be[st]=(be[st]||0)+1}let Ee=this.buildFileMetrics(J,f),Ne={lensName:this.name,tool:this.config?.tool.name||"knip",timestamp:Date.now(),success:!0,issues:f,fileMetrics:Ee,metrics:{filesAnalyzed:re,totalIssues:f.length,issuesBySeverity:_e,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:be}}};return Ne.qualityScore=_.calculateQualityScore(Ne),Ne}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 w of g.dependencies)f.dependencies.push(["",w]);if(g.devDependencies&&Array.isArray(g.devDependencies))for(let w of g.devDependencies)f.devDependencies.push(["",w]);if(g.optionalPeerDependencies&&Array.isArray(g.optionalPeerDependencies))for(let w of g.optionalPeerDependencies)f.optionalPeerDependencies.push(["",w]);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 w of g.exports)f.exports[S].push(`${w.name} (${w.line}:${w.col})`)}if(g.nsExports&&Array.isArray(g.nsExports)){f.nsExports[S]||(f.nsExports[S]=[]);for(let w of g.nsExports)f.nsExports[S].push(`${w.name} (${w.line}:${w.col})`)}if(g.types&&Array.isArray(g.types)){f.types[S]||(f.types[S]=[]);for(let w of g.types)f.types[S].push(`${w.name} (${w.line}:${w.col})`)}if(g.nsTypes&&Array.isArray(g.nsTypes)){f.nsTypes[S]||(f.nsTypes[S]=[]);for(let w of g.nsTypes)f.nsTypes[S].push(`${w.name} (${w.line}:${w.col})`)}if(g.classMembers&&Array.isArray(g.classMembers)){f.classMembers[S]||(f.classMembers[S]=[]);for(let w of g.classMembers)f.classMembers[S].push(`${w.name} (${w.line}:${w.col})`)}if(g.enumMembers&&Array.isArray(g.enumMembers)){f.enumMembers[S]||(f.enumMembers[S]=[]);for(let w of g.enumMembers)f.enumMembers[S].push(`${w.name} (${w.line}:${w.col})`)}if(g.duplicates&&Array.isArray(g.duplicates)){f.duplicates[S]||(f.duplicates[S]=[]);for(let w of g.duplicates)f.duplicates[S].push([w.name,w.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 flr.PathMapper(c)}return this.pathMapper}findAllSourceFiles(){let c=this.config?.cwd||process.cwd(),f=[],g=S=>{try{let w=(0,ulr.readdirSync)(S,{withFileTypes:!0});for(let J of w){let re=(0,Wke.join)(S,J.name);if(J.isDirectory())!plr.has(J.name)&&!J.name.startsWith(".")&&g(re);else if(J.isFile()){let _e=(0,Wke.extname)(J.name);_lr.has(_e)&&f.push((0,Wke.relative)(c,re))}}}catch(w){this.debug(`Failed to read directory ${S}:`,w)}};return g(c),f}async execute(){return this.config?.tool&&((this.config.tool.args||[]).some(g=>g.includes("--reporter")||g==="-r")||this.addArgsToNpmScript(["--reporter","json"])),super.execute()}};xoe.KnipLens=Uke});var U_t=jt(Toe=>{"use strict";Object.defineProperty(Toe,"__esModule",{value:!0});Toe.PrettierLens=void 0;var dlr=Ik(),mlr=wk(),Vke=class _ extends dlr.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 w=Math.max(0,100-S/g*100);return Math.round(w*100)/100}parse(c){let f=[],g=[],S=c.stderr||c.stdout||"";if(!S)return{filesNeedingFormatting:f,filesChecked:0,analyzedFilePaths:g};let w=S.split(`
|
|
792
|
-
`).map(_e=>_e.trim()).filter(Boolean),J=/^\[debug\] resolve config from ["'](.+?)["']$/;for(let _e of w){let be=_e.match(J);if(be){g.push(be[1]);continue}if(_e.startsWith("Checking formatting...")||_e.startsWith("All matched files")||_e.startsWith("Code style issues found")||_e.startsWith("Code style issues")||_e.includes("prettier --write")||_e.startsWith(">")||_e.startsWith("$")||_e.startsWith("[debug]")||_e.match(/^(npm|yarn|pnpm|bun)\s+/)||_e==="")continue;let Ee=_e.replace(/^\[warn\]\s*/,"");Ee&&!Ee.match(/^\d+.*files?.*checked/i)&&!Ee.match(/Code style issues/)&&f.push(Ee)}let re=g.length;if(re===0){let _e=S.match(/Code style issues found in (\d+) file/i);if(_e){let Ne=parseInt(_e[1],10);Ne===f.length&&(re=Ne)}let Ee=(c.stderr||"").match(/Checked (\d+) files/i)||S.match(/Checked (\d+) files/i);Ee&&(re=parseInt(Ee[1],10))}return{filesNeedingFormatting:f,filesChecked:re,analyzedFilePaths:g}}format(c){let f=[],g=[],S=this.getPathMapper(),w=c.analyzedFilePaths.map(Ee=>S.toRelative(Ee)),J=new Set(c.filesNeedingFormatting.map(Ee=>S.toRelative(Ee)));for(let Ee of w){let Ne=J.has(Ee);g.push({path:Ee,hasIssues:Ne})}for(let Ee of c.filesNeedingFormatting){let Ne=S.toRelative(Ee);f.push({file:Ne,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,_e=this.buildFileMetrics(w,f),be={lensName:this.name,tool:this.config?.tool.name||"prettier",timestamp:Date.now(),success:!0,issues:f,analyzedFiles:g,fileMetrics:_e,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 be.qualityScore=_.calculateQualityScore(be),be}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new mlr.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(w=>w==="--check"||w==="-c")||this.addArgsToNpmScript(["--check"]),c.some(w=>w==="--no-error-on-unmatched-pattern")||this.addArgsToNpmScript(["--no-error-on-unmatched-pattern"]),c.some(w=>w.startsWith("--log-level"))||this.addArgsToNpmScript(["--log-level","debug"])}return super.execute()}};Toe.PrettierLens=Vke});var V_t=jt(Aoe=>{"use strict";Object.defineProperty(Aoe,"__esModule",{value:!0});Aoe.TypeScriptLens=void 0;var hlr=Ik(),glr=wk(),I2;(function(_){_[_.Warning=0]="Warning",_[_.Error=1]="Error",_[_.Suggestion=2]="Suggestion",_[_.Message=3]="Message"})(I2||(I2={}));var Gke=class _ extends hlr.BaseLens{name="typescript";description="TypeScript type checking";languages=["typescript","javascript"];supportedTools=["tsc","typescript"];pathMapper;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:w,info:J}=f.issuesBySeverity;if(S===0&&w===0&&J===0)return 100;let re=S/g*8,_e=w/g*2,be=J/g*.5,Ee=re+_e+be,Ne=Math.max(0,Math.min(100,100-Ee));return Math.round(Ne*100)/100}parse(c){let f=[],g=[];if(c.stdout){let be=c.stdout.split(`
|
|
792
|
+
`).map(_e=>_e.trim()).filter(Boolean),J=/^\[debug\] resolve config from ["'](.+?)["']$/;for(let _e of w){let be=_e.match(J);if(be){g.push(be[1]);continue}if(_e.startsWith("Checking formatting...")||_e.startsWith("All matched files")||_e.startsWith("Code style issues found")||_e.startsWith("Code style issues")||_e.includes("prettier --write")||_e.startsWith(">")||_e.startsWith("$")||_e.startsWith("[debug]")||_e.match(/^(npm|yarn|pnpm|bun)\s+/)||_e==="")continue;let Ee=_e.replace(/^\[warn\]\s*/,"");Ee&&!Ee.match(/^\d+.*files?.*checked/i)&&!Ee.match(/Code style issues/)&&f.push(Ee)}let re=g.length;if(re===0){let _e=S.match(/Code style issues found in (\d+) file/i);if(_e){let Ne=parseInt(_e[1],10);Ne===f.length&&(re=Ne)}let Ee=(c.stderr||"").match(/Checked (\d+) files/i)||S.match(/Checked (\d+) files/i);Ee&&(re=parseInt(Ee[1],10))}return{filesNeedingFormatting:f,filesChecked:re,analyzedFilePaths:g}}format(c){let f=[],g=[],S=this.getPathMapper(),w=c.analyzedFilePaths.map(Ee=>S.toRelative(Ee)),J=new Set(c.filesNeedingFormatting.map(Ee=>S.toRelative(Ee)));for(let Ee of w){let Ne=J.has(Ee);g.push({path:Ee,hasIssues:Ne})}for(let Ee of c.filesNeedingFormatting){let Ne=S.toRelative(Ee);f.push({file:Ne,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,_e=this.buildFileMetrics(w,f),be={lensName:this.name,tool:this.config?.tool.name||"prettier",timestamp:Date.now(),success:!0,issues:f,analyzedFiles:g,fileMetrics:_e,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 be.qualityScore=_.calculateQualityScore(be),be}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new mlr.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(w=>w==="--check"||w==="-c")||this.addArgsToNpmScript(["--check"]),c.some(w=>w==="--no-error-on-unmatched-pattern")||this.addArgsToNpmScript(["--no-error-on-unmatched-pattern"]),c.some(w=>w.startsWith("--log-level"))||this.addArgsToNpmScript(["--log-level","debug"])}return super.execute()}};Toe.PrettierLens=Vke});var V_t=jt(Aoe=>{"use strict";Object.defineProperty(Aoe,"__esModule",{value:!0});Aoe.TypeScriptLens=void 0;var hlr=Ik(),glr=wk(),I2;(function(_){_[_.Warning=0]="Warning",_[_.Error=1]="Error",_[_.Suggestion=2]="Suggestion",_[_.Message=3]="Message"})(I2||(I2={}));var Gke=class _ extends hlr.BaseLens{name="typescript";description="TypeScript type checking";languages=["typescript","javascript"];supportedTools=["tsc","typescript"];pathMapper;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:w,info:J}=f.issuesBySeverity;if(S===0&&w===0&&J===0)return 100;let re=S/g*8,_e=w/g*2,be=J/g*.5,Ee=re+_e+be,Ne=Math.max(0,Math.min(100,100-Ee));return Math.round(Ne*100)/100}parse(c){let f=[],g=[];if(process.env.DEBUG_TYPESCRIPT_LENS&&(console.log(`[TypeScriptLens] stdout length: ${c.stdout?.length||0}`),console.log(`[TypeScriptLens] stdout preview: ${c.stdout?.slice(0,500)}`),console.log(`[TypeScriptLens] stderr length: ${c.stderr?.length||0}`)),c.stdout){let be=c.stdout.split(`
|
|
793
793
|
`).filter(Ee=>Ee.trim().length>0);for(let Ee of be){let Ne=Ee.trim();(Ne.endsWith(".ts")||Ne.endsWith(".tsx"))&&!Ne.includes("/node_modules/")&&g.push(Ne)}}let S=g.length,w=c.stderr||"";if(!w)return{errors:f,filesAnalyzed:S,analyzedFilePaths:g};let J=/^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm,re;for(;(re=J.exec(w))!==null;){let[,be,Ee,Ne,Y,st,Ve]=re;f.push({file:be,line:parseInt(Ee,10),column:parseInt(Ne,10),code:st,message:Ve,category:Y==="error"?I2.Error:I2.Warning})}let _e=/^([^:]+):(\d+):(\d+)\s+-\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm;for(;(re=_e.exec(w))!==null;){let[,be,Ee,Ne,Y,st,Ve]=re;f.some(kt=>kt.file===be&&kt.line===parseInt(Ee,10)&&kt.column===parseInt(Ne,10)&&kt.code===st)||f.push({file:be,line:parseInt(Ee,10),column:parseInt(Ne,10),code:st,message:Ve,category:Y==="error"?I2.Error:I2.Warning})}return{errors:f,filesAnalyzed:S,analyzedFilePaths:g}}format(c){let f=[],g=this.getPathMapper(),S=c.analyzedFilePaths.map(st=>g.toRelative(st));for(let st of c.errors){let Ve=g.toRelative(st.file);f.push({file:Ve,line:st.line,column:st.column,severity:this.mapTSSeverity(st.category),message:st.message,rule:st.code,source:this.name,category:this.categorizeError(st.code)})}let w=new Set(c.errors.map(st=>st.file)).size,J=c.errors.filter(st=>st.category===I2.Error).length,re=c.errors.filter(st=>st.category===I2.Warning).length,_e=c.errors.filter(st=>st.category===I2.Suggestion).length,be={};for(let st of c.errors)be[st.code]=(be[st.code]||0)+1;let Ee=Object.entries(be).sort((st,Ve)=>Ve[1]-st[1]).slice(0,5),Ne=this.buildFileMetrics(S,f),Y={lensName:this.name,tool:this.config?.tool.name||"tsc",timestamp:Date.now(),success:!0,issues:f,fileMetrics:Ne,metrics:{filesAnalyzed:c.filesAnalyzed,totalIssues:f.length,issuesBySeverity:{error:J,warning:re,info:_e,hint:0},executionTime:0,custom:{filesWithErrors:w,totalErrors:J,totalWarnings:re,totalSuggestions:_e,uniqueErrorCodes:Object.keys(be).length,topErrors:Ee.map(([st,Ve])=>({code:st,count:Ve}))}}};return Y.qualityScore=_.calculateQualityScore(Y),Y}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 glr.PathMapper(c)}return this.pathMapper}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()}};Aoe.TypeScriptLens=Gke});var G_t=jt(Foe=>{"use strict";Object.defineProperty(Foe,"__esModule",{value:!0});Foe.GitLens=void 0;var ylr=Ik(),vlr=wk(),$ke=class _ extends ylr.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,w=(g.deleted||0)*2,J=(g.untracked||0)*1,re=S+w+J,_e=Math.max(0,Math.min(100,100-re));return Math.round(_e*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 w=await this.executor.execute(f,["rev-parse","--abbrev-ref","HEAD"],{cwd:c});w.error?(this.debug("Branch command error:",w.error),S.push("branch retrieval failed")):w.exitCode===0?g.branch=w.stdout.trim():(this.debug("Branch command failed with exit code:",w.exitCode),S.push("branch retrieval failed"))}catch(w){this.debug("Failed to get branch:",w),S.push("branch retrieval failed")}try{let w=await this.executor.execute(f,["rev-parse","HEAD"],{cwd:c});w.error?(this.debug("Commit command error:",w.error),S.push("commit retrieval failed")):w.exitCode===0?g.commit=w.stdout.trim():(this.debug("Commit command failed with exit code:",w.exitCode),S.push("commit retrieval failed"))}catch(w){this.debug("Failed to get commit:",w),S.push("commit retrieval failed")}try{let w=await this.executor.execute(f,["status","--porcelain"],{cwd:c});if(w.error)throw new Error(`Git command not found or failed to execute: ${w.error.message}`);if(w.exitCode===0)g.status=w.stdout;else throw new Error(`Git status failed with exit code ${w.exitCode}: ${w.stderr}`)}catch(w){throw this.debug("Failed to get status:",w),S.push("status retrieval failed"),new Error(`Git status failed: ${w}`)}if(this.includeCommitDetails&&g.commit)try{let w=await this.executor.execute(f,["log","-1",'--format="%H|%h|%an|%ae|%ad|%B"',"--date=iso"],{cwd:c});w.exitCode===0&&(g.commitDetails=w.stdout.trim());let J=await this.executor.execute(f,["show","--stat","--format=","HEAD"],{cwd:c});J.exitCode===0&&(g.commitStats=J.stdout.trim())}catch(w){this.debug("Failed to get commit details:",w)}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=[],w=[],J=[],re=[],_e=[];for(let Ee of g)Ee.status==="??"&&S.push(Ee.file),(Ee.unstagedStatus==="M"||Ee.stagedStatus==="M")&&w.push(Ee.file),Ee.stagedStatus!==" "&&Ee.stagedStatus!=="?"&&J.push(Ee.file),(Ee.stagedStatus==="D"||Ee.unstagedStatus==="D")&&re.push(Ee.file),Ee.stagedStatus==="R"&&Ee.originalFile&&_e.push({from:Ee.originalFile,to:Ee.file});let be;if(f.commitDetails){let Ee=f.commitDetails.split("|");if(Ee.length>=6){let Ne=Ee.slice(5).join("|");if(be={hash:Ee[0],shortHash:Ee[1],author:Ee[2],authorEmail:Ee[3],date:Ee[4],message:Ne},f.commitStats){let Y=f.commitStats.match(/(\d+)\s+file[s]?\s+changed(?:,\s+(\d+)\s+insertion)?(?:.*,\s+(\d+)\s+deletion)?/);Y&&(be.files=parseInt(Y[1],10),be.insertions=Y[2]?parseInt(Y[2],10):0,be.deletions=Y[3]?parseInt(Y[3],10):0)}}}return{branch:f.branch,commit:f.commit?.substring(0,8),commitDetails:be,status:g,untracked:S,modified:w,staged:J,deleted:re,renamed:_e}}parseStatus(c){let f=c.split(`
|
|
795
795
|
`).filter(S=>S.trim()),g=[];for(let S of f){if(S.length<3)continue;let w=S.substring(0,2),J=w[0]||" ",re=w[1]||" ",_e=S.substring(3),be=_e,Ee;if(J==="R"&&_e.includes(" -> ")){let Ne=_e.split(" -> ");Ee=Ne[0],be=Ne[1]}g.push({status:w,stagedStatus:J,unstagedStatus:re,file:be,originalFile:Ee})}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,w=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:w?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 vlr.PathMapper(c)}return this.pathMapper}canHandle(c){return c.name==="git"&&c.available}};Foe.GitLens=$ke});var $_t=jt(koe=>{"use strict";Object.defineProperty(koe,"__esModule",{value:!0});koe.AlexandriaLens=void 0;var Dlr=Ik(),blr=wk(),Hke=class extends Dlr.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(),w=[];for(let _e of c.coveredFilesList||[]){let be=S.toRelative(_e);w.push(be),g.push({path:be,hasIssues:!1})}for(let _e of c.uncoveredFiles||[]){let be=S.toRelative(_e);w.push(be),g.push({path:be,hasIssues:!0}),f.push({file:be,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(w,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 blr.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}}};koe.AlexandriaLens=Hke});var H_t=jt(Ioe=>{"use strict";Object.defineProperty(Ioe,"__esModule",{value:!0});Ioe.NodeExecutor=void 0;var Kke=require("child_process"),Qke=class{type="node";async execute(c,f=[],g={}){let S=Date.now();return new Promise(w=>{let{cwd:J=process.cwd(),env:re=process.env,timeout:_e=12e4,maxBuffer:be=10*1024*1024,encoding:Ee="utf8",shell:Ne=!1}=g,Y="",st="",Ve=!1,We,kt=(0,Kke.spawn)(c,f,{cwd:J,env:re,shell:Ne});_e>0&&(We=setTimeout(()=>{Ve=!0,kt.kill("SIGTERM"),setTimeout(()=>{kt.killed||kt.kill("SIGKILL")},5e3)},_e)),kt.stdout?.on("data",sr=>{let Br=sr.toString(Ee);Y.length+Br.length<=be&&(Y+=Br)}),kt.stderr?.on("data",sr=>{let Br=sr.toString(Ee);st.length+Br.length<=be&&(st+=Br)}),kt.on("close",sr=>{We&&clearTimeout(We);let Br=Date.now()-S;w({stdout:Y,stderr:st,exitCode:sr??-1,duration:Br,timedOut:Ve,command:c,args:f})}),kt.on("error",sr=>{We&&clearTimeout(We);let Br=Date.now()-S;w({stdout:Y,stderr:st,exitCode:-1,duration:Br,error:sr,command:c,args:f})})})}stream(c,f=[],g={}){let{cwd:S=process.cwd(),env:w=process.env,timeout:J=12e4,shell:re=!1,onStdout:_e,onStderr:be}=g,Ee=Date.now(),Ne=!1,Y,st=(0,Kke.spawn)(c,f,{cwd:S,env:w,shell:re});J>0&&(Y=setTimeout(()=>{Ne=!0,st.kill("SIGTERM"),setTimeout(()=>{st.killed||st.kill("SIGKILL")},5e3)},J)),_e&&st.stdout&&st.stdout.on("data",We=>{_e(We.toString())}),be&&st.stderr&&st.stderr.on("data",We=>{be(We.toString())});let Ve=new Promise(We=>{let kt="",sr="";st.stdout?.on("data",Br=>{kt+=Br.toString()}),st.stderr?.on("data",Br=>{sr+=Br.toString()}),st.on("close",Br=>{Y&&clearTimeout(Y),We({stdout:kt,stderr:sr,exitCode:Br??-1,duration:Date.now()-Ee,timedOut:Ne,command:c,args:f})}),st.on("error",Br=>{Y&&clearTimeout(Y),We({stdout:kt,stderr:sr,exitCode:-1,duration:Date.now()-Ee,error:Br,command:c,args:f})})});return{stdout:st.stdout,stderr:st.stderr,exitPromise:Ve,kill:()=>{st.kill()}}}async isAvailable(c){try{let f=process.platform==="win32"?"where":"which";return new Promise(g=>{(0,Kke.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}}};Ioe.NodeExecutor=Qke});var Q_t=jt(woe=>{"use strict";Object.defineProperty(woe,"__esModule",{value:!0});woe.MockExecutor=void 0;var K_t=require("stream"),Xke=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(w=>setTimeout(w,10));let S;if(this.sequentialResponses.has(c)){let w=this.callCounts.get(c)||0;S=this.sequentialResponses.get(c)[w]||this.defaultResponse,this.callCounts.set(c,w+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,w=new K_t.Readable({read(){this.push(S.stdout||""),this.push(null)}}),J=new K_t.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(_e=>{setTimeout(()=>{_e({stdout:S.stdout||"",stderr:S.stderr||"",exitCode:S.exitCode??0,duration:S.duration||10,command:c,args:f})},S.duration||10)});return{stdout:w,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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principal-ai/quality-lens-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
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.
|
|
46
|
+
"@principal-ai/codebase-quality-lenses": "^0.1.25",
|
|
47
47
|
"@principal-ai/repository-abstraction": "^0.2.0",
|
|
48
48
|
"@types/jest": "^30.0.0",
|
|
49
49
|
"@types/node": "^20.0.0",
|