designlang 12.10.0 → 12.10.1
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +21 -0
- package/bin/design-extract.js +60 -24
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"name": "designlang",
|
|
10
10
|
"source": "./",
|
|
11
11
|
"description": "Eight slash commands wrapping the designlang CLI: /extract (full design language \u2192 DTCG, Tailwind, Figma), /grade (shareable HTML report card + SVG badge), /battle (head-to-head graded comparison), /remix (restyle in 6 vocabularies \u2014 brutalist, swiss, art-deco, cyberpunk, soft-ui, editorial), /pack (one downloadable design-system bundle), /theme-swap (OKLCH-correct recolour around a new brand primary), /brand (full editorial brand-guidelines book \u2014 13 chapters, hand-off-ready), /pair (fuse two designs across configurable axes \u2014 colours from one site, typography from another).",
|
|
12
|
-
"version": "12.10.
|
|
12
|
+
"version": "12.10.1",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Manavarya Singh"
|
|
15
15
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "designlang",
|
|
3
3
|
"description": "Extract any website's design language and ship it. Eight slash commands \u2014 /extract, /grade, /battle, /remix, /pack, /theme-swap, /brand, /pair \u2014 wrap the designlang CLI to pull DTCG tokens, Tailwind/shadcn/Figma vars, motion + voice, generate shareable graded report cards, head-to-head battle pages, six-vocabulary remixes, downloadable design-system bundles, OKLCH-correct theme recolouring, full editorial brand-guidelines books, and design crossovers between two sites.",
|
|
4
|
-
"version": "12.10.
|
|
4
|
+
"version": "12.10.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Manavarya Singh",
|
|
7
7
|
"url": "https://github.com/Manavarya09"
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [12.10.1] — 2026-05-13
|
|
4
|
+
|
|
5
|
+
**Tiny ship: \`stats\` now scans multiple URLs at once.**
|
|
6
|
+
|
|
7
|
+
\`designlang stats\` previously took exactly one URL. Now it takes any
|
|
8
|
+
number, runs them in parallel, and prints each block with a divider:
|
|
9
|
+
|
|
10
|
+
\`\`\`bash
|
|
11
|
+
npx designlang stats stripe.com vercel.com linear.app
|
|
12
|
+
\`\`\`
|
|
13
|
+
|
|
14
|
+
In \`--as-json\` mode:
|
|
15
|
+
|
|
16
|
+
- One URL → a bare object (legacy shape, unchanged)
|
|
17
|
+
- Two-or-more URLs → an array of objects
|
|
18
|
+
- Per-URL failures don't kill the batch — they surface as
|
|
19
|
+
\`{ url, error }\` in JSON or a red row in pretty mode, and the
|
|
20
|
+
process exits non-zero only when at least one site failed.
|
|
21
|
+
|
|
22
|
+
No flag changes, no schema breaks for the existing single-URL callers.
|
|
23
|
+
|
|
3
24
|
## [12.10.0] — 2026-05-12
|
|
4
25
|
|
|
5
26
|
**Small ship: \`designlang stats\` + low-confidence warning in grade cards.**
|
package/bin/design-extract.js
CHANGED
|
@@ -946,23 +946,31 @@ program
|
|
|
946
946
|
|
|
947
947
|
// ── Stats command — fast stdout summary, no files written ──
|
|
948
948
|
program
|
|
949
|
-
.command('stats <
|
|
950
|
-
.description('Print a concise one-screen summary to stdout — grade, primary, fonts, spacing, voice. No files written.')
|
|
951
|
-
.option('-j, --as-json', 'emit machine-readable JSON to stdout instead of pretty text')
|
|
952
|
-
.action(async (
|
|
953
|
-
|
|
954
|
-
|
|
949
|
+
.command('stats <urls...>')
|
|
950
|
+
.description('Print a concise one-screen summary to stdout — grade, primary, fonts, spacing, voice. Accepts multiple URLs. No files written.')
|
|
951
|
+
.option('-j, --as-json', 'emit machine-readable JSON to stdout instead of pretty text (an array when multiple URLs)')
|
|
952
|
+
.action(async (urls, opts) => {
|
|
953
|
+
// Normalise each URL the same way the single-URL path used to.
|
|
954
|
+
const targets = urls.map(u => {
|
|
955
|
+
const full = u.startsWith('http') ? u : `https://${u}`;
|
|
956
|
+
validateUrl(full);
|
|
957
|
+
return full;
|
|
958
|
+
});
|
|
955
959
|
|
|
956
960
|
// Quiet path for --as-json: no spinner / chrome noise, just data on stdout.
|
|
957
961
|
// (`--json` is already a global program flag; `--as-json` avoids the clash.)
|
|
958
962
|
const wantJson = !!opts.asJson;
|
|
959
|
-
const spinner = wantJson
|
|
960
|
-
|
|
963
|
+
const spinner = wantJson
|
|
964
|
+
? null
|
|
965
|
+
: ora(targets.length === 1 ? `Reading ${targets[0]}...` : `Reading ${targets.length} sites in parallel...`).start();
|
|
966
|
+
|
|
967
|
+
// Single helper used by both pretty and JSON paths.
|
|
968
|
+
async function summarise(url) {
|
|
961
969
|
const design = await extractDesignLanguage(url);
|
|
962
970
|
const s = design.score || {};
|
|
963
971
|
const primary = design.colors?.primary;
|
|
964
972
|
const families = (design.typography?.families || []).map(f => f?.name || f).filter(Boolean);
|
|
965
|
-
|
|
973
|
+
return {
|
|
966
974
|
url,
|
|
967
975
|
title: design.meta?.title,
|
|
968
976
|
grade: s.grade ?? null,
|
|
@@ -985,30 +993,24 @@ program
|
|
|
985
993
|
stack: design.stack?.framework,
|
|
986
994
|
intent: design.pageIntent?.type,
|
|
987
995
|
};
|
|
996
|
+
}
|
|
988
997
|
|
|
989
|
-
|
|
990
|
-
if (spinner) spinner.stop();
|
|
991
|
-
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
spinner.stop();
|
|
998
|
+
function printPretty(summary) {
|
|
996
999
|
const gradeColor =
|
|
997
1000
|
summary.grade === 'A' ? chalk.green
|
|
998
1001
|
: summary.grade === 'B' ? chalk.cyan
|
|
999
1002
|
: summary.grade === 'C' ? chalk.yellow
|
|
1000
1003
|
: summary.grade === 'D' ? chalk.magenta
|
|
1001
1004
|
: chalk.red;
|
|
1005
|
+
const primary = summary.primary;
|
|
1002
1006
|
const confTag = primary && primary.confidence != null
|
|
1003
1007
|
? (primary.confidence < 0.5
|
|
1004
1008
|
? chalk.yellow(`~${Math.round(primary.confidence * 100)}% conf`)
|
|
1005
1009
|
: chalk.gray(`${Math.round(primary.confidence * 100)}% conf`))
|
|
1006
1010
|
: '';
|
|
1007
|
-
const line = (label, value) =>
|
|
1008
|
-
` ${chalk.gray(label.padEnd(12))} ${value}`;
|
|
1009
|
-
|
|
1011
|
+
const line = (label, value) => ` ${chalk.gray(label.padEnd(12))} ${value}`;
|
|
1010
1012
|
console.log('');
|
|
1011
|
-
console.log(` ${chalk.bold(url)}`);
|
|
1013
|
+
console.log(` ${chalk.bold(summary.url)}`);
|
|
1012
1014
|
if (summary.title) console.log(` ${chalk.gray(summary.title)}`);
|
|
1013
1015
|
console.log('');
|
|
1014
1016
|
console.log(line('Grade', `${gradeColor.bold(summary.grade || '—')} ${chalk.gray('·')} ${chalk.bold(String(summary.score ?? '—') + '/100')}`));
|
|
@@ -1017,10 +1019,10 @@ program
|
|
|
1017
1019
|
} else {
|
|
1018
1020
|
console.log(line('Primary', chalk.gray('—')));
|
|
1019
1021
|
}
|
|
1020
|
-
if (families.length) {
|
|
1021
|
-
const head = families[0];
|
|
1022
|
-
const body = families[1] || head;
|
|
1023
|
-
const extra =
|
|
1022
|
+
if (summary.families.length) {
|
|
1023
|
+
const head = summary.families[0];
|
|
1024
|
+
const body = summary.families[1] || head;
|
|
1025
|
+
const extra = summary.fontFamilyCount > 2 ? chalk.gray(` +${summary.fontFamilyCount - 2}`) : '';
|
|
1024
1026
|
console.log(line('Fonts', `${head}${body && body !== head ? chalk.gray(' / ') + body : ''}${extra}`));
|
|
1025
1027
|
} else {
|
|
1026
1028
|
console.log(line('Fonts', chalk.gray('—')));
|
|
@@ -1034,7 +1036,41 @@ program
|
|
|
1034
1036
|
console.log(line('Material', summary.material || chalk.gray('—')));
|
|
1035
1037
|
console.log(line('Tone', summary.tone || chalk.gray('—')));
|
|
1036
1038
|
console.log(line('Intent', summary.intent || chalk.gray('—')));
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
try {
|
|
1042
|
+
// Settle so a single failure doesn't kill the whole batch; per-URL
|
|
1043
|
+
// errors are surfaced as individual rejections in both paths.
|
|
1044
|
+
const results = await Promise.allSettled(targets.map(summarise));
|
|
1045
|
+
|
|
1046
|
+
if (wantJson) {
|
|
1047
|
+
if (spinner) spinner.stop();
|
|
1048
|
+
const payload = results.map((r, i) => r.status === 'fulfilled'
|
|
1049
|
+
? r.value
|
|
1050
|
+
: { url: targets[i], error: r.reason?.message || String(r.reason) });
|
|
1051
|
+
// When the caller passed a single URL we keep the legacy shape
|
|
1052
|
+
// (a bare object) so existing scripts don't break. Multiple URLs
|
|
1053
|
+
// become an array.
|
|
1054
|
+
const out = targets.length === 1 ? payload[0] : payload;
|
|
1055
|
+
process.stdout.write(JSON.stringify(out, null, 2) + '\n');
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
spinner.stop();
|
|
1060
|
+
let anyFailed = false;
|
|
1061
|
+
results.forEach((r, i) => {
|
|
1062
|
+
if (i > 0) console.log(chalk.gray(' ' + '─'.repeat(60)));
|
|
1063
|
+
if (r.status === 'fulfilled') {
|
|
1064
|
+
printPretty(r.value);
|
|
1065
|
+
} else {
|
|
1066
|
+
anyFailed = true;
|
|
1067
|
+
console.log('');
|
|
1068
|
+
console.log(` ${chalk.bold(targets[i])}`);
|
|
1069
|
+
console.log(` ${chalk.red('failed:')} ${chalk.red(r.reason?.message || String(r.reason))}`);
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1037
1072
|
console.log('');
|
|
1073
|
+
if (anyFailed) process.exitCode = 1;
|
|
1038
1074
|
} catch (err) {
|
|
1039
1075
|
if (spinner) spinner.fail('Stats failed');
|
|
1040
1076
|
console.error(chalk.red(`\n ${err.message}\n`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "designlang",
|
|
3
|
-
"version": "12.10.
|
|
3
|
+
"version": "12.10.1",
|
|
4
4
|
"description": "Extract the complete design language from any website and ship it \u2014 clone to a working Next.js starter, guard tokens with a CI drift bot, or browse everything in a local studio. Outputs W3C DTCG tokens, motion tokens, typed anatomy stubs, Tailwind config, and ready-to-paste v0 / Lovable / Cursor / Claude-Artifacts prompts.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|