tech-debt-visualizer 0.2.18 → 0.2.20

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.
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Technical Debt Cleanliness Score: map debt score (0-100) to one of five tiers.
3
- * Lower debt score = higher tier (cleaner code).
2
+ * Technical Debt Cleanliness Score: map cleanliness score (0-100) to one of five tiers.
3
+ * Cleanliness: 0 = most debt, 100 = least debt. Tier 1 = worst, Tier 5 = best.
4
4
  */
5
5
  export interface CleanlinessTier {
6
6
  tier: 1 | 2 | 3 | 4 | 5;
7
7
  label: string;
8
8
  description: string;
9
9
  }
10
- /** Debt score 0-100 (higher = worse). Returns tier 1-5 (1 = worst, 5 = best). */
11
- export declare function getCleanlinessTier(debtScore: number): CleanlinessTier;
10
+ /** Cleanliness score 0-100 (0 = worst, 100 = best). Returns tier 1-5: 1 = 0-20, 2 = 21-40, 3 = 41-60, 4 = 61-80, 5 = 81-100. */
11
+ export declare function getCleanlinessTier(cleanlinessScore: number): CleanlinessTier;
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Technical Debt Cleanliness Score: map debt score (0-100) to one of five tiers.
3
- * Lower debt score = higher tier (cleaner code).
2
+ * Technical Debt Cleanliness Score: map cleanliness score (0-100) to one of five tiers.
3
+ * Cleanliness: 0 = most debt, 100 = least debt. Tier 1 = worst, Tier 5 = best.
4
4
  */
5
5
  const TIERS = [
6
6
  { tier: 1, label: "Prompt Roulette Champion", description: "100% vibes, 0% understanding" },
@@ -9,16 +9,16 @@ const TIERS = [
9
9
  { tier: 4, label: "Power Tool User", description: "AI is the nail gun" },
10
10
  { tier: 5, label: "Pure Coder", description: "Hand-crafted artisanal code, no AI needed" },
11
11
  ];
12
- /** Debt score 0-100 (higher = worse). Returns tier 1-5 (1 = worst, 5 = best). */
13
- export function getCleanlinessTier(debtScore) {
14
- const clamped = Math.max(0, Math.min(100, Math.round(debtScore)));
12
+ /** Cleanliness score 0-100 (0 = worst, 100 = best). Returns tier 1-5: 1 = 0-20, 2 = 21-40, 3 = 41-60, 4 = 61-80, 5 = 81-100. */
13
+ export function getCleanlinessTier(cleanlinessScore) {
14
+ const clamped = Math.max(0, Math.min(100, Math.round(cleanlinessScore)));
15
15
  if (clamped <= 20)
16
- return TIERS[4]; // 5/5
16
+ return TIERS[0]; // tier 1
17
17
  if (clamped <= 40)
18
- return TIERS[3]; // 4/5
18
+ return TIERS[1]; // tier 2
19
19
  if (clamped <= 60)
20
- return TIERS[2]; // 3/5
20
+ return TIERS[2]; // tier 3
21
21
  if (clamped <= 80)
22
- return TIERS[1]; // 2/5
23
- return TIERS[0]; // 1/5
22
+ return TIERS[3]; // tier 4
23
+ return TIERS[4]; // tier 5
24
24
  }
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import { Command } from "commander";
10
10
  import chalk from "chalk";
11
11
  import cliProgress from "cli-progress";
12
12
  import { getCleanlinessTier } from "./cleanliness-score.js";
13
- import { getDebtScore } from "./debt-score.js";
13
+ import { getCleanlinessScore, getDebtScore } from "./debt-score.js";
14
14
  import { runAnalysis } from "./engine.js";
15
15
  import { assessFileCleanliness, assessOverallCleanliness, resolveLLMConfig, } from "./llm.js";
16
16
  import { generateHtmlReport } from "./reports/html.js";
@@ -113,7 +113,7 @@ program
113
113
  ...run.fileMetrics[idx],
114
114
  llmAssessment: result.value.assessment,
115
115
  llmSuggestedCode: result.value.suggestedCode,
116
- llmFileScore: result.value.fileScore,
116
+ llmFileScore: result.value.fileScore != null ? 100 - result.value.fileScore : undefined,
117
117
  llmSeverity: result.value.severity,
118
118
  llmRawAssessment: result.value.raw,
119
119
  };
@@ -130,7 +130,7 @@ program
130
130
  if (overall) {
131
131
  run.llmOverallAssessment = overall.assessment;
132
132
  if (overall.score != null)
133
- run.llmOverallScore = overall.score;
133
+ run.llmOverallScore = 100 - overall.score;
134
134
  if (overall.severity)
135
135
  run.llmOverallSeverity = overall.severity;
136
136
  run.llmOverallRaw = overall.raw;
@@ -189,13 +189,13 @@ program
189
189
  });
190
190
  function printCliReport(run, ci) {
191
191
  const { debtItems, fileMetrics, errors } = run;
192
- const score = getDebtScore(run);
193
- const cleanliness = getCleanlinessTier(score);
192
+ const cleanlinessScore = getCleanlinessScore(run);
193
+ const cleanliness = getCleanlinessTier(cleanlinessScore);
194
194
  process.stdout.write("\n");
195
195
  process.stdout.write(chalk.bold.dim(" Technical Debt Cleanliness Score\n"));
196
196
  process.stdout.write(" " + "—".repeat(52) + "\n");
197
197
  const tierColor = cleanlinessTierColor(cleanliness.tier);
198
- process.stdout.write(tierColor(` ${cleanliness.label} (${Math.round(score)}/100)\n`));
198
+ process.stdout.write(tierColor(` ${cleanliness.label} (${cleanliness.tier} out of 5)\n`));
199
199
  process.stdout.write(tierColor(` ${cleanliness.description}\n`));
200
200
  process.stdout.write(" " + "—".repeat(52) + "\n\n");
201
201
  process.stdout.write(chalk.bold(" Summary\n"));
@@ -205,8 +205,7 @@ function printCliReport(run, ci) {
205
205
  if (run.debtTrend && run.debtTrend.length > 0) {
206
206
  process.stdout.write(` Recent commits: ${chalk.cyan(String(run.debtTrend.length))}\n`);
207
207
  }
208
- process.stdout.write(` Debt score: ${severityColor(score)} / 100\n`);
209
- process.stdout.write(chalk.dim(" (weighted average of debt item severity × confidence, 0–100)\n\n"));
208
+ process.stdout.write(` Score: ${tierColor(`${cleanliness.tier} out of 5`)}\n\n`);
210
209
  const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };
211
210
  for (const d of debtItems) {
212
211
  bySeverity[d.severity]++;
@@ -4,9 +4,9 @@
4
4
  */
5
5
  import type { AnalysisRun } from "./types.js";
6
6
  /**
7
- * Debt score 0–100. Uses a single consistent source when LLM is available so overall and file scores match:
8
- * - If LLM overall score is set: use it as-is.
9
- * - Else if any file has LLM file score: use average of those.
10
- * - Else: static score from debt items.
7
+ * Debt score 0–100 (higher = more debt). Stored and computed internally; for display use getCleanlinessScore.
8
+ * When LLM is used, we store debt = 100 - llm_cleanliness so that this still returns "debt".
11
9
  */
12
10
  export declare function getDebtScore(run: AnalysisRun): number;
11
+ /** Cleanliness score 0–100 (0 = most debt, 100 = least debt). Use this for display and tier. */
12
+ export declare function getCleanlinessScore(run: AnalysisRun): number;
@@ -12,10 +12,8 @@ function getStaticDebtScore(run) {
12
12
  return Math.min(100, Math.round((sum / items.length) * 25));
13
13
  }
14
14
  /**
15
- * Debt score 0–100. Uses a single consistent source when LLM is available so overall and file scores match:
16
- * - If LLM overall score is set: use it as-is.
17
- * - Else if any file has LLM file score: use average of those.
18
- * - Else: static score from debt items.
15
+ * Debt score 0–100 (higher = more debt). Stored and computed internally; for display use getCleanlinessScore.
16
+ * When LLM is used, we store debt = 100 - llm_cleanliness so that this still returns "debt".
19
17
  */
20
18
  export function getDebtScore(run) {
21
19
  if (run.llmOverallScore != null) {
@@ -30,3 +28,7 @@ export function getDebtScore(run) {
30
28
  }
31
29
  return getStaticDebtScore(run);
32
30
  }
31
+ /** Cleanliness score 0–100 (0 = most debt, 100 = least debt). Use this for display and tier. */
32
+ export function getCleanlinessScore(run) {
33
+ return 100 - getDebtScore(run);
34
+ }
package/dist/llm.js CHANGED
@@ -292,7 +292,7 @@ ${snippet}
292
292
  Output only:
293
293
  1. A two- to four-sentence summary of the issues (how clean/maintainable, main concerns). No code block unless absolutely necessary to demonstrate.
294
294
  2. On the next line write only one word: critical, high, medium, low, or none (this file's technical debt severity; none = no significant debt).
295
- 3. On the line after that write only a number 0-100 (100 = most technical debt).
295
+ 3. On the line after that write only a number 0-100 (0 = most debt, 100 = least debt / cleanest).
296
296
  No preamble.`;
297
297
  const raw = await chat(prompt, {
298
298
  ...resolved,
@@ -330,7 +330,7 @@ Top risk files (by hotspot): ${topFiles.join(", ")}
330
330
  Output only:
331
331
  1. A single paragraph of 7–10 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
- 3. On the line after that write only a number 0-100 (100 = most debt).
333
+ 3. On the line after that write only a number 0-100 (0 = most debt, 100 = least debt / cleanest).
334
334
  No preamble.`;
335
335
  const raw = await chat(prompt, {
336
336
  ...resolved,
@@ -506,7 +506,7 @@ body.dashboard-page {
506
506
  display: flex;
507
507
  align-items: baseline;
508
508
  justify-content: center;
509
- gap: 0.4rem; /* space between number and "of 100" */
509
+ gap: 0.4rem; /* space between number and "out of 5" */
510
510
  margin-bottom: 0.5rem;
511
511
  }
512
512
 
@@ -2,7 +2,7 @@ import { readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { getCleanlinessTier } from "../cleanliness-score.js";
5
- import { getDebtScore } from "../debt-score.js";
5
+ import { getCleanlinessScore } from "../debt-score.js";
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
7
  const ASSETS_DIR = join(__dirname, "assets");
8
8
  export async function generateHtmlReport(run, options) {
@@ -46,9 +46,9 @@ function adjustHexBrightness(hex, factor) {
46
46
  }
47
47
  function buildHtml(run, title, darkMode, css, script) {
48
48
  const theme = darkMode ? "dark" : "light";
49
- const debtScore = getDebtScore(run);
50
- const scoreNum = Math.round(Math.max(0, Math.min(100, debtScore)));
51
- const cleanliness = getCleanlinessTier(debtScore);
49
+ const cleanlinessScore = getCleanlinessScore(run);
50
+ const scoreNum = Math.round(Math.max(0, Math.min(100, cleanlinessScore)));
51
+ const cleanliness = getCleanlinessTier(cleanlinessScore);
52
52
  const hasLlm = !!(run.llmOverallAssessment || run.llmOverallRaw);
53
53
  const dataJson = JSON.stringify({
54
54
  fileMetrics: run.fileMetrics,
@@ -60,7 +60,7 @@ function buildHtml(run, title, darkMode, css, script) {
60
60
  summary: {
61
61
  filesAnalyzed: run.fileMetrics.length,
62
62
  debtCount: run.debtItems.length,
63
- debtScore,
63
+ debtScore: 100 - cleanlinessScore,
64
64
  cleanlinessScore: scoreNum,
65
65
  cleanlinessTier: cleanliness.tier,
66
66
  cleanlinessLabel: cleanliness.label,
@@ -78,11 +78,11 @@ function buildHtml(run, title, darkMode, css, script) {
78
78
  <meta charset="UTF-8" />
79
79
  <meta name="viewport" content="width=device-width, initial-scale=1" />
80
80
  <title>${escapeHtml(title)}</title>
81
- <meta property="og:title" content="${escapeHtml(title)} — ${scoreNum}/100 ${escapeHtml(cleanliness.label)}" />
81
+ <meta property="og:title" content="${escapeHtml(title)} — ${cleanliness.tier} out of 5 ${escapeHtml(cleanliness.label)}" />
82
82
  <meta property="og:description" content="${escapeHtml(cleanliness.description)}" />
83
83
  <meta property="og:type" content="website" />
84
84
  <meta name="twitter:card" content="summary" />
85
- <meta name="twitter:title" content="${escapeHtml(title)} — ${scoreNum}/100" />
85
+ <meta name="twitter:title" content="${escapeHtml(title)} — ${cleanliness.tier} out of 5" />
86
86
  <meta name="twitter:description" content="${escapeHtml(cleanliness.label)}: ${escapeHtml(cleanliness.description)}" />
87
87
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
88
88
  <style>${css}</style>
@@ -95,9 +95,9 @@ function buildHtml(run, title, darkMode, css, script) {
95
95
  <span class="dashboard-meta">${escapeHtml(run.repoPath)}</span>
96
96
  </div>
97
97
  <div class="dashboard-header-right">
98
- <div class="dashboard-score tier-${cleanliness.tier}" aria-label="Score ${scoreNum} of 100">
99
- <span class="dashboard-score-value">${scoreNum}</span>
100
- <span class="dashboard-score-of">/ 100</span>
98
+ <div class="dashboard-score tier-${cleanliness.tier}" aria-label="Score ${cleanliness.tier} out of 5">
99
+ <span class="dashboard-score-value">${cleanliness.tier}</span>
100
+ <span class="dashboard-score-of"> out of 5</span>
101
101
  <span class="dashboard-score-label">${escapeHtml(cleanliness.label)}</span>
102
102
  </div>
103
103
  <button type="button" class="btn-ai-prompts btn-ai-prompts-header" id="btnAiPrompts">AI cleanup prompts</button>
@@ -114,8 +114,8 @@ function buildHtml(run, title, darkMode, css, script) {
114
114
  </div>
115
115
  <div class="panel-body panel-body-score">
116
116
  <div class="score-numeric">
117
- <span class="score-num">${scoreNum}</span>
118
- <span class="score-of">of 100</span>
117
+ <span class="score-num">${cleanliness.tier}</span>
118
+ <span class="score-of"> out of 5</span>
119
119
  </div>
120
120
  <p class="score-label">${escapeHtml(cleanliness.label)}</p>
121
121
  <p class="score-desc">${escapeHtml(cleanliness.description)}</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tech-debt-visualizer",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
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",