tech-debt-visualizer 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/reports/html.js +109 -118
  2. package/package.json +1 -1
@@ -41,189 +41,180 @@ function buildHtml(run, title, darkMode) {
41
41
  <meta charset="UTF-8" />
42
42
  <meta name="viewport" content="width=device-width, initial-scale=1" />
43
43
  <title>${escapeHtml(title)}</title>
44
+ <meta property="og:title" content="${escapeHtml(title)} — ${cleanliness.tier}/5 ${escapeHtml(cleanliness.label)}" />
45
+ <meta property="og:description" content="${escapeHtml(cleanliness.description)}" />
46
+ <meta property="og:type" content="website" />
47
+ <meta name="twitter:card" content="summary" />
48
+ <meta name="twitter:title" content="${escapeHtml(title)} — ${cleanliness.tier}/5" />
49
+ <meta name="twitter:description" content="${escapeHtml(cleanliness.label)}: ${escapeHtml(cleanliness.description)}" />
44
50
  <style>
45
51
  :root {
46
- --bg: #0f0f12;
47
- --surface: #1a1a1f;
48
- --border: #2a2a32;
49
- --text: #e4e4e7;
50
- --text-muted: #71717a;
51
- --accent: #6366f1;
52
- --accent-dim: #4f46e5;
53
- --green: #22c55e;
54
- --yellow: #eab308;
55
- --red: #ef4444;
56
- --gradient: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
57
- }
58
- [data-theme="light"] {
59
- --bg: #fafafa;
52
+ --bg: #fff;
60
53
  --surface: #fff;
61
- --border: #e4e4e7;
62
- --text: #18181b;
63
- --text-muted: #71717a;
54
+ --border: #ccc;
55
+ --text: #222;
56
+ --text-muted: #666;
57
+ --link: #0568c2;
58
+ }
59
+ [data-theme="dark"] {
60
+ --bg: #1a1a1a;
61
+ --surface: #252525;
62
+ --border: #404040;
63
+ --text: #e0e0e0;
64
+ --text-muted: #999;
65
+ --link: #6eb3f7;
64
66
  }
65
67
  * { box-sizing: border-box; }
66
68
  body {
67
69
  margin: 0;
68
- font-family: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
70
+ font-family: system-ui, sans-serif;
69
71
  background: var(--bg);
70
72
  color: var(--text);
71
73
  min-height: 100vh;
72
- letter-spacing: -0.01em;
74
+ font-size: 14px;
75
+ line-height: 1.5;
73
76
  }
74
- .container { max-width: 1100px; margin: 0 auto; padding: 2.5rem 2rem; }
77
+ .container { max-width: 900px; margin: 0 auto; padding: 1.5rem 1.25rem; }
75
78
  .no-llm-banner {
76
79
  width: 100%;
77
80
  background: var(--surface);
78
- border-bottom: 2px solid var(--border);
79
- padding: 0.75rem 1.5rem;
80
- text-align: center;
81
- }
82
- .no-llm-banner .no-llm-cta { font-size: 1rem; font-weight: 600; color: var(--text); margin: 0; }
83
- .hero-caption { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted); margin: 0 0 1rem; font-weight: 600; text-align: center; }
84
- .hero {
81
+ border-bottom: 1px solid var(--border);
82
+ padding: 0.5rem 1rem;
85
83
  text-align: center;
86
- margin-bottom: 2rem;
87
84
  }
85
+ .no-llm-banner .no-llm-cta { font-size: 14px; font-weight: normal; color: var(--text); margin: 0; }
86
+ .hero-caption { font-size: 12px; color: var(--text-muted); margin: 0 0 0.5rem; text-align: center; }
87
+ .hero { text-align: center; margin-bottom: 1.5rem; }
88
88
  .score-badge {
89
- display: inline-block;
90
- width: 120px;
91
- padding: 1rem 0.5rem 0.85rem;
89
+ display: inline-flex;
90
+ flex-direction: column;
91
+ align-items: center;
92
+ justify-content: center;
93
+ width: 110px;
94
+ height: 120px;
95
+ margin-bottom: 0.5rem;
92
96
  background: var(--tier-bg);
93
- color: var(--tier-fg);
94
- border: 2px solid var(--tier-fg);
95
- border-radius: 8px;
96
- margin-bottom: 0.75rem;
97
+ color: var(--tier-num);
98
+ clip-path: polygon(50% 0%, 100% 18%, 100% 82%, 50% 100%, 0% 82%, 0% 18%);
99
+ -webkit-clip-path: polygon(50% 0%, 100% 18%, 100% 82%, 50% 100%, 0% 82%, 0% 18%);
97
100
  }
98
- .score-badge .num { display: block; font-size: 3rem; font-weight: 700; line-height: 1; letter-spacing: -0.03em; text-align: center; }
99
- .score-badge .of { display: block; font-size: 0.75rem; font-weight: 600; text-align: center; text-transform: uppercase; letter-spacing: 0.08em; margin-top: 0.25rem; opacity: 0.9; }
100
- .hero .score-label { font-size: 1.25rem; font-weight: 700; color: var(--text); margin: 0 0 0.25rem; letter-spacing: -0.01em; }
101
- .hero .score-desc { font-size: 0.9rem; color: var(--text-muted); line-height: 1.5; margin: 0 0 0.5rem; max-width: 380px; margin-left: auto; margin-right: auto; }
102
- .hero .report-meta { font-size: 0.8rem; color: var(--text-muted); }
103
- .hero.tier-1 { --tier-bg: #1c1917; --tier-fg: #f87171; }
104
- .hero.tier-2 { --tier-bg: #1c1917; --tier-fg: #fb923c; }
105
- .hero.tier-3 { --tier-bg: #1c1917; --tier-fg: #facc15; }
106
- .hero.tier-4 { --tier-bg: #0f172a; --tier-fg: #38bdf8; }
107
- .hero.tier-5 { --tier-bg: #052e16; --tier-fg: #4ade80; }
108
- [data-theme="light"] .hero.tier-1 { --tier-bg: #fef2f2; --tier-fg: #dc2626; }
109
- [data-theme="light"] .hero.tier-2 { --tier-bg: #fff7ed; --tier-fg: #ea580c; }
110
- [data-theme="light"] .hero.tier-3 { --tier-bg: #fefce8; --tier-fg: #ca8a04; }
111
- [data-theme="light"] .hero.tier-4 { --tier-bg: #f0f9ff; --tier-fg: #0284c7; }
112
- [data-theme="light"] .hero.tier-5 { --tier-bg: #f0fdf4; --tier-fg: #16a34a; }
101
+ .score-badge .num { display: block; font-size: 2.75rem; font-weight: 900; line-height: 1; text-align: center; }
102
+ .score-badge .of { display: block; font-size: 12px; font-weight: bold; text-align: center; margin-top: 0.15rem; color: var(--tier-num); opacity: 0.95; }
103
+ .hero .score-label { font-size: 1.1rem; font-weight: bold; color: var(--text); margin: 0 0 0.2rem; }
104
+ .hero .score-desc { font-size: 13px; color: var(--text-muted); margin: 0 0 0.35rem; max-width: 360px; margin-left: auto; margin-right: auto; }
105
+ .hero .report-meta { font-size: 12px; color: var(--text-muted); }
106
+ .hero.tier-1 { --tier-bg: #c00; --tier-num: #fff; }
107
+ .hero.tier-2 { --tier-bg: #e85d00; --tier-num: #fff; }
108
+ .hero.tier-3 { --tier-bg: #b8860b; --tier-num: #fff; }
109
+ .hero.tier-4 { --tier-bg: #069; --tier-num: #fff; }
110
+ .hero.tier-5 { --tier-bg: #0a6b0a; --tier-num: #fff; }
113
111
  .summary-cards {
114
112
  display: grid;
115
113
  grid-template-columns: repeat(4, 1fr);
116
- gap: 1rem;
117
- margin-bottom: 2.5rem;
114
+ gap: 0.75rem;
115
+ margin-bottom: 1.5rem;
118
116
  }
119
117
  @media (max-width: 640px) { .summary-cards { grid-template-columns: repeat(2, 1fr); } }
120
118
  .card {
121
119
  background: var(--surface);
122
120
  border: 1px solid var(--border);
123
- border-radius: 12px;
124
- padding: 1.25rem 1.35rem;
125
- transition: border-color 0.2s;
121
+ padding: 0.75rem 1rem;
126
122
  }
127
- .card:hover { border-color: var(--text-muted); }
128
- .card .value { font-size: 1.65rem; font-weight: 700; color: var(--text); letter-spacing: -0.02em; }
129
- .card .label { font-size: 0.72rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 0.2rem; }
123
+ .card .value { font-size: 1.35rem; font-weight: bold; color: var(--text); }
124
+ .card .label { font-size: 12px; color: var(--text-muted); margin-top: 0.15rem; }
130
125
  .section {
131
126
  background: var(--surface);
132
127
  border: 1px solid var(--border);
133
- border-radius: 12px;
134
- padding: 1.5rem;
135
- margin-bottom: 1.5rem;
128
+ padding: 1rem 1.25rem;
129
+ margin-bottom: 1rem;
136
130
  }
137
- .section h2 { font-size: 1.1rem; margin: 0 0 1rem; color: var(--text-muted); font-weight: 600; }
131
+ .section h2 { font-size: 1rem; margin: 0 0 0.75rem; color: var(--text); font-weight: bold; }
138
132
  #treemap {
139
133
  display: flex;
140
134
  flex-wrap: wrap;
141
- gap: 8px;
142
- min-height: 200px;
143
- padding: 0.5rem 0;
135
+ gap: 4px;
136
+ min-height: 160px;
137
+ padding: 0.25rem 0;
144
138
  }
145
139
  .treemap-cell {
146
- border-radius: 8px;
147
140
  display: flex;
148
141
  align-items: flex-end;
149
- min-width: 72px;
150
- padding: 8px 10px;
151
- font-size: 0.72rem;
142
+ min-width: 64px;
143
+ padding: 6px 8px;
144
+ font-size: 11px;
152
145
  cursor: pointer;
153
- transition: transform 0.15s, filter 0.15s, box-shadow 0.15s;
154
146
  overflow: hidden;
155
147
  text-overflow: ellipsis;
156
148
  white-space: nowrap;
149
+ border: 1px solid rgba(0,0,0,0.1);
157
150
  }
158
- .treemap-cell:hover { transform: scale(1.04); filter: brightness(1.1); box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
159
- .treemap-cell[data-severity="critical"] { background: linear-gradient(180deg, #ef4444 0%, #b91c1c 100%); color: #fff; }
160
- .treemap-cell[data-severity="high"] { background: linear-gradient(180deg, #f59e0b 0%, #d97706 100%); color: #fff; }
161
- .treemap-cell[data-severity="medium"] { background: linear-gradient(180deg, #eab308 0%, #ca8a04 100%); color: #1a1a1f; }
162
- .treemap-cell[data-severity="low"] { background: linear-gradient(180deg, #22c55e 0%, #16a34a 100%); color: #fff; }
163
- .treemap-cell[data-severity="none"] { background: var(--border); color: var(--text-muted); }
151
+ .treemap-cell:hover { outline: 2px solid var(--text); outline-offset: 1px; }
152
+ .treemap-cell[data-severity="critical"] { background: #c00; color: #fff; border-color: #900; }
153
+ .treemap-cell[data-severity="high"] { background: #e85d00; color: #fff; border-color: #b84a00; }
154
+ .treemap-cell[data-severity="medium"] { background: #b8860b; color: #fff; border-color: #8b6914; }
155
+ .treemap-cell[data-severity="low"] { background: #0a6b0a; color: #fff; border-color: #064906; }
156
+ .treemap-cell[data-severity="none"] { background: var(--border); color: var(--text-muted); border-color: var(--border); }
164
157
  .debt-list { list-style: none; padding: 0; margin: 0; }
165
158
  .debt-list li {
166
159
  border-bottom: 1px solid var(--border);
167
- padding: 0.85rem 0;
160
+ padding: 0.6rem 0;
168
161
  cursor: pointer;
169
- transition: background 0.15s;
170
162
  }
171
163
  .debt-list li:last-child { border-bottom: none; }
172
- .debt-list li:hover { background: rgba(99, 102, 241, 0.08); }
173
- .debt-list .title { font-weight: 600; margin-bottom: 0.25rem; }
174
- .debt-list .meta { font-size: 0.8rem; color: var(--text-muted); }
175
- .debt-list .insight { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.35rem; line-height: 1.4; }
176
- .badge { display: inline-block; padding: 0.2em 0.5em; border-radius: 4px; font-size: 0.7rem; font-weight: 600; }
177
- .badge-critical { background: #ef4444; color: #fff; }
178
- .badge-high { background: #f59e0b; color: #fff; }
179
- .badge-medium { background: #eab308; color: #1a1a1f; }
180
- .badge-low { background: #22c55e; color: #fff; }
164
+ .debt-list li:hover { background: var(--bg); }
165
+ .debt-list .title { font-weight: bold; margin-bottom: 0.2rem; }
166
+ .debt-list .meta { font-size: 12px; color: var(--text-muted); }
167
+ .debt-list .insight { font-size: 13px; color: var(--text-muted); margin-top: 0.25rem; line-height: 1.4; }
168
+ .badge { display: inline-block; padding: 0.15em 0.4em; font-size: 11px; font-weight: bold; }
169
+ .badge-critical { background: #c00; color: #fff; }
170
+ .badge-high { background: #e85d00; color: #fff; }
171
+ .badge-medium { background: #b8860b; color: #fff; }
172
+ .badge-low { background: #0a6b0a; color: #fff; }
181
173
  #detail {
182
174
  position: fixed;
183
175
  inset: 0;
184
- background: rgba(0,0,0,0.6);
176
+ background: rgba(0,0,0,0.5);
185
177
  display: none;
186
178
  align-items: center;
187
179
  justify-content: center;
188
180
  z-index: 100;
189
- padding: 2rem;
181
+ padding: 1rem;
190
182
  }
191
183
  #detail.show { display: flex; }
192
184
  #detail .panel {
193
185
  background: var(--surface);
194
186
  border: 1px solid var(--border);
195
- border-radius: 16px;
196
- max-width: 520px;
187
+ max-width: 480px;
197
188
  width: 100%;
198
189
  max-height: 85vh;
199
190
  overflow: auto;
200
- padding: 1.5rem;
191
+ padding: 1.25rem;
201
192
  }
202
- #detail .panel h3 { margin: 0 0 0.5rem; }
203
- #detail .panel .file { font-family: monospace; font-size: 0.85rem; color: var(--accent); }
204
- #detail .panel .explanation { margin-top: 1rem; line-height: 1.5; color: var(--text-muted); }
205
- #detail .panel .close-hint { margin-top: 1rem; font-size: 0.75rem; color: var(--text-muted); opacity: 0.8; }
206
- #detail .panel .file-assessment { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); font-size: 0.9rem; color: var(--text-muted); line-height: 1.5; }
207
- #detail .panel .file-assessment strong { color: var(--text); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
208
- #detail .panel .suggested-code { margin-top: 1rem; padding: 0.75rem; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; font-size: 0.8rem; overflow-x: auto; }
193
+ #detail .panel h3 { margin: 0 0 0.35rem; font-size: 1rem; }
194
+ #detail .panel .file { font-family: ui-monospace, monospace; font-size: 13px; color: var(--link); }
195
+ #detail .panel .explanation { margin-top: 0.75rem; line-height: 1.5; color: var(--text-muted); font-size: 13px; }
196
+ #detail .panel .close-hint { margin-top: 0.75rem; font-size: 12px; color: var(--text-muted); }
197
+ #detail .panel .file-assessment { margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--border); font-size: 13px; color: var(--text-muted); line-height: 1.5; }
198
+ #detail .panel .file-assessment strong { color: var(--text); font-size: 12px; }
199
+ #detail .panel .suggested-code { margin-top: 0.75rem; padding: 0.5rem; background: var(--bg); border: 1px solid var(--border); font-size: 12px; overflow-x: auto; }
209
200
  #detail .panel .suggested-code pre { margin: 0; white-space: pre-wrap; }
210
- .llm-overall { border-left: 4px solid var(--accent); }
211
- .llm-overall h2 { color: var(--accent); }
212
- .llm-overall .llm-overall-text { margin: 0; color: var(--text); line-height: 1.6; font-size: 1rem; }
213
- .llm-next-steps h2 { color: var(--accent); }
214
- .llm-next-steps ul { margin: 0; padding-left: 1.25rem; color: var(--text); line-height: 1.6; }
215
- .priority-matrix { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 1rem; }
216
- .priority-matrix .quadrant { padding: 1rem; border-radius: 8px; border: 1px solid var(--border); }
217
- .priority-matrix .quadrant h4 { margin: 0 0 0.5rem; font-size: 0.9rem; }
218
- .priority-matrix .quadrant p { margin: 0; font-size: 0.8rem; color: var(--text-muted); }
219
- .section-desc { font-size: 0.875rem; color: var(--text-muted); margin: -0.5rem 0 1rem; line-height: 1.45; }
220
- .legend { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; margin-bottom: 1rem; font-size: 0.8rem; color: var(--text-muted); }
221
- .legend span { display: inline-flex; align-items: center; gap: 0.35rem; }
222
- .legend .swatch { width: 12px; height: 12px; border-radius: 3px; }
223
- .legend .swatch-crit { background: linear-gradient(135deg, #ef4444, #b91c1c); }
224
- .legend .swatch-high { background: linear-gradient(135deg, #f59e0b, #d97706); }
225
- .legend .swatch-med { background: linear-gradient(135deg, #eab308, #ca8a04); }
226
- .legend .swatch-low { background: linear-gradient(135deg, #22c55e, #16a34a); }
201
+ .llm-overall { border-left: 3px solid var(--link); padding-left: 0.5rem; margin-left: -0.5rem; }
202
+ .llm-overall h2 { color: var(--text); font-size: 1rem; }
203
+ .llm-overall .llm-overall-text { margin: 0; color: var(--text); line-height: 1.5; font-size: 14px; }
204
+ .llm-next-steps h2 { color: var(--text); font-size: 1rem; }
205
+ .llm-next-steps ul { margin: 0; padding-left: 1.25rem; color: var(--text); line-height: 1.5; }
206
+ .priority-matrix { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 0.75rem; }
207
+ .priority-matrix .quadrant { padding: 0.75rem; border: 1px solid var(--border); }
208
+ .priority-matrix .quadrant h4 { margin: 0 0 0.35rem; font-size: 0.9rem; font-weight: bold; }
209
+ .priority-matrix .quadrant p { margin: 0; font-size: 13px; color: var(--text-muted); }
210
+ .section-desc { font-size: 13px; color: var(--text-muted); margin: -0.35rem 0 0.75rem; line-height: 1.4; }
211
+ .legend { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin-bottom: 0.75rem; font-size: 12px; color: var(--text-muted); }
212
+ .legend span { display: inline-flex; align-items: center; gap: 0.25rem; }
213
+ .legend .swatch { width: 10px; height: 10px; }
214
+ .legend .swatch-crit { background: #c00; }
215
+ .legend .swatch-high { background: #e85d00; }
216
+ .legend .swatch-med { background: #b8860b; }
217
+ .legend .swatch-low { background: #0a6b0a; }
227
218
  .legend .swatch-none { background: var(--border); }
228
219
  </style>
229
220
  </head>
@@ -346,7 +337,7 @@ function buildHtml(run, title, darkMode) {
346
337
  const sev = { critical: 4, high: 3, medium: 2, low: 1 };
347
338
  DATA.debtItems.sort((a,b) => (sev[b.severity] || 0) - (sev[a.severity] || 0)).forEach(d => {
348
339
  const li = document.createElement('li');
349
- li.innerHTML = '<span class="title">' + escapeHtml(d.title) + '</span> <span class="badge badge-' + d.severity + '">' + d.severity + '</span>' + (d.suggestedCode ? ' <span class="badge" style="background:var(--accent);color:#fff">refactor</span>' : '') + '<br><span class="meta">' + escapeHtml(d.file) + (d.line ? ':' + d.line : '') + '</span>' + (d.insight ? '<div class="insight">' + escapeHtml(d.insight) + '</div>' : '');
340
+ li.innerHTML = '<span class="title">' + escapeHtml(d.title) + '</span> <span class="badge badge-' + d.severity + '">' + d.severity + '</span>' + (d.suggestedCode ? ' <span class="badge" style="background:var(--link);color:#fff">refactor</span>' : '') + '<br><span class="meta">' + escapeHtml(d.file) + (d.line ? ':' + d.line : '') + '</span>' + (d.insight ? '<div class="insight">' + escapeHtml(d.insight) + '</div>' : '');
350
341
  li.addEventListener('click', () => showDetail(d.file, [d]));
351
342
  list.appendChild(li);
352
343
  });
@@ -370,7 +361,7 @@ function buildHtml(run, title, darkMode) {
370
361
  if (fileMetric && (fileMetric.llmAssessment || fileMetric.llmSuggestedCode)) {
371
362
  fileAssessEl.style.display = 'block';
372
363
  let html = '<strong>LLM file assessment</strong><br>' + (fileMetric.llmAssessment ? escapeHtml(fileMetric.llmAssessment) : '');
373
- if (fileMetric.llmSuggestedCode) html += '<br><br><strong>Suggested refactor</strong><pre style="margin:0.5rem 0 0;padding:0.5rem;background:var(--bg);border-radius:6px;font-size:0.8rem;overflow-x:auto">' + escapeHtml(fileMetric.llmSuggestedCode) + '</pre>';
364
+ if (fileMetric.llmSuggestedCode) html += '<br><br><strong>Suggested refactor</strong><pre style="margin:0.5rem 0 0;padding:0.5rem;background:var(--bg);border:1px solid var(--border);font-size:12px;overflow-x:auto">' + escapeHtml(fileMetric.llmSuggestedCode) + '</pre>';
374
365
  fileAssessEl.innerHTML = html;
375
366
  } else {
376
367
  fileAssessEl.style.display = 'none';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tech-debt-visualizer",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",