@se-studio/project-build 1.0.125 → 1.0.126

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,11 @@
1
1
  # @se-studio/project-build
2
2
 
3
+ ## 1.0.126
4
+
5
+ ### Patch Changes
6
+
7
+ - Version bump: patch for changed packages
8
+
3
9
  ## 1.0.125
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/project-build",
3
- "version": "1.0.125",
3
+ "version": "1.0.126",
4
4
  "description": "Build tools and management scripts for SE Studio projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,19 +61,19 @@
61
61
  "url": "https://github.com/Something-Else-Studio/se-core-product/issues"
62
62
  },
63
63
  "dependencies": {
64
- "@biomejs/biome": "^2.4.10",
64
+ "@biomejs/biome": "^2.4.12",
65
65
  "@biomejs/js-api": "^4.0.0",
66
- "@biomejs/wasm-nodejs": "^2.4.10",
66
+ "@biomejs/wasm-nodejs": "^2.4.12",
67
67
  "change-case": "^5.4.4",
68
68
  "chroma-js": "^3.2.0",
69
- "contentful-management": "^12.2.0",
70
- "dotenv": "^17.4.0"
69
+ "contentful-management": "^12.3.1",
70
+ "dotenv": "^17.4.2"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/chroma-js": "^3.1.2",
74
- "@types/node": "^22.19.15",
74
+ "@types/node": "^22.19.17",
75
75
  "typescript": "^6.0.2",
76
- "vitest": "^4.1.2"
76
+ "vitest": "^4.1.4"
77
77
  },
78
78
  "scripts": {
79
79
  "build": "node scripts/merge-contentful-skills.mjs && tsc --project tsconfig.build.json",
@@ -235,11 +235,16 @@ cms-edit add CTA --target bottomContent
235
235
  # Add after a specific component
236
236
  cms-edit add HeroSimple --after @c1
237
237
 
238
- # Add inside a collection
238
+ # Add inside a collection (--parent derives target field from the parent's content type)
239
+ # collection parent → uses 'contents'; page/article parent → uses 'content' by default
239
240
  cms-edit add Card --parent @c2
241
+ cms-edit add Hero --parent @c0 --target content # explicit target when parent is a page
240
242
 
241
243
  # Add an explicit collection type
242
244
  cms-edit add CardGrid --content-type collection
245
+
246
+ # Link an EXISTING entry instead of creating a new one (e.g. a shared CTA used on every page)
247
+ cms-edit add CTA --content-type component --existing-id 4xKj2abcDef
243
248
  ```
244
249
 
245
250
  Discover available types first:
@@ -303,6 +308,16 @@ cms-edit links remove @c5 1
303
308
  cms-edit links move @c5 2 0
304
309
  ```
305
310
 
311
+ You can also bulk-replace the `links` array on a component using `set --links`:
312
+
313
+ ```bash
314
+ # Replace the entire links array with specific IDs
315
+ cms-edit set @c5 links linkId1,linkId2,linkId3 --links
316
+
317
+ # Append a link entry ID to the existing array
318
+ cms-edit set @c5 links linkId4 --links --append
319
+ ```
320
+
306
321
  ## Assets
307
322
 
308
323
  ```bash
@@ -331,7 +346,13 @@ cms-edit nav add --label "Docs" --href https://docs.example.com --after @c1
331
346
 
332
347
  ```bash
333
348
  # Create a new page (session opens on the new entry)
349
+ # All flags after --title are optional
334
350
  cms-edit create page --slug /about-us --title "About Us" --description "Learn about our team"
351
+ cms-edit create page --slug /about-us --title "About Us" \
352
+ --template-id <template-entry-id> \
353
+ --featured-image <asset-id> \
354
+ --indexed \
355
+ --cms-label "About Us (internal)"
335
356
 
336
357
  # Create a new article (requires articleType entry ID)
337
358
  cms-edit create article --slug /blog/my-post --title "My Post" --article-type-id 3abcDef456
@@ -588,18 +609,164 @@ echo '[...]' | cms-edit run # Pipe from stdin
588
609
  cms-edit run --file ops.json --dry-run # Validate without saving
589
610
  ```
590
611
 
591
- Supported ops: `open`, `set`, `rtf`, `rtf-replace`, `save`.
612
+ Supported ops: `open`, `set`, `rtf`, `rtf-replace`, `save`, `add`, `links-add`.
592
613
 
593
- Example `ops.json`:
614
+ | Op | args | opts |
615
+ |----|------|------|
616
+ | `open` | `["/slug"]` | — |
617
+ | `set` | `[ref, field, value]` | — |
618
+ | `rtf` | `[ref, field, markdown]` | — |
619
+ | `rtf-replace` | `[ref, field]` | `{ find, replacePlain?, mode? }` |
620
+ | `save` | — | — |
621
+ | `add` | `[type, contentType]` | `{ after?, parent?, target?, existingId? }` |
622
+ | `links-add` | `[ref]` | `{ type, label, href?, slug?, id?, assetId? }` |
623
+
624
+ The `add` op returns the new `@ref` in the step message; subsequent ops can reference it.
625
+
626
+ Example `ops.json` — update an existing page with a new CTA that has two buttons:
594
627
  ```json
595
628
  [
596
629
  { "cmd": "open", "args": ["/pricing"] },
597
- { "cmd": "set", "args": ["@c0", "heading", "New Heading"] },
598
- { "cmd": "rtf", "args": ["@c1", "body", "## Section\n\nContent here."] },
630
+ { "cmd": "add", "args": ["CTA", "component"], "opts": { "target": "bottomContent" } },
631
+ { "cmd": "set", "args": ["@c5", "heading", "Ready to get started?"] },
632
+ { "cmd": "links-add", "args": ["@c5"], "opts": { "type": "external", "label": "Start free trial", "href": "https://app.example.com" } },
633
+ { "cmd": "links-add", "args": ["@c5"], "opts": { "type": "internal", "label": "Learn more", "slug": "/about" } },
599
634
  { "cmd": "save" }
600
635
  ]
601
636
  ```
602
637
 
638
+ ## Create Page or Article from JSON
639
+
640
+ Create a complete page or article — including all components, fields, and CTA links — from a single declarative JSON file. This is the recommended approach for creating multiple pages or articles in bulk.
641
+
642
+ ```bash
643
+ cms-edit create from-json --file page.json # Create from file
644
+ cms-edit create from-json --file page.json --dry-run # Preview without writing
645
+ cat page.json | cms-edit create from-json # Pipe from stdin
646
+ ```
647
+
648
+ **Page JSON schema:**
649
+
650
+ ```json
651
+ {
652
+ "type": "page",
653
+ "slug": "/parent-coaching/digital-life-safety/cyberbullying",
654
+ "title": "Cyberbullying",
655
+ "description": "Optional meta description (SEO)",
656
+ "templateId": "contentful-template-entry-id",
657
+ "indexed": true,
658
+ "components": [
659
+ {
660
+ "contentType": "component",
661
+ "type": "HeroSimple",
662
+ "target": "content",
663
+ "fields": {
664
+ "heading": "Protecting Your Child from Cyberbullying",
665
+ "body": "## Why it matters\n\nContent here with **bold** and [links](https://example.com).",
666
+ "backgroundColour": "Yellow"
667
+ },
668
+ "links": [
669
+ { "type": "external", "label": "Download Guide", "href": "https://example.com/guide.pdf" },
670
+ { "type": "internal", "label": "Learn More", "slug": "/resources" }
671
+ ]
672
+ },
673
+ {
674
+ "contentType": "collection",
675
+ "type": "CardGrid",
676
+ "fields": { "heading": "Related topics" },
677
+ "items": [
678
+ {
679
+ "contentType": "component",
680
+ "type": "Card",
681
+ "fields": { "heading": "Screen Time" }
682
+ },
683
+ {
684
+ "existingId": "abc123def456",
685
+ "comment": "Reuse existing 'Emotional Regulation' card"
686
+ }
687
+ ]
688
+ },
689
+ {
690
+ "existingId": "xyz789ghi012",
691
+ "comment": "Shared 'Join BLK Now' CTA reused on every page"
692
+ }
693
+ ]
694
+ }
695
+ ```
696
+
697
+ **Article JSON schema:**
698
+
699
+ ```json
700
+ {
701
+ "type": "article",
702
+ "slug": "/resources/publications/cyberbullying/new-research-2025",
703
+ "title": "New Research on Cyberbullying 2025",
704
+ "description": "Key findings from the 2025 cyberbullying study.",
705
+ "articleTypeId": "3abcDef456ghi",
706
+ "date": "2025-04-14",
707
+ "components": [
708
+ {
709
+ "contentType": "component",
710
+ "type": "RichText",
711
+ "fields": {
712
+ "body": "## Introduction\n\nNew research shows..."
713
+ }
714
+ },
715
+ {
716
+ "contentType": "component",
717
+ "type": "CTA",
718
+ "target": "bottomContent",
719
+ "links": [
720
+ { "type": "external", "label": "Download Full Report", "href": "https://example.com/report.pdf" }
721
+ ]
722
+ }
723
+ ]
724
+ }
725
+ ```
726
+
727
+ - `type` defaults to `"page"`. Set `"type": "article"` (or include `articleTypeId`) for articles.
728
+ - `articleTypeId` is required for articles. Find valid IDs with `cms-edit list --type articleType`.
729
+ - `date` defaults to today (YYYY-MM-DD) if omitted.
730
+
731
+ **Key points:**
732
+ - Any component entry in `components` or `items` may use `{ existingId }` to link an existing entry instead of creating a new one.
733
+ - The same applies to `links` entries — use `{ existingId }` to attach an existing link entry.
734
+ - `fields.body` (and any value containing newlines or Markdown syntax) is automatically converted to Contentful rich text.
735
+ - `target` sets which content array to use: `topContent`, `content` (default), or `bottomContent`.
736
+ - All entries are created as **drafts**. A human must publish in Contentful.
737
+ - `--dry-run` prints the full plan without writing anything.
738
+
739
+ ## Find Existing Entries (for existingId)
740
+
741
+ When building page JSON that references existing entries, find their Contentful IDs first:
742
+
743
+ ```bash
744
+ # Search for a shared component by name
745
+ cms-edit search "join blk now" --type component --json
746
+ # → output includes "id" field — use this as existingId in your page JSON
747
+
748
+ # Browse all components of a specific type
749
+ cms-edit list --type component --filter 'fields.componentType=CTA'
750
+
751
+ # Confirm an entry before referencing it
752
+ cms-edit resolve 4xKj2abcDef
753
+ ```
754
+
755
+ ## Inventory & Status
756
+
757
+ Use `sitemap` to see all pages in a space with their publication status:
758
+
759
+ ```bash
760
+ cms-edit sitemap # All pages
761
+ cms-edit sitemap --prefix /parent-coaching # Filter by slug prefix
762
+ cms-edit sitemap --status draft # Draft pages only
763
+ cms-edit sitemap --sort updated # Most recently updated first
764
+ cms-edit sitemap --tree # Tree view
765
+ cms-edit sitemap --include page,article # Include articles
766
+ ```
767
+
768
+ **Note on bulk publish:** The tool cannot publish entries — all saves create drafts only. This is intentional. Review and publish drafts from the Contentful web app.
769
+
603
770
  ## Concurrent Sessions
604
771
 
605
772
  Use `--session <name>` or `CONTENTFUL_CMS_SESSION=<name>` to isolate parallel workflows.
@@ -0,0 +1,240 @@
1
+ ---
2
+ name: "Image Guide"
3
+ description: "Generate a comprehensive image guide (both Markdown and HTML) for a site's CMS image assets, with rich AI-generated visual descriptions and content relationship trees."
4
+ ---
5
+
6
+ # Skill: contentful-cms — Image Guide
7
+
8
+ Use this skill to generate a **fully enriched image guide** for a site. The guide documents every image in the CMS with:
9
+ - Rich visual descriptions generated by inspecting each image
10
+ - Content relationship tree showing which pages/components use each image
11
+ - Two output formats: Markdown (AI-consumable) and HTML (human reference)
12
+
13
+ The output files are written to the app's `docs/` directory (or a path you specify).
14
+
15
+ ## When to use
16
+
17
+ - Client or team wants a reference guide for all images in the CMS
18
+ - Need to know where a specific image is used across the site
19
+ - Preparing image guidance for AI agents that will be choosing images
20
+ - Auditing image coverage or identifying unused assets
21
+
22
+ ## Prerequisites
23
+
24
+ - `cms-edit` is configured for the target space (run `cms-edit health` to verify)
25
+ - You have read access to the image URLs (standard Contentful CDN URLs work)
26
+ - The app directory is known (e.g. `apps/example-brightlifekids/`)
27
+
28
+ ## Brand Context
29
+
30
+ Before starting, check if a brand context skill is available (e.g., "BrightLife Kids Brand Context"). If so, incorporate brand terminology in the descriptions and "When to use" guidance.
31
+
32
+ ---
33
+
34
+ ## Workflow
35
+
36
+ ### Step 0 — Load description cache
37
+
38
+ Each image's description is stored as its own small file to avoid token-limit issues when reading or writing:
39
+
40
+ ```
41
+ docs/descriptions/{assetId}.json
42
+ ```
43
+
44
+ **To check if an image is already cached:**
45
+ ```bash
46
+ ls docs/descriptions/{assetId}.json 2>/dev/null && echo "cached" || echo "not cached"
47
+ ```
48
+
49
+ **Per-image file format:**
50
+ ```json
51
+ {
52
+ "subjects": "...",
53
+ "setting": "...",
54
+ "composition": "...",
55
+ "colours": "...",
56
+ "mood": "...",
57
+ "style": "...",
58
+ "constraints": "...",
59
+ "whenToUse": "...",
60
+ "inspectedAt": "2026-04-15T10:00:00Z"
61
+ }
62
+ ```
63
+
64
+ **Write-through caching — CRITICAL:** After visually inspecting each NEW image, immediately write its description to `docs/descriptions/{assetId}.json` using the Write tool BEFORE inspecting the next image. One image → one Write call → next image. Each file is tiny (~1KB), so no token limits apply.
65
+
66
+ If `docs/descriptions/{assetId}.json` already exists, read it and use the cached data — **skip the vision call entirely**.
67
+
68
+ At the end of the run, report: `N from cache, M newly inspected`.
69
+
70
+ **Phase discipline — cache first, guides second:** Complete ALL image inspections and per-image cache writes before starting any guide file. Do not interleave inspection with guide writing.
71
+
72
+ > **Note:** If a legacy `docs/image-descriptions-cache.json` file exists, ignore it. The per-file cache supersedes it.
73
+
74
+ ### Step 1 — Gather structural data
75
+
76
+ Run the audit command to get all images and their page/component usages:
77
+
78
+ ```bash
79
+ cms-edit --json audit images
80
+ ```
81
+
82
+ This outputs JSON with every image asset including:
83
+ - Asset ID, title, filename, dimensions, MIME type, CDN URL
84
+ - `usages[]`: the slug-bearing ancestors (page, article, articleType, pageVariant, tag, person) that ultimately use this asset. Intermediate wrapper entries (media, visual, component, etc.) are walked through transparently and not included. Each usage has `{ id, contentType, label, slug }`.
85
+
86
+ Save the output to a temporary file or keep it in context.
87
+
88
+ If the output is large, focus on images grouped by page. Use `cms-edit audit tree --page /<slug>` to see the relationship tree for a specific page:
89
+
90
+ ```bash
91
+ cms-edit audit tree --page /
92
+ cms-edit audit tree --page /families
93
+ ```
94
+
95
+ ### Step 2 — Inspect each image visually
96
+
97
+ For each image in the JSON output, fetch the image URL and inspect it carefully. The CDN URL supports resize parameters — use `?w=800&q=85` for a good preview:
98
+
99
+ ```
100
+ https://images.ctfassets.net/{spaceId}/{assetId}/{hash}/{filename}?w=800&q=85
101
+ ```
102
+
103
+ For each image generate a **visual description** covering ALL of these fields:
104
+
105
+ | Field | What to capture |
106
+ |-------|----------------|
107
+ | **Subjects** | Count of people, apparent ages, genders (if relevant), expressions, what they are doing |
108
+ | **Setting** | Indoor/outdoor, room type or environment, background detail level, time of day |
109
+ | **Composition** | Landscape or portrait, crop tightness (headshot / mid-shot / wide / full-bleed), focal point position, negative space |
110
+ | **Colours** | 3–5 dominant colours with approximate descriptions (e.g. "warm cream, sage green, muted terracotta"), warm vs cool tone, contrast level |
111
+ | **Mood** | One or two words: playful, warm, clinical, energetic, calm, aspirational, inclusive, serious |
112
+ | **Style** | Photography (stock / custom-produced), illustration, icon, UI mockup, logo |
113
+ | **Constraints** | What the image does NOT have — e.g. "no text overlay space", "subject fills frame", "no negative space for overlay", "transparent background" |
114
+
115
+ For icons, logos, and UI mockups, the description can be shorter and focus on what the graphic represents and its visual style.
116
+
117
+ ### Step 3 — Determine "When to use" guidance
118
+
119
+ Based on the image's current usages and its visual content, write a concise "When to use" paragraph covering:
120
+ - Component types it suits (Hero, CtaCard, wide-format, etc.)
121
+ - Content topics or page contexts where it fits
122
+ - What NOT to use it for (age group constraints, format constraints, etc.)
123
+ - Any reuse notes (e.g. "also used as /partners hero — suitable for both card and full-width formats")
124
+
125
+ ### Step 4 — Write the Markdown guide
126
+
127
+ Output path: `docs/image-guide.md` inside the app directory (e.g. `apps/example-brightlifekids/docs/image-guide.md`).
128
+
129
+ **IMPORTANT — chunked writing to avoid output token limits:** The guide file will be large (many KB). Never try to write the entire file in a single Write tool call. Instead, use bash heredoc append operations in batches:
130
+
131
+ ```bash
132
+ # First call — write file header + first ~35 images (use actual app path)
133
+ cat > apps/example-brightlifekids/docs/image-guide.md << 'MDEOF'
134
+ # BrightLife Kids — Image Guide
135
+
136
+ > Generated 2026-04-15. Space: blk. 202 images documented.
137
+ ...
138
+ ## Image 1 · filename.jpg
139
+ ...
140
+ MDEOF
141
+
142
+ # Subsequent calls — APPEND next batch (note >>)
143
+ cat >> apps/example-brightlifekids/docs/image-guide.md << 'MDEOF'
144
+ ## Image 36 · filename.jpg
145
+ ...
146
+ MDEOF
147
+ ```
148
+
149
+ Keep each bash call to **35 images maximum** (~18,000 tokens of content per call). Use as many `cat >>` append calls as needed. For descriptions, read from the cached `docs/descriptions/{assetId}.json` files rather than re-inspecting.
150
+
151
+ Use this structure:
152
+
153
+ ```markdown
154
+ # {Brand} — Image Guide
155
+
156
+ > Generated {date}. Space: {spaceKey}. {N} images documented.
157
+ >
158
+ > **AI usage note**: Each entry below has consistent fields for programmatic selection.
159
+ > Match `Subjects`, `Setting`, and `Mood` to the content context. Use `Constraints` to
160
+ > rule out images that won't work for a given layout. `Used on` shows exact page/component context.
161
+
162
+ ---
163
+
164
+ ## {image title} · {filename}
165
+
166
+ **Asset ID**: `{id}`
167
+ **Dimensions**: {width}×{height} · {contentType}
168
+ **CDN URL**: `{url}?w=800&q=85`
169
+
170
+ **Used on**:
171
+ - {slug} — {contentType} "{label}"
172
+ - _(repeat for each usage; omit if usages array is empty — mark as "Unused / unattached")_
173
+
174
+ **Subjects**: {description}
175
+ **Setting**: {description}
176
+ **Composition**: {description}
177
+ **Colours**: {description}
178
+ **Mood**: {description}
179
+ **Style**: {description}
180
+ **Constraints**: {description}
181
+
182
+ **When to use**: {paragraph}
183
+
184
+ ---
185
+ ```
186
+
187
+ Repeat for every image. Group images by page/section using `## Section: {page title}` headings before each page's images, matching the structure the `audit images` output provides.
188
+
189
+ ### Step 5 — Write the HTML guide
190
+
191
+ Output path: `docs/image-guide.html` inside the app directory.
192
+
193
+ **IMPORTANT — chunked writing:** HTML files are much larger than Markdown. Use the same bash heredoc append strategy, but with **smaller batches of 15–20 image cards** per operation. Start with the full `<html>`, `<head>`, CSS, and opening body tags, then append cards in batches, then append the closing tags last.
194
+
195
+ The HTML guide is a self-contained human reference (no server needed). Model it on the existing `tmp/blk-image-guide.html` style but with the following enhancements:
196
+
197
+ 1. **Visual detail block**: Add a new `<div class="visual-detail-box">` section in each card containing the structured visual fields (Subjects, Setting, Composition, Colours, Mood, Style, Constraints) as a compact `<table>`.
198
+
199
+ 2. **Usage tree**: In the metadata table, expand the `Pages` row to show the full chain: `{pageSlug} → {componentType} "{label}" (field: {fieldName})`.
200
+
201
+ 3. **Site tree section**: Add a collapsible `<details>` section at the top of the page titled "Full Site Content Tree" that shows the inverse view — for each page, what images appear on it.
202
+
203
+ 4. **LLM note**: Update the LLM usage note at the top to reference the structured visual fields.
204
+
205
+ The HTML must:
206
+ - Be fully self-contained (inline CSS, no external dependencies)
207
+ - Work without a web server (file:// protocol)
208
+ - Match the brand colours of the target site
209
+ - Show thumbnail images with lazy loading
210
+
211
+ ### Step 6 — Verify and report
212
+
213
+ After writing both files, confirm:
214
+ 1. Every image from the `audit images` output has an entry in both files
215
+ 2. The "Used on" relationships match what `audit tree` shows
216
+ 3. The Markdown file is clean and can be read without a browser
217
+
218
+ Present a summary:
219
+
220
+ | Image | Pages used on | Visual description added | Notes |
221
+ |-------|--------------|--------------------------|-------|
222
+ | ... | ... | ✓ | ... |
223
+
224
+ Report the output paths and any images that had no usages (potential orphans).
225
+
226
+ ---
227
+
228
+ ## Tips
229
+
230
+ - **Efficient image inspection**: Fetch images in batches. Process all images for a page together before moving to the next page.
231
+ - **Orphaned assets**: Images with no usages (`usages: []` in the JSON) are likely unused. Flag them but still document them — they may be intentionally held in reserve.
232
+ - **SVG icons**: For SVG assets, use the direct URL (no resize params needed). Describe the graphic shape and colour precisely.
233
+ - **Stock vs custom**: Check the filename for patterns like `AdobeStock_`, `pexels-`, `unsplash-` to identify stock images. Custom-produced images typically have branded filenames.
234
+ - **Mobile variants**: Some components have both `visual` and `mobileVisual` fields. If the same image appears in both, note the dual-use in the description.
235
+
236
+ ## Related skills
237
+
238
+ - **core**: Full cms-edit workflow reference
239
+ - **alt-text-audit**: Audit and improve alt text on existing images
240
+ - **contentful-cms-screenshots**: Take live screenshots of pages for reference
@@ -5,6 +5,7 @@
5
5
  "rich-text": "Rich text (rtf) and embeds (append/insert); Markdown support",
6
6
  "screenshots": "Screenshot command, agent-browser requirement, mock vs live, --url-only",
7
7
  "alt-text-audit": "Audit and improve image alt text across site pages",
8
+ "image-guide": "Generate a comprehensive image guide (MD + HTML) with AI visual descriptions and content relationship trees",
8
9
  "seo-descriptions": "Generate or improve SEO meta descriptions for pages",
9
10
  "schema-org": "Generate Schema.org structured data as Mustache templates"
10
11
  }