Files
Manavarya09 48b92c794b feat(v8): credibility + distribution release
Reliability fixes that restore trust on real sites:

- colors.js: brand-color detection rewritten — ranks chromatic clusters by
  interactiveBg x100 + saturation x2 + log(usage), requires HSL sat >25 or
  an interactive-bg hit. Linear primary: #d0d6e0 (gray) -> #e4f222 (lime).
  Stripe: #533afd. Verified on 5 ground-truth sites.
- accessibility.js + crawler.js: crawler now emits hasText per element
  (direct text-node child with visible chars); WCAG extractor filters
  decorative glyph spans, transparent overlays, non-text containers.
  Linear: 25% (171 failing pairs) -> 83% (1 failing pair).
- scoring.js: rubric recalibrated against Stripe/Linear/Vercel/GitHub/Apple.
  Loosened color/shadow/radii/type-scale thresholds; softened spacing
  no-base penalty when tokenization is present; cssHealth now weighted in
  the overall. Linear 47->76, Stripe 81->88, Apple 83->86.

New CLI flags:

- --selector <css>: scope extraction to a DOM subtree. Stripe: 2409 -> 112
  elements when scoped to footer. Falls back to full doc if invalid.
- --system-chrome: channel: 'chrome' in Playwright launch; skips the
  bundled Chromium download.
- --json: full extraction to stdout (already partial in v7, now first-class
  and documented).

New distribution surfaces (each publishes to its own registry):

- vscode-extension/: Extract-from-URL + inject-into-workspace commands.
- raycast-extension/: Extract, Score, Copy-CLI commands.
- figma-plugin/: URL or paste-JSON -> Figma Variables with multi-mode.
- github-action/: "Design regression guard" runs designlang on PRs, diffs
  tokens vs baseline, comments the delta, optional fail-on-change.
- smithery.yaml + smithery.dockerfile + docs/MCP-REGISTRY.md: MCP registry
  submission checklist.
- chrome-extension/PRIVACY.md + STORE_LISTING.md: Chrome/Firefox/Edge
  store listing prep (extension code already existed in v7.1).
- docs/LAUNCH.md: PH + Show HN + Twitter copy + day-of checklist.
- docs/demo.tape: VHS tape for the animated README hero.

README updated: hero references demo.gif with PNG fallback, adds "Install
everywhere" table for the new surfaces, documents the three new flags.
.npmignore excludes every companion-surface directory so the npm tarball
stays 109KB / 73 files.

All 275 tests pass.
2026-04-20 03:14:04 +04:00

82 lines
2.3 KiB
JavaScript

#!/usr/bin/env node
// Minimal diff for DTCG-shaped (and legacy) design-tokens.json files.
// Usage: node diff-tokens.js <baseline.json> <new.json>
//
// Emits markdown to stdout. Each `- {path}: {from} → {to}` line is one changed
// token; the action's outputs key off these lines.
const { readFileSync } = require('fs');
function load(p) {
try { return JSON.parse(readFileSync(p, 'utf8')); }
catch (e) { console.error(`Failed to read ${p}: ${e.message}`); process.exit(0); }
}
// DTCG leaves are `{ "$value": ..., "$type": ... }`. Legacy leaves are strings
// or primitives. Normalise into a flat `{ path: value }` map.
function flatten(node, path, out) {
if (node == null) return;
if (typeof node !== 'object') {
out[path] = node;
return;
}
if ('$value' in node && (typeof node.$value !== 'object' || node.$value === null)) {
out[path] = node.$value;
return;
}
if (Array.isArray(node)) {
out[path] = JSON.stringify(node);
return;
}
for (const key of Object.keys(node)) {
if (key.startsWith('$')) continue;
flatten(node[key], path ? `${path}.${key}` : key, out);
}
}
const [baselinePath, newPath] = process.argv.slice(2);
const baseline = load(baselinePath);
const next = load(newPath);
const a = {};
const b = {};
flatten(baseline, '', a);
flatten(next, '', b);
const added = [];
const removed = [];
const changed = [];
for (const k of Object.keys(b)) {
if (!(k in a)) added.push([k, b[k]]);
else if (a[k] !== b[k]) changed.push([k, a[k], b[k]]);
}
for (const k of Object.keys(a)) {
if (!(k in b)) removed.push([k, a[k]]);
}
const total = added.length + removed.length + changed.length;
if (total === 0) {
console.log('**No design token changes** — the extracted design matches the baseline.');
process.exit(0);
}
console.log(`**${total} token changes** vs baseline (${changed.length} changed, ${added.length} added, ${removed.length} removed).`);
console.log('');
if (changed.length) {
console.log('#### Changed');
for (const [k, from, to] of changed) console.log(`- \`${k}\`: \`${from}\` → \`${to}\``);
console.log('');
}
if (added.length) {
console.log('#### Added');
for (const [k, v] of added) console.log(`- \`${k}\`: \`${v}\``);
console.log('');
}
if (removed.length) {
console.log('#### Removed');
for (const [k, v] of removed) console.log(`- \`${k}\` (was \`${v}\`)`);
console.log('');
}