tech-debt-visualizer 0.2.20 → 0.2.22

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,26 +1,51 @@
1
1
  # Technical Debt Visualizer
2
2
 
3
+ **[tech-debt-visualizer](https://www.npmjs.com/package/tech-debt-visualizer)** on npm
4
+
3
5
  Analyze a repo and get a **cleanliness score**, **debt breakdown**, and optional **AI explanations and refactor suggestions**—in the terminal or as an interactive HTML report.
4
6
 
5
- ![Node 18+](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)
6
- ![Languages](https://img.shields.io/badge/languages-JS%20%7C%20TS%20%7C%20Python-green?style=flat-square)
7
- ![License](https://img.shields.io/badge/license-GPL--3.0-blue?style=flat-square)
7
+ ![npm version](https://img.shields.io/npm/v/tech-debt-visualizer)
8
+ ![npm downloads](https://img.shields.io/npm/dm/tech-debt-visualizer)
9
+ ![Node version](https://img.shields.io/node/v/tech-debt-visualizer)
10
+ ![License](https://img.shields.io/badge/license-GPL--3.0-blue)
11
+ ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)
8
12
 
9
13
  ---
10
14
 
11
- ## Quick start
15
+ ## From the get-go
16
+
17
+ **Option A — No install (run from any folder):**
18
+
19
+ ```bash
20
+ npx tech-debt-visualizer analyze .
21
+ ```
22
+
23
+ **Option B — Install once, then run:**
12
24
 
13
25
  ```bash
14
- git clone <this-repo>
15
- cd tech-debt-visualizer
16
- npm install && npm run build
17
- node dist/cli.js analyze . --format cli
26
+ npm install -g tech-debt-visualizer
27
+ tech-debt-visualizer analyze .
18
28
  ```
19
29
 
20
- To try the **HTML dashboard**:
21
- `node dist/cli.js analyze . --format html -o report.html` then open `report.html`.
30
+ That's the command: **`tech-debt-visualizer analyze .`** (the `.` is "this folder"). You get a terminal report: cleanliness tier (1–5), debt items, hotspots, and a "what to fix" list. No config required. Node 18+.
22
31
 
23
- To use **AI insights** (explanations + optional code refactors): set `GEMINI_API_KEY` or `OPENAI_API_KEY` and run the same commands without `--no-llm`.
32
+ - **HTML report?** Add `-f html -o report.html`, then open the file.
33
+ - **No API key?** Add `--no-llm` for metrics only (no AI).
34
+
35
+ More options: run **`tech-debt-visualizer analyze --help`** (or with `npx` if you didn't install globally).
36
+
37
+ ---
38
+
39
+ ## How to run it
40
+
41
+ | What you want | Command |
42
+ |----------------|--------|
43
+ | **Terminal report** | `tech-debt-visualizer analyze .` (or `npx tech-debt-visualizer analyze .` if not installed) |
44
+ | **HTML report** | `tech-debt-visualizer analyze . -f html -o report.html` |
45
+ | **No AI (no API key)** | `tech-debt-visualizer analyze . --no-llm` |
46
+ | **From this repo (dev)** | `npm run build` then `npm run analyze` |
47
+
48
+ Use **`tech-debt-visualizer`** (not `tech-debt`); `npx tech-debt` is a different package.
24
49
 
25
50
  ---
26
51
 
@@ -60,44 +85,30 @@ So: **static metrics + git → score & tier → optional LLM explanations and co
60
85
 
61
86
  ---
62
87
 
63
- ## Install & run
64
-
65
- | How you run it | Command |
66
- |----------------|--------|
67
- | **From this repo** | `node dist/cli.js analyze [path]` (after `npm run build`) |
68
- | **Global (after publish)** | `npm install -g tech-debt-visualizer` then `tech-debt analyze [path]` |
69
- | **No install (after publish)** | `npx tech-debt-visualizer analyze [path]` |
70
-
71
- Use **`tech-debt-visualizer`** in the command (not `tech-debt`); `npx tech-debt` runs a different npm package. From this repo you can also run `npm run analyze` or `node dist/cli.js analyze .`.
72
-
73
- Requires **Node 18+**.
74
-
75
- ---
76
-
77
88
  ## Options
78
89
 
79
90
  | Option | Meaning |
80
91
  |--------|--------|
81
92
  | `-f, --format` | `cli` (default), `html`, `json`, or `markdown` |
82
- | `-o, --output` | Output path (e.g. `report.html` for HTML) |
83
- | `--no-llm` | Skip all LLM calls (no API key needed) |
84
- | `--llm` | Enable LLM (default). Use with `--llm-key` and/or `--llm-model` |
93
+ | `-o, --output` | Output file path (for html/json/markdown) |
94
+ | `--no-llm` | Skip AI insights (no API key needed) |
85
95
  | `--llm-key <key>` | API key (overrides env / `.env`) |
86
96
  | `--llm-model <model>` | Model name (e.g. `gemini-1.5-flash`, `gpt-4o-mini`) |
87
- | `--ci` | Terse output; exit code 1 if debt score &gt; 60 |
97
+ | `--ci` | CI mode: terse output; exit 1 if debt is high |
88
98
 
89
99
  Examples:
90
100
 
91
101
  ```bash
92
- node dist/cli.js analyze . -f html -o report.html
93
- node dist/cli.js analyze ./src -f json -o debt.json
94
- node dist/cli.js analyze . --ci
95
- # With LLM key and model on the command line:
96
- node dist/cli.js analyze . --llm-key YOUR_GEMINI_KEY --llm-model gemini-1.5-flash
97
- # Or use a .env file in the current directory (GEMINI_API_KEY=...)
98
- node dist/cli.js analyze .
102
+ npx tech-debt-visualizer analyze .
103
+ npx tech-debt-visualizer analyze . -f html -o report.html
104
+ npx tech-debt-visualizer analyze ./src -f json -o debt.json
105
+ npx tech-debt-visualizer analyze . --no-llm
106
+ npx tech-debt-visualizer analyze . --ci
107
+ npx tech-debt-visualizer analyze . --llm-key YOUR_KEY --llm-model gemini-1.5-flash
99
108
  ```
100
109
 
110
+ Full list: `npx tech-debt-visualizer analyze --help`
111
+
101
112
  ---
102
113
 
103
114
  ## LLM (optional)
@@ -161,7 +172,7 @@ src/
161
172
 
162
173
  ---
163
174
 
164
- ## Publishing (maintainers)
175
+ ## Publishing
165
176
 
166
177
  To publish this package to npm: see **[docs/PUBLISHING.md](docs/PUBLISHING.md)** for step-by-step instructions (login, build, publish, scoped name if needed).
167
178
 
package/dist/cli.js CHANGED
@@ -3,8 +3,10 @@
3
3
  * CLI entry: colorful terminal output, progress bars, actionable insights.
4
4
  * Loads .env from cwd first; supports --llm-key and --llm-model.
5
5
  */
6
+ import { readFileSync } from "node:fs";
6
7
  import { readFile } from "node:fs/promises";
7
- import { join } from "node:path";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
8
10
  import { loadEnv } from "./load-env.js";
9
11
  import { Command } from "commander";
10
12
  import chalk from "chalk";
@@ -17,24 +19,44 @@ import { generateHtmlReport } from "./reports/html.js";
17
19
  import { generateJsonReport } from "./reports/json.js";
18
20
  import { generateMarkdownReport } from "./reports/markdown.js";
19
21
  import { SEVERITY_ORDER } from "./types.js";
22
+ function getVersion() {
23
+ try {
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ const pkgPath = join(__dirname, "..", "package.json");
26
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
27
+ return (pkg && pkg.version) || "0.0.0";
28
+ }
29
+ catch {
30
+ return "0.0.0";
31
+ }
32
+ }
20
33
  const program = new Command();
21
34
  program
22
- .name("tech-debt")
23
- .description("Analyze repositories and visualize technical debt with AI-powered insights")
24
- .version("0.1.2");
35
+ .name("tech-debt-visualizer")
36
+ .description("Analyze a repo and get a cleanliness score, debt breakdown, and optional AI insights. No install required.")
37
+ .version(getVersion());
25
38
  program
26
39
  .command("analyze")
27
- .description("Analyze a repository and output report")
28
- .argument("[path]", "Repository path", ".")
29
- .option("-o, --output <path>", "Output file path (default: report.html or stdout for CLI)")
40
+ .description("Analyze a folder (default: current directory) and print or save a report")
41
+ .argument("[path]", "Path to the repo or folder to analyze", ".")
30
42
  .option("-f, --format <type>", "Output format: cli | html | json | markdown", "cli")
31
- .option("--no-llm", "Skip LLM-powered insights")
32
- .option("--llm", "Enable LLM (default). Use with --llm-key and/or --llm-model")
43
+ .option("-o, --output <path>", "Write output to this file (for html/json/markdown)")
44
+ .option("--no-llm", "Skip AI insights (no API key needed; use this for a quick run)")
45
+ .option("--llm", "Enable AI insights (default when an API key is set)")
33
46
  .option("--llm-key <key>", "API key (overrides env: GEMINI_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY)")
34
- .option("--llm-endpoint <url>", "OpenAI-compatible API base URL (e.g. https://api.openai.com/v1 or proxy)")
47
+ .option("--llm-endpoint <url>", "OpenAI-compatible API base URL")
35
48
  .option("--llm-model <model>", "Model name (e.g. gpt-4o-mini, gemini-2.5-flash)")
36
49
  .option("--llm-max-tokens <n>", "Max tokens per response", (v) => parseInt(v, 10))
37
- .option("--ci", "CI mode: minimal output, exit with non-zero if debt score is high")
50
+ .option("--ci", "CI mode: terse output; exit 1 if debt is high")
51
+ .addHelpText("after", `
52
+ Quick start:
53
+ npx tech-debt-visualizer analyze . No install: analyze current folder → terminal report
54
+ tech-debt-visualizer analyze . Same, if you ran: npm install -g tech-debt-visualizer
55
+ tech-debt-visualizer analyze . -f html -o report.html Save interactive HTML report
56
+ tech-debt-visualizer analyze . --no-llm Skip AI (no API key needed)
57
+
58
+ Requires Node 18+. For AI insights, set GEMINI_API_KEY or OPENAI_API_KEY (or use --llm-key).
59
+ `)
38
60
  .action(async (path, opts) => {
39
61
  const repoPath = join(process.cwd(), path);
40
62
  const format = (opts.format ?? "cli");
@@ -274,7 +296,7 @@ function printCliReport(run, ci) {
274
296
  process.stdout.write(chalk.dim(" No debt items. Keep it up.\n"));
275
297
  }
276
298
  process.stdout.write("\n");
277
- process.stdout.write(chalk.dim(" Run with --format html -o report.html for the interactive dashboard.\n\n"));
299
+ process.stdout.write(chalk.dim(" Tip: npx tech-debt-visualizer analyze . -f html -o report.html interactive dashboard.\n\n"));
278
300
  }
279
301
  function severityOrder(s) {
280
302
  return SEVERITY_ORDER[s] ?? 0;
package/dist/llm.js CHANGED
@@ -328,7 +328,7 @@ All files in this codebase: ${allFiles.join(", ")}
328
328
  Top risk files (by hotspot): ${topFiles.join(", ")}
329
329
 
330
330
  Output only:
331
- 1. A single paragraph of 710 sentences that gives full context for the whole codebase. Cover ALL files: briefly note which files or areas are in good shape, which have issues, and how they fit together. Include strengths, main concerns, and the single most important improvement. Write for someone who needs to understand the entire codebase, not just the problematic parts. No code block unless absolutely necessary.
331
+ 1. A single paragraph of 58 sentences that gives full context for the whole codebase. Cover ALL files: briefly note which files or areas are in good shape, which have issues, and how they fit together. Include strengths, main concerns, and the single most important improvement. Write for someone who needs to understand the entire codebase, not just the problematic parts. No code block unless absolutely necessary.
332
332
  2. On the next line write only one word: critical, high, medium, low, or none (overall codebase technical debt severity).
333
333
  3. On the line after that write only a number 0-100 (0 = most debt, 100 = least debt / cleanest).
334
334
  No preamble.`;
@@ -146,14 +146,20 @@ body.dashboard-page {
146
146
  }
147
147
 
148
148
  .dashboard-score-value { font-size: 1.25rem; line-height: 1; }
149
- .dashboard-score-of { font-size: 0.85rem; font-weight: 500; color: var(--text-muted); }
149
+ .dashboard-score-of { font-size: 0.85rem; font-weight: 500; }
150
150
  .dashboard-score-label { font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.04em; margin-left: 0.35rem; opacity: 0.95; }
151
151
 
152
- .dashboard-score.tier-1 { background: rgba(229, 57, 53, 0.2); color: #ff8a80; font-weight: 700; }
153
- .dashboard-score.tier-2 { background: rgba(245, 124, 0, 0.2); color: #ffb74d; font-weight: 700; }
154
- .dashboard-score.tier-3 { background: rgba(249, 168, 37, 0.2); color: #ffd54f; font-weight: 700; }
155
- .dashboard-score.tier-4 { background: rgba(41, 182, 246, 0.2); color: #82b1ff; font-weight: 700; }
156
- .dashboard-score.tier-5 { background: rgba(67, 160, 71, 0.2); color: #81c784; font-weight: 700; }
152
+ /* Match hero score panel tier colors (1=worst, 5=best) */
153
+ .dashboard-score.tier-1 { background: rgba(255, 107, 107, 0.2); color: #ff6b6b; font-weight: 700; }
154
+ .dashboard-score.tier-1 .dashboard-score-of { color: rgba(255, 107, 107, 0.9); }
155
+ .dashboard-score.tier-2 { background: rgba(255, 107, 53, 0.2); color: #ff6b35; font-weight: 700; }
156
+ .dashboard-score.tier-2 .dashboard-score-of { color: rgba(255, 107, 53, 0.95); }
157
+ .dashboard-score.tier-3 { background: rgba(255, 179, 71, 0.2); color: #ffd23f; font-weight: 700; }
158
+ .dashboard-score.tier-3 .dashboard-score-of { color: rgba(255, 210, 63, 0.95); }
159
+ .dashboard-score.tier-4 { background: rgba(78, 205, 196, 0.2); color: #4ecdc4; font-weight: 700; }
160
+ .dashboard-score.tier-4 .dashboard-score-of { color: rgba(78, 205, 196, 0.95); }
161
+ .dashboard-score.tier-5 { background: rgba(6, 255, 165, 0.2); color: #06ffa5; font-weight: 700; }
162
+ .dashboard-score.tier-5 .dashboard-score-of { color: rgba(6, 255, 165, 0.95); }
157
163
 
158
164
  .dashboard-date {
159
165
  font-size: 12px;
@@ -550,20 +556,59 @@ body.dashboard-page {
550
556
  font-weight: 600;
551
557
  }
552
558
 
553
- /* ——— Hero-style score panel (reference look) ——— */
559
+ /* ——— Hero-style score panel: colors tied to tier (1=worst, 5=best) ——— */
554
560
  .panel-score-pop {
561
+ --score-accent-a: #ff6b35;
562
+ --score-accent-b: #ff3366;
563
+ --score-glow: rgba(255, 107, 53, 0.35);
555
564
  border: 2px solid rgba(255, 107, 53, 0.3);
556
- box-shadow: var(--glow), 0 20px 60px rgba(0, 0, 0, 0.4);
565
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
557
566
  background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--surface-hover) 100%);
558
567
  }
559
568
 
569
+ .panel-score-pop[data-tier="1"] {
570
+ --score-accent-a: #ff6b6b;
571
+ --score-accent-b: #e53935;
572
+ --score-glow: rgba(229, 57, 53, 0.35);
573
+ border-color: rgba(229, 57, 53, 0.4);
574
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
575
+ }
576
+ .panel-score-pop[data-tier="2"] {
577
+ --score-accent-a: #ff6b35;
578
+ --score-accent-b: #ff3366;
579
+ --score-glow: rgba(255, 107, 53, 0.35);
580
+ border-color: rgba(255, 107, 53, 0.4);
581
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
582
+ }
583
+ .panel-score-pop[data-tier="3"] {
584
+ --score-accent-a: #ffb347;
585
+ --score-accent-b: #ffd23f;
586
+ --score-glow: rgba(255, 210, 63, 0.3);
587
+ border-color: rgba(255, 210, 63, 0.4);
588
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
589
+ }
590
+ .panel-score-pop[data-tier="4"] {
591
+ --score-accent-a: #4ecdc4;
592
+ --score-accent-b: #29b6f6;
593
+ --score-glow: rgba(78, 205, 196, 0.3);
594
+ border-color: rgba(78, 205, 196, 0.4);
595
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
596
+ }
597
+ .panel-score-pop[data-tier="5"] {
598
+ --score-accent-a: #06ffa5;
599
+ --score-accent-b: #43a047;
600
+ --score-glow: rgba(6, 255, 165, 0.3);
601
+ border-color: rgba(6, 255, 165, 0.4);
602
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
603
+ }
604
+
560
605
  .panel-score-pop::before {
561
606
  display: none;
562
607
  }
563
608
 
564
609
  .panel-score-pop:hover {
565
610
  transform: none;
566
- box-shadow: var(--glow), 0 20px 60px rgba(0, 0, 0, 0.4);
611
+ box-shadow: 0 0 30px var(--score-glow), 0 20px 60px rgba(0, 0, 0, 0.4);
567
612
  }
568
613
 
569
614
  .panel-score-pop .panel-body-score {
@@ -587,22 +632,22 @@ body.dashboard-page {
587
632
  font-size: 3.25rem;
588
633
  font-weight: 800;
589
634
  line-height: 1;
590
- background: linear-gradient(180deg, var(--accent-orange) 0%, var(--accent-red) 100%);
635
+ background: linear-gradient(180deg, var(--score-accent-a) 0%, var(--score-accent-b) 100%);
591
636
  -webkit-background-clip: text;
592
637
  -webkit-text-fill-color: transparent;
593
638
  background-clip: text;
594
- filter: drop-shadow(0 0 20px rgba(255, 107, 53, 0.35));
639
+ filter: drop-shadow(0 0 20px var(--score-glow));
595
640
  }
596
641
 
597
642
  .panel-score-pop .score-of {
598
643
  font-size: 1.35rem;
599
644
  font-weight: 700;
600
- color: var(--text-muted);
645
+ color: var(--score-accent-a);
601
646
  }
602
647
 
603
648
  .panel-score-pop .score-label {
604
649
  display: inline-block;
605
- background: linear-gradient(135deg, var(--accent-orange), var(--accent-red));
650
+ background: linear-gradient(135deg, var(--score-accent-a), var(--score-accent-b));
606
651
  padding: 0.45rem 1.1rem;
607
652
  border-radius: 50px;
608
653
  font-family: "Inter", sans-serif;
@@ -610,12 +655,16 @@ body.dashboard-page {
610
655
  font-weight: 700;
611
656
  letter-spacing: 0.5px;
612
657
  text-transform: uppercase;
613
- box-shadow: 0 6px 18px rgba(255, 107, 53, 0.35);
658
+ box-shadow: 0 6px 18px var(--score-glow);
614
659
  margin-bottom: 0.35rem;
615
660
  -webkit-text-fill-color: initial;
616
661
  color: #fff;
617
662
  }
618
663
 
664
+ .panel-score-pop[data-tier="3"] .score-label {
665
+ color: #1a1a1a;
666
+ }
667
+
619
668
  .panel-score-pop .score-desc {
620
669
  font-size: 0.9rem;
621
670
  color: var(--text-muted);
@@ -652,18 +701,6 @@ body.dashboard-page {
652
701
  flex-wrap: wrap;
653
702
  }
654
703
 
655
- .panel-score-pop[data-tier="1"] .score-num { --accent-orange: #ff6b6b; --accent-red: #e53935; }
656
- .panel-score-pop[data-tier="2"] .score-num { --accent-orange: #ff6b35; --accent-red: #ff3366; }
657
- .panel-score-pop[data-tier="3"] .score-num { --accent-orange: #ffb347; --accent-red: #ffd23f; }
658
- .panel-score-pop[data-tier="4"] .score-num { --accent-orange: #4ecdc4; --accent-red: #29b6f6; }
659
- .panel-score-pop[data-tier="5"] .score-num { --accent-orange: #06ffa5; --accent-red: #43a047; }
660
-
661
- .panel-score-pop[data-tier="1"] .score-label { background: linear-gradient(135deg, #ff6b6b, #e53935); }
662
- .panel-score-pop[data-tier="2"] .score-label { background: linear-gradient(135deg, var(--accent-orange), var(--accent-red)); }
663
- .panel-score-pop[data-tier="3"] .score-label { background: linear-gradient(135deg, #ffb347, #ffd23f); color: #1a1a1a; }
664
- .panel-score-pop[data-tier="4"] .score-label { background: linear-gradient(135deg, #4ecdc4, #29b6f6); }
665
- .panel-score-pop[data-tier="5"] .score-label { background: linear-gradient(135deg, #06ffa5, #43a047); }
666
-
667
704
  /* ——— Description of problems panel (top-right) ——— */
668
705
  .panel-empty {
669
706
  margin: 0;
@@ -792,6 +829,8 @@ body.dashboard-page {
792
829
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
793
830
  gap: 0.4rem;
794
831
  min-height: 80px;
832
+ max-height: 10.5rem; /* ~2 rows of cells (72px + gap) * 2 */
833
+ overflow-y: auto;
795
834
  padding: 0.15rem 0;
796
835
  }
797
836
 
@@ -1091,12 +1130,12 @@ body.dashboard-page {
1091
1130
  .dashboard-main ::-webkit-scrollbar-thumb,
1092
1131
  .panel-body::-webkit-scrollbar-thumb,
1093
1132
  .overlay-prompt-wrap::-webkit-scrollbar-thumb {
1094
- background: var(--accent-orange);
1133
+ background: var(--border);
1095
1134
  border-radius: 4px;
1096
1135
  }
1097
1136
 
1098
1137
  .dashboard-main ::-webkit-scrollbar-thumb:hover,
1099
1138
  .panel-body::-webkit-scrollbar-thumb:hover,
1100
1139
  .overlay-prompt-wrap::-webkit-scrollbar-thumb:hover {
1101
- background: var(--accent-red);
1140
+ background: var(--text-muted);
1102
1141
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tech-debt-visualizer",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
4
4
  "description": "Language-agnostic CLI that analyzes repos and generates interactive technical debt visualizations with AI-powered insights",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",