roast-my-design-system 9.1.0 → 9.1.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
@@ -63,9 +63,9 @@ This tool draws the map.
63
63
 
64
64
  ## What you get
65
65
 
66
- ### Where agents will invent
66
+ ### Where will your agent have to guess?
67
67
 
68
- The places where the repo has no answer yet.
68
+ The first thing the report says: the places where the repo has no answer yet, or "No gaps found".
69
69
 
70
70
  - the gap, in one line
71
71
  - the files that prove it
@@ -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
- ![The full diagnosis report for vercel/ai-chatbot in dark mode: a fixed side panel with the health score and what it measures, the stack, how the repo was read as a shadcn install, an index of every section and what is not the team's and not counted; then the verdict on what the agent will learn here, the Where agents will invent section, the What the repo teaches the agent analysis written by Claude, priced Fix what makes agents guess moves each with its copy-the-fix-prompt button, the wrapped present with the agent rules, an agent trap callout, 3-yardstick tiles including the 2 shadcn tiles, the adoption map treemap, palette forensics, the shadcn theme variable by variable, spacing receipts, typography specimens, offenders, duplicates, and the component usage ledger](assets/report-full-dark.png?v=9.1.0)
145
+ ![The full diagnosis report for vercel/ai-chatbot in dark mode: a fixed side panel with the health score and what it measures, the stack, how the repo was read as a shadcn install, an index of every section and what is not the team's and not counted; then where the agent will have to guess, the What the repo teaches the agent analysis written by Claude, priced Fix what makes agents guess moves each with its copy-the-fix-prompt button, the wrapped present with the agent rules, an agent trap callout, 3-yardstick tiles including the 2 shadcn tiles, the adoption map treemap, palette forensics, the shadcn theme variable by variable, spacing receipts, typography specimens, offenders, duplicates, and the component usage ledger](assets/report-full-dark.png?v=9.1.2)
146
146
 
147
147
  The same report in light mode (one file, built-in toggle):
148
148
 
149
- ![The diagnosis report in light mode](assets/report-light-hero.png?v=9.1.0)
149
+ ![The diagnosis report in light mode](assets/report-light-hero.png?v=9.1.2)
150
150
 
151
151
  ## Why the numbers hold
152
152
 
@@ -348,7 +348,7 @@ You get the roast in chat plus `design-system-roast.html` at your repo root, a s
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
350
  - a **Fix what makes agents guess** list: up to 3 moves derived from your repo's own numbers, each with a file-path receipt
351
- - a **Where agents will invent** section, first under the verdict: the gaps where the repo has no answer yet, with the files that prove each one and the move that closes it, or the honest empty state when none is found
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
 
354
354
  After the roast, the skill offers to write `design-system-rules.md` to disk and merge it into your CLAUDE.md, `.cursor/rules` or AGENTS.md.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roast-my-design-system",
3
- "version": "9.1.0",
3
+ "version": "9.1.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": [
@@ -351,15 +351,23 @@ let verdict = noSystemLikely
351
351
  ? 'This repo is in good shape, and your agent has rules to read. Keep them in step with the code.'
352
352
  : 'This repo is in good shape. The gap is documentation: your agent still can\'t see the system.')
353
353
  : findings.slice(0, 3).join('. ') + '.';
354
- // The lead line answers the report's question before the measured verdict
355
- // does: does this repo give an agent something to copy, and where does it
356
- // not. A gap named here is one lib/gaps admitted after a fleet probe.
354
+ // The lead line answers the report's first question, where will the agent
355
+ // have to guess, before the measured verdict does. A repo with an answer gets
356
+ // copied; a repo with no answer gets guessed at. A gap named here is one
357
+ // lib/gaps admitted after a fleet probe; nothing else is called a gap. The
358
+ // card never talks about the scan's reach: a reader came for a diagnosis,
359
+ // not for the limits of the instrument (Greg, 28 Sep 2026).
357
360
  const gapLead = (noSystemLikely || fresh) ? '' : (() => {
358
361
  const gaps = h.gaps ?? [];
359
- if (!gaps.length) return 'This repo gives an agent something to copy everywhere this scan can measure.';
360
- const named = gaps.map((g) => g.title.charAt(0).toLowerCase() + g.title.slice(1));
361
- return `Most of this repo gives an agent something to copy. ${gaps.length === 1 ? 'One gap remains' : `${gaps.length} gaps remain`}: ${esc(named.join('; '))}.`;
362
+ return gaps.length ? `${gaps.length} gap${gaps.length === 1 ? '' : 's'} found.` : 'No gaps found.';
362
363
  })();
364
+ // Under the headline: the condition, and nothing about the scan's reach.
365
+ // What the fixes do to the score is said once, in the fixes section.
366
+ function gapSub() {
367
+ return (h.gaps ?? []).length
368
+ ? 'The agent has no clear answer for these parts of the system.'
369
+ : 'Your repo gives the agent a clear answer for every check in this scan.';
370
+ }
363
371
  if (bench && findings.length && !fresh) {
364
372
  const core = [['colors', tokenLed ? colorStrays : colors.length], ['greys', tokenLed ? greyStrays : greys.length],
365
373
  ['spacing', spacingTotal], ['typefaces', typefaces.length], ['exactDuplicates', hardDupes.length], ['inlineStyles', inline.count]];
@@ -1213,9 +1221,9 @@ function whereToStartSection() {
1213
1221
  for (const item of top3) if (item.metric && item.after !== undefined && item.delta > 0) applied.set(item.metric, item.after);
1214
1222
  const after = projectedScore(applied);
1215
1223
  startProjection = { count: top3.length, after };
1216
- const words = ['One tweak', 'Two tweaks', 'Three tweaks'][top3.length - 1];
1224
+ const words = ['One fix', 'Two fixes', 'Three fixes'][top3.length - 1];
1217
1225
  const head = healthScore !== null && after > healthScore
1218
- ? `${words} · <b class="proj">${healthScore} &rarr; ${after}</b>`
1226
+ ? `${words} could raise the design system health score from <b class="proj">${healthScore} to ${after}</b>.`
1219
1227
  : `${words} to increase your score.`;
1220
1228
  const chip = (item) => item.delta > 0
1221
1229
  ? `<span class="delta" title="once all of them are done">+${item.delta}</span>`
@@ -1257,24 +1265,17 @@ function whereToStartSection() {
1257
1265
  // A gap is a place where the next piece of UI has nothing to reuse (lib/gaps).
1258
1266
  // The September 2026 runs showed agents inventing exactly there; the section
1259
1267
  // names the gap, the files that prove it and the one move that closes it.
1260
- function gapsSection() {
1268
+ function gapsList() {
1261
1269
  if (noSystemLikely || fresh) return '';
1262
1270
  const gaps = h.gaps ?? [];
1263
- if (!gaps.length) {
1264
- return `<section class="glass pad" style="margin-top:16px">
1265
- ${sectionHead('Where agents will invent', 'No gap found. This scan checks for one kind of gap so far, a chart palette, and this repo either has one or has no charts. The list grows as more gap kinds are measured on real agent runs; a clean result here says the known gaps are closed, and no more than that.')}
1266
- </section>`;
1267
- }
1268
- const head = `${gaps.length === 1 ? 'One place' : `${gaps.length} places`} where this repo gives an agent nothing to copy. Asked to build there, an agent invents, because that is what the repo taught it. Nothing here is a violation: there is no rule yet to break. Define the answer once and every agent after that inherits it.`;
1269
- return `<section class="glass pad" style="margin-top:16px">
1270
- ${sectionHead('Where agents will invent', head)}
1271
- <div class="ledger">${gaps.map((g, i) => `
1271
+ if (!gaps.length) return '';
1272
+ return `<div class="ledger gaps-list">${gaps.map((g, i) => `
1272
1273
  <div class="ledger-row gap-row">
1273
1274
  <span class="ledger-idx">${String(i + 1).padStart(2, '0')}</span>
1274
1275
  <div class="start-body"><div class="start-head"><div class="start-title">${esc(g.title)}</div></div><div class="sub">${esc(g.detail)}</div>
1275
1276
  <div class="sub" style="margin-top:6px"><b>Close it:</b> ${esc(g.fix)}</div>
1276
1277
  ${g.files?.length ? `<div class="chips-row" style="margin-top:8px">${g.files.map((f) => `<span class="chip mono">${esc(f)}</span>`).join('')}</div>` : ''}</div>
1277
- </div>`).join('')}</div></section>`;
1278
+ </div>`).join('')}</div>`;
1278
1279
  }
1279
1280
 
1280
1281
  // ---------- package by package ----------
@@ -1560,16 +1561,16 @@ function ogTags() {
1560
1561
  // index of what rendered, and what is not the team's and not counted.
1561
1562
  function sidePanel() {
1562
1563
  const date = esc((h.harvestedAt ?? '').slice(0, 10));
1563
- const def = 'How safely an AI agent can build on this repo without going off-system.';
1564
+ const def = 'How well this repo follows the design system rules Roast checks.';
1564
1565
  const lift = startProjection && healthScore !== null && startProjection.after > healthScore
1565
- ? ` <b>${['One fix lifts', 'Two fixes lift', 'Three fixes lift'][startProjection.count - 1] ?? 'The fixes lift'} it to ${startProjection.after}.</b>` : '';
1566
+ ? ` <b>${['One fix', 'Two fixes', 'Three fixes'][startProjection.count - 1] ?? 'The fixes'} could raise it to ${startProjection.after}.</b>` : '';
1566
1567
  const rp = P.shadcn?.registryPaint ?? null;
1567
1568
  const bd = breakdown.ownScore !== null && breakdown.installedPoints > 0 && rp
1568
1569
  ? `<div class="bd">Of which <b>${breakdown.installedPoints} point${breakdown.installedPoints === 1 ? '' : 's'}</b> come from installed code you did not write: ${esc(rp.dirs.map((d) => basename(d)).join(', '))} (${n(rp.files)} file${rp.files === 1 ? '' : 's'}, ${n(rp.tinUses)} palette colour${rp.tinUses === 1 ? '' : 's'}). Your own code alone would score <b>${breakdown.ownScore}</b>. Kept in the score because your agent reads those files like everything else; left out of the fixes because they are not yours to edit.</div>` : '';
1569
1570
  const scoreBlock = healthScore !== null
1570
- ? `<div class="score">${eyebrow('Health score')}<div class="val">${healthScore}<span class="slash">/</span><span class="of">100</span></div><div class="def">${def}${lift}</div>${bd}</div>`
1571
+ ? `<div class="score">${eyebrow('Design system health')}<div class="val">${healthScore}<span class="slash">/</span><span class="of">100</span></div><div class="def">${def}${lift}</div>${bd}</div>`
1571
1572
  : noSystemLikely
1572
- ? `<div class="score muted">${eyebrow('Health score')}<div class="val">&mdash;</div><div class="note">nothing here was measured · see the note</div><div class="def">${def}</div></div>` : '';
1573
+ ? `<div class="score muted">${eyebrow('Design system health')}<div class="val">&mdash;</div><div class="note">nothing here was measured · see the note</div><div class="def">${def}</div></div>` : '';
1573
1574
  const chips = `<div class="chips">${stack.map((c) => `<span class="chip">${esc(c)}</span>`).join('')}${(P.shadcn?.sheet?.tweakcnPresent ?? 0) >= 10 ? '<span class="chip">tweakcn theme</span>' : ''}${P.shadcn?.lint ? '<span class="chip">shadcn/lint</span>' : ''}${dsUnrecognised ? '<span class="chip chip-dim">design system: unrecognised</span>' : ''}${legacyChip ? `<span class="chip chip-dim">${esc(legacyChip)}</span>` : ''}${agentFiles.map((c) => `<span class="chip chip-agent">${esc(c.file)}</span>`).join('')}</div>`;
1574
1575
  const facts = [
1575
1576
  shadcnReceipt(),
@@ -1787,6 +1788,7 @@ ${ogTags()}
1787
1788
  .verdict-card .b2 { left:-40px; bottom:-80px; width:224px; height:224px; background:var(--blob2); filter:blur(48px); }
1788
1789
  .verdict { position:relative; font:600 clamp(18px,2.6vw,24px)/1.45 var(--disp); letter-spacing:-.01em; margin-top:10px; }
1789
1790
  .verdict-sub { position:relative; margin-top:12px; font-size:14.5px; line-height:1.6; color:var(--dim); }
1791
+ .verdict-card .gaps-list { position:relative; margin-top:18px; }
1790
1792
  .gap-empty { padding:0 26px 22px; color:var(--dim); font-size:14px; line-height:1.6; }
1791
1793
  .gap-why { margin-top:6px; color:var(--dim); font-size:13.5px; }
1792
1794
 
@@ -2110,12 +2112,10 @@ ${sidePanel()}
2110
2112
  : `There is most likely <b>no design system in this repo</b>: almost no colour or spacing values were found. Styling may live outside this codebase (CDN stylesheets, a parent repo, or generated output). No score is given.`}</span></div>` : ''}
2111
2113
  <div class="glass verdict-card">
2112
2114
  <div class="blob b1"></div><div class="blob b2"></div>
2113
- ${eyebrow(noSystemLikely || fresh ? 'Summary' : 'What will your agent learn here?')}
2114
- ${gapLead ? `<div class="verdict">${gapLead}</div><div class="verdict-sub">${esc(verdict)}</div>` : `<div class="verdict">${esc(verdict)}</div>`}
2115
+ ${eyebrow(noSystemLikely || fresh ? 'Summary' : 'Where will your agent have to guess?')}
2116
+ ${gapLead ? `<div class="verdict">${gapLead}</div><div class="verdict-sub">${gapSub()}</div>${gapsList()}` : `<div class="verdict">${esc(verdict)}</div>`}
2115
2117
  </div>
2116
2118
 
2117
- ${gapsSection()}
2118
-
2119
2119
  ${notesSection()}
2120
2120
 
2121
2121
  ${extraSectionsHtml()}
@@ -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.1.0';
4
+ export const VERSION = '9.1.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.