spec-layer 0.4.0 → 0.6.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.
Files changed (3) hide show
  1. package/README.md +168 -17
  2. package/dist/cli.js +1591 -124
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -14,9 +14,12 @@ After publishing a library from the plugin's Library screen, it shows a setup
14
14
  command. Run it once in your repository:
15
15
 
16
16
  ```bash
17
- npx spec-layer setup --id lib_... --key sl_...
17
+ npx spec-layer setup --id lib_... --key sl_... --platform web
18
18
  ```
19
19
 
20
+ `--platform` says what you build; without it, `setup` reads the repository
21
+ root and writes a token file only when it finds a web signal.
22
+
20
23
  That records the library id, stores the key in a gitignored
21
24
  `speclayer.local.json`, and writes `.speclayer/`. Every later command needs no
22
25
  flags at all:
@@ -55,25 +58,95 @@ also keeps `.speclayer/manifest.json` on one format: 0.1.0 wrote no
55
58
  versions have no such command, so the setup command the plugin copies fails
56
59
  against them. The Foundation landing under `tokens/` as Design Tokens Format
57
60
  Module 2025.10 files, rather than `ai/foundation.yaml`, needs 0.4.0 or later.
61
+ `tools` and `skill` need 0.5.0 or later. `components/` in place of
62
+ `ai/components/`, `path` in place of `aiPath` in the manifest, and the
63
+ `outputs` block need 0.6.0 or later.
58
64
 
59
65
  ## Commands
60
66
 
61
67
  | Command | What it does |
62
68
  |---|---|
63
- | `setup --id lib_... --key sl_... [--out DIR] [selection]` | Writes `speclayer.json`, stores the key in `speclayer.local.json`, then pulls. The command the plugin copies. |
64
- | `init --id lib_... [--out DIR] [selection]` | Writes `speclayer.json` so later commands need no flags. No key, no network. |
65
- | `pull [--id lib_...] [--key sl_...] [selection]` | Fetches the library and writes it into `DIR` (default `.speclayer`). |
69
+ | `setup --id lib_... --key sl_... [--out DIR] [--platform P]... [selection]` | Writes `speclayer.json`, stores the key in `speclayer.local.json`, then pulls. The command the plugin copies. |
70
+ | `init --id lib_... [--out DIR] [--platform P]... [selection]` | Writes `speclayer.json` so later commands need no flags. No key, no network. |
71
+ | `pull [--id lib_...] [--key sl_...] [--platform P]... [selection]` | Fetches the library and writes it into `DIR` (default `.speclayer`). |
66
72
  | `status [--id lib_...] [--key sl_...]` | Checks freshness without writing. Exits `2` when the local copy is behind. |
67
73
  | `list` | Lists every artifact in the last pull, with its file path or `not written`. |
68
74
  | `show foundation [--canonical]` | Prints the Foundation's DTCG document to stdout. |
69
75
  | `show component NAME [--canonical]` | Prints one component's AI YAML to stdout. |
76
+ | `tools [--json]` | Lists every command with what it reaches, needs, and writes. |
77
+ | `skill [--install] [--agent HOST]... [--platform P] [--json]` | Prints a guide for a coding agent, adapted to this repository and the last pull; `--install` writes it where the agent reads instructions. |
70
78
 
71
79
  `--api URL` overrides the API origin (default `https://api.spec-layer.com`).
72
80
 
81
+ ## For a coding agent
82
+
83
+ The setup command is usually handed to a coding agent, and a bare command
84
+ tells the agent nothing about what it just wrote or how to read it. Two
85
+ local commands close that gap; neither needs a key or the network.
86
+
87
+ `spec-layer tools` lists every command with the facts an agent needs before
88
+ running one: whether it reaches the network, whether it needs the pull key,
89
+ what it writes, and what each exit code means. `--json` prints the same list
90
+ in a stable shape for machines.
91
+
92
+ `spec-layer skill` prints a guide to the pulled files, and `--install` writes
93
+ it where the agent reads project instructions:
94
+
95
+ ```bash
96
+ npx spec-layer skill --install
97
+ ```
98
+
99
+ `setup` names this command as the next step after a successful pull, and the
100
+ plugin's Publish screen has a **Copy for an AI agent** button that copies the
101
+ setup command already followed by it.
102
+
103
+ The guide is built from three things and nothing else:
104
+
105
+ - The tool list above.
106
+ - **What the last pull wrote.** Every component with its file path, every
107
+ token collection with its modes and default, the token files, the
108
+ `report.json` counts, and how many tokens landed as plain numbers because
109
+ their Figma scopes state no unit. Before a pull the guide says so and names
110
+ nothing.
111
+ - **What the repository root says about the codebase.** Detection reads only
112
+ the top level of the working directory (`package.json` dependency names,
113
+ build files, agent configuration directories) and names the file behind
114
+ every conclusion. A signal it cannot find is reported as absent, never
115
+ guessed. The platform decides which Figma `code_syntax` key the guide points
116
+ at (`WEB`, `iOS`, `ANDROID`; Flutter has none) and which token pipeline
117
+ advice it gives: Tailwind, Style Dictionary (with the `legacy` value form
118
+ suggested when package.json declares a major version below 5), Swift,
119
+ Kotlin or Compose, or Dart.
120
+
121
+ `--platform web|ios|android|flutter` overrides the detected target, which is
122
+ the way to get platform advice in a repository that carries no signal (a new
123
+ directory, a monorepo whose apps sit one level down). `--json` prints the
124
+ detection, the pull summary, and the install targets instead of the guide.
125
+
126
+ `--install` writes to every agent host detected at the root, or to the hosts
127
+ named with a repeatable `--agent`, or to `AGENTS.md` when nothing is detected
128
+ and nothing is named. Each run says which files it wrote, updated, or left
129
+ unchanged.
130
+
131
+ | Host | `--agent` | File |
132
+ |---|---|---|
133
+ | Claude Code | `claude` | `.claude/skills/spec-layer/SKILL.md` |
134
+ | Cursor | `cursor` | `.cursor/rules/spec-layer.mdc` |
135
+ | GitHub Copilot | `copilot` | `.github/instructions/spec-layer.instructions.md` |
136
+ | Windsurf | `windsurf` | `.windsurf/rules/spec-layer.md` |
137
+ | Gemini CLI | `gemini` | `GEMINI.md`, between `<!-- spec-layer:begin -->` and `<!-- spec-layer:end -->` |
138
+ | Anything that reads `AGENTS.md` | `agents-md` | `AGENTS.md`, between the same markers |
139
+
140
+ The dedicated files are replaced whole. The shared files (`AGENTS.md`,
141
+ `GEMINI.md`) are yours: only the marked block is replaced, and a file without
142
+ the markers gets the block appended. Re-run `skill --install` after a pull
143
+ that adds components or when the codebase changes stack. The written files
144
+ carry no key and are meant to be committed with the rest of the repository.
145
+
73
146
  ## Pulling part of a library
74
147
 
75
148
  By default `pull` writes the Foundation and every documented component. When
76
- your repo implements only some of them, narrow what lands in `ai/`:
149
+ your repo implements only some of them, narrow what lands in `components/`:
77
150
 
78
151
  ```bash
79
152
  npx spec-layer pull --only foundation # tokens and styles, no components
@@ -104,7 +177,7 @@ That stores an `include` block in `speclayer.json`:
104
177
  Selection flags on `pull` replace the stored selection for that run; they are
105
178
  never merged with it.
106
179
 
107
- The selection only decides which `ai/` files are written. `bundle.json`
180
+ The selection only decides which `components/` files are written. `bundle.json`
108
181
  always holds the whole library, so `list` and `show` can answer for any
109
182
  artifact, written or not, and `status` compares one hash.
110
183
 
@@ -171,7 +244,7 @@ matter what the ignore rules say.
171
244
  ```text
172
245
  .speclayer/
173
246
  bundle.json the published bundle, verbatim
174
- manifest.json every artifact indexed by content hash and path, plus the selection
247
+ manifest.json every artifact indexed by content hash and path, plus the selection and outputs
175
248
  tokens/ the Foundation as Design Tokens Format Module 2025.10 files
176
249
  <collection>.<mode>.json one file per collection and mode, rooted at the collection name
177
250
  styles.typography.json text styles as typography composites (when present)
@@ -179,15 +252,21 @@ matter what the ignore rules say.
179
252
  resolver.json Design Tokens Resolver Module 2025.10: sets, modifiers, order
180
253
  spec-layer.meta.json Figma ids, scopes, code syntax, publication, keyed by DTCG path
181
254
  report.json what DTCG could not express, with reasons and stable ids
182
- ai/components/<name>.yaml one file per selected component
255
+ components/<name>.yaml one file per selected component
256
+ outputs/
257
+ web-css.map.json DTCG path -> CSS custom property, with where the name came from
258
+ web-css.report.json what the CSS file could not express
259
+ spec-layer/
260
+ tokens.css the web token file, written in place at outputs[].path
183
261
  ```
184
262
 
185
- Point your agent at `.speclayer/ai/` and `.speclayer/tokens/`. The component
186
- YAML is the same compact form the plugin's **Copy for AI** puts on your
187
- clipboard; `bundle.json` additionally holds the full canonical artifacts if
188
- you need them.
263
+ Point your agent at `.speclayer/components/` and `.speclayer/tokens/`, and
264
+ import the token file for your platform from where `outputs` puts it. The
265
+ component YAML is the same compact form the plugin's **Copy for AI** puts on
266
+ your clipboard; `bundle.json` additionally holds the full canonical artifacts
267
+ if you need them.
189
268
 
190
- In `manifest.json`, an artifact the selection left unwritten has `"aiPath":
269
+ In `manifest.json`, an artifact the selection left unwritten has `"path":
191
270
  null`. A manifest from CLI 0.1.0 has no `selection` field and means
192
271
  everything was written.
193
272
 
@@ -200,7 +279,8 @@ When nothing changed since the last pull with the same selection, `pull`
200
279
  prints `Already up to date` and writes nothing. Every republish stamps a new
201
280
  export id and time into the canonical artifacts, so `bundle.json` and
202
281
  `manifest.json` change on each republish even when the content did not. The
203
- `ai/` YAML files, the `tokens/` files, and the content hashes stay stable.
282
+ `components/` YAML files, the `tokens/` files, and the content hashes stay
283
+ stable.
204
284
 
205
285
  ## Configuring the token output
206
286
 
@@ -227,12 +307,83 @@ Point Style Dictionary at `.speclayer/tokens/` and load the files
227
307
  `resolver.json` names for the mode you are building. The metadata sidecar and
228
308
  the report are not token files; exclude them from token globs.
229
309
 
310
+ ## Token files for your code
311
+
312
+ `pull` also writes a file your build compiles, one per platform output. For
313
+ the web that is a CSS file of custom properties. The file is written only
314
+ when that pull writes the Foundation; with `--only components` it is left
315
+ exactly as it was, and `list` shows it as `not written`.
316
+
317
+ ```css
318
+ :root {
319
+ /* Foundation */
320
+ --foundation-colors-blue-500: #2e72d1;
321
+ --foundation-spacing-200: 8px;
322
+ /* Mapped Colors, Light */
323
+ --mapped-colors-surface-primary-default: var(--foundation-colors-blue-500);
324
+ }
325
+
326
+ [data-theme="dark"] {
327
+ /* Mapped Colors, Dark */
328
+ --mapped-colors-surface-primary-default: var(--foundation-colors-blue-900);
329
+ }
330
+ ```
331
+
332
+ Sets and every collection's default mode sit at `:root`; every other mode is
333
+ a block under `[data-theme="<mode>"]`. Aliases stay as `var()`. A number whose
334
+ Figma scopes state no unit stays a bare number. Nothing about a mode's name
335
+ selects a media query; wire `data-theme` to `prefers-color-scheme` yourself if
336
+ the OS should choose.
337
+
338
+ The file is written **in place** at the path in `speclayer.json`, outside the
339
+ managed directory, so your bundler keeps watching it and the diff shows up in
340
+ review. It begins with a header naming the library and the Foundation's
341
+ content hash, and `pull` refuses to overwrite a file at that path that lacks
342
+ the header.
343
+
344
+ ```json
345
+ {
346
+ "platforms": ["web"],
347
+ "outputs": [
348
+ { "platform": "web", "format": "css", "path": "spec-layer/tokens.css", "case": "kebab" }
349
+ ]
350
+ }
351
+ ```
352
+
353
+ `setup` and `init` write this block from `--platform`, or from what they detect
354
+ at the repository root, so the path is always on record. `pull` writes every
355
+ entry; `"outputs": []` writes none. `case` chooses how derived names are
356
+ spelled: `kebab` (default), `camel`, `pascal`, `snake`, or `constant`. A name
357
+ the designer declared as `code_syntax` in Figma is used verbatim and never
358
+ re-cased. `.speclayer/outputs/web-css.map.json` records every emitted name and
359
+ whether it was declared or derived; two tokens that would share a name are
360
+ both omitted and listed in `web-css.report.json`.
361
+
362
+ Two collections with modes share one attribute by default, which cannot be
363
+ right for both; the report says so, and `modes` declares a selector per
364
+ collection:
365
+
366
+ ```json
367
+ { "platform": "web", "format": "css", "path": "spec-layer/tokens.css",
368
+ "modes": { "Density": "[data-density=\"{mode}\"]" } }
369
+ ```
370
+
371
+ `root` and `modeSelector` override the defaults `:root` and
372
+ `[data-theme="{mode}"]`; `{mode}` and `{collection}` are replaced by slugs.
373
+ A repository that already builds tokens with Style Dictionary can keep reading
374
+ `tokens/`: the CSS file is a projection of the same files, not a second
375
+ source, so import one or the other.
376
+
377
+ Commit `.speclayer/`, `speclayer.json`, and the output paths. A repository
378
+ that would rather regenerate in CI ignores them and runs `pull` there;
379
+ `status` exits `2` when a pull is due.
380
+
230
381
  ## Exit codes
231
382
 
232
383
  | Code | Meaning |
233
384
  |---|---|
234
385
  | `0` | Success, or `status` found the local copy up to date. |
235
- | `1` | Usage error, bad key or id, unknown component name, or a network or server failure. |
386
+ | `1` | Usage error, bad key or id, unknown component name, a network or server failure, or a file `skill --install` could not write. |
236
387
  | `2` | `status` only: the local copy is behind, or no local pull exists yet. |
237
388
 
238
389
  `status` is safe in CI: it writes nothing, and exit `2` is the signal to run
@@ -240,5 +391,5 @@ the report are not token files; exclude them from token globs.
240
391
 
241
392
  ## Requirements
242
393
 
243
- Node 22 or newer. Publishing requires a Spec Layer Pro license; pulling does
244
- not.
394
+ Node 22 or newer. Publishing one Figma file is free; Pro publishes up to ten.
395
+ Pulling needs only the library id and pull key.