spec-layer 0.2.1 → 0.4.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 +99 -21
  2. package/dist/cli.js +1575 -57
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -11,19 +11,23 @@ and writes it to disk.
11
11
  ## Quick start
12
12
 
13
13
  After publishing a library from the plugin's Library screen, it shows a setup
14
- command. Run it in your repository:
14
+ command. Run it once in your repository:
15
15
 
16
16
  ```bash
17
- SPEC_LAYER_KEY=sl_... npx spec-layer pull --id lib_...
17
+ npx spec-layer setup --id lib_... --key sl_...
18
18
  ```
19
19
 
20
- That writes `.speclayer/` and is enough on its own. To avoid repeating the
21
- library id, record it once:
20
+ That records the library id, stores the key in a gitignored
21
+ `speclayer.local.json`, and writes `.speclayer/`. Every later command needs no
22
+ flags at all:
22
23
 
23
24
  ```bash
24
- npx spec-layer init --id lib_...
25
+ npx spec-layer pull
25
26
  ```
26
27
 
28
+ `init` still writes the config without a key or a network call, for a repo
29
+ that supplies the key from the environment instead.
30
+
27
31
  ## Installing, or not
28
32
 
29
33
  `npx` needs no install step: it fetches the package and runs it. That is the
@@ -47,17 +51,21 @@ npm install --save-dev spec-layer
47
51
 
48
52
  `npx spec-layer` then runs the pinned local copy, no `--yes` needed. Pinning
49
53
  also keeps `.speclayer/manifest.json` on one format: 0.1.0 wrote no
50
- `selection` field, and 0.2.0 does.
54
+ `selection` field, and 0.2.0 onward does. `setup` needs 0.3.0 or later; earlier
55
+ versions have no such command, so the setup command the plugin copies fails
56
+ against them. The Foundation landing under `tokens/` as Design Tokens Format
57
+ Module 2025.10 files, rather than `ai/foundation.yaml`, needs 0.4.0 or later.
51
58
 
52
59
  ## Commands
53
60
 
54
61
  | Command | What it does |
55
62
  |---|---|
56
- | `init --id lib_... [--out DIR] [selection]` | Writes `speclayer.json` so later commands need no flags. |
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. |
57
65
  | `pull [--id lib_...] [--key sl_...] [selection]` | Fetches the library and writes it into `DIR` (default `.speclayer`). |
58
66
  | `status [--id lib_...] [--key sl_...]` | Checks freshness without writing. Exits `2` when the local copy is behind. |
59
67
  | `list` | Lists every artifact in the last pull, with its file path or `not written`. |
60
- | `show foundation [--canonical]` | Prints the Foundation's AI YAML to stdout. |
68
+ | `show foundation [--canonical]` | Prints the Foundation's DTCG document to stdout. |
61
69
  | `show component NAME [--canonical]` | Prints one component's AI YAML to stdout. |
62
70
 
63
71
  `--api URL` overrides the API origin (default `https://api.spec-layer.com`).
@@ -114,25 +122,70 @@ name, `show` refuses to guess and points you at `list`.
114
122
 
115
123
  ## The pull key
116
124
 
117
- Every command that talks to the server reads the pull key from `SPEC_LAYER_KEY`
118
- or `--key`. It is never written to disk, and `speclayer.json` never contains
119
- it. Treat it as a secret: it grants read access to the published bundle. If it
120
- leaks, rotate it from the plugin's Library screen. The old key stops working
121
- once the change propagates, which can take up to about a minute.
125
+ `spec-layer setup` stores the key in `speclayer.local.json` next to
126
+ `speclayer.json` and makes sure git ignores it before writing it. Every later
127
+ command in that directory needs no key. On POSIX systems the file is written
128
+ at mode `0600`; on Windows there is no equivalent permission bit, so it
129
+ inherits whatever the directory allows.
130
+
131
+ Commands that talk to the server resolve the key in this order:
132
+
133
+ 1. `--key sl_...`
134
+ 2. `SPEC_LAYER_KEY` in the environment
135
+ 3. `speclayer.local.json`, when it was issued for the same library
136
+
137
+ Environment sits above the file so CI can supply a key without touching the
138
+ working tree. A stored key issued for a different library is ignored, and the
139
+ CLI says which library it belongs to rather than letting the server answer 401.
140
+
141
+ Treat the key as a secret: it grants read access to the published bundle.
142
+ `speclayer.local.json` is gitignored, never printed by any command, and never
143
+ copied into `speclayer.json`, `bundle.json`, `manifest.json`, or anything under
144
+ the output directory. If it leaks, rotate it from the plugin's Library screen,
145
+ then run the new setup command. The old key stops working once the change
146
+ propagates, which can take up to about a minute.
147
+
148
+ Re-running `setup` replaces the stored key and keeps the rest of your setup:
149
+ with no `--out` and no selection flag it preserves the output directory and the
150
+ `include` block already in `speclayer.json` rather than resetting them to the
151
+ defaults. Pass `--out` or a selection flag to change them. (`init` still
152
+ overwrites `speclayer.json` outright, which is what a first run is for.)
153
+
154
+ Outside a git working tree, the key is still stored and the CLI says it left
155
+ `.gitignore` alone. Inside one, `setup` refuses to write the key whenever it
156
+ cannot confirm the file will be ignored, and says what to do instead. Three
157
+ cases refuse:
158
+
159
+ - `.gitignore` cannot be written.
160
+ - git itself could not be run, anywhere inside a working tree.
161
+ - the entry is in `.gitignore`, but git still does not ignore the file. That
162
+ almost always means `speclayer.local.json` is already tracked, and the CLI
163
+ names `git rm --cached speclayer.local.json` as the way out.
164
+
165
+ git decides in every case. The entry sitting in `.gitignore` is not taken as
166
+ proof, because `git check-ignore` does not report a tracked file as ignored no
167
+ matter what the ignore rules say.
122
168
 
123
169
  ## What `pull` writes
124
170
 
125
171
  ```text
126
172
  .speclayer/
127
- bundle.json the published bundle, verbatim
128
- manifest.json every artifact indexed by content hash and ai path, plus the selection
129
- ai/foundation.yaml tokens, styles, and modes (when selected and the library has a Foundation)
130
- ai/components/<name>.yaml one file per selected component
173
+ bundle.json the published bundle, verbatim
174
+ manifest.json every artifact indexed by content hash and path, plus the selection
175
+ tokens/ the Foundation as Design Tokens Format Module 2025.10 files
176
+ <collection>.<mode>.json one file per collection and mode, rooted at the collection name
177
+ styles.typography.json text styles as typography composites (when present)
178
+ styles.effects.json effect styles as shadow composites (when present)
179
+ resolver.json Design Tokens Resolver Module 2025.10: sets, modifiers, order
180
+ spec-layer.meta.json Figma ids, scopes, code syntax, publication, keyed by DTCG path
181
+ report.json what DTCG could not express, with reasons and stable ids
182
+ ai/components/<name>.yaml one file per selected component
131
183
  ```
132
184
 
133
- Point your agent at `.speclayer/ai/`. The YAML there is the same compact form
134
- the plugin's **Copy for AI** puts on your clipboard; `bundle.json` additionally
135
- holds the full canonical artifacts if you need them.
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.
136
189
 
137
190
  In `manifest.json`, an artifact the selection left unwritten has `"aiPath":
138
191
  null`. A manifest from CLI 0.1.0 has no `selection` field and means
@@ -147,7 +200,32 @@ When nothing changed since the last pull with the same selection, `pull`
147
200
  prints `Already up to date` and writes nothing. Every republish stamps a new
148
201
  export id and time into the canonical artifacts, so `bundle.json` and
149
202
  `manifest.json` change on each republish even when the content did not. The
150
- `ai/` YAML files and the content hashes stay stable.
203
+ `ai/` YAML files, the `tokens/` files, and the content hashes stay stable.
204
+
205
+ ## Configuring the token output
206
+
207
+ `speclayer.json` may carry a `dtcg` block:
208
+
209
+ {
210
+ "libraryId": "lib_...",
211
+ "outDir": ".speclayer",
212
+ "dtcg": {
213
+ "values": "standard",
214
+ "units": { "Foundation/spacing/*": "px", "Foundation/radius/*": "px" }
215
+ }
216
+ }
217
+
218
+ `values` is `standard` (the 2025.10 object forms, the default) or `legacy`
219
+ (the string forms Style Dictionary 4 and Tokens Studio read today). `units`
220
+ promotes a number whose Figma scopes state no unit to a dimension. Keys are a
221
+ collection name, a slash, and a glob over the variable name. An override that
222
+ contradicts a stated scope is ignored and listed in `report.json`. Nothing is
223
+ inferred from a name. Changing the `dtcg` block re-projects `tokens/` on the
224
+ next `pull` even when the library has not been republished.
225
+
226
+ Point Style Dictionary at `.speclayer/tokens/` and load the files
227
+ `resolver.json` names for the mode you are building. The metadata sidecar and
228
+ the report are not token files; exclude them from token globs.
151
229
 
152
230
  ## Exit codes
153
231