@se-studio/project-build 1.0.104 → 1.0.105
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 +6 -0
- package/dist/management/sync-skills.d.ts +3 -1
- package/dist/management/sync-skills.d.ts.map +1 -1
- package/dist/management/sync-skills.js +25 -4
- package/dist/management/sync-skills.js.map +1 -1
- package/dist/seskills.js +10 -3
- package/dist/seskills.js.map +1 -1
- package/package.json +1 -1
- package/skills/contentful-cms/generate-cms-guidelines/SKILL.md +302 -0
- package/skills/se-marketing-sites/curate-showcase-mocks/SKILL.md +340 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
export declare function syncSkills(targetDir?: string
|
|
1
|
+
export declare function syncSkills(targetDir?: string,
|
|
2
|
+
/** When true, exits silently (code 0) if not running as an installed package. Safe for postinstall. */
|
|
3
|
+
ifInstalled?: boolean): Promise<void>;
|
|
2
4
|
//# sourceMappingURL=sync-skills.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-skills.d.ts","sourceRoot":"","sources":["../../src/management/sync-skills.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync-skills.d.ts","sourceRoot":"","sources":["../../src/management/sync-skills.ts"],"names":[],"mappings":"AAmCA,wBAAsB,UAAU,CAC9B,SAAS,GAAE,MAAsB;AACjC,uGAAuG;AACvG,WAAW,UAAQ,iBAsCpB"}
|
|
@@ -17,16 +17,37 @@ async function copyDir(src, dest) {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Returns true when this script is running from inside a pnpm/npm workspace
|
|
22
|
+
* (i.e. as a local package, not as an installed dependency from the registry).
|
|
23
|
+
*
|
|
24
|
+
* Detection: if the path to this file does NOT contain "node_modules" then we
|
|
25
|
+
* are running from the workspace source — syncing would overwrite the canonical
|
|
26
|
+
* skill files with the distributed copies, which is the wrong direction.
|
|
27
|
+
*/
|
|
28
|
+
function isWorkspacePackage() {
|
|
29
|
+
return !__dirname.includes('node_modules');
|
|
30
|
+
}
|
|
31
|
+
export async function syncSkills(targetDir = process.cwd(),
|
|
32
|
+
/** When true, exits silently (code 0) if not running as an installed package. Safe for postinstall. */
|
|
33
|
+
ifInstalled = false) {
|
|
34
|
+
if (isWorkspacePackage()) {
|
|
35
|
+
if (ifInstalled) {
|
|
36
|
+
// Running inside the monorepo during a workspace install — skip silently.
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
console.warn('Warning: seskills sync is running from a workspace package (not from node_modules).\n' +
|
|
40
|
+
'Skipping to avoid overwriting canonical skill files in the monorepo.\n' +
|
|
41
|
+
'Run `seskills sync` from an external project that has @se-studio/project-build installed.');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
21
44
|
// Locate the skills directory relative to this file (dist/management/sync-skills.js)
|
|
22
|
-
//
|
|
23
|
-
// dist/management/ -> dist/ -> root -> skills
|
|
45
|
+
// dist/management/ -> dist/ -> package root -> skills/
|
|
24
46
|
const packageRoot = path.resolve(__dirname, '..', '..');
|
|
25
47
|
const skillsSourceDir = path.join(packageRoot, 'skills');
|
|
26
48
|
const skillsTargetDir = path.join(targetDir, '.cursor', 'skills');
|
|
27
49
|
console.log(`Syncing skills from ${skillsSourceDir} to ${skillsTargetDir}...`);
|
|
28
50
|
try {
|
|
29
|
-
// Check if source exists
|
|
30
51
|
try {
|
|
31
52
|
await fs.promises.access(skillsSourceDir);
|
|
32
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-skills.js","sourceRoot":"","sources":["../../src/management/sync-skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC9C,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAExE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAE7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,
|
|
1
|
+
{"version":3,"file":"sync-skills.js","sourceRoot":"","sources":["../../src/management/sync-skills.ts"],"names":[],"mappings":"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"}
|
package/dist/seskills.js
CHANGED
|
@@ -10,11 +10,18 @@ async function main() {
|
|
|
10
10
|
const args = process.argv.slice(2);
|
|
11
11
|
const command = args[0];
|
|
12
12
|
if (command === 'sync') {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// Filter out flags from positional args
|
|
14
|
+
const positional = args.slice(1).filter((a) => !a.startsWith('--'));
|
|
15
|
+
const ifInstalled = args.includes('--if-installed');
|
|
16
|
+
const targetDir = positional[0] || process.cwd();
|
|
17
|
+
await syncSkills(targetDir, ifInstalled);
|
|
15
18
|
}
|
|
16
19
|
else {
|
|
17
|
-
console.log('Usage: seskills sync [target-dir]');
|
|
20
|
+
console.log('Usage: seskills sync [target-dir] [--if-installed]');
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log(' --if-installed Exit silently when running as a workspace package.');
|
|
23
|
+
console.log(' Use this in a postinstall script so it only runs in');
|
|
24
|
+
console.log(' external projects, not inside the monorepo.');
|
|
18
25
|
process.exit(1);
|
|
19
26
|
}
|
|
20
27
|
}
|
package/dist/seskills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seskills.js","sourceRoot":"","sources":["../src/seskills.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,
|
|
1
|
+
{"version":3,"file":"seskills.js","sourceRoot":"","sources":["../src/seskills.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,wCAAwC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACpD,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACjD,MAAM,UAAU,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;QACpF,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Skill: Generate CMS Guidelines
|
|
2
|
+
|
|
3
|
+
Use this skill when you need to generate, regenerate, or merge CMS guideline markdown fragments for any app in the monorepo.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When to use this skill
|
|
8
|
+
|
|
9
|
+
- **Full from scratch:** Generating guidelines for all components, collections, and externals in an app for the first time.
|
|
10
|
+
- **Single type:** Regenerating the guideline for one component, collection, or external (e.g. after editing the component code).
|
|
11
|
+
- **Merge only:** Rebuilding `COMPONENT_GUIDELINES_FOR_LLM.md` after manual edits to guideline fragments.
|
|
12
|
+
- **Regenerate all:** Re-running everything after bulk code changes or prompt tweaks.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Prerequisite: Showcase lifecycle
|
|
17
|
+
|
|
18
|
+
Guidelines are only meaningful when the showcase is populated with realistic data. Complete these steps **before** running guideline generation for the first time:
|
|
19
|
+
|
|
20
|
+
1. **Build the site** and ensure all content is correct and published in Contentful.
|
|
21
|
+
2. **Generate showcase data:**
|
|
22
|
+
```bash
|
|
23
|
+
pnpm --filter <appName> generate-showcase
|
|
24
|
+
```
|
|
25
|
+
This writes `src/cms-showcase/showcase-examples.json` to the app.
|
|
26
|
+
3. **Curate showcase mocks:** Follow the [curate-showcase-mocks skill](.cursor/skills/se-marketing-sites/curate-showcase-mocks/SKILL.md) to produce `showcase-mocks.json`.
|
|
27
|
+
4. **Generate field list:**
|
|
28
|
+
```bash
|
|
29
|
+
# From the app directory:
|
|
30
|
+
pnpm run cms-discovery:field-list
|
|
31
|
+
# Or from repo root:
|
|
32
|
+
pnpm --filter <appName> exec cms-generate-field-list --app-dir .
|
|
33
|
+
```
|
|
34
|
+
This writes `generated/cms-discovery/field-list.json`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Inputs
|
|
39
|
+
|
|
40
|
+
| Input | Description |
|
|
41
|
+
|---|---|
|
|
42
|
+
| **App directory** | Repo-relative path, e.g. `apps/example-om1` or `apps/example-se2026` |
|
|
43
|
+
| **Mode** | `full` \| `single` \| `merge-only` |
|
|
44
|
+
| **Type name** | Required for `single` mode — the exact type name from discovery, e.g. `"Hero"` or `"Cards Grid"` |
|
|
45
|
+
| **Discovery URL** | URL to the live app's discovery endpoint, e.g. `http://localhost:3013/api/cms/discovery/` |
|
|
46
|
+
|
|
47
|
+
**App ports** (app must be running for `full` and `single` modes):
|
|
48
|
+
|
|
49
|
+
| App | Port | Discovery URL |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| example-brightline | 3010 | `http://localhost:3010/api/cms/discovery/` |
|
|
52
|
+
| example-se2026 | 3012 | `http://localhost:3012/api/cms/discovery/` |
|
|
53
|
+
| example-om1 | 3013 | `http://localhost:3013/api/cms/discovery/` |
|
|
54
|
+
| example-empty | 3014 | `http://localhost:3014/api/cms/discovery/` |
|
|
55
|
+
| example-brightlifekids | 3015 | `http://localhost:3015/api/cms/discovery/` |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Mode: full
|
|
60
|
+
|
|
61
|
+
Run all steps from scratch. Generates guidelines for all collections, externals, and components.
|
|
62
|
+
|
|
63
|
+
### Step 1 — Verify prerequisites
|
|
64
|
+
|
|
65
|
+
Confirm that:
|
|
66
|
+
- The app is running (check `http://localhost:<port>/api/cms/discovery/` returns JSON).
|
|
67
|
+
- `generated/cms-discovery/field-list.json` exists in the app directory.
|
|
68
|
+
- Showcase has been generated (see Prerequisite section above).
|
|
69
|
+
|
|
70
|
+
### Step 2 — Generate collections and externals
|
|
71
|
+
|
|
72
|
+
Run the project-independent generator. It reads discovery, writes all `collections/*.md`, creates any missing `externals/*.md` templates, and updates `colour-hints.json`:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cms-generate-collection-guidelines \
|
|
76
|
+
--discovery-url <discoveryUrl> \
|
|
77
|
+
--app-dir <appDir>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Overwrite behaviour:**
|
|
81
|
+
- **Collections:** always overwritten (regenerated from discovery on each run).
|
|
82
|
+
- **Externals:** created only if the file does not exist. Existing external files are preserved to protect hand-authored schema documentation.
|
|
83
|
+
|
|
84
|
+
### Step 2b — Fill in external component schemas (first time only)
|
|
85
|
+
|
|
86
|
+
For each external component file created in `docs/cms-guidelines/externals/`, open the file and fill in the **Fields & Schema** and **Usage** sections. These files are not regenerated once created, so the schema documentation you add here is permanent.
|
|
87
|
+
|
|
88
|
+
For each external type:
|
|
89
|
+
1. Check the Contentful content type schema (or ask the project owner) for the list of fields, their types, and purpose.
|
|
90
|
+
2. Replace the `<!-- TODO: ... -->` block in `## Fields & Schema` with a filled-in Markdown table.
|
|
91
|
+
3. Replace the `## Usage` placeholder with a short description of how to add and configure the component via `cms-edit`.
|
|
92
|
+
4. Commit the completed files to version control.
|
|
93
|
+
|
|
94
|
+
Example of a completed `## Fields & Schema` section:
|
|
95
|
+
|
|
96
|
+
```markdown
|
|
97
|
+
## Fields & Schema
|
|
98
|
+
|
|
99
|
+
| Field | Type | Required | Notes |
|
|
100
|
+
|-------|------|----------|-------|
|
|
101
|
+
| externalComponentType | Symbol | Yes | Must be set to `ResearchChart` |
|
|
102
|
+
| data | Object | No | Chart config payload — see project data-viz spec |
|
|
103
|
+
| cmsLabel | Symbol | Yes | Internal label for CMS authoring |
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Step 3 — Generate component guidelines
|
|
107
|
+
|
|
108
|
+
For each component in discovery order, run the full per-component pipeline defined in
|
|
109
|
+
[`packages/contentful-cms/skills/cms-guidelines/generate-component-guidelines.md`](../../../packages/contentful-cms/skills/cms-guidelines/generate-component-guidelines.md).
|
|
110
|
+
|
|
111
|
+
To find unfinished components:
|
|
112
|
+
1. Fetch `<discoveryUrl>` and collect all `components[].name` values.
|
|
113
|
+
2. Compute slug for each: `name.toLowerCase().replace(/\s+/g, '-').replace(/[()]/g, '')`.
|
|
114
|
+
3. Check which slugs lack a corresponding file in `<appDir>/docs/cms-guidelines/components/<slug>.md`.
|
|
115
|
+
4. Process only the unfinished ones (or all, if regenerating).
|
|
116
|
+
|
|
117
|
+
**For each unfinished component** (process in batches of 5 if preferred):
|
|
118
|
+
|
|
119
|
+
Run a Cursor subagent with this prompt, substituting `<COMPONENT_TYPE>` and `<APP_DIR>`:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Run the full guideline generation pipeline for <COMPONENT_TYPE>.
|
|
123
|
+
Target app: <APP_DIR> (all paths relative to repo root / that directory).
|
|
124
|
+
|
|
125
|
+
Read these pipeline docs first (they are in packages/contentful-cms/skills/cms-guidelines/):
|
|
126
|
+
- generate-component-guidelines.md (overall pipeline)
|
|
127
|
+
- variant-loop.md (Phase A: variant loop)
|
|
128
|
+
- generation-prompt.md (Phase B: generation)
|
|
129
|
+
- colour-hint-prompt.md (Phase C: colour hint)
|
|
130
|
+
- validation-prompt.md (Phase D: validation)
|
|
131
|
+
|
|
132
|
+
=== Phase A: Variant loop ===
|
|
133
|
+
Follow variant-loop.md.
|
|
134
|
+
1. Read src/project/components/<TypeName>.tsx (or collections/<TypeName>.tsx).
|
|
135
|
+
2. Read generated/cms-discovery/field-list.json for field metadata.
|
|
136
|
+
3. Propose 5 variants using variant-proposal-prompt.md.
|
|
137
|
+
4. Capture screenshots:
|
|
138
|
+
cms-capture-screenshots --variants /tmp/<type-slug>-variants.json --app-dir <APP_DIR>
|
|
139
|
+
This also updates docs/cms-guidelines/screenshots/index.json automatically.
|
|
140
|
+
5. Evaluate screenshots using evaluation-prompt.md.
|
|
141
|
+
When done: save accepted list to generated/cms-discovery/accepted-variants/<type-slug>.json
|
|
142
|
+
|
|
143
|
+
=== Phase B: Generate guideline ===
|
|
144
|
+
Follow generation-prompt.md.
|
|
145
|
+
1. Describe screenshots (Step 1 prompt).
|
|
146
|
+
2. Extract behaviour from code (Step 2 prompt).
|
|
147
|
+
3. Merge into guideline block (Step 3 prompt).
|
|
148
|
+
IMPORTANT: Read docs/cms-guidelines/screenshots/index.json and .contentful-cms.json first.
|
|
149
|
+
The guideline must include a ## Screenshots section with image links:
|
|
150
|
+

|
|
151
|
+
Only include variants present in index.json. Use devBaseUrl from .contentful-cms.json.
|
|
152
|
+
4. Save to docs/cms-guidelines/components/<type-slug>.md.
|
|
153
|
+
|
|
154
|
+
=== Phase C: Colour hint ===
|
|
155
|
+
Follow colour-hint-prompt.md.
|
|
156
|
+
Run:
|
|
157
|
+
cms-update-colour-hints --app-dir <APP_DIR> \
|
|
158
|
+
--type "<COMPONENT_TYPE>" --hint "<hint>" --notes "<brief reason>"
|
|
159
|
+
|
|
160
|
+
=== Phase D: Validate ===
|
|
161
|
+
Follow validation-prompt.md. Apply fixes until APPROVED.
|
|
162
|
+
|
|
163
|
+
Do NOT run merge yet — merge runs once after all components.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Step 4 — Merge
|
|
167
|
+
|
|
168
|
+
After all components are done, run merge:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
cms-merge-guidelines --app-dir <appDir>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Or from the app directory: `pnpm run cms-guidelines:merge`
|
|
175
|
+
|
|
176
|
+
### Step 5 — Commit (optional)
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
git add <appDir>/docs/cms-guidelines/ <appDir>/generated/cms-discovery/
|
|
180
|
+
git commit -m "chore(<app>): generate all CMS guidelines"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Mode: single
|
|
186
|
+
|
|
187
|
+
Regenerate the guideline for one type. Useful after editing a component's code.
|
|
188
|
+
|
|
189
|
+
### Step 1 — Fetch discovery to determine type category
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
curl -sL '<discoveryUrl>' | node -e "
|
|
193
|
+
const data = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
|
194
|
+
const name = '<TYPE_NAME>';
|
|
195
|
+
const inComponents = data.components.some(c => c.name === name);
|
|
196
|
+
const inCollections = data.collections.some(c => c.name === name);
|
|
197
|
+
const inExternals = data.externals.some(c => c.name === name);
|
|
198
|
+
console.log(inComponents ? 'component' : inCollections ? 'collection' : inExternals ? 'external' : 'not found');
|
|
199
|
+
"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Step 2a — If component
|
|
203
|
+
|
|
204
|
+
Run the full per-component pipeline (Phases A–D) from the subagent prompt in Mode: full → Step 3, for just this one type.
|
|
205
|
+
|
|
206
|
+
### Step 2b — If collection or external
|
|
207
|
+
|
|
208
|
+
For a **collection:** re-run the generator — it always overwrites collection files:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
cms-generate-collection-guidelines \
|
|
212
|
+
--discovery-url <discoveryUrl> \
|
|
213
|
+
--app-dir <appDir>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For an **external:** the generator will not overwrite an existing file. Edit `docs/cms-guidelines/externals/<slug>.md` directly, updating the `## Fields & Schema` and `## Usage` sections as needed. If you need to regenerate from the template (e.g. for a new external), delete the file first and re-run the generator, then fill in the schema sections.
|
|
217
|
+
|
|
218
|
+
### Step 3 — Merge
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
cms-merge-guidelines --app-dir <appDir>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Mode: merge-only
|
|
227
|
+
|
|
228
|
+
Use when guideline fragments have been edited manually or generated outside this skill.
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
cms-merge-guidelines --app-dir <appDir>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Or from the app directory: `pnpm run cms-guidelines:merge`
|
|
235
|
+
|
|
236
|
+
This rebuilds `docs/cms-guidelines/COMPONENT_GUIDELINES_FOR_LLM.md` from all existing `components/*.md`, `collections/*.md`, and `externals/*.md` fragments.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Output files
|
|
241
|
+
|
|
242
|
+
All produced under `<appDir>`:
|
|
243
|
+
|
|
244
|
+
| File | Description |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `docs/cms-guidelines/components/<slug>.md` | Per-component guideline fragment (includes screenshot links) |
|
|
247
|
+
| `docs/cms-guidelines/collections/<slug>.md` | Per-collection guideline fragment |
|
|
248
|
+
| `docs/cms-guidelines/externals/<slug>.md` | Per-external guideline fragment |
|
|
249
|
+
| `docs/cms-guidelines/screenshots/index.json` | Index of all captured screenshots (type, variant, file, date) |
|
|
250
|
+
| `docs/cms-guidelines/COMPONENT_GUIDELINES_FOR_LLM.md` | Merged full document (includes screenshot links) |
|
|
251
|
+
| `generated/cms-discovery/accepted-variants/<slug>.json` | Accepted variant list (components only) |
|
|
252
|
+
| `generated/cms-discovery/colour-hints.json` | Colour application hints for all types |
|
|
253
|
+
|
|
254
|
+
### Screenshot links in guidelines
|
|
255
|
+
|
|
256
|
+
Each component guideline contains a `## Screenshots` section with image links:
|
|
257
|
+
|
|
258
|
+
```markdown
|
|
259
|
+
## Screenshots
|
|
260
|
+
|
|
261
|
+
| Variant | Preview |
|
|
262
|
+
|---------|---------|
|
|
263
|
+
| Default |  |
|
|
264
|
+
| Navy |  |
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
These links:
|
|
268
|
+
- Resolve when the dev server is running (the `/cms/screenshot` route serves the PNG files)
|
|
269
|
+
- Use the `devBaseUrl` from `.contentful-cms.json` for the host
|
|
270
|
+
- Work for both human reviewers browsing the guidelines and AI assistants reading the markdown
|
|
271
|
+
- Are preserved in `COMPONENT_GUIDELINES_FOR_LLM.md` when `cms-merge-guidelines` runs
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Pipeline reference
|
|
276
|
+
|
|
277
|
+
All per-component pipeline docs live in `packages/contentful-cms/skills/cms-guidelines/`:
|
|
278
|
+
|
|
279
|
+
| File | Purpose |
|
|
280
|
+
|---|---|
|
|
281
|
+
| `generate-component-guidelines.md` | Full pipeline overview (Phases A–F) |
|
|
282
|
+
| `variant-loop.md` | Phase A: propose → screenshot → evaluate |
|
|
283
|
+
| `variant-proposal-prompt.md` | LLM prompt for proposing variants |
|
|
284
|
+
| `evaluation-prompt.md` | LLM prompt for evaluating screenshots |
|
|
285
|
+
| `generation-prompt.md` | Phase B: three-step guideline generation |
|
|
286
|
+
| `colour-hint-prompt.md` | Phase C: derive colour application hint |
|
|
287
|
+
| `validation-prompt.md` | Phase D: 9-check validation |
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## New CLI reference
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
cms-generate-collection-guidelines --discovery-url <url> --app-dir <path>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
| Flag | Description |
|
|
298
|
+
|---|---|
|
|
299
|
+
| `--discovery-url <url>` | Discovery API URL (required). App must be running. |
|
|
300
|
+
| `--app-dir <path>` | App directory (default: cwd). |
|
|
301
|
+
|
|
302
|
+
Writes `docs/cms-guidelines/collections/*.md`, `docs/cms-guidelines/externals/*.md`, and updates `generated/cms-discovery/colour-hints.json`. Project-independent: works for any app in the monorepo.
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: curate-showcase-mocks
|
|
3
|
+
description: Extracts real component/collection data from Contentful and curates the best examples into showcase-mocks.json, making the CMS showcase display realistic content instead of generic placeholder text.
|
|
4
|
+
license: Private
|
|
5
|
+
metadata:
|
|
6
|
+
author: se-core-product
|
|
7
|
+
version: "2.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Curate Showcase Mocks
|
|
11
|
+
|
|
12
|
+
This skill refreshes the CMS showcase with realistic content from the live Contentful space.
|
|
13
|
+
It uses a **two-phase CLI pipeline** — extraction followed by LLM-driven curation — to produce
|
|
14
|
+
`src/generated/showcase-mocks.json`, which the showcase loads at runtime.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
Run this skill when:
|
|
19
|
+
- A new app has been populated in Contentful and the showcase still shows placeholder text
|
|
20
|
+
- The CMS content has been significantly updated and the showcase looks stale
|
|
21
|
+
- New component or collection types have been added and need good mock data
|
|
22
|
+
|
|
23
|
+
## Prerequisites
|
|
24
|
+
|
|
25
|
+
- The app's `.env.local` must contain `CONTENTFUL_SPACE_ID`, `CONTENTFUL_ACCESS_TOKEN`, and `CONTENTFUL_ENVIRONMENT_NAME`
|
|
26
|
+
- An LLM API key in `.env.local`: `OPENAI_API_KEY` (preferred) or `ANTHROPIC_API_KEY`
|
|
27
|
+
- Optional: `CONTENTFUL_PREVIEW_ACCESS_TOKEN` to also include draft/unpublished entries
|
|
28
|
+
- For monorepo apps: all packages must be built (`pnpm build` from repo root)
|
|
29
|
+
- The app must be fully set up (see **First-time setup** below if not yet done)
|
|
30
|
+
|
|
31
|
+
## First-time setup (new apps)
|
|
32
|
+
|
|
33
|
+
Before running this skill on a new app, four one-time changes are required.
|
|
34
|
+
|
|
35
|
+
### 1 — Add scripts to `package.json`
|
|
36
|
+
|
|
37
|
+
**Monorepo app** (uses local packages via relative paths):
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
"generate-showcase": "node ../../packages/project-build/dist/generate-showcase-data.js",
|
|
41
|
+
"generate-showcase-mocks": "node ../../packages/project-build/dist/generate-showcase-mocks.js"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**External/standalone project** (uses npm-installed packages):
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
"generate-showcase": "node node_modules/@se-studio/project-build/dist/generate-showcase-data.js",
|
|
48
|
+
"generate-showcase-mocks": "node node_modules/@se-studio/project-build/dist/generate-showcase-mocks.js"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Alternatively for external projects, use the installed binaries directly (available on PATH after install):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
generate-showcase-data # runs in-place from the project root
|
|
55
|
+
generate-showcase-mocks
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2 — Gitignore the generated files
|
|
59
|
+
|
|
60
|
+
In the app's `.gitignore`, add:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
# Generated showcase files (large, regenerable — curated mocks committed separately)
|
|
64
|
+
src/generated/showcase-examples.json
|
|
65
|
+
src/generated/showcase-mocks-draft.json
|
|
66
|
+
src/generated/cms-discovery/accepted-variants/
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3 — Wire the render pages to use curated mocks
|
|
70
|
+
|
|
71
|
+
Both `src/app/(cms-dev)/cms/showcase/render/page.tsx` and `render-all/page.tsx` need to import
|
|
72
|
+
`mergeShowcaseMocks` and the curated mocks file.
|
|
73
|
+
|
|
74
|
+
**`render/page.tsx`** — change from:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { DEFAULT_SHOWCASE_CONTROL_STATE, ShowcaseRenderPage } from '@se-studio/core-ui';
|
|
78
|
+
// ... other imports ...
|
|
79
|
+
|
|
80
|
+
export default async function Page(...) {
|
|
81
|
+
return (
|
|
82
|
+
<ShowcaseRenderPage
|
|
83
|
+
componentMockMap={componentMockMap}
|
|
84
|
+
collectionMockMap={collectionMockMap}
|
|
85
|
+
collectionCardMockMap={collectionCardMockMap}
|
|
86
|
+
...
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
to:
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { DEFAULT_SHOWCASE_CONTROL_STATE, ShowcaseRenderPage, mergeShowcaseMocks } from '@se-studio/core-ui';
|
|
96
|
+
// ... other imports ...
|
|
97
|
+
import curatedMocks from '@/generated/showcase-mocks.json';
|
|
98
|
+
|
|
99
|
+
const { componentMockMap: mergedComponentMocks, collectionMockMap: mergedCollectionMocks, collectionCardMockMap: mergedCardMocks } =
|
|
100
|
+
mergeShowcaseMocks(curatedMocks, { componentMockMap, collectionMockMap, collectionCardMockMap });
|
|
101
|
+
|
|
102
|
+
export default async function Page(...) {
|
|
103
|
+
return (
|
|
104
|
+
<ShowcaseRenderPage
|
|
105
|
+
componentMockMap={mergedComponentMocks}
|
|
106
|
+
collectionMockMap={mergedCollectionMocks}
|
|
107
|
+
collectionCardMockMap={mergedCardMocks}
|
|
108
|
+
...
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Apply the same pattern to **`render-all/page.tsx`**.
|
|
115
|
+
|
|
116
|
+
### 4 — Create an empty `showcase-mocks.json` stub
|
|
117
|
+
|
|
118
|
+
Create `src/generated/showcase-mocks.json` so the import compiles before curated data exists:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"curatedAt": "2026-01-01T00:00:00.000Z",
|
|
123
|
+
"components": {},
|
|
124
|
+
"collections": {}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Once these four steps are done, proceed with the steps below.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Pipeline Overview
|
|
133
|
+
|
|
134
|
+
The workflow is now a **three-step pipeline**:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Step 1: generate-showcase-data → showcase-examples.json (all CMS data, sorted by completeness)
|
|
138
|
+
Step 2: generate-showcase-mocks → showcase-mocks-draft.json (LLM selects best + proposes variants)
|
|
139
|
+
Step 3: AI review (this skill) → showcase-mocks.json (final curated mocks, committed)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Steps 1 and 2 are automated CLI commands. Step 3 is where you (the AI) review the draft,
|
|
143
|
+
adjust anything the LLM got wrong, handle layout variants, and write the final committed file.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Steps
|
|
148
|
+
|
|
149
|
+
### Step 1 — Run the extraction script
|
|
150
|
+
|
|
151
|
+
Run the CLI to fetch all component/collection entries from Contentful:
|
|
152
|
+
|
|
153
|
+
**Monorepo:**
|
|
154
|
+
```bash
|
|
155
|
+
pnpm --filter {appName} generate-showcase
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**External project (from project root):**
|
|
159
|
+
```bash
|
|
160
|
+
node node_modules/@se-studio/project-build/dist/generate-showcase-data.js
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Optional flags:**
|
|
164
|
+
- `--include-drafts` — also fetches draft/unpublished entries via the Preview API (requires `CONTENTFUL_PREVIEW_ACCESS_TOKEN`)
|
|
165
|
+
- `--all-types` — fetches all entry content types without a filter (instead of fetching component and collection separately)
|
|
166
|
+
|
|
167
|
+
This writes `src/generated/showcase-examples.json` — every example grouped by type, sorted by
|
|
168
|
+
`fieldCompleteness` descending. This file is gitignored.
|
|
169
|
+
|
|
170
|
+
### Step 2 — Run the LLM curation script
|
|
171
|
+
|
|
172
|
+
**Monorepo:**
|
|
173
|
+
```bash
|
|
174
|
+
pnpm --filter {appName} generate-showcase-mocks
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**External project:**
|
|
178
|
+
```bash
|
|
179
|
+
node node_modules/@se-studio/project-build/dist/generate-showcase-mocks.js
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This reads `showcase-examples.json`, calls the LLM (OpenAI or Anthropic — auto-detected from
|
|
183
|
+
`.env.local`), and produces:
|
|
184
|
+
- `src/generated/showcase-mocks-draft.json` — best mock per type + proposed variant param sets
|
|
185
|
+
- `src/generated/cms-discovery/accepted-variants/<slug>.json` — per-type variant files
|
|
186
|
+
|
|
187
|
+
**Optional flags:**
|
|
188
|
+
- `--model <model>` — override the LLM model (e.g. `--model gpt-4o`)
|
|
189
|
+
- `--types <Type1,Type2>` — limit to specific type names (comma-separated, useful for re-running single types)
|
|
190
|
+
|
|
191
|
+
### Step 3 — Read the draft and registrations
|
|
192
|
+
|
|
193
|
+
Read these files:
|
|
194
|
+
|
|
195
|
+
1. `src/generated/showcase-mocks-draft.json` — the LLM's selected mocks + variant proposals
|
|
196
|
+
2. `src/lib/registrations.ts` — the app's component/collection registrations
|
|
197
|
+
|
|
198
|
+
From the registrations file, collect:
|
|
199
|
+
- The full list of registered component type names
|
|
200
|
+
- The full list of registered collection type names
|
|
201
|
+
- Any registrations with `showcaseExclude: true` — these types must be skipped entirely
|
|
202
|
+
|
|
203
|
+
Check the draft against the registrations: are there registered types missing from the draft?
|
|
204
|
+
If so, check `showcase-examples.json` directly to find examples for those types.
|
|
205
|
+
|
|
206
|
+
### Step 4 — Review and refine mocks
|
|
207
|
+
|
|
208
|
+
For each type in the draft:
|
|
209
|
+
|
|
210
|
+
**Validate the LLM selection:**
|
|
211
|
+
- Confirm the selected mock has a real heading (not a test entry)
|
|
212
|
+
- Confirm it has a working visual URL (if the field exists)
|
|
213
|
+
- Confirm the mock fields are complete and reflect real brand content
|
|
214
|
+
|
|
215
|
+
**Add layout variants not in the CMS:**
|
|
216
|
+
Some types have meaningful variants that may not exist as separate CMS entries — a flipped
|
|
217
|
+
layout, a narrow/wide version, or a no-visual state. These can be represented by adjusting
|
|
218
|
+
the base mock with URL param overrides. Review each type's variant proposals from the LLM
|
|
219
|
+
(in `showcase-mocks-draft.json`) and add any important ones that are missing:
|
|
220
|
+
|
|
221
|
+
- For a Hero with a left-layout variant: add a variant with `{ "showcaseParams": { "flip": "true" } }` or similar
|
|
222
|
+
- For a content block with a narrow option: `{ "showcaseParams": { "width": "narrow" } }`
|
|
223
|
+
- Adjust the LLM's proposed params to match the actual param names used in the component's showcase controls
|
|
224
|
+
|
|
225
|
+
**For collections — curating cards:**
|
|
226
|
+
- Select ALL cards from the best example (do not cap — use the real count)
|
|
227
|
+
- If fewer than 4 cards, check the next-best example for additional cards
|
|
228
|
+
- Cards with no heading and no body are useless — skip them
|
|
229
|
+
|
|
230
|
+
### Step 5 — Write showcase-mocks.json
|
|
231
|
+
|
|
232
|
+
Write the curated data to `src/generated/showcase-mocks.json`. This file IS committed to git.
|
|
233
|
+
|
|
234
|
+
Use the LLM draft as the starting point and apply your corrections from Step 4.
|
|
235
|
+
|
|
236
|
+
**Format:**
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"curatedAt": "2026-02-28T14:00:00.000Z",
|
|
241
|
+
"components": {
|
|
242
|
+
"Hero": {
|
|
243
|
+
"heading": "Mental health care for kids and teens. Parenting support for you.",
|
|
244
|
+
"preHeading": "Brightline",
|
|
245
|
+
"body": { "json": { "nodeType": "document", "content": [...] } },
|
|
246
|
+
"visual": { "width": 1200, "height": 800, "url": "https://images.ctfassets.net/..." },
|
|
247
|
+
"backgroundColour": "Off White"
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"collections": {
|
|
251
|
+
"FAQ": {
|
|
252
|
+
"mock": { "heading": "Top FAQs" },
|
|
253
|
+
"cards": [
|
|
254
|
+
{ "heading": "Who is Brightline?", "body": { "json": { ... } } }
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Rules for the output:**
|
|
262
|
+
- Set `curatedAt` to the current ISO timestamp
|
|
263
|
+
- Only include types that have real CMS data
|
|
264
|
+
- For component mocks: include only fields present in the source data
|
|
265
|
+
- For collection mocks: always include `mock` and `cards`
|
|
266
|
+
- Rich Text body fields must be `{ "json": <Document> }` — copy as-is
|
|
267
|
+
- Visual fields must include `width`, `height`, AND `url` — never strip `url`
|
|
268
|
+
- Include `widthPercent` when present on media/externalVideo entries
|
|
269
|
+
- Include `otherMedia` when present — copy the full array including `url` and `widthPercent`
|
|
270
|
+
- Do NOT invent or modify content — use the real data from the examples file
|
|
271
|
+
- Include `backgroundColour` and `textColour` where the source has them
|
|
272
|
+
- For cards: include ALL fields present in source, including `backgroundColour`, `textColour`, `links`
|
|
273
|
+
|
|
274
|
+
### Step 6 — Verify
|
|
275
|
+
|
|
276
|
+
After writing, briefly confirm:
|
|
277
|
+
- The file is valid JSON
|
|
278
|
+
- Component and collection counts look reasonable (non-zero)
|
|
279
|
+
- Key types (Hero, main collections) have entries
|
|
280
|
+
- Visual fields include `url` properties
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Output files
|
|
285
|
+
|
|
286
|
+
| File | Location | Committed |
|
|
287
|
+
|------|----------|-----------|
|
|
288
|
+
| `showcase-examples.json` | `src/generated/showcase-examples.json` | No (gitignored) |
|
|
289
|
+
| `showcase-mocks-draft.json` | `src/generated/showcase-mocks-draft.json` | No (gitignored) |
|
|
290
|
+
| `accepted-variants/` | `src/generated/cms-discovery/accepted-variants/` | No (gitignored) |
|
|
291
|
+
| `showcase-mocks.json` | `src/generated/showcase-mocks.json` | Yes |
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## How the showcase uses this
|
|
296
|
+
|
|
297
|
+
The showcase uses a **two-layer model**:
|
|
298
|
+
|
|
299
|
+
1. **Base: mock data** — `showcase-mocks.json` is merged over inline registration mocks via
|
|
300
|
+
`mergeShowcaseMocks()` from `@se-studio/core-ui`. Curated data takes precedence; types without
|
|
301
|
+
curated data fall back to their inline `mock:` in the registration.
|
|
302
|
+
|
|
303
|
+
2. **Patch: URL params** — Any control field in the URL (e.g. `?backgroundColour=Navy`) overrides
|
|
304
|
+
the mock. The control bar encodes only values that differ from the mock baseline.
|
|
305
|
+
|
|
306
|
+
`?clean=true` skips mock data entirely and uses the default showcase control state only.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## External project setup (seskills)
|
|
311
|
+
|
|
312
|
+
### Installing skills
|
|
313
|
+
|
|
314
|
+
For standalone projects not in the monorepo, install or update skills via:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
seskills sync
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
This copies all SE Studio cursor skills (including this one) into the project's `.cursor/skills/`
|
|
321
|
+
directory. The `seskills` binary is provided by `@se-studio/project-build`.
|
|
322
|
+
|
|
323
|
+
### Auto-sync on package update
|
|
324
|
+
|
|
325
|
+
Add a `postinstall` script to the project's `package.json` so skills automatically sync
|
|
326
|
+
whenever `pnpm install` is run (including after bumping `@se-studio/project-build`):
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
"postinstall": "seskills sync --if-installed"
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The `--if-installed` flag makes the sync a no-op if run inside the monorepo itself
|
|
333
|
+
(where `project-build` is a workspace package, not an installed npm package), so it
|
|
334
|
+
is safe to add to any project.
|
|
335
|
+
|
|
336
|
+
### Script paths
|
|
337
|
+
|
|
338
|
+
The CLI scripts are available as installed binaries after `npm install @se-studio/project-build`.
|
|
339
|
+
Both `generate-showcase-data` and `generate-showcase-mocks` read `.env.local` from `process.cwd()`,
|
|
340
|
+
so run them from the project root.
|