Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions skills/wix-headless/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ If `wix.config.json` is present in the working directory, offer: *"I found an ex
| 3 | seeders + design-system + image-phase-1 | design-system (fg) | merge `designTokens` into site.json; `emit-design-tokens.mjs`; grep Layout.astro CSS imports |
| 4 | components + components-css + image-phase-2 (all bg) | (none — all backgrounded) | `copy-utility-templates.mjs components`; on Image Phase 1 return: `patch-decorative-slots.mjs`; on Phase 3 return: `check-manifest.mjs components` |
| 5 | pages | components done + Phase 1 seeders done | `copy-utility-templates.mjs pages` |
| 6 | (bash) | pages done + image-phase-2 done | `check-manifest.mjs pages`; `release.sh`; `finalize-run-json.mjs` |
| 6 | (bash) | pages done + image-phase-2 done | `merge-navigation.mjs` + `merge-home.mjs` (collect each Phase 4 agent's `data.navContributions` / `data.homeContributions`); `check-manifest.mjs pages`; `release.sh`; `finalize-run-json.mjs` |

**Phase axis.** Core pipeline: `Phase 1 (Seed) → Phase 2 (Design System) → Phase 3 (Components) → Phase 4 (Pages)`. Image pipeline runs in parallel: Image Phase 1 (Decorative) alongside Phases 1–2; Image Phase 2 (Entity) alongside Phase 3 (depends only on Phase 1 Seed entity IDs + brand). Each Phase 4 agent writes its routes ONCE with both visual design and data queries — no placeholder-then-rewrite split.

Expand Down Expand Up @@ -263,11 +263,21 @@ Each prompt includes the standard fields PLUS:

**Rate-limit recovery for `image-phase-2-entity`.** If the subagent returns `status: "failed"` with an error matching `/limit|quota|resets/i`, do NOT stall or retry the subagent. Run the inline recovery in the orchestrator: batched generate (one call) → concurrent imports (one batch) → concurrent product/CMS PATCHes (one batch). Procedure encoded in `references/shared/IMAGE_GENERATION.md`.

2. **Post-Phase-4 manifest check.** `node "<SKILL_ROOT>/scripts/check-manifest.mjs" "$(pwd)" pages "<packs-csv>"`. Same recovery rules as Phase 3 check. Surface any unrecoverable `missing[]` entries (exit code 1) before invoking release — those are page files Phase 4 didn't write that have no template fallback. Record `{ phase: "manifest-check-pages", seconds }`.
2. **Merge home-page contributions.** Phase 4 page agents now return per-pack `data.homeContributions` (per `references/shared/RETURN_CONTRACT.md`) instead of patching `src/pages/index.astro` themselves. Pipe contributions through the merge script:

3. **Wait for npm install** — the background install from Wave 2. Wait on its handle; do not `sleep`-poll. On non-zero exit follow the recovery ladder in `references/SETUP.md` § "npm install recovery" (foreground retry with timeout, never delete the lockfile).
```bash
echo "$HOME_CONTRIBUTIONS_JSON" | node "<SKILL_ROOT>/scripts/merge-home.mjs" "$(pwd)"
```

`$HOME_CONTRIBUTIONS_JSON` is `{contributions: [<agent return's data.homeContributions>, ...]}` in pack order. Markers today: `home:stores` (stores featured grid), `home:gift-cards` (gift-cards probe-gated teaser, disabled pack — script reports it in `skipped[]` if the designer didn't emit the marker, status: \`partial\` but non-fatal). Record `{ phase: "merge-home", seconds }`.

> **Note on stores home-and-nav scope:** that agent still writes `index.astro` directly to perform category-href rewrites on the designer's category cards (non-marker edits). The merge script reads the post-edit file, so those rewrites are preserved. Only the `home:stores` featured-grid section moved to the contribution model.

3. **Post-Phase-4 manifest check.** `node "<SKILL_ROOT>/scripts/check-manifest.mjs" "$(pwd)" pages "<packs-csv>"`. Same recovery rules as Phase 3 check. Surface any unrecoverable `missing[]` entries (exit code 1) before invoking release — those are page files Phase 4 didn't write that have no template fallback. Record `{ phase: "manifest-check-pages", seconds }`.

4. **Wait for npm install** — the background install from Wave 2. Wait on its handle; do not `sleep`-poll. On non-zero exit follow the recovery ladder in `references/SETUP.md` § "npm install recovery" (foreground retry with timeout, never delete the lockfile).

4. **`bash <SKILL_ROOT>/scripts/release.sh`** — runs `npx @wix/cli build` + `release`, extracts the URL from `Site published on <url>`, prints the URL on stdout. Capture build / release timings via `date -u` wrappers and record `{ phase: "build", seconds }` and `{ phase: "release", seconds }`. The script's stdout becomes `outcome.releaseUrl` in `run.json`. This populates the **Frontend link** in headless settings so transactional emails link to the deployed frontend. On build failure, surface the compiler error and stop — do NOT deploy a broken site.
5. **`bash <SKILL_ROOT>/scripts/release.sh`** — runs `npx @wix/cli build` + `release`, extracts the URL from `Site published on <url>`, prints the URL on stdout. Capture build / release timings via `date -u` wrappers and record `{ phase: "build", seconds }` and `{ phase: "release", seconds }`. The script's stdout becomes `outcome.releaseUrl` in `run.json`. This populates the **Frontend link** in headless settings so transactional emails link to the deployed frontend. On build failure, surface the compiler error and stop — do NOT deploy a broken site.

Use `bash <SKILL_ROOT>/scripts/preview.sh` (not this step) only when the user is iterating on an existing site and explicitly asks for a fast preview without touching production.

Expand Down Expand Up @@ -298,7 +308,7 @@ One concluding turn containing, in order:

1. **Release URL text first** — bold heading / link at the top so the user sees it immediately.
2. **Compose the draft `run.json` blob** in scratch. Aggregate every subagent return into `phases[]`, set `outcome.previewUrl`, fill `run.started` (from `runStartedAt`) / `run.ended` (capture now via `date -u`), compute `run.totalSeconds`, and compose `requiredPhases[]` — phases that MUST have a captured duration:
- Always: `mcp-bootstrap`, `init-site-json`, `scaffold`, `env-pull`, `seed-utilities`, `emit-design-tokens`, `manifest-check-components`, `manifest-check-pages`, `decorative-slot-patch`, `npm-install`, `build`, `release` (or `preview` if `preview.sh` was used).
- Always: `mcp-bootstrap`, `init-site-json`, `scaffold`, `env-pull`, `seed-utilities`, `emit-design-tokens`, `manifest-check-components`, `manifest-check-pages`, `decorative-slot-patch`, `merge-home`, `npm-install`, `build`, `release` (or `preview` if `preview.sh` was used).
- Per app installed in Wave 2: `app-install-<appName>`.
- When `copy-utility-templates` ran: `copy-utility-templates-components` and/or `copy-utility-templates-pages`.
- `image-phase-2-entity`'s duration arrives via its return; record from there if any pack produced entities.
Expand Down
66 changes: 46 additions & 20 deletions skills/wix-headless/references/gift-cards/PAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ Files this agent OWNS (writes fresh):

- `src/pages/gift-cards.astro` — landing page; redirects to `/` when probe returns null

Files this agent PATCHES (insert at marker, preserve everything else):
Navigation + home contributions (returned as JSON, NOT direct writes):

- `src/components/Navigation.astro` — insert "Gift Cards" link at `<!-- nav:links -->`
- `src/pages/index.astro` — insert home teaser at `<!-- home:gift-cards -->`
- The "Gift Cards" link is returned as `data.navContributions` (spliced into `Navigation.astro` by `scripts/merge-navigation.mjs`).
- The home teaser is returned as `data.homeContributions` (spliced into `src/pages/index.astro` by `scripts/merge-home.mjs`).

Files this agent MUST NOT touch:
- `src/utils/gift-cards.ts`, `src/components/GiftCardPurchase.tsx`, `src/styles/components-gift-cards.css` — Components scope.
Expand Down Expand Up @@ -69,21 +69,33 @@ Body: hero image + name + description + `<GiftCardPurchase client:load product={
```
4. If other verticals (stores, blog, forms) already inserted at the same marker, preserve every existing line — your snippet appends.

### 3. Patch `src/pages/index.astro`
### 3. Home teaser contribution (returned as `data.homeContributions`)

1. Read the file.
2. Add to frontmatter:
```astro
import { getGiftCardProduct } from "../utils/gift-cards";
import { resolveWixImageUrl } from "../utils/wix-image";
> **Do NOT write `src/pages/index.astro` from this scope.** Return the contribution as JSON; the orchestrator splices it via `scripts/merge-home.mjs` after all Phase 4 agents return. If the `<!-- home:gift-cards -->` marker is absent from the designer's emission (this is `disabled: true` pack — the designer may have skipped it), the merge script reports it in `skipped[]` with reason `MARKER_NOT_FOUND` — non-fatal, observable.

const giftCardProduct = await getGiftCardProduct();
const giftCardImage = giftCardProduct
? resolveWixImageUrl(giftCardProduct.image, 800, 600)
: null;
```
(`resolveWixImageUrl` import may already be present from the stores patcher — if so, do not re-import.)
3. Locate the line containing `<!-- home:gift-cards -->`. Insert the teaser snippet immediately after it (see `templates/_home-teaser-snippet.astro`).
Build the contribution as part of your return JSON:

```json
{
"data": {
"homeContributions": {
"imports": [
"import { getGiftCardProduct } from '../utils/gift-cards';",
"import { resolveWixImageUrl } from '../utils/wix-image';"
],
"frontmatter": [
"const giftCardProduct = await getGiftCardProduct().catch(() => null);",
"const giftCardImage = giftCardProduct ? resolveWixImageUrl(giftCardProduct.image, 800, 600) : null;"
],
"byMarker": {
"home:gift-cards": "{giftCardProduct && (<section class=\"gift-card-teaser\">…teaser snippet from templates/_home-teaser-snippet.astro…</section>)}"
}
}
}
}
```

The merge script dedupes the `resolveWixImageUrl` import against the existing frontmatter (it may already be imported by another pack's contribution). Imports + frontmatter additions are dedupe-safe.

## Verification

Expand All @@ -104,18 +116,32 @@ After writing/patching, grep the project to confirm:
"pageWritten": true,
"navigationPatched": true,
"homePatched": true,
"markersFound": ["<!-- nav:links -->", "<!-- home:gift-cards -->"]
"markersFound": ["<!-- nav:links -->", "<!-- home:gift-cards -->"],
"homeContributions": {
"imports": [
"import { getGiftCardProduct } from '../utils/gift-cards';",
"import { resolveWixImageUrl } from '../utils/wix-image';"
],
"frontmatter": [
"const giftCardProduct = await getGiftCardProduct().catch(() => null);",
"const giftCardImage = giftCardProduct ? resolveWixImageUrl(giftCardProduct.image, 800, 600) : null;"
],
"byMarker": {
"home:gift-cards": "{giftCardProduct && (<section class=\"gift-card-teaser\">…</section>)}"
}
}
},
"files": [
"src/pages/gift-cards.astro",
"src/components/Navigation.astro",
"src/pages/index.astro"
"src/components/Navigation.astro"
],
"errors": []
}
```

If a marker is missing, return `status: "partial"` with `errors: [{ code: "MARKER_NOT_FOUND", file: "<path>", marker: "<marker>" }]`. Do NOT invent your own insertion point — that signals the designer foundation didn't scaffold the shell correctly and should be fixed upstream.
> `src/pages/index.astro` is removed from `files[]` — the orchestrator owns home-page writes via `scripts/merge-home.mjs`. The Navigation.astro line predates the navContributions migration (sibling PR).

If the home marker is absent (e.g. the designer skipped `<!-- home:gift-cards -->` because the pack is `disabled`), the merge script reports it in `skipped[]`; the agent should NOT manually patch index.astro to compensate. Surfacing the omission keeps the designer's emission contract honest.

## Anti-patterns

Expand Down
36 changes: 36 additions & 0 deletions skills/wix-headless/references/shared/RETURN_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,42 @@ Phase 4 CMS page agents reference these collection names; the image agent attach
}
```

### Phase 2: homeContributions (index.astro contributions)

Identical shape to `navContributions` (see above) but targets `src/pages/index.astro` and `home:*` markers. Phase 4 page agents that previously patched the home page at marker comments (stores `home-and-nav` at `<!-- home:stores -->`, gift-cards `pages` at `<!-- home:gift-cards -->`) now return their contribution as `data.homeContributions`. The orchestrator collects every Phase 4 agent's `homeContributions`, then invokes `scripts/merge-home.mjs` ONCE to splice them into the designer-emitted shell.

```json
{
"status": "complete",
"phase": "stores-pages-home-and-nav",
"scope": "pages-home-and-nav",
"data": {
"homeContributions": {
"imports": [
"import ProductCard from '../components/ProductCard.astro';",
"import { productsV3 } from '@wix/stores';"
],
"frontmatter": [
"let featured: any[] = [];",
"try { featured = (await productsV3.queryProducts().limit(12).find()).items ?? []; } catch (err) { console.error('[home] featured products query failed:', err); }",
"featured = featured.filter((p) => p?.ribbon?.name !== 'Gift Card').slice(0, 3);"
],
"byMarker": {
"home:stores": "{featured.length > 0 && (<section class=\"featured-section\">…<div class=\"product-grid\">{featured.map((p) => <ProductCard product={p} />)}</div>…</section>)}"
}
},
"featuredProductsCount": 3
},
"files": [
"src/pages/index.astro"
]
}
```

> The stores `home-and-nav` agent still lists `src/pages/index.astro` in `files[]` because it ALSO performs non-marker edits on the page (category-card href rewrites). The orchestrator reads the post-edit file before invoking `merge-home.mjs`, so those rewrites are preserved.

The `gift-cards` page agent contributes at `home:gift-cards`. If the designer didn't emit that marker (e.g. because gift-cards is `disabled: true` and the designer was told to skip surfaces for disabled packs), `merge-home.mjs` reports it in `skipped[]` with reason `MARKER_NOT_FOUND` — non-fatal, observable.

### Designer foundation

```json
Expand Down
Loading