@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.
@@ -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-BdZstlkf.js");
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
- if (theme.action === "skipped" && theme.themePath && skillRegistry) missingThemeTokens = findMissingThemeTokens(await readFile(theme.themePath, "utf8"), skillRegistry.flattened);
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: theme.action,
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
- return {
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 { buildHeaderLine as A, cliVersion as C, createRegistrySource as D, writeLockfile as E, verifyFetchedFamily as F, extractHeader as M, rewriteHeaderSha as N, resolvePresetFamilies as O, sealRecipeFile as P, DEFAULT_REGISTRY as S, readLockfile as T, NewFamilyError as _, formatFindingsText as a, add as b, UpgradeError as c, BuildError as d, build as f, reseal as g, preset as h, extractClassUsages as i, computeBodySha as j, detectProject as k, upgrade as l, ls as m, formatBenchTable as n, lint as o, formatLsText as p, ALL_RULES as r, verify as s, bench as t, dev as u, newFamily as v, init as w, renameFamilyInSource as x, remove as y };
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-BGO3pupw.js.map
2558
+ //# sourceMappingURL=bench-DQtfv5aq.js.map