@se-studio/skills 1.3.3 → 1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @se-studio/skills
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Bulk version bump: minor for all packages
8
+
9
+ ## 1.3.4
10
+
11
+ ### Patch Changes
12
+
13
+ - **cms-seo-audit:** Document sitemap+unindexed crawl, all-page `.md` requirement, and expected listing-hub noise.
14
+
3
15
  ## 1.3.3
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/skills",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "SE Studio agent skills for marketing site development with Contentful CMS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -7,7 +7,7 @@ description: "Run the full marketing-site CMS SEO workflow: audit CSV from Conte
7
7
 
8
8
  Use when improving SEO across a Contentful-backed SE marketing site: meta descriptions, schema.org linking, featured images, bulk publish after CMS edits, and live production HTML checks.
9
9
 
10
- **Packages:** `@se-studio/cms-seo` (CMS audit/apply/publish), `@se-studio/site-check` (production HTML audit, Screaming Frog — see **screaming-frog-audit** skill).
10
+ **Packages:** `@se-studio/cms-seo` (CMS audit/apply/publish), `@se-studio/site-check/production-audit` (production HTML audit). Screaming Frog: **screaming-frog-audit** skill.
11
11
 
12
12
  ---
13
13
 
@@ -101,11 +101,14 @@ Smoke-test with header nav: Pedestal `/about/`, Headwater `/`.
101
101
  pnpm seo:audit:production
102
102
  ```
103
103
 
104
- Uses `@se-studio/site-check/production-audit` (`runProductionSeoAudit`). Crawls production sitemap, checks each URL for:
104
+ Uses `@se-studio/site-check/production-audit` (`runProductionSeoAudit`). Crawls **sitemap.xml + sitemap-unindexed.xml**, checks each URL for:
105
105
 
106
106
  - Title, meta description, H1, thin content
107
107
  - Canonical, noindex, JSON-LD validity and schema types
108
- - Markdown export parity (`index.md` / `*.md` vs HTML)
108
+ - Markdown export: every sitemap page URL must return 200 for its `.md` mirror (`/download/` and static assets excluded)
109
+ - `markdown-index.txt` cross-check (supplementary — URLs in sitemap but not in the index)
110
+
111
+ High `markdown_missing` on category/listing hubs is expected until those routes ship `.md` exports.
109
112
 
110
113
  Outputs:
111
114
 
@@ -27,12 +27,11 @@ Run after any of these change:
27
27
 
28
28
  | Action | Automatic on git push? |
29
29
  |--------|------------------------|
30
- | Copy **committed** `editor-pack/` + `.mcpb` into cms-edit-host | Yes (`stage-site.mjs` on Vercel build) |
30
+ | Copy **committed** `editor-pack/` into cms-edit-host | Yes (`cms-edit host stage` via `stage-site.mjs` on Vercel build) |
31
31
  | Run `editor-pack generate` | **No** — always manual (this skill) |
32
- | Rebuild `.mcpb` on Vercel | **No** — commit locally (`pnpm cms-edit:mcpb` or `build-mcpb.sh`) when `hosted.mcpUrl` or extension metadata changes |
33
32
  | Update hosted guide/prompts from `@se-studio/contentful-cms` | Redeploy host after bumping package version |
34
33
 
35
- Editors do **not** reinstall `.mcpb` when only the editor pack changes.
34
+ Editors do **not** reconnect Claude Integrations when only the editor pack changes.
36
35
 
37
36
  **Staging:** `stage-site.mjs` copies committed artifacts into `cms-edit/host/` before build. Requires `CMS_EDIT_ROOT` on Vercel. Single-site repos default to `cms-edit` locally; multi-site repos need `CMS_EDIT_ROOT` in `cms-edit/host/.env.local`. Run manually with `pnpm cms-edit:stage` (or site-specific variant).
38
37
 
@@ -88,13 +87,13 @@ git commit -m "chore(cms-edit): regenerate editor pack"
88
87
 
89
88
  ### Customer repo with `cms-edit/host/` (SE Studio, Pedestal, Headwater)
90
89
 
91
- Commit `editor-pack/` (and `.mcpb` if `hosted.mcpUrl` changed), then push to the branch Vercel watches (usually `develop`). Changes under `cms-edit/**` trigger a host rebuild (`stage-site.mjs` copies committed artifacts).
90
+ Commit `editor-pack/`, then push to the branch Vercel watches (usually `develop`). Changes under `cms-edit/**` trigger a host rebuild (`stage-site.mjs` copies committed artifacts).
92
91
 
93
92
  ```bash
94
93
  git push
95
94
  ```
96
95
 
97
- Manual deploy without pushing: `pnpm cms-edit:deploy` (single-site) or `pnpm cms-edit:deploy:<site>` (multi-site) — runs validate, stage, then `vercel deploy --prod`.
96
+ Manual deploy without pushing: `pnpm cms-edit:deploy` (single-site) or `pnpm cms-edit:deploy:<site>` (multi-site) — runs validate, stage, then `vercel deploy --prod` **from the repo root** with `--project <vercel-project>`. Do not `cd cms-edit/host` first (Vercel Root Directory is already `cms-edit/host`).
98
97
 
99
98
  ### Customers without `cms-edit/host/` in their repo
100
99
 
@@ -114,10 +113,10 @@ SE Studio sites store the marketing homepage as Contentful slug **`index`** (pub
114
113
  ## Verify after deploy
115
114
 
116
115
  ```bash
117
- curl -s -H "Authorization: Bearer <PAT>" "https://<host>/api/health" | jq .gettingStarted
116
+ curl -s "https://<host>/api/health" | jq
118
117
  ```
119
118
 
120
- In Claude Desktop (hosted extension): ask to read `cms-edit://customer/routing` and confirm new component types appear in `cms-edit://customer/components-index`.
119
+ In Claude Desktop (hosted integration): ask to read `cms-edit://customer/routing` and confirm new component types appear in `cms-edit://customer/components-index`.
121
120
 
122
121
  ## Related docs
123
122
 
@@ -133,4 +132,4 @@ In Claude Desktop (hosted extension): ask to read `cms-edit://customer/routing`
133
132
  |------------|-------|
134
133
  | Guidelines changed | `contentful-cms-update-cms-guidelines` |
135
134
  | New registration | `se-marketing-sites-register-cms-features` |
136
- | Editor `.mcpb` install | `contentful-cms-setup` (hosted path) |
135
+ | Editor Integrations setup | `contentful-cms-setup` (hosted path) |
@@ -11,35 +11,32 @@ Use this skill when the user wants to install or configure the `cms-edit` MCP se
11
11
 
12
12
  | Path | When to use |
13
13
  |------|-------------|
14
- | **Hosted (`.mcpb`)** | User is a content editor; SE sent a `.mcpb` file; no Node.js |
14
+ | **Hosted (Integrations)** | Content editor; SE sent an onboarding URL (e.g. `/cms-edit`); no Node.js |
15
15
  | **Local (setup wizard)** | Developer; multi-space; or no hosted deployment |
16
16
 
17
17
  Ask which applies if unclear.
18
18
 
19
19
  ---
20
20
 
21
- ## Hosted setup (`.mcpb` extension)
21
+ ## Hosted setup (Claude Integrations + OAuth)
22
22
 
23
- Use when the user has a **`.mcpb` file** from SE (e.g. `cms-edit-om1.mcpb`). Do **not** run the setup wizard.
23
+ Use when SE sent an **onboarding link** (e.g. `https://your-site.content.se.studio/cms-edit`). Do **not** run the setup wizard.
24
24
 
25
- ### Step 1: Get a Contentful token
25
+ ### Step 1: Connect to Claude
26
26
 
27
- Same as local — tell the user to create a **personal access token** in Contentful (Settings → CMA tokens), name it `Claude Desktop`, and copy it.
27
+ 1. Open the link SE sent (or **Connect to Claude** on `/cms-edit`)
28
+ 2. Confirm the connector in Claude Desktop or claude.ai
29
+ 3. Sign in with **Contentful** when prompted (same account SE invited to the space)
28
30
 
29
- ### Step 2: Install the extension
30
-
31
- 1. Open [Claude Desktop](https://claude.ai/download)
32
- 2. **Settings → Extensions → Install Extension…** (or double-click the `.mcpb` file)
33
- 3. Paste the Contentful token when prompted
34
- 4. Fully quit and reopen Claude Desktop
31
+ Manual alternative: Claude → **Customize → Connectors** → Add custom connector → paste the MCP URL (`…/api/mcp`) → Connect.
35
32
 
36
33
  Full editor guide: `packages/contentful-cms/HOSTED.md`
37
34
 
38
- ### Step 3: Verify
35
+ ### Step 2: Verify
39
36
 
40
- In Claude, ask to list pages or open the homepage. If `cms_edit` returns content, setup is complete.
37
+ In Claude, ask to read the cms-edit guide or verify the connection. If `cms_edit` returns content, setup is complete.
41
38
 
42
- **Token update:** Settings → Extensions → open the cms-edit extension → update token.
39
+ **Reconnect:** Settings → Integrations → Connect again if the connection stops working.
43
40
 
44
41
  ---
45
42
 
@@ -126,4 +123,4 @@ If it returns a page structure, setup is complete. If it errors, see Troubleshoo
126
123
  It should contain an `mcpServers.cms-edit` entry. If missing, run the wizard again.
127
124
 
128
125
  **Adding another space**
129
- → Run `npx @se-studio/contentful-cms@latest setup` again — it merges the new space into the existing config.
126
+ → Run `npx @se-studio/contentful-cms@latest setup` again — it merges the new space into the existing config.
@@ -22,12 +22,17 @@ The repo contains the official migration:
22
22
 
23
23
  ```bash
24
24
  # Create the redirect content type (clean fromPath + fromInternal / toPath + toInternal model)
25
- node scripts/migrations/18-create-redirect-content-type.js
25
+ contentful space migration ... scripts/migrations/18-create-redirect-content-type.js
26
+
27
+ # If the redirect CT already exists but lacks field defaults (statusCode → 301, active → true):
28
+ contentful space migration ... scripts/migrations/22-set-redirect-field-defaults.js
26
29
  ```
27
30
 
28
- Run it with the Contentful CLI (or the contentful-cms package tools) and the usual `CONTENTFUL_SPACE_ID` + `CONTENTFUL_MANAGEMENT_TOKEN` + environment.
31
+ Run with the Contentful CLI (or the contentful-cms package tools) and the usual `CONTENTFUL_SPACE_ID` + `CONTENTFUL_MANAGEMENT_TOKEN` + environment.
32
+
33
+ If you previously created a Redirect CT using an older multi-field version of the migration, **delete the "Redirect" content type first**, then re-run migration 18 to get the clean single-ref model.
29
34
 
30
- If you previously created a Redirect CT using an older multi-field version of the migration, **delete the "Redirect" content type first**, then re-run to get the clean single-ref model.
35
+ Migration 22 only updates the content type definition (editor defaults for **new** entries). It does not backfill existing redirect entries.
31
36
 
32
37
  After running you will have a new (or repaired) content type called **Redirect**.
33
38
 
@@ -44,8 +49,8 @@ Key fields (all documented with help text in the migration):
44
49
  - `toInternal` (single reference picker, same allowed types as fromInternal)
45
50
 
46
51
  **Other**
47
- - `statusCode` — dropdown: 301 (permanent — recommended), 302, 307, 308.
48
- - `active` — boolean (default on). Turn off to disable a rule without deleting it.
52
+ - `statusCode` — dropdown: 301 (permanent — recommended), 302, 307, 308. **Defaults to 301** in the editor for new entries.
53
+ - `active` — boolean. **Defaults to true** for new entries. Turn off to disable a rule without deleting it.
49
54
  - `note` — internal editor note (never shown on the site).
50
55
  - `cmsLabel` — required internal label.
51
56
 
@@ -200,15 +205,29 @@ Pure `fromPath` vanity redirects were already absent from sitemaps (no backing c
200
205
 
201
206
  ### 4.3 Webhook = Deploy Hook (the trigger)
202
207
 
203
- In Contentful → Settings → Webhooks, create (or reuse) a webhook that fires on:
208
+ Baked redirects require a **rebuild**, not ISR revalidation. Use a Contentful webhook that calls your **Vercel Deploy Hook** URL (not `/api/revalidate`).
209
+
210
+ **Automated setup (recommended):**
204
211
 
205
- - Entry publish / unpublish / delete for content type `redirect`
212
+ 1. In Vercel → Project → Settings → **Deploy Hooks**, create a hook for Production (and optionally Preview). Copy each URL.
213
+ 2. Add to `.env.local`:
214
+ ```bash
215
+ VERCEL_DEPLOY_HOOK_URL=https://api.vercel.com/v1/integrations/deploy/...
216
+ # optional:
217
+ VERCEL_PREVIEW_DEPLOY_HOOK_URL=https://api.vercel.com/v1/integrations/deploy/...
218
+ VERCEL_PROTECTION_BYPASS_TOKEN=... # only if you need the bypass header on hook calls
219
+ ```
220
+ 3. From the app directory (requires `CONTENTFUL_MANAGEMENT_TOKEN` + `CONTENTFUL_SPACE_ID`):
221
+ ```bash
222
+ pnpm setup:redirect-deploy-hook
223
+ ```
224
+ This creates/replaces Contentful webhooks named `Vercel Deploy Hook (Redirects)` (and `… – Preview` when the preview URL is set). They fire on **Entry publish / unpublish / delete** filtered to content type `redirect`.
206
225
 
207
- Point the URL at your **Vercel Deploy Hook** (Project → Settings → Deploy Hooks → create one for Production and optionally for Preview).
226
+ The script lives at [`scripts/setup-redirect-deploy-hook.ts`](../../../../scripts/setup-redirect-deploy-hook.ts) in the monorepo; `example-empty` wires it via `package.json`.
208
227
 
209
- Add the usual headers your deploys need (`x-vercel-protection-bypass` if you use deployment protection, `REVALIDATION_SECRET` if you also want the normal reval to run, etc.).
228
+ **Manual setup:** same triggers and filter (`redirect` only), POST to the deploy hook URL. Do **not** point this at `/api/revalidate` — that only invalidates cache tags and will not regenerate `src/generated/redirects.ts`.
210
229
 
211
- That's it. Publish a redirect → Vercel starts a build → the generate step runs → the new static map is in the bundle → redirects work.
230
+ That's it. Publish a redirect → Vercel starts a build → `prebuild` runs `generate:redirects` → the new static map is in the bundle → redirects work.
212
231
 
213
232
  ## 5. Testing
214
233
 
@@ -0,0 +1,211 @@
1
+ ---
2
+ name: se-marketing-sites-smoke-test-setup
3
+ description: "Set up or regenerate smoke.cases.json for local smoke tests from the production sitemap. Use when adding smoke tests, refreshing smoke URLs after route or content changes, or migrating off smoke.config.ts."
4
+ ---
5
+
6
+ # Smoke test setup (static `smoke.cases.json`)
7
+
8
+ Local smoke tests are **HTTP-only**: no `cms-server`, Contentful, or preload. Each app commits **`smoke.cases.json`** with curated URLs. Regenerate this file when routes or indexed content change materially.
9
+
10
+ Requires `@se-studio/site-check` **2.1.2+** for cache log audit; **2.0.0+** for static smoke.
11
+
12
+ Preview / `DRAFT_ONLY` Contentful access in local dev is expected and not a smoke failure.
13
+
14
+ ## Prerequisites
15
+
16
+ - App has `scripts/smoke-test-run.ts` calling `runStaticSmokeTest('smoke.cases.json')`.
17
+ - `package.json`: `"smoke-test:run": "tsx scripts/smoke-test-run.ts"`.
18
+ - `SITEMAP_PROD_URL` in `.env.example` (production sitemap for URL curation).
19
+
20
+ ## Script matrix
21
+
22
+ | Script | Purpose |
23
+ |--------|---------|
24
+ | `pnpm smoke-test` | Start dev server + functional smoke (default) |
25
+ | `pnpm smoke-test:run` | Smoke only (server already up) |
26
+ | `pnpm smoke-test:preview` | Smoke against Vercel preview (`runPreviewStaticSmokeTest`; no local server) |
27
+ | `pnpm smoke-test:audit` | Functional smoke + server log cache audit |
28
+ | `pnpm smoke-test:cache` | `build` + `start` + double-pass `x-nextjs-cache` verify |
29
+ | `pnpm smoke-test:deploy-check` | Post-build gate: `start` (no rebuild) + functional smoke — use in Vercel `buildCommand` |
30
+ | `pnpm smoke-test:live` | Live deployment URL smoke — GitHub Action + Vercel Deployment Checks |
31
+
32
+ Example `package.json` entries:
33
+
34
+ ```json
35
+ "smoke-test": "smoke-test-one 3012",
36
+ "smoke-test:run": "tsx scripts/smoke-test-run.ts",
37
+ "smoke-test:preview": "bash -c 'set -a && [ -f .env.local ] && . ./.env.local; set +a && exec tsx scripts/smoke-test-preview.ts'",
38
+ "smoke-test:audit": "SMOKE_TEST_AUDIT_CACHE_LOGS=true smoke-test-one 3012",
39
+ "smoke-test:cache": "SMOKE_TEST_SERVER_SCRIPT=start SMOKE_TEST_VERIFY_CACHE=true smoke-test-one 3012",
40
+ "smoke-test:deploy-check": "smoke-test-deploy-check",
41
+ "smoke-test:live": "smoke-test-live"
42
+ ```
43
+
44
+ **Vercel build gate** — append to root `vercel.json` so failed smoke fails the build before deploy:
45
+
46
+ ```json
47
+ {
48
+ "buildCommand": "pnpm build && pnpm smoke-test:deploy-check"
49
+ }
50
+ ```
51
+
52
+ **Vercel Deployment Check (live URL)** — GitHub Action on `vercel.deployment.ready` tests `client_payload.url` before production domains alias. Workflow must live on the repo **default branch**. Register the status `name` in Vercel → Settings → Build and Deployment → Deployment Checks.
53
+
54
+ Filter on `client_payload.environment == 'production'` when Deployment Checks target production only. Vercel also dispatches for preview and custom environments (`preview`, `develop`, etc.); skip those to avoid duplicate CI runs. Use `workflow_dispatch` without an environment filter for manual smoke against any URL.
55
+
56
+ ```yaml
57
+ # .github/workflows/deployment-smoke.yml
58
+ name: Deployment smoke
59
+
60
+ on:
61
+ repository_dispatch:
62
+ types:
63
+ - vercel.deployment.ready
64
+
65
+ jobs:
66
+ smoke:
67
+ if: |
68
+ github.event.client_payload.project.name == '<vercel-project-name>' &&
69
+ github.event.client_payload.environment == 'production'
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ - uses: vercel/repository-dispatch/actions/checkout@v1
73
+ - uses: pnpm/action-setup@v4
74
+ with:
75
+ version: 11
76
+ - uses: actions/setup-node@v4
77
+ with:
78
+ node-version: 24
79
+ cache: pnpm
80
+ - run: pnpm install --frozen-lockfile
81
+ - name: Live deployment smoke
82
+ env:
83
+ DEPLOYMENT_URL: ${{ github.event.client_payload.url }}
84
+ VERCEL_PROTECTION_BYPASS_TOKEN: ${{ secrets.VERCEL_PROTECTION_BYPASS_TOKEN }}
85
+ run: pnpm smoke-test:live
86
+ - name: Report Deployment Check status
87
+ if: always()
88
+ uses: vercel/repository-dispatch/actions/status@v1
89
+ with:
90
+ name: "Vercel - <vercel-project-name>: deployment smoke"
91
+ ```
92
+
93
+ GitHub secret: `VERCEL_PROTECTION_BYPASS_TOKEN` (Vercel → Deployment Protection → Protection Bypass for Automation). Set `SMOKE_TEST_IGNORE=true` to bypass smoke in an emergency.
94
+
95
+ Or from the app directory without a per-app script: `node ../../scripts/smoke-test-preview.mjs` (loads `.env.local` and calls `runPreviewStaticSmokeTest`).
96
+
97
+ ## Environment variables
98
+
99
+ | Variable | Purpose |
100
+ |----------|---------|
101
+ | `SITEMAP_PROD_URL` | Production site URL for sitemap fetch when curating `smoke.cases.json` |
102
+ | `PREVIEW_SITE_URL` | Vercel develop/preview deployment URL for `smoke-test:preview` |
103
+ | `DEPLOYMENT_URL` | Live deployment URL for `smoke-test:live` (CI / `repository_dispatch` payload) |
104
+ | `VERCEL_PROTECTION_BYPASS_TOKEN` | Deployment Protection bypass secret (aliases: `VERCEL_AUTOMATION_BYPASS_SECRET`, `VERCEL_BYPASS_TOKEN`) |
105
+ | `PRODUCTION_SITE_URL` | Optional canonical production URL for audits and related tooling |
106
+
107
+ Add these to `.env.example` under an SEO / site-check section. `runPreviewStaticSmokeTest` requires `PREVIEW_SITE_URL` and a bypass token in `.env.local`.
108
+
109
+ ## Workflow
110
+
111
+ ### 1. Confirm port
112
+
113
+ Read `package.json` — e.g. `next dev -p 3012` → port **3012**.
114
+
115
+ ### 2. Fetch sitemap (production first)
116
+
117
+ Use `SITEMAP_PROD_URL` from `.env.example`:
118
+
119
+ ```bash
120
+ curl -sSL "$SITEMAP_PROD_URL"
121
+ ```
122
+
123
+ Parse all `<loc>` URLs. Strip host; keep pathnames with trailing slashes as in sitemap.
124
+
125
+ Use **local** sitemap only when verifying routes not yet on production:
126
+
127
+ ```bash
128
+ curl -sS "http://localhost:<port>/sitemap.xml"
129
+ ```
130
+
131
+ ### 3. Understand route patterns
132
+
133
+ Read (do not guess from constants alone):
134
+
135
+ - `src/app/(cms-routes)/` — custom segments (e.g. se-website uses `/work/`, not `/articles/`).
136
+ - `src/lib/constants.ts` — `ARTICLES_BASE`, feature flags, slugs.
137
+ - Prior smoke output or `.md` probes for listing pages that do not export markdown.
138
+
139
+ ### 4. Bucket URLs into categories
140
+
141
+ | Category | Typical paths | Samples |
142
+ |----------|---------------|---------|
143
+ | `home` | `/` | 1 |
144
+ | `page` | Top-level CMS pages (not home, not article trees) | 2 |
145
+ | `article-type-index` | e.g. `/work/`, `/blog/` | 1 |
146
+ | `article` | Nested article/case-study URLs | 2 |
147
+ | `tag` / `tags-index` | If in sitemap and enabled | 1–2 each |
148
+ | `person` / `people-listing` | If in sitemap and enabled | 1–2 each |
149
+
150
+ **Exclude** obvious non-prod slugs: `tmp-*`, draft pages, unless intentionally tested.
151
+
152
+ Keep sets lean (6–10 cases). Avoid heavy paginated listing URLs unless needed for coverage.
153
+
154
+ ### 5. Set `expectMarkdown`
155
+
156
+ - **true** — page and `.md` should return 200 with `text/markdown` (home, pages, articles).
157
+ - **false** — listing shells that return 404 or “not supported” for `.md` (optional; omit markdown checks).
158
+
159
+ Probe when unsure (local dev server):
160
+
161
+ ```bash
162
+ curl -sI "http://localhost:<port>/some-path.md"
163
+ ```
164
+
165
+ ### 6. Write `smoke.cases.json`
166
+
167
+ ```json
168
+ {
169
+ "siteName": "my-app",
170
+ "port": 3012,
171
+ "cases": [
172
+ { "category": "home", "label": "Home", "path": "/", "expectMarkdown": true },
173
+ { "category": "page", "label": "About", "path": "/about/", "expectMarkdown": true }
174
+ ]
175
+ }
176
+ ```
177
+
178
+ - `path` — site-relative, trailing slash when the site uses trailing slashes.
179
+ - `port` — default; override at run time with `SMOKE_TEST_PORT`.
180
+
181
+ ### 7. Verify
182
+
183
+ ```bash
184
+ pnpm smoke-test:run
185
+ ```
186
+
187
+ Expect `Summary: N cases, 0 failed`. Preview API / `DRAFT_ONLY` logs in dev are OK.
188
+
189
+ Optional cache audit:
190
+
191
+ ```bash
192
+ pnpm smoke-test:audit
193
+ ```
194
+
195
+ Expect `cache log audit: ok` with no 2MB errors. `cache skip` lines are warnings by default.
196
+
197
+ ### 8. Commit
198
+
199
+ Commit `smoke.cases.json`. Remove legacy `smoke.config.ts` if present.
200
+
201
+ ## Migrating from `smoke.config.ts`
202
+
203
+ 1. Delete `smoke.config.ts`.
204
+ 2. Simplify `smoke-test:run` script (no bash, no `NODE_OPTIONS`, no preload).
205
+ 3. Update `@se-studio/site-check` to `^2.1.2`.
206
+ 4. Follow workflow above to create `smoke.cases.json`.
207
+
208
+ ## Reference
209
+
210
+ - Example: `apps/example-empty/smoke.cases.json` (monorepo).
211
+ - Package API: `loadStaticSmokeConfig`, `runStaticSmokeTest`, `runPreviewStaticSmokeTest`, `auditCacheLogs` from `@se-studio/site-check/smoke-test`.
@@ -399,16 +399,12 @@ Expected: `200 OK`. A `401` means the secret in the header doesn't match the dep
399
399
 
400
400
  ## (Optional) Redirects via the rebuild pattern
401
401
 
402
- If the project uses the `se-marketing-sites-redirects` skill, also configure a webhook that fires on the new `redirect` content type and points at a **Vercel Deploy Hook** (not a revalidation URL).
402
+ If the project uses the `se-marketing-sites-redirects` skill, also wire redirect rebuild webhooks (separate from `/api/revalidate`):
403
403
 
404
- See `.agents/skills/se-marketing-sites-redirects/SKILL.md` (or the source in `packages/skills/skills/se-marketing-sites-redirects/SKILL.md`) for:
404
+ 1. Create Vercel Deploy Hook(s) (Production + optional Preview) and set `VERCEL_DEPLOY_HOOK_URL` (and optionally `VERCEL_PREVIEW_DEPLOY_HOOK_URL`) in `.env.local`.
405
+ 2. Run `pnpm setup:redirect-deploy-hook` from the app (monorepo script: `scripts/setup-redirect-deploy-hook.ts`).
405
406
 
406
- - Running the two official migration scripts (create the CT + later remove legacy `redirectTo` fields)
407
- - The exact content type fields + recommended help text
408
- - The build-time generate script + static middleware
409
- - Wiring the deploy hook webhook
407
+ See `.agents/skills/se-marketing-sites-redirects/SKILL.md` for migrations, generate script, middleware, and full webhook details.
410
408
 
411
- This is deliberately the same "publish → deploy hook → build bakes static data" pattern used for A/B tests. It is the only supported path in v1 (Edge Config fast path is future work).
412
-
413
- You can have both the normal revalidation webhooks **and** the redirect deploy-hook webhook active at the same time.
409
+ This is the same "publish → deploy hook → build bakes static data" pattern as A/B tests. You can run **both** ISR revalidation webhooks and redirect deploy-hook webhooks at the same time.
414
410
  - **To rotate the secret later**: re-run `scripts/setup-contentful-webhooks.ts` — it will generate a new secret and update everything automatically.