@getvitops/cli 0.1.0 → 0.2.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/README.md +20 -0
- package/dist/cli.mjs +117 -4
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -22,6 +22,8 @@ npx vitops generate --format bricks,css --out dist
|
|
|
22
22
|
| `vitops init [--out design-system.json] [--force]` | write a starter config with `$schema` |
|
|
23
23
|
| `vitops validate <file>` | schema-check (non-zero exit on error) |
|
|
24
24
|
| `vitops generate -i <file> -f <formats> -o <dir>` | generate `bricks` / `css` / `tailwind` output |
|
|
25
|
+
| `vitops favicon -i <svg\|png> -o <dir>` | generate a favicon set from a source image |
|
|
26
|
+
| `vitops agents [-o AGENTS.md] [--docs-dir <dir>]` | teach AI agents about the design system |
|
|
25
27
|
|
|
26
28
|
## Using the output
|
|
27
29
|
|
|
@@ -77,4 +79,22 @@ The CLI only writes files — how they reach WordPress is up to you:
|
|
|
77
79
|
- **CI:** run `vitops generate --format bricks` in your pipeline and deploy the artifact the
|
|
78
80
|
same way you deploy the rest of the theme.
|
|
79
81
|
|
|
82
|
+
## Teaching AI agents (`vitops agents`)
|
|
83
|
+
|
|
84
|
+
So an AI coding agent in a consumer project can discover the design system, `vitops agents`
|
|
85
|
+
writes a small, marker-delimited **managed block** into your `AGENTS.md` (idempotent — re-run to
|
|
86
|
+
update) and emits the reference docs bundle it points at:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
vitops agents # updates ./AGENTS.md, docs → ./.vitops/docs
|
|
90
|
+
vitops agents --out CLAUDE.md --docs-dir docs/vitops --input design-system.json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The block lists the CLI commands and points at the generated class vocabulary
|
|
94
|
+
(`<docs-dir>/css/classes.md`) and Bricks element reference (`<docs-dir>/bricks/elements.md`), both
|
|
95
|
+
derived from your `design-system.json`. Re-running only replaces the content between the
|
|
96
|
+
`<!-- vitops:start -->` / `<!-- vitops:end -->` markers, leaving the rest of the file untouched. If
|
|
97
|
+
you'd rather not commit the generated docs, add your `--docs-dir` (e.g. `.vitops/`) to
|
|
98
|
+
`.gitignore` and run `vitops agents` in a postinstall/CI step.
|
|
99
|
+
|
|
80
100
|
Powered by [`@getvitops/generator`](https://www.npmjs.com/package/@getvitops/generator).
|
package/dist/cli.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import { parseArgs } from "node:util";
|
|
3
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { resolve } from "node:path";
|
|
5
|
-
import { SCHEMA_URL, defaultConfig, generate, validate } from "@getvitops/generator";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { SCHEMA_URL, defaultConfig, generate, generateDocs, validate } from "@getvitops/generator";
|
|
6
7
|
import { generateFavicons } from "@getvitops/utils";
|
|
7
8
|
|
|
8
9
|
//#region src/cli.ts
|
|
@@ -13,6 +14,7 @@ import { generateFavicons } from "@getvitops/utils";
|
|
|
13
14
|
* vitops init [--out design-system.json] [--force]
|
|
14
15
|
* vitops validate <design-system.json>
|
|
15
16
|
* vitops favicon --input <svg|png> --out <dir> [--low-res <svg|png>]
|
|
17
|
+
* vitops agents [--input <json>] [--out AGENTS.md] [--docs-dir <dir>]
|
|
16
18
|
*
|
|
17
19
|
* Thin wrapper over @getvitops/generator (generation) and @getvitops/utils (favicons).
|
|
18
20
|
* Every client brings their own consumer-editable design-system.json.
|
|
@@ -29,6 +31,7 @@ Usage:
|
|
|
29
31
|
vitops init [options] Scaffold a starter design-system.json
|
|
30
32
|
vitops validate <file> Validate a config against the schema
|
|
31
33
|
vitops favicon [options] Generate a favicon set from a source image
|
|
34
|
+
vitops agents [options] Write design-system docs into AGENTS.md (for AI agents)
|
|
32
35
|
|
|
33
36
|
Generate options:
|
|
34
37
|
-i, --input <path> Config file (default: ./design-system.json)
|
|
@@ -44,6 +47,11 @@ Favicon options:
|
|
|
44
47
|
-o, --out <dir> Output directory (default: ./public)
|
|
45
48
|
--low-res <path> Optional simplified source for the 16px icon
|
|
46
49
|
|
|
50
|
+
Agents options:
|
|
51
|
+
-i, --input <path> Config file (default: ./design-system.json)
|
|
52
|
+
-o, --out <path> Doc file to update, idempotently (default: ./AGENTS.md)
|
|
53
|
+
--docs-dir <dir> Where to write the reference docs bundle (default: ./.vitops/docs)
|
|
54
|
+
|
|
47
55
|
Common:
|
|
48
56
|
-h, --help Show this help
|
|
49
57
|
`;
|
|
@@ -168,6 +176,110 @@ async function cmdFavicon(argv) {
|
|
|
168
176
|
fail(err.message);
|
|
169
177
|
}
|
|
170
178
|
}
|
|
179
|
+
function loadConfig(path) {
|
|
180
|
+
if (!existsSync(path)) fail(`config not found: ${path}`);
|
|
181
|
+
let raw;
|
|
182
|
+
try {
|
|
183
|
+
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
184
|
+
} catch (err) {
|
|
185
|
+
fail(`could not parse JSON: ${err.message}`);
|
|
186
|
+
}
|
|
187
|
+
const result = validate(raw);
|
|
188
|
+
if (!result.ok) {
|
|
189
|
+
console.error(`✖ ${path} is invalid:`);
|
|
190
|
+
for (const e of result.errors) console.error(` • ${e.path.join(".") || "(root)"}: ${e.message}`);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
return result.data;
|
|
194
|
+
}
|
|
195
|
+
function cliVersion() {
|
|
196
|
+
try {
|
|
197
|
+
return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
|
|
198
|
+
} catch {
|
|
199
|
+
return "0.0.0";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function generatorAssetsDir() {
|
|
203
|
+
return join(dirname(createRequire(import.meta.url).resolve("@getvitops/generator/package.json")), "assets");
|
|
204
|
+
}
|
|
205
|
+
const AGENTS_START = "<!-- vitops:start -->";
|
|
206
|
+
const AGENTS_END = "<!-- vitops:end -->";
|
|
207
|
+
function cmdAgents(argv) {
|
|
208
|
+
const { values } = parseArgs({
|
|
209
|
+
args: argv,
|
|
210
|
+
options: {
|
|
211
|
+
input: {
|
|
212
|
+
type: "string",
|
|
213
|
+
short: "i",
|
|
214
|
+
default: "design-system.json"
|
|
215
|
+
},
|
|
216
|
+
out: {
|
|
217
|
+
type: "string",
|
|
218
|
+
short: "o",
|
|
219
|
+
default: "AGENTS.md"
|
|
220
|
+
},
|
|
221
|
+
"docs-dir": {
|
|
222
|
+
type: "string",
|
|
223
|
+
default: ".vitops/docs"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
allowPositionals: false
|
|
227
|
+
});
|
|
228
|
+
const inputRel = values.input;
|
|
229
|
+
const ds = loadConfig(resolve(inputRel));
|
|
230
|
+
const docsDir = values["docs-dir"];
|
|
231
|
+
let docs = {};
|
|
232
|
+
try {
|
|
233
|
+
docs = generateDocs(ds, generatorAssetsDir());
|
|
234
|
+
} catch (err) {
|
|
235
|
+
fail(`could not generate docs: ${err.message}`);
|
|
236
|
+
}
|
|
237
|
+
for (const [rel, content] of Object.entries(docs)) {
|
|
238
|
+
const p = resolve(docsDir, rel);
|
|
239
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
240
|
+
writeFileSync(p, content);
|
|
241
|
+
}
|
|
242
|
+
const block = [
|
|
243
|
+
AGENTS_START,
|
|
244
|
+
"## Vitops design system",
|
|
245
|
+
"",
|
|
246
|
+
`Styled with the Vitops design system (\`@getvitops/*\`); tokens live in \`${inputRel}\`.`,
|
|
247
|
+
"Generate output with the CLI:",
|
|
248
|
+
"",
|
|
249
|
+
"- `vitops generate --format tailwind --out src/styles` — Tailwind v4 / Astro",
|
|
250
|
+
"- `vitops generate --format css --out dist` — standalone CSS",
|
|
251
|
+
"- `vitops generate --format bricks --out <theme>/dist` — WordPress / Bricks",
|
|
252
|
+
"- `vitops init` · `vitops validate` · `vitops favicon`",
|
|
253
|
+
"",
|
|
254
|
+
"Prefer the framework’s utility + component classes over hand-written CSS.",
|
|
255
|
+
`Full class vocabulary + Bricks element reference: \`${docsDir}/css/classes.md\`,`,
|
|
256
|
+
`\`${docsDir}/bricks/elements.md\` (regenerate both with \`vitops agents\`).`,
|
|
257
|
+
"",
|
|
258
|
+
`<!-- regenerate: vitops agents · @getvitops/cli@${cliVersion()} -->`,
|
|
259
|
+
AGENTS_END
|
|
260
|
+
].join("\n");
|
|
261
|
+
const outPath = resolve(values.out);
|
|
262
|
+
let next;
|
|
263
|
+
let action;
|
|
264
|
+
if (existsSync(outPath)) {
|
|
265
|
+
const cur = readFileSync(outPath, "utf8");
|
|
266
|
+
const s = cur.indexOf(AGENTS_START);
|
|
267
|
+
const e = cur.indexOf(AGENTS_END);
|
|
268
|
+
if (s !== -1 && e !== -1 && e > s) {
|
|
269
|
+
next = cur.slice(0, s) + block + cur.slice(e + 19);
|
|
270
|
+
action = "updated block in";
|
|
271
|
+
} else {
|
|
272
|
+
next = cur.replace(/\s*$/, "") + "\n\n" + block + "\n";
|
|
273
|
+
action = "appended block to";
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
277
|
+
next = block + "\n";
|
|
278
|
+
action = "created";
|
|
279
|
+
}
|
|
280
|
+
writeFileSync(outPath, next);
|
|
281
|
+
console.log(`✓ ${action} ${values.out} + wrote ${Object.keys(docs).length} docs to ${docsDir}/`);
|
|
282
|
+
}
|
|
171
283
|
async function main() {
|
|
172
284
|
const [command, ...rest] = process.argv.slice(2);
|
|
173
285
|
if (!command || command === "-h" || command === "--help" || command === "help") {
|
|
@@ -179,7 +291,8 @@ async function main() {
|
|
|
179
291
|
case "init": return cmdInit(rest);
|
|
180
292
|
case "validate": return cmdValidate(rest);
|
|
181
293
|
case "favicon": return cmdFavicon(rest);
|
|
182
|
-
|
|
294
|
+
case "agents": return cmdAgents(rest);
|
|
295
|
+
default: fail(`unknown command "${command}" (expected: generate | init | validate | favicon | agents). Try: vitops --help`);
|
|
183
296
|
}
|
|
184
297
|
}
|
|
185
298
|
main().catch((err) => fail(err.message));
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/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 *\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 } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { generate, validate, defaultConfig, SCHEMA_URL, type Format } from '@getvitops/generator';\nimport { generateFavicons } from '@getvitops/utils';\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\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\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 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\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 default:\n fail(\n `unknown command \"${command}\" (expected: generate | init | validate). 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/cli.ts"],"sourcesContent":["#!/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 *\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';\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] Write design-system docs into AGENTS.md (for AI agents)\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)\n -o, --out <path> Doc file to update, idempotently (default: ./AGENTS.md)\n --docs-dir <dir> Where to write the reference docs bundle (default: ./.vitops/docs)\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 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\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', default: '.vitops/docs' },\n },\n allowPositionals: false,\n });\n const inputRel = values.input as string;\n const ds = loadConfig(resolve(inputRel));\n const docsDir = values['docs-dir'] as string;\n\n // Emit the OKF docs bundle so the AGENTS.md pointer resolves for every consumer\n // (only the `bricks` generate format writes docs/ otherwise).\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(docsDir, rel);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, content);\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 'Prefer the framework’s utility + component classes over hand-written CSS.',\n `Full class vocabulary + Bricks element reference: \\`${docsDir}/css/classes.md\\`,`,\n `\\`${docsDir}/bricks/elements.md\\` (regenerate both with \\`vitops agents\\`).`,\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} + wrote ${Object.keys(docs).length} docs to ${docsDir}/`);\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 default:\n fail(\n `unknown command \"${command}\" (expected: generate | init | validate | favicon | agents). 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.
|
|
3
|
+
"version": "0.2.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": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@getvitops/generator": "0.
|
|
24
|
-
"@getvitops/utils": "0.
|
|
23
|
+
"@getvitops/generator": "0.2.0",
|
|
24
|
+
"@getvitops/utils": "0.2.0"
|
|
25
25
|
}
|
|
26
26
|
}
|