@getvitops/cli 0.8.0 → 0.9.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @getvitops/cli
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **The `tailwind` format now emits the full role colour vocabulary.** It previously emitted only
8
+ the functional role utilities, so 87 classes — `bg-<role>-x-muted`, `bg-<role>-bold`,
9
+ `bg-<role>-x-bold`, `text-<role>-bold`, `text-<role>-x-bold`,
10
+ `border-<role>-{muted,x-muted,x-bold}`, for every role — existed in the `css` and `bricks`
11
+ outputs and silently did nothing in `tailwind`. Nothing in the test suite built the tailwind
12
+ format, so the divergence was invisible; it was found by a consumer who hand-forked four
13
+ background planes into their own stylesheet to work around the absence.
14
+
15
+ All three formats now render from one emitter (`roleColorUtilities()`), which resolves the
16
+ plane-vs-stop namespace collision explicitly instead of relying on the CSS minifier dropping a
17
+ shadowed rule. No class changes meaning, and the `css`/`bricks` output is unchanged.
18
+
19
+ Also fixed in the tailwind format:
20
+ - `colors.utilities` is now honoured. It was hardcoded to `bg`/`text`/`border`, so enabling
21
+ `outline`/`fill`/`stroke` worked in `css`/`bricks` and was ignored here. (For raw hue scales
22
+ it remains a floor rather than a ceiling — those are `@theme` colours, and Tailwind derives
23
+ every colour family from them on demand.)
24
+ - **Component container queries are no longer stripped.** The pass that drops the framework's
25
+ pre-expanded `md-*` breakpoint utilities (Tailwind regenerates those as `@md:`) matched every
26
+ `@container (min-width: …)` block, including component behaviour — most visibly the
27
+ sitenav's, so `.sitenav--bp-{sm,md,lg,xl}` were removed and the nav stayed in its mobile
28
+ layout at every width.
29
+
30
+ New: **`vitops lint`** reports framework classes in your source that resolve to nothing — the
31
+ failure mode where an unknown utility looks exactly like a working one. It is format-aware
32
+ (`md-flex-row` is a real class in `css`/`bricks` and inert in `tailwind`) and only judges
33
+ classes anchored to your own config, so it stays quiet on Tailwind's utilities and your own.
34
+
35
+ ```
36
+ vitops lint --format tailwind --src src
37
+ ```
38
+
39
+ ### Patch Changes
40
+
41
+ - Updated dependencies
42
+ - Updated dependencies
43
+ - Updated dependencies [c949cae]
44
+ - Updated dependencies
45
+ - Updated dependencies
46
+ - Updated dependencies
47
+ - @getvitops/generator@0.9.0
48
+ - @getvitops/utils@0.9.0
49
+
3
50
  ## 0.8.0
4
51
 
5
52
  ### Minor Changes
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
3
  import { parseArgs } from "node:util";
4
- import { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
5
- import { dirname, join, parse, relative, resolve } from "node:path";
6
- import { SCHEMA_URL, defaultConfig, generate, generateDocs, validate } from "@getvitops/generator";
4
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
5
+ import { dirname, extname, join, parse, relative, resolve } from "node:path";
6
+ import { SCHEMA_URL, defaultConfig, expandPalette, functionalRole, generate, generateDocs, roleColorUtilities, validate } from "@getvitops/generator";
7
7
  import { generateFavicons } from "@getvitops/utils";
8
8
 
9
9
  //#region src/agents.ts
@@ -94,6 +94,149 @@ function linkSkill(linkPath, targetDir) {
94
94
  }
95
95
  }
96
96
 
97
+ //#endregion
98
+ //#region src/lint.ts
99
+ const UTIL_FAMILIES = [
100
+ "bg",
101
+ "text",
102
+ "border",
103
+ "outline",
104
+ "fill",
105
+ "stroke"
106
+ ];
107
+ const ROLE_MODIFIERS = [
108
+ "",
109
+ "muted",
110
+ "x-muted",
111
+ "bold",
112
+ "x-bold",
113
+ "solid",
114
+ "solid-bold",
115
+ "bg-bold"
116
+ ];
117
+ function vocabulary(ds, roleClasses) {
118
+ return {
119
+ roles: Object.keys(ds.colors?.roles ?? {}),
120
+ hues: Object.keys(ds.colors?.palette ?? {}),
121
+ steps: [
122
+ "50",
123
+ "100",
124
+ "200",
125
+ "300",
126
+ "400",
127
+ "500",
128
+ "600",
129
+ "700",
130
+ "800",
131
+ "900",
132
+ "950"
133
+ ],
134
+ typeRoles: Object.keys(ds.typography?.roles ?? {}),
135
+ shadows: Object.keys(ds.shadows ?? {}),
136
+ patterns: Object.keys(ds.patterns?.items ?? {}),
137
+ roleClasses: new Set(roleClasses)
138
+ };
139
+ }
140
+ /** Strip Tailwind variant prefixes (`@md:`, `hover:`, `dark:`) from a candidate. */
141
+ const stripVariants = (cls) => {
142
+ let out = cls;
143
+ while (/^@?[a-zA-Z0-9_-]+:/.test(out)) out = out.slice(out.indexOf(":") + 1);
144
+ return out;
145
+ };
146
+ const nearest = (want, pool) => pool.find((p) => p.startsWith(want) || want.startsWith(p));
147
+ /**
148
+ * Judge one class token. Returns null when the class is none of our business —
149
+ * which is the common case and the whole reason this is low-noise.
150
+ */
151
+ function judge(raw, v, format) {
152
+ const cls = stripVariants(raw);
153
+ const bp = /^(sm|md|lg|xl)-(.+)$/.exec(cls);
154
+ if (bp && format === "tailwind") return {
155
+ cls: raw,
156
+ reason: `\`${bp[1]}-\` responsive classes are not emitted in the tailwind format`,
157
+ suggestion: `@${bp[1]}:${bp[2]} (framework breakpoints) or ${bp[1]}:${bp[2]} (Tailwind's)`
158
+ };
159
+ const base = bp && format !== "tailwind" ? bp[2] : cls;
160
+ const util = new RegExp(`^(${UTIL_FAMILIES.join("|")})-(.+)$`).exec(base);
161
+ if (util) {
162
+ const [, fam, rest] = util;
163
+ if (v.roleClasses.has(base)) return null;
164
+ const prefix = (names) => names.filter((n) => rest === n || rest.startsWith(`${n}-`)).sort((a, b) => b.length - a.length)[0];
165
+ const hue = prefix(v.hues);
166
+ const role = prefix(v.roles);
167
+ if (role && (!hue || role.length > hue.length)) {
168
+ const mod = rest.slice(role.length + 1);
169
+ return {
170
+ cls: raw,
171
+ reason: `\`${fam}-${role}${mod ? `-${mod}` : ""}\` is not emitted for the \`${role}\` role`,
172
+ suggestion: `valid modifiers: ${ROLE_MODIFIERS.filter(Boolean).join(", ")}`
173
+ };
174
+ }
175
+ if (hue) {
176
+ const step = rest.slice(hue.length + 1);
177
+ if (step === "") return {
178
+ cls: raw,
179
+ reason: `\`${fam}-${hue}\` names a palette hue with no step`,
180
+ suggestion: `${fam}-${hue}-500, or a role such as ${fam}-${v.roles[0] ?? "neutral"}`
181
+ };
182
+ if (!v.steps.includes(step)) return {
183
+ cls: raw,
184
+ reason: `\`${step}\` is not a step on the \`${hue}\` scale (steps are 50…950)`,
185
+ suggestion: `${fam}-${hue}-500, or a role such as ${fam}-${v.roles[0] ?? "neutral"} which also flips in dark mode`
186
+ };
187
+ return null;
188
+ }
189
+ return null;
190
+ }
191
+ const font = /^font-(.+)$/.exec(base);
192
+ if (font && v.typeRoles.length && !v.typeRoles.includes(font[1])) {
193
+ const near = nearest(font[1], v.typeRoles);
194
+ if (near) return {
195
+ cls: raw,
196
+ reason: `\`${font[1]}\` is not a typography role`,
197
+ suggestion: `font-${near}`
198
+ };
199
+ }
200
+ const ds = /^drop-shadow-(.+)$/.exec(base);
201
+ if (ds && v.shadows.length && !v.shadows.includes(ds[1])) return {
202
+ cls: raw,
203
+ reason: `\`${ds[1]}\` is not a defined shadow`,
204
+ suggestion: `drop-shadow-${v.shadows[0]}`
205
+ };
206
+ return null;
207
+ }
208
+ const CLASS_ATTR = /(?:class|className|:class)\s*=\s*(?:"([^"]*)"|'([^']*)'|\{`([^`]*)`\})/g;
209
+ /** Extract class tokens from a source file, with line numbers. */
210
+ function extractClasses(src) {
211
+ const out = [];
212
+ for (const m of src.matchAll(CLASS_ATTR)) {
213
+ const value = m[1] ?? m[2] ?? m[3] ?? "";
214
+ const line = src.slice(0, m.index).split("\n").length;
215
+ for (const tok of value.split(/\s+/)) if (tok && !tok.includes("${") && !tok.includes("{") && /^[@\w:[\]().%/-]+$/.test(tok)) out.push({
216
+ cls: tok,
217
+ line
218
+ });
219
+ }
220
+ return out;
221
+ }
222
+ function lintSource(files, v, format) {
223
+ const findings = [];
224
+ const seen = /* @__PURE__ */ new Set();
225
+ for (const f of files) for (const { cls, line } of extractClasses(f.text)) {
226
+ const verdict = judge(cls, v, format);
227
+ if (!verdict) continue;
228
+ const key = `${f.path}:${line}:${cls}`;
229
+ if (seen.has(key)) continue;
230
+ seen.add(key);
231
+ findings.push({
232
+ file: f.path,
233
+ line,
234
+ ...verdict
235
+ });
236
+ }
237
+ return findings;
238
+ }
239
+
97
240
  //#endregion
98
241
  //#region src/cli.ts
99
242
  /**
@@ -105,6 +248,7 @@ function linkSkill(linkPath, targetDir) {
105
248
  * vitops favicon --input <svg|png> --out <dir> [--low-res <svg|png>]
106
249
  * vitops agents [--input <json>] [--out AGENTS.md] [--docs-dir <dir>]
107
250
  * vitops docs [topic] [--input <json>] [--all]
251
+ * vitops lint [--input <json>] [--format <fmt>] [--src <dir>]
108
252
  *
109
253
  * Thin wrapper over @getvitops/generator (generation) and @getvitops/utils (favicons).
110
254
  * Every client brings their own consumer-editable design-system.json.
@@ -123,6 +267,7 @@ Usage:
123
267
  vitops favicon [options] Generate a favicon set from a source image
124
268
  vitops agents [options] Link the design-system agent skill + AGENTS.md pointer
125
269
  vitops docs [topic] Print live design-system reference docs to stdout
270
+ vitops lint [options] Report framework classes in your source that resolve to nothing
126
271
 
127
272
  Generate options:
128
273
  -i, --input <path> Config file (default: ./design-system.json)
@@ -150,6 +295,12 @@ Docs options:
150
295
  -i, --input <path> Config file (default: ./design-system.json)
151
296
  --all Print every topic, concatenated
152
297
 
298
+ Lint options:
299
+ -i, --input <path> Config file (default: ./design-system.json)
300
+ -f, --format <fmt> Format you build (bricks | css | tailwind; default: bricks).
301
+ Responsive md-* classes are real in css/bricks, inert in tailwind.
302
+ -s, --src <dir> Directory to scan (default: ./src)
303
+
153
304
  Common:
154
305
  -h, --help Show this help
155
306
  `;
@@ -289,6 +440,7 @@ function loadConfig(path) {
289
440
  for (const e of result.errors) console.error(` • ${e.path.join(".") || "(root)"}: ${e.message}`);
290
441
  process.exit(1);
291
442
  }
443
+ for (const w of result.warnings) console.warn(` ! ${w}`);
292
444
  return result.data;
293
445
  }
294
446
  function cliVersion() {
@@ -331,6 +483,88 @@ function cmdDocs(argv) {
331
483
  const paths = values.all ? Object.values(TOPICS).map((t) => t.path) : [TOPICS[topic].path];
332
484
  process.stdout.write(paths.map((p) => docs[p]).join("\n"));
333
485
  }
486
+ const SCAN_EXT = new Set([
487
+ ".astro",
488
+ ".html",
489
+ ".htm",
490
+ ".js",
491
+ ".jsx",
492
+ ".ts",
493
+ ".tsx",
494
+ ".vue",
495
+ ".svelte",
496
+ ".php",
497
+ ".md",
498
+ ".mdx"
499
+ ]);
500
+ const SCAN_SKIP = new Set([
501
+ "node_modules",
502
+ "dist",
503
+ ".git",
504
+ ".astro",
505
+ "build",
506
+ "coverage"
507
+ ]);
508
+ function scanFiles(dir, acc = []) {
509
+ for (const e of readdirSync(dir, { withFileTypes: true })) {
510
+ if (e.name.startsWith(".") && e.name !== ".") continue;
511
+ const p = join(dir, e.name);
512
+ if (e.isDirectory()) {
513
+ if (!SCAN_SKIP.has(e.name)) scanFiles(p, acc);
514
+ } else if (SCAN_EXT.has(extname(e.name))) acc.push({
515
+ path: p,
516
+ text: readFileSync(p, "utf8")
517
+ });
518
+ }
519
+ return acc;
520
+ }
521
+ function cmdLint(argv) {
522
+ const { values } = parseArgs({
523
+ args: argv,
524
+ options: {
525
+ input: {
526
+ type: "string",
527
+ short: "i",
528
+ default: "design-system.json"
529
+ },
530
+ format: {
531
+ type: "string",
532
+ short: "f",
533
+ default: "bricks"
534
+ },
535
+ src: {
536
+ type: "string",
537
+ short: "s",
538
+ default: "src"
539
+ }
540
+ },
541
+ allowPositionals: false
542
+ });
543
+ const format = values.format;
544
+ if (!FORMATS.has(format)) fail(`unknown format "${format}" (expected: bricks | css | tailwind)`);
545
+ const ds = loadConfig(resolve(values.input));
546
+ const srcDir = resolve(values.src);
547
+ if (!existsSync(srcDir)) fail(`source directory not found: ${srcDir}`);
548
+ const roleClasses = roleColorUtilities(Object.entries(ds.colors.roles).map(([role, hue]) => functionalRole(role, hue, expandPalette(ds.colors.palette)[hue])), ds.colors.utilities ?? [
549
+ "bg",
550
+ "text",
551
+ "border"
552
+ ]).map((u) => u.cls);
553
+ const files = scanFiles(srcDir);
554
+ const findings = lintSource(files, vocabulary(ds, roleClasses), format);
555
+ if (!findings.length) {
556
+ console.log(`✓ no unresolvable framework classes in ${values.src} (${files.length} file${files.length === 1 ? "" : "s"} scanned)`);
557
+ return;
558
+ }
559
+ for (const f of findings) {
560
+ console.error(`${f.file}:${f.line} ${f.cls}`);
561
+ console.error(` ${f.reason}`);
562
+ if (f.suggestion) console.error(` try: ${f.suggestion}`);
563
+ }
564
+ const n = findings.length;
565
+ console.error(`\n✖ ${n} unresolvable class${n === 1 ? "" : "es"} in ${files.length} file${files.length === 1 ? "" : "s"}`);
566
+ process.exit(1);
567
+ }
334
568
  function cmdAgents(argv) {
335
569
  const { values } = parseArgs({
336
570
  args: argv,
@@ -449,7 +683,8 @@ async function main() {
449
683
  case "favicon": return cmdFavicon(rest);
450
684
  case "agents": return cmdAgents(rest);
451
685
  case "docs": return cmdDocs(rest);
452
- default: fail(`unknown command "${command}" (expected: generate | init | validate | favicon | agents | docs). Try: vitops --help`);
686
+ case "lint": return cmdLint(rest);
687
+ default: fail(`unknown command "${command}" (expected: generate | init | validate | favicon | agents | docs | lint). Try: vitops --help`);
453
688
  }
454
689
  }
455
690
  main().catch((err) => fail(err.message));
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../src/agents.ts","../src/cli.ts"],"sourcesContent":["/**\n * Side-effect-free helpers for the `vitops agents` / `vitops docs` commands.\n * Kept out of cli.ts (which runs main() on import) so they are unit-testable.\n */\nimport {\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n readlinkSync,\n rmSync,\n symlinkSync,\n} from 'node:fs';\nimport { dirname, join, parse, relative, resolve } from 'node:path';\n\nexport const SKILL_NAME = 'vitops-design-system';\n\n/** Marker the 0.5.0-era generated skill carried; lets us migrate that layout. */\nexport const GENERATED_MARKER = '<!-- GENERATED by @getvitops/cli';\n\n/**\n * `vitops docs` topics → docs-bundle paths (as returned by `generateDocs`).\n * Order is the `--all` concatenation order.\n */\nexport const TOPICS: Record<string, { path: string; summary: string }> = {\n classes: {\n path: 'css/classes.md',\n summary: 'CSS framework class vocabulary (colour, type, space, layout, animation, patterns)',\n },\n authoring: {\n path: 'authoring.md',\n summary: 'every design-system.json field, rendered from the JSON Schema',\n },\n formats: {\n path: 'formats.md',\n summary: \"tailwind vs css vs bricks: what's emitted vs what the platform provides\",\n },\n color: {\n path: 'concepts/color.md',\n summary: 'seeded OKLCH scales, functional tokens, automatic dark mode',\n },\n scales: {\n path: 'concepts/scales.md',\n summary: 'fluid modular type & space scales',\n },\n patterns: {\n path: 'concepts/patterns.md',\n summary: 'pattern CSS: token cascade, override hooks, states, role variants',\n },\n elements: {\n path: 'bricks/elements.md',\n summary: 'Bricks Builder custom elements, controls, defaults',\n },\n};\n\n/**\n * Find the installed package's skill directory by walking up from `cwd` looking\n * for `node_modules/@getvitops/cli/skill/SKILL.md`. Returns the LOGICAL path\n * (through the `node_modules/@getvitops/cli` link, unresolved) or null.\n *\n * Deliberately not derived from import.meta.url: under pnpm the running module's\n * URL is the realpath in `node_modules/.pnpm/@getvitops+cli@<version>/…`, which\n * changes on every version bump — a symlink to it would dangle after upgrades.\n * The logical path is recreated by the package manager on every install, so a\n * link through it always resolves to the currently installed version.\n */\nexport function findSkillTarget(cwd: string): string | null {\n let dir = resolve(cwd);\n const { root } = parse(dir);\n for (;;) {\n const skillDir = join(dir, 'node_modules', '@getvitops', 'cli', 'skill');\n if (existsSync(join(skillDir, 'SKILL.md'))) return skillDir;\n if (dir === root) return null;\n dir = dirname(dir);\n }\n}\n\n/**\n * Idempotently symlink `linkPath` → `targetDir` (relative target). Replaces a\n * stale symlink; migrates a real directory left by the old emitting `vitops\n * agents` (identified by GENERATED_MARKER in its SKILL.md); refuses to clobber\n * anything else. Returns a warning string, or null on success / no-op.\n */\nexport function linkSkill(linkPath: string, targetDir: string): string | null {\n const target = relative(dirname(linkPath), resolve(targetDir));\n try {\n const st = lstatSync(linkPath, { throwIfNoEntry: false });\n if (st && !st.isSymbolicLink()) {\n const oldSkill = join(linkPath, 'SKILL.md');\n const isGenerated =\n st.isDirectory() &&\n existsSync(oldSkill) &&\n readFileSync(oldSkill, 'utf8').includes(GENERATED_MARKER);\n if (!isGenerated)\n return `left ${linkPath} alone (exists and is not a symlink) — link it to ${targetDir} yourself if wanted`;\n rmSync(linkPath, { recursive: true }); // old generated skill layout → replace\n } else if (st) {\n if (readlinkSync(linkPath) === target) return null;\n rmSync(linkPath);\n } else {\n mkdirSync(dirname(linkPath), { recursive: true });\n }\n symlinkSync(target, linkPath);\n return null;\n } catch (err) {\n return `could not symlink ${linkPath}: ${(err as Error).message}`;\n }\n}\n","#!/usr/bin/env node\n/**\n * `vitops` — CLI for the Vitops design-system generator.\n *\n * vitops generate --input <json> --format <bricks|css|tailwind[,…]> --out <dir>\n * vitops init [--out design-system.json] [--force]\n * vitops validate <design-system.json>\n * vitops favicon --input <svg|png> --out <dir> [--low-res <svg|png>]\n * vitops agents [--input <json>] [--out AGENTS.md] [--docs-dir <dir>]\n * vitops docs [topic] [--input <json>] [--all]\n *\n * Thin wrapper over @getvitops/generator (generation) and @getvitops/utils (favicons).\n * Every client brings their own consumer-editable design-system.json.\n */\nimport { parseArgs } from 'node:util';\nimport { writeFileSync, existsSync, readFileSync, mkdirSync } from 'node:fs';\nimport { resolve, join, dirname } from 'node:path';\nimport { createRequire } from 'node:module';\nimport {\n generate,\n validate,\n defaultConfig,\n generateDocs,\n SCHEMA_URL,\n type Format,\n type DesignSystem,\n} from '@getvitops/generator';\nimport { generateFavicons } from '@getvitops/utils';\nimport { findSkillTarget, linkSkill, SKILL_NAME, TOPICS } from './agents.ts';\n\nconst FORMATS = new Set<Format>(['bricks', 'css', 'tailwind']);\n\nconst HELP = `vitops — generate design-system outputs from a design-system.json\n\nUsage:\n vitops generate [options] Generate platform output from a config\n vitops init [options] Scaffold a starter design-system.json\n vitops validate <file> Validate a config against the schema\n vitops favicon [options] Generate a favicon set from a source image\n vitops agents [options] Link the design-system agent skill + AGENTS.md pointer\n vitops docs [topic] Print live design-system reference docs to stdout\n\nGenerate options:\n -i, --input <path> Config file (default: ./design-system.json)\n -f, --format <list> bricks | css | tailwind (comma-separated; default: bricks)\n -o, --out <dir> Output directory (default: ./dist)\n\nInit options:\n -o, --out <path> Where to write (default: ./design-system.json)\n --force Overwrite an existing file\n\nFavicon options:\n -i, --input <path> Source SVG or PNG (required)\n -o, --out <dir> Output directory (default: ./public)\n --low-res <path> Optional simplified source for the 16px icon\n\nAgents options:\n -i, --input <path> Config file (default: ./design-system.json; validated if present)\n -o, --out <path> Doc file to update, idempotently (default: ./AGENTS.md)\n --docs-dir <dir> Legacy layout: write the docs bundle as files to this dir\n instead of linking the packaged skill\n\nDocs options:\n <topic> classes | authoring | formats | color | scales | patterns | elements\n (no topic: list topics with summaries)\n -i, --input <path> Config file (default: ./design-system.json)\n --all Print every topic, concatenated\n\nCommon:\n -h, --help Show this help\n`;\n\nfunction fail(msg: string): never {\n console.error(`✖ ${msg}`);\n process.exit(1);\n}\n\nasync function cmdGenerate(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n format: { type: 'string', short: 'f', default: 'bricks' },\n out: { type: 'string', short: 'o', default: 'dist' },\n },\n allowPositionals: false,\n });\n const input = resolve(values.input as string);\n if (!existsSync(input)) fail(`config not found: ${input}`);\n const formats = (values.format as string)\n .split(',')\n .map((f) => f.trim())\n .filter(Boolean);\n for (const f of formats)\n if (!FORMATS.has(f as Format))\n fail(`unknown format \"${f}\" (expected: bricks | css | tailwind)`);\n\n for (const format of formats as Format[]) {\n try {\n const res = await generate({ input, format, outDir: values.out as string });\n console.log(`✓ ${format} → ${res.outDir} (${res.written.length} paths)`);\n } catch (err) {\n fail((err as Error).message);\n }\n }\n}\n\nfunction cmdInit(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n out: { type: 'string', short: 'o', default: 'design-system.json' },\n force: { type: 'boolean', default: false },\n },\n allowPositionals: false,\n });\n const out = resolve(values.out as string);\n if (existsSync(out) && !values.force) fail(`${out} already exists (use --force to overwrite)`);\n writeFileSync(out, JSON.stringify(defaultConfig(), null, 2) + '\\n');\n console.log(`✓ wrote ${out}`);\n console.log(\n ` Edit it, then: vitops generate --input ${values.out} --format tailwind --out src/styles`,\n );\n console.log(` Editors read the \"$schema\" (${SCHEMA_URL}) for autocomplete + validation.`);\n}\n\nfunction cmdValidate(argv: string[]) {\n const { values, positionals } = parseArgs({\n args: argv,\n options: { input: { type: 'string', short: 'i' } },\n allowPositionals: true,\n });\n const path = resolve((positionals[0] ?? values.input ?? 'design-system.json') as string);\n if (!existsSync(path)) fail(`config not found: ${path}`);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf8'));\n } catch (err) {\n fail(`could not parse JSON: ${(err as Error).message}`);\n }\n const result = validate(raw);\n for (const w of result.warnings) console.warn(` ! ${w}`);\n if (result.ok) {\n console.log(`✓ ${path} is valid`);\n return;\n }\n console.error(`✖ ${path} is invalid:`);\n for (const e of result.errors) console.error(` • ${e.path.join('.') || '(root)'}: ${e.message}`);\n process.exit(1);\n}\n\nasync function cmdFavicon(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i' },\n out: { type: 'string', short: 'o', default: 'public' },\n 'low-res': { type: 'string' },\n },\n allowPositionals: false,\n });\n if (!values.input) fail('favicon: --input <svg|png> is required');\n const source = resolve(values.input as string);\n if (!existsSync(source)) fail(`source not found: ${source}`);\n try {\n const written = await generateFavicons({\n source,\n outputDir: values.out as string,\n ...(values['low-res'] ? { lowResSource: resolve(values['low-res'] as string) } : {}),\n });\n console.log(`✓ favicons → ${values.out} (${written.length} files)`);\n } catch (err) {\n fail((err as Error).message);\n }\n}\n\n// Read + parse + validate a design-system.json, or exit with a message.\nfunction loadConfig(path: string): DesignSystem {\n if (!existsSync(path)) fail(`config not found: ${path}`);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf8'));\n } catch (err) {\n fail(`could not parse JSON: ${(err as Error).message}`);\n }\n const result = validate(raw);\n if (!result.ok) {\n console.error(`✖ ${path} is invalid:`);\n for (const e of result.errors)\n console.error(` • ${e.path.join('.') || '(root)'}: ${e.message}`);\n process.exit(1);\n }\n return result.data;\n}\n\n// This CLI's own version (dist/cli.mjs → package-root package.json).\nfunction cliVersion(): string {\n try {\n return (\n JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version ??\n '0.0.0'\n );\n } catch {\n return '0.0.0';\n }\n}\n\n// The framework asset root shipped inside @getvitops/generator (holds the Bricks\n// PHP that generateDocs reads for the element reference).\nfunction generatorAssetsDir(): string {\n const pkg = createRequire(import.meta.url).resolve('@getvitops/generator/package.json');\n return join(dirname(pkg), 'assets');\n}\n\nconst AGENTS_START = '<!-- vitops:start -->';\nconst AGENTS_END = '<!-- vitops:end -->';\n\n/** Print a live reference doc (rendered from the project's config) to stdout. */\nfunction cmdDocs(argv: string[]) {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n all: { type: 'boolean', default: false },\n },\n allowPositionals: true,\n });\n const topic = positionals[0];\n const topicList = () =>\n Object.entries(TOPICS)\n .map(([name, t]) => ` ${name.padEnd(10)} ${t.summary}`)\n .join('\\n');\n if (!topic && !values.all) {\n console.log(\n `vitops docs <topic> — print a live design-system reference to stdout\\n\\nTopics:\\n${topicList()}\\n\\nAlso: vitops docs --all (every topic, concatenated)`,\n );\n return;\n }\n if (topic && !TOPICS[topic]) fail(`unknown topic \"${topic}\". Valid topics:\\n${topicList()}`);\n const ds = loadConfig(resolve(values.input as string));\n const docs = generateDocs(ds, generatorAssetsDir());\n const paths = values.all\n ? Object.values(TOPICS).map((t) => t.path)\n : [TOPICS[topic as string]!.path];\n process.stdout.write(paths.map((p) => docs[p]).join('\\n'));\n}\n\nfunction cmdAgents(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n out: { type: 'string', short: 'o', default: 'AGENTS.md' },\n 'docs-dir': { type: 'string' },\n },\n allowPositionals: false,\n });\n const inputRel = values.input as string;\n // The command is pure wiring: validate the config when present (fail on an\n // invalid one), but don't require it — docs are rendered live by `vitops docs`.\n let ds: DesignSystem | null = null;\n if (existsSync(resolve(inputRel))) ds = loadConfig(resolve(inputRel));\n else console.warn(` ⚠ ${inputRel} not found — run \\`vitops init\\` to scaffold one`);\n\n // Explicit --docs-dir = legacy layout: write the docs bundle as files, no skill.\n const legacyDocsDir = values['docs-dir'] as string | undefined;\n let summary: string;\n let pointer: string[];\n\n if (legacyDocsDir) {\n if (!ds) fail(`--docs-dir needs a config to render docs from (${inputRel} not found)`);\n let docs: Record<string, string> = {};\n try {\n docs = generateDocs(ds, generatorAssetsDir());\n } catch (err) {\n fail(`could not generate docs: ${(err as Error).message}`);\n }\n for (const [rel, content] of Object.entries(docs)) {\n const p = resolve(legacyDocsDir, rel);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, content);\n }\n summary = `wrote ${Object.keys(docs).length} docs to ${legacyDocsDir}/`;\n pointer = [\n 'Prefer the framework’s utility + component classes over hand-written CSS.',\n `Reference docs (regenerate with \\`vitops agents --docs-dir ${legacyDocsDir}\\`): \\`${legacyDocsDir}/css/classes.md\\`,`,\n `\\`${legacyDocsDir}/authoring.md\\`, \\`${legacyDocsDir}/formats.md\\`, \\`${legacyDocsDir}/bricks/elements.md\\`.`,\n ];\n } else {\n // Link the packaged skill (ships inside @getvitops/cli) into the agent\n // discovery locations; nothing is generated into the repo.\n const target = findSkillTarget(process.cwd());\n if (target) {\n for (const dir of ['.agents', '.claude']) {\n const warn = linkSkill(resolve(dir, 'skills', SKILL_NAME), target);\n if (warn) console.warn(` ⚠ ${warn}`);\n }\n summary = `linked {.agents,.claude}/skills/${SKILL_NAME} → ${target}`;\n } else {\n console.warn(\n ` ⚠ could not find node_modules/@getvitops/cli/skill — install @getvitops/cli as a devDependency, then re-run \\`vitops agents\\``,\n );\n summary = 'no skill linked';\n }\n pointer = [\n 'Prefer the framework’s utility + component classes over hand-written CSS.',\n `Full design-system context lives in the \\`${SKILL_NAME}\\` skill (linked from`,\n '`.agents/skills/` and `.claude/skills/` into the installed `@getvitops/cli`;',\n 're-link with `vitops agents` if the links are deleted — they survive version',\n 'bumps). Reference docs print live, from this project’s config, via:',\n '',\n ...Object.entries(TOPICS).map(([name, t]) => `- \\`vitops docs ${name}\\` — ${t.summary}`),\n ];\n }\n\n const block = [\n AGENTS_START,\n '## Vitops design system',\n '',\n `Styled with the Vitops design system (\\`@getvitops/*\\`); tokens live in \\`${inputRel}\\`.`,\n 'Generate output with the CLI:',\n '',\n '- `vitops generate --format tailwind --out src/styles` — Tailwind v4 / Astro',\n '- `vitops generate --format css --out dist` — standalone CSS',\n '- `vitops generate --format bricks --out <theme>/dist` — WordPress / Bricks',\n '- `vitops init` · `vitops validate` · `vitops favicon`',\n '',\n ...pointer,\n '',\n `<!-- regenerate: vitops agents · @getvitops/cli@${cliVersion()} -->`,\n AGENTS_END,\n ].join('\\n');\n\n const outPath = resolve(values.out as string);\n let next: string;\n let action: string;\n if (existsSync(outPath)) {\n const cur = readFileSync(outPath, 'utf8');\n const s = cur.indexOf(AGENTS_START);\n const e = cur.indexOf(AGENTS_END);\n if (s !== -1 && e !== -1 && e > s) {\n next = cur.slice(0, s) + block + cur.slice(e + AGENTS_END.length);\n action = 'updated block in';\n } else {\n next = cur.replace(/\\s*$/, '') + '\\n\\n' + block + '\\n';\n action = 'appended block to';\n }\n } else {\n mkdirSync(dirname(outPath), { recursive: true });\n next = block + '\\n';\n action = 'created';\n }\n writeFileSync(outPath, next);\n console.log(`✓ ${action} ${values.out} + ${summary}`);\n}\n\nasync function main() {\n const [command, ...rest] = process.argv.slice(2);\n if (!command || command === '-h' || command === '--help' || command === 'help') {\n console.log(HELP);\n return;\n }\n switch (command) {\n case 'generate':\n return cmdGenerate(rest);\n case 'init':\n return cmdInit(rest);\n case 'validate':\n return cmdValidate(rest);\n case 'favicon':\n return cmdFavicon(rest);\n case 'agents':\n return cmdAgents(rest);\n case 'docs':\n return cmdDocs(rest);\n default:\n fail(\n `unknown command \"${command}\" (expected: generate | init | validate | favicon | agents | docs). Try: vitops --help`,\n );\n }\n}\n\nmain().catch((err) => fail((err as Error).message));\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/agents.ts","../src/lint.ts","../src/cli.ts"],"sourcesContent":["/**\n * Side-effect-free helpers for the `vitops agents` / `vitops docs` commands.\n * Kept out of cli.ts (which runs main() on import) so they are unit-testable.\n */\nimport {\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n readlinkSync,\n rmSync,\n symlinkSync,\n} from 'node:fs';\nimport { dirname, join, parse, relative, resolve } from 'node:path';\n\nexport const SKILL_NAME = 'vitops-design-system';\n\n/** Marker the 0.5.0-era generated skill carried; lets us migrate that layout. */\nexport const GENERATED_MARKER = '<!-- GENERATED by @getvitops/cli';\n\n/**\n * `vitops docs` topics → docs-bundle paths (as returned by `generateDocs`).\n * Order is the `--all` concatenation order.\n */\nexport const TOPICS: Record<string, { path: string; summary: string }> = {\n classes: {\n path: 'css/classes.md',\n summary: 'CSS framework class vocabulary (colour, type, space, layout, animation, patterns)',\n },\n authoring: {\n path: 'authoring.md',\n summary: 'every design-system.json field, rendered from the JSON Schema',\n },\n formats: {\n path: 'formats.md',\n summary: \"tailwind vs css vs bricks: what's emitted vs what the platform provides\",\n },\n color: {\n path: 'concepts/color.md',\n summary: 'seeded OKLCH scales, functional tokens, automatic dark mode',\n },\n scales: {\n path: 'concepts/scales.md',\n summary: 'fluid modular type & space scales',\n },\n patterns: {\n path: 'concepts/patterns.md',\n summary: 'pattern CSS: token cascade, override hooks, states, role variants',\n },\n elements: {\n path: 'bricks/elements.md',\n summary: 'Bricks Builder custom elements, controls, defaults',\n },\n};\n\n/**\n * Find the installed package's skill directory by walking up from `cwd` looking\n * for `node_modules/@getvitops/cli/skill/SKILL.md`. Returns the LOGICAL path\n * (through the `node_modules/@getvitops/cli` link, unresolved) or null.\n *\n * Deliberately not derived from import.meta.url: under pnpm the running module's\n * URL is the realpath in `node_modules/.pnpm/@getvitops+cli@<version>/…`, which\n * changes on every version bump — a symlink to it would dangle after upgrades.\n * The logical path is recreated by the package manager on every install, so a\n * link through it always resolves to the currently installed version.\n */\nexport function findSkillTarget(cwd: string): string | null {\n let dir = resolve(cwd);\n const { root } = parse(dir);\n for (;;) {\n const skillDir = join(dir, 'node_modules', '@getvitops', 'cli', 'skill');\n if (existsSync(join(skillDir, 'SKILL.md'))) return skillDir;\n if (dir === root) return null;\n dir = dirname(dir);\n }\n}\n\n/**\n * Idempotently symlink `linkPath` → `targetDir` (relative target). Replaces a\n * stale symlink; migrates a real directory left by the old emitting `vitops\n * agents` (identified by GENERATED_MARKER in its SKILL.md); refuses to clobber\n * anything else. Returns a warning string, or null on success / no-op.\n */\nexport function linkSkill(linkPath: string, targetDir: string): string | null {\n const target = relative(dirname(linkPath), resolve(targetDir));\n try {\n const st = lstatSync(linkPath, { throwIfNoEntry: false });\n if (st && !st.isSymbolicLink()) {\n const oldSkill = join(linkPath, 'SKILL.md');\n const isGenerated =\n st.isDirectory() &&\n existsSync(oldSkill) &&\n readFileSync(oldSkill, 'utf8').includes(GENERATED_MARKER);\n if (!isGenerated)\n return `left ${linkPath} alone (exists and is not a symlink) — link it to ${targetDir} yourself if wanted`;\n rmSync(linkPath, { recursive: true }); // old generated skill layout → replace\n } else if (st) {\n if (readlinkSync(linkPath) === target) return null;\n rmSync(linkPath);\n } else {\n mkdirSync(dirname(linkPath), { recursive: true });\n }\n symlinkSync(target, linkPath);\n return null;\n } catch (err) {\n return `could not symlink ${linkPath}: ${(err as Error).message}`;\n }\n}\n","/**\n * `vitops lint` — find framework classes in consumer source that resolve to\n * nothing in the format being built.\n *\n * The problem this exists for: an unknown utility class is indistinguishable\n * from a working one. Nothing errors, nothing warns, the element just doesn't\n * get the style. Two shapes of that were found in a real consumer site:\n *\n * • `bg-navy-d` — a leftover from the named-step scale (`d`/`xd`/`xxd`)\n * deleted in favour of numeric steps. The hue is real, the step is not.\n * It appeared ~10× and looked fine only because the `.card` it sat on\n * supplied its own background.\n * • `md-flex-row` — the css/bricks spelling of a responsive variant, used in\n * a `tailwind`-format project where that class is never emitted (Tailwind\n * regenerates those on demand as `@md:`). Silently inert.\n *\n * DESIGN: this deliberately only inspects classes ANCHORED TO THE CONSUMER'S\n * OWN CONFIG — a hue name, a role name, a type role, a shadow, a pattern. It\n * never tries to enumerate \"all valid classes\", because in the tailwind format\n * that would mean knowing Tailwind's entire built-in vocabulary, and every\n * unknown would be a false positive. Anchoring means a finding is always\n * actionable: you named something from your design system, and it doesn't\n * resolve.\n */\nimport type { DesignSystem, Format } from '@getvitops/generator';\n\nexport interface LintFinding {\n file: string;\n line: number;\n cls: string;\n reason: string;\n suggestion?: string;\n}\n\nconst UTIL_FAMILIES = ['bg', 'text', 'border', 'outline', 'fill', 'stroke'];\nconst BREAKPOINTS = ['sm', 'md', 'lg', 'xl'];\nconst ROLE_MODIFIERS = ['', 'muted', 'x-muted', 'bold', 'x-bold', 'solid', 'solid-bold', 'bg-bold'];\n\n/** Everything the config makes namable, so we only judge classes we can judge. */\ninterface Vocabulary {\n roles: string[];\n hues: string[];\n steps: string[];\n typeRoles: string[];\n shadows: string[];\n patterns: string[];\n /** Every role utility the generator actually emits, e.g. `bg-surface-x-muted`. */\n roleClasses: Set<string>;\n}\n\nexport function vocabulary(ds: DesignSystem, roleClasses: Iterable<string>): Vocabulary {\n return {\n roles: Object.keys(ds.colors?.roles ?? {}),\n hues: Object.keys(ds.colors?.palette ?? {}),\n steps: ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'],\n typeRoles: Object.keys(ds.typography?.roles ?? {}),\n shadows: Object.keys(ds.shadows ?? {}),\n patterns: Object.keys(ds.patterns?.items ?? {}),\n roleClasses: new Set(roleClasses),\n };\n}\n\n/** Strip Tailwind variant prefixes (`@md:`, `hover:`, `dark:`) from a candidate. */\nconst stripVariants = (cls: string): string => {\n let out = cls;\n while (/^@?[a-zA-Z0-9_-]+:/.test(out)) out = out.slice(out.indexOf(':') + 1);\n return out;\n};\n\nconst nearest = (want: string, pool: string[]): string | undefined =>\n pool.find((p) => p.startsWith(want) || want.startsWith(p));\n\n/**\n * Judge one class token. Returns null when the class is none of our business —\n * which is the common case and the whole reason this is low-noise.\n */\nexport function judge(\n raw: string,\n v: Vocabulary,\n format: Format,\n): Omit<LintFinding, 'file' | 'line'> | null {\n const cls = stripVariants(raw);\n\n // ── the `<bp>-` responsive spelling ────────────────────────────────────────\n const bp = /^(sm|md|lg|xl)-(.+)$/.exec(cls);\n if (bp && format === 'tailwind')\n return {\n cls: raw,\n reason: `\\`${bp[1]}-\\` responsive classes are not emitted in the tailwind format`,\n suggestion: `@${bp[1]}:${bp[2]} (framework breakpoints) or ${bp[1]}:${bp[2]} (Tailwind's)`,\n };\n // In css/bricks the bare-prefix form is real; fall through and judge the base\n // against the rest of the vocabulary.\n const base = bp && format !== 'tailwind' ? (bp[2] as string) : cls;\n\n // ── <util>-<hue>-<step> ────────────────────────────────────────────────────\n const util = new RegExp(`^(${UTIL_FAMILIES.join('|')})-(.+)$`).exec(base);\n if (util) {\n const [, fam, rest] = util as unknown as [string, string, string];\n // Anything the generator actually emits is valid, full stop. Checking this\n // first also settles the ambiguity below for every well-formed class.\n if (v.roleClasses.has(base)) return null;\n\n // Role and hue names can share a prefix — `defaultConfig()` has the hue\n // `brand` and the role `brand-primary`, so matching hues first would read\n // `bg-brand-primary-x-muted` as hue `brand` + step `primary-x-muted` and\n // report a bogus bad step. Take the LONGEST match across both vocabularies.\n const prefix = (names: string[]) =>\n names\n .filter((n) => rest === n || rest.startsWith(`${n}-`))\n .sort((a, b) => b.length - a.length)[0];\n const hue = prefix(v.hues);\n const role = prefix(v.roles);\n const useRole = role && (!hue || role.length > hue.length);\n\n if (useRole) {\n const mod = rest.slice((role as string).length + 1);\n return {\n cls: raw,\n reason: `\\`${fam}-${role}${mod ? `-${mod}` : ''}\\` is not emitted for the \\`${role}\\` role`,\n suggestion: `valid modifiers: ${ROLE_MODIFIERS.filter(Boolean).join(', ')}`,\n };\n }\n if (hue) {\n const step = rest.slice(hue.length + 1);\n if (step === '')\n return {\n cls: raw,\n reason: `\\`${fam}-${hue}\\` names a palette hue with no step`,\n suggestion: `${fam}-${hue}-500, or a role such as ${fam}-${v.roles[0] ?? 'neutral'}`,\n };\n if (!v.steps.includes(step))\n return {\n cls: raw,\n reason: `\\`${step}\\` is not a step on the \\`${hue}\\` scale (steps are 50…950)`,\n suggestion: `${fam}-${hue}-500, or a role such as ${fam}-${v.roles[0] ?? 'neutral'} which also flips in dark mode`,\n };\n return null; // valid raw step\n }\n return null; // not anchored to this config — not ours to judge\n }\n\n // ── font-<type-role> ───────────────────────────────────────────────────────\n const font = /^font-(.+)$/.exec(base);\n if (font && v.typeRoles.length && !v.typeRoles.includes(font[1] as string)) {\n const near = nearest(font[1] as string, v.typeRoles);\n // Only complain when it looks like a type role attempt, not e.g. font-bold.\n if (near)\n return {\n cls: raw,\n reason: `\\`${font[1]}\\` is not a typography role`,\n suggestion: `font-${near}`,\n };\n }\n\n // ── drop-shadow-<name> ─────────────────────────────────────────────────────\n const ds = /^drop-shadow-(.+)$/.exec(base);\n if (ds && v.shadows.length && !v.shadows.includes(ds[1] as string))\n return {\n cls: raw,\n reason: `\\`${ds[1]}\\` is not a defined shadow`,\n suggestion: `drop-shadow-${v.shadows[0]}`,\n };\n\n return null;\n}\n\nconst CLASS_ATTR = /(?:class|className|:class)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|\\{`([^`]*)`\\})/g;\n\n/** Extract class tokens from a source file, with line numbers. */\nexport function extractClasses(src: string): { cls: string; line: number }[] {\n const out: { cls: string; line: number }[] = [];\n for (const m of src.matchAll(CLASS_ATTR)) {\n const value = m[1] ?? m[2] ?? m[3] ?? '';\n const line = src.slice(0, m.index).split('\\n').length;\n for (const tok of value.split(/\\s+/))\n // Skip template holes and dynamic fragments — a partial token would be\n // judged as a typo and this must not cry wolf.\n if (tok && !tok.includes('${') && !tok.includes('{') && /^[@\\w:[\\]().%/-]+$/.test(tok))\n out.push({ cls: tok, line });\n }\n return out;\n}\n\nexport function lintSource(\n files: { path: string; text: string }[],\n v: Vocabulary,\n format: Format,\n): LintFinding[] {\n const findings: LintFinding[] = [];\n const seen = new Set<string>();\n for (const f of files)\n for (const { cls, line } of extractClasses(f.text)) {\n const verdict = judge(cls, v, format);\n if (!verdict) continue;\n const key = `${f.path}:${line}:${cls}`;\n if (seen.has(key)) continue;\n seen.add(key);\n findings.push({ file: f.path, line, ...verdict });\n }\n return findings;\n}\n","#!/usr/bin/env node\n/**\n * `vitops` — CLI for the Vitops design-system generator.\n *\n * vitops generate --input <json> --format <bricks|css|tailwind[,…]> --out <dir>\n * vitops init [--out design-system.json] [--force]\n * vitops validate <design-system.json>\n * vitops favicon --input <svg|png> --out <dir> [--low-res <svg|png>]\n * vitops agents [--input <json>] [--out AGENTS.md] [--docs-dir <dir>]\n * vitops docs [topic] [--input <json>] [--all]\n * vitops lint [--input <json>] [--format <fmt>] [--src <dir>]\n *\n * Thin wrapper over @getvitops/generator (generation) and @getvitops/utils (favicons).\n * Every client brings their own consumer-editable design-system.json.\n */\nimport { parseArgs } from 'node:util';\nimport { writeFileSync, existsSync, readFileSync, mkdirSync, readdirSync } from 'node:fs';\nimport { resolve, join, dirname, extname } from 'node:path';\nimport { createRequire } from 'node:module';\nimport {\n generate,\n validate,\n defaultConfig,\n generateDocs,\n roleColorUtilities,\n functionalRole,\n expandPalette,\n SCHEMA_URL,\n type Format,\n type DesignSystem,\n} from '@getvitops/generator';\nimport { generateFavicons } from '@getvitops/utils';\nimport { findSkillTarget, linkSkill, SKILL_NAME, TOPICS } from './agents.ts';\nimport { lintSource, vocabulary } from './lint.ts';\n\nconst FORMATS = new Set<Format>(['bricks', 'css', 'tailwind']);\n\nconst HELP = `vitops — generate design-system outputs from a design-system.json\n\nUsage:\n vitops generate [options] Generate platform output from a config\n vitops init [options] Scaffold a starter design-system.json\n vitops validate <file> Validate a config against the schema\n vitops favicon [options] Generate a favicon set from a source image\n vitops agents [options] Link the design-system agent skill + AGENTS.md pointer\n vitops docs [topic] Print live design-system reference docs to stdout\n vitops lint [options] Report framework classes in your source that resolve to nothing\n\nGenerate options:\n -i, --input <path> Config file (default: ./design-system.json)\n -f, --format <list> bricks | css | tailwind (comma-separated; default: bricks)\n -o, --out <dir> Output directory (default: ./dist)\n\nInit options:\n -o, --out <path> Where to write (default: ./design-system.json)\n --force Overwrite an existing file\n\nFavicon options:\n -i, --input <path> Source SVG or PNG (required)\n -o, --out <dir> Output directory (default: ./public)\n --low-res <path> Optional simplified source for the 16px icon\n\nAgents options:\n -i, --input <path> Config file (default: ./design-system.json; validated if present)\n -o, --out <path> Doc file to update, idempotently (default: ./AGENTS.md)\n --docs-dir <dir> Legacy layout: write the docs bundle as files to this dir\n instead of linking the packaged skill\n\nDocs options:\n <topic> classes | authoring | formats | color | scales | patterns | elements\n (no topic: list topics with summaries)\n -i, --input <path> Config file (default: ./design-system.json)\n --all Print every topic, concatenated\n\nLint options:\n -i, --input <path> Config file (default: ./design-system.json)\n -f, --format <fmt> Format you build (bricks | css | tailwind; default: bricks).\n Responsive md-* classes are real in css/bricks, inert in tailwind.\n -s, --src <dir> Directory to scan (default: ./src)\n\nCommon:\n -h, --help Show this help\n`;\n\nfunction fail(msg: string): never {\n console.error(`✖ ${msg}`);\n process.exit(1);\n}\n\nasync function cmdGenerate(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n format: { type: 'string', short: 'f', default: 'bricks' },\n out: { type: 'string', short: 'o', default: 'dist' },\n },\n allowPositionals: false,\n });\n const input = resolve(values.input as string);\n if (!existsSync(input)) fail(`config not found: ${input}`);\n const formats = (values.format as string)\n .split(',')\n .map((f) => f.trim())\n .filter(Boolean);\n for (const f of formats)\n if (!FORMATS.has(f as Format))\n fail(`unknown format \"${f}\" (expected: bricks | css | tailwind)`);\n\n for (const format of formats as Format[]) {\n try {\n const res = await generate({ input, format, outDir: values.out as string });\n console.log(`✓ ${format} → ${res.outDir} (${res.written.length} paths)`);\n } catch (err) {\n fail((err as Error).message);\n }\n }\n}\n\nfunction cmdInit(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n out: { type: 'string', short: 'o', default: 'design-system.json' },\n force: { type: 'boolean', default: false },\n },\n allowPositionals: false,\n });\n const out = resolve(values.out as string);\n if (existsSync(out) && !values.force) fail(`${out} already exists (use --force to overwrite)`);\n writeFileSync(out, JSON.stringify(defaultConfig(), null, 2) + '\\n');\n console.log(`✓ wrote ${out}`);\n console.log(\n ` Edit it, then: vitops generate --input ${values.out} --format tailwind --out src/styles`,\n );\n console.log(` Editors read the \"$schema\" (${SCHEMA_URL}) for autocomplete + validation.`);\n}\n\nfunction cmdValidate(argv: string[]) {\n const { values, positionals } = parseArgs({\n args: argv,\n options: { input: { type: 'string', short: 'i' } },\n allowPositionals: true,\n });\n const path = resolve((positionals[0] ?? values.input ?? 'design-system.json') as string);\n if (!existsSync(path)) fail(`config not found: ${path}`);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf8'));\n } catch (err) {\n fail(`could not parse JSON: ${(err as Error).message}`);\n }\n const result = validate(raw);\n for (const w of result.warnings) console.warn(` ! ${w}`);\n if (result.ok) {\n console.log(`✓ ${path} is valid`);\n return;\n }\n console.error(`✖ ${path} is invalid:`);\n for (const e of result.errors) console.error(` • ${e.path.join('.') || '(root)'}: ${e.message}`);\n process.exit(1);\n}\n\nasync function cmdFavicon(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i' },\n out: { type: 'string', short: 'o', default: 'public' },\n 'low-res': { type: 'string' },\n },\n allowPositionals: false,\n });\n if (!values.input) fail('favicon: --input <svg|png> is required');\n const source = resolve(values.input as string);\n if (!existsSync(source)) fail(`source not found: ${source}`);\n try {\n const written = await generateFavicons({\n source,\n outputDir: values.out as string,\n ...(values['low-res'] ? { lowResSource: resolve(values['low-res'] as string) } : {}),\n });\n console.log(`✓ favicons → ${values.out} (${written.length} files)`);\n } catch (err) {\n fail((err as Error).message);\n }\n}\n\n// Read + parse + validate a design-system.json, or exit with a message.\nfunction loadConfig(path: string): DesignSystem {\n if (!existsSync(path)) fail(`config not found: ${path}`);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, 'utf8'));\n } catch (err) {\n fail(`could not parse JSON: ${(err as Error).message}`);\n }\n const result = validate(raw);\n if (!result.ok) {\n console.error(`✖ ${path} is invalid:`);\n for (const e of result.errors)\n console.error(` • ${e.path.join('.') || '(root)'}: ${e.message}`);\n process.exit(1);\n }\n // Warnings go to stderr, not stdout: `vitops docs <topic>` is designed to be\n // piped, so anything here must not land in the piped document. They used to\n // be dropped entirely on this path, which meant `docs` and `agents` stayed\n // silent about collisions that `generate` and `validate` both reported.\n for (const w of result.warnings) console.warn(` ! ${w}`);\n return result.data;\n}\n\n// This CLI's own version (dist/cli.mjs → package-root package.json).\nfunction cliVersion(): string {\n try {\n return (\n JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version ??\n '0.0.0'\n );\n } catch {\n return '0.0.0';\n }\n}\n\n// The framework asset root shipped inside @getvitops/generator (holds the Bricks\n// PHP that generateDocs reads for the element reference).\nfunction generatorAssetsDir(): string {\n const pkg = createRequire(import.meta.url).resolve('@getvitops/generator/package.json');\n return join(dirname(pkg), 'assets');\n}\n\nconst AGENTS_START = '<!-- vitops:start -->';\nconst AGENTS_END = '<!-- vitops:end -->';\n\n/** Print a live reference doc (rendered from the project's config) to stdout. */\nfunction cmdDocs(argv: string[]) {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n all: { type: 'boolean', default: false },\n },\n allowPositionals: true,\n });\n const topic = positionals[0];\n const topicList = () =>\n Object.entries(TOPICS)\n .map(([name, t]) => ` ${name.padEnd(10)} ${t.summary}`)\n .join('\\n');\n if (!topic && !values.all) {\n console.log(\n `vitops docs <topic> — print a live design-system reference to stdout\\n\\nTopics:\\n${topicList()}\\n\\nAlso: vitops docs --all (every topic, concatenated)`,\n );\n return;\n }\n if (topic && !TOPICS[topic]) fail(`unknown topic \"${topic}\". Valid topics:\\n${topicList()}`);\n const ds = loadConfig(resolve(values.input as string));\n const docs = generateDocs(ds, generatorAssetsDir());\n const paths = values.all\n ? Object.values(TOPICS).map((t) => t.path)\n : [TOPICS[topic as string]!.path];\n process.stdout.write(paths.map((p) => docs[p]).join('\\n'));\n}\n\nconst SCAN_EXT = new Set([\n '.astro',\n '.html',\n '.htm',\n '.js',\n '.jsx',\n '.ts',\n '.tsx',\n '.vue',\n '.svelte',\n '.php',\n '.md',\n '.mdx',\n]);\nconst SCAN_SKIP = new Set(['node_modules', 'dist', '.git', '.astro', 'build', 'coverage']);\n\nfunction scanFiles(dir: string, acc: { path: string; text: string }[] = []) {\n for (const e of readdirSync(dir, { withFileTypes: true })) {\n if (e.name.startsWith('.') && e.name !== '.') continue;\n const p = join(dir, e.name);\n if (e.isDirectory()) {\n if (!SCAN_SKIP.has(e.name)) scanFiles(p, acc);\n } else if (SCAN_EXT.has(extname(e.name))) {\n acc.push({ path: p, text: readFileSync(p, 'utf8') });\n }\n }\n return acc;\n}\n\nfunction cmdLint(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n format: { type: 'string', short: 'f', default: 'bricks' },\n src: { type: 'string', short: 's', default: 'src' },\n },\n allowPositionals: false,\n });\n const format = values.format as Format;\n if (!FORMATS.has(format)) fail(`unknown format \"${format}\" (expected: bricks | css | tailwind)`);\n const ds = loadConfig(resolve(values.input as string));\n const srcDir = resolve(values.src as string);\n if (!existsSync(srcDir)) fail(`source directory not found: ${srcDir}`);\n\n // Ask the generator what it actually emits rather than re-deriving the rules\n // here — a linter that models the vocabulary separately just drifts into\n // reporting classes that do exist.\n const roleClasses = roleColorUtilities(\n Object.entries(ds.colors.roles).map(([role, hue]) =>\n functionalRole(role, hue, expandPalette(ds.colors.palette)[hue]!),\n ),\n ds.colors.utilities ?? ['bg', 'text', 'border'],\n ).map((u) => u.cls);\n\n const files = scanFiles(srcDir);\n const findings = lintSource(files, vocabulary(ds, roleClasses), format);\n\n if (!findings.length) {\n console.log(\n `✓ no unresolvable framework classes in ${values.src} ` +\n `(${files.length} file${files.length === 1 ? '' : 's'} scanned)`,\n );\n return;\n }\n for (const f of findings) {\n console.error(`${f.file}:${f.line} ${f.cls}`);\n console.error(` ${f.reason}`);\n if (f.suggestion) console.error(` try: ${f.suggestion}`);\n }\n const n = findings.length;\n console.error(\n `\\n✖ ${n} unresolvable class${n === 1 ? '' : 'es'} in ` +\n `${files.length} file${files.length === 1 ? '' : 's'}`,\n );\n process.exit(1);\n}\n\nfunction cmdAgents(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'design-system.json' },\n out: { type: 'string', short: 'o', default: 'AGENTS.md' },\n 'docs-dir': { type: 'string' },\n },\n allowPositionals: false,\n });\n const inputRel = values.input as string;\n // The command is pure wiring: validate the config when present (fail on an\n // invalid one), but don't require it — docs are rendered live by `vitops docs`.\n let ds: DesignSystem | null = null;\n if (existsSync(resolve(inputRel))) ds = loadConfig(resolve(inputRel));\n else console.warn(` ⚠ ${inputRel} not found — run \\`vitops init\\` to scaffold one`);\n\n // Explicit --docs-dir = legacy layout: write the docs bundle as files, no skill.\n const legacyDocsDir = values['docs-dir'] as string | undefined;\n let summary: string;\n let pointer: string[];\n\n if (legacyDocsDir) {\n if (!ds) fail(`--docs-dir needs a config to render docs from (${inputRel} not found)`);\n let docs: Record<string, string> = {};\n try {\n docs = generateDocs(ds, generatorAssetsDir());\n } catch (err) {\n fail(`could not generate docs: ${(err as Error).message}`);\n }\n for (const [rel, content] of Object.entries(docs)) {\n const p = resolve(legacyDocsDir, rel);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, content);\n }\n summary = `wrote ${Object.keys(docs).length} docs to ${legacyDocsDir}/`;\n pointer = [\n 'Prefer the framework’s utility + component classes over hand-written CSS.',\n `Reference docs (regenerate with \\`vitops agents --docs-dir ${legacyDocsDir}\\`): \\`${legacyDocsDir}/css/classes.md\\`,`,\n `\\`${legacyDocsDir}/authoring.md\\`, \\`${legacyDocsDir}/formats.md\\`, \\`${legacyDocsDir}/bricks/elements.md\\`.`,\n ];\n } else {\n // Link the packaged skill (ships inside @getvitops/cli) into the agent\n // discovery locations; nothing is generated into the repo.\n const target = findSkillTarget(process.cwd());\n if (target) {\n for (const dir of ['.agents', '.claude']) {\n const warn = linkSkill(resolve(dir, 'skills', SKILL_NAME), target);\n if (warn) console.warn(` ⚠ ${warn}`);\n }\n summary = `linked {.agents,.claude}/skills/${SKILL_NAME} → ${target}`;\n } else {\n console.warn(\n ` ⚠ could not find node_modules/@getvitops/cli/skill — install @getvitops/cli as a devDependency, then re-run \\`vitops agents\\``,\n );\n summary = 'no skill linked';\n }\n pointer = [\n 'Prefer the framework’s utility + component classes over hand-written CSS.',\n `Full design-system context lives in the \\`${SKILL_NAME}\\` skill (linked from`,\n '`.agents/skills/` and `.claude/skills/` into the installed `@getvitops/cli`;',\n 're-link with `vitops agents` if the links are deleted — they survive version',\n 'bumps). Reference docs print live, from this project’s config, via:',\n '',\n ...Object.entries(TOPICS).map(([name, t]) => `- \\`vitops docs ${name}\\` — ${t.summary}`),\n ];\n }\n\n const block = [\n AGENTS_START,\n '## Vitops design system',\n '',\n `Styled with the Vitops design system (\\`@getvitops/*\\`); tokens live in \\`${inputRel}\\`.`,\n 'Generate output with the CLI:',\n '',\n '- `vitops generate --format tailwind --out src/styles` — Tailwind v4 / Astro',\n '- `vitops generate --format css --out dist` — standalone CSS',\n '- `vitops generate --format bricks --out <theme>/dist` — WordPress / Bricks',\n '- `vitops init` · `vitops validate` · `vitops favicon`',\n '',\n ...pointer,\n '',\n `<!-- regenerate: vitops agents · @getvitops/cli@${cliVersion()} -->`,\n AGENTS_END,\n ].join('\\n');\n\n const outPath = resolve(values.out as string);\n let next: string;\n let action: string;\n if (existsSync(outPath)) {\n const cur = readFileSync(outPath, 'utf8');\n const s = cur.indexOf(AGENTS_START);\n const e = cur.indexOf(AGENTS_END);\n if (s !== -1 && e !== -1 && e > s) {\n next = cur.slice(0, s) + block + cur.slice(e + AGENTS_END.length);\n action = 'updated block in';\n } else {\n next = cur.replace(/\\s*$/, '') + '\\n\\n' + block + '\\n';\n action = 'appended block to';\n }\n } else {\n mkdirSync(dirname(outPath), { recursive: true });\n next = block + '\\n';\n action = 'created';\n }\n writeFileSync(outPath, next);\n console.log(`✓ ${action} ${values.out} + ${summary}`);\n}\n\nasync function main() {\n const [command, ...rest] = process.argv.slice(2);\n if (!command || command === '-h' || command === '--help' || command === 'help') {\n console.log(HELP);\n return;\n }\n switch (command) {\n case 'generate':\n return cmdGenerate(rest);\n case 'init':\n return cmdInit(rest);\n case 'validate':\n return cmdValidate(rest);\n case 'favicon':\n return cmdFavicon(rest);\n case 'agents':\n return cmdAgents(rest);\n case 'docs':\n return cmdDocs(rest);\n case 'lint':\n return cmdLint(rest);\n default:\n fail(\n `unknown command \"${command}\" (expected: generate | init | validate | favicon | agents | docs | lint). Try: vitops --help`,\n );\n }\n}\n\nmain().catch((err) => fail((err as Error).message));\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getvitops/cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "CLI for the Vitops design-system generator: generate, init, and validate a design-system.json.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -22,8 +22,8 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@getvitops/generator": "0.8.0",
26
- "@getvitops/utils": "0.8.0"
25
+ "@getvitops/generator": "0.9.0",
26
+ "@getvitops/utils": "0.9.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "vitest": "^4.1.9"