dep-report 0.0.1 → 0.0.3

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # dep-report
2
2
 
3
+ > **Turn your dependency chaos into a daily, version-controlled risk brief.**
4
+
3
5
  Zero-config CLI tool that generates version-controlled snapshots of dependency risk.
4
6
 
5
7
  ## Installation
@@ -18,7 +20,19 @@ Or use with npx (no installation needed):
18
20
  npx dep-report
19
21
  ```
20
22
 
21
- ## Quick Start
23
+ ## The Problem
24
+
25
+ Dependency drift is invisible until it explodes.
26
+
27
+ You get bombarded with automated PRs but can't tell which ones actually matter. No context, just version bumps. A security advisory drops and you're scrambling to figure out your exposure. A build breaks because some package hasn't been touched in 3 years. Management asks about technical debt and you're pulling together an answer on the spot.
28
+
29
+ The real issue isn't automation—it's visibility. You need to see what's outdated, understand the risk, and have evidence for your decisions. Not just a flood of PRs.
30
+
31
+ **Renovate/Dependabot create noise. dep-report creates evidence.**
32
+
33
+ ## The Solution
34
+
35
+ dep-report gives you a daily, human-readable risk brief, checked into your repo.
22
36
 
23
37
  Run in your project directory:
24
38
 
@@ -32,6 +46,15 @@ This will:
32
46
  3. Enrich with registry metadata (publish dates, age)
33
47
  4. Generate reports in `.dep-report/reports/`
34
48
 
49
+ ## The Outcome
50
+
51
+ You can see at a glance whether you're getting healthier or rotting.
52
+
53
+ **Proof Point:**
54
+ > "Six months ago we had 34 stale dependencies, 9 majors ignored. Today we're at 3 and 1—and we can prove it from the reports in `/.dep-report/reports`."
55
+
56
+ ## Quick Start
57
+
35
58
  ## Usage
36
59
 
37
60
  ### Initialize Configuration
@@ -118,18 +141,19 @@ Exit code conditions for CI/CD integration:
118
141
 
119
142
  Whether to generate reports when no outdated packages are found. Default: `true`.
120
143
 
121
- ### Notes
144
+ ### Notes (Decision Log)
122
145
 
123
- Add custom notes to packages in `.dep-report/notes.json`:
146
+ Transform tribal knowledge into auditable decisions. Add notes to packages in `.dep-report/notes.json`:
124
147
 
125
148
  ```json
126
149
  {
127
- "package-name": "Known issue: waiting for v2.0.0 release",
128
- "another-package": "Upgrade blocked by breaking changes"
150
+ "react": "BLOCKED: waiting for team migration",
151
+ "lodash": "DEFERRED: Q2 2026 - requires architecture refactor",
152
+ "axios": "ACCEPTED RISK: pinned for stability @platform-team"
129
153
  }
130
154
  ```
131
155
 
132
- Notes appear in reports next to the package entry.
156
+ Notes with keywords (`BLOCKED:`, `DEFERRED:`, `ACCEPTED RISK:`) are automatically highlighted in reports with badges, creating a self-documenting decision log.
133
157
 
134
158
  ## Usage Examples
135
159
 
@@ -210,6 +234,23 @@ The tool respects npm registry rate limits by:
210
234
 
211
235
  Age is calculated based on when the **currently installed version** was published, not when the latest version was published. This answers: "How old is the dependency we're actively using?"
212
236
 
237
+ ## Guarantees
238
+
239
+ **Privacy:**
240
+ - No tracking, no analytics, no phoning home
241
+ - All data stays local in your repository
242
+ - Registry queries are read-only package metadata
243
+
244
+ **Control:**
245
+ - Outputs are plain files under your version control
246
+ - No vendor lock-in, no proprietary formats
247
+ - Works offline with cached data
248
+
249
+ **Transparency:**
250
+ - Open source (MIT license)
251
+ - Readable templates, editable notes
252
+ - Deterministic output (same input = same report)
253
+
213
254
  ## Development
214
255
 
215
256
  ```bash
@@ -248,15 +289,3 @@ See [sandbox/README.md](sandbox/README.md) for details.
248
289
  2. Run `bun run test:sandbox` (must pass)
249
290
  3. Visually inspect HTML reports
250
291
  4. Run `npm run build` and test CLI manually
251
-
252
- ## Project Status
253
-
254
- ✅ **Production Ready**
255
- - ✅ Package manager detection (npm, pnpm, bun)
256
- - ✅ Outdated package scanning
257
- - ✅ Registry enrichment with age calculation
258
- - ✅ Risk & age calculation
259
- - ✅ Markdown & HTML report generation
260
- - ✅ Configuration system
261
- - ✅ Notes system
262
- - ✅ Comprehensive test suite
@@ -0,0 +1 @@
1
+ var t={starter:{name:"starter",displayName:"Starter",description:"Just getting visibility - no CI failures",config:{staleThreshold:"24 months",ignorePatterns:[],formats:{markdown:!0,html:!0},concurrency:5,failConditions:{stale:!1,major:!1},reportEmptyState:!0}},production:{name:"production",displayName:"Production",description:"Prevent major upgrades from rotting indefinitely (recommended)",config:{staleThreshold:"12 months",ignorePatterns:[],formats:{markdown:!0,html:!0},concurrency:5,failConditions:{stale:!1,major:!0},reportEmptyState:!0}},strict:{name:"strict",displayName:"Strict",description:"Old dependencies break builds",config:{staleThreshold:"6 months",ignorePatterns:[],formats:{markdown:!0,html:!0},concurrency:5,failConditions:{stale:!0,major:!0},reportEmptyState:!0}}};function r(e){return t[e]}function n(){return Object.values(t)}function s(e){return e in t}export{t as a,r as b,n as c,s as d};
package/dist/cli.js CHANGED
@@ -1,37 +1,122 @@
1
1
  #!/usr/bin/env node
2
- import{Command as At}from"commander";import{existsSync as ot,mkdirSync as nt,writeFileSync as k,readFileSync as Ft}from"fs";import{join as y}from"path";import{existsSync as at}from"fs";import{join as it}from"path";function D(t=process.cwd()){let e=[{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:o}of e){let s=it(t,r);if(at(s))return{manager:o,lockfile:r}}return null}function N(t){return{npm:"npm outdated --json",pnpm:"pnpm outdated --json",bun:"bun outdated --json"}[t]}import{exec as ct}from"child_process";import{promisify as dt}from"util";var lt=dt(ct);async function T(t,e=process.cwd()){let r=N(t);try{let{stdout:o,stderr:s}=await lt(r,{cwd:e,maxBuffer:10485760}),c=o.trim()||s.trim();if(!c)return{};try{return JSON.parse(c)}catch(i){if(c.includes("All packages are up to date")||c==="{}")return{};throw new Error(`Failed to parse outdated output: ${i instanceof Error?i.message:String(i)}`)}}catch(o){if(o.stdout)try{return JSON.parse(o.stdout)}catch{throw o.code==="ENOENT"?new Error(`Package manager "${t}" not found. Please install it first.`):new Error(`Failed to execute outdated command: ${o.message}`)}if(o.code==="ENOENT")throw new Error(`Package manager "${t}" not found. Please install it first.`);return{}}}function I(t){let e=[];for(let[r,o]of Object.entries(t)){if(typeof o!="object"||o===null||Array.isArray(o))continue;let s=o.current||o.installed||o.version||"-",c=o.latest||o.wanted||s,i=o.wanted||o.current||c,a=o.type||o.dependencyType||mt(r);!r||!c||e.push({name:r,current:String(s),wanted:String(i),latest:String(c),type:a})}return e}function mt(t){return t.startsWith("@types/")||t.includes("-test")||t.includes("-spec")||t==="typescript"||t==="eslint"||t.startsWith("eslint-")||t.startsWith("@eslint/")?"devDependencies":"dependencies"}var x=class{constructor(e="https://registry.npmjs.org"){this.baseUrl=e}async getMetadata(e){try{let r=`${this.baseUrl}/${encodeURIComponent(e)}`,o=await fetch(r,{headers:{Accept:"application/json"}});if(!o.ok){if(o.status===404)return null;throw new Error(`Registry request failed: ${o.status}`)}return await o.json()}catch{return null}}};var A=new x;async function pt(t,e=A,r=new Date){let s=await(typeof e=="string"?new x(e):e).getMetadata(t.name);if(!s||!s.time)return{...t,currentPublishedAt:null,latestPublishedAt:null,age:null,isStale:!1,risk:"Exotic"};let c=s.time[t.current]?new Date(s.time[t.current]):null,i=s.time[t.latest]?new Date(s.time[t.latest]):null,a=null;if(c){let p=r.getTime()-c.getTime();a=Math.floor(p/(1e3*60*60*24))}return{...t,currentPublishedAt:c,latestPublishedAt:i,age:a,isStale:!1,risk:"Exotic"}}async function F(t,e=5,r=A,o=new Date){let s=typeof r=="string"?new x(r):r,c=[];for(let i=0;i<t.length;i+=e){let a=t.slice(i,i+e),p=await Promise.all(a.map(d=>pt(d,s,o)));c.push(...p),i+e<t.length&&await new Promise(d=>setTimeout(d,500))}return c}import{diff as ut,valid as _}from"semver";function ft(t){return!t||t==="-"||t==="missing"?!1:/^(file:|git\+|https?:|link:|workspace:)/.test(t)}function gt(t,e){if(ft(t))return"Exotic";if(!t||t==="-"||t==="missing")return"NotInstalled";if(!_(t)||!_(e))return"Exotic";try{switch(ut(t,e)){case"major":return"Major";case"minor":return"Minor";case"patch":return"Patch";default:return"Patch"}}catch{return"Exotic"}}function L(t,e=null){return t.map(r=>{let o=gt(r.current,r.latest),s=e!==null&&r.age!==null&&r.age>e;return{...r,risk:o,isStale:s}})}import{format as z}from"date-fns";function ht(t){if(t===null)return"Unknown";if(t<30)return`${t}d`;if(t<365)return`${Math.floor(t/30)}m`;let e=Math.floor(t/365),r=Math.floor(t%365/30);return r>0?`${e}y ${r}m`:`${e}y`}function M(t,e=new Date){let r=z(e,"yyyy-MM-dd"),o=z(e,"yyyy-MM-dd HH:mm:ss");if(t.length===0)return`# Dependency Report (${r})
2
+ import{b as oe}from"./chunk-KNT3JZ7P.js";import{Command as wt}from"commander";import{existsSync as Fe,mkdirSync as Le,writeFileSync as T,readFileSync as St}from"fs";import{join as v}from"path";import{existsSync as _e}from"fs";import{join as He}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=He(e,r);if(_e(s))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 Ke}from"child_process";import{promisify as Je}from"util";var We=Je(Ke);function ie(e){if(!/\|\s*Package\s*\|/i.test(e))return null;let t=[],r=e.split(`
3
+ `).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 ce(e,t=process.cwd()){let r=ae(e);try{let{stdout:n,stderr:s}=await We(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=ie(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=ie(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{}}}function le(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||de(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||de(n);!n||!a||t.push({name:n,current:String(c),wanted:String(k),latest:String(a),type:u})}return t}function de(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 me=new L;async function Ye(e,t=me,r=new Date){let s=await(typeof t=="string"?new L(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 ue(e,t=5,r=me,n=new Date){let s=typeof r=="string"?new L(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($=>Ye($,s,n)));c.push(...u),a+t<e.length&&await new Promise($=>setTimeout($,500))}return c}import{diff as Ge,valid as pe}from"semver";function qe(e){return!e||e==="-"||e==="missing"?!1:/^(file:|git\+|https?:|link:|workspace:)/.test(e)}function Ve(e,t){if(qe(e))return"Exotic";if(!e||e==="-"||e==="missing")return"NotInstalled";if(!pe(e)||!pe(t))return"Exotic";try{switch(Ge(e,t)){case"major":return"Major";case"minor":return"Minor";case"patch":return"Patch";default:return"Patch"}}catch{return"Exotic"}}function fe(e,t=null){return e.map(r=>{let n=Ve(r.current,r.latest),s=t!==null&&r.age!==null&&r.age>t;return{...r,risk:n,isStale:s}})}import{format as ge}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,l="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?(l="atRisk",g="\u{1F534}",o=`At Risk (${Math.round(h)}% stale)`):h>=r.degrading.stalePercent||b>=r.degrading.majorPercent?(l="degrading",g="\u{1F7E1}",o=`Degrading (${Math.round(h)}% stale)`):(l="healthy",g="\u{1F7E2}",o="Healthy"):s>=r.atRisk.stalePercent||f>=r.atRisk.majorPercent?(l="atRisk",g="\u{1F534}",o=`At Risk (${s} stale)`):s>=r.degrading.stalePercent||f>=r.degrading.majorPercent?(l="degrading",g="\u{1F7E1}",o=`Degrading (${s} stale)`):(l="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?(l="atRisk",g="\u{1F534}",o=`At Risk (${Math.round(i)}% stale)`):i>=5||f>=10?(l="degrading",g="\u{1F7E1}",o=`Degrading (${Math.round(i)}% stale)`):(l="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:l,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=ge(t,"yyyy-MM-dd"),s=ge(t,"yyyy-MM-dd HH:mm:ss");if(e.length===0)return`# Dependency Report (${n})
3
4
 
4
- Generated at: ${o}
5
+ Generated at: ${s}
5
6
 
6
7
  \u2705 All dependencies are up to date
7
- `;let s=[...t].sort((i,a)=>{let p={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},d=(p[i.risk]||99)-(p[a.risk]||99);return d!==0?d:i.age===null&&a.age===null?0:i.age===null?1:a.age===null?-1:a.age-i.age}),c=`# Dependency Report (${r})
8
+ `;let c=r??e.length,a=F(e,c),k=[...e].sort((d,y)=>{let l={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},g=(l[d.risk]||99)-(l[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})
8
9
 
9
- Generated at: ${o}
10
+ Generated at: ${s}
10
11
 
11
- ## Outdated Packages (${t.length})
12
+ \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
13
+ ${a.riskStatusEmoji} ${a.riskStatusText}
14
+ \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
15
 
13
- | Package | Current | Latest | Risk | Age | Stale? | Notes |
14
- |---------|---------|--------|------|-----|--------|-------|
15
- `;for(let i of s){let a=ht(i.age),p=i.risk,d=i.isStale?"Yes":"No",w=i.note||"";c+=`| ${i.name} | ${i.current} | ${i.latest} | ${p} | ${a} | ${d} | ${w} |
16
- `}return c}import{format as U}from"date-fns";function b(t){let e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return t.replace(/[&<>"']/g,r=>e[r])}function yt(t){if(t===null)return"Unknown";if(t<30)return`${t}d`;if(t<365)return`${Math.floor(t/30)}m`;let e=Math.floor(t/365),r=Math.floor(t%365/30);return r>0?`${e}y ${r}m`:`${e}y`}function wt(t){switch(t){case"Major":return"#dc2626";case"Minor":return"#ea580c";case"Patch":return"#ca8a04";case"Exotic":return"#6b7280";case"NotInstalled":return"#9ca3af";default:return"#6b7280"}}function O(t,e=new Date){let r=U(e,"yyyy-MM-dd"),o=U(e,"yyyy-MM-dd HH:mm:ss"),s=[...t].sort((a,p)=>{let d={Major:0,Minor:1,Patch:2,Exotic:3,NotInstalled:4},w=(d[a.risk]||99)-(d[p.risk]||99);return w!==0?w:a.age===null&&p.age===null?0:a.age===null?1:p.age===null?-1:p.age-a.age}),c="";for(let a of s){let p=yt(a.age),d=wt(a.risk),w=a.isStale?"Yes":"No",C=a.isStale?"stale-yes":"stale-no",$=b(a.note||"");c+=`
17
- <tr>
18
- <td class="package-name">${b(a.name)}</td>
19
- <td>${b(a.current)}</td>
20
- <td>${b(a.latest)}</td>
21
- <td><span class="risk-badge" style="background-color: ${d}">${b(a.risk)}</span></td>
22
- <td>${b(p)}</td>
23
- <td class="${C}">${w}</td>
24
- <td class="notes">${$}</td>
25
- </tr>`}let i=t.length===0?`
16
+ Total: ${a.total} | Outdated: ${a.outdated} | Stale: ${a.stale} | Up-to-date: ${a.upToDate}
17
+ `;(a.blocked>0||a.deferred>0||a.accepted>0)&&(u+=`Blocked: ${a.blocked} | Deferred: ${a.deferred} | Accepted Risk: ${a.accepted}
18
+ `),u+=`
19
+ **Risk Assessment:** ${a.stale} stale dependencies and ${a.major} unaddressed major upgrades detected.
20
+
21
+ `;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
22
+
23
+ `;let d=$.filter(l=>O(l)>=20||l.risk==="Major"||l.note&&/BLOCKED/i.test(l.note)),y=$.filter(l=>!d.includes(l));if(d.length>0){u+=`\u{1F534} Critical Risk
24
+ `;for(let l of d){let g=q(l.age),o=V(l.behindByDays),i=l.risk==="Major"?"Major update":l.risk==="Minor"?"Minor update":"Patch update",h=l.note?`
25
+ ${I(l.note)}`:"";u+=` \u2022 ${l.name} (${l.current} \u2192 ${l.latest})
26
+ `,u+=` ${g} old, behind by ${o} | ${i}${h}
27
+
28
+ `}}if(y.length>0){u+=`\u{1F7E1} Review Soon
29
+ `;for(let l of y){let g=q(l.age),o=V(l.behindByDays),i=l.risk==="Major"?"Major update":l.risk==="Minor"?"Minor update":"Patch update",h=l.note?`
30
+ ${I(l.note)}`:"";u+=` \u2022 ${l.name} (${l.current} \u2192 ${l.latest})
31
+ `,u+=` ${g} old, behind by ${o} | ${i}${h}
32
+
33
+ `}}u+=`
34
+ `}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
35
+
36
+ `,u+=`\u2705 No critical actions required
37
+
38
+ `;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
39
+
40
+ `,u+=`| Package | Current | Latest | Age | Behind | Risk | Status | Notes |
41
+ `,u+=`|---------|---------|--------|-----|---------|------|--------|-------|
42
+ `;for(let d of k){let y=q(d.age),l=V(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} | ${l} | ${g} | ${o} | ${i} |
43
+ `}return u}import{format as he}from"date-fns";function E(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 Qe(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=he(t,"yyyy-MM-dd"),s=he(t,"yyyy-MM-dd HH:mm:ss");if(e.length===0)return`<!DOCTYPE html>
44
+ <html lang="en">
45
+ <head>
46
+ <meta charset="UTF-8">
47
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
48
+ <title>Dependency Report (${n})</title>
49
+ <style>
50
+ * { margin: 0; padding: 0; box-sizing: border-box; }
51
+ body {
52
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
53
+ line-height: 1.6;
54
+ color: #1f2937;
55
+ background-color: #f9fafb;
56
+ padding: 2rem;
57
+ }
58
+ .container {
59
+ max-width: 1400px;
60
+ margin: 0 auto;
61
+ background: white;
62
+ border-radius: 8px;
63
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
64
+ padding: 2rem;
65
+ }
66
+ .empty-state {
67
+ text-align: center;
68
+ padding: 4rem 2rem;
69
+ color: #059669;
70
+ }
71
+ .empty-state h2 {
72
+ font-size: 1.5rem;
73
+ font-weight: 500;
74
+ }
75
+ </style>
76
+ </head>
77
+ <body>
78
+ <div class="container">
79
+ <h1>Dependency Report (${n})</h1>
80
+ <div class="timestamp">Generated at: ${s}</div>
26
81
  <div class="empty-state">
27
82
  <h2>\u2705 All dependencies are up to date</h2>
28
83
  </div>
29
- `:"";return`<!DOCTYPE html>
84
+ </div>
85
+ </body>
86
+ </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?E(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"";y+=`
87
+ <div class="package-card">
88
+ <div class="package-header">
89
+ <strong>${E(o.name)}</strong> (${E(o.current)} \u2192 ${E(o.latest)})
90
+ </div>
91
+ <div class="package-details">
92
+ ${i} old, behind by ${h} | ${f}
93
+ ${p?`<br>${p} ${w?E(w):""}`:""}
94
+ </div>
95
+ </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?E(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"";y+=`
96
+ <div class="package-card">
97
+ <div class="package-header">
98
+ <strong>${E(o.name)}</strong> (${E(o.current)} \u2192 ${E(o.latest)})
99
+ </div>
100
+ <div class="package-details">
101
+ ${i} old, behind by ${h} | ${f}
102
+ ${p?`<br>${p} ${w?E(w):""}`:""}
103
+ </div>
104
+ </div>`}y+="</div>"}}else y='<div class="no-actions">\u2705 No critical actions required</div>';let l="";for(let o of k){let i=X(o.age),h=Z(o.behindByDays),f=Qe(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>`:"",R=o.note?E(o.note.replace(/^(BLOCKED|DEFERRED|ACCEPTED(\s+RISK)?)[:\-\s]+/i,"").trim()):"",M=w&&R?`${w} ${R}`:w||R||"";l+=`
105
+ <tr>
106
+ <td class="package-name">${E(o.name)}</td>
107
+ <td>${E(o.current)}</td>
108
+ <td>${E(o.latest)}</td>
109
+ <td>${E(i)}</td>
110
+ <td>${E(h)}</td>
111
+ <td><span class="risk-badge" style="background-color: ${f}">${E(o.risk)}</span></td>
112
+ <td>${b}</td>
113
+ <td class="notes">${M}</td>
114
+ </tr>`}let g=a.riskStatus==="healthy"?"#10b981":a.riskStatus==="degrading"?"#f59e0b":"#ef4444";return`<!DOCTYPE html>
30
115
  <html lang="en">
31
116
  <head>
32
117
  <meta charset="UTF-8">
33
118
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
34
- <title>Dependency Report (${r})</title>
119
+ <title>Dependency Report (${n})</title>
35
120
  <style>
36
121
  * {
37
122
  margin: 0;
@@ -61,24 +146,117 @@ Generated at: ${o}
61
146
  .timestamp {
62
147
  color: #6b7280;
63
148
  font-size: 0.875rem;
64
- margin-bottom: 2rem;
149
+ margin-bottom: 1rem;
65
150
  }
66
- .empty-state {
151
+ .status-badge {
152
+ background: ${g};
153
+ color: white;
154
+ padding: 0.5rem 1rem;
155
+ border-radius: 6px;
156
+ font-weight: 600;
157
+ font-size: 1.1rem;
67
158
  text-align: center;
68
- padding: 4rem 2rem;
69
- color: #059669;
159
+ margin: 1.5rem 0;
70
160
  }
71
- .empty-state h2 {
161
+ .summary-grid {
162
+ display: grid;
163
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
164
+ gap: 1rem;
165
+ margin: 1.5rem 0;
166
+ }
167
+ .summary-card {
168
+ background: #f9fafb;
169
+ padding: 1rem;
170
+ border-radius: 6px;
171
+ border: 1px solid #e5e7eb;
172
+ }
173
+ .summary-card strong {
174
+ display: block;
72
175
  font-size: 1.5rem;
73
- font-weight: 500;
176
+ color: #111827;
177
+ margin-bottom: 0.25rem;
178
+ }
179
+ .summary-card span {
180
+ color: #6b7280;
181
+ font-size: 0.875rem;
182
+ }
183
+ .risk-assessment {
184
+ background: #fef3c7;
185
+ border-left: 4px solid #f59e0b;
186
+ padding: 1rem;
187
+ margin: 1.5rem 0;
188
+ border-radius: 4px;
189
+ }
190
+ .action-section {
191
+ margin: 2rem 0;
192
+ }
193
+ .action-group {
194
+ margin: 1.5rem 0;
195
+ }
196
+ .action-title {
197
+ font-size: 1.25rem;
198
+ margin-bottom: 1rem;
199
+ padding-bottom: 0.5rem;
200
+ border-bottom: 2px solid #e5e7eb;
201
+ }
202
+ .action-title.critical {
203
+ color: #dc2626;
204
+ border-bottom-color: #dc2626;
205
+ }
206
+ .action-title.review {
207
+ color: #f59e0b;
208
+ border-bottom-color: #f59e0b;
209
+ }
210
+ .package-card {
211
+ background: #f9fafb;
212
+ border: 1px solid #e5e7eb;
213
+ border-radius: 6px;
214
+ padding: 1rem;
215
+ margin-bottom: 0.75rem;
216
+ }
217
+ .package-header {
218
+ font-size: 1rem;
219
+ margin-bottom: 0.5rem;
220
+ }
221
+ .package-details {
222
+ color: #6b7280;
223
+ font-size: 0.875rem;
224
+ }
225
+ .badge {
226
+ display: inline-block;
227
+ padding: 0.25rem 0.5rem;
228
+ border-radius: 4px;
229
+ font-size: 0.75rem;
230
+ font-weight: 600;
231
+ margin-right: 0.5rem;
232
+ }
233
+ .badge-blocked {
234
+ background: #dc2626;
235
+ color: white;
236
+ }
237
+ .badge-deferred {
238
+ background: #f59e0b;
239
+ color: white;
240
+ }
241
+ .badge-accepted {
242
+ background: #3b82f6;
243
+ color: white;
244
+ }
245
+ .no-actions {
246
+ text-align: center;
247
+ padding: 2rem;
248
+ color: #059669;
249
+ font-size: 1.1rem;
74
250
  }
75
251
  table {
76
252
  width: 100%;
77
253
  border-collapse: collapse;
78
- margin-top: 1rem;
254
+ margin-top: 2rem;
79
255
  }
80
256
  thead {
81
257
  background-color: #f3f4f6;
258
+ position: sticky;
259
+ top: 0;
82
260
  }
83
261
  th {
84
262
  text-align: left;
@@ -111,16 +289,13 @@ Generated at: ${o}
111
289
  text-transform: uppercase;
112
290
  letter-spacing: 0.05em;
113
291
  }
114
- .stale-yes {
115
- color: #dc2626;
292
+ .status-stable {
293
+ color: #10b981;
116
294
  font-weight: 600;
117
295
  }
118
- .stale-no {
119
- color: #059669;
120
- }
121
296
  .notes {
122
297
  color: #6b7280;
123
- font-style: italic;
298
+ font-size: 0.875rem;
124
299
  }
125
300
  @media (max-width: 768px) {
126
301
  body {
@@ -129,6 +304,9 @@ Generated at: ${o}
129
304
  .container {
130
305
  padding: 1rem;
131
306
  }
307
+ .summary-grid {
308
+ grid-template-columns: repeat(2, 1fr);
309
+ }
132
310
  table {
133
311
  font-size: 0.875rem;
134
312
  }
@@ -136,35 +314,116 @@ Generated at: ${o}
136
314
  padding: 0.5rem;
137
315
  }
138
316
  }
317
+ @media print {
318
+ body {
319
+ background: white;
320
+ }
321
+ .container {
322
+ box-shadow: none;
323
+ }
324
+ }
139
325
  </style>
140
326
  </head>
141
327
  <body>
142
328
  <div class="container">
143
- <h1>Dependency Report (${r})</h1>
144
- <div class="timestamp">Generated at: ${o}</div>
145
- ${i||`
146
- <h2 style="margin-top: 1.5rem; margin-bottom: 1rem; font-size: 1.25rem; color: #374151;">
147
- Outdated Packages (${t.length})
148
- </h2>
329
+ <h1>Dependency Report (${n})</h1>
330
+ <div class="timestamp">Generated at: ${s}</div>
331
+
332
+ <div class="status-badge">
333
+ ${a.riskStatusEmoji} ${a.riskStatusText}
334
+ </div>
335
+
336
+ <div class="summary-grid">
337
+ <div class="summary-card">
338
+ <strong>${a.total}</strong>
339
+ <span>Total dependencies</span>
340
+ </div>
341
+ <div class="summary-card">
342
+ <strong>${a.outdated}</strong>
343
+ <span>Outdated (${a.major} major, ${a.minor} minor, ${a.patch} patch)</span>
344
+ </div>
345
+ <div class="summary-card">
346
+ <strong>${a.stale}</strong>
347
+ <span>Stale (>12 months)</span>
348
+ </div>
349
+ <div class="summary-card">
350
+ <strong>${a.upToDate}</strong>
351
+ <span>Up-to-date</span>
352
+ </div>
353
+ ${a.blocked>0||a.deferred>0||a.accepted>0?`
354
+ <div class="summary-card">
355
+ <strong>${a.blocked}</strong>
356
+ <span>Blocked upgrades</span>
357
+ </div>
358
+ <div class="summary-card">
359
+ <strong>${a.deferred}</strong>
360
+ <span>Deferred upgrades</span>
361
+ </div>
362
+ <div class="summary-card">
363
+ <strong>${a.accepted}</strong>
364
+ <span>Accepted risks</span>
365
+ </div>
366
+ `:""}
367
+ </div>
368
+
369
+ <div class="risk-assessment">
370
+ <strong>Risk Assessment:</strong> ${a.stale} stale dependencies and ${a.major} unaddressed major upgrades detected.
371
+ </div>
372
+
373
+ <div class="action-section">
374
+ <h2 style="margin-bottom: 1rem; font-size: 1.25rem; color: #374151;">Action Required</h2>
375
+ ${y}
376
+ </div>
377
+
378
+ <h2 style="margin-top: 2rem; margin-bottom: 1rem; font-size: 1.25rem; color: #374151;">Full Dependency List</h2>
149
379
  <table>
150
380
  <thead>
151
381
  <tr>
152
382
  <th>Package</th>
153
383
  <th>Current</th>
154
384
  <th>Latest</th>
155
- <th>Risk</th>
156
385
  <th>Age</th>
157
- <th>Stale?</th>
386
+ <th>Behind</th>
387
+ <th>Risk</th>
388
+ <th>Status</th>
158
389
  <th>Notes</th>
159
390
  </tr>
160
391
  </thead>
161
392
  <tbody>
162
- ${c}
393
+ ${l}
163
394
  </tbody>
164
395
  </table>
165
- `}
166
396
  </div>
167
397
  </body>
168
- </html>`}import{existsSync as J,access as kt,constants as bt,mkdirSync as $t,writeFileSync as xt,unlinkSync as Pt}from"fs";import{join as H}from"path";import{promisify as St}from"util";var jt=St(kt);async function G(t=process.cwd()){let e=H(t,"node_modules");if(!J(e))throw new Error('node_modules directory not found. Please run "npm install", "pnpm install", or "bun install" first.')}async function W(t){if(!J(t))try{$t(t,{recursive:!0})}catch(r){throw new Error(`Cannot create directory ${t}: ${r instanceof Error?r.message:String(r)}`)}try{await jt(t,bt.W_OK)}catch{throw new Error(`No write permission for directory: ${t}`)}let e=H(t,`.write-test-${Date.now()}.tmp`);try{xt(e,"ok"),Pt(e)}catch(r){throw new Error(`Cannot write to directory ${t}: ${r instanceof Error?r.message:String(r)}`)}}function j(t,e){try{return JSON.parse(t)}catch(r){throw r instanceof SyntaxError?new Error(`Invalid JSON in ${e}: ${r.message}`):r}}var m={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"},Y=["-","\\","|","/"],E=null,q="",n={info:t=>{console.log(`${m.cyan}[INFO]${m.reset} ${t}`)},success:t=>{console.log(`${m.green}${m.bright}[OK]${m.reset} ${m.green}${t}${m.reset}`)},warn:t=>{console.warn(`${m.yellow}[WARN]${m.reset} ${t}`)},error:t=>{console.error(`${m.red}${m.bright}[ERR]${m.reset} ${m.red}${t}${m.reset}`)},progress:(t,e,r)=>{let o=Math.round(t/e*100);process.stdout.write(`\r${m.cyan}${r}${m.reset} ${m.dim}(${t}/${e}, ${o}%)${m.reset}`),t===e&&process.stdout.write(`
169
- `)},startSpinner:t=>{q=t;let e=0;E=setInterval(()=>{process.stdout.write(`\r${m.cyan}${Y[e]}${m.reset} ${q}`),e=(e+1)%Y.length},100)},stopSpinner:()=>{E&&(clearInterval(E),E=null,process.stdout.write("\r"+" ".repeat(process.stdout.columns||80)+"\r"))}};import{format as st}from"date-fns";import{existsSync as Rt,readFileSync as Ct}from"fs";import{join as Mt}from"path";import{z as g}from"zod";var l={staleThreshold:"18 months",ignorePatterns:[],formats:{markdown:!0,html:!0},concurrency:5,failConditions:{stale:!1,major:!1},reportEmptyState:!0},Et=g.object({staleThreshold:g.string().default(l.staleThreshold),ignorePatterns:g.array(g.string()).default(l.ignorePatterns),formats:g.object({markdown:g.boolean().default(l.formats.markdown),html:g.boolean().default(l.formats.html)}).default(l.formats),concurrency:g.number().int().positive().default(l.concurrency),failConditions:g.object({stale:g.boolean().default(l.failConditions.stale),major:g.boolean().default(l.failConditions.major)}).default(l.failConditions),reportEmptyState:g.boolean().default(l.reportEmptyState)}).passthrough();function B(t){try{return Et.parse(t)}catch(e){if(e instanceof g.ZodError){let r=e.errors.map(o=>`${o.path.join(".")}: ${o.message}`).join(", ");throw new Error(`Invalid config: ${r}`)}throw e}}function K(t=process.cwd()){let e=Mt(t,".dep-report","config.json");if(!Rt(e))return n.info("No config.json found, using defaults"),l;try{let r=Ct(e,"utf-8"),o=j(r,e),s={staleThreshold:o.staleThreshold??l.staleThreshold,ignorePatterns:o.ignorePatterns??l.ignorePatterns,formats:{markdown:o.formats?.markdown??l.formats.markdown,html:o.formats?.html??l.formats.html},concurrency:o.concurrency??l.concurrency,failConditions:{stale:o.failConditions?.stale??l.failConditions.stale,major:o.failConditions?.major??l.failConditions.major},reportEmptyState:o.reportEmptyState??l.reportEmptyState},c=B(s);return n.info("Loaded config from .dep-report/config.json"),c}catch(r){return n.warn(`Failed to load config: ${r instanceof Error?r.message:String(r)}`),n.warn("Using default configuration"),l}}function Ot(t){let r=t.trim().toLowerCase().match(/^(\d+)\s+(year|years|month|months|day|days|week|weeks)$/);if(!r)throw new Error(`Invalid duration format: "${t}". Expected format: "18 months", "2 years", "90 days", etc.`);let o=parseInt(r[1],10),s=r[2];switch(s){case"day":case"days":return o*24*60*60*1e3;case"week":case"weeks":return o*7*24*60*60*1e3;case"month":case"months":return o*30*24*60*60*1e3;case"year":case"years":return o*365*24*60*60*1e3;default:throw new Error(`Unsupported time unit: ${s}`)}}function V(t){let e=Ot(t);return Math.floor(e/(1e3*60*60*24))}import{existsSync as vt,readFileSync as Dt}from"fs";import{join as Nt}from"path";function Z(t=process.cwd()){let e=Nt(t,".dep-report","notes.json");if(!vt(e))return{};try{let r=Dt(e,"utf-8"),o=j(r,e);if(typeof o!="object"||o===null||Array.isArray(o))return n.warn("Invalid notes.json format, expected object"),{};for(let[s,c]of Object.entries(o))typeof c!="string"&&(n.warn(`Invalid note for ${s}, expected string`),delete o[s]);return n.info(`Loaded ${Object.keys(o).length} notes from notes.json`),o}catch(r){return n.warn(`Failed to load notes: ${r instanceof Error?r.message:String(r)}`),{}}}function Q(t,e){return t.map(r=>{let o=e[r.name];return o?{...r,note:o}:r})}import{minimatch as Tt}from"minimatch";function X(t,e){return e.length===0?t:t.filter(r=>{for(let o of e)if(Tt(r.name,o))return!1;return!0})}import{existsSync as P,mkdirSync as tt,writeFileSync as v}from"fs";import{join as S}from"path";async function et(t=process.cwd(),e=!1){let r=S(t,".dep-report"),o=S(r,"config.json"),s=S(r,"notes.json"),c=S(r,"reports"),i=S(r,".gitignore");if(P(r)?n.info(".dep-report/ directory already exists"):(tt(r,{recursive:!0}),n.success("Created .dep-report/ directory")),P(c)||(tt(c,{recursive:!0}),n.success("Created .dep-report/reports/ directory")),!P(o)||e){let a=JSON.stringify(l,null,2);v(o,a,"utf-8"),n.success("Created .dep-report/config.json")}else n.info("config.json already exists, skipping");if(P(s))n.info("notes.json already exists, skipping");else{let a=JSON.stringify({},null,2);v(s,a,"utf-8"),n.success("Created .dep-report/notes.json")}P(i)?n.info(".gitignore already exists, skipping"):(v(i,`.cache.json
170
- `,"utf-8"),n.success("Created .dep-report/.gitignore")),n.success("Initialization complete!"),n.info("You can now customize .dep-report/config.json and add notes to .dep-report/notes.json")}var It="https://registry.npmjs.org";async function rt(t=It,e=5e3){let r=new AbortController,o=setTimeout(()=>r.abort(),e);try{let s=`${t}/lodash`;return(await fetch(s,{headers:{Accept:"application/json"},signal:r.signal})).ok}catch{return!1}finally{clearTimeout(o)}}var R=new At,_t=new URL("../package.json",import.meta.url),Lt=JSON.parse(Ft(_t,"utf-8")),zt=Lt.version??"0.0.0";R.name("dep-report").description("Zero-config CLI tool that generates version-controlled snapshots of dependency risk").version(zt);R.command("init").description("Scaffold .dep-report/ directory structure").option("--include-config","Force overwrite config.json even if it exists").action(async t=>{try{await et(process.cwd(),t.includeConfig),process.exit(0)}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exit(1)}});R.action(async()=>{try{let t=process.cwd(),e=K(t);n.info("Checking prerequisites..."),await G(t);let r=y(t,".dep-report");await W(r),n.info("Detecting package manager...");let o=D(t);o||(n.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)),n.success(`Detected: ${o.manager}`),n.info("Scanning for outdated packages...");let s=await T(o.manager,t);if(Object.keys(s).length===0){if(n.success("No outdated packages found!"),e.reportEmptyState){let u=y(t,".dep-report","reports");ot(u)||nt(u,{recursive:!0});let f=st(new Date,"yyyy-MM-dd");if(e.formats.markdown){let h=M([]);k(y(u,`${f}_outdated.md`),h),k(y(u,"latest.md"),h),n.success(`Report generated: .dep-report/reports/${f}_outdated.md`)}if(e.formats.html){let h=O([]);k(y(u,`${f}_outdated.html`),h),k(y(u,"latest.html"),h),n.success(`HTML report generated: .dep-report/reports/${f}_outdated.html`)}}process.exit(0)}n.info(`Found ${Object.keys(s).length} outdated packages`);let c=I(s);n.startSpinner("Checking registry connectivity...");let i=await rt();n.stopSpinner(),i||(n.error("Unable to reach the npm registry."),n.info("If you have a cache, try running with --refresh."),process.exit(1)),n.success("Registry connectivity confirmed"),n.startSpinner(`Enriching ${c.length} packages with registry metadata...`);let a=await F(c,e.concurrency);n.stopSpinner(),n.success("Enrichment complete");let p=V(e.staleThreshold),d=L(a,p),w=d.length;d=X(d,e.ignorePatterns),w>d.length&&n.info(`Filtered out ${w-d.length} packages based on ignorePatterns`);let C=Z(t);if(d=Q(d,C),e.formats.markdown||e.formats.html){n.info("Generating reports...");let u=y(t,".dep-report","reports");ot(u)||nt(u,{recursive:!0});let f=st(new Date,"yyyy-MM-dd");if(e.formats.markdown){let h=M(d);k(y(u,`${f}_outdated.md`),h),k(y(u,"latest.md"),h),n.success(`Report generated: .dep-report/reports/${f}_outdated.md`),n.success("Latest report: .dep-report/reports/latest.md")}if(e.formats.html){let h=O(d);k(y(u,`${f}_outdated.html`),h),k(y(u,"latest.html"),h),n.success(`HTML report generated: .dep-report/reports/${f}_outdated.html`),n.success("Latest HTML report: .dep-report/reports/latest.html")}}let $=!1;e.failConditions.stale&&d.some(f=>f.isStale)&&(n.error("Found stale packages (--fail-if-stale)"),$=!0),e.failConditions.major&&d.some(f=>f.risk==="Major")&&(n.error("Found major version updates (--fail-if-major)"),$=!0),process.exit($?1:0)}catch(t){n.error(t instanceof Error?t.message:String(t)),process.exit(1)}});R.parse();
398
+ </html>`}import{existsSync as ye,access as Xe,constants as Ze,mkdirSync as et,writeFileSync as tt,unlinkSync as rt}from"fs";import{join as be}from"path";import{promisify as nt}from"util";var ot=nt(Xe);async function ke(e=process.cwd()){let t=be(e,"node_modules");if(!ye(t))throw new Error('node_modules directory not found. Please run "npm install", "pnpm install", or "bun install" first.')}async function $e(e){if(!ye(e))try{et(e,{recursive:!0})}catch(r){throw new Error(`Cannot create directory ${e}: ${r instanceof Error?r.message:String(r)}`)}try{await ot(e,Ze.W_OK)}catch{throw new Error(`No write permission for directory: ${e}`)}let t=be(e,`.write-test-${Date.now()}.tmp`);try{tt(t,"ok"),rt(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"},we=["-","\\","|","/"],K=null,Se="",m={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(`
399
+ `)},startSpinner:e=>{Se=e;let t=0;K=setInterval(()=>{process.stdout.write(`\r${j.cyan}${we[t]}${j.reset} ${Se}`),t=(t+1)%we.length},100)},stopSpinner:()=>{K&&(clearInterval(K),K=null,process.stdout.write("\r"+" ".repeat(process.stdout.columns||80)+"\r"))}};import{format as Be}from"date-fns";import{existsSync as at,readFileSync as it}from"fs";import{join as ct}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},st=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 Pe(e){try{return st.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 xe(e=process.cwd()){let t=ct(e,".dep-report","config.json");if(!at(t))return m.info("No config.json found, using defaults"),P;try{let r=it(t,"utf-8"),n=H(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=Pe(s);return m.info("Loaded config from .dep-report/config.json"),c}catch(r){return m.warn(`Failed to load config: ${r instanceof Error?r.message:String(r)}`),m.warn("Using default configuration"),P}}function dt(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 je(e){let t=dt(e);return Math.floor(t/(1e3*60*60*24))}import{existsSync as lt,readFileSync as mt}from"fs";import{join as ut}from"path";function Re(e=process.cwd()){let t=ut(e,".dep-report","notes.json");if(!lt(t))return{};try{let r=mt(t,"utf-8"),n=H(r,t);if(typeof n!="object"||n===null||Array.isArray(n))return m.warn("Invalid notes.json format, expected object"),{};for(let[s,c]of Object.entries(n))typeof c!="string"&&(m.warn(`Invalid note for ${s}, expected string`),delete n[s]);return m.info(`Loaded ${Object.keys(n).length} notes from notes.json`),n}catch(r){return m.warn(`Failed to load notes: ${r instanceof Error?r.message:String(r)}`),{}}}function Ee(e,t){return e.map(r=>{let n=t[r.name];return n?{...r,note:n}:r})}import{minimatch as pt}from"minimatch";function Me(e,t){return t.length===0?e:e.filter(r=>{for(let n of t)if(pt(r.name,n))return!1;return!0})}import{existsSync as B,mkdirSync as De,writeFileSync as te}from"fs";import{join as U}from"path";async function ve(e=process.cwd(),t=!1,r){let n=U(e,".dep-report"),s=U(n,"config.json"),c=U(n,"notes.json"),a=U(n,"reports"),k=U(n,".gitignore");if(B(n)?m.info(".dep-report/ directory already exists"):(De(n,{recursive:!0}),m.success("Created .dep-report/ directory")),B(a)||(De(a,{recursive:!0}),m.success("Created .dep-report/reports/ directory")),!B(s)||t){let u=P;if(r){let d=oe(r);u=d.config,m.info(`Using preset: ${d.displayName} - ${d.description}`)}let $=JSON.stringify(u,null,2);te(s,$,"utf-8"),m.success("Created .dep-report/config.json")}else m.info("config.json already exists, skipping");if(B(c))m.info("notes.json already exists, skipping");else{let u=JSON.stringify({},null,2);te(c,u,"utf-8"),m.success("Created .dep-report/notes.json")}B(k)?m.info(".gitignore already exists, skipping"):(te(k,`.cache.json
400
+ `,"utf-8"),m.success("Created .dep-report/.gitignore")),m.success("Initialization complete!"),m.info("You can now customize .dep-report/config.json and add notes to .dep-report/notes.json")}import{readFileSync as Ce,existsSync as re,readdirSync as ft}from"fs";import{join as J}from"path";import{format as gt,parse as W,subDays as ht,differenceInDays as ne}from"date-fns";function Oe(e,t){let r=e.match(/\| Package \|.*?\n\|-+\|\n([\s\S]*?)\n\n/);if(!r)return null;let n=r[1].trim().split(`
401
+ `),s=[];for(let d of n){let y=d.split("|").map(S=>S.trim()).filter(S=>S);if(y.length<6)continue;let[l,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 R=null;if(h&&h!=="\u2014"){let S=h.match(/(\d+)d|(\d+)m|(\d+)y/);S&&(S[1]?R=parseInt(S[1]):S[2]?R=parseInt(S[2])*30:S[3]&&(R=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"),s.push({name:l,current:g,latest:o,wanted:o,type:"dependencies",currentPublishedAt:null,latestPublishedAt:null,age:w,behindByDays:R,isStale:w!==null&&w>365,risk:M,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 Te(e,t){if(t==="latest"){let r=J(e,"latest.md");return re(r)?r:null}if(t==="last-month"){let n=ht(new Date,30),s=ft(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:W(a[1],"yyyy-MM-dd",new Date)}:null}).filter(c=>c!==null).sort((c,a)=>Math.abs(ne(c.date,n))-Math.abs(ne(a.date,n)));return s.length>0?J(e,s[0].file):null}try{let r=W(t,"yyyy-MM-dd",new Date),n=gt(r,"yyyy-MM-dd"),s=J(e,`${n}_outdated.md`);if(re(s))return s}catch{}return null}function Ne(e){return 100-e.stale*5-e.major*3}async function Ie(e,t,r=process.cwd()){let n=J(r,".dep-report","reports");re(n)||(m.error("No reports directory found. Run dep-report first to generate reports."),process.exit(1));let s=Te(n,e),c=Te(n,t);s||(m.error(`Report not found for: ${e}`),process.exit(1)),c||(m.error(`Report not found for: ${t}`),process.exit(1));let a=Ce(s,"utf-8"),k=Ce(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,l=Oe(a,d),g=Oe(k,y);(!l||!g)&&(m.error("Failed to parse reports"),process.exit(1));let o=ne(W(y,"yyyy-MM-dd",new Date),W(d,"yyyy-MM-dd",new Date)),i=g.summary.stale-l.summary.stale,h=g.summary.major-l.summary.major,f=new Set(l.packages.map(x=>x.name)),b=new Set(g.packages.map(x=>x.name)),p=g.packages.filter(x=>!f.has(x.name)),w=l.packages.filter(x=>!b.has(x.name)),R=g.packages.filter(x=>{let _=l.packages.find(G=>G.name===x.name);return _&&_.current!==x.current}),M=Ne(l.summary),S=Ne(g.summary),N=M>0?(S-M)/M*100:0;if(console.log(`
402
+ Dependency Health Comparison`),console.log(`From: ${d} \u2192 ${y} (${o} days)
403
+ `),R.length>0){console.log("\u{1F4C8} Improvements:");for(let x of R.slice(0,5)){let _=l.packages.find(G=>G.name===x.name);console.log(` \u2022 ${x.name}: ${_?.current} \u2192 ${x.current}`)}R.length>5&&console.log(` ... and ${R.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: ${l.summary.stale} \u2192 ${g.summary.stale} (${x}${i})`)}if(h!==0){let x=h>0?"+":"";console.log(` \u2022 Major upgrades pending: ${l.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: ${M.toFixed(1)} \u2192 ${S.toFixed(1)}
404
+ `),process.exit(N<0?1:0)}var yt="https://registry.npmjs.org";async function Ae(e=yt,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 bt,existsSync as kt}from"fs";import{join as $t}from"path";function Y(e=process.cwd()){let t=$t(e,"package.json");if(!kt(t))return 0;try{let r=bt(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}}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",`
405
+ dep-report - Generate dependency risk reports
406
+
407
+ USAGE
408
+ dep-report [options]
409
+
410
+ DESCRIPTION
411
+ Scans for outdated packages and generates a daily risk brief
412
+ showing age, staleness, and major upgrades. Reports are
413
+ version-controlled in .dep-report/reports/
414
+
415
+ QUICK START
416
+ dep-report # Run audit, generate reports
417
+ dep-report init # Create config files
418
+ `).addHelpText("after",`
419
+ EXAMPLES
420
+ dep-report # Daily audit
421
+ dep-report init # Initialize configuration
422
+
423
+ LEARN MORE
424
+ https://github.com/hussmarsidi/dep-reports
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)||(m.error(`Invalid preset: ${e.preset}. Valid options: starter, production, strict`),process.exit(1)),r=e.preset),await ve(process.cwd(),e.includeConfig,r),process.exit(0)}catch(t){m.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 Ie(e,t)}catch(r){m.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=xe(t);m.info("Checking prerequisites..."),await ke(t);let n=v(t,".dep-report");await $e(n),m.info("Detecting package manager...");let s=se(t);s||(m.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)),m.success(`Detected: ${s.manager}`),m.info("Scanning for outdated packages...");let c=await ce(s.manager,t);if(Object.keys(c).length===0){if(m.success("No outdated packages found!"),r.reportEmptyState){let o=v(t,".dep-report","reports");Fe(o)||Le(o,{recursive:!0});let i=Be(new Date,"yyyy-MM-dd"),h=Y(t);if(r.formats.markdown){let f=Q([],new Date,h);T(v(o,`${i}_outdated.md`),f),T(v(o,"latest.md"),f),m.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),m.success(`HTML report generated: .dep-report/reports/${i}_outdated.html`)}}process.exit(0)}m.info(`Found ${Object.keys(c).length} outdated packages`);let a=le(c);m.startSpinner("Checking registry connectivity...");let k=await Ae();m.stopSpinner(),k||(m.error("Unable to reach the npm registry."),m.info("If you have a cache, try running with --refresh."),process.exit(1)),m.success("Registry connectivity confirmed"),m.startSpinner(`Enriching ${a.length} packages with registry metadata...`);let u=await ue(a,r.concurrency);m.stopSpinner(),m.success("Enrichment complete");let $=je(r.staleThreshold),d=fe(u,$),y=d.length;d=Me(d,r.ignorePatterns),y>d.length&&m.info(`Filtered out ${y-d.length} packages based on ignorePatterns`);let l=Re(t);if(d=Ee(d,l),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",R=p.behindByDays!==null?`${p.behindByDays}d`:"\u2014",M=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 ${R}) - ${p.risk} ${p.current} \u2192 ${p.latest}${M?`, ${M}`:""}`)}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",R=A(b)?"\u2705 Stable":"Outdated";console.log(` ${b.name}: ${b.current} \u2192 ${b.latest} (${p}, ${w}, ${b.risk}, ${R})`)}console.log("")}console.log(`[No files written]
429
+ `);let f=!1;r.failConditions.stale&&d.some(p=>p.isStale)&&(m.error("Found stale packages (--fail-if-stale)"),f=!0),r.failConditions.major&&d.some(p=>p.risk==="Major")&&(m.error("Found major version updates (--fail-if-major)"),f=!0),process.exit(f?1:0)}if(r.formats.markdown||r.formats.html){m.info("Generating reports...");let o=v(t,".dep-report","reports");Fe(o)||Le(o,{recursive:!0});let i=Be(new Date,"yyyy-MM-dd"),h=Y(t);if(r.formats.markdown){let f=Q(d,new Date,h);T(v(o,`${i}_outdated.md`),f),T(v(o,"latest.md"),f),m.success(`Report generated: .dep-report/reports/${i}_outdated.md`),m.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),m.success(`HTML report generated: .dep-report/reports/${i}_outdated.html`),m.success("Latest HTML report: .dep-report/reports/latest.html")}}let g=!1;r.failConditions.stale&&d.some(i=>i.isStale)&&(m.error("Found stale packages (--fail-if-stale)"),g=!0),r.failConditions.major&&d.some(i=>i.risk==="Major")&&(m.error("Found major version updates (--fail-if-major)"),g=!0),process.exit(g?1:0)}catch(t){m.error(t instanceof Error?t.message:String(t)),process.exit(1)}});z.parse();
@@ -0,0 +1 @@
1
+ import{a,b,c,d}from"./chunk-KNT3JZ7P.js";export{a as PRESETS,b as getPreset,d as isValidPresetName,c as listPresets};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dep-report",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
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",