@se-studio/skills 1.0.6 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # @se-studio/skills
2
2
 
3
+ ## 1.0.12
4
+
5
+ ### Patch Changes
6
+
7
+ - Version bump: patch for changed packages
8
+
9
+ ## 1.0.11
10
+
11
+ ### Patch Changes
12
+
13
+ - Version bump: patch for changed packages
14
+
15
+ ## 1.0.10
16
+
17
+ ### Patch Changes
18
+
19
+ - Add site-workflows-contentful-vercel-setup skill
20
+
21
+ ## 1.0.9
22
+
23
+ ### Patch Changes
24
+
25
+ - Add site-workflows-copy-doc-snapshot skill
26
+ - Add site-workflows-new-project skill
27
+ - Add site-workflows-project-cleanup skill
28
+
29
+ ## 1.0.8
30
+
31
+ ### Patch Changes
32
+
33
+ - Add site-workflows-apply-design-snapshot skill
34
+
35
+ ## 1.0.7
36
+
37
+ ### Patch Changes
38
+
39
+ - Add site-workflows-figma-design-snapshot skill
40
+
3
41
  ## 1.0.6
4
42
 
5
43
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/skills",
3
- "version": "1.0.6",
3
+ "version": "1.0.12",
4
4
  "description": "SE Studio agent skills for marketing site development with Contentful CMS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -130,7 +130,7 @@ cms-edit set @root items <id1>,<id2>,<id3> --links
130
130
 
131
131
  **Rich text fields** (body, additionalCopy):
132
132
  ```bash
133
- printf '## Why it matters\n\nOur platform helps teams **move faster** with [confidence](https://example.com).\n\n- Instant setup\n- No code required\n- 99.9%% uptime\n' | cms-edit rtf @c1 body -
133
+ printf '## Why it matters\n\nOur platform helps teams **move faster** with [confidence](https://example.com).\n\n- Instant setup\n- No code required\n- 99.9%% uptime\n' | cms-edit rtf @c1 body --markdown -
134
134
  ```
135
135
 
136
136
  Markdown support:
@@ -146,17 +146,17 @@ For any content with multiple paragraphs or newlines, use `printf` piped to stdi
146
146
 
147
147
  ```bash
148
148
  # Correct — printf interprets \n properly
149
- printf '## Why it matters\n\nOur platform helps teams **move faster**.\n\n- Instant setup\n- No code required\n' | cms-edit rtf @c1 body -
149
+ printf '## Why it matters\n\nOur platform helps teams **move faster**.\n\n- Instant setup\n- No code required\n' | cms-edit rtf @c1 body --markdown -
150
150
 
151
151
  # Also correct — file input
152
- cms-edit rtf @c1 body --file path/to/file.md
153
- cms-edit rtf @c1 body - < path/to/file.md
152
+ cms-edit rtf @c1 body --markdown --file path/to/file.md
153
+ cms-edit rtf @c1 body --markdown - < path/to/file.md
154
154
  ```
155
155
 
156
156
  Single-line content (no newlines) can be passed as a quoted argument directly:
157
157
 
158
158
  ```bash
159
- cms-edit rtf @c1 body "Simple single-paragraph body text with **bold**."
159
+ cms-edit rtf @c1 body --markdown "Simple single-paragraph body text with **bold**."
160
160
  ```
161
161
 
162
162
  **Surgical rich text replace** (compliance / quidget tokens — does not re-import the whole field):
@@ -237,7 +237,7 @@ Same as Component plus:
237
237
  When adding body content and a CTA (e.g. PDF download) to an article:
238
238
 
239
239
  1. `cms-edit open <article-slug>` (or `open <id> --id`)
240
- 2. Set body: `cms-edit rtf @<ref> body "..."` or `--file path/to.md`. If you need to add a body component first, use `add` then `rtf`.
240
+ 2. Set body: `cms-edit rtf @<ref> body --markdown "..."` or `--markdown --file path/to.md`. If you need to add a body component first, use `add` then `rtf`.
241
241
  3. `cms-edit add CTA --target bottomContent`
242
242
  4. Set CTA links: use `--type external --label "Download PDF" --href <url>` for an external PDF URL, or `--type download --label "Download PDF" --asset-id <asset-id>` for a Contentful asset (get the ID from `cms-edit asset search "..."` or `asset info <id>`).
243
243
  5. `cms-edit save`
@@ -442,7 +442,7 @@ cms-edit read @c0
442
442
  cms-edit set @c0 heading "We build for the future"
443
443
 
444
444
  # 5. Update the body copy (use printf for multiline content)
445
- printf '## Our mission\n\nWe help companies **ship faster** and _smarter_.\n\n- Founded in 2018\n- 500+ clients\n- [Join us](/careers)\n' | cms-edit rtf @c0 body -
445
+ printf '## Our mission\n\nWe help companies **ship faster** and _smarter_.\n\n- Founded in 2018\n- 500+ clients\n- [Join us](/careers)\n' | cms-edit rtf @c0 body --markdown -
446
446
 
447
447
  # 6. Review
448
448
  cms-edit diff
@@ -469,7 +469,7 @@ cms-edit open /products
469
469
  cms-edit types component # discover what's available
470
470
  cms-edit add CTA --after @c3
471
471
  cms-edit set @c4 heading "Ready to get started?"
472
- cms-edit rtf @c4 body "Join thousands of teams who trust us."
472
+ cms-edit rtf @c4 body --markdown "Join thousands of teams who trust us."
473
473
  cms-edit links add @c4 --type external --label "Start free trial" --href https://app.example.com
474
474
  cms-edit save
475
475
  ```
@@ -763,7 +763,7 @@ cat page.json | cms-edit create from-json # Pipe from stdin
763
763
  - Any component entry in `components` or `items` may use `{ existingId }` to link an existing entry instead of creating a new one.
764
764
  - The same applies to `links` entries — use `{ existingId }` to attach an existing link entry.
765
765
  - `cmsLabel` sets the human-readable label shown in Contentful's entry list. Defaults to `type` or `contentType` if omitted. **Always set `cmsLabel` on components when a page has multiple instances of the same type** (e.g. three CTAs) — editors need to distinguish them.
766
- - String `fields` values are converted to Contentful rich text when they match the Markdown heuristic: contains `\n\n` or `**` or `_`, starts with `#`, starts with `- `, or starts with `> ` (blockquote with a space). **Plain single-line text with none of those patterns is not converted** — for RichText fields, add `\n\n` or a heading line, or use `cms-edit rtf` afterwards.
766
+ - String `fields` values become Rich Text when they auto-detect as Markdown (same heuristic), HTML (tag-like), or Rich Text JSON (`nodeType: document`). Otherwise strings stay as-is — use `{ "value": "…", "format": "text"|"markdown"|"html"|"json" }` or `cms-edit rtf` with `--text|--markdown|--html|--json`.
767
767
  - `target` sets which content array to use: `topContent`, `content` (default), or `bottomContent`.
768
768
  - Slugs must not have a trailing slash — `from-json` strips it with a warning, but avoid it in source JSON.
769
769
  - All entries are created as **drafts**. A human must publish in Contentful.
@@ -9,10 +9,10 @@ Use this skill when editing **rich text** fields (body, additionalCopy) and inse
9
9
 
10
10
  ## Rich text (rtf)
11
11
 
12
- - **Replace** body with Markdown (single paragraph, no newlines): `cms-edit rtf @c1 body "Simple body with **bold** and [link](https://example.com)."`
12
+ - **Replace** body with Markdown (single paragraph, no newlines): `cms-edit rtf @c1 body --markdown "Simple body with **bold** and [link](https://example.com)."`
13
13
  - **Multiline content** — use `printf` piped to stdin; `\n` in a double-quoted shell string is **not** a newline in bash:
14
14
  ```bash
15
- printf '## Heading\n\nParagraph with **bold** and [link](https://example.com).\n' | cms-edit rtf @c1 body -
15
+ printf '## Heading\n\nParagraph with **bold** and [link](https://example.com).\n' | cms-edit rtf @c1 body --markdown -
16
16
  ```
17
17
  - Use `--file path/to/file.md` or stdin (`-`) for long content.
18
18
  - Markdown supported: headings, bold/italic, links, lists, blockquote, inline code, `---`.
@@ -86,7 +86,7 @@ Add `--dry-run` to count matches without writing.
86
86
  Replace an entire rich text field by piping Markdown from stdin. Avoids shell quoting issues for long content.
87
87
 
88
88
  ```bash
89
- echo "## New heading\n\nNew body text." | cms-edit rtf edit @c1 body
89
+ echo "## New heading\n\nNew body text." | cms-edit rtf edit @c1 body --markdown
90
90
  ```
91
91
 
92
92
  In human (interactive) mode, the command prints the current Markdown to stdout first, then reads the replacement from stdin.
@@ -0,0 +1,285 @@
1
+ ---
2
+ name: site-workflows-apply-design-snapshot
3
+ description: Reads design.md and applies the design tokens to the project — updating tailwind.config.json (colours + typography), handling custom fonts, and regenerating all downstream files via pnpm codegen. Run after /figma-design-snapshot to sync the codebase with the latest Figma changes.
4
+ license: MIT
5
+ metadata:
6
+ author: se-studio
7
+ version: "1.0.0"
8
+ ---
9
+
10
+ # Apply Design Snapshot
11
+
12
+ Reads `design.md` and applies its design tokens to the project. Run this after `/figma-design-snapshot` to keep the codebase in sync with Figma.
13
+
14
+ ## Usage
15
+
16
+ ```
17
+ /apply-design-snapshot
18
+ ```
19
+
20
+ No arguments needed. Reads `design.md` and `.design-snapshot.json` from the project root, updates `tailwind.config.json` and `globals.css`, then runs `pnpm codegen` to regenerate all typed token files.
21
+
22
+ ---
23
+
24
+ ## CRITICAL: The token pipeline
25
+
26
+ ```
27
+ tailwind.config.json
28
+ ↓ pnpm codegen
29
+ src/generated/colors.ts ← typed colour lookups (auto-generated)
30
+ src/generated/textStyles.ts ← typed type-scale names (auto-generated)
31
+ src/generated/setailwind.css ← CSS custom properties + utilities (auto-generated)
32
+ ```
33
+
34
+ **Never edit files in `src/generated/` directly** — they are always overwritten by `codegen`. Only edit `tailwind.config.json` and `globals.css`.
35
+
36
+ ---
37
+
38
+ ## Step 1 — Check prerequisites
39
+
40
+ 1. Check that `design.md` exists in the project root (or at `outputPath` from `.design-snapshot.json`).
41
+ - If missing: stop and tell the user to run `/figma-design-snapshot` first.
42
+ 2. Check that `tailwind.config.json` exists.
43
+ - If missing: stop and tell the user this skill requires the SE Studio token pipeline.
44
+
45
+ ---
46
+
47
+ ## Step 2 — Parse design.md
48
+
49
+ Read `design.md` and extract:
50
+
51
+ ### Colours
52
+ Find the `## Colour Palette` section. For every table row matching `| Token | Hex |`, extract the token name and hex value. Ignore swatch columns. Collect all colours regardless of group (Primary / Neutral / etc.).
53
+
54
+ ### Typography
55
+ Find `## Typography`. Extract the **Desktop** table (lines under `### Desktop`) and the **Mobile** table (lines under `### Mobile`). For each row capture: style name, size (strip `px`), weight label, line-height, letter-spacing.
56
+
57
+ Weight label → number mapping:
58
+ - Regular → 400
59
+ - Medium → 500
60
+ - SemiBold → 600
61
+ - Bold → 700
62
+
63
+ Letter-spacing conversion (Figma `%` → CSS `em`): divide by 100. e.g. `−1.3%` → `-0.013em`. If the value is `0` keep it as `0`.
64
+
65
+ Line-height conversion: strip `%` and divide by 100. e.g. `120%` → `1.2`. If already a decimal, keep as-is. If in `px`, keep as the px value.
66
+
67
+ ### Font family
68
+ Find `**Font family:**` in the Typography section. Extract the font name (e.g. `Booton-TRIAL`).
69
+
70
+ ### Breakpoints
71
+ Find `## Breakpoints & Canvas`. Extract rows — identify the desktop canvas width (largest) and mobile canvas width (smallest).
72
+
73
+ ---
74
+
75
+ ## Step 3 — Read current tailwind.config.json
76
+
77
+ Read `tailwind.config.json` in full. Record:
78
+ - `colorOptions` — the current colour map (must preserve all existing keys)
79
+ - `fontTable.font` — the current font family string
80
+ - `fontTable.weight` — the base font weight
81
+ - `fontTable.styles` — the current style map (keys are class names used in the codebase — **never rename or remove them**)
82
+ - `colorOpposites` — existing colour contrast pairs
83
+ - `foregroundColors` — existing foreground colour list
84
+ - `colorFile` — keep unchanged
85
+
86
+ ---
87
+
88
+ ## Step 4 — Ask about fonts
89
+
90
+ Before modifying any file, ask the user this question (use `AskUserQuestion`):
91
+
92
+ > The design uses **[font name from design.md]** (Regular 400, Medium 500, SemiBold 600).
93
+ >
94
+ > How should I handle the font?
95
+ >
96
+ > **A)** I have the font files — tell me the path (relative to project root or absolute) and I'll copy them to `public/fonts/` and wire up `@font-face`.
97
+ > **B)** I don't have the files yet — set up placeholder `@font-face` rules so I can drop files in later.
98
+ > **C)** Skip fonts — only update colours and type sizes.
99
+
100
+ Wait for the answer. Record as `fontStrategy` (A / B / C). If A, also record `fontSourcePath` from their reply.
101
+
102
+ ---
103
+
104
+ ## Step 5 — Build the colour patch
105
+
106
+ Construct the updated `colorOptions` object:
107
+
108
+ 1. **Start with all existing entries** exactly as they are. The `Light` and `Dark` keys are especially critical — they feed `lookupColourString()`, `lookupOpposite()`, and `lookupColourClassNames()` throughout the component system.
109
+
110
+ 2. **Add new entries** from design.md. Skip any name that already exists (case-insensitive match). Use the exact name string from design.md as the key (the codegen tool kebab-cases it for CSS variables automatically).
111
+
112
+ 3. **Compute colour opposites** for each new colour using WCAG relative luminance:
113
+ 1. Parse the hex value into R, G, B as integers 0–255, then normalise to 0–1 by dividing by 255.
114
+ 2. Linearise each channel: if c ≤ 0.03928 → `c / 12.92`, else `((c + 0.055) / 1.055) ^ 2.4`.
115
+ 3. Compute luminance: `L = 0.2126·R + 0.7152·G + 0.0722·B`.
116
+ 4. If `L ≤ 0.179` → the colour is dark; opposite is `"Light"` (white/light text will be legible).
117
+ If `L > 0.179` → the colour is light; opposite is `"Dark"` (dark text will be legible).
118
+
119
+ 4. **Show the user** the full list of colours being added (name + hex + computed opposite) before writing anything. Ask them to confirm or correct any pairs.
120
+
121
+ ---
122
+
123
+ ## Step 6 — Build the typography patch
124
+
125
+ Map Figma's style names to the existing project class names using this table. The left column is how the style appears in design.md; the right is the `fontTable.styles` key to update in `tailwind.config.json`.
126
+
127
+ | design.md style | tailwind.config.json key |
128
+ |---|---|
129
+ | H1 (Desktop) | `h1` |
130
+ | H2 (Desktop) | `h2` |
131
+ | H3 (Desktop) | `h3` |
132
+ | H4 (Desktop) | `h4` |
133
+ | P1 (Desktop) | `p1` |
134
+ | P2 (Desktop) | `p2` |
135
+ | P3 (Desktop) | `p3` |
136
+ | P4 (Desktop) | `p3Med` |
137
+ | Button 1 (Desktop) | `large-button` |
138
+
139
+ > **Note:** If your project uses different `fontTable.styles` keys, adjust the right-hand column to match what is in your `tailwind.config.json`. Keys not present in the table are left exactly as-is.
140
+
141
+ For each mapped style, construct the updated `fontTable.styles` entry following these rules:
142
+
143
+ - `"default"` = the **Mobile** size for that style (from the Mobile table in design.md)
144
+ - `"desktop"` = the **Desktop** size (only include if it differs from `"default"`)
145
+ - `"weight"` = only include when the weight is not the base `fontTable.weight` (typically 400)
146
+ - `"lineHeight"` = converted value (see Step 2 conversion rules)
147
+ - `"letterSpacing"` = converted value (see Step 2 conversion rules); omit if `0`
148
+ - `"additional"` = **preserve exactly** from the existing entry (e.g. `text-transform: uppercase` on `h1`) — do not remove it
149
+ - Style keys not in the mapping table above (e.g. `hHome`, `h2Med`, `h2plus`, `nav`, etc.) → **leave completely unchanged**
150
+
151
+ Example output for `h2`:
152
+ ```json
153
+ "h2": {
154
+ "weight": 500,
155
+ "letterSpacing": "-0.013em",
156
+ "lineHeight": 1.2,
157
+ "default": 40,
158
+ "desktop": 51
159
+ }
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Step 7 — Build the font patch
165
+
166
+ ### Strategy A — font files provided
167
+
168
+ 1. List all font files at `fontSourcePath` matching `*.woff2`, `*.woff`, `*.ttf`, `*.otf`.
169
+ 2. Create `public/fonts/` if it does not exist.
170
+ 3. Copy all matched files into `public/fonts/`.
171
+ 4. For each file, infer the face weight from the filename:
172
+ - Filename contains `Regular` or `400` → weight: 400, style: normal
173
+ - Contains `Medium` or `500` → weight: 500, style: normal
174
+ - Contains `SemiBold` or `Semi` or `600` → weight: 600, style: normal
175
+ - Contains `Bold` or `700` → weight: 700, style: normal
176
+ - Contains `Italic` → add `font-style: italic` alongside the matching weight
177
+ 5. Build `@font-face` blocks — prefer `woff2` format; fall back to `woff` then `ttf`.
178
+ 6. Insert the `@font-face` blocks into `globals.css` **before** the `@import "tailwindcss"` line (font declarations must precede Tailwind).
179
+ 7. Update `tailwind.config.json` → `fontTable.font` to the font family name from design.md.
180
+ 8. Update `globals.css` `@theme` block: replace the `--font-sans` value with `"[FontName]", system-ui, ui-sans-serif, sans-serif`.
181
+
182
+ ### Strategy B — placeholder
183
+
184
+ 1. Add the following block to `globals.css` before the `@import "tailwindcss"` line:
185
+
186
+ ```css
187
+ /* TODO: Replace src with actual font files placed in public/fonts/ */
188
+ @font-face {
189
+ font-family: "[FontName]";
190
+ src: local("[FontName]");
191
+ font-weight: 400;
192
+ font-style: normal;
193
+ font-display: swap;
194
+ }
195
+ @font-face {
196
+ font-family: "[FontName]";
197
+ src: local("[FontName]");
198
+ font-weight: 500;
199
+ font-style: normal;
200
+ font-display: swap;
201
+ }
202
+ @font-face {
203
+ font-family: "[FontName]";
204
+ src: local("[FontName]");
205
+ font-weight: 600;
206
+ font-style: normal;
207
+ font-display: swap;
208
+ }
209
+ ```
210
+
211
+ 2. Update `tailwind.config.json` → `fontTable.font` to the font family name.
212
+ 3. Update `globals.css` `--font-sans` to `"[FontName]", system-ui, ui-sans-serif, sans-serif`.
213
+ 4. After writing, tell the user: *"Place your font files in `public/fonts/` and replace each `src: local(...)` line with `src: url('/fonts/YourFile.woff2') format('woff2')`."*
214
+
215
+ ### Strategy C — skip
216
+
217
+ No font changes. Skip this step entirely.
218
+
219
+ ---
220
+
221
+ ## Step 8 — Apply all changes
222
+
223
+ Write files in this order:
224
+
225
+ 1. **`tailwind.config.json`** — merge in the new `colorOptions`, updated `colorOpposites`, and updated `fontTable.styles`. All other fields (`sizes`, `colorFile`, `foregroundColors`, etc.) must be preserved exactly.
226
+ 2. **`src/app/globals.css`** — apply font changes (strategies A or B only).
227
+ 3. **`public/fonts/`** — copy font files (strategy A only).
228
+
229
+ Before writing `tailwind.config.json`, do a final sanity check:
230
+ - `Light` and `Dark` keys still present with their original hex values
231
+ - No existing `fontTable.styles` keys removed
232
+ - JSON is valid
233
+
234
+ ---
235
+
236
+ ## Step 9 — Regenerate
237
+
238
+ ```bash
239
+ pnpm codegen
240
+ ```
241
+
242
+ If this fails:
243
+ - Show the error output
244
+ - Diagnose the likely cause (invalid JSON in tailwind.config.json, unknown field, etc.)
245
+ - Suggest a fix
246
+ - Do NOT run `pnpm validate` until codegen succeeds
247
+
248
+ ---
249
+
250
+ ## Step 10 — Validate
251
+
252
+ ```bash
253
+ pnpm validate
254
+ ```
255
+
256
+ This runs Biome lint + TypeScript type-check. Report pass or fail. If it fails, show the errors.
257
+
258
+ ---
259
+
260
+ ## Step 11 — Report to user
261
+
262
+ Summarise what happened:
263
+
264
+ ```
265
+ ✓ Colours added: [N] new colours (list names)
266
+ ✓ Typography updated: [list of class names updated]
267
+ ✓ Font: [registered as FontName / placeholder set up / skipped]
268
+ ✓ pnpm codegen: passed
269
+ ✓ pnpm validate: passed (or: ✗ failed — see errors above)
270
+
271
+ Next steps:
272
+ git diff tailwind.config.json ← review the token changes
273
+ git diff src/app/globals.css ← review font changes
274
+ git add -p && git commit -m "design: apply snapshot YYYY-MM-DD"
275
+ ```
276
+
277
+ ---
278
+
279
+ ## What this skill does NOT touch
280
+
281
+ - `design.md` — read-only input, never modified
282
+ - `.design-snapshot.json` — read-only config
283
+ - `src/generated/*` — auto-regenerated by codegen, never edited directly
284
+ - Any files in `src/project/` — components are not updated; only tokens change
285
+ - Existing `fontTable.styles` keys not in the mapping table — left exactly as-is