@shortwind/cli 0.1.0-beta.12 → 0.1.0-beta.14
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/dist/{bench-BGO3pupw.js → bench-DQtfv5aq.js} +118 -10
- package/dist/bench-DQtfv5aq.js.map +1 -0
- package/dist/bin.js +144 -3
- package/dist/bin.js.map +1 -1
- package/dist/catalog.generated-fXJjJvJ2.js +98 -0
- package/dist/catalog.generated-fXJjJvJ2.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/dist/bench-BGO3pupw.js.map +0 -1
- package/dist/catalog.generated-BdZstlkf.js +0 -83
- package/dist/catalog.generated-BdZstlkf.js.map +0 -1
|
@@ -168,7 +168,7 @@ const BUNDLED_ORIGIN = "bundled:@shortwind/catalog";
|
|
|
168
168
|
function bundledSource() {
|
|
169
169
|
let cache = null;
|
|
170
170
|
const load = () => {
|
|
171
|
-
cache ??= import("./catalog.generated-
|
|
171
|
+
cache ??= import("./catalog.generated-fXJjJvJ2.js");
|
|
172
172
|
return cache;
|
|
173
173
|
};
|
|
174
174
|
return {
|
|
@@ -436,6 +436,82 @@ async function scaffoldTheme(cwd) {
|
|
|
436
436
|
};
|
|
437
437
|
}
|
|
438
438
|
const THEME_COLOR_TOKENS = new Set([...THEME_BLOCK.matchAll(/--color-([\w-]+)\s*:/g)].map((m) => m[1] ?? ""));
|
|
439
|
+
const THEME_SUPPLEMENT_MARKER = "/* shortwind:theme-supplement";
|
|
440
|
+
function blockSectionValues(selector) {
|
|
441
|
+
const m = THEME_BLOCK.match(new RegExp(`${selector.replace(".", "\\.")}\\s*\\{([^}]*)\\}`));
|
|
442
|
+
const out = /* @__PURE__ */ new Map();
|
|
443
|
+
for (const decl of (m?.[1] ?? "").matchAll(/--([\w-]+)\s*:\s*([^;]+);/g)) out.set(decl[1], decl[2].trim());
|
|
444
|
+
return out;
|
|
445
|
+
}
|
|
446
|
+
const THEME_LIGHT_VALUES = blockSectionValues(":root");
|
|
447
|
+
const THEME_DARK_VALUES = blockSectionValues(".dark");
|
|
448
|
+
function buildThemeSupplement(css, missing) {
|
|
449
|
+
const tokens = missing.filter((t) => THEME_LIGHT_VALUES.has(t));
|
|
450
|
+
if (tokens.length === 0) return null;
|
|
451
|
+
const light = tokens.map((t) => ` --${t}: ${THEME_LIGHT_VALUES.get(t)};`);
|
|
452
|
+
const dark = tokens.filter((t) => THEME_DARK_VALUES.has(t)).map((t) => ` --${t}: ${THEME_DARK_VALUES.get(t)};`);
|
|
453
|
+
const mapping = tokens.map((t) => ` --color-${t}: var(--${t});`);
|
|
454
|
+
const lines = [
|
|
455
|
+
`${THEME_SUPPLEMENT_MARKER} — placeholder values for tokens your theme didn't define. Tune them to your palette. */`,
|
|
456
|
+
":root {",
|
|
457
|
+
...light,
|
|
458
|
+
"}"
|
|
459
|
+
];
|
|
460
|
+
if (dark.length > 0) {
|
|
461
|
+
if (/@custom-variant\s+dark|\.dark\s*\{/.test(css)) lines.push(".dark {", ...dark, "}");
|
|
462
|
+
else if (/@media\s*\(\s*prefers-color-scheme\s*:\s*dark\s*\)/.test(css)) lines.push("@media (prefers-color-scheme: dark) {", " :root {", ...dark.map((l) => ` ${l}`), " }", "}");
|
|
463
|
+
}
|
|
464
|
+
lines.push("@theme inline {", ...mapping, "}", "/* end shortwind theme-supplement */");
|
|
465
|
+
return lines.join("\n");
|
|
466
|
+
}
|
|
467
|
+
const TONE_MARKER = "/* shortwind:tones";
|
|
468
|
+
const TONES = [
|
|
469
|
+
{
|
|
470
|
+
name: "neutral",
|
|
471
|
+
bg: "var(--muted)",
|
|
472
|
+
fg: "var(--muted-foreground)"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
name: "success",
|
|
476
|
+
bg: "oklch(0.962 0.044 156.743)",
|
|
477
|
+
fg: "oklch(0.448 0.119 151.328)",
|
|
478
|
+
darkBg: "oklch(0.393 0.095 152.535)",
|
|
479
|
+
darkFg: "oklch(0.925 0.084 155.995)"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
name: "warning",
|
|
483
|
+
bg: "oklch(0.962 0.059 95.617)",
|
|
484
|
+
fg: "oklch(0.473 0.137 46.201)",
|
|
485
|
+
darkBg: "oklch(0.414 0.112 45.904)",
|
|
486
|
+
darkFg: "oklch(0.924 0.12 95.746)"
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: "danger",
|
|
490
|
+
bg: "color-mix(in oklab, var(--destructive) 15%, transparent)",
|
|
491
|
+
fg: "var(--destructive)"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
name: "info",
|
|
495
|
+
bg: "color-mix(in oklab, var(--primary) 15%, transparent)",
|
|
496
|
+
fg: "var(--primary)"
|
|
497
|
+
}
|
|
498
|
+
];
|
|
499
|
+
function buildToneBlock(css) {
|
|
500
|
+
const rule = (name, bg, fg) => `[data-tone="${name}"] { --tone-bg: ${bg}; --tone-fg: ${fg}; }`;
|
|
501
|
+
const lines = [
|
|
502
|
+
`${TONE_MARKER} — semantic tones for tone-aware recipes (@badge, …). Set on an element:`,
|
|
503
|
+
` <span class="@badge" data-tone="success">. Add your own: [data-tone="sev1"] { --tone-bg: …; --tone-fg: … } */`,
|
|
504
|
+
...TONES.map((t) => rule(t.name, t.bg, t.fg))
|
|
505
|
+
];
|
|
506
|
+
const darkTones = TONES.filter((t) => t.darkBg && t.darkFg);
|
|
507
|
+
if (darkTones.length > 0) {
|
|
508
|
+
const darkRules = darkTones.map((t) => " " + rule(t.name, t.darkBg, t.darkFg));
|
|
509
|
+
if (/@custom-variant\s+dark|\.dark\s*\{/.test(css)) lines.push(".dark {", ...darkRules, "}");
|
|
510
|
+
else if (/@media\s*\(\s*prefers-color-scheme\s*:\s*dark\s*\)/.test(css)) lines.push("@media (prefers-color-scheme: dark) {", ...darkRules, "}");
|
|
511
|
+
}
|
|
512
|
+
lines.push("/* end shortwind tones */");
|
|
513
|
+
return lines.join("\n");
|
|
514
|
+
}
|
|
439
515
|
const COLOR_UTILITY_RE = /^(?:bg|text|border|ring|outline|fill|stroke|divide|accent|caret|decoration|shadow|from|via|to|placeholder)-(.+)$/;
|
|
440
516
|
function referencedThemeTokens(flattened) {
|
|
441
517
|
const out = /* @__PURE__ */ new Set();
|
|
@@ -618,8 +694,30 @@ async function init(options) {
|
|
|
618
694
|
const skillPath = path.join(cwd, "skills", "shortwind", "SKILL.md");
|
|
619
695
|
const skillRegistry = await writeSkillMd(skillPath, recipesDir, families, shape.bundler);
|
|
620
696
|
const theme = await scaffoldTheme(cwd);
|
|
697
|
+
let themeAction = theme.action;
|
|
621
698
|
let missingThemeTokens = [];
|
|
622
|
-
|
|
699
|
+
let supplementedThemeTokens = [];
|
|
700
|
+
if (theme.action === "skipped" && theme.themePath && skillRegistry) {
|
|
701
|
+
const css = await readFile(theme.themePath, "utf8");
|
|
702
|
+
missingThemeTokens = findMissingThemeTokens(css, skillRegistry.flattened);
|
|
703
|
+
const supplement = buildThemeSupplement(css, missingThemeTokens);
|
|
704
|
+
if (supplement) {
|
|
705
|
+
await writeFile(theme.themePath, `${css.replace(/\s*$/, "")}\n\n${supplement}\n`);
|
|
706
|
+
supplementedThemeTokens = missingThemeTokens;
|
|
707
|
+
missingThemeTokens = [];
|
|
708
|
+
themeAction = "supplemented";
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
let tonesPath = null;
|
|
712
|
+
let tonesAction = "skipped";
|
|
713
|
+
if (theme.themePath) {
|
|
714
|
+
const css = await readFile(theme.themePath, "utf8");
|
|
715
|
+
tonesPath = theme.themePath;
|
|
716
|
+
if (!css.includes("/* shortwind:tones")) {
|
|
717
|
+
await writeFile(theme.themePath, `${css.replace(/\s*$/, "")}\n\n${buildToneBlock(css)}\n`);
|
|
718
|
+
tonesAction = "written";
|
|
719
|
+
}
|
|
720
|
+
}
|
|
623
721
|
const safelistCssPaths = [];
|
|
624
722
|
if (shape.bundler !== "vite" && shape.bundler !== "astro" && skillRegistry) for (const file of findTailwindEntryCssFiles(cwd)) {
|
|
625
723
|
syncSourceDirectiveToFile(file, skillRegistry);
|
|
@@ -629,6 +727,7 @@ async function init(options) {
|
|
|
629
727
|
const agentsFile = await wireAgentsInstructions(cwd, skillPath);
|
|
630
728
|
return {
|
|
631
729
|
packageManager: shape.packageManager,
|
|
730
|
+
bundler: shape.bundler,
|
|
632
731
|
preset: options.preset,
|
|
633
732
|
registry,
|
|
634
733
|
families,
|
|
@@ -640,7 +739,10 @@ async function init(options) {
|
|
|
640
739
|
huskyPath,
|
|
641
740
|
skillPath,
|
|
642
741
|
themePath: theme.themePath,
|
|
643
|
-
themeAction
|
|
742
|
+
themeAction,
|
|
743
|
+
tonesPath,
|
|
744
|
+
tonesAction,
|
|
745
|
+
supplementedThemeTokens,
|
|
644
746
|
safelistCssPaths,
|
|
645
747
|
missingThemeTokens,
|
|
646
748
|
bundlerConfigPath: bundlerConfig.configPath,
|
|
@@ -852,11 +954,16 @@ async function readConfig(cwd) {
|
|
|
852
954
|
...DEFAULT_CONFIG,
|
|
853
955
|
...parsed
|
|
854
956
|
};
|
|
855
|
-
|
|
957
|
+
const config = {
|
|
856
958
|
registry: assertConfigString(merged.registry, "registry", configPath),
|
|
857
959
|
recipesDir: assertWithinCwd(cwd, assertConfigString(merged.recipesDir, "recipesDir", configPath), "recipesDir", configPath),
|
|
858
960
|
outputPath: assertWithinCwd(cwd, assertConfigString(merged.outputPath, "outputPath", configPath), "outputPath", configPath)
|
|
859
961
|
};
|
|
962
|
+
if (merged.content !== void 0) {
|
|
963
|
+
if (!Array.isArray(merged.content) || merged.content.some((g) => typeof g !== "string")) throw new Error(`${configPath}: "content" must be an array of glob strings`);
|
|
964
|
+
config.content = merged.content;
|
|
965
|
+
}
|
|
966
|
+
return config;
|
|
860
967
|
}
|
|
861
968
|
function installedFamilies(recipesDir) {
|
|
862
969
|
if (!existsSync(recipesDir)) return [];
|
|
@@ -1752,7 +1859,7 @@ const ALL_RULES = [
|
|
|
1752
1859
|
"recipe/no-sibling-overlap",
|
|
1753
1860
|
"recipe/reserved-name"
|
|
1754
1861
|
];
|
|
1755
|
-
const DEFAULT_CONTENT = ["src/**/*.{html,js,jsx,ts,tsx,vue,svelte,astro,md,mdx}"];
|
|
1862
|
+
const DEFAULT_CONTENT = ["{src,app,pages,components,lib}/**/*.{html,js,jsx,ts,tsx,vue,svelte,astro,md,mdx}"];
|
|
1756
1863
|
async function lint(options) {
|
|
1757
1864
|
const cwd = path.resolve(options.cwd);
|
|
1758
1865
|
const config = await readConfig(cwd);
|
|
@@ -1763,7 +1870,7 @@ async function lint(options) {
|
|
|
1763
1870
|
findings.push(...parseFindings);
|
|
1764
1871
|
findings.push(...checkRecipeNames(registry, recipesDir, enabledRules));
|
|
1765
1872
|
findings.push(...checkReservedNames(registry, recipesDir, enabledRules));
|
|
1766
|
-
const files = await glob(options.content ?? DEFAULT_CONTENT, {
|
|
1873
|
+
const files = await glob(options.content ?? config.content ?? DEFAULT_CONTENT, {
|
|
1767
1874
|
cwd,
|
|
1768
1875
|
absolute: true,
|
|
1769
1876
|
onlyFiles: true,
|
|
@@ -1807,7 +1914,7 @@ async function lint(options) {
|
|
|
1807
1914
|
}
|
|
1808
1915
|
}
|
|
1809
1916
|
}
|
|
1810
|
-
if (enabledRules.has("recipe/unused")) {
|
|
1917
|
+
if (enabledRules.has("recipe/unused") && files.length > 0) {
|
|
1811
1918
|
const recipesByName = /* @__PURE__ */ new Map();
|
|
1812
1919
|
for (const recs of Object.values(registry.families)) for (const r of recs) recipesByName.set(r.name, r);
|
|
1813
1920
|
for (const name of Object.keys(registry.flattened)) {
|
|
@@ -1832,7 +1939,8 @@ async function lint(options) {
|
|
|
1832
1939
|
return {
|
|
1833
1940
|
ok: !findings.some((f) => f.severity === "error"),
|
|
1834
1941
|
findings,
|
|
1835
|
-
filesFixed
|
|
1942
|
+
filesFixed,
|
|
1943
|
+
scannedFiles: files.length
|
|
1836
1944
|
};
|
|
1837
1945
|
}
|
|
1838
1946
|
function loadRegistry(recipesDir, rules) {
|
|
@@ -2445,6 +2553,6 @@ function formatBenchTable(result) {
|
|
|
2445
2553
|
return lines.join("\n");
|
|
2446
2554
|
}
|
|
2447
2555
|
//#endregion
|
|
2448
|
-
export {
|
|
2556
|
+
export { createRegistrySource as A, readConfig as C, init as D, cliVersion as E, extractHeader as F, rewriteHeaderSha as I, sealRecipeFile as L, detectProject as M, buildHeaderLine as N, readLockfile as O, computeBodySha as P, verifyFetchedFamily as R, installedFamilies as S, DEFAULT_REGISTRY as T, reseal as _, extractClassUsages as a, remove as b, verify as c, dev as d, BuildError as f, preset as g, ls as h, DEFAULT_CONTENT as i, resolvePresetFamilies as j, writeLockfile as k, UpgradeError as l, formatLsText as m, formatBenchTable as n, formatFindingsText as o, build as p, ALL_RULES as r, lint as s, bench as t, upgrade as u, NewFamilyError as v, renameFamilyInSource as w, add as x, newFamily as y };
|
|
2449
2557
|
|
|
2450
|
-
//# sourceMappingURL=bench-
|
|
2558
|
+
//# sourceMappingURL=bench-DQtfv5aq.js.map
|