@getvitops/cli 0.9.0 → 1.0.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 +226 -0
- package/README.md +23 -10
- package/dist/cli.mjs +185 -33
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
- package/skill/SKILL.md +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,231 @@
|
|
|
1
1
|
# @getvitops/cli
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bb92a14: **The colour system is rebuilt on a target-prefixed grammar and a shared lightness ladder.**
|
|
8
|
+
This is a breaking change to every colour token and utility class.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
Two axes shared one class namespace — functional _planes_ (`--<role>-bg-muted`) and
|
|
13
|
+
appearance-relative _stops_ (`--color-<role>-muted`) — arbitrated by a "plane wins" rule. The
|
|
14
|
+
result was not a scale. On the shipped palette, light mode:
|
|
15
|
+
|
|
16
|
+
| class | resolved to | step |
|
|
17
|
+
| ---------------------------------- | ------------ | --------------------------------------------- |
|
|
18
|
+
| `bg-ui-accent-x-muted` | stop | 100 |
|
|
19
|
+
| `bg-ui-accent-muted` | plane | 100 — identical, so `x-muted` was a dead rung |
|
|
20
|
+
| `bg-ui-accent` | plane | 50 — _lighter_ than both its "muted" rungs |
|
|
21
|
+
| `border-ui-accent-muted` / `-bold` | stop / plane | 300 / 300 — identical |
|
|
22
|
+
| `text-ui-accent-bold` | stop | 700 — _lighter_ than `text-…-muted` (800) |
|
|
23
|
+
|
|
24
|
+
Every family was non-monotonic, two had duplicate rungs, and `--color-<role>-muted` was
|
|
25
|
+
unreachable through any `bg-` class.
|
|
26
|
+
|
|
27
|
+
## The new grammar
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
--color-<target>-<role>[-<variant>] target ∈ bg | text | icon | border
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The target is **inside** the name, so `bg-danger-muted` and `text-danger-muted` are different
|
|
34
|
+
tokens and there is nothing left to arbitrate. **The class name is the token name minus
|
|
35
|
+
`--color-`** — one vocabulary instead of two.
|
|
36
|
+
|
|
37
|
+
Variants are ordinal (`xx-muted` < `x-muted` < `muted` < bare < `bold` < `x-bold`) and the
|
|
38
|
+
tables are sparse: only cells that hold their contrast target exist.
|
|
39
|
+
|
|
40
|
+
## Role kinds
|
|
41
|
+
|
|
42
|
+
`colors.roles` values may now be `{ hue, kind }` as well as a bare hue string:
|
|
43
|
+
|
|
44
|
+
```jsonc
|
|
45
|
+
"roles": {
|
|
46
|
+
"danger": "rust", // shorthand => chromatic
|
|
47
|
+
"surface": { "hue": "navy", "kind": "surface" }
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **`surface`** — a page/panel colour: `bg-<role>` is the card, `bg-<role>-muted` the page
|
|
52
|
+
behind it, `bg-<role>-x-muted` a well, `bg-<role>-bold` the inverse surface. Full text scale.
|
|
53
|
+
- **`chromatic`** (default) — a signal colour: tints (`bg-<role>-x-muted`/`-muted`) and solids
|
|
54
|
+
(`bg-<role>-solid[-bold|-x-bold]`), with **no bare `bg-<role>`** — say how loud you mean.
|
|
55
|
+
`text-on-<role>` is the guaranteed foreground for the solid family.
|
|
56
|
+
|
|
57
|
+
## Palette generation
|
|
58
|
+
|
|
59
|
+
Every ramp now sits on one **fixed lightness ladder** (50 → L 0.98 … 950 → L 0.21); only chroma
|
|
60
|
+
and hue vary. That is what makes a step mean the same lightness in every hue. Previously each
|
|
61
|
+
seed transposed the curve, so relative luminance at step 300 ranged from 0.253 to 0.384 across
|
|
62
|
+
the shipped palette — the same variant read differently depending on the role.
|
|
63
|
+
|
|
64
|
+
Authored colours are still reproduced **exactly**. A `seed`, an `anchors` entry or a `tones`
|
|
65
|
+
value is pinned verbatim at its nearest step; every other step takes the ladder. Snapping brand
|
|
66
|
+
colours to the ladder was measured and rejected: 11 of 18 real brand hexes moved beyond a
|
|
67
|
+
just-noticeable difference (worst ΔE-OK 0.050 — Facebook's `#1877F2` → `#0067e1`) and six left
|
|
68
|
+
sRGB gamut. Deviation is now bounded and local to pinned steps, and warns past ~0.03 L.
|
|
69
|
+
|
|
70
|
+
Two tones that claim the same step now **error** instead of one silently overwriting the other;
|
|
71
|
+
the record form (`tones: { "600": "…", "700": "…" }`) is how you resolve it.
|
|
72
|
+
|
|
73
|
+
## New
|
|
74
|
+
- **`icon-<role>`** — a non-text tier, so a glyph may run more vivid than text. `icon` is now a
|
|
75
|
+
default utility family alongside `bg`/`text`/`border`.
|
|
76
|
+
- **`--color-border-focus`** — the focus-ring tone, taken from `ui-primary`'s solid.
|
|
77
|
+
- **Contrast is enforced at build time**, not only in tests: text ≥ APCA Lc 75 on its primary
|
|
78
|
+
background, ≥ 60 on secondary planes, icons and surface boundaries ≥ 45, both appearances.
|
|
79
|
+
A violation now fails `generate`. Chromatic text is checked against the _surface_ planes it
|
|
80
|
+
actually sits on, not only its own tints. `text-<role>-x-muted` (placeholder) and `-xx-muted`
|
|
81
|
+
(disabled) are explicitly exempt; nothing else is.
|
|
82
|
+
|
|
83
|
+
## Migrating
|
|
84
|
+
|
|
85
|
+
Rename `--<role>-<suffix>` → `--color-<target>-<role>[-<variant>]`, and the same for classes:
|
|
86
|
+
|
|
87
|
+
| before | after |
|
|
88
|
+
| --------------------------------------- | ---------------------------------------------------------------- |
|
|
89
|
+
| `--<role>-bg` / `bg-<role>` (chromatic) | `--color-bg-<role>-x-muted` / `bg-<role>-x-muted` |
|
|
90
|
+
| `--<role>-bg-muted` | `--color-bg-<role>-muted` |
|
|
91
|
+
| `--<role>-solid` / `-solid-bold` | `--color-bg-<role>-solid` / `-solid-bold` |
|
|
92
|
+
| `--<role>-on-solid` / `text-on-<role>` | `--color-text-on-<role>` (class unchanged) |
|
|
93
|
+
| `--<role>-text` / `-text-muted` | `--color-text-<role>` / `-muted` |
|
|
94
|
+
| `--<role>-border` / `-border-bold` | `--color-border-<role>` / `-bold` |
|
|
95
|
+
| `--color-<role>-muted` (stop) | judge by use: `--color-bg-<role>-muted` or `--color-text-<role>` |
|
|
96
|
+
|
|
97
|
+
**`surface` background names rotate**, value-preserving: what was `--surface-bg` (the page) is
|
|
98
|
+
now `--color-bg-surface-muted`; what was `--surface-bg-bold` (raised) is now
|
|
99
|
+
`--color-bg-surface`. Elevation is expressed by which token you reach for — page `bg-muted`,
|
|
100
|
+
card `bg` — rather than a raised/sunken pair, which is what lets a future surfaces axis flatten
|
|
101
|
+
it without touching markup.
|
|
102
|
+
|
|
103
|
+
`vitops lint` reports role classes that no longer resolve, and now derives its suggestions from
|
|
104
|
+
what the generator actually emits rather than a hand-maintained list.
|
|
105
|
+
|
|
106
|
+
### Minor Changes
|
|
107
|
+
|
|
108
|
+
- bb92a14: Add a fourth output format, `design`, that emits `DESIGN.md` — the agent-facing brief in
|
|
109
|
+
[google-labs-code/design.md](https://github.com/google-labs-code/design.md) format.
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
vitops generate --format design --out . # DESIGN.md, and nothing else
|
|
113
|
+
vitops generate --format css,design # compose it with a stylesheet
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The file is YAML front matter carrying the tokens (`colors`, `typography`, `rounded`,
|
|
117
|
+
`spacing`, `components`, cross-referenced with `{group.token}`) followed by a prose body
|
|
118
|
+
carrying the rationale — colour model, fluid scales, layout vocabulary, elevation, shape
|
|
119
|
+
cascade, component tiers, do's and don'ts. Every section is rendered from your config, so
|
|
120
|
+
it cannot describe a system the other formats don't build. Point a coding agent, a Figma
|
|
121
|
+
import, or a designer at this one file when they don't have the toolchain; `vitops docs`
|
|
122
|
+
remains the richer reference for those who do.
|
|
123
|
+
|
|
124
|
+
It is emitted with `--out .` in mind: DESIGN.md conventionally lives at a repo root beside
|
|
125
|
+
`AGENTS.md`, not in a build directory.
|
|
126
|
+
|
|
127
|
+
Three things the spec cannot express, handled the same way every time and explained in the
|
|
128
|
+
emitted prose so the file is self-describing:
|
|
129
|
+
- **Fluid `clamp()` sizes** → the maximum (desktop) value, since a spec `Dimension` is a
|
|
130
|
+
bare number plus px/em/rem.
|
|
131
|
+
- **Dark mode** → light values only, with the automatic functional flip explained. Role
|
|
132
|
+
tokens are emitted as `{colors.<hue>-<step>}` references into the raw ramps rather than
|
|
133
|
+
flattened hexes, so the role → ramp lineage survives the export — flattening them is
|
|
134
|
+
exactly what breaks dark mode downstream.
|
|
135
|
+
- **A `50%` radius** → dropped from `rounded` (it is not a `Dimension`) and named in the
|
|
136
|
+
Shapes prose instead, so nothing is silently lost.
|
|
137
|
+
|
|
138
|
+
**New:** an optional `meta` key in `design-system.json` (`{ name, description }`) supplies
|
|
139
|
+
the brand name and the Overview paragraph. It affects no other format.
|
|
140
|
+
|
|
141
|
+
**New:** `StylesheetFormat` (`Exclude<Format, 'design'>`), exported from
|
|
142
|
+
`@getvitops/generator`. `@getvitops/astro`'s `css.format` now takes that narrower type —
|
|
143
|
+
`design` produces no stylesheet to inject, so passing it there is a type error rather than
|
|
144
|
+
a missing-file failure at build time. `vitops lint --format` is likewise restricted to the
|
|
145
|
+
three CSS formats. No change for anyone already passing `tailwind`, `css` or `bricks`.
|
|
146
|
+
|
|
147
|
+
- bb92a14: Generate legal documents from your site config
|
|
148
|
+
|
|
149
|
+
`vitops legal` renders a privacy policy, terms of service and cookie notice from a site
|
|
150
|
+
config, in markdown, HTML or EmDash Portable Text:
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
vitops legal --out ./content # every enabled document, as markdown
|
|
154
|
+
vitops legal --doc privacy --format html # one document, as an HTML fragment
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The documents are **derived from your config**, not filled into a form. The analytics
|
|
158
|
+
provider they name is the one whose ID you set; the personal information they list is what
|
|
159
|
+
your configured forms actually collect; the countries they name come from the providers you
|
|
160
|
+
use. So a provider swap updates the policy on the next build, and the fix for a wrong policy
|
|
161
|
+
is a corrected config — hand-editing the output is overwritten.
|
|
162
|
+
|
|
163
|
+
Enable documents under `legal`, which gains the facts the prose asserts:
|
|
164
|
+
|
|
165
|
+
```jsonc
|
|
166
|
+
{
|
|
167
|
+
"legal": {
|
|
168
|
+
"jurisdiction": "ca", // only 'ca' (PIPEDA) ships today
|
|
169
|
+
"privacyPolicy": {
|
|
170
|
+
"enabled": true,
|
|
171
|
+
"lastUpdated": "2026-08-01",
|
|
172
|
+
"retention": "24 months after our last contact with you",
|
|
173
|
+
// Third parties the config cannot imply. Analytics, Turnstile and your
|
|
174
|
+
// deploy platform are detected automatically — list only the rest.
|
|
175
|
+
"processors": [
|
|
176
|
+
{
|
|
177
|
+
"name": "Stripe",
|
|
178
|
+
"purpose": "payment processing",
|
|
179
|
+
"country": "the United States",
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
"termsOfService": { "enabled": true },
|
|
184
|
+
"cookieConsent": {
|
|
185
|
+
"enabled": true,
|
|
186
|
+
"type": "opt-in",
|
|
187
|
+
"categories": ["Essential", "Analytics"],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Delivery, by stack:
|
|
194
|
+
- **Any stack** — `vitops legal`. No integration code; prints to stdout without `--out`.
|
|
195
|
+
- **WordPress/Bricks** — `vitops generate --site <path>` also writes `dist/legal/*.html`, and
|
|
196
|
+
the theme loader now registers `[vitops_legal doc="privacy"]` to render one in a page. The
|
|
197
|
+
document updates on the next deploy with no action in WordPress.
|
|
198
|
+
- **Astro** — `getvitops({ legal: { input: 'site.json', out: 'src/content/legal' } })` writes
|
|
199
|
+
markdown into a content collection and re-renders when the site config changes. It needs a
|
|
200
|
+
`css` config (that is what registers the Vite plugin); without one, use the CLI.
|
|
201
|
+
- **EmDash** — `--format portable-text`, pasted into the admin.
|
|
202
|
+
|
|
203
|
+
Also new on the public API: `generateLegal()`, `renderMarkdown()`, `renderNodes()`,
|
|
204
|
+
`derivePolicyVars()`, `parseMarkdown()` / `toHtmlFragment()` / `toPortableText()`, and
|
|
205
|
+
`resolvePrivacyContact()`.
|
|
206
|
+
|
|
207
|
+
Two things to know before you publish anything this produces:
|
|
208
|
+
- **It is not legal advice.** Every document opens with a review banner saying so. The
|
|
209
|
+
bundled terms-of-service prose in particular is generic website boilerplate and
|
|
210
|
+
deliberately does not cover sales, refunds, subscriptions, accounts or user-generated
|
|
211
|
+
content — a site doing any of those needs clauses drafted for it.
|
|
212
|
+
- **It is only as true as your config.** A policy asserting things your site does not do is
|
|
213
|
+
worse than no policy. Check that the config describes reality before you ship the output.
|
|
214
|
+
|
|
215
|
+
`validateSite` now rejects a config that enables a privacy policy without a contact for
|
|
216
|
+
privacy requests or a `domains.canonical`, since both are interpolated into sentences that
|
|
217
|
+
would otherwise render blank.
|
|
218
|
+
|
|
219
|
+
### Patch Changes
|
|
220
|
+
|
|
221
|
+
- Updated dependencies [bb92a14]
|
|
222
|
+
- Updated dependencies [bb92a14]
|
|
223
|
+
- Updated dependencies [bb92a14]
|
|
224
|
+
- Updated dependencies [bb92a14]
|
|
225
|
+
- Updated dependencies [eeb059f]
|
|
226
|
+
- @getvitops/generator@1.0.0
|
|
227
|
+
- @getvitops/utils@1.0.0
|
|
228
|
+
|
|
3
229
|
## 0.9.0
|
|
4
230
|
|
|
5
231
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @getvitops/cli
|
|
2
2
|
|
|
3
|
-
CLI for the Vitops design-system generator. Turn a `design-system.json` into
|
|
4
|
-
|
|
3
|
+
CLI for the Vitops design-system generator. Turn a `design-system.json` into Tailwind v4,
|
|
4
|
+
Bricks, `DESIGN.md`, or standalone CSS output.
|
|
5
5
|
|
|
6
6
|
```sh
|
|
7
7
|
# scaffold a starter config (stamps a $schema for editor autocomplete)
|
|
@@ -17,14 +17,14 @@ npx vitops generate --format bricks,css --out dist
|
|
|
17
17
|
|
|
18
18
|
## Commands
|
|
19
19
|
|
|
20
|
-
| command | does
|
|
21
|
-
| -------------------------------------------------- |
|
|
22
|
-
| `vitops init [--out design-system.json] [--force]` | write a starter config with `$schema`
|
|
23
|
-
| `vitops validate <file>` | schema-check (non-zero exit on error)
|
|
24
|
-
| `vitops generate -i <file> -f <formats> -o <dir>` |
|
|
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>]` | link the agent skill + AGENTS.md pointer
|
|
27
|
-
| `vitops docs [topic] [--all]` | print live reference docs to stdout
|
|
20
|
+
| command | does |
|
|
21
|
+
| -------------------------------------------------- | ----------------------------------------------- |
|
|
22
|
+
| `vitops init [--out design-system.json] [--force]` | write a starter config with `$schema` |
|
|
23
|
+
| `vitops validate <file>` | schema-check (non-zero exit on error) |
|
|
24
|
+
| `vitops generate -i <file> -f <formats> -o <dir>` | `tailwind` / `bricks` / `design` / `css` 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>]` | link the agent skill + AGENTS.md pointer |
|
|
27
|
+
| `vitops docs [topic] [--all]` | print live reference docs to stdout |
|
|
28
28
|
|
|
29
29
|
## Using the output
|
|
30
30
|
|
|
@@ -80,6 +80,19 @@ The CLI only writes files — how they reach WordPress is up to you:
|
|
|
80
80
|
- **CI:** run `vitops generate --format bricks` in your pipeline and deploy the artifact the
|
|
81
81
|
same way you deploy the rest of the theme.
|
|
82
82
|
|
|
83
|
+
**Agent brief (`DESIGN.md`).** `--format design` emits a single `DESIGN.md` and **no CSS** — the
|
|
84
|
+
portable brief in [design.md](https://github.com/google-labs-code/design.md) format (YAML token
|
|
85
|
+
front matter, then prose) for a coding agent or design tool that doesn't have the toolchain
|
|
86
|
+
installed. It conventionally lives at the repo root beside `AGENTS.md`:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
vitops generate --input design-system.json --format design --out .
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`--format` is comma-separated, but a run shares one `--out` — so keep the brief its own invocation
|
|
93
|
+
whenever your stylesheet goes somewhere other than the repo root. Regenerate it with your CSS; it's
|
|
94
|
+
derived from the same config, so it can't drift from what the browser gets.
|
|
95
|
+
|
|
83
96
|
## Teaching AI agents (`vitops agents` + `vitops docs`)
|
|
84
97
|
|
|
85
98
|
This package **ships an agent skill** (`skill/SKILL.md`, the [Agent Skills](https://code.claude.com/docs/en/skills)
|
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,8 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, extname, join, parse, relative, resolve } from "node:path";
|
|
6
|
-
import {
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { NUMERIC_STEPS, SCHEMA_URL, defaultConfig, enabledDocs, expandPalette, functionalRole, generate, generateDocs, generateLegal, resolveSiteConfig, roleColorUtilities, roleHue, roleKind, validate } from "@getvitops/generator";
|
|
7
8
|
import { generateFavicons } from "@getvitops/utils";
|
|
8
9
|
|
|
9
10
|
//#region src/agents.ts
|
|
@@ -96,41 +97,57 @@ function linkSkill(linkPath, targetDir) {
|
|
|
96
97
|
|
|
97
98
|
//#endregion
|
|
98
99
|
//#region src/lint.ts
|
|
100
|
+
/**
|
|
101
|
+
* `vitops lint` — find framework classes in consumer source that resolve to
|
|
102
|
+
* nothing in the format being built.
|
|
103
|
+
*
|
|
104
|
+
* The problem this exists for: an unknown utility class is indistinguishable
|
|
105
|
+
* from a working one. Nothing errors, nothing warns, the element just doesn't
|
|
106
|
+
* get the style. Two shapes of that were found in a real consumer site:
|
|
107
|
+
*
|
|
108
|
+
* • `bg-navy-d` — a leftover from the named-step scale (`d`/`xd`/`xxd`)
|
|
109
|
+
* deleted in favour of numeric steps. The hue is real, the step is not.
|
|
110
|
+
* It appeared ~10× and looked fine only because the `.card` it sat on
|
|
111
|
+
* supplied its own background.
|
|
112
|
+
* • `md-flex-row` — the css/bricks spelling of a responsive variant, used in
|
|
113
|
+
* a `tailwind`-format project where that class is never emitted (Tailwind
|
|
114
|
+
* regenerates those on demand as `@md:`). Silently inert.
|
|
115
|
+
*
|
|
116
|
+
* DESIGN: this deliberately only inspects classes ANCHORED TO THE CONSUMER'S
|
|
117
|
+
* OWN CONFIG — a hue name, a role name, a type role, a shadow, a pattern. It
|
|
118
|
+
* never tries to enumerate "all valid classes", because in the tailwind format
|
|
119
|
+
* that would mean knowing Tailwind's entire built-in vocabulary, and every
|
|
120
|
+
* unknown would be a false positive. Anchoring means a finding is always
|
|
121
|
+
* actionable: you named something from your design system, and it doesn't
|
|
122
|
+
* resolve.
|
|
123
|
+
*/
|
|
99
124
|
const UTIL_FAMILIES = [
|
|
100
125
|
"bg",
|
|
101
126
|
"text",
|
|
127
|
+
"icon",
|
|
102
128
|
"border",
|
|
103
129
|
"outline",
|
|
104
130
|
"fill",
|
|
105
131
|
"stroke"
|
|
106
132
|
];
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
133
|
+
/**
|
|
134
|
+
* The modifiers actually emitted for one family + role, read back out of the
|
|
135
|
+
* generator's own class list.
|
|
136
|
+
*
|
|
137
|
+
* This used to be a hand-maintained array, which is the wrong shape for a
|
|
138
|
+
* suggestion: the two role kinds emit different modifiers (a chromatic role has
|
|
139
|
+
* `solid` and no bare form; a surface role the reverse), so a single list was
|
|
140
|
+
* wrong for one of them no matter what it said.
|
|
141
|
+
*/
|
|
142
|
+
const emittedModifiers = (roleClasses, fam, role) => {
|
|
143
|
+
const prefix = `${fam}-${role}`;
|
|
144
|
+
return [...roleClasses].filter((c) => c === prefix || c.startsWith(`${prefix}-`)).map((c) => c.slice(prefix.length + 1)).filter(Boolean).sort();
|
|
145
|
+
};
|
|
117
146
|
function vocabulary(ds, roleClasses) {
|
|
118
147
|
return {
|
|
119
148
|
roles: Object.keys(ds.colors?.roles ?? {}),
|
|
120
149
|
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
|
-
],
|
|
150
|
+
steps: [...NUMERIC_STEPS],
|
|
134
151
|
typeRoles: Object.keys(ds.typography?.roles ?? {}),
|
|
135
152
|
shadows: Object.keys(ds.shadows ?? {}),
|
|
136
153
|
patterns: Object.keys(ds.patterns?.items ?? {}),
|
|
@@ -166,10 +183,11 @@ function judge(raw, v, format) {
|
|
|
166
183
|
const role = prefix(v.roles);
|
|
167
184
|
if (role && (!hue || role.length > hue.length)) {
|
|
168
185
|
const mod = rest.slice(role.length + 1);
|
|
186
|
+
const valid = emittedModifiers(v.roleClasses, fam, role);
|
|
169
187
|
return {
|
|
170
188
|
cls: raw,
|
|
171
189
|
reason: `\`${fam}-${role}${mod ? `-${mod}` : ""}\` is not emitted for the \`${role}\` role`,
|
|
172
|
-
suggestion: `valid modifiers: ${
|
|
190
|
+
suggestion: valid.length ? `valid modifiers: ${valid.join(", ")}` : `the \`${role}\` role emits no \`${fam}-*\` utilities`
|
|
173
191
|
};
|
|
174
192
|
}
|
|
175
193
|
if (hue) {
|
|
@@ -242,22 +260,39 @@ function lintSource(files, v, format) {
|
|
|
242
260
|
/**
|
|
243
261
|
* `vitops` — CLI for the Vitops design-system generator.
|
|
244
262
|
*
|
|
245
|
-
* vitops generate --input <json> --format <bricks|css|tailwind[,…]> --out <dir>
|
|
263
|
+
* vitops generate --input <json> --format <bricks|css|tailwind|design[,…]> --out <dir>
|
|
246
264
|
* vitops init [--out design-system.json] [--force]
|
|
247
265
|
* vitops validate <design-system.json>
|
|
248
266
|
* vitops favicon --input <svg|png> --out <dir> [--low-res <svg|png>]
|
|
249
267
|
* vitops agents [--input <json>] [--out AGENTS.md] [--docs-dir <dir>]
|
|
250
268
|
* vitops docs [topic] [--input <json>] [--all]
|
|
251
269
|
* vitops lint [--input <json>] [--format <fmt>] [--src <dir>]
|
|
270
|
+
* vitops legal [--input <site.json>] [--doc <name>] [--format <md|html|portable-text>] [--out <dir>]
|
|
252
271
|
*
|
|
253
272
|
* Thin wrapper over @getvitops/generator (generation) and @getvitops/utils (favicons).
|
|
254
273
|
* Every client brings their own consumer-editable design-system.json.
|
|
255
274
|
*/
|
|
256
275
|
const FORMATS = new Set([
|
|
276
|
+
"bricks",
|
|
277
|
+
"css",
|
|
278
|
+
"tailwind",
|
|
279
|
+
"design"
|
|
280
|
+
]);
|
|
281
|
+
const LINT_FORMATS = new Set([
|
|
257
282
|
"bricks",
|
|
258
283
|
"css",
|
|
259
284
|
"tailwind"
|
|
260
285
|
]);
|
|
286
|
+
const LEGAL_DOCS = new Set([
|
|
287
|
+
"privacy",
|
|
288
|
+
"terms",
|
|
289
|
+
"cookies"
|
|
290
|
+
]);
|
|
291
|
+
const LEGAL_OUTPUTS = new Set([
|
|
292
|
+
"md",
|
|
293
|
+
"html",
|
|
294
|
+
"portable-text"
|
|
295
|
+
]);
|
|
261
296
|
const HELP = `vitops — generate design-system outputs from a design-system.json
|
|
262
297
|
|
|
263
298
|
Usage:
|
|
@@ -268,11 +303,17 @@ Usage:
|
|
|
268
303
|
vitops agents [options] Link the design-system agent skill + AGENTS.md pointer
|
|
269
304
|
vitops docs [topic] Print live design-system reference docs to stdout
|
|
270
305
|
vitops lint [options] Report framework classes in your source that resolve to nothing
|
|
306
|
+
vitops legal [options] Render legal documents from a site config
|
|
271
307
|
|
|
272
308
|
Generate options:
|
|
273
309
|
-i, --input <path> Config file (default: ./design-system.json)
|
|
274
|
-
-f, --format <list> bricks | css | tailwind (comma-separated; default: bricks)
|
|
310
|
+
-f, --format <list> bricks | css | tailwind | design (comma-separated; default: bricks)
|
|
311
|
+
design emits DESIGN.md only (the agent-facing brief) — pair it
|
|
312
|
+
with --out . to write it beside AGENTS.md, or compose:
|
|
313
|
+
--format css,design
|
|
275
314
|
-o, --out <dir> Output directory (default: ./dist)
|
|
315
|
+
--site <path> Site config; also emits legal/*.html into the output
|
|
316
|
+
directory (see: vitops legal). Omitted: no legal files.
|
|
276
317
|
|
|
277
318
|
Init options:
|
|
278
319
|
-o, --out <path> Where to write (default: ./design-system.json)
|
|
@@ -301,6 +342,20 @@ Lint options:
|
|
|
301
342
|
Responsive md-* classes are real in css/bricks, inert in tailwind.
|
|
302
343
|
-s, --src <dir> Directory to scan (default: ./src)
|
|
303
344
|
|
|
345
|
+
Legal options:
|
|
346
|
+
-i, --input <path> Site config: .json, or a .js/.ts module with a default
|
|
347
|
+
export (default: ./site.json)
|
|
348
|
+
-d, --doc <name> privacy | terms | cookies (repeatable; default: those
|
|
349
|
+
enabled in the config)
|
|
350
|
+
-f, --format <fmt> md | html | portable-text (default: md)
|
|
351
|
+
html suits WordPress/Bricks and plain sites;
|
|
352
|
+
portable-text suits EmDash
|
|
353
|
+
-o, --out <dir> Write files here (default: print to stdout)
|
|
354
|
+
--site-env <env> Environment whose A/B variant applies (default: production)
|
|
355
|
+
|
|
356
|
+
Generated from your config — a starting point, not legal advice. Review before
|
|
357
|
+
publishing, and make sure the config describes what your site actually does.
|
|
358
|
+
|
|
304
359
|
Common:
|
|
305
360
|
-h, --help Show this help
|
|
306
361
|
`;
|
|
@@ -326,19 +381,23 @@ async function cmdGenerate(argv) {
|
|
|
326
381
|
type: "string",
|
|
327
382
|
short: "o",
|
|
328
383
|
default: "dist"
|
|
329
|
-
}
|
|
384
|
+
},
|
|
385
|
+
site: { type: "string" }
|
|
330
386
|
},
|
|
331
387
|
allowPositionals: false
|
|
332
388
|
});
|
|
333
389
|
const input = resolve(values.input);
|
|
334
390
|
if (!existsSync(input)) fail(`config not found: ${input}`);
|
|
391
|
+
const site = values.site ? resolve(values.site) : void 0;
|
|
392
|
+
if (site && !existsSync(site)) fail(`site config not found: ${site}`);
|
|
335
393
|
const formats = values.format.split(",").map((f) => f.trim()).filter(Boolean);
|
|
336
|
-
for (const f of formats) if (!FORMATS.has(f)) fail(`unknown format "${f}" (expected: bricks | css | tailwind)`);
|
|
394
|
+
for (const f of formats) if (!FORMATS.has(f)) fail(`unknown format "${f}" (expected: bricks | css | tailwind | design)`);
|
|
337
395
|
for (const format of formats) try {
|
|
338
396
|
const res = await generate({
|
|
339
397
|
input,
|
|
340
398
|
format,
|
|
341
|
-
outDir: values.out
|
|
399
|
+
outDir: values.out,
|
|
400
|
+
...site ? { site } : {}
|
|
342
401
|
});
|
|
343
402
|
console.log(`✓ ${format} → ${res.outDir} (${res.written.length} paths)`);
|
|
344
403
|
} catch (err) {
|
|
@@ -443,6 +502,95 @@ function loadConfig(path) {
|
|
|
443
502
|
for (const w of result.warnings) console.warn(` ! ${w}`);
|
|
444
503
|
return result.data;
|
|
445
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Read + resolve a site config, or exit with a message.
|
|
507
|
+
*
|
|
508
|
+
* Accepts JSON, or a JS/TS module with a default export — deliberately not YAML,
|
|
509
|
+
* which would mean a parser dependency for one command. `resolveSiteConfig` is
|
|
510
|
+
* documented as taking an already-parsed object precisely so the loader is the
|
|
511
|
+
* consumer's choice; anyone on YAML can convert it or export from a module.
|
|
512
|
+
*/
|
|
513
|
+
async function loadSiteConfig(path, siteEnv) {
|
|
514
|
+
if (!existsSync(path)) fail(`site config not found: ${path}`);
|
|
515
|
+
let raw;
|
|
516
|
+
if (/\.(json)$/.test(path)) try {
|
|
517
|
+
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
518
|
+
} catch (err) {
|
|
519
|
+
fail(`could not parse JSON: ${err.message}`);
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
try {
|
|
523
|
+
raw = (await import(pathToFileURL(path).href)).default;
|
|
524
|
+
} catch (err) {
|
|
525
|
+
fail(`could not import ${path}: ${err.message}`);
|
|
526
|
+
}
|
|
527
|
+
if (raw == null) fail(`${path} has no default export`);
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
return resolveSiteConfig(raw, siteEnv);
|
|
531
|
+
} catch (err) {
|
|
532
|
+
fail(err.message);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Render the site's legal documents.
|
|
537
|
+
*
|
|
538
|
+
* The universal delivery path: every consumer has this CLI regardless of stack,
|
|
539
|
+
* so a WordPress theme, an Eleventy build or a hand-written HTML site all get
|
|
540
|
+
* the same documents without any integration code. Prints to stdout like
|
|
541
|
+
* `vitops docs`, or writes files when given `--out`.
|
|
542
|
+
*/
|
|
543
|
+
async function cmdLegal(argv) {
|
|
544
|
+
const { values } = parseArgs({
|
|
545
|
+
args: argv,
|
|
546
|
+
options: {
|
|
547
|
+
input: {
|
|
548
|
+
type: "string",
|
|
549
|
+
short: "i",
|
|
550
|
+
default: "site.json"
|
|
551
|
+
},
|
|
552
|
+
doc: {
|
|
553
|
+
type: "string",
|
|
554
|
+
short: "d",
|
|
555
|
+
multiple: true
|
|
556
|
+
},
|
|
557
|
+
format: {
|
|
558
|
+
type: "string",
|
|
559
|
+
short: "f",
|
|
560
|
+
default: "md"
|
|
561
|
+
},
|
|
562
|
+
out: {
|
|
563
|
+
type: "string",
|
|
564
|
+
short: "o"
|
|
565
|
+
},
|
|
566
|
+
"site-env": {
|
|
567
|
+
type: "string",
|
|
568
|
+
default: "production"
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
allowPositionals: false
|
|
572
|
+
});
|
|
573
|
+
const output = values.format;
|
|
574
|
+
if (!LEGAL_OUTPUTS.has(output)) fail(`unknown format "${output}" (expected: ${[...LEGAL_OUTPUTS].join(" | ")})`);
|
|
575
|
+
const requested = values.doc ?? [];
|
|
576
|
+
for (const d of requested) if (!LEGAL_DOCS.has(d)) fail(`unknown doc "${d}" (expected: ${[...LEGAL_DOCS].join(" | ")})`);
|
|
577
|
+
const site = await loadSiteConfig(resolve(values.input), values["site-env"]);
|
|
578
|
+
const docs = requested.length ? requested : enabledDocs(site);
|
|
579
|
+
if (docs.length === 0) fail("no legal documents are enabled — set legal.privacyPolicy.enabled (or termsOfService / cookieConsent) in your site config, or name one with --doc");
|
|
580
|
+
const files = generateLegal(site, {
|
|
581
|
+
docs,
|
|
582
|
+
output
|
|
583
|
+
});
|
|
584
|
+
if (!values.out) {
|
|
585
|
+
process.stdout.write(Object.values(files).join("\n"));
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const outDir = resolve(values.out);
|
|
589
|
+
mkdirSync(outDir, { recursive: true });
|
|
590
|
+
for (const [name, content] of Object.entries(files)) writeFileSync(join(outDir, name), content);
|
|
591
|
+
console.log(`✓ legal → ${outDir} (${Object.keys(files).length} files)`);
|
|
592
|
+
console.log(" These are generated from your config and are not legal advice — review them before publishing.");
|
|
593
|
+
}
|
|
446
594
|
function cliVersion() {
|
|
447
595
|
try {
|
|
448
596
|
return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
|
|
@@ -541,13 +689,15 @@ function cmdLint(argv) {
|
|
|
541
689
|
allowPositionals: false
|
|
542
690
|
});
|
|
543
691
|
const format = values.format;
|
|
544
|
-
if (!
|
|
692
|
+
if (!LINT_FORMATS.has(format)) fail(`unknown format "${format}" (expected: bricks | css | tailwind)`);
|
|
545
693
|
const ds = loadConfig(resolve(values.input));
|
|
546
694
|
const srcDir = resolve(values.src);
|
|
547
695
|
if (!existsSync(srcDir)) fail(`source directory not found: ${srcDir}`);
|
|
548
|
-
const
|
|
696
|
+
const palette = expandPalette(ds.colors.palette);
|
|
697
|
+
const roleClasses = roleColorUtilities(Object.entries(ds.colors.roles).map(([role, spec]) => functionalRole(role, roleHue(spec), palette[roleHue(spec)], roleKind(spec))), ds.colors.utilities ?? [
|
|
549
698
|
"bg",
|
|
550
699
|
"text",
|
|
700
|
+
"icon",
|
|
551
701
|
"border"
|
|
552
702
|
]).map((u) => u.cls);
|
|
553
703
|
const files = scanFiles(srcDir);
|
|
@@ -641,6 +791,7 @@ function cmdAgents(argv) {
|
|
|
641
791
|
"- `vitops generate --format tailwind --out src/styles` — Tailwind v4 / Astro",
|
|
642
792
|
"- `vitops generate --format css --out dist` — standalone CSS",
|
|
643
793
|
"- `vitops generate --format bricks --out <theme>/dist` — WordPress / Bricks",
|
|
794
|
+
"- `vitops generate --format design --out .` — `DESIGN.md`, the agent-facing brief",
|
|
644
795
|
"- `vitops init` · `vitops validate` · `vitops favicon`",
|
|
645
796
|
"",
|
|
646
797
|
...pointer,
|
|
@@ -684,7 +835,8 @@ async function main() {
|
|
|
684
835
|
case "agents": return cmdAgents(rest);
|
|
685
836
|
case "docs": return cmdDocs(rest);
|
|
686
837
|
case "lint": return cmdLint(rest);
|
|
687
|
-
|
|
838
|
+
case "legal": return cmdLegal(rest);
|
|
839
|
+
default: fail(`unknown command "${command}" (expected: generate | init | validate | favicon | agents | docs | lint | legal). Try: vitops --help`);
|
|
688
840
|
}
|
|
689
841
|
}
|
|
690
842
|
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/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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"}
|
|
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 { NUMERIC_STEPS, type DesignSystem, type 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', 'icon', 'border', 'outline', 'fill', 'stroke'];\nconst BREAKPOINTS = ['sm', 'md', 'lg', 'xl'];\n\n/**\n * The modifiers actually emitted for one family + role, read back out of the\n * generator's own class list.\n *\n * This used to be a hand-maintained array, which is the wrong shape for a\n * suggestion: the two role kinds emit different modifiers (a chromatic role has\n * `solid` and no bare form; a surface role the reverse), so a single list was\n * wrong for one of them no matter what it said.\n */\nconst emittedModifiers = (roleClasses: Set<string>, fam: string, role: string): string[] => {\n const prefix = `${fam}-${role}`;\n return [...roleClasses]\n .filter((c) => c === prefix || c.startsWith(`${prefix}-`))\n .map((c) => c.slice(prefix.length + 1))\n .filter(Boolean)\n .sort();\n};\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: [...NUMERIC_STEPS],\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 const valid = emittedModifiers(v.roleClasses, fam as string, role as string);\n return {\n cls: raw,\n reason: `\\`${fam}-${role}${mod ? `-${mod}` : ''}\\` is not emitted for the \\`${role}\\` role`,\n suggestion: valid.length\n ? `valid modifiers: ${valid.join(', ')}`\n : `the \\`${role}\\` role emits no \\`${fam}-*\\` utilities`,\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|design[,…]> --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 * vitops legal [--input <site.json>] [--doc <name>] [--format <md|html|portable-text>] [--out <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 { pathToFileURL } from 'node:url';\nimport {\n generate,\n validate,\n defaultConfig,\n generateDocs,\n generateLegal,\n enabledDocs,\n resolveSiteConfig,\n roleColorUtilities,\n functionalRole,\n expandPalette,\n roleHue,\n roleKind,\n SCHEMA_URL,\n type Format,\n type StylesheetFormat,\n type DesignSystem,\n type LegalDoc,\n type LegalOutput,\n type SiteConfig,\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', 'design']);\n// `lint` judges class names against what a build emits, and the `design` format\n// emits no CSS at all — so it is a valid target for `generate` and a category\n// error for `lint`.\nconst LINT_FORMATS = new Set<StylesheetFormat>(['bricks', 'css', 'tailwind']);\n\n// `legal` reads a *site* config, not a design-system.json, and has its own\n// output set — it renders documents, not stylesheets.\nconst LEGAL_DOCS = new Set<LegalDoc>(['privacy', 'terms', 'cookies']);\nconst LEGAL_OUTPUTS = new Set<LegalOutput>(['md', 'html', 'portable-text']);\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 vitops legal [options] Render legal documents from a site config\n\nGenerate options:\n -i, --input <path> Config file (default: ./design-system.json)\n -f, --format <list> bricks | css | tailwind | design (comma-separated; default: bricks)\n design emits DESIGN.md only (the agent-facing brief) — pair it\n with --out . to write it beside AGENTS.md, or compose:\n --format css,design\n -o, --out <dir> Output directory (default: ./dist)\n --site <path> Site config; also emits legal/*.html into the output\n directory (see: vitops legal). Omitted: no legal files.\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\nLegal options:\n -i, --input <path> Site config: .json, or a .js/.ts module with a default\n export (default: ./site.json)\n -d, --doc <name> privacy | terms | cookies (repeatable; default: those\n enabled in the config)\n -f, --format <fmt> md | html | portable-text (default: md)\n html suits WordPress/Bricks and plain sites;\n portable-text suits EmDash\n -o, --out <dir> Write files here (default: print to stdout)\n --site-env <env> Environment whose A/B variant applies (default: production)\n\n Generated from your config — a starting point, not legal advice. Review before\n publishing, and make sure the config describes what your site actually does.\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 site: { type: 'string' },\n },\n allowPositionals: false,\n });\n const input = resolve(values.input as string);\n if (!existsSync(input)) fail(`config not found: ${input}`);\n const site = values.site ? resolve(values.site as string) : undefined;\n if (site && !existsSync(site)) fail(`site config not found: ${site}`);\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 | design)`);\n\n for (const format of formats as Format[]) {\n try {\n const res = await generate({\n input,\n format,\n outDir: values.out as string,\n ...(site ? { site } : {}),\n });\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/**\n * Read + resolve a site config, or exit with a message.\n *\n * Accepts JSON, or a JS/TS module with a default export — deliberately not YAML,\n * which would mean a parser dependency for one command. `resolveSiteConfig` is\n * documented as taking an already-parsed object precisely so the loader is the\n * consumer's choice; anyone on YAML can convert it or export from a module.\n */\nasync function loadSiteConfig(path: string, siteEnv: string): Promise<SiteConfig> {\n if (!existsSync(path)) fail(`site config not found: ${path}`);\n let raw: unknown;\n if (/\\.(json)$/.test(path)) {\n try {\n raw = JSON.parse(readFileSync(path, 'utf8'));\n } catch (err) {\n fail(`could not parse JSON: ${(err as Error).message}`);\n }\n } else {\n try {\n raw = (await import(pathToFileURL(path).href)).default;\n } catch (err) {\n fail(`could not import ${path}: ${(err as Error).message}`);\n }\n if (raw == null) fail(`${path} has no default export`);\n }\n try {\n return resolveSiteConfig(raw, siteEnv);\n } catch (err) {\n // resolveSiteConfig already formats one issue per line.\n fail((err as Error).message);\n }\n}\n\n/**\n * Render the site's legal documents.\n *\n * The universal delivery path: every consumer has this CLI regardless of stack,\n * so a WordPress theme, an Eleventy build or a hand-written HTML site all get\n * the same documents without any integration code. Prints to stdout like\n * `vitops docs`, or writes files when given `--out`.\n */\nasync function cmdLegal(argv: string[]) {\n const { values } = parseArgs({\n args: argv,\n options: {\n input: { type: 'string', short: 'i', default: 'site.json' },\n doc: { type: 'string', short: 'd', multiple: true },\n format: { type: 'string', short: 'f', default: 'md' },\n out: { type: 'string', short: 'o' },\n 'site-env': { type: 'string', default: 'production' },\n },\n allowPositionals: false,\n });\n\n const output = values.format as LegalOutput;\n if (!LEGAL_OUTPUTS.has(output))\n fail(`unknown format \"${output}\" (expected: ${[...LEGAL_OUTPUTS].join(' | ')})`);\n\n const requested = (values.doc ?? []) as string[];\n for (const d of requested)\n if (!LEGAL_DOCS.has(d as LegalDoc))\n fail(`unknown doc \"${d}\" (expected: ${[...LEGAL_DOCS].join(' | ')})`);\n\n const site = await loadSiteConfig(resolve(values.input as string), values['site-env'] as string);\n const docs = requested.length ? (requested as LegalDoc[]) : enabledDocs(site);\n if (docs.length === 0)\n fail(\n 'no legal documents are enabled — set legal.privacyPolicy.enabled (or termsOfService / cookieConsent) in your site config, or name one with --doc',\n );\n\n const files = generateLegal(site, { docs, output });\n\n if (!values.out) {\n process.stdout.write(Object.values(files).join('\\n'));\n return;\n }\n const outDir = resolve(values.out as string);\n mkdirSync(outDir, { recursive: true });\n for (const [name, content] of Object.entries(files)) writeFileSync(join(outDir, name), content);\n console.log(`✓ legal → ${outDir} (${Object.keys(files).length} files)`);\n console.log(\n ' These are generated from your config and are not legal advice — review them before publishing.',\n );\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 StylesheetFormat;\n if (!LINT_FORMATS.has(format))\n 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 palette = expandPalette(ds.colors.palette);\n const roleClasses = roleColorUtilities(\n Object.entries(ds.colors.roles).map(([role, spec]) =>\n functionalRole(role, roleHue(spec), palette[roleHue(spec)]!, roleKind(spec)),\n ),\n ds.colors.utilities ?? ['bg', 'text', 'icon', '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 generate --format design --out .` — `DESIGN.md`, the agent-facing brief',\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 case 'legal':\n return cmdLegal(rest);\n default:\n fail(\n `unknown command \"${command}\" (expected: generate | init | validate | favicon | agents | docs | lint | legal). 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": "1.0.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.
|
|
26
|
-
"@getvitops/utils": "0.
|
|
25
|
+
"@getvitops/generator": "1.0.0",
|
|
26
|
+
"@getvitops/utils": "1.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"vitest": "^4.1.9"
|
package/skill/SKILL.md
CHANGED
|
@@ -40,7 +40,23 @@ never stale and always names the project's actual tokens. (If `vitops` isn't on
|
|
|
40
40
|
## Other commands
|
|
41
41
|
|
|
42
42
|
- `vitops generate --format <tailwind|css|bricks>` — generate the platform output.
|
|
43
|
+
- `vitops generate --format design --out .` — write `DESIGN.md`, the agent-facing brief
|
|
44
|
+
(google-labs-code/design.md format: YAML token front matter + prose rationale). It
|
|
45
|
+
emits no CSS, so it composes: `--format css,design`. The live reference above is
|
|
46
|
+
richer; DESIGN.md is for handing the identity to a tool that doesn't have this skill.
|
|
43
47
|
- `vitops init` / `vitops validate` — scaffold / check a `design-system.json`.
|
|
48
|
+
- `vitops legal` — render the site's privacy policy, terms of service and cookie notice
|
|
49
|
+
from a **site config** (not a `design-system.json`). `--format md|html|portable-text`
|
|
50
|
+
covers Astro content collections, WordPress/Bricks fragments and EmDash respectively;
|
|
51
|
+
`--out <dir>` writes files, otherwise it prints to stdout.
|
|
52
|
+
The documents are **derived from the config**: the analytics provider it names is the
|
|
53
|
+
one whose ID is set, the personal information it lists is what the configured forms
|
|
54
|
+
collect, the countries it names come from the providers in use. So the fix for a wrong
|
|
55
|
+
policy is a corrected config, never hand-editing the output — the next build overwrites
|
|
56
|
+
it. Declare processors the config cannot imply (payment, CRM, mail) under
|
|
57
|
+
`legal.privacyPolicy.processors`.
|
|
58
|
+
Generated from config, not legal advice — always tell the user to have it reviewed
|
|
59
|
+
before publishing.
|
|
44
60
|
- `vitops agents` — (re-)link this skill into `.agents/skills/` + `.claude/skills/` and
|
|
45
61
|
refresh the AGENTS.md pointer block. The links point into the installed package and
|
|
46
62
|
survive version bumps; re-run only if they were deleted.
|