roast-my-design-system 9.2.1 → 9.2.2
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
|
@@ -73,7 +73,7 @@ The first thing the report says: the places where the repo has no answer yet, or
|
|
|
73
73
|
|
|
74
74
|
One gap is known for certain today, because the runs found it: charts hardcoding colours in a repo with no chart palette. 43 of 126 public repos look like that. A gap joins the list when it has been measured.
|
|
75
75
|
|
|
76
|
-
###
|
|
76
|
+
### Fixes you can make right now to increase the health score
|
|
77
77
|
|
|
78
78
|
The mess the agent will copy, ranked by what fixing it is worth.
|
|
79
79
|
|
|
@@ -142,11 +142,11 @@ Eleven reports, hosted exactly as the tool writes them. Every number determinist
|
|
|
142
142
|
|
|
143
143
|
The full report for vercel/ai-chatbot. The verdict answers what the agent will learn here, the gap section comes first, then "What the repo teaches the agent", Claude's read of the scan:
|
|
144
144
|
|
|
145
|
-

|
|
146
146
|
|
|
147
147
|
The same report in light mode (one file, built-in toggle):
|
|
148
148
|
|
|
149
|
-

|
|
150
150
|
|
|
151
151
|
## Why the numbers hold
|
|
152
152
|
|
|
@@ -347,7 +347,7 @@ You get the roast in chat plus `design-system-roast.html` at your repo root, a s
|
|
|
347
347
|
- stat tiles comparing you to all 3 yardsticks
|
|
348
348
|
- a **light/dark theme toggle** in one file
|
|
349
349
|
- the usage-weighted palette bar, the grey ramp, the off-scale spacing receipts, the duplicate-component receipts with clickable file paths, and the worst-offenders ledger
|
|
350
|
-
- a **
|
|
350
|
+
- a **Fixes you can make right now to increase the health score** list: up to 3 moves derived from your repo's own numbers, each with a file-path receipt
|
|
351
351
|
- **Where will your agent have to guess?** opens the report: the gaps where the repo has no answer yet, with the files that prove each one and the move that closes it, or "No gaps found"
|
|
352
352
|
- **Give the agent the answers**: `design-system-rules.md` wrapped inside the report as a present. Unwrap, then copy or download the agent rules generated from your scan
|
|
353
353
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roast-my-design-system",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.2",
|
|
4
4
|
"mcpName": "io.github.gregkozakiewicz/roast-my-design-system",
|
|
5
5
|
"description": "Your AI can write the UI. This makes sure it writes your UI. A deterministic scanner scores your design system 0-100 against 112 public repos, reads React and web components (Stencil, Lit), hands you a copy-paste fix prompt for each top finding, writes rules for Claude, Cursor, Copilot and Windsurf with --apply, and runs as a local MCP server with --mcp.",
|
|
6
6
|
"keywords": [
|
|
@@ -1201,17 +1201,22 @@ function whereToStartSection() {
|
|
|
1201
1201
|
}
|
|
1202
1202
|
|
|
1203
1203
|
// What each move is actually worth, then rank by payoff for real.
|
|
1204
|
+
// A move with no points says why, so the list never promises what the
|
|
1205
|
+
// score cannot give: the thing it fixes is not scored, or its tile is
|
|
1206
|
+
// already green, or the move lands inside the band it started in.
|
|
1204
1207
|
for (const item of c) {
|
|
1205
|
-
item.delta = 0; item.target = null;
|
|
1208
|
+
item.delta = 0; item.target = null; item.why = 'not part of the score';
|
|
1206
1209
|
if (!item.metric) continue;
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1210
|
+
const tile = bigStats.find((st) => st.metric === item.metric);
|
|
1211
|
+
const now = tile?.healthValue;
|
|
1212
|
+
if (now === undefined || !(tile.health in SCORE_OF)) continue;
|
|
1209
1213
|
if (item.after !== undefined) {
|
|
1210
1214
|
const gain = bandPoints(item.metric, now, item.after);
|
|
1211
1215
|
if (gain > 0) { item.delta = gain; continue; }
|
|
1212
1216
|
}
|
|
1213
1217
|
const nb = nextBand(item.metric, now);
|
|
1214
1218
|
if (nb && nb.gain > 0) item.target = nb;
|
|
1219
|
+
else item.why = healthOf(item.metric, now) === 'good' ? 'already green' : 'no points on its own';
|
|
1215
1220
|
}
|
|
1216
1221
|
const top3 = c.sort((a, b) => (b.delta - a.delta) || (b.score - a.score)).slice(0, 3);
|
|
1217
1222
|
if (!top3.length) return '';
|
|
@@ -1220,16 +1225,32 @@ function whereToStartSection() {
|
|
|
1220
1225
|
const applied = new Map();
|
|
1221
1226
|
for (const item of top3) if (item.metric && item.after !== undefined && item.delta > 0) applied.set(item.metric, item.after);
|
|
1222
1227
|
const after = projectedScore(applied);
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
+
// The line under the heading counts only the moves that pay, and says what
|
|
1229
|
+
// the others are. "Three fixes to increase your score" stood over a list
|
|
1230
|
+
// where 1 of the 3 could, by 4 points (shadcn-admin, 2026-09-29).
|
|
1231
|
+
const paying = healthScore !== null && after > healthScore ? top3.filter((item) => item.delta > 0) : [];
|
|
1232
|
+
const later = top3.filter((item) => !paying.includes(item) && item.target);
|
|
1233
|
+
startProjection = { count: paying.length, after };
|
|
1234
|
+
const COUNT = ['one', 'two', 'three'];
|
|
1235
|
+
const cap = (s) => s[0].toUpperCase() + s.slice(1);
|
|
1236
|
+
const total = top3.length;
|
|
1237
|
+
const none = total - paying.length - later.length;
|
|
1238
|
+
const ofThese = (k) => (k === total
|
|
1239
|
+
? `${cap(COUNT[k - 1])} ${k === 1 ? 'fix' : 'fixes'}`
|
|
1240
|
+
: `${cap(COUNT[k - 1])} of these ${COUNT[total - 1]} fixes`);
|
|
1241
|
+
const inFull = (k) => `once ${k === 1 ? 'it is' : 'they are'} done in full`;
|
|
1242
|
+
const rest = none ? ` The remaining ${none === 1 ? 'one does' : `${COUNT[none - 1]} do`} not move the score.` : '';
|
|
1243
|
+
const head = paying.length
|
|
1244
|
+
? `${ofThese(paying.length)} could raise the design system health score from <b class="proj">${healthScore} to ${after}</b>.${later.length ? ` ${cap(COUNT[later.length - 1])} more ${later.length === 1 ? 'pays' : 'pay'} ${inFull(later.length)}.` : ''}${rest}`
|
|
1245
|
+
: later.length
|
|
1246
|
+
? `${ofThese(later.length)} ${later.length === 1 ? `raises the score, by ${later[0].target.gain},` : 'raise the score'} ${inFull(later.length)}.${rest}`
|
|
1247
|
+
: `${total === 1 ? 'It does' : 'They do'} not move the score. ${total === 1 ? 'It is' : 'They are'} here because ${total === 1 ? 'it stops' : 'each one stops'} the agent guessing.`;
|
|
1248
|
+
const title = paying.length || later.length ? 'Fixes you can make right now to increase the health score' : 'Fixes you can make right now';
|
|
1228
1249
|
const chip = (item) => item.delta > 0
|
|
1229
1250
|
? `<span class="delta" title="once all of them are done">+${item.delta}</span>`
|
|
1230
1251
|
: item.target
|
|
1231
1252
|
? `<span class="delta delta-target">${item.target.target === 0 ? 'clear them all' : `under ${n(item.target.target)}`} · +${item.target.gain}</span>`
|
|
1232
|
-
:
|
|
1253
|
+
: `<span class="delta delta-none">${item.why}</span>`;
|
|
1233
1254
|
// The copy button beside each move hands the finding to whatever agent the
|
|
1234
1255
|
// reader pastes it into: one move per prompt, so progress stays visible and
|
|
1235
1256
|
// finishable. Prompt text is composed from the same title/sub the row shows
|
|
@@ -1251,7 +1272,7 @@ function whereToStartSection() {
|
|
|
1251
1272
|
delta: item.delta || 0, prompt: promptFor(item),
|
|
1252
1273
|
}));
|
|
1253
1274
|
return `<section class="glass pad">
|
|
1254
|
-
${sectionHead(
|
|
1275
|
+
${sectionHead(title, head)}
|
|
1255
1276
|
<div class="ledger">${top3.map((item, i) => `
|
|
1256
1277
|
<div class="ledger-row start-row">
|
|
1257
1278
|
<span class="ledger-idx">${String(i + 1).padStart(2, '0')}</span>
|
|
@@ -1651,7 +1672,7 @@ function exceptionsBlock() {
|
|
|
1651
1672
|
function addIndex(page) {
|
|
1652
1673
|
// heading text is already HTML-escaped; strip tags and leading counts only
|
|
1653
1674
|
const short = (t) => t.replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim().replace(/^[\d,]+ /, '')
|
|
1654
|
-
.replace(/^What your AI agent sees today$/, 'What your agent sees').replace(/^Give the agent the answers$/, 'Agent rules').replace(/^What the repo teaches the agent$/, 'What it teaches').replace(/^
|
|
1675
|
+
.replace(/^What your AI agent sees today$/, 'What your agent sees').replace(/^Give the agent the answers$/, 'Agent rules').replace(/^What the repo teaches the agent$/, 'What it teaches').replace(/^Fixes you can make right now( to increase the health score)?$/, 'What to fix')
|
|
1655
1676
|
.replace(/^The shadcn theme and the 2 shadcn checks$/, 'shadcn theme and checks')
|
|
1656
1677
|
.replace(/^Your Tailwind theme, and what goes around it$/, 'Your Tailwind theme').replace(/^Your (\w+) theme, and what is written around it$/, 'Your $1 theme').replace(/, declared .*$/, '')
|
|
1657
1678
|
.replace(/^off-scale spacing values$/, 'Off-scale spacing').replace(/^inline style blocks?$/, 'Inline styles').replace(/^typefaces?$/, 'Typefaces');
|
|
@@ -2047,6 +2068,7 @@ ${ogTags()}
|
|
|
2047
2068
|
.delta { font:700 11px/1 var(--sans); letter-spacing:.04em; padding:5px 9px; border-radius:99px;
|
|
2048
2069
|
background:var(--ok-soft); color:var(--ok); white-space:nowrap; }
|
|
2049
2070
|
.delta-target { background:var(--amber-soft); color:var(--amber); font-weight:600; }
|
|
2071
|
+
.delta-none { background:transparent; box-shadow:inset 0 0 0 1px var(--line-soft); color:var(--dim); font-weight:500; letter-spacing:0; }
|
|
2050
2072
|
.proj { color:var(--accent); font-weight:700; }
|
|
2051
2073
|
.ndot { display:inline-block; width:9px; height:9px; border-radius:3px; margin-right:4px; vertical-align:-1px; box-shadow:inset 0 0 0 1px var(--cell-ring); }
|
|
2052
2074
|
.nsim { color:var(--dim2); font-weight:400; padding:0 2px; }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Single version constant for the engine — imported by diagnose (report
|
|
2
2
|
// footer) and rules (generated-by line). This is the bump spot that used to
|
|
3
3
|
// live as a const inside diagnose/index.mjs.
|
|
4
|
-
export const VERSION = '9.2.
|
|
4
|
+
export const VERSION = '9.2.2';
|
|
5
5
|
// The shape of harvest.json and summary.json. Bumped only when a field is
|
|
6
6
|
// renamed, removed or changes meaning; a new field is not a new schema. A
|
|
7
7
|
// tool comparing two scans compares like with like by this number, not by VERSION.
|