dep-report 0.0.2 → 0.0.4

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 +73 -72
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,45 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import{b as oe}from"./chunk-KNT3JZ7P.js";import{Command as $t}from"commander";import{existsSync as Ie,mkdirSync as Ae,writeFileSync as T,readFileSync as wt}from"fs";import{join as v}from"path";import{existsSync as Be}from"fs";import{join as ze}from"path";function se(e=process.cwd()){let t=[{file:"pnpm-lock.yaml",manager:"pnpm"},{file:"bun.lock",manager:"bun"},{file:"bun.lockb",manager:"bun"},{file:"package-lock.json",manager:"npm"}];for(let{file:r,manager:n}of t){let i=ze(e,r);if(Be(i))return{manager:n,lockfile:r}}return null}function ae(e){return{npm:"npm outdated --json",pnpm:"pnpm outdated --json",bun:"bun outdated --json"}[e]}import{exec as _e}from"child_process";import{promisify as He}from"util";var Ke=He(_e);async function ie(e,t=process.cwd()){let r=ae(e);try{let{stdout:n,stderr:i}=await Ke(r,{cwd:t,maxBuffer:10485760}),m=n.trim()||i.trim();if(!m)return{};try{return JSON.parse(m)}catch(a){if(m.includes("All packages are up to date")||m==="{}")return{};throw new Error(`Failed to parse outdated output: ${a instanceof Error?a.message:String(a)}`)}}catch(n){if(n.stdout)try{return JSON.parse(n.stdout)}catch{throw n.code==="ENOENT"?new Error(`Package manager "${e}" not found. Please install it first.`):new Error(`Failed to execute outdated command: ${n.message}`)}if(n.code==="ENOENT")throw new Error(`Package manager "${e}" not found. Please install it first.`);return{}}}function ce(e){let t=[];for(let[r,n]of Object.entries(e)){if(typeof n!="object"||n===null||Array.isArray(n))continue;let i=n.current||n.installed||n.version||"-",m=n.latest||n.wanted||i,a=n.wanted||n.current||m,w=n.type||n.dependencyType||Je(r);!r||!m||t.push({name:r,current:String(i),wanted:String(a),latest:String(m),type:w})}return t}function Je(e){return e.startsWith("@types/")||e.includes("-test")||e.includes("-spec")||e==="typescript"||e==="eslint"||e.startsWith("eslint-")||e.startsWith("@eslint/")?"devDependencies":"dependencies"}var L=class{constructor(t="https://registry.npmjs.org"){this.baseUrl=t}async getMetadata(t){try{let r=`${this.baseUrl}/${encodeURIComponent(t)}`,n=await fetch(r,{headers:{Accept:"application/json"}});if(!n.ok){if(n.status===404)return null;throw new Error(`Registry request failed: ${n.status}`)}return await n.json()}catch{return null}}};var de=new L;async function We(e,t=de,r=new Date){let i=await(typeof t=="string"?new L(t):t).getMetadata(e.name);if(!i||!i.time)return{...e,currentPublishedAt:null,latestPublishedAt:null,age:null,behindByDays:null,isStale:!1,risk:"Exotic"};let m=i.time[e.current]?new Date(i.time[e.current]):null,a=i.time[e.latest]?new Date(i.time[e.latest]):null,w=null;if(m){let k=r.getTime()-m.getTime();w=Math.floor(k/(1e3*60*60*24))}let p=null;if(m&&a){let k=a.getTime()-m.getTime();p=Math.floor(k/(1e3*60*60*24))}return{...e,currentPublishedAt:m,latestPublishedAt:a,age:w,behindByDays:p,isStale:!1,risk:"Exotic"}}async function le(e,t=5,r=de,n=new Date){let i=typeof r=="string"?new L(r):r,m=[];for(let a=0;a<e.length;a+=t){let w=e.slice(a,a+t),p=await Promise.all(w.map(k=>We(k,i,n)));m.push(...p),a+t<e.length&&await new Promise(k=>setTimeout(k,500))}return m}import{diff as Ye,valid as me}from"semver";function Ge(e){return!e||e==="-"||e==="missing"?!1:/^(file:|git\+|https?:|link:|workspace:)/.test(e)}function qe(e,t){if(Ge(e))return"Exotic";if(!e||e==="-"||e==="missing")return"NotInstalled";if(!me(e)||!me(t))return"Exotic";try{switch(Ye(e,t)){case"major":return"Major";case"minor":return"Minor";case"patch":return"Patch";default:return"Patch"}}catch{return"Exotic"}}function ue(e,t=null){return e.map(r=>{let n=qe(r.current,r.latest),i=t!==null&&r.age!==null&&r.age>t;return{...r,risk:n,isStale:i}})}import{format as pe}from"date-fns";function C(e){if(!e)return null;let t={blocked:/^BLOCKED[:\-\s]/i,deferred:/^DEFERRED[:\-\s]/i,accepted:/^ACCEPTED(\s+RISK)?[:\-\s]/i};return t.blocked.test(e)?"blocked":t.deferred.test(e)?"deferred":t.accepted.test(e)?"accepted":null}function I(e){if(!e)return"";let t=C(e);if(!t)return e;let r={blocked:"\u{1F534} BLOCKED",deferred:"\u{1F7E1} DEFERRED",accepted:"\u{1F535} ACCEPTED RISK"},n=e.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim();return`${r[t]}: ${n}`}function O(e){let t=0;e.age!==null&&(e.age>730?t+=10:e.age>365&&(t+=5)),e.risk==="Major"?t+=8:e.risk==="Minor"&&(t+=3);let r=C(e.note);return r==="blocked"?t+=15:r==="deferred"&&(t+=5),e.behindByDays!==null&&e.behindByDays>365&&(t+=7),t}function A(e){return e.current===e.latest}function F(e,t,r){let n=e.length,i=e.filter(s=>s.isStale).length,m=t-n,a=e.filter(s=>s.risk==="Major").length,w=e.filter(s=>s.risk==="Minor").length,p=e.filter(s=>s.risk==="Patch").length,k=e.filter(s=>C(s.note)==="blocked").length,c=e.filter(s=>C(s.note)==="deferred").length,y=e.filter(s=>C(s.note)==="accepted").length,d="healthy",g="\u{1F7E2}",o="Healthy";if(r){let s=r.method,h=t>0?i/t*100:0,f=e.filter(u=>u.risk==="Major").length,b=t>0?f/t*100:0;s==="percentage"?h>=r.atRisk.stalePercent||b>=r.atRisk.majorPercent?(d="atRisk",g="\u{1F534}",o=`At Risk (${Math.round(h)}% stale)`):h>=r.degrading.stalePercent||b>=r.degrading.majorPercent?(d="degrading",g="\u{1F7E1}",o=`Degrading (${Math.round(h)}% stale)`):(d="healthy",g="\u{1F7E2}",o="Healthy"):i>=r.atRisk.stalePercent||f>=r.atRisk.majorPercent?(d="atRisk",g="\u{1F534}",o=`At Risk (${i} stale)`):i>=r.degrading.stalePercent||f>=r.degrading.majorPercent?(d="degrading",g="\u{1F7E1}",o=`Degrading (${i} stale)`):(d="healthy",g="\u{1F7E2}",o="Healthy")}else{let s=t>0?i/t*100:0,h=e.filter(b=>b.risk==="Major").length,f=t>0?h/t*100:0;s>=15||f>=20?(d="atRisk",g="\u{1F534}",o=`At Risk (${Math.round(s)}% stale)`):s>=5||f>=10?(d="degrading",g="\u{1F7E1}",o=`Degrading (${Math.round(s)}% stale)`):(d="healthy",g="\u{1F7E2}",o="Healthy")}return{total:t,outdated:n,stale:i,upToDate:m,blocked:k,deferred:c,accepted:y,major:a,minor:w,patch:p,riskStatus:d,riskStatusEmoji:g,riskStatusText:o}}function q(e){if(e===null)return"Unknown";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function V(e){if(e===null)return"\u2014";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function Q(e,t=new Date,r){let n=pe(t,"yyyy-MM-dd"),i=pe(t,"yyyy-MM-dd HH:mm:ss");if(e.length===0)return`# Dependency Report (${n})
3
-
4
- Generated at: ${i}
5
-
6
- \u2705 All dependencies are up to date
7
- `;let m=r??e.length,a=F(e,m),w=[...e].sort((c,y)=>{let d={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},g=(d[c.risk]||99)-(d[y.risk]||99);return g!==0?g:c.age===null&&y.age===null?0:c.age===null?1:y.age===null?-1:y.age-c.age}),p=`# Dependency Report (${n})
8
-
9
- Generated at: ${i}
10
-
11
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
12
- ${a.riskStatusEmoji} ${a.riskStatusText}
13
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
14
-
15
- Total: ${a.total} | Outdated: ${a.outdated} | Stale: ${a.stale} | Up-to-date: ${a.upToDate}
16
- `;(a.blocked>0||a.deferred>0||a.accepted>0)&&(p+=`Blocked: ${a.blocked} | Deferred: ${a.deferred} | Accepted Risk: ${a.accepted}
17
- `),p+=`
18
- **Risk Assessment:** ${a.stale} stale dependencies and ${a.major} unaddressed major upgrades detected.
19
-
20
- `;let k=w.map(c=>({pkg:c,score:O(c)})).filter(({score:c})=>c>15).sort((c,y)=>y.score-c.score).slice(0,7).map(({pkg:c})=>c);if(k.length>0){p+=`\u2501\u2501\u2501 ACTION REQUIRED \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
21
-
22
- `;let c=k.filter(d=>O(d)>=20||d.risk==="Major"||d.note&&/BLOCKED/i.test(d.note)),y=k.filter(d=>!c.includes(d));if(c.length>0){p+=`\u{1F534} Critical Risk
23
- `;for(let d of c){let g=q(d.age),o=V(d.behindByDays),s=d.risk==="Major"?"Major update":d.risk==="Minor"?"Minor update":"Patch update",h=d.note?`
24
- ${I(d.note)}`:"";p+=` \u2022 ${d.name} (${d.current} \u2192 ${d.latest})
25
- `,p+=` ${g} old, behind by ${o} | ${s}${h}
26
-
27
- `}}if(y.length>0){p+=`\u{1F7E1} Review Soon
28
- `;for(let d of y){let g=q(d.age),o=V(d.behindByDays),s=d.risk==="Major"?"Major update":d.risk==="Minor"?"Minor update":"Patch update",h=d.note?`
29
- ${I(d.note)}`:"";p+=` \u2022 ${d.name} (${d.current} \u2192 ${d.latest})
30
- `,p+=` ${g} old, behind by ${o} | ${s}${h}
31
-
32
- `}}p+=`
33
- `}else p+=`\u2501\u2501\u2501 ACTION REQUIRED \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
34
-
35
- `,p+=`\u2705 No critical actions required
36
-
37
- `;p+=`\u2501\u2501\u2501 FULL DEPENDENCY LIST \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
38
-
39
- `,p+=`| Package | Current | Latest | Age | Behind | Risk | Status | Notes |
40
- `,p+=`|---------|---------|--------|-----|---------|------|--------|-------|
41
- `;for(let c of w){let y=q(c.age),d=V(c.behindByDays),g=c.risk==="Major"?"\u{1F534} Major":c.risk==="Minor"?"\u{1F7E1} Minor":c.risk==="Patch"?"\u{1F7E2} Patch":c.risk,o=A(c)?"\u2705 Stable":"Outdated",s=c.note?I(c.note):"";p+=`| ${c.name} | ${c.current} | ${c.latest} | ${y} | ${d} | ${g} | ${o} | ${s} |
42
- `}return p}import{format as fe}from"date-fns";function R(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return e.replace(/[&<>"']/g,r=>t[r])}function X(e){if(e===null)return"Unknown";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function Z(e){if(e===null)return"\u2014";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function Ve(e){switch(e){case"Major":return"#dc2626";case"Minor":return"#ea580c";case"Patch":return"#ca8a04";case"Exotic":return"#6b7280";case"NotInstalled":return"#9ca3af";default:return"#6b7280"}}function ee(e,t=new Date,r){let n=fe(t,"yyyy-MM-dd"),i=fe(t,"yyyy-MM-dd HH:mm:ss");if(e.length===0)return`<!DOCTYPE html>
2
+ import{b as oe}from"./chunk-KNT3JZ7P.js";import{Command as wt}from"commander";import{format as Fe}from"date-fns";import{existsSync as Le,mkdirSync as Be,readFileSync as St,writeFileSync as T}from"fs";import{join as v}from"path";import{readFileSync as ie,existsSync as q,readdirSync as _e}from"fs";import{join as K}from"path";import{format as He,parse as J,subDays as Ke,differenceInDays as V}from"date-fns";var j={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"},se=["-","\\","|","/"],H=null,ae="",l={info:e=>{console.log(`${j.cyan}[INFO]${j.reset} ${e}`)},success:e=>{console.log(`${j.green}${j.bright}[OK]${j.reset} ${j.green}${e}${j.reset}`)},warn:e=>{console.warn(`${j.yellow}[WARN]${j.reset} ${e}`)},error:e=>{console.error(`${j.red}${j.bright}[ERR]${j.reset} ${j.red}${e}${j.reset}`)},progress:(e,t,r)=>{let n=Math.round(e/t*100);process.stdout.write(`\r${j.cyan}${r}${j.reset} ${j.dim}(${e}/${t}, ${n}%)${j.reset}`),e===t&&process.stdout.write(`
3
+ `)},startSpinner:e=>{ae=e;let t=0;H=setInterval(()=>{process.stdout.write(`\r${j.cyan}${se[t]}${j.reset} ${ae}`),t=(t+1)%se.length},100)},stopSpinner:()=>{H&&(clearInterval(H),H=null,process.stdout.write("\r"+" ".repeat(process.stdout.columns||80)+"\r"))}};function ce(e,t){let r=e.match(/\| Package \|.*?\n\|-+\|\n([\s\S]*?)\n\n/);if(!r)return null;let n=r[1].trim().split(`
4
+ `),s=[];for(let d of n){let y=d.split("|").map(S=>S.trim()).filter(S=>S);if(y.length<6)continue;let[m,g,o,i,h,f,b,p]=y;if(b.includes("Stable"))continue;let w=null;if(i&&i!=="Unknown"){let S=i.match(/(\d+)d|(\d+)m|(\d+)y/);S&&(S[1]?w=parseInt(S[1]):S[2]?w=parseInt(S[2])*30:S[3]&&(w=parseInt(S[3])*365))}let E=null;if(h&&h!=="\u2014"){let S=h.match(/(\d+)d|(\d+)m|(\d+)y/);S&&(S[1]?E=parseInt(S[1]):S[2]?E=parseInt(S[2])*30:S[3]&&(E=parseInt(S[3])*365))}let R="Patch";f.includes("Major")?R="Major":f.includes("Minor")?R="Minor":f.includes("Patch")?R="Patch":f.includes("Exotic")?R="Exotic":f.includes("NotInstalled")&&(R="NotInstalled"),s.push({name:m,current:g,latest:o,wanted:o,type:"dependencies",currentPublishedAt:null,latestPublishedAt:null,age:w,behindByDays:E,isStale:w!==null&&w>365,risk:R,note:p||void 0})}let c=e.match(/Total: (\d+) \| Outdated: (\d+) \| Stale: (\d+)/),a=c?parseInt(c[1]):s.length,k=c?parseInt(c[2]):s.length,u=c?parseInt(c[3]):s.filter(d=>d.isStale).length,$=s.filter(d=>d.risk==="Major").length;return{date:t,packages:s,summary:{total:a,outdated:k,stale:u,major:$}}}function de(e,t){if(t==="latest"){let r=K(e,"latest.md");return q(r)?r:null}if(t==="last-month"){let n=Ke(new Date,30),s=_e(e).filter(c=>c.endsWith("_outdated.md")).map(c=>{let a=c.match(/(\d{4}-\d{2}-\d{2})_outdated\.md/);return a?{file:c,date:J(a[1],"yyyy-MM-dd",new Date)}:null}).filter(c=>c!==null).sort((c,a)=>Math.abs(V(c.date,n))-Math.abs(V(a.date,n)));return s.length>0?K(e,s[0].file):null}try{let r=J(t,"yyyy-MM-dd",new Date),n=He(r,"yyyy-MM-dd"),s=K(e,`${n}_outdated.md`);if(q(s))return s}catch{}return null}function le(e){return 100-e.stale*5-e.major*3}async function me(e,t,r=process.cwd()){let n=K(r,".dep-report","reports");q(n)||(l.error("No reports directory found. Run dep-report first to generate reports."),process.exit(1));let s=de(n,e),c=de(n,t);s||(l.error(`Report not found for: ${e}`),process.exit(1)),c||(l.error(`Report not found for: ${t}`),process.exit(1));let a=ie(s,"utf-8"),k=ie(c,"utf-8"),u=s.match(/(\d{4}-\d{2}-\d{2})_outdated\.md/),$=c.match(/(\d{4}-\d{2}-\d{2})_outdated\.md/),d=u?u[1]:e,y=$?$[1]:t,m=ce(a,d),g=ce(k,y);(!m||!g)&&(l.error("Failed to parse reports"),process.exit(1));let o=V(J(y,"yyyy-MM-dd",new Date),J(d,"yyyy-MM-dd",new Date)),i=g.summary.stale-m.summary.stale,h=g.summary.major-m.summary.major,f=new Set(m.packages.map(x=>x.name)),b=new Set(g.packages.map(x=>x.name)),p=g.packages.filter(x=>!f.has(x.name)),w=m.packages.filter(x=>!b.has(x.name)),E=g.packages.filter(x=>{let _=m.packages.find(G=>G.name===x.name);return _&&_.current!==x.current}),R=le(m.summary),S=le(g.summary),N=R>0?(S-R)/R*100:0;if(console.log(`
5
+ Dependency Health Comparison`),console.log(`From: ${d} \u2192 ${y} (${o} days)
6
+ `),E.length>0){console.log("\u{1F4C8} Improvements:");for(let x of E.slice(0,5)){let _=m.packages.find(G=>G.name===x.name);console.log(` \u2022 ${x.name}: ${_?.current} \u2192 ${x.current}`)}E.length>5&&console.log(` ... and ${E.length-5} more`),console.log("")}if(i!==0||h!==0){if(console.log("\u{1F4CA} Metrics:"),i!==0){let x=i>0?"+":"";console.log(` \u2022 Stale packages: ${m.summary.stale} \u2192 ${g.summary.stale} (${x}${i})`)}if(h!==0){let x=h>0?"+":"";console.log(` \u2022 Major upgrades pending: ${m.summary.major} \u2192 ${g.summary.major} (${x}${h})`)}console.log("")}p.length>0&&console.log(`\u2795 Added: ${p.map(x=>x.name).join(", ")}`),w.length>0&&console.log(`\u2796 Removed: ${w.map(x=>x.name).join(", ")}`),(p.length>0||w.length>0)&&console.log("");let Ue=N>0?"\u2705":N<0?"\u26A0\uFE0F":"\u27A1\uFE0F",ze=N>0?"improved":N<0?"regressed":"unchanged";console.log(`${Ue} Overall: Health ${ze} by ${Math.abs(N).toFixed(1)}%`),console.log(` Score: ${R.toFixed(1)} \u2192 ${S.toFixed(1)}
7
+ `),process.exit(N<0?1:0)}import{existsSync as L,mkdirSync as pe,writeFileSync as Q}from"fs";import{join as B}from"path";import{z as D}from"zod";var P={staleThreshold:"18 months",ignorePatterns:[],formats:{markdown:!0,html:!0},concurrency:5,failConditions:{stale:!1,major:!1},reportEmptyState:!0},Je=D.object({staleThreshold:D.string().default(P.staleThreshold),ignorePatterns:D.array(D.string()).default(P.ignorePatterns),formats:D.object({markdown:D.boolean().default(P.formats.markdown),html:D.boolean().default(P.formats.html)}).default(P.formats),concurrency:D.number().int().positive().default(P.concurrency),failConditions:D.object({stale:D.boolean().default(P.failConditions.stale),major:D.boolean().default(P.failConditions.major)}).default(P.failConditions),reportEmptyState:D.boolean().default(P.reportEmptyState)}).passthrough();function ue(e){try{return Je.parse(e)}catch(t){if(t instanceof D.ZodError){let r=t.errors.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ");throw new Error(`Invalid config: ${r}`)}throw t}}async function fe(e=process.cwd(),t=!1,r){let n=B(e,".dep-report"),s=B(n,"config.json"),c=B(n,"notes.json"),a=B(n,"reports"),k=B(n,".gitignore");if(L(n)?l.info(".dep-report/ directory already exists"):(pe(n,{recursive:!0}),l.success("Created .dep-report/ directory")),L(a)||(pe(a,{recursive:!0}),l.success("Created .dep-report/reports/ directory")),!L(s)||t){let u=P;if(r){let d=oe(r);u=d.config,l.info(`Using preset: ${d.displayName} - ${d.description}`)}let $=JSON.stringify(u,null,2);Q(s,$,"utf-8"),l.success("Created .dep-report/config.json")}else l.info("config.json already exists, skipping");if(L(c))l.info("notes.json already exists, skipping");else{let u=JSON.stringify({},null,2);Q(c,u,"utf-8"),l.success("Created .dep-report/notes.json")}L(k)?l.info(".gitignore already exists, skipping"):(Q(k,`.cache.json
8
+ `,"utf-8"),l.success("Created .dep-report/.gitignore")),l.success("Initialization complete!"),l.info("You can now customize .dep-report/config.json and add notes to .dep-report/notes.json")}import{existsSync as Ze,readFileSync as et}from"fs";import{join as tt}from"path";import{existsSync as ge,access as We,constants as Ye,mkdirSync as Ge,writeFileSync as qe,unlinkSync as Ve}from"fs";import{join as he}from"path";import{promisify as Qe}from"util";var Xe=Qe(We);async function ye(e=process.cwd(),t=!1,r){let n=he(e,"node_modules");if(!ge(n)){if(t){r&&r('node_modules directory not found, but lockfile exists. The outdated command may not work correctly. Consider running "npm install", "pnpm install", or "bun install" first.');return}throw new Error('node_modules directory not found. Please run "npm install", "pnpm install", or "bun install" first.')}}async function be(e){if(!ge(e))try{Ge(e,{recursive:!0})}catch(r){throw new Error(`Cannot create directory ${e}: ${r instanceof Error?r.message:String(r)}`)}try{await Xe(e,Ye.W_OK)}catch{throw new Error(`No write permission for directory: ${e}`)}let t=he(e,`.write-test-${Date.now()}.tmp`);try{qe(t,"ok"),Ve(t)}catch(r){throw new Error(`Cannot write to directory ${e}: ${r instanceof Error?r.message:String(r)}`)}}function W(e,t){try{return JSON.parse(e)}catch(r){throw r instanceof SyntaxError?new Error(`Invalid JSON in ${t}: ${r.message}`):r}}function ke(e=process.cwd()){let t=tt(e,".dep-report","config.json");if(!Ze(t))return l.info("No config.json found, using defaults"),P;try{let r=et(t,"utf-8"),n=W(r,t),s={staleThreshold:n.staleThreshold??P.staleThreshold,ignorePatterns:n.ignorePatterns??P.ignorePatterns,formats:{markdown:n.formats?.markdown??P.formats.markdown,html:n.formats?.html??P.formats.html},concurrency:n.concurrency??P.concurrency,failConditions:{stale:n.failConditions?.stale??P.failConditions.stale,major:n.failConditions?.major??P.failConditions.major},reportEmptyState:n.reportEmptyState??P.reportEmptyState},c=ue(s);return l.info("Loaded config from .dep-report/config.json"),c}catch(r){return l.warn(`Failed to load config: ${r instanceof Error?r.message:String(r)}`),l.warn("Using default configuration"),P}}import{diff as rt,valid as $e}from"semver";function nt(e){return!e||e==="-"||e==="missing"?!1:/^(file:|git\+|https?:|link:|workspace:)/.test(e)}function ot(e,t){if(nt(e))return"Exotic";if(!e||e==="-"||e==="missing")return"NotInstalled";if(!$e(e)||!$e(t))return"Exotic";try{switch(rt(e,t)){case"major":return"Major";case"minor":return"Minor";case"patch":return"Patch";default:return"Patch"}}catch{return"Exotic"}}function we(e,t=null){return e.map(r=>{let n=ot(r.current,r.latest),s=t!==null&&r.age!==null&&r.age>t;return{...r,risk:n,isStale:s}})}import{existsSync as st}from"fs";import{join as at}from"path";function Se(e=process.cwd()){let t=[{file:"pnpm-lock.yaml",manager:"pnpm"},{file:"bun.lock",manager:"bun"},{file:"bun.lockb",manager:"bun"},{file:"package-lock.json",manager:"npm"}];for(let{file:r,manager:n}of t){let s=at(e,r);if(st(s))return{manager:n,lockfile:r}}return null}function Pe(e){return{npm:"npm outdated --json",pnpm:"pnpm outdated --json",bun:"bun outdated --json"}[e]}var U=class{constructor(t="https://registry.npmjs.org"){this.baseUrl=t}async getMetadata(t){try{let r=`${this.baseUrl}/${encodeURIComponent(t)}`,n=await fetch(r,{headers:{Accept:"application/json"}});if(!n.ok){if(n.status===404)return null;throw new Error(`Registry request failed: ${n.status}`)}return await n.json()}catch{return null}}};var xe=new U;async function it(e,t=xe,r=new Date){let s=await(typeof t=="string"?new U(t):t).getMetadata(e.name);if(!s||!s.time)return{...e,currentPublishedAt:null,latestPublishedAt:null,age:null,behindByDays:null,isStale:!1,risk:"Exotic"};let c=s.time[e.current]?new Date(s.time[e.current]):null,a=s.time[e.latest]?new Date(s.time[e.latest]):null,k=null;if(c){let $=r.getTime()-c.getTime();k=Math.floor($/(1e3*60*60*24))}let u=null;if(c&&a){let $=a.getTime()-c.getTime();u=Math.floor($/(1e3*60*60*24))}return{...e,currentPublishedAt:c,latestPublishedAt:a,age:k,behindByDays:u,isStale:!1,risk:"Exotic"}}async function je(e,t=5,r=xe,n=new Date){let s=typeof r=="string"?new U(r):r,c=[];for(let a=0;a<e.length;a+=t){let k=e.slice(a,a+t),u=await Promise.all(k.map($=>it($,s,n)));c.push(...u),a+t<e.length&&await new Promise($=>setTimeout($,500))}return c}function Me(e){let t=[],r=Array.isArray(e)?e:Array.isArray(e.packages)?e.packages:null;if(r){for(let n of r){if(!n||typeof n!="object")continue;let s=n.name||n.package||n.pkg,c=n.current||n.installed||n.version||"-",a=n.latest||n.update||n.wanted||c,k=n.wanted||n.update||n.current||a,u=n.type||n.dependencyType||n.kind||Ee(String(s));!s||!a||t.push({name:String(s),current:String(c),wanted:String(k),latest:String(a),type:u})}return t}for(let[n,s]of Object.entries(e)){if(typeof s!="object"||s===null||Array.isArray(s))continue;let c=s.current||s.installed||s.version||"-",a=s.latest||s.wanted||c,k=s.wanted||s.current||a,u=s.type||s.dependencyType||Ee(n);!n||!a||t.push({name:n,current:String(c),wanted:String(k),latest:String(a),type:u})}return t}function Ee(e){return e.startsWith("@types/")||e.includes("-test")||e.includes("-spec")||e==="typescript"||e==="eslint"||e.startsWith("eslint-")||e.startsWith("@eslint/")?"devDependencies":"dependencies"}import{exec as ct}from"child_process";import{promisify as dt}from"util";var lt=dt(ct);function Re(e){if(!/\|\s*Package\s*\|/i.test(e))return null;let t=[],r=e.split(`
9
+ `).map(n=>n.trim()).filter(Boolean);for(let n of r){if(!n.startsWith("|"))continue;let s=n.split("|").map($=>$.trim()).filter(Boolean);if(s.length<4)continue;let[c,a,k,u]=s;!c||/^-+$/.test(c)||c.toLowerCase()==="package"||t.push({name:c,current:a,update:k,latest:u})}return t.length>0?t:null}async function De(e,t=process.cwd()){let r=Pe(e);try{let{stdout:n,stderr:s}=await lt(r,{cwd:t,maxBuffer:10485760}),c=n.trim()||s.trim();if(!c)return{};try{return JSON.parse(c)}catch(a){if(e==="bun"){let k=Re(c);if(k)return k}if(c.includes("All packages are up to date")||c==="{}")return{};throw new Error(`Failed to parse outdated output: ${a instanceof Error?a.message:String(a)}`)}}catch(n){let s=String(n.stdout||n.stderr||"").trim();if(s)try{return JSON.parse(s)}catch{if(e==="bun"){let c=Re(s);if(c)return c}if(/no outdated|up to date/i.test(s)||s==="{}")return{};throw n.code==="ENOENT"?new Error(`Package manager "${e}" not found. Please install it first.`):new Error(`Failed to execute outdated command: ${n.message}`)}if(n.code==="ENOENT")throw new Error(`Package manager "${e}" not found. Please install it first.`);return{}}}import{existsSync as mt,readFileSync as ut}from"fs";import{join as pt}from"path";function ve(e=process.cwd()){let t=pt(e,".dep-report","notes.json");if(!mt(t))return{};try{let r=ut(t,"utf-8"),n=W(r,t);if(typeof n!="object"||n===null||Array.isArray(n))return l.warn("Invalid notes.json format, expected object"),{};for(let[s,c]of Object.entries(n))typeof c!="string"&&(l.warn(`Invalid note for ${s}, expected string`),delete n[s]);return l.info(`Loaded ${Object.keys(n).length} notes from notes.json`),n}catch(r){return l.warn(`Failed to load notes: ${r instanceof Error?r.message:String(r)}`),{}}}function Ce(e,t){return e.map(r=>{let n=t[r.name];return n?{...r,note:n}:r})}import{format as Oe}from"date-fns";function C(e){if(!e)return null;let t={blocked:/^BLOCKED[:\-\s]/i,deferred:/^DEFERRED[:\-\s]/i,accepted:/^ACCEPTED(\s+RISK)?[:\-\s]/i};return t.blocked.test(e)?"blocked":t.deferred.test(e)?"deferred":t.accepted.test(e)?"accepted":null}function I(e){if(!e)return"";let t=C(e);if(!t)return e;let r={blocked:"\u{1F534} BLOCKED",deferred:"\u{1F7E1} DEFERRED",accepted:"\u{1F535} ACCEPTED RISK"},n=e.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim();return`${r[t]}: ${n}`}function O(e){let t=0;e.age!==null&&(e.age>730?t+=10:e.age>365&&(t+=5)),e.risk==="Major"?t+=8:e.risk==="Minor"&&(t+=3);let r=C(e.note);return r==="blocked"?t+=15:r==="deferred"&&(t+=5),e.behindByDays!==null&&e.behindByDays>365&&(t+=7),t}function A(e){return e.current===e.latest}function F(e,t,r){let n=e.length,s=e.filter(i=>i.isStale).length,c=t-n,a=e.filter(i=>i.risk==="Major").length,k=e.filter(i=>i.risk==="Minor").length,u=e.filter(i=>i.risk==="Patch").length,$=e.filter(i=>C(i.note)==="blocked").length,d=e.filter(i=>C(i.note)==="deferred").length,y=e.filter(i=>C(i.note)==="accepted").length,m="healthy",g="\u{1F7E2}",o="Healthy";if(r){let i=r.method,h=t>0?s/t*100:0,f=e.filter(p=>p.risk==="Major").length,b=t>0?f/t*100:0;i==="percentage"?h>=r.atRisk.stalePercent||b>=r.atRisk.majorPercent?(m="atRisk",g="\u{1F534}",o=`At Risk (${Math.round(h)}% stale)`):h>=r.degrading.stalePercent||b>=r.degrading.majorPercent?(m="degrading",g="\u{1F7E1}",o=`Degrading (${Math.round(h)}% stale)`):(m="healthy",g="\u{1F7E2}",o="Healthy"):s>=r.atRisk.stalePercent||f>=r.atRisk.majorPercent?(m="atRisk",g="\u{1F534}",o=`At Risk (${s} stale)`):s>=r.degrading.stalePercent||f>=r.degrading.majorPercent?(m="degrading",g="\u{1F7E1}",o=`Degrading (${s} stale)`):(m="healthy",g="\u{1F7E2}",o="Healthy")}else{let i=t>0?s/t*100:0,h=e.filter(b=>b.risk==="Major").length,f=t>0?h/t*100:0;i>=15||f>=20?(m="atRisk",g="\u{1F534}",o=`At Risk (${Math.round(i)}% stale)`):i>=5||f>=10?(m="degrading",g="\u{1F7E1}",o=`Degrading (${Math.round(i)}% stale)`):(m="healthy",g="\u{1F7E2}",o="Healthy")}return{total:t,outdated:n,stale:s,upToDate:c,blocked:$,deferred:d,accepted:y,major:a,minor:k,patch:u,riskStatus:m,riskStatusEmoji:g,riskStatusText:o}}function M(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return e.replace(/[&<>"']/g,r=>t[r])}function X(e){if(e===null)return"Unknown";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function Z(e){if(e===null)return"\u2014";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function ft(e){switch(e){case"Major":return"#dc2626";case"Minor":return"#ea580c";case"Patch":return"#ca8a04";case"Exotic":return"#6b7280";case"NotInstalled":return"#9ca3af";default:return"#6b7280"}}function ee(e,t=new Date,r){let n=Oe(t,"yyyy-MM-dd"),s=Oe(t,"yyyy-MM-dd HH:mm:ss");if(e.length===0)return`<!DOCTYPE html>
43
10
  <html lang="en">
44
11
  <head>
45
12
  <meta charset="UTF-8">
@@ -76,40 +43,40 @@ Total: ${a.total} | Outdated: ${a.outdated} | Stale: ${a.stale} | Up-to-date: ${
76
43
  <body>
77
44
  <div class="container">
78
45
  <h1>Dependency Report (${n})</h1>
79
- <div class="timestamp">Generated at: ${i}</div>
46
+ <div class="timestamp">Generated at: ${s}</div>
80
47
  <div class="empty-state">
81
48
  <h2>\u2705 All dependencies are up to date</h2>
82
49
  </div>
83
50
  </div>
84
51
  </body>
85
- </html>`;let m=r??e.length,a=F(e,m),w=[...e].sort((o,s)=>{let h={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},f=(h[o.risk]||99)-(h[s.risk]||99);return f!==0?f:o.age===null&&s.age===null?0:o.age===null?1:s.age===null?-1:s.age-o.age}),p=w.map(o=>({pkg:o,score:O(o)})).filter(({score:o})=>o>15).sort((o,s)=>s.score-o.score).slice(0,7).map(({pkg:o})=>o),k=p.filter(o=>O(o)>=20||o.risk==="Major"||o.note&&/BLOCKED/i.test(o.note)),c=p.filter(o=>!k.includes(o)),y="";if(p.length>0){if(k.length>0){y+='<div class="action-group critical">',y+='<h3 class="action-title critical">\u{1F534} Critical Risk</h3>';for(let o of k){let s=X(o.age),h=Z(o.behindByDays),f=o.risk==="Major"?"Major update":o.risk==="Minor"?"Minor update":"Patch update",b=C(o.note),u=b?`<span class="badge badge-${b}">${b.toUpperCase()}</span>`:"",$=o.note?R(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"";y+=`
52
+ </html>`;let c=r??e.length,a=F(e,c),k=[...e].sort((o,i)=>{let h={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},f=(h[o.risk]||99)-(h[i.risk]||99);return f!==0?f:o.age===null&&i.age===null?0:o.age===null?1:i.age===null?-1:i.age-o.age}),u=k.map(o=>({pkg:o,score:O(o)})).filter(({score:o})=>o>15).sort((o,i)=>i.score-o.score).slice(0,7).map(({pkg:o})=>o),$=u.filter(o=>O(o)>=20||o.risk==="Major"||o.note&&/BLOCKED/i.test(o.note)),d=u.filter(o=>!$.includes(o)),y="";if(u.length>0){if($.length>0){y+='<div class="action-group critical">',y+='<h3 class="action-title critical">\u{1F534} Critical Risk</h3>';for(let o of $){let i=X(o.age),h=Z(o.behindByDays),f=o.risk==="Major"?"Major update":o.risk==="Minor"?"Minor update":"Patch update",b=C(o.note),p=b?`<span class="badge badge-${b}">${b.toUpperCase()}</span>`:"",w=o.note?M(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"";y+=`
86
53
  <div class="package-card">
87
54
  <div class="package-header">
88
- <strong>${R(o.name)}</strong> (${R(o.current)} \u2192 ${R(o.latest)})
55
+ <strong>${M(o.name)}</strong> (${M(o.current)} \u2192 ${M(o.latest)})
89
56
  </div>
90
57
  <div class="package-details">
91
- ${s} old, behind by ${h} | ${f}
92
- ${u?`<br>${u} ${$?R($):""}`:""}
58
+ ${i} old, behind by ${h} | ${f}
59
+ ${p?`<br>${p} ${w?M(w):""}`:""}
93
60
  </div>
94
- </div>`}y+="</div>"}if(c.length>0){y+='<div class="action-group review">',y+='<h3 class="action-title review">\u{1F7E1} Review Soon</h3>';for(let o of c){let s=X(o.age),h=Z(o.behindByDays),f=o.risk==="Major"?"Major update":o.risk==="Minor"?"Minor update":"Patch update",b=C(o.note),u=b?`<span class="badge badge-${b}">${b.toUpperCase()}</span>`:"",$=o.note?R(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"";y+=`
61
+ </div>`}y+="</div>"}if(d.length>0){y+='<div class="action-group review">',y+='<h3 class="action-title review">\u{1F7E1} Review Soon</h3>';for(let o of d){let i=X(o.age),h=Z(o.behindByDays),f=o.risk==="Major"?"Major update":o.risk==="Minor"?"Minor update":"Patch update",b=C(o.note),p=b?`<span class="badge badge-${b}">${b.toUpperCase()}</span>`:"",w=o.note?M(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"";y+=`
95
62
  <div class="package-card">
96
63
  <div class="package-header">
97
- <strong>${R(o.name)}</strong> (${R(o.current)} \u2192 ${R(o.latest)})
64
+ <strong>${M(o.name)}</strong> (${M(o.current)} \u2192 ${M(o.latest)})
98
65
  </div>
99
66
  <div class="package-details">
100
- ${s} old, behind by ${h} | ${f}
101
- ${u?`<br>${u} ${$?R($):""}`:""}
67
+ ${i} old, behind by ${h} | ${f}
68
+ ${p?`<br>${p} ${w?M(w):""}`:""}
102
69
  </div>
103
- </div>`}y+="</div>"}}else y='<div class="no-actions">\u2705 No critical actions required</div>';let d="";for(let o of w){let s=X(o.age),h=Z(o.behindByDays),f=Ve(o.risk),b=A(o)?'<span class="status-stable">\u2705 Stable</span>':"Outdated",u=C(o.note),$=u?`<span class="badge badge-${u}">${u.toUpperCase()}</span>`:"",E=o.note?R(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"",M=$&&E?`${$} ${E}`:$||E||"";d+=`
70
+ </div>`}y+="</div>"}}else y='<div class="no-actions">\u2705 No critical actions required</div>';let m="";for(let o of k){let i=X(o.age),h=Z(o.behindByDays),f=ft(o.risk),b=A(o)?'<span class="status-stable">\u2705 Stable</span>':"Outdated",p=C(o.note),w=p?`<span class="badge badge-${p}">${p.toUpperCase()}</span>`:"",E=o.note?M(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"",R=w&&E?`${w} ${E}`:w||E||"";m+=`
104
71
  <tr>
105
- <td class="package-name">${R(o.name)}</td>
106
- <td>${R(o.current)}</td>
107
- <td>${R(o.latest)}</td>
108
- <td>${R(s)}</td>
109
- <td>${R(h)}</td>
110
- <td><span class="risk-badge" style="background-color: ${f}">${R(o.risk)}</span></td>
72
+ <td class="package-name">${M(o.name)}</td>
73
+ <td>${M(o.current)}</td>
74
+ <td>${M(o.latest)}</td>
75
+ <td>${M(i)}</td>
76
+ <td>${M(h)}</td>
77
+ <td><span class="risk-badge" style="background-color: ${f}">${M(o.risk)}</span></td>
111
78
  <td>${b}</td>
112
- <td class="notes">${M}</td>
79
+ <td class="notes">${R}</td>
113
80
  </tr>`}let g=a.riskStatus==="healthy"?"#10b981":a.riskStatus==="degrading"?"#f59e0b":"#ef4444";return`<!DOCTYPE html>
114
81
  <html lang="en">
115
82
  <head>
@@ -326,7 +293,7 @@ Total: ${a.total} | Outdated: ${a.outdated} | Stale: ${a.stale} | Up-to-date: ${
326
293
  <body>
327
294
  <div class="container">
328
295
  <h1>Dependency Report (${n})</h1>
329
- <div class="timestamp">Generated at: ${i}</div>
296
+ <div class="timestamp">Generated at: ${s}</div>
330
297
 
331
298
  <div class="status-badge">
332
299
  ${a.riskStatusEmoji} ${a.riskStatusText}
@@ -389,18 +356,52 @@ Total: ${a.total} | Outdated: ${a.outdated} | Stale: ${a.stale} | Up-to-date: ${
389
356
  </tr>
390
357
  </thead>
391
358
  <tbody>
392
- ${d}
359
+ ${m}
393
360
  </tbody>
394
361
  </table>
395
362
  </div>
396
363
  </body>
397
- </html>`}import{existsSync as ge,access as Qe,constants as Xe,mkdirSync as Ze,writeFileSync as et,unlinkSync as tt}from"fs";import{join as he}from"path";import{promisify as rt}from"util";var nt=rt(Qe);async function ye(e=process.cwd()){let t=he(e,"node_modules");if(!ge(t))throw new Error('node_modules directory not found. Please run "npm install", "pnpm install", or "bun install" first.')}async function be(e){if(!ge(e))try{Ze(e,{recursive:!0})}catch(r){throw new Error(`Cannot create directory ${e}: ${r instanceof Error?r.message:String(r)}`)}try{await nt(e,Xe.W_OK)}catch{throw new Error(`No write permission for directory: ${e}`)}let t=he(e,`.write-test-${Date.now()}.tmp`);try{et(t,"ok"),tt(t)}catch(r){throw new Error(`Cannot write to directory ${e}: ${r instanceof Error?r.message:String(r)}`)}}function H(e,t){try{return JSON.parse(e)}catch(r){throw r instanceof SyntaxError?new Error(`Invalid JSON in ${t}: ${r.message}`):r}}var j={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"},ke=["-","\\","|","/"],K=null,$e="",l={info:e=>{console.log(`${j.cyan}[INFO]${j.reset} ${e}`)},success:e=>{console.log(`${j.green}${j.bright}[OK]${j.reset} ${j.green}${e}${j.reset}`)},warn:e=>{console.warn(`${j.yellow}[WARN]${j.reset} ${e}`)},error:e=>{console.error(`${j.red}${j.bright}[ERR]${j.reset} ${j.red}${e}${j.reset}`)},progress:(e,t,r)=>{let n=Math.round(e/t*100);process.stdout.write(`\r${j.cyan}${r}${j.reset} ${j.dim}(${e}/${t}, ${n}%)${j.reset}`),e===t&&process.stdout.write(`
398
- `)},startSpinner:e=>{$e=e;let t=0;K=setInterval(()=>{process.stdout.write(`\r${j.cyan}${ke[t]}${j.reset} ${$e}`),t=(t+1)%ke.length},100)},stopSpinner:()=>{K&&(clearInterval(K),K=null,process.stdout.write("\r"+" ".repeat(process.stdout.columns||80)+"\r"))}};import{format as Fe}from"date-fns";import{existsSync as st,readFileSync as at}from"fs";import{join as it}from"path";import{z as D}from"zod";var P={staleThreshold:"18 months",ignorePatterns:[],formats:{markdown:!0,html:!0},concurrency:5,failConditions:{stale:!1,major:!1},reportEmptyState:!0},ot=D.object({staleThreshold:D.string().default(P.staleThreshold),ignorePatterns:D.array(D.string()).default(P.ignorePatterns),formats:D.object({markdown:D.boolean().default(P.formats.markdown),html:D.boolean().default(P.formats.html)}).default(P.formats),concurrency:D.number().int().positive().default(P.concurrency),failConditions:D.object({stale:D.boolean().default(P.failConditions.stale),major:D.boolean().default(P.failConditions.major)}).default(P.failConditions),reportEmptyState:D.boolean().default(P.reportEmptyState)}).passthrough();function we(e){try{return ot.parse(e)}catch(t){if(t instanceof D.ZodError){let r=t.errors.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ");throw new Error(`Invalid config: ${r}`)}throw t}}function Se(e=process.cwd()){let t=it(e,".dep-report","config.json");if(!st(t))return l.info("No config.json found, using defaults"),P;try{let r=at(t,"utf-8"),n=H(r,t),i={staleThreshold:n.staleThreshold??P.staleThreshold,ignorePatterns:n.ignorePatterns??P.ignorePatterns,formats:{markdown:n.formats?.markdown??P.formats.markdown,html:n.formats?.html??P.formats.html},concurrency:n.concurrency??P.concurrency,failConditions:{stale:n.failConditions?.stale??P.failConditions.stale,major:n.failConditions?.major??P.failConditions.major},reportEmptyState:n.reportEmptyState??P.reportEmptyState},m=we(i);return l.info("Loaded config from .dep-report/config.json"),m}catch(r){return l.warn(`Failed to load config: ${r instanceof Error?r.message:String(r)}`),l.warn("Using default configuration"),P}}function ct(e){let r=e.trim().toLowerCase().match(/^(\d+)\s+(year|years|month|months|day|days|week|weeks)$/);if(!r)throw new Error(`Invalid duration format: "${e}". Expected format: "18 months", "2 years", "90 days", etc.`);let n=parseInt(r[1],10),i=r[2];switch(i){case"day":case"days":return n*24*60*60*1e3;case"week":case"weeks":return n*7*24*60*60*1e3;case"month":case"months":return n*30*24*60*60*1e3;case"year":case"years":return n*365*24*60*60*1e3;default:throw new Error(`Unsupported time unit: ${i}`)}}function Pe(e){let t=ct(e);return Math.floor(t/(1e3*60*60*24))}import{existsSync as dt,readFileSync as lt}from"fs";import{join as mt}from"path";function xe(e=process.cwd()){let t=mt(e,".dep-report","notes.json");if(!dt(t))return{};try{let r=lt(t,"utf-8"),n=H(r,t);if(typeof n!="object"||n===null||Array.isArray(n))return l.warn("Invalid notes.json format, expected object"),{};for(let[i,m]of Object.entries(n))typeof m!="string"&&(l.warn(`Invalid note for ${i}, expected string`),delete n[i]);return l.info(`Loaded ${Object.keys(n).length} notes from notes.json`),n}catch(r){return l.warn(`Failed to load notes: ${r instanceof Error?r.message:String(r)}`),{}}}function je(e,t){return e.map(r=>{let n=t[r.name];return n?{...r,note:n}:r})}import{minimatch as ut}from"minimatch";function Ee(e,t){return t.length===0?e:e.filter(r=>{for(let n of t)if(ut(r.name,n))return!1;return!0})}import{existsSync as U,mkdirSync as Re,writeFileSync as te}from"fs";import{join as B}from"path";async function Me(e=process.cwd(),t=!1,r){let n=B(e,".dep-report"),i=B(n,"config.json"),m=B(n,"notes.json"),a=B(n,"reports"),w=B(n,".gitignore");if(U(n)?l.info(".dep-report/ directory already exists"):(Re(n,{recursive:!0}),l.success("Created .dep-report/ directory")),U(a)||(Re(a,{recursive:!0}),l.success("Created .dep-report/reports/ directory")),!U(i)||t){let p=P;if(r){let c=oe(r);p=c.config,l.info(`Using preset: ${c.displayName} - ${c.description}`)}let k=JSON.stringify(p,null,2);te(i,k,"utf-8"),l.success("Created .dep-report/config.json")}else l.info("config.json already exists, skipping");if(U(m))l.info("notes.json already exists, skipping");else{let p=JSON.stringify({},null,2);te(m,p,"utf-8"),l.success("Created .dep-report/notes.json")}U(w)?l.info(".gitignore already exists, skipping"):(te(w,`.cache.json
399
- `,"utf-8"),l.success("Created .dep-report/.gitignore")),l.success("Initialization complete!"),l.info("You can now customize .dep-report/config.json and add notes to .dep-report/notes.json")}import{readFileSync as De,existsSync as re,readdirSync as pt}from"fs";import{join as J}from"path";import{format as ft,parse as W,subDays as gt,differenceInDays as ne}from"date-fns";function ve(e,t){let r=e.match(/\| Package \|.*?\n\|-+\|\n([\s\S]*?)\n\n/);if(!r)return null;let n=r[1].trim().split(`
400
- `),i=[];for(let c of n){let y=c.split("|").map(S=>S.trim()).filter(S=>S);if(y.length<6)continue;let[d,g,o,s,h,f,b,u]=y;if(b.includes("Stable"))continue;let $=null;if(s&&s!=="Unknown"){let S=s.match(/(\d+)d|(\d+)m|(\d+)y/);S&&(S[1]?$=parseInt(S[1]):S[2]?$=parseInt(S[2])*30:S[3]&&($=parseInt(S[3])*365))}let E=null;if(h&&h!=="\u2014"){let S=h.match(/(\d+)d|(\d+)m|(\d+)y/);S&&(S[1]?E=parseInt(S[1]):S[2]?E=parseInt(S[2])*30:S[3]&&(E=parseInt(S[3])*365))}let M="Patch";f.includes("Major")?M="Major":f.includes("Minor")?M="Minor":f.includes("Patch")?M="Patch":f.includes("Exotic")?M="Exotic":f.includes("NotInstalled")&&(M="NotInstalled"),i.push({name:d,current:g,latest:o,wanted:o,type:"dependencies",currentPublishedAt:null,latestPublishedAt:null,age:$,behindByDays:E,isStale:$!==null&&$>365,risk:M,note:u||void 0})}let m=e.match(/Total: (\d+) \| Outdated: (\d+) \| Stale: (\d+)/),a=m?parseInt(m[1]):i.length,w=m?parseInt(m[2]):i.length,p=m?parseInt(m[3]):i.filter(c=>c.isStale).length,k=i.filter(c=>c.risk==="Major").length;return{date:t,packages:i,summary:{total:a,outdated:w,stale:p,major:k}}}function Ce(e,t){if(t==="latest"){let r=J(e,"latest.md");return re(r)?r:null}if(t==="last-month"){let n=gt(new Date,30),i=pt(e).filter(m=>m.endsWith("_outdated.md")).map(m=>{let a=m.match(/(\d{4}-\d{2}-\d{2})_outdated\.md/);return a?{file:m,date:W(a[1],"yyyy-MM-dd",new Date)}:null}).filter(m=>m!==null).sort((m,a)=>Math.abs(ne(m.date,n))-Math.abs(ne(a.date,n)));return i.length>0?J(e,i[0].file):null}try{let r=W(t,"yyyy-MM-dd",new Date),n=ft(r,"yyyy-MM-dd"),i=J(e,`${n}_outdated.md`);if(re(i))return i}catch{}return null}function Oe(e){return 100-e.stale*5-e.major*3}async function Te(e,t,r=process.cwd()){let n=J(r,".dep-report","reports");re(n)||(l.error("No reports directory found. Run dep-report first to generate reports."),process.exit(1));let i=Ce(n,e),m=Ce(n,t);i||(l.error(`Report not found for: ${e}`),process.exit(1)),m||(l.error(`Report not found for: ${t}`),process.exit(1));let a=De(i,"utf-8"),w=De(m,"utf-8"),p=i.match(/(\d{4}-\d{2}-\d{2})_outdated\.md/),k=m.match(/(\d{4}-\d{2}-\d{2})_outdated\.md/),c=p?p[1]:e,y=k?k[1]:t,d=ve(a,c),g=ve(w,y);(!d||!g)&&(l.error("Failed to parse reports"),process.exit(1));let o=ne(W(y,"yyyy-MM-dd",new Date),W(c,"yyyy-MM-dd",new Date)),s=g.summary.stale-d.summary.stale,h=g.summary.major-d.summary.major,f=new Set(d.packages.map(x=>x.name)),b=new Set(g.packages.map(x=>x.name)),u=g.packages.filter(x=>!f.has(x.name)),$=d.packages.filter(x=>!b.has(x.name)),E=g.packages.filter(x=>{let _=d.packages.find(G=>G.name===x.name);return _&&_.current!==x.current}),M=Oe(d.summary),S=Oe(g.summary),N=M>0?(S-M)/M*100:0;if(console.log(`
401
- Dependency Health Comparison`),console.log(`From: ${c} \u2192 ${y} (${o} days)
402
- `),E.length>0){console.log("\u{1F4C8} Improvements:");for(let x of E.slice(0,5)){let _=d.packages.find(G=>G.name===x.name);console.log(` \u2022 ${x.name}: ${_?.current} \u2192 ${x.current}`)}E.length>5&&console.log(` ... and ${E.length-5} more`),console.log("")}if(s!==0||h!==0){if(console.log("\u{1F4CA} Metrics:"),s!==0){let x=s>0?"+":"";console.log(` \u2022 Stale packages: ${d.summary.stale} \u2192 ${g.summary.stale} (${x}${s})`)}if(h!==0){let x=h>0?"+":"";console.log(` \u2022 Major upgrades pending: ${d.summary.major} \u2192 ${g.summary.major} (${x}${h})`)}console.log("")}u.length>0&&console.log(`\u2795 Added: ${u.map(x=>x.name).join(", ")}`),$.length>0&&console.log(`\u2796 Removed: ${$.map(x=>x.name).join(", ")}`),(u.length>0||$.length>0)&&console.log("");let Le=N>0?"\u2705":N<0?"\u26A0\uFE0F":"\u27A1\uFE0F",Ue=N>0?"improved":N<0?"regressed":"unchanged";console.log(`${Le} Overall: Health ${Ue} by ${Math.abs(N).toFixed(1)}%`),console.log(` Score: ${M.toFixed(1)} \u2192 ${S.toFixed(1)}
403
- `),process.exit(N<0?1:0)}var ht="https://registry.npmjs.org";async function Ne(e=ht,t=5e3){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{let i=`${e}/lodash`;return(await fetch(i,{headers:{Accept:"application/json"},signal:r.signal})).ok}catch{return!1}finally{clearTimeout(n)}}import{readFileSync as yt,existsSync as bt}from"fs";import{join as kt}from"path";function Y(e=process.cwd()){let t=kt(e,"package.json");if(!bt(t))return 0;try{let r=yt(t,"utf-8"),n=JSON.parse(r),i=Object.keys(n.dependencies||{}).length,m=Object.keys(n.devDependencies||{}).length,a=Object.keys(n.peerDependencies||{}).length,w=Object.keys(n.optionalDependencies||{}).length;return i+m+a+w}catch{return 0}}var z=new $t,St=new URL("../package.json",import.meta.url),Pt=JSON.parse(wt(St,"utf-8")),xt=Pt.version??"0.0.0";z.name("dep-report").description("Generate dependency risk reports").version(xt).addHelpText("before",`
364
+ </html>`}import{format as Te}from"date-fns";function te(e){if(e===null)return"Unknown";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function re(e){if(e===null)return"\u2014";if(e<30)return`${e}d`;if(e<365)return`${Math.floor(e/30)}m`;let t=Math.floor(e/365),r=Math.floor(e%365/30);return r>0?`${t}y ${r}m`:`${t}y`}function ne(e,t=new Date,r){let n=Te(t,"yyyy-MM-dd"),s=Te(t,"yyyy-MM-dd HH:mm:ss");if(e.length===0)return`# Dependency Report (${n})
365
+
366
+ Generated at: ${s}
367
+
368
+ \u2705 All dependencies are up to date
369
+ `;let c=r??e.length,a=F(e,c),k=[...e].sort((d,y)=>{let m={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},g=(m[d.risk]||99)-(m[y.risk]||99);return g!==0?g:d.age===null&&y.age===null?0:d.age===null?1:y.age===null?-1:y.age-d.age}),u=`# Dependency Report (${n})
370
+
371
+ Generated at: ${s}
372
+
373
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
374
+ ${a.riskStatusEmoji} ${a.riskStatusText}
375
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
376
+
377
+ Total: ${a.total} | Outdated: ${a.outdated} | Stale: ${a.stale} | Up-to-date: ${a.upToDate}
378
+ `;(a.blocked>0||a.deferred>0||a.accepted>0)&&(u+=`Blocked: ${a.blocked} | Deferred: ${a.deferred} | Accepted Risk: ${a.accepted}
379
+ `),u+=`
380
+ **Risk Assessment:** ${a.stale} stale dependencies and ${a.major} unaddressed major upgrades detected.
381
+
382
+ `;let $=k.map(d=>({pkg:d,score:O(d)})).filter(({score:d})=>d>15).sort((d,y)=>y.score-d.score).slice(0,7).map(({pkg:d})=>d);if($.length>0){u+=`\u2501\u2501\u2501 ACTION REQUIRED \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
383
+
384
+ `;let d=$.filter(m=>O(m)>=20||m.risk==="Major"||m.note&&/BLOCKED/i.test(m.note)),y=$.filter(m=>!d.includes(m));if(d.length>0){u+=`\u{1F534} Critical Risk
385
+ `;for(let m of d){let g=te(m.age),o=re(m.behindByDays),i=m.risk==="Major"?"Major update":m.risk==="Minor"?"Minor update":"Patch update",h=m.note?`
386
+ ${I(m.note)}`:"";u+=` \u2022 ${m.name} (${m.current} \u2192 ${m.latest})
387
+ `,u+=` ${g} old, behind by ${o} | ${i}${h}
388
+
389
+ `}}if(y.length>0){u+=`\u{1F7E1} Review Soon
390
+ `;for(let m of y){let g=te(m.age),o=re(m.behindByDays),i=m.risk==="Major"?"Major update":m.risk==="Minor"?"Minor update":"Patch update",h=m.note?`
391
+ ${I(m.note)}`:"";u+=` \u2022 ${m.name} (${m.current} \u2192 ${m.latest})
392
+ `,u+=` ${g} old, behind by ${o} | ${i}${h}
393
+
394
+ `}}u+=`
395
+ `}else u+=`\u2501\u2501\u2501 ACTION REQUIRED \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
396
+
397
+ `,u+=`\u2705 No critical actions required
398
+
399
+ `;u+=`\u2501\u2501\u2501 FULL DEPENDENCY LIST \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
400
+
401
+ `,u+=`| Package | Current | Latest | Age | Behind | Risk | Status | Notes |
402
+ `,u+=`|---------|---------|--------|-----|---------|------|--------|-------|
403
+ `;for(let d of k){let y=te(d.age),m=re(d.behindByDays),g=d.risk==="Major"?"\u{1F534} Major":d.risk==="Minor"?"\u{1F7E1} Minor":d.risk==="Patch"?"\u{1F7E2} Patch":d.risk,o=A(d)?"\u2705 Stable":"Outdated",i=d.note?I(d.note):"";u+=`| ${d.name} | ${d.current} | ${d.latest} | ${y} | ${m} | ${g} | ${o} | ${i} |
404
+ `}return u}import{minimatch as gt}from"minimatch";function Ne(e,t){return t.length===0?e:e.filter(r=>{for(let n of t)if(gt(r.name,n))return!1;return!0})}var ht="https://registry.npmjs.org";async function Ie(e=ht,t=5e3){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{let s=`${e}/lodash`;return(await fetch(s,{headers:{Accept:"application/json"},signal:r.signal})).ok}catch{return!1}finally{clearTimeout(n)}}import{readFileSync as yt,existsSync as bt}from"fs";import{join as kt}from"path";function Y(e=process.cwd()){let t=kt(e,"package.json");if(!bt(t))return 0;try{let r=yt(t,"utf-8"),n=JSON.parse(r),s=Object.keys(n.dependencies||{}).length,c=Object.keys(n.devDependencies||{}).length,a=Object.keys(n.peerDependencies||{}).length,k=Object.keys(n.optionalDependencies||{}).length;return s+c+a+k}catch{return 0}}function $t(e){let r=e.trim().toLowerCase().match(/^(\d+)\s+(year|years|month|months|day|days|week|weeks)$/);if(!r)throw new Error(`Invalid duration format: "${e}". Expected format: "18 months", "2 years", "90 days", etc.`);let n=parseInt(r[1],10),s=r[2];switch(s){case"day":case"days":return n*24*60*60*1e3;case"week":case"weeks":return n*7*24*60*60*1e3;case"month":case"months":return n*30*24*60*60*1e3;case"year":case"years":return n*365*24*60*60*1e3;default:throw new Error(`Unsupported time unit: ${s}`)}}function Ae(e){let t=$t(e);return Math.floor(t/(1e3*60*60*24))}var z=new wt,Pt=new URL("../package.json",import.meta.url),xt=JSON.parse(St(Pt,"utf-8")),jt=xt.version??"0.0.0";z.name("dep-report").description("Generate dependency risk reports").version(jt).addHelpText("before",`
404
405
  dep-report - Generate dependency risk reports
405
406
 
406
407
  USAGE
@@ -421,8 +422,8 @@ EXAMPLES
421
422
 
422
423
  LEARN MORE
423
424
  https://github.com/hussmarsidi/dep-reports
424
- `);z.command("init").description("Scaffold .dep-report/ directory structure").option("--include-config","Force overwrite config.json even if it exists").option("--preset <preset>","Use a preset configuration (starter|production|strict)","production").action(async e=>{try{let{isValidPresetName:t}=await import("./presets-BJSOBSDA.js"),r;e.preset&&(t(e.preset)||(l.error(`Invalid preset: ${e.preset}. Valid options: starter, production, strict`),process.exit(1)),r=e.preset),await Me(process.cwd(),e.includeConfig,r),process.exit(0)}catch(t){l.error(t instanceof Error?t.message:String(t)),process.exit(1)}});z.command("compare").description("Compare two dependency reports to track health over time").argument("<from>",'Start date (YYYY-MM-DD), "latest", or "last-month"').argument("<to>",'End date (YYYY-MM-DD) or "latest"').action(async(e,t)=>{try{await Te(e,t)}catch(r){l.error(r instanceof Error?r.message:String(r)),process.exit(1)}});z.option("--dry-run [level]","Preview summary without writing files (summary|actions|full)","actions").action(async e=>{try{let t=process.cwd(),r=Se(t);l.info("Checking prerequisites..."),await ye(t);let n=v(t,".dep-report");await be(n),l.info("Detecting package manager...");let i=se(t);i||(l.error("No package manager detected. Please ensure you have package-lock.json, pnpm-lock.yaml, bun.lock, or bun.lockb in your project."),process.exit(1)),l.success(`Detected: ${i.manager}`),l.info("Scanning for outdated packages...");let m=await ie(i.manager,t);if(Object.keys(m).length===0){if(l.success("No outdated packages found!"),r.reportEmptyState){let o=v(t,".dep-report","reports");Ie(o)||Ae(o,{recursive:!0});let s=Fe(new Date,"yyyy-MM-dd"),h=Y(t);if(r.formats.markdown){let f=Q([],new Date,h);T(v(o,`${s}_outdated.md`),f),T(v(o,"latest.md"),f),l.success(`Report generated: .dep-report/reports/${s}_outdated.md`)}if(r.formats.html){let f=ee([],new Date,h);T(v(o,`${s}_outdated.html`),f),T(v(o,"latest.html"),f),l.success(`HTML report generated: .dep-report/reports/${s}_outdated.html`)}}process.exit(0)}l.info(`Found ${Object.keys(m).length} outdated packages`);let a=ce(m);l.startSpinner("Checking registry connectivity...");let w=await Ne();l.stopSpinner(),w||(l.error("Unable to reach the npm registry."),l.info("If you have a cache, try running with --refresh."),process.exit(1)),l.success("Registry connectivity confirmed"),l.startSpinner(`Enriching ${a.length} packages with registry metadata...`);let p=await le(a,r.concurrency);l.stopSpinner(),l.success("Enrichment complete");let k=Pe(r.staleThreshold),c=ue(p,k),y=c.length;c=Ee(c,r.ignorePatterns),y>c.length&&l.info(`Filtered out ${y-c.length} packages based on ignorePatterns`);let d=xe(t);if(c=je(c,d),e.dryRun){let o=Y(t),s=F(c,o),h=typeof e.dryRun=="string"?e.dryRun:"actions";if(console.log(`
425
- Dry Run Summary`),console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(`Status: ${s.riskStatusEmoji} ${s.riskStatusText}
426
- `),console.log(`Total dependencies: ${s.total}`),console.log(`Outdated: ${s.outdated} (${s.major} major, ${s.minor} minor, ${s.patch} patch)`),console.log(`Stale (>12 months): ${s.stale}
427
- `),h==="actions"||h==="full"){let b=c.map(u=>({pkg:u,score:O(u)})).filter(({score:u})=>u>15).sort((u,$)=>$.score-u.score).slice(0,7).map(({pkg:u})=>u);if(b.length>0){console.log("Action Required:");for(let u of b){let $=u.age!==null?`${u.age}d`:"Unknown",E=u.behindByDays!==null?`${u.behindByDays}d`:"\u2014",M=u.note?I(u.note):"",S=u.risk==="Major"?"\u{1F534}":u.risk==="Minor"?"\u{1F7E1}":"\u{1F7E2}";console.log(` ${S} ${u.name} (${$}, behind by ${E}) - ${u.risk} ${u.current} \u2192 ${u.latest}${M?`, ${M}`:""}`)}console.log("")}}if(h==="full"){console.log("Full Dependency List:");for(let b of c){let u=b.age!==null?`${b.age}d`:"Unknown",$=b.behindByDays!==null?`${b.behindByDays}d`:"\u2014",E=A(b)?"\u2705 Stable":"Outdated";console.log(` ${b.name}: ${b.current} \u2192 ${b.latest} (${u}, ${$}, ${b.risk}, ${E})`)}console.log("")}console.log(`[No files written]
428
- `);let f=!1;r.failConditions.stale&&c.some(u=>u.isStale)&&(l.error("Found stale packages (--fail-if-stale)"),f=!0),r.failConditions.major&&c.some(u=>u.risk==="Major")&&(l.error("Found major version updates (--fail-if-major)"),f=!0),process.exit(f?1:0)}if(r.formats.markdown||r.formats.html){l.info("Generating reports...");let o=v(t,".dep-report","reports");Ie(o)||Ae(o,{recursive:!0});let s=Fe(new Date,"yyyy-MM-dd"),h=Y(t);if(r.formats.markdown){let f=Q(c,new Date,h);T(v(o,`${s}_outdated.md`),f),T(v(o,"latest.md"),f),l.success(`Report generated: .dep-report/reports/${s}_outdated.md`),l.success("Latest report: .dep-report/reports/latest.md")}if(r.formats.html){let f=ee(c,new Date,h);T(v(o,`${s}_outdated.html`),f),T(v(o,"latest.html"),f),l.success(`HTML report generated: .dep-report/reports/${s}_outdated.html`),l.success("Latest HTML report: .dep-report/reports/latest.html")}}let g=!1;r.failConditions.stale&&c.some(s=>s.isStale)&&(l.error("Found stale packages (--fail-if-stale)"),g=!0),r.failConditions.major&&c.some(s=>s.risk==="Major")&&(l.error("Found major version updates (--fail-if-major)"),g=!0),process.exit(g?1:0)}catch(t){l.error(t instanceof Error?t.message:String(t)),process.exit(1)}});z.parse();
425
+ `);z.command("init").description("Scaffold .dep-report/ directory structure").option("--include-config","Force overwrite config.json even if it exists").option("--preset <preset>","Use a preset configuration (starter|production|strict)","production").action(async e=>{try{let{isValidPresetName:t}=await import("./presets-BJSOBSDA.js"),r;e.preset&&(t(e.preset)||(l.error(`Invalid preset: ${e.preset}. Valid options: starter, production, strict`),process.exit(1)),r=e.preset),await fe(process.cwd(),e.includeConfig,r),process.exit(0)}catch(t){l.error(t instanceof Error?t.message:String(t)),process.exit(1)}});z.command("compare").description("Compare two dependency reports to track health over time").argument("<from>",'Start date (YYYY-MM-DD), "latest", or "last-month"').argument("<to>",'End date (YYYY-MM-DD) or "latest"').action(async(e,t)=>{try{await me(e,t)}catch(r){l.error(r instanceof Error?r.message:String(r)),process.exit(1)}});z.option("--dry-run [level]","Preview summary without writing files (summary|actions|full)","actions").action(async e=>{try{let t=process.cwd(),r=ke(t);l.info("Checking prerequisites..."),l.info("Detecting package manager...");let n=Se(t);n||(l.error("No package manager detected. Please ensure you have package-lock.json, pnpm-lock.yaml, bun.lock, or bun.lockb in your project."),process.exit(1)),l.success(`Detected: ${n.manager}`),await ye(t,!!n,l.warn);let s=v(t,".dep-report");await be(s),l.info("Scanning for outdated packages...");let c=await De(n.manager,t);if(Object.keys(c).length===0){if(l.success("No outdated packages found!"),r.reportEmptyState){let o=v(t,".dep-report","reports");Le(o)||Be(o,{recursive:!0});let i=Fe(new Date,"yyyy-MM-dd"),h=Y(t);if(r.formats.markdown){let f=ne([],new Date,h);T(v(o,`${i}_outdated.md`),f),T(v(o,"latest.md"),f),l.success(`Report generated: .dep-report/reports/${i}_outdated.md`)}if(r.formats.html){let f=ee([],new Date,h);T(v(o,`${i}_outdated.html`),f),T(v(o,"latest.html"),f),l.success(`HTML report generated: .dep-report/reports/${i}_outdated.html`)}}process.exit(0)}l.info(`Found ${Object.keys(c).length} outdated packages`);let a=Me(c);l.startSpinner("Checking registry connectivity...");let k=await Ie();l.stopSpinner(),k||(l.error("Unable to reach the npm registry."),l.info("If you have a cache, try running with --refresh."),process.exit(1)),l.success("Registry connectivity confirmed"),l.startSpinner(`Enriching ${a.length} packages with registry metadata...`);let u=await je(a,r.concurrency);l.stopSpinner(),l.success("Enrichment complete");let $=Ae(r.staleThreshold),d=we(u,$),y=d.length;d=Ne(d,r.ignorePatterns),y>d.length&&l.info(`Filtered out ${y-d.length} packages based on ignorePatterns`);let m=ve(t);if(d=Ce(d,m),e.dryRun){let o=Y(t),i=F(d,o),h=typeof e.dryRun=="string"?e.dryRun:"actions";if(console.log(`
426
+ Dry Run Summary`),console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(`Status: ${i.riskStatusEmoji} ${i.riskStatusText}
427
+ `),console.log(`Total dependencies: ${i.total}`),console.log(`Outdated: ${i.outdated} (${i.major} major, ${i.minor} minor, ${i.patch} patch)`),console.log(`Stale (>12 months): ${i.stale}
428
+ `),h==="actions"||h==="full"){let b=d.map(p=>({pkg:p,score:O(p)})).filter(({score:p})=>p>15).sort((p,w)=>w.score-p.score).slice(0,7).map(({pkg:p})=>p);if(b.length>0){console.log("Action Required:");for(let p of b){let w=p.age!==null?`${p.age}d`:"Unknown",E=p.behindByDays!==null?`${p.behindByDays}d`:"\u2014",R=p.note?I(p.note):"",S=p.risk==="Major"?"\u{1F534}":p.risk==="Minor"?"\u{1F7E1}":"\u{1F7E2}";console.log(` ${S} ${p.name} (${w}, behind by ${E}) - ${p.risk} ${p.current} \u2192 ${p.latest}${R?`, ${R}`:""}`)}console.log("")}}if(h==="full"){console.log("Full Dependency List:");for(let b of d){let p=b.age!==null?`${b.age}d`:"Unknown",w=b.behindByDays!==null?`${b.behindByDays}d`:"\u2014",E=A(b)?"\u2705 Stable":"Outdated";console.log(` ${b.name}: ${b.current} \u2192 ${b.latest} (${p}, ${w}, ${b.risk}, ${E})`)}console.log("")}console.log(`[No files written]
429
+ `);let f=!1;r.failConditions.stale&&d.some(p=>p.isStale)&&(l.error("Found stale packages (--fail-if-stale)"),f=!0),r.failConditions.major&&d.some(p=>p.risk==="Major")&&(l.error("Found major version updates (--fail-if-major)"),f=!0),process.exit(f?1:0)}if(r.formats.markdown||r.formats.html){l.info("Generating reports...");let o=v(t,".dep-report","reports");Le(o)||Be(o,{recursive:!0});let i=Fe(new Date,"yyyy-MM-dd"),h=Y(t);if(r.formats.markdown){let f=ne(d,new Date,h);T(v(o,`${i}_outdated.md`),f),T(v(o,"latest.md"),f),l.success(`Report generated: .dep-report/reports/${i}_outdated.md`),l.success("Latest report: .dep-report/reports/latest.md")}if(r.formats.html){let f=ee(d,new Date,h);T(v(o,`${i}_outdated.html`),f),T(v(o,"latest.html"),f),l.success(`HTML report generated: .dep-report/reports/${i}_outdated.html`),l.success("Latest HTML report: .dep-report/reports/latest.html")}}let g=!1;r.failConditions.stale&&d.some(i=>i.isStale)&&(l.error("Found stale packages (--fail-if-stale)"),g=!0),r.failConditions.major&&d.some(i=>i.risk==="Major")&&(l.error("Found major version updates (--fail-if-major)"),g=!0),process.exit(g?1:0)}catch(t){l.error(t instanceof Error?t.message:String(t)),process.exit(1)}});z.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dep-report",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Zero-config CLI tool that generates version-controlled snapshots of dependency risk",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",