[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-automattic-replicate-theme":3,"mdc--aqpodf-key":36,"related-org-automattic-replicate-theme":3232,"related-repo-automattic-replicate-theme":3420},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":31,"sourceUrl":34,"mdContent":35},"replicate-theme","reconstruct WordPress themes with parity","Parity-first carry-and-scope theme reconstruction — dispatched by `\u002Fliberate` after capture. Instead of projecting the source onto editable WordPress blocks (the `replicate-with-blocks` path), it CARRIES the source page near-verbatim and SCOPES the source's own CSS under a per-site wrapper, producing a high-fidelity but NON-block-editable theme. It owns only the reconstruct→theme stage (capture already happened in `\u002Fliberate`); writes `output-carry.wxr` + a `\u003Csite>-carry` theme and installs into a Studio site named after the source. Use when the user picks \"theme replication\" at the `\u002Fliberate` checkpoint, or asks to \"carry the HTML\", \"scope the source CSS\", or maximize visual parity vs. blocks.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"automattic","Automattic","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fautomattic.png",[12,16,19,22],{"name":13,"slug":14,"type":15},"Full Site Editing","full-site-editing","tag",{"name":17,"slug":18,"type":15},"WordPress","wordpress",{"name":20,"slug":21,"type":15},"Migration","migration",{"name":23,"slug":24,"type":15},"Themes","themes",31,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fdata-liberation-agent","2026-06-08T08:17:40.678833",null,1,[],{"repoUrl":26,"stars":25,"forks":29,"topics":32,"description":33},[],"Extract content from closed web platforms into WordPress-compatible WXR files.","https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fdata-liberation-agent\u002Ftree\u002FHEAD\u002Fskills\u002Freplicate-theme","---\nname: replicate-theme\ndescription: Parity-first carry-and-scope theme reconstruction — dispatched by `\u002Fliberate` after capture. Instead of projecting the source onto editable WordPress blocks (the `replicate-with-blocks` path), it CARRIES the source page near-verbatim and SCOPES the source's own CSS under a per-site wrapper, producing a high-fidelity but NON-block-editable theme. It owns only the reconstruct→theme stage (capture already happened in `\u002Fliberate`); writes `output-carry.wxr` + a `\u003Csite>-carry` theme and installs into a Studio site named after the source. Use when the user picks \"theme replication\" at the `\u002Fliberate` checkpoint, or asks to \"carry the HTML\", \"scope the source CSS\", or maximize visual parity vs. blocks.\nallowed-tools:\n  - Bash\n  - Read\n  - Write\n  - Edit\n  - Glob\n  - Grep\n  - AskUserQuestion\ndisable-model-invocation: true\n---\n\n# Replicate Theme — Carry-and-Scope Parity Path\n\nYou are the **carry-and-scope reconstruct orchestrator**. `\u002Fliberate` dispatches you inline after it has captured the site; you rebuild it by carrying the source markup near-verbatim and scoping the source's own CSS, rather than projecting onto core blocks. The goal is maximum visual parity. You own only the reconstruct→theme stage — capture already happened in `\u002Fliberate`.\n\n**Read this first — what you are trading.** This path emits each page region as a single `core\u002Fhtml` island. These pages are **raw-HTML-editable, not block-editable**. You are deliberately trading all block editability for fidelity. Do not \"improve\" the output by converting islands to blocks — that is the block path's (`replicate-with-blocks`) job, and the whole point here is to NOT do that.\n\n**Honesty bar.** Per [[feedback_honest_visual_assessment]] and [[feedback_never_guess_always_look]]: when you report parity, render source and built at the same width, crop both, read both, and itemize the real differences bluntly BEFORE claiming any win. Never assert parity you have not looked at.\n\n## Entry contract — capture already happened\n\n`\u002Fliberate` dispatches you **after** extraction with the resolved `\u003CoutputDir>` (from `liberate_paths`), which already holds the carry inputs. **Assume they exist.** If any required input is missing\u002Fincomplete, STOP and tell the operator to run `\u002Fliberate \u003Curl>` first — do NOT capture here (that's a `\u002Fliberate` capture gap to surface, not silently re-run).\n\n**The carry inputs you consume (all produced by `\u002Fliberate`'s extraction):**\n\n- `html\u002F*.html` — rendered source HTML per page (the carry source). **Required.** Posts are captured as `post--\u003Cname>.html`.\n- `screenshots\u002Fdesktop\u002F*.png` + `screenshots\u002Fmobile\u002F*.png` + `screenshots\u002Fmanifest.json` — source truth for the parity compare. **Required.**\n- `output.wxr` — the base WXR you patch into `output-carry.wxr`.\n- `redirect-map.json` — `[{from,to}]` source-path → local-permalink map. Drives the internal-link rewrite (nav + body hrefs → local). Without it, links pass through to the source domain.\n- `media\u002F` + `media-stubs.json` — downloaded assets and their CDN-URL→filename records. The reconstruct installs these into the site and rewrites carried `\u003Cimg>`\u002F`url()` to the local WP library.\n- `sections\u002F*.json` — optional (the splitter keys off the DOM, not specs), but read if present.\n\n## MCP tool you call\n\n| Tool | What it does |\n|---|---|\n| `liberate_reconstruct_pages_carry({ outputDir, studioSitePath, themeName?, pages })` | **The carry reconstruct.** For each `{ slug, sourceUrl, title, isHome?, postType?, htmlSlug? }`: loads `html\u002F\u003ChtmlSlug ?? slug>.html` (or fetches `sourceUrl`), `collectCss` (cached to `\u003CoutputDir>\u002Fcss\u002F\u003Cslug>.css`), splits header\u002Fmain\u002Ffooter, carries each region verbatim into a `core\u002Fhtml` island, scopes the source CSS (chrome → `body.lib-carry-site` site-wide; main → `body.lib-carry-site.lib-carry-page-\u003Cslug>`), treeshakes against the carried DOM. It also **rewrites internal links** to local permalinks (shared `buildPageLinkMap` over `redirect-map.json`) and **installs the run's media + rewrites carried `\u003Cimg>`\u002F`url()` to the local WP library** (shared `installRunMediaMap` → `installMediaForUrl`). Writes a real FSE block theme to `\u003CstudioSitePath>\u002Fwp-content\u002Fthemes\u002F\u003Cderived-slug>-carry\u002F` (parts\u002Fheader.html, parts\u002Ffooter.html, templates\u002F incl. `single.html` for posts, assets\u002Fcss\u002Fsite.css + page-*.css, functions.php with `is_front_page()`\u002F`is_page()`\u002F`is_single()` body-class + enqueue conditions, theme.json, style.css). Returns `{ themeRoot, themeSlug, themeFilesWritten, mediaInstalled, mediaErrors, fetchErrors, pages: [{ slug, title, isHome, postType, postContent }] }`. |\n\nThe tool reuses the SAME helpers as the block `replicate-with-blocks` path — `buildPageLinkMap` (`src\u002Flib\u002Freplicate\u002Fpage-link-map.ts`) and `installRunMediaMap` (`src\u002Flib\u002Freplicate\u002Frun-media-map.ts`). Don't reimplement link\u002Fmedia logic in the orchestrator.\n\nYou also reuse the shared install\u002Fimport\u002Fcompare tools: `liberate_preview` (provision Studio site), `liberate_import` (WXR import), `liberate_compare` (source-vs-rendered pixel diff). Read their schemas in `src\u002Fmcp-server.ts` before calling.\n\n> **Theme slug derives from `outputDir`.** The resolved `\u003CoutputDir>` drives the theme slug: `\u003Chost>-carry` (the `-carry` suffix is on the THEME name only — the Studio *site* name is just `\u003Chost>`, see step 2). `installMediaForUrl` self-hosts the run's media directly. (Known gap: the slug should really derive from `studioSitePath`, not `outputDir`.)\n\n> **The MCP server does NOT hot-reload.** `liberate_reconstruct_pages_carry` is a new tool — if the server was started before it was added, restart the MCP server first or the tool will be missing. (See AGENTS.md.)\n\n## The flow\n\n**Committed scripts that drive this (all site-generic, all paths from argv):**\n\n| Script | Does |\n|---|---|\n| `carry-reconstruct-drive.ts \u003Cout> --slim` | Step 2: slim `output.wxr` for provisioning (drop attachment items, flip draft→publish), backing the full WXR up to `output.wxr.full`. |\n| `scripts\u002Fcarry-reconstruct-drive.ts` | Steps 1 + 3 + 4 in one run: build the page list, drive `reconstructPagesCarryHandler` (theme + media + islands + `_swap.php`), write `output-carry.wxr`, restore `output.wxr` from `.full`. Pass `\u003CoutputDir> --list` (instead of `\u003CstudioSitePath>`) to just build + inspect the page list cheaply (no handler load). `EXCLUDE=slug1,slug2` drops junk\u002Funwanted pages (404, sitemap, thank-you, or per-site curation). |\n| `scripts\u002Fcarry-replica-shots.ts` | Step 6: screenshot the live carry site into a replica dir for `liberate_compare`. |\n\nThe reconstruct tool can't run via the MCP server (long-lived, no hot-reload), so these tsx scripts run the on-disk handler directly. The page-list + WXR-patch logic is the tested lib `src\u002Flib\u002Freplicate\u002Fcarry-page-list.ts` (`buildCarryPageList` \u002F `buildOutputCarryWxr`) — the single source of truth shared by the driver and its `--list` inspector.\n\n### 1. Resolve the run and build the page list\n\nThe driver builds this internally via `buildCarryPageList` (in the tested lib `src\u002Flib\u002Freplicate\u002Fcarry-page-list.ts`) — you don't hand-assemble it; run `… \u003CoutputDir> --list` to inspect what will carry first. The join it performs, for reference: read `screenshots\u002Fmanifest.json` (URL → files), cross-reference `output.wxr`(.full) for each `page`\u002F`post` item's `post_name` (slug) + title, and produce `pages: [{ slug, sourceUrl, title, isHome?, postType?, htmlSlug? }]`:\n  - **Pages**: `slug` = WP `post_name`, `postType: 'page'`, `htmlSlug` = slug. The front page is captured as `homepage` (matched by root-URL `\u003Clink>` OR `post_name` `home`\u002F`homepage`).\n  - **Posts**: `slug` = bare WP `post_name`, `postType: 'post'`, `htmlSlug` = the manifest slug (e.g. `post--world-teacher-day`). The WXR post `\u003Clink>` drops `\u002Fpost\u002F` but the manifest URL keeps it; join by exact `post--\u003Cpost_name>.html` then prefix-match (`%`-encoded \u002F truncated slugs).\n  - Pages with no captured `html\u002F\u003ChtmlSlug>.html` are skipped + logged.\n\n### 1a. Scope: full carry vs hybrid (blog-dominant sites)\n\n`buildCarryPageList` covers every captured page AND post — correct for **small** sites. But on a **blog\u002Fnews-dominant** source (hundreds of posts), carrying every post is the wrong trade: the carry path emits one scoped-CSS sheet **per** carried page, so N-hundred posts bloat the theme to tens of MB of near-duplicate blog-template CSS (see \"CSS weight\" below), and a pixel-carried article gains nothing over native rendering. Posts are text + images — they belong in a normal blog template fed by the WXR content already extracted.\n\n**Hybrid (default for content-heavy sites):** carry only the custom\u002Fmarketing pages (homepage + service\u002Fabout\u002Flanding — the bespoke designs); let posts, the blog index\u002Farchives, events, and tag\u002Fcategory pages stay **native** (imported from the WXR at provision, rendered by the theme's block templates). Scope the carry set with `EXCLUDE=` on `carry-reconstruct-drive.ts` (drop `\u002Fnews`, `\u002Fblog`, `\u002Fthe-dose`, post archives, …) — run `--list` first to confirm what carries. The capture must cover the carried pages in FULL (a representative-only sample can't carry — `\u002Fliberate` Step 5 makes capture scope depend on this choice); surface the gap, don't silently skip.\n\n**Native-side jobs when going hybrid:**\n\n1. **Working blog templates — now automatic.** When no POST is carried, `buildCarryThemeFiles` auto-emits clean native `single.html` (post-title + date + featured image + content + prev\u002Fnext), `home.html`, and `archive.html` (a `core\u002Fquery` inherit loop) — built from the home page's chrome scaffold with NO dual-viewport wrapper, so they render clean-and-native (NOT pixel-matched to the source feed). `index.html` stays the homepage fallback; set `page_for_posts` to the blog page so `\u002Fblog` resolves to `home.html`. Override with `nativeBlog` on `CarryThemeInput` if needed. (Carried-post runs keep the carried-island `single.html` instead.)\n2. **Native-post media localization.** The carry tool rewrites carried-island `\u003Cimg>`\u002F`url()` to the local library, but **native post bodies keep their source-CDN URLs** — the images ARE downloaded + installed by step 3's media install, only the *content references* aren't rewritten. After step 3, run `npx tsx scripts\u002Flocalize-native-post-media.ts \u003CoutputDir> \u003CstudioSitePath>` to rewrite native `post_content` to the local copies (source→local map from `media-stubs.json`'s recorded `localUrl`s). [[feedback_never_lose_source_content]]\n\n### 2. Provision the Studio site\n\n- **Slim first:** `npx tsx scripts\u002Fcarry-reconstruct-drive.ts \u003CoutputDir> --slim`. A media-heavy WXR (hundreds of attachments) trips Studio's ~120s blueprint-import silence timeout (surfaces as `Error establishing a database connection`; the half-created site is removed) — see [[project_studio_import_heartbeat]]. The `--slim` mode (lib `slimWxrForProvision`) slims `output.wxr` IN PLACE (drops every `attachment` `\u003Citem>`, flips draft→publish) and backs the full WXR up to `output.wxr.full`. The reconstruct installs media separately (step 3), so the provisioned site loses nothing — and **step 3's driver restores `output.wxr` from `.full` at the end**, so the slim is transient and the dir is never left lossy (a later blocks run \u002F `liberate_verify` still sees the full WXR).\n- Provision via `liberate_preview({ outputDir })` — it reads the now-slimmed `output.wxr`. The site is named `\u003Csite>` (e.g. `~\u002FStudio\u002F\u003Csite>`, no path suffix); if a blocks-path site already exists with that name, `studio.ts` uniques it (`\u003Csite>-2`, …), so both paths on one extraction yield distinct sites without clobbering. `liberate_preview` returns `path` (the resolved Studio WP root) — pass it straight through as `studioSitePath` in step 3 (no need to re-derive `~\u002FStudio\u002F\u003Csite>`).\n\n### 3. Run the carry reconstruct (steps 1 + 3 + 4, one command)\n\n- `npx tsx scripts\u002Fcarry-reconstruct-drive.ts \u003CoutputDir> \u003CstudioSitePath> \"\u003CSite> (Carry)\"` — use `liberate_preview`'s returned `path` as `\u003CstudioSitePath>`. This runs `reconstructPagesCarryHandler` on the on-disk source (the MCP server can't — it doesn't hot-reload) and, in one pass: builds the page list (step 1), installs the run's media + self-hosts it (`installMediaForUrl` — one site, one stub store, no cross-site stamping), rewrites links + img\u002Furl to local, writes the theme, writes the islands + `_swap.php`, writes `output-carry.wxr` (step 4), and restores `output.wxr` from `.full`. The theme slug derives from `outputDir` → `\u003Chost>-carry` (theme name only — distinct from the un-suffixed *site* name). The driver prints `THEMESLUG=…`, the `mediaInstalled`\u002F`mediaErrors`\u002F`fetchErrors` counts, the `missingMediaDownloaded`\u002F`fontsLocalized` self-host steps, and the **`self-host audit: residualCdnAssets=N`** assertion (0 = no external asset deps survived).\n- **Verify the fixes landed**, don't assume: confirm `residualCdnAssets=0` (anything else lists the offending hosts\u002Fsamples); the homepage island should have local `\u002F…\u002F` nav hrefs (not `https:\u002F\u002F\u003Csource>\u002F…`) and `…\u002Fwp-content\u002Fuploads\u002F…` img srcs (not the CDN); a post island should have `is_single('\u003Cslug>')` in functions.php; spot-check a few rewritten image\u002Ffont URLs return HTTP 200.\n\n### 4. `output-carry.wxr` (handled by the step-3 driver)\n\nThe step-3 driver already writes this (`buildOutputCarryWxr`): it copies the FULL `output.wxr.full` (with attachments — this is the import deliverable, NOT the slimmed provision WXR) and, for each island, REPLACES that item's `\u003Ccontent:encoded>` body with the island (matching `page` AND `post` items by `\u003Cwp:post_name>` == slug), preserving everything else (titles, dates, IDs, menus, media items) verbatim ([[feedback_never_lose_source_content]]). The island is CDATA-wrapped (any `]]>` escaped as `]]]]>\u003C![CDATA[>`) via a per-item **function** replacer — not a greedy regex, not a string replacement (avoids the `$&`\u002F`$1` footgun, see [[project_capture_document_nesting_bug]]). The driver prints `items`\u002F`patched`\u002F`cdataBalanced`; confirm the item count round-trips and `xmllint --noout \u003CoutputDir>\u002Foutput-carry.wxr` passes.\n\n### 5. Swap content into the live site + activate\n\n- **Do NOT re-import `output-carry.wxr` to update content** — the WXR importer skips items whose GUID already exists, so it won't overwrite content already in the site. Instead swap directly. The step-3 driver already wrote the islands + a `_swap.php` into `\u003CstudioSitePath>\u002Fwp-content\u002Fuploads\u002F_carry-islands\u002F`; run it: `studio wp --path \u003CstudioSitePath> --user=admin eval-file \u002Fwordpress\u002Fwp-content\u002Fuploads\u002F_carry-islands\u002F_swap.php` (VFS path — Studio mounts the site at `\u002Fwordpress`; `--user=admin` gives `unfiltered_html` so KSES doesn't strip carried markup). It finds each post by `post_name` across `['page','post']` and `wp_update_post`s its `post_content`, publishing it.\n- Activate the carry theme (`studio wp --path \u003CstudioSitePath> theme activate \u003CthemeSlug>`). Set the static front page (`option update show_on_front page` + `option update page_on_front \u003Chomepage id>`) and `rewrite flush`.\n\n### 5a. Enrich product marketing (stores only)\n\n- If the run has products, run `npx tsx scripts\u002Fenrich-product-marketing.ts \u003CoutputDir> \u003CstudioSitePath>` AFTER products are imported + media is installed. It rebuilds the CDN→local media map from the attachments' `_dla_source_url` meta (one query — covers already-installed media, which `installRunMediaMap` would miss), reconstructs each product's marketing sections into core blocks (joining section-image URLs to the library by basename so the structured renderers emit them instead of falling back to islands), writes them to each product's `post_content` (joined by SKU) and the short blurb to the excerpt, in one bulk DB pass. It prints a per-product `N core blocks, M html islands` line; expect mostly core blocks (islands only for sections too complex to reconstruct without losing content).\n- **Verify:** load a product page — the buy box (gallery + title + price + add-to-cart) is functional Woo, and the rich marketing renders full-width below it (not a thin blurb). A product that comes out thin means its section specs weren't captured (re-capture) or its marketing is JS-rendered.\n\n### 6. Render, screenshot, and compare — the parity verdict\n\n- Screenshot the built site (desktop + mobile) for every page: `npx tsx scripts\u002Fcarry-replica-shots.ts \u003CoutputDir> \u003CcarryBaseUrl> \u003CoutputDir>\u002Freplica-carry`. It navigates via `redirect-map.json` (posts move `\u002Fpost\u002F\u003Cslug>` → `\u002F\u003Cslug>\u002F`, which WP further 301s to its date permalink, so the bare source path would rely on WP's flaky canonical-redirect guessing), and keys the replica manifest by the SOURCE url so `liberate_compare` joins origin↔replica by pathname.\n- Run `liberate_compare({ originDir: \"\u003CoutputDir>\u002Fscreenshots\", replicaDir: \"\u003CoutputDir>\u002Freplica-carry\" })` against the SOURCE screenshots. Emit `\u003CoutputDir>\u002Frun-report-carry.json` with a per-page and overall parity score, mirroring the block path's `run-report.json` shape. **Include `residualCdnAssets`** (from the step-3 driver's self-host audit; 0 = fully self-hosted) with any offending hosts\u002Fsamples — this is a correctness deliverable, reported separately from the pixel score.\n- **Chrome-fidelity audit.** After the carry build, run `npx tsx scripts\u002Fcarry-chrome-audit-run.ts \u003CoutputDir> \u003CbuiltBaseUrl> \u003CstudioSitePath>` — it renders the built site's header, footer, and nav, diffs them against the source `chrome-fidelity.json` captured during screenshots, and appends source-copied corrections (display, opacity, text-decoration, line-height, font-size, etc.) to the theme's `site.css`. It writes `\u003CoutputDir>\u002Fchrome-audit.json` and populates two run-report tallies: `chromeCorrections` (CSS properties auto-applied to close the gap — informational, self-healing) and `droppedChrome` (a source chrome element — nav link, footer item, logo — that didn't survive the carry at all). A non-zero `droppedChrome` triggers a **warn** verdict and should be investigated; `chromeCorrections` is reported but does not affect the verdict.\n- **Report the carry score directly NEXT TO the block path's score** for the same pages. This is the deliverable — the evidence for whether carry-and-scope actually wins, and by how much.\n- Then do the honest visual pass: for the 2–3 worst pages, crop source and built at the same width side by side, read both, and itemize the real differences. State plainly where the carry theme still falls short.\n\n## Self-hosting & structure — VERIFY, don't assume\n\nAn earlier version of this skill listed \"media is self-hosted\" as a settled fact you needn't re-check. That was both **wrong** (a Wix carry shipped ~half its gallery images, its whole font library, and dead preload `\u003Clink>`s still on the builder CDN) and a **trap** — telling the agent not to re-describe it as a gap suppressed the verify-before-claiming discipline ([[feedback_never_guess_always_look]]). So: **never assert self-hosting from memory. The reconstruct ASSERTS it and you report the number.** After all localization the handler runs `findExternalAssetRefs` (`src\u002Flib\u002Freplicate\u002Fcarry-cdn-audit.ts`) over the assembled islands + theme CSS\u002Fparts and returns `residualCdnAssets` (+ `residualCdnByHost` \u002F `residualCdnSamples`); the driver prints `self-host audit: residualCdnAssets=N`. **A clean run is 0** — put it in the run-report. Anything >0 is a leak to chase (it does not flip the verdict, but it is not \"done\"). The audit scans ASSET positions only (`\u003Cimg src>`\u002F`srcset`, CSS `url()`), so it never false-flags `\u003Ciframe>` embeds or editorial `\u003Ca href>` links.\n\nSelf-hosting seams — what closes each leak:\n- **Images.** `installRunMediaMap` installs the run's media and rewrites carried `\u003Cimg src>`\u002F`srcset` to the local library. Two former leaks, now closed: (a) responsive\u002Fgallery **mobile-crop** URLs are injected AFTER that rewrite — `assembleResponsiveMobile` (`carry-responsive-assemble.ts`) repoints them to the local desktop copy via the Wix media-id alias; (b) images the extraction never downloaded (no local copy to point at) are fetched up front by `fetchMissingCarriedMedia` (`carry-missing-media.ts`) before install.\n- **Fonts.** `localizeCarryFonts` (`carry-fonts.ts`) strips `@font-face` whose family is never applied, downloads the used fonts into the theme's `assets\u002Ffonts\u002F` (handles protocol-relative `\u002F\u002Fstatic.parastorage.com`, Wix's main font CDN), rewrites `url()` → `..\u002Ffonts\u002F`, and strips dev-only `sourceMappingURL` CDN comments. Fonts are also kept OUT of media collection upstream (`isFontUrl` in `media.ts`) so they never enter the uploads pipeline.\n- **Resource-hint links.** `carryHtml` strips `\u003Clink rel=preload\u002Fprefetch\u002Fmodulepreload\u002Fpreconnect\u002Fdns-prefetch>` and any `\u003Clink>` whose href is on a builder CDN — inert in a static carry but a browser would still prefetch them.\n- **Internal links are local.** Nav + body hrefs → imported permalinks via the shared `buildPageLinkMap`. Editorial\u002Fexternal links (RSS, social, \"powered by\"\u002Fhelp-article links) are correctly LEFT ALONE — they are content, not asset deps ([[feedback_never_lose_source_content]]).\n- **Posts are carried.** `postType: 'post'` scopes via `is_single()` and renders through one shared `single.html`; per-post CSS still scopes individually by body class.\n- **It is a real FSE block theme.** `wp_is_block_theme()` → true (theme.json v3 + block templates + parts). Only the page\u002Fpost *body* is a single `core\u002Fhtml` island (the deliberate non-block-editable trade).\n- **WooCommerce store pages get chrome + rich product marketing (v4).** When the run has products, the reconstruct emits `templates\u002Fsingle-product.html` + `templates\u002Farchive-product.html` wrapped in a dedicated `header-store` part + canonical footer. **`archive-product.html`** wraps `wp:woocommerce\u002Flegacy-template` (classic shop grid + sorting\u002Fpagination). **`single-product.html`** uses MODERN WC product blocks for the buy box (`product-image-gallery` + `core\u002Fpost-title` + `product-rating` + `product-price` + `product-summary` + `add-to-cart-form` + `product-meta`) so order is controllable, then renders the product's rich source marketing FULL-WIDTH below via `core\u002Fpost-content`. That post_content is produced by **`scripts\u002Fenrich-product-marketing.ts`** (flow step 5a): it reconstructs each product page's marketing sections (everything but the gallery\u002Fhero Woo reproduces + footer chrome) into CORE blocks via the block path's `reconstructPagePattern` (with a per-section `core\u002Fhtml` fallback where reconstruction would drop content), and sets the short Shopify blurb as the product excerpt (shown by `product-summary`). theme.json carries the captured palette\u002Ffont tokens (`loadCarryDesignTokens`) so the core blocks resolve their color\u002Ffont references. The source's \"you may also like\" lands at the end of the marketing (the standalone `woocommerce\u002Frelated-products` block does not render on this template). Provision also sets `woocommerce_coming_soon=no` (WC 8.x+ ships it ON). If NO header can be isolated, the handler emits a `warnings[]` entry and store pages fall back to WC's bare defaults. Product *data* fidelity still depends on the extraction tier (Tier 1 = no variant images \u002F collections→categories); marketing fidelity depends on the captured section specs (a JS-rendered comparison table whose columns weren't captured renders sparse).\n\n## Known limitations (state these in the report; do not let them masquerade as success)\n\n- **CSS-file `url()` *backgrounds* only rewrite on exact map-key match.** Carried HTML `\u003Cimg>`\u002F`srcset`, font `url()`s, and inline `url()` self-host robustly (see \"Self-hosting seams\" above — incl. Wix transform URLs via `rewriteMediaUrls`'s longest-source-first ordering). But *background-image* `url()`s in the scoped CSS sheets are only rewritten when the exact URL is a map key; a relative\u002Fquery-string background can still point at the source. This is no longer a silent gap: the **residual-CDN audit flags any that survive** (`residualCdnAssets`), so it shows up in the run-report instead of shipping unnoticed.\n- **`data-pin-media` (Pinterest) transform URLs still mangle** — invisible (not rendered), harmless; the candidate collector doesn't scan that attribute.\n- **Non-semantic chrome (headers ride inline).** On sites without top-level `\u003Cheader>`\u002F`\u003Cfooter>` tags (many Wix\u002FSquarespace — and Shopify, whose `\u003Cheader>` is wrapped deeply enough that `splitRegions` doesn't lift it), the separate header\u002Ffooter parts come back empty and the chrome rides INLINE in each page's main island. Content pages render fine (their island carries the header); WooCommerce store pages — which have no island — instead use the extracted `header-store` part (see \"store pages get chrome\" above).\n- **Dynamic behavior dropped.** Scripts are stripped; carousels, menus, scroll effects won't animate. Static computed layout is carried.\n- **Wix scale offset (the dominant fidelity gap).** Carried Wix layout renders larger than the source capture at the same width (Wix's responsive scaling is JS-driven and absent in static carry), pushing content below the fold. Worst on the homepage. This — not media\u002Flinks — is the open lever.\n- **CSS weight.** Per-page sheets carry treeshaken source CSS; on chrome-less Wix the full chrome CSS duplicates into every page\u002Fpost sheet (50 sheets × ~150KB). Acceptable for a parity path.\n\n## When you finish\n\nSummarize the carry vs block parity scores side by side and the honest itemized gaps on the worst pages.\n\n**Pixel scores on dynamic (Wix\u002FJS) sites carry real capture noise — quantify it before claiming a win.** Capturing the SAME built site 2–3 times moved the overall score ±0.02, and individual dynamic content pages (blog feeds, galleries) swung 0.10–0.12 from lazy-load\u002Fanimation timing. On corneliusholmes that spread *exceeded* the carry-vs-block gap → the numeric A\u002FB is a **tie**, even though the carried pages are content-faithful. So: report the multi-capture spread, and separate **correctness wins** (self-hosted assets via `residualCdnAssets=0`, local links, posts rendering — verify each visually\u002Fby HTTP, never from memory) from **pixel-score wins** (often within noise). Recommend next steps from the evidence — the Wix scale offset is the highest-leverage open item, not media or links.\n",{"data":37,"body":47},{"name":4,"description":6,"allowed-tools":38,"disable-model-invocation":46},[39,40,41,42,43,44,45],"Bash","Read","Write","Edit","Glob","Grep","AskUserQuestion",true,{"type":48,"children":49},"root",[50,59,89,122,132,139,194,209,351,357,573,613,650,732,753,759,767,922,958,965,1037,1204,1210,1241,1310,1318,1491,1497,1678,1684,1884,1897,2014,2020,2151,2157,2213,2219,2400,2406,2527,2532,2990,2996,3176,3182,3187],{"type":51,"tag":52,"props":53,"children":55},"element","h1",{"id":54},"replicate-theme-carry-and-scope-parity-path",[56],{"type":57,"value":58},"text","Replicate Theme — Carry-and-Scope Parity Path",{"type":51,"tag":60,"props":61,"children":62},"p",{},[63,65,71,73,80,82,87],{"type":57,"value":64},"You are the ",{"type":51,"tag":66,"props":67,"children":68},"strong",{},[69],{"type":57,"value":70},"carry-and-scope reconstruct orchestrator",{"type":57,"value":72},". ",{"type":51,"tag":74,"props":75,"children":77},"code",{"className":76},[],[78],{"type":57,"value":79},"\u002Fliberate",{"type":57,"value":81}," dispatches you inline after it has captured the site; you rebuild it by carrying the source markup near-verbatim and scoping the source's own CSS, rather than projecting onto core blocks. The goal is maximum visual parity. You own only the reconstruct→theme stage — capture already happened in ",{"type":51,"tag":74,"props":83,"children":85},{"className":84},[],[86],{"type":57,"value":79},{"type":57,"value":88},".",{"type":51,"tag":60,"props":90,"children":91},{},[92,97,99,105,107,112,114,120],{"type":51,"tag":66,"props":93,"children":94},{},[95],{"type":57,"value":96},"Read this first — what you are trading.",{"type":57,"value":98}," This path emits each page region as a single ",{"type":51,"tag":74,"props":100,"children":102},{"className":101},[],[103],{"type":57,"value":104},"core\u002Fhtml",{"type":57,"value":106}," island. These pages are ",{"type":51,"tag":66,"props":108,"children":109},{},[110],{"type":57,"value":111},"raw-HTML-editable, not block-editable",{"type":57,"value":113},". You are deliberately trading all block editability for fidelity. Do not \"improve\" the output by converting islands to blocks — that is the block path's (",{"type":51,"tag":74,"props":115,"children":117},{"className":116},[],[118],{"type":57,"value":119},"replicate-with-blocks",{"type":57,"value":121},") job, and the whole point here is to NOT do that.",{"type":51,"tag":60,"props":123,"children":124},{},[125,130],{"type":51,"tag":66,"props":126,"children":127},{},[128],{"type":57,"value":129},"Honesty bar.",{"type":57,"value":131}," Per [[feedback_honest_visual_assessment]] and [[feedback_never_guess_always_look]]: when you report parity, render source and built at the same width, crop both, read both, and itemize the real differences bluntly BEFORE claiming any win. Never assert parity you have not looked at.",{"type":51,"tag":133,"props":134,"children":136},"h2",{"id":135},"entry-contract-capture-already-happened",[137],{"type":57,"value":138},"Entry contract — capture already happened",{"type":51,"tag":60,"props":140,"children":141},{},[142,147,149,154,156,162,164,170,172,177,179,185,187,192],{"type":51,"tag":74,"props":143,"children":145},{"className":144},[],[146],{"type":57,"value":79},{"type":57,"value":148}," dispatches you ",{"type":51,"tag":66,"props":150,"children":151},{},[152],{"type":57,"value":153},"after",{"type":57,"value":155}," extraction with the resolved ",{"type":51,"tag":74,"props":157,"children":159},{"className":158},[],[160],{"type":57,"value":161},"\u003CoutputDir>",{"type":57,"value":163}," (from ",{"type":51,"tag":74,"props":165,"children":167},{"className":166},[],[168],{"type":57,"value":169},"liberate_paths",{"type":57,"value":171},"), which already holds the carry inputs. ",{"type":51,"tag":66,"props":173,"children":174},{},[175],{"type":57,"value":176},"Assume they exist.",{"type":57,"value":178}," If any required input is missing\u002Fincomplete, STOP and tell the operator to run ",{"type":51,"tag":74,"props":180,"children":182},{"className":181},[],[183],{"type":57,"value":184},"\u002Fliberate \u003Curl>",{"type":57,"value":186}," first — do NOT capture here (that's a ",{"type":51,"tag":74,"props":188,"children":190},{"className":189},[],[191],{"type":57,"value":79},{"type":57,"value":193}," capture gap to surface, not silently re-run).",{"type":51,"tag":60,"props":195,"children":196},{},[197],{"type":51,"tag":66,"props":198,"children":199},{},[200,202,207],{"type":57,"value":201},"The carry inputs you consume (all produced by ",{"type":51,"tag":74,"props":203,"children":205},{"className":204},[],[206],{"type":57,"value":79},{"type":57,"value":208},"'s extraction):",{"type":51,"tag":210,"props":211,"children":212},"ul",{},[213,239,269,287,306,340],{"type":51,"tag":214,"props":215,"children":216},"li",{},[217,223,225,230,232,238],{"type":51,"tag":74,"props":218,"children":220},{"className":219},[],[221],{"type":57,"value":222},"html\u002F*.html",{"type":57,"value":224}," — rendered source HTML per page (the carry source). ",{"type":51,"tag":66,"props":226,"children":227},{},[228],{"type":57,"value":229},"Required.",{"type":57,"value":231}," Posts are captured as ",{"type":51,"tag":74,"props":233,"children":235},{"className":234},[],[236],{"type":57,"value":237},"post--\u003Cname>.html",{"type":57,"value":88},{"type":51,"tag":214,"props":240,"children":241},{},[242,248,250,256,257,263,265],{"type":51,"tag":74,"props":243,"children":245},{"className":244},[],[246],{"type":57,"value":247},"screenshots\u002Fdesktop\u002F*.png",{"type":57,"value":249}," + ",{"type":51,"tag":74,"props":251,"children":253},{"className":252},[],[254],{"type":57,"value":255},"screenshots\u002Fmobile\u002F*.png",{"type":57,"value":249},{"type":51,"tag":74,"props":258,"children":260},{"className":259},[],[261],{"type":57,"value":262},"screenshots\u002Fmanifest.json",{"type":57,"value":264}," — source truth for the parity compare. ",{"type":51,"tag":66,"props":266,"children":267},{},[268],{"type":57,"value":229},{"type":51,"tag":214,"props":270,"children":271},{},[272,278,280,286],{"type":51,"tag":74,"props":273,"children":275},{"className":274},[],[276],{"type":57,"value":277},"output.wxr",{"type":57,"value":279}," — the base WXR you patch into ",{"type":51,"tag":74,"props":281,"children":283},{"className":282},[],[284],{"type":57,"value":285},"output-carry.wxr",{"type":57,"value":88},{"type":51,"tag":214,"props":288,"children":289},{},[290,296,298,304],{"type":51,"tag":74,"props":291,"children":293},{"className":292},[],[294],{"type":57,"value":295},"redirect-map.json",{"type":57,"value":297}," — ",{"type":51,"tag":74,"props":299,"children":301},{"className":300},[],[302],{"type":57,"value":303},"[{from,to}]",{"type":57,"value":305}," source-path → local-permalink map. Drives the internal-link rewrite (nav + body hrefs → local). Without it, links pass through to the source domain.",{"type":51,"tag":214,"props":307,"children":308},{},[309,315,316,322,324,330,332,338],{"type":51,"tag":74,"props":310,"children":312},{"className":311},[],[313],{"type":57,"value":314},"media\u002F",{"type":57,"value":249},{"type":51,"tag":74,"props":317,"children":319},{"className":318},[],[320],{"type":57,"value":321},"media-stubs.json",{"type":57,"value":323}," — downloaded assets and their CDN-URL→filename records. The reconstruct installs these into the site and rewrites carried ",{"type":51,"tag":74,"props":325,"children":327},{"className":326},[],[328],{"type":57,"value":329},"\u003Cimg>",{"type":57,"value":331},"\u002F",{"type":51,"tag":74,"props":333,"children":335},{"className":334},[],[336],{"type":57,"value":337},"url()",{"type":57,"value":339}," to the local WP library.",{"type":51,"tag":214,"props":341,"children":342},{},[343,349],{"type":51,"tag":74,"props":344,"children":346},{"className":345},[],[347],{"type":57,"value":348},"sections\u002F*.json",{"type":57,"value":350}," — optional (the splitter keys off the DOM, not specs), but read if present.",{"type":51,"tag":133,"props":352,"children":354},{"id":353},"mcp-tool-you-call",[355],{"type":57,"value":356},"MCP tool you call",{"type":51,"tag":358,"props":359,"children":360},"table",{},[361,380],{"type":51,"tag":362,"props":363,"children":364},"thead",{},[365],{"type":51,"tag":366,"props":367,"children":368},"tr",{},[369,375],{"type":51,"tag":370,"props":371,"children":372},"th",{},[373],{"type":57,"value":374},"Tool",{"type":51,"tag":370,"props":376,"children":377},{},[378],{"type":57,"value":379},"What it does",{"type":51,"tag":381,"props":382,"children":383},"tbody",{},[384],{"type":51,"tag":366,"props":385,"children":386},{},[387,397],{"type":51,"tag":388,"props":389,"children":390},"td",{},[391],{"type":51,"tag":74,"props":392,"children":394},{"className":393},[],[395],{"type":57,"value":396},"liberate_reconstruct_pages_carry({ outputDir, studioSitePath, themeName?, pages })",{"type":51,"tag":388,"props":398,"children":399},{},[400,405,407,413,415,421,423,429,431,437,439,445,447,452,454,460,462,468,470,475,477,483,485,490,492,510,512,518,520,526,528,534,536,542,544,550,551,557,558,564,566,572],{"type":51,"tag":66,"props":401,"children":402},{},[403],{"type":57,"value":404},"The carry reconstruct.",{"type":57,"value":406}," For each ",{"type":51,"tag":74,"props":408,"children":410},{"className":409},[],[411],{"type":57,"value":412},"{ slug, sourceUrl, title, isHome?, postType?, htmlSlug? }",{"type":57,"value":414},": loads ",{"type":51,"tag":74,"props":416,"children":418},{"className":417},[],[419],{"type":57,"value":420},"html\u002F\u003ChtmlSlug ?? slug>.html",{"type":57,"value":422}," (or fetches ",{"type":51,"tag":74,"props":424,"children":426},{"className":425},[],[427],{"type":57,"value":428},"sourceUrl",{"type":57,"value":430},"), ",{"type":51,"tag":74,"props":432,"children":434},{"className":433},[],[435],{"type":57,"value":436},"collectCss",{"type":57,"value":438}," (cached to ",{"type":51,"tag":74,"props":440,"children":442},{"className":441},[],[443],{"type":57,"value":444},"\u003CoutputDir>\u002Fcss\u002F\u003Cslug>.css",{"type":57,"value":446},"), splits header\u002Fmain\u002Ffooter, carries each region verbatim into a ",{"type":51,"tag":74,"props":448,"children":450},{"className":449},[],[451],{"type":57,"value":104},{"type":57,"value":453}," island, scopes the source CSS (chrome → ",{"type":51,"tag":74,"props":455,"children":457},{"className":456},[],[458],{"type":57,"value":459},"body.lib-carry-site",{"type":57,"value":461}," site-wide; main → ",{"type":51,"tag":74,"props":463,"children":465},{"className":464},[],[466],{"type":57,"value":467},"body.lib-carry-site.lib-carry-page-\u003Cslug>",{"type":57,"value":469},"), treeshakes against the carried DOM. It also ",{"type":51,"tag":66,"props":471,"children":472},{},[473],{"type":57,"value":474},"rewrites internal links",{"type":57,"value":476}," to local permalinks (shared ",{"type":51,"tag":74,"props":478,"children":480},{"className":479},[],[481],{"type":57,"value":482},"buildPageLinkMap",{"type":57,"value":484}," over ",{"type":51,"tag":74,"props":486,"children":488},{"className":487},[],[489],{"type":57,"value":295},{"type":57,"value":491},") and ",{"type":51,"tag":66,"props":493,"children":494},{},[495,497,502,503,508],{"type":57,"value":496},"installs the run's media + rewrites carried ",{"type":51,"tag":74,"props":498,"children":500},{"className":499},[],[501],{"type":57,"value":329},{"type":57,"value":331},{"type":51,"tag":74,"props":504,"children":506},{"className":505},[],[507],{"type":57,"value":337},{"type":57,"value":509}," to the local WP library",{"type":57,"value":511}," (shared ",{"type":51,"tag":74,"props":513,"children":515},{"className":514},[],[516],{"type":57,"value":517},"installRunMediaMap",{"type":57,"value":519}," → ",{"type":51,"tag":74,"props":521,"children":523},{"className":522},[],[524],{"type":57,"value":525},"installMediaForUrl",{"type":57,"value":527},"). Writes a real FSE block theme to ",{"type":51,"tag":74,"props":529,"children":531},{"className":530},[],[532],{"type":57,"value":533},"\u003CstudioSitePath>\u002Fwp-content\u002Fthemes\u002F\u003Cderived-slug>-carry\u002F",{"type":57,"value":535}," (parts\u002Fheader.html, parts\u002Ffooter.html, templates\u002F incl. ",{"type":51,"tag":74,"props":537,"children":539},{"className":538},[],[540],{"type":57,"value":541},"single.html",{"type":57,"value":543}," for posts, assets\u002Fcss\u002Fsite.css + page-*.css, functions.php with ",{"type":51,"tag":74,"props":545,"children":547},{"className":546},[],[548],{"type":57,"value":549},"is_front_page()",{"type":57,"value":331},{"type":51,"tag":74,"props":552,"children":554},{"className":553},[],[555],{"type":57,"value":556},"is_page()",{"type":57,"value":331},{"type":51,"tag":74,"props":559,"children":561},{"className":560},[],[562],{"type":57,"value":563},"is_single()",{"type":57,"value":565}," body-class + enqueue conditions, theme.json, style.css). Returns ",{"type":51,"tag":74,"props":567,"children":569},{"className":568},[],[570],{"type":57,"value":571},"{ themeRoot, themeSlug, themeFilesWritten, mediaInstalled, mediaErrors, fetchErrors, pages: [{ slug, title, isHome, postType, postContent }] }",{"type":57,"value":88},{"type":51,"tag":60,"props":574,"children":575},{},[576,578,583,585,590,592,598,599,604,605,611],{"type":57,"value":577},"The tool reuses the SAME helpers as the block ",{"type":51,"tag":74,"props":579,"children":581},{"className":580},[],[582],{"type":57,"value":119},{"type":57,"value":584}," path — ",{"type":51,"tag":74,"props":586,"children":588},{"className":587},[],[589],{"type":57,"value":482},{"type":57,"value":591}," (",{"type":51,"tag":74,"props":593,"children":595},{"className":594},[],[596],{"type":57,"value":597},"src\u002Flib\u002Freplicate\u002Fpage-link-map.ts",{"type":57,"value":491},{"type":51,"tag":74,"props":600,"children":602},{"className":601},[],[603],{"type":57,"value":517},{"type":57,"value":591},{"type":51,"tag":74,"props":606,"children":608},{"className":607},[],[609],{"type":57,"value":610},"src\u002Flib\u002Freplicate\u002Frun-media-map.ts",{"type":57,"value":612},"). Don't reimplement link\u002Fmedia logic in the orchestrator.",{"type":51,"tag":60,"props":614,"children":615},{},[616,618,624,626,632,634,640,642,648],{"type":57,"value":617},"You also reuse the shared install\u002Fimport\u002Fcompare tools: ",{"type":51,"tag":74,"props":619,"children":621},{"className":620},[],[622],{"type":57,"value":623},"liberate_preview",{"type":57,"value":625}," (provision Studio site), ",{"type":51,"tag":74,"props":627,"children":629},{"className":628},[],[630],{"type":57,"value":631},"liberate_import",{"type":57,"value":633}," (WXR import), ",{"type":51,"tag":74,"props":635,"children":637},{"className":636},[],[638],{"type":57,"value":639},"liberate_compare",{"type":57,"value":641}," (source-vs-rendered pixel diff). Read their schemas in ",{"type":51,"tag":74,"props":643,"children":645},{"className":644},[],[646],{"type":57,"value":647},"src\u002Fmcp-server.ts",{"type":57,"value":649}," before calling.",{"type":51,"tag":651,"props":652,"children":653},"blockquote",{},[654],{"type":51,"tag":60,"props":655,"children":656},{},[657,669,671,676,678,684,686,692,694,700,702,708,710,715,717,723,725,730],{"type":51,"tag":66,"props":658,"children":659},{},[660,662,668],{"type":57,"value":661},"Theme slug derives from ",{"type":51,"tag":74,"props":663,"children":665},{"className":664},[],[666],{"type":57,"value":667},"outputDir",{"type":57,"value":88},{"type":57,"value":670}," The resolved ",{"type":51,"tag":74,"props":672,"children":674},{"className":673},[],[675],{"type":57,"value":161},{"type":57,"value":677}," drives the theme slug: ",{"type":51,"tag":74,"props":679,"children":681},{"className":680},[],[682],{"type":57,"value":683},"\u003Chost>-carry",{"type":57,"value":685}," (the ",{"type":51,"tag":74,"props":687,"children":689},{"className":688},[],[690],{"type":57,"value":691},"-carry",{"type":57,"value":693}," suffix is on the THEME name only — the Studio ",{"type":51,"tag":695,"props":696,"children":697},"em",{},[698],{"type":57,"value":699},"site",{"type":57,"value":701}," name is just ",{"type":51,"tag":74,"props":703,"children":705},{"className":704},[],[706],{"type":57,"value":707},"\u003Chost>",{"type":57,"value":709},", see step 2). ",{"type":51,"tag":74,"props":711,"children":713},{"className":712},[],[714],{"type":57,"value":525},{"type":57,"value":716}," self-hosts the run's media directly. (Known gap: the slug should really derive from ",{"type":51,"tag":74,"props":718,"children":720},{"className":719},[],[721],{"type":57,"value":722},"studioSitePath",{"type":57,"value":724},", not ",{"type":51,"tag":74,"props":726,"children":728},{"className":727},[],[729],{"type":57,"value":667},{"type":57,"value":731},".)",{"type":51,"tag":651,"props":733,"children":734},{},[735],{"type":51,"tag":60,"props":736,"children":737},{},[738,743,745,751],{"type":51,"tag":66,"props":739,"children":740},{},[741],{"type":57,"value":742},"The MCP server does NOT hot-reload.",{"type":57,"value":744}," ",{"type":51,"tag":74,"props":746,"children":748},{"className":747},[],[749],{"type":57,"value":750},"liberate_reconstruct_pages_carry",{"type":57,"value":752}," is a new tool — if the server was started before it was added, restart the MCP server first or the tool will be missing. (See AGENTS.md.)",{"type":51,"tag":133,"props":754,"children":756},{"id":755},"the-flow",[757],{"type":57,"value":758},"The flow",{"type":51,"tag":60,"props":760,"children":761},{},[762],{"type":51,"tag":66,"props":763,"children":764},{},[765],{"type":57,"value":766},"Committed scripts that drive this (all site-generic, all paths from argv):",{"type":51,"tag":358,"props":768,"children":769},{},[770,786],{"type":51,"tag":362,"props":771,"children":772},{},[773],{"type":51,"tag":366,"props":774,"children":775},{},[776,781],{"type":51,"tag":370,"props":777,"children":778},{},[779],{"type":57,"value":780},"Script",{"type":51,"tag":370,"props":782,"children":783},{},[784],{"type":57,"value":785},"Does",{"type":51,"tag":381,"props":787,"children":788},{},[789,820,899],{"type":51,"tag":366,"props":790,"children":791},{},[792,801],{"type":51,"tag":388,"props":793,"children":794},{},[795],{"type":51,"tag":74,"props":796,"children":798},{"className":797},[],[799],{"type":57,"value":800},"carry-reconstruct-drive.ts \u003Cout> --slim",{"type":51,"tag":388,"props":802,"children":803},{},[804,806,811,813,819],{"type":57,"value":805},"Step 2: slim ",{"type":51,"tag":74,"props":807,"children":809},{"className":808},[],[810],{"type":57,"value":277},{"type":57,"value":812}," for provisioning (drop attachment items, flip draft→publish), backing the full WXR up to ",{"type":51,"tag":74,"props":814,"children":816},{"className":815},[],[817],{"type":57,"value":818},"output.wxr.full",{"type":57,"value":88},{"type":51,"tag":366,"props":821,"children":822},{},[823,832],{"type":51,"tag":388,"props":824,"children":825},{},[826],{"type":51,"tag":74,"props":827,"children":829},{"className":828},[],[830],{"type":57,"value":831},"scripts\u002Fcarry-reconstruct-drive.ts",{"type":51,"tag":388,"props":833,"children":834},{},[835,837,843,845,851,853,858,860,865,867,873,875,881,883,889,891,897],{"type":57,"value":836},"Steps 1 + 3 + 4 in one run: build the page list, drive ",{"type":51,"tag":74,"props":838,"children":840},{"className":839},[],[841],{"type":57,"value":842},"reconstructPagesCarryHandler",{"type":57,"value":844}," (theme + media + islands + ",{"type":51,"tag":74,"props":846,"children":848},{"className":847},[],[849],{"type":57,"value":850},"_swap.php",{"type":57,"value":852},"), write ",{"type":51,"tag":74,"props":854,"children":856},{"className":855},[],[857],{"type":57,"value":285},{"type":57,"value":859},", restore ",{"type":51,"tag":74,"props":861,"children":863},{"className":862},[],[864],{"type":57,"value":277},{"type":57,"value":866}," from ",{"type":51,"tag":74,"props":868,"children":870},{"className":869},[],[871],{"type":57,"value":872},".full",{"type":57,"value":874},". Pass ",{"type":51,"tag":74,"props":876,"children":878},{"className":877},[],[879],{"type":57,"value":880},"\u003CoutputDir> --list",{"type":57,"value":882}," (instead of ",{"type":51,"tag":74,"props":884,"children":886},{"className":885},[],[887],{"type":57,"value":888},"\u003CstudioSitePath>",{"type":57,"value":890},") to just build + inspect the page list cheaply (no handler load). ",{"type":51,"tag":74,"props":892,"children":894},{"className":893},[],[895],{"type":57,"value":896},"EXCLUDE=slug1,slug2",{"type":57,"value":898}," drops junk\u002Funwanted pages (404, sitemap, thank-you, or per-site curation).",{"type":51,"tag":366,"props":900,"children":901},{},[902,911],{"type":51,"tag":388,"props":903,"children":904},{},[905],{"type":51,"tag":74,"props":906,"children":908},{"className":907},[],[909],{"type":57,"value":910},"scripts\u002Fcarry-replica-shots.ts",{"type":51,"tag":388,"props":912,"children":913},{},[914,916,921],{"type":57,"value":915},"Step 6: screenshot the live carry site into a replica dir for ",{"type":51,"tag":74,"props":917,"children":919},{"className":918},[],[920],{"type":57,"value":639},{"type":57,"value":88},{"type":51,"tag":60,"props":923,"children":924},{},[925,927,933,934,940,942,948,950,956],{"type":57,"value":926},"The reconstruct tool can't run via the MCP server (long-lived, no hot-reload), so these tsx scripts run the on-disk handler directly. The page-list + WXR-patch logic is the tested lib ",{"type":51,"tag":74,"props":928,"children":930},{"className":929},[],[931],{"type":57,"value":932},"src\u002Flib\u002Freplicate\u002Fcarry-page-list.ts",{"type":57,"value":591},{"type":51,"tag":74,"props":935,"children":937},{"className":936},[],[938],{"type":57,"value":939},"buildCarryPageList",{"type":57,"value":941}," \u002F ",{"type":51,"tag":74,"props":943,"children":945},{"className":944},[],[946],{"type":57,"value":947},"buildOutputCarryWxr",{"type":57,"value":949},") — the single source of truth shared by the driver and its ",{"type":51,"tag":74,"props":951,"children":953},{"className":952},[],[954],{"type":57,"value":955},"--list",{"type":57,"value":957}," inspector.",{"type":51,"tag":959,"props":960,"children":962},"h3",{"id":961},"_1-resolve-the-run-and-build-the-page-list",[963],{"type":57,"value":964},"1. Resolve the run and build the page list",{"type":51,"tag":60,"props":966,"children":967},{},[968,970,975,977,982,984,990,992,997,999,1004,1006,1012,1013,1019,1021,1027,1029,1035],{"type":57,"value":969},"The driver builds this internally via ",{"type":51,"tag":74,"props":971,"children":973},{"className":972},[],[974],{"type":57,"value":939},{"type":57,"value":976}," (in the tested lib ",{"type":51,"tag":74,"props":978,"children":980},{"className":979},[],[981],{"type":57,"value":932},{"type":57,"value":983},") — you don't hand-assemble it; run ",{"type":51,"tag":74,"props":985,"children":987},{"className":986},[],[988],{"type":57,"value":989},"… \u003CoutputDir> --list",{"type":57,"value":991}," to inspect what will carry first. The join it performs, for reference: read ",{"type":51,"tag":74,"props":993,"children":995},{"className":994},[],[996],{"type":57,"value":262},{"type":57,"value":998}," (URL → files), cross-reference ",{"type":51,"tag":74,"props":1000,"children":1002},{"className":1001},[],[1003],{"type":57,"value":277},{"type":57,"value":1005},"(.full) for each ",{"type":51,"tag":74,"props":1007,"children":1009},{"className":1008},[],[1010],{"type":57,"value":1011},"page",{"type":57,"value":331},{"type":51,"tag":74,"props":1014,"children":1016},{"className":1015},[],[1017],{"type":57,"value":1018},"post",{"type":57,"value":1020}," item's ",{"type":51,"tag":74,"props":1022,"children":1024},{"className":1023},[],[1025],{"type":57,"value":1026},"post_name",{"type":57,"value":1028}," (slug) + title, and produce ",{"type":51,"tag":74,"props":1030,"children":1032},{"className":1031},[],[1033],{"type":57,"value":1034},"pages: [{ slug, sourceUrl, title, isHome?, postType?, htmlSlug? }]",{"type":57,"value":1036},":",{"type":51,"tag":210,"props":1038,"children":1039},{},[1040,1116,1191],{"type":51,"tag":214,"props":1041,"children":1042},{},[1043,1048,1050,1056,1058,1063,1065,1071,1072,1078,1080,1086,1088,1094,1096,1101,1102,1108,1109,1114],{"type":51,"tag":66,"props":1044,"children":1045},{},[1046],{"type":57,"value":1047},"Pages",{"type":57,"value":1049},": ",{"type":51,"tag":74,"props":1051,"children":1053},{"className":1052},[],[1054],{"type":57,"value":1055},"slug",{"type":57,"value":1057}," = WP ",{"type":51,"tag":74,"props":1059,"children":1061},{"className":1060},[],[1062],{"type":57,"value":1026},{"type":57,"value":1064},", ",{"type":51,"tag":74,"props":1066,"children":1068},{"className":1067},[],[1069],{"type":57,"value":1070},"postType: 'page'",{"type":57,"value":1064},{"type":51,"tag":74,"props":1073,"children":1075},{"className":1074},[],[1076],{"type":57,"value":1077},"htmlSlug",{"type":57,"value":1079}," = slug. The front page is captured as ",{"type":51,"tag":74,"props":1081,"children":1083},{"className":1082},[],[1084],{"type":57,"value":1085},"homepage",{"type":57,"value":1087}," (matched by root-URL ",{"type":51,"tag":74,"props":1089,"children":1091},{"className":1090},[],[1092],{"type":57,"value":1093},"\u003Clink>",{"type":57,"value":1095}," OR ",{"type":51,"tag":74,"props":1097,"children":1099},{"className":1098},[],[1100],{"type":57,"value":1026},{"type":57,"value":744},{"type":51,"tag":74,"props":1103,"children":1105},{"className":1104},[],[1106],{"type":57,"value":1107},"home",{"type":57,"value":331},{"type":51,"tag":74,"props":1110,"children":1112},{"className":1111},[],[1113],{"type":57,"value":1085},{"type":57,"value":1115},").",{"type":51,"tag":214,"props":1117,"children":1118},{},[1119,1124,1125,1130,1132,1137,1138,1144,1145,1150,1152,1158,1160,1165,1167,1173,1175,1181,1183,1189],{"type":51,"tag":66,"props":1120,"children":1121},{},[1122],{"type":57,"value":1123},"Posts",{"type":57,"value":1049},{"type":51,"tag":74,"props":1126,"children":1128},{"className":1127},[],[1129],{"type":57,"value":1055},{"type":57,"value":1131}," = bare WP ",{"type":51,"tag":74,"props":1133,"children":1135},{"className":1134},[],[1136],{"type":57,"value":1026},{"type":57,"value":1064},{"type":51,"tag":74,"props":1139,"children":1141},{"className":1140},[],[1142],{"type":57,"value":1143},"postType: 'post'",{"type":57,"value":1064},{"type":51,"tag":74,"props":1146,"children":1148},{"className":1147},[],[1149],{"type":57,"value":1077},{"type":57,"value":1151}," = the manifest slug (e.g. ",{"type":51,"tag":74,"props":1153,"children":1155},{"className":1154},[],[1156],{"type":57,"value":1157},"post--world-teacher-day",{"type":57,"value":1159},"). The WXR post ",{"type":51,"tag":74,"props":1161,"children":1163},{"className":1162},[],[1164],{"type":57,"value":1093},{"type":57,"value":1166}," drops ",{"type":51,"tag":74,"props":1168,"children":1170},{"className":1169},[],[1171],{"type":57,"value":1172},"\u002Fpost\u002F",{"type":57,"value":1174}," but the manifest URL keeps it; join by exact ",{"type":51,"tag":74,"props":1176,"children":1178},{"className":1177},[],[1179],{"type":57,"value":1180},"post--\u003Cpost_name>.html",{"type":57,"value":1182}," then prefix-match (",{"type":51,"tag":74,"props":1184,"children":1186},{"className":1185},[],[1187],{"type":57,"value":1188},"%",{"type":57,"value":1190},"-encoded \u002F truncated slugs).",{"type":51,"tag":214,"props":1192,"children":1193},{},[1194,1196,1202],{"type":57,"value":1195},"Pages with no captured ",{"type":51,"tag":74,"props":1197,"children":1199},{"className":1198},[],[1200],{"type":57,"value":1201},"html\u002F\u003ChtmlSlug>.html",{"type":57,"value":1203}," are skipped + logged.",{"type":51,"tag":959,"props":1205,"children":1207},{"id":1206},"_1a-scope-full-carry-vs-hybrid-blog-dominant-sites",[1208],{"type":57,"value":1209},"1a. Scope: full carry vs hybrid (blog-dominant sites)",{"type":51,"tag":60,"props":1211,"children":1212},{},[1213,1218,1220,1225,1227,1232,1234,1239],{"type":51,"tag":74,"props":1214,"children":1216},{"className":1215},[],[1217],{"type":57,"value":939},{"type":57,"value":1219}," covers every captured page AND post — correct for ",{"type":51,"tag":66,"props":1221,"children":1222},{},[1223],{"type":57,"value":1224},"small",{"type":57,"value":1226}," sites. But on a ",{"type":51,"tag":66,"props":1228,"children":1229},{},[1230],{"type":57,"value":1231},"blog\u002Fnews-dominant",{"type":57,"value":1233}," source (hundreds of posts), carrying every post is the wrong trade: the carry path emits one scoped-CSS sheet ",{"type":51,"tag":66,"props":1235,"children":1236},{},[1237],{"type":57,"value":1238},"per",{"type":57,"value":1240}," carried page, so N-hundred posts bloat the theme to tens of MB of near-duplicate blog-template CSS (see \"CSS weight\" below), and a pixel-carried article gains nothing over native rendering. Posts are text + images — they belong in a normal blog template fed by the WXR content already extracted.",{"type":51,"tag":60,"props":1242,"children":1243},{},[1244,1249,1251,1256,1258,1264,1266,1272,1274,1280,1281,1287,1288,1294,1296,1301,1303,1308],{"type":51,"tag":66,"props":1245,"children":1246},{},[1247],{"type":57,"value":1248},"Hybrid (default for content-heavy sites):",{"type":57,"value":1250}," carry only the custom\u002Fmarketing pages (homepage + service\u002Fabout\u002Flanding — the bespoke designs); let posts, the blog index\u002Farchives, events, and tag\u002Fcategory pages stay ",{"type":51,"tag":66,"props":1252,"children":1253},{},[1254],{"type":57,"value":1255},"native",{"type":57,"value":1257}," (imported from the WXR at provision, rendered by the theme's block templates). Scope the carry set with ",{"type":51,"tag":74,"props":1259,"children":1261},{"className":1260},[],[1262],{"type":57,"value":1263},"EXCLUDE=",{"type":57,"value":1265}," on ",{"type":51,"tag":74,"props":1267,"children":1269},{"className":1268},[],[1270],{"type":57,"value":1271},"carry-reconstruct-drive.ts",{"type":57,"value":1273}," (drop ",{"type":51,"tag":74,"props":1275,"children":1277},{"className":1276},[],[1278],{"type":57,"value":1279},"\u002Fnews",{"type":57,"value":1064},{"type":51,"tag":74,"props":1282,"children":1284},{"className":1283},[],[1285],{"type":57,"value":1286},"\u002Fblog",{"type":57,"value":1064},{"type":51,"tag":74,"props":1289,"children":1291},{"className":1290},[],[1292],{"type":57,"value":1293},"\u002Fthe-dose",{"type":57,"value":1295},", post archives, …) — run ",{"type":51,"tag":74,"props":1297,"children":1299},{"className":1298},[],[1300],{"type":57,"value":955},{"type":57,"value":1302}," first to confirm what carries. The capture must cover the carried pages in FULL (a representative-only sample can't carry — ",{"type":51,"tag":74,"props":1304,"children":1306},{"className":1305},[],[1307],{"type":57,"value":79},{"type":57,"value":1309}," Step 5 makes capture scope depend on this choice); surface the gap, don't silently skip.",{"type":51,"tag":60,"props":1311,"children":1312},{},[1313],{"type":51,"tag":66,"props":1314,"children":1315},{},[1316],{"type":57,"value":1317},"Native-side jobs when going hybrid:",{"type":51,"tag":1319,"props":1320,"children":1321},"ol",{},[1322,1423],{"type":51,"tag":214,"props":1323,"children":1324},{},[1325,1330,1332,1338,1340,1345,1347,1353,1355,1361,1363,1369,1371,1377,1379,1385,1387,1392,1394,1399,1401,1407,1408,1414,1416,1421],{"type":51,"tag":66,"props":1326,"children":1327},{},[1328],{"type":57,"value":1329},"Working blog templates — now automatic.",{"type":57,"value":1331}," When no POST is carried, ",{"type":51,"tag":74,"props":1333,"children":1335},{"className":1334},[],[1336],{"type":57,"value":1337},"buildCarryThemeFiles",{"type":57,"value":1339}," auto-emits clean native ",{"type":51,"tag":74,"props":1341,"children":1343},{"className":1342},[],[1344],{"type":57,"value":541},{"type":57,"value":1346}," (post-title + date + featured image + content + prev\u002Fnext), ",{"type":51,"tag":74,"props":1348,"children":1350},{"className":1349},[],[1351],{"type":57,"value":1352},"home.html",{"type":57,"value":1354},", and ",{"type":51,"tag":74,"props":1356,"children":1358},{"className":1357},[],[1359],{"type":57,"value":1360},"archive.html",{"type":57,"value":1362}," (a ",{"type":51,"tag":74,"props":1364,"children":1366},{"className":1365},[],[1367],{"type":57,"value":1368},"core\u002Fquery",{"type":57,"value":1370}," inherit loop) — built from the home page's chrome scaffold with NO dual-viewport wrapper, so they render clean-and-native (NOT pixel-matched to the source feed). ",{"type":51,"tag":74,"props":1372,"children":1374},{"className":1373},[],[1375],{"type":57,"value":1376},"index.html",{"type":57,"value":1378}," stays the homepage fallback; set ",{"type":51,"tag":74,"props":1380,"children":1382},{"className":1381},[],[1383],{"type":57,"value":1384},"page_for_posts",{"type":57,"value":1386}," to the blog page so ",{"type":51,"tag":74,"props":1388,"children":1390},{"className":1389},[],[1391],{"type":57,"value":1286},{"type":57,"value":1393}," resolves to ",{"type":51,"tag":74,"props":1395,"children":1397},{"className":1396},[],[1398],{"type":57,"value":1352},{"type":57,"value":1400},". Override with ",{"type":51,"tag":74,"props":1402,"children":1404},{"className":1403},[],[1405],{"type":57,"value":1406},"nativeBlog",{"type":57,"value":1265},{"type":51,"tag":74,"props":1409,"children":1411},{"className":1410},[],[1412],{"type":57,"value":1413},"CarryThemeInput",{"type":57,"value":1415}," if needed. (Carried-post runs keep the carried-island ",{"type":51,"tag":74,"props":1417,"children":1419},{"className":1418},[],[1420],{"type":57,"value":541},{"type":57,"value":1422}," instead.)",{"type":51,"tag":214,"props":1424,"children":1425},{},[1426,1431,1433,1438,1439,1444,1446,1451,1453,1458,1460,1466,1468,1474,1476,1481,1483,1489],{"type":51,"tag":66,"props":1427,"children":1428},{},[1429],{"type":57,"value":1430},"Native-post media localization.",{"type":57,"value":1432}," The carry tool rewrites carried-island ",{"type":51,"tag":74,"props":1434,"children":1436},{"className":1435},[],[1437],{"type":57,"value":329},{"type":57,"value":331},{"type":51,"tag":74,"props":1440,"children":1442},{"className":1441},[],[1443],{"type":57,"value":337},{"type":57,"value":1445}," to the local library, but ",{"type":51,"tag":66,"props":1447,"children":1448},{},[1449],{"type":57,"value":1450},"native post bodies keep their source-CDN URLs",{"type":57,"value":1452}," — the images ARE downloaded + installed by step 3's media install, only the ",{"type":51,"tag":695,"props":1454,"children":1455},{},[1456],{"type":57,"value":1457},"content references",{"type":57,"value":1459}," aren't rewritten. After step 3, run ",{"type":51,"tag":74,"props":1461,"children":1463},{"className":1462},[],[1464],{"type":57,"value":1465},"npx tsx scripts\u002Flocalize-native-post-media.ts \u003CoutputDir> \u003CstudioSitePath>",{"type":57,"value":1467}," to rewrite native ",{"type":51,"tag":74,"props":1469,"children":1471},{"className":1470},[],[1472],{"type":57,"value":1473},"post_content",{"type":57,"value":1475}," to the local copies (source→local map from ",{"type":51,"tag":74,"props":1477,"children":1479},{"className":1478},[],[1480],{"type":57,"value":321},{"type":57,"value":1482},"'s recorded ",{"type":51,"tag":74,"props":1484,"children":1486},{"className":1485},[],[1487],{"type":57,"value":1488},"localUrl",{"type":57,"value":1490},"s). [[feedback_never_lose_source_content]]",{"type":51,"tag":959,"props":1492,"children":1494},{"id":1493},"_2-provision-the-studio-site",[1495],{"type":57,"value":1496},"2. Provision the Studio site",{"type":51,"tag":210,"props":1498,"children":1499},{},[1500,1598],{"type":51,"tag":214,"props":1501,"children":1502},{},[1503,1508,1509,1515,1517,1523,1525,1531,1533,1539,1541,1546,1548,1554,1555,1561,1563,1568,1570,1588,1590,1596],{"type":51,"tag":66,"props":1504,"children":1505},{},[1506],{"type":57,"value":1507},"Slim first:",{"type":57,"value":744},{"type":51,"tag":74,"props":1510,"children":1512},{"className":1511},[],[1513],{"type":57,"value":1514},"npx tsx scripts\u002Fcarry-reconstruct-drive.ts \u003CoutputDir> --slim",{"type":57,"value":1516},". A media-heavy WXR (hundreds of attachments) trips Studio's ~120s blueprint-import silence timeout (surfaces as ",{"type":51,"tag":74,"props":1518,"children":1520},{"className":1519},[],[1521],{"type":57,"value":1522},"Error establishing a database connection",{"type":57,"value":1524},"; the half-created site is removed) — see [[project_studio_import_heartbeat]]. The ",{"type":51,"tag":74,"props":1526,"children":1528},{"className":1527},[],[1529],{"type":57,"value":1530},"--slim",{"type":57,"value":1532}," mode (lib ",{"type":51,"tag":74,"props":1534,"children":1536},{"className":1535},[],[1537],{"type":57,"value":1538},"slimWxrForProvision",{"type":57,"value":1540},") slims ",{"type":51,"tag":74,"props":1542,"children":1544},{"className":1543},[],[1545],{"type":57,"value":277},{"type":57,"value":1547}," IN PLACE (drops every ",{"type":51,"tag":74,"props":1549,"children":1551},{"className":1550},[],[1552],{"type":57,"value":1553},"attachment",{"type":57,"value":744},{"type":51,"tag":74,"props":1556,"children":1558},{"className":1557},[],[1559],{"type":57,"value":1560},"\u003Citem>",{"type":57,"value":1562},", flips draft→publish) and backs the full WXR up to ",{"type":51,"tag":74,"props":1564,"children":1566},{"className":1565},[],[1567],{"type":57,"value":818},{"type":57,"value":1569},". The reconstruct installs media separately (step 3), so the provisioned site loses nothing — and ",{"type":51,"tag":66,"props":1571,"children":1572},{},[1573,1575,1580,1581,1586],{"type":57,"value":1574},"step 3's driver restores ",{"type":51,"tag":74,"props":1576,"children":1578},{"className":1577},[],[1579],{"type":57,"value":277},{"type":57,"value":866},{"type":51,"tag":74,"props":1582,"children":1584},{"className":1583},[],[1585],{"type":57,"value":872},{"type":57,"value":1587}," at the end",{"type":57,"value":1589},", so the slim is transient and the dir is never left lossy (a later blocks run \u002F ",{"type":51,"tag":74,"props":1591,"children":1593},{"className":1592},[],[1594],{"type":57,"value":1595},"liberate_verify",{"type":57,"value":1597}," still sees the full WXR).",{"type":51,"tag":214,"props":1599,"children":1600},{},[1601,1603,1609,1611,1616,1618,1624,1626,1632,1634,1640,1642,1648,1650,1655,1657,1663,1665,1670,1672,1677],{"type":57,"value":1602},"Provision via ",{"type":51,"tag":74,"props":1604,"children":1606},{"className":1605},[],[1607],{"type":57,"value":1608},"liberate_preview({ outputDir })",{"type":57,"value":1610}," — it reads the now-slimmed ",{"type":51,"tag":74,"props":1612,"children":1614},{"className":1613},[],[1615],{"type":57,"value":277},{"type":57,"value":1617},". The site is named ",{"type":51,"tag":74,"props":1619,"children":1621},{"className":1620},[],[1622],{"type":57,"value":1623},"\u003Csite>",{"type":57,"value":1625}," (e.g. ",{"type":51,"tag":74,"props":1627,"children":1629},{"className":1628},[],[1630],{"type":57,"value":1631},"~\u002FStudio\u002F\u003Csite>",{"type":57,"value":1633},", no path suffix); if a blocks-path site already exists with that name, ",{"type":51,"tag":74,"props":1635,"children":1637},{"className":1636},[],[1638],{"type":57,"value":1639},"studio.ts",{"type":57,"value":1641}," uniques it (",{"type":51,"tag":74,"props":1643,"children":1645},{"className":1644},[],[1646],{"type":57,"value":1647},"\u003Csite>-2",{"type":57,"value":1649},", …), so both paths on one extraction yield distinct sites without clobbering. ",{"type":51,"tag":74,"props":1651,"children":1653},{"className":1652},[],[1654],{"type":57,"value":623},{"type":57,"value":1656}," returns ",{"type":51,"tag":74,"props":1658,"children":1660},{"className":1659},[],[1661],{"type":57,"value":1662},"path",{"type":57,"value":1664}," (the resolved Studio WP root) — pass it straight through as ",{"type":51,"tag":74,"props":1666,"children":1668},{"className":1667},[],[1669],{"type":57,"value":722},{"type":57,"value":1671}," in step 3 (no need to re-derive ",{"type":51,"tag":74,"props":1673,"children":1675},{"className":1674},[],[1676],{"type":57,"value":1631},{"type":57,"value":1115},{"type":51,"tag":959,"props":1679,"children":1681},{"id":1680},"_3-run-the-carry-reconstruct-steps-1-3-4-one-command",[1682],{"type":57,"value":1683},"3. Run the carry reconstruct (steps 1 + 3 + 4, one command)",{"type":51,"tag":210,"props":1685,"children":1686},{},[1687,1835],{"type":51,"tag":214,"props":1688,"children":1689},{},[1690,1696,1698,1703,1705,1710,1712,1717,1719,1724,1726,1731,1733,1738,1740,1745,1747,1752,1753,1758,1760,1765,1766,1771,1773,1777,1779,1785,1787,1793,1794,1800,1801,1807,1809,1815,1816,1822,1824,1833],{"type":51,"tag":74,"props":1691,"children":1693},{"className":1692},[],[1694],{"type":57,"value":1695},"npx tsx scripts\u002Fcarry-reconstruct-drive.ts \u003CoutputDir> \u003CstudioSitePath> \"\u003CSite> (Carry)\"",{"type":57,"value":1697}," — use ",{"type":51,"tag":74,"props":1699,"children":1701},{"className":1700},[],[1702],{"type":57,"value":623},{"type":57,"value":1704},"'s returned ",{"type":51,"tag":74,"props":1706,"children":1708},{"className":1707},[],[1709],{"type":57,"value":1662},{"type":57,"value":1711}," as ",{"type":51,"tag":74,"props":1713,"children":1715},{"className":1714},[],[1716],{"type":57,"value":888},{"type":57,"value":1718},". This runs ",{"type":51,"tag":74,"props":1720,"children":1722},{"className":1721},[],[1723],{"type":57,"value":842},{"type":57,"value":1725}," on the on-disk source (the MCP server can't — it doesn't hot-reload) and, in one pass: builds the page list (step 1), installs the run's media + self-hosts it (",{"type":51,"tag":74,"props":1727,"children":1729},{"className":1728},[],[1730],{"type":57,"value":525},{"type":57,"value":1732}," — one site, one stub store, no cross-site stamping), rewrites links + img\u002Furl to local, writes the theme, writes the islands + ",{"type":51,"tag":74,"props":1734,"children":1736},{"className":1735},[],[1737],{"type":57,"value":850},{"type":57,"value":1739},", writes ",{"type":51,"tag":74,"props":1741,"children":1743},{"className":1742},[],[1744],{"type":57,"value":285},{"type":57,"value":1746}," (step 4), and restores ",{"type":51,"tag":74,"props":1748,"children":1750},{"className":1749},[],[1751],{"type":57,"value":277},{"type":57,"value":866},{"type":51,"tag":74,"props":1754,"children":1756},{"className":1755},[],[1757],{"type":57,"value":872},{"type":57,"value":1759},". The theme slug derives from ",{"type":51,"tag":74,"props":1761,"children":1763},{"className":1762},[],[1764],{"type":57,"value":667},{"type":57,"value":519},{"type":51,"tag":74,"props":1767,"children":1769},{"className":1768},[],[1770],{"type":57,"value":683},{"type":57,"value":1772}," (theme name only — distinct from the un-suffixed ",{"type":51,"tag":695,"props":1774,"children":1775},{},[1776],{"type":57,"value":699},{"type":57,"value":1778}," name). The driver prints ",{"type":51,"tag":74,"props":1780,"children":1782},{"className":1781},[],[1783],{"type":57,"value":1784},"THEMESLUG=…",{"type":57,"value":1786},", the ",{"type":51,"tag":74,"props":1788,"children":1790},{"className":1789},[],[1791],{"type":57,"value":1792},"mediaInstalled",{"type":57,"value":331},{"type":51,"tag":74,"props":1795,"children":1797},{"className":1796},[],[1798],{"type":57,"value":1799},"mediaErrors",{"type":57,"value":331},{"type":51,"tag":74,"props":1802,"children":1804},{"className":1803},[],[1805],{"type":57,"value":1806},"fetchErrors",{"type":57,"value":1808}," counts, the ",{"type":51,"tag":74,"props":1810,"children":1812},{"className":1811},[],[1813],{"type":57,"value":1814},"missingMediaDownloaded",{"type":57,"value":331},{"type":51,"tag":74,"props":1817,"children":1819},{"className":1818},[],[1820],{"type":57,"value":1821},"fontsLocalized",{"type":57,"value":1823}," self-host steps, and the ",{"type":51,"tag":66,"props":1825,"children":1826},{},[1827],{"type":51,"tag":74,"props":1828,"children":1830},{"className":1829},[],[1831],{"type":57,"value":1832},"self-host audit: residualCdnAssets=N",{"type":57,"value":1834}," assertion (0 = no external asset deps survived).",{"type":51,"tag":214,"props":1836,"children":1837},{},[1838,1843,1845,1851,1853,1859,1861,1867,1868,1874,1876,1882],{"type":51,"tag":66,"props":1839,"children":1840},{},[1841],{"type":57,"value":1842},"Verify the fixes landed",{"type":57,"value":1844},", don't assume: confirm ",{"type":51,"tag":74,"props":1846,"children":1848},{"className":1847},[],[1849],{"type":57,"value":1850},"residualCdnAssets=0",{"type":57,"value":1852}," (anything else lists the offending hosts\u002Fsamples); the homepage island should have local ",{"type":51,"tag":74,"props":1854,"children":1856},{"className":1855},[],[1857],{"type":57,"value":1858},"\u002F…\u002F",{"type":57,"value":1860}," nav hrefs (not ",{"type":51,"tag":74,"props":1862,"children":1864},{"className":1863},[],[1865],{"type":57,"value":1866},"https:\u002F\u002F\u003Csource>\u002F…",{"type":57,"value":491},{"type":51,"tag":74,"props":1869,"children":1871},{"className":1870},[],[1872],{"type":57,"value":1873},"…\u002Fwp-content\u002Fuploads\u002F…",{"type":57,"value":1875}," img srcs (not the CDN); a post island should have ",{"type":51,"tag":74,"props":1877,"children":1879},{"className":1878},[],[1880],{"type":57,"value":1881},"is_single('\u003Cslug>')",{"type":57,"value":1883}," in functions.php; spot-check a few rewritten image\u002Ffont URLs return HTTP 200.",{"type":51,"tag":959,"props":1885,"children":1887},{"id":1886},"_4-output-carrywxr-handled-by-the-step-3-driver",[1888,1890,1895],{"type":57,"value":1889},"4. ",{"type":51,"tag":74,"props":1891,"children":1893},{"className":1892},[],[1894],{"type":57,"value":285},{"type":57,"value":1896}," (handled by the step-3 driver)",{"type":51,"tag":60,"props":1898,"children":1899},{},[1900,1902,1907,1909,1914,1916,1922,1924,1929,1931,1936,1938,1944,1946,1952,1954,1960,1962,1967,1969,1975,1976,1982,1984,1990,1991,1997,1998,2004,2006,2012],{"type":57,"value":1901},"The step-3 driver already writes this (",{"type":51,"tag":74,"props":1903,"children":1905},{"className":1904},[],[1906],{"type":57,"value":947},{"type":57,"value":1908},"): it copies the FULL ",{"type":51,"tag":74,"props":1910,"children":1912},{"className":1911},[],[1913],{"type":57,"value":818},{"type":57,"value":1915}," (with attachments — this is the import deliverable, NOT the slimmed provision WXR) and, for each island, REPLACES that item's ",{"type":51,"tag":74,"props":1917,"children":1919},{"className":1918},[],[1920],{"type":57,"value":1921},"\u003Ccontent:encoded>",{"type":57,"value":1923}," body with the island (matching ",{"type":51,"tag":74,"props":1925,"children":1927},{"className":1926},[],[1928],{"type":57,"value":1011},{"type":57,"value":1930}," AND ",{"type":51,"tag":74,"props":1932,"children":1934},{"className":1933},[],[1935],{"type":57,"value":1018},{"type":57,"value":1937}," items by ",{"type":51,"tag":74,"props":1939,"children":1941},{"className":1940},[],[1942],{"type":57,"value":1943},"\u003Cwp:post_name>",{"type":57,"value":1945}," == slug), preserving everything else (titles, dates, IDs, menus, media items) verbatim ([[feedback_never_lose_source_content]]). The island is CDATA-wrapped (any ",{"type":51,"tag":74,"props":1947,"children":1949},{"className":1948},[],[1950],{"type":57,"value":1951},"]]>",{"type":57,"value":1953}," escaped as ",{"type":51,"tag":74,"props":1955,"children":1957},{"className":1956},[],[1958],{"type":57,"value":1959},"]]]]>\u003C![CDATA[>",{"type":57,"value":1961},") via a per-item ",{"type":51,"tag":66,"props":1963,"children":1964},{},[1965],{"type":57,"value":1966},"function",{"type":57,"value":1968}," replacer — not a greedy regex, not a string replacement (avoids the ",{"type":51,"tag":74,"props":1970,"children":1972},{"className":1971},[],[1973],{"type":57,"value":1974},"$&",{"type":57,"value":331},{"type":51,"tag":74,"props":1977,"children":1979},{"className":1978},[],[1980],{"type":57,"value":1981},"$1",{"type":57,"value":1983}," footgun, see [[project_capture_document_nesting_bug]]). The driver prints ",{"type":51,"tag":74,"props":1985,"children":1987},{"className":1986},[],[1988],{"type":57,"value":1989},"items",{"type":57,"value":331},{"type":51,"tag":74,"props":1992,"children":1994},{"className":1993},[],[1995],{"type":57,"value":1996},"patched",{"type":57,"value":331},{"type":51,"tag":74,"props":1999,"children":2001},{"className":2000},[],[2002],{"type":57,"value":2003},"cdataBalanced",{"type":57,"value":2005},"; confirm the item count round-trips and ",{"type":51,"tag":74,"props":2007,"children":2009},{"className":2008},[],[2010],{"type":57,"value":2011},"xmllint --noout \u003CoutputDir>\u002Foutput-carry.wxr",{"type":57,"value":2013}," passes.",{"type":51,"tag":959,"props":2015,"children":2017},{"id":2016},"_5-swap-content-into-the-live-site-activate",[2018],{"type":57,"value":2019},"5. Swap content into the live site + activate",{"type":51,"tag":210,"props":2021,"children":2022},{},[2023,2117],{"type":51,"tag":214,"props":2024,"children":2025},{},[2026,2038,2040,2045,2047,2053,2055,2061,2063,2069,2071,2077,2079,2085,2087,2092,2094,2100,2102,2108,2110,2115],{"type":51,"tag":66,"props":2027,"children":2028},{},[2029,2031,2036],{"type":57,"value":2030},"Do NOT re-import ",{"type":51,"tag":74,"props":2032,"children":2034},{"className":2033},[],[2035],{"type":57,"value":285},{"type":57,"value":2037}," to update content",{"type":57,"value":2039}," — the WXR importer skips items whose GUID already exists, so it won't overwrite content already in the site. Instead swap directly. The step-3 driver already wrote the islands + a ",{"type":51,"tag":74,"props":2041,"children":2043},{"className":2042},[],[2044],{"type":57,"value":850},{"type":57,"value":2046}," into ",{"type":51,"tag":74,"props":2048,"children":2050},{"className":2049},[],[2051],{"type":57,"value":2052},"\u003CstudioSitePath>\u002Fwp-content\u002Fuploads\u002F_carry-islands\u002F",{"type":57,"value":2054},"; run it: ",{"type":51,"tag":74,"props":2056,"children":2058},{"className":2057},[],[2059],{"type":57,"value":2060},"studio wp --path \u003CstudioSitePath> --user=admin eval-file \u002Fwordpress\u002Fwp-content\u002Fuploads\u002F_carry-islands\u002F_swap.php",{"type":57,"value":2062}," (VFS path — Studio mounts the site at ",{"type":51,"tag":74,"props":2064,"children":2066},{"className":2065},[],[2067],{"type":57,"value":2068},"\u002Fwordpress",{"type":57,"value":2070},"; ",{"type":51,"tag":74,"props":2072,"children":2074},{"className":2073},[],[2075],{"type":57,"value":2076},"--user=admin",{"type":57,"value":2078}," gives ",{"type":51,"tag":74,"props":2080,"children":2082},{"className":2081},[],[2083],{"type":57,"value":2084},"unfiltered_html",{"type":57,"value":2086}," so KSES doesn't strip carried markup). It finds each post by ",{"type":51,"tag":74,"props":2088,"children":2090},{"className":2089},[],[2091],{"type":57,"value":1026},{"type":57,"value":2093}," across ",{"type":51,"tag":74,"props":2095,"children":2097},{"className":2096},[],[2098],{"type":57,"value":2099},"['page','post']",{"type":57,"value":2101}," and ",{"type":51,"tag":74,"props":2103,"children":2105},{"className":2104},[],[2106],{"type":57,"value":2107},"wp_update_post",{"type":57,"value":2109},"s its ",{"type":51,"tag":74,"props":2111,"children":2113},{"className":2112},[],[2114],{"type":57,"value":1473},{"type":57,"value":2116},", publishing it.",{"type":51,"tag":214,"props":2118,"children":2119},{},[2120,2122,2128,2130,2136,2137,2143,2144,2150],{"type":57,"value":2121},"Activate the carry theme (",{"type":51,"tag":74,"props":2123,"children":2125},{"className":2124},[],[2126],{"type":57,"value":2127},"studio wp --path \u003CstudioSitePath> theme activate \u003CthemeSlug>",{"type":57,"value":2129},"). Set the static front page (",{"type":51,"tag":74,"props":2131,"children":2133},{"className":2132},[],[2134],{"type":57,"value":2135},"option update show_on_front page",{"type":57,"value":249},{"type":51,"tag":74,"props":2138,"children":2140},{"className":2139},[],[2141],{"type":57,"value":2142},"option update page_on_front \u003Chomepage id>",{"type":57,"value":491},{"type":51,"tag":74,"props":2145,"children":2147},{"className":2146},[],[2148],{"type":57,"value":2149},"rewrite flush",{"type":57,"value":88},{"type":51,"tag":959,"props":2152,"children":2154},{"id":2153},"_5a-enrich-product-marketing-stores-only",[2155],{"type":57,"value":2156},"5a. Enrich product marketing (stores only)",{"type":51,"tag":210,"props":2158,"children":2159},{},[2160,2203],{"type":51,"tag":214,"props":2161,"children":2162},{},[2163,2165,2171,2173,2179,2181,2186,2188,2193,2195,2201],{"type":57,"value":2164},"If the run has products, run ",{"type":51,"tag":74,"props":2166,"children":2168},{"className":2167},[],[2169],{"type":57,"value":2170},"npx tsx scripts\u002Fenrich-product-marketing.ts \u003CoutputDir> \u003CstudioSitePath>",{"type":57,"value":2172}," AFTER products are imported + media is installed. It rebuilds the CDN→local media map from the attachments' ",{"type":51,"tag":74,"props":2174,"children":2176},{"className":2175},[],[2177],{"type":57,"value":2178},"_dla_source_url",{"type":57,"value":2180}," meta (one query — covers already-installed media, which ",{"type":51,"tag":74,"props":2182,"children":2184},{"className":2183},[],[2185],{"type":57,"value":517},{"type":57,"value":2187}," would miss), reconstructs each product's marketing sections into core blocks (joining section-image URLs to the library by basename so the structured renderers emit them instead of falling back to islands), writes them to each product's ",{"type":51,"tag":74,"props":2189,"children":2191},{"className":2190},[],[2192],{"type":57,"value":1473},{"type":57,"value":2194}," (joined by SKU) and the short blurb to the excerpt, in one bulk DB pass. It prints a per-product ",{"type":51,"tag":74,"props":2196,"children":2198},{"className":2197},[],[2199],{"type":57,"value":2200},"N core blocks, M html islands",{"type":57,"value":2202}," line; expect mostly core blocks (islands only for sections too complex to reconstruct without losing content).",{"type":51,"tag":214,"props":2204,"children":2205},{},[2206,2211],{"type":51,"tag":66,"props":2207,"children":2208},{},[2209],{"type":57,"value":2210},"Verify:",{"type":57,"value":2212}," load a product page — the buy box (gallery + title + price + add-to-cart) is functional Woo, and the rich marketing renders full-width below it (not a thin blurb). A product that comes out thin means its section specs weren't captured (re-capture) or its marketing is JS-rendered.",{"type":51,"tag":959,"props":2214,"children":2216},{"id":2215},"_6-render-screenshot-and-compare-the-parity-verdict",[2217],{"type":57,"value":2218},"6. Render, screenshot, and compare — the parity verdict",{"type":51,"tag":210,"props":2220,"children":2221},{},[2222,2264,2306,2385,2395],{"type":51,"tag":214,"props":2223,"children":2224},{},[2225,2227,2233,2235,2240,2242,2248,2249,2255,2257,2262],{"type":57,"value":2226},"Screenshot the built site (desktop + mobile) for every page: ",{"type":51,"tag":74,"props":2228,"children":2230},{"className":2229},[],[2231],{"type":57,"value":2232},"npx tsx scripts\u002Fcarry-replica-shots.ts \u003CoutputDir> \u003CcarryBaseUrl> \u003CoutputDir>\u002Freplica-carry",{"type":57,"value":2234},". It navigates via ",{"type":51,"tag":74,"props":2236,"children":2238},{"className":2237},[],[2239],{"type":57,"value":295},{"type":57,"value":2241}," (posts move ",{"type":51,"tag":74,"props":2243,"children":2245},{"className":2244},[],[2246],{"type":57,"value":2247},"\u002Fpost\u002F\u003Cslug>",{"type":57,"value":519},{"type":51,"tag":74,"props":2250,"children":2252},{"className":2251},[],[2253],{"type":57,"value":2254},"\u002F\u003Cslug>\u002F",{"type":57,"value":2256},", which WP further 301s to its date permalink, so the bare source path would rely on WP's flaky canonical-redirect guessing), and keys the replica manifest by the SOURCE url so ",{"type":51,"tag":74,"props":2258,"children":2260},{"className":2259},[],[2261],{"type":57,"value":639},{"type":57,"value":2263}," joins origin↔replica by pathname.",{"type":51,"tag":214,"props":2265,"children":2266},{},[2267,2269,2275,2277,2283,2285,2291,2293,2304],{"type":57,"value":2268},"Run ",{"type":51,"tag":74,"props":2270,"children":2272},{"className":2271},[],[2273],{"type":57,"value":2274},"liberate_compare({ originDir: \"\u003CoutputDir>\u002Fscreenshots\", replicaDir: \"\u003CoutputDir>\u002Freplica-carry\" })",{"type":57,"value":2276}," against the SOURCE screenshots. Emit ",{"type":51,"tag":74,"props":2278,"children":2280},{"className":2279},[],[2281],{"type":57,"value":2282},"\u003CoutputDir>\u002Frun-report-carry.json",{"type":57,"value":2284}," with a per-page and overall parity score, mirroring the block path's ",{"type":51,"tag":74,"props":2286,"children":2288},{"className":2287},[],[2289],{"type":57,"value":2290},"run-report.json",{"type":57,"value":2292}," shape. ",{"type":51,"tag":66,"props":2294,"children":2295},{},[2296,2298],{"type":57,"value":2297},"Include ",{"type":51,"tag":74,"props":2299,"children":2301},{"className":2300},[],[2302],{"type":57,"value":2303},"residualCdnAssets",{"type":57,"value":2305}," (from the step-3 driver's self-host audit; 0 = fully self-hosted) with any offending hosts\u002Fsamples — this is a correctness deliverable, reported separately from the pixel score.",{"type":51,"tag":214,"props":2307,"children":2308},{},[2309,2314,2316,2322,2324,2330,2332,2338,2340,2346,2348,2354,2356,2362,2364,2369,2371,2376,2378,2383],{"type":51,"tag":66,"props":2310,"children":2311},{},[2312],{"type":57,"value":2313},"Chrome-fidelity audit.",{"type":57,"value":2315}," After the carry build, run ",{"type":51,"tag":74,"props":2317,"children":2319},{"className":2318},[],[2320],{"type":57,"value":2321},"npx tsx scripts\u002Fcarry-chrome-audit-run.ts \u003CoutputDir> \u003CbuiltBaseUrl> \u003CstudioSitePath>",{"type":57,"value":2323}," — it renders the built site's header, footer, and nav, diffs them against the source ",{"type":51,"tag":74,"props":2325,"children":2327},{"className":2326},[],[2328],{"type":57,"value":2329},"chrome-fidelity.json",{"type":57,"value":2331}," captured during screenshots, and appends source-copied corrections (display, opacity, text-decoration, line-height, font-size, etc.) to the theme's ",{"type":51,"tag":74,"props":2333,"children":2335},{"className":2334},[],[2336],{"type":57,"value":2337},"site.css",{"type":57,"value":2339},". It writes ",{"type":51,"tag":74,"props":2341,"children":2343},{"className":2342},[],[2344],{"type":57,"value":2345},"\u003CoutputDir>\u002Fchrome-audit.json",{"type":57,"value":2347}," and populates two run-report tallies: ",{"type":51,"tag":74,"props":2349,"children":2351},{"className":2350},[],[2352],{"type":57,"value":2353},"chromeCorrections",{"type":57,"value":2355}," (CSS properties auto-applied to close the gap — informational, self-healing) and ",{"type":51,"tag":74,"props":2357,"children":2359},{"className":2358},[],[2360],{"type":57,"value":2361},"droppedChrome",{"type":57,"value":2363}," (a source chrome element — nav link, footer item, logo — that didn't survive the carry at all). A non-zero ",{"type":51,"tag":74,"props":2365,"children":2367},{"className":2366},[],[2368],{"type":57,"value":2361},{"type":57,"value":2370}," triggers a ",{"type":51,"tag":66,"props":2372,"children":2373},{},[2374],{"type":57,"value":2375},"warn",{"type":57,"value":2377}," verdict and should be investigated; ",{"type":51,"tag":74,"props":2379,"children":2381},{"className":2380},[],[2382],{"type":57,"value":2353},{"type":57,"value":2384}," is reported but does not affect the verdict.",{"type":51,"tag":214,"props":2386,"children":2387},{},[2388,2393],{"type":51,"tag":66,"props":2389,"children":2390},{},[2391],{"type":57,"value":2392},"Report the carry score directly NEXT TO the block path's score",{"type":57,"value":2394}," for the same pages. This is the deliverable — the evidence for whether carry-and-scope actually wins, and by how much.",{"type":51,"tag":214,"props":2396,"children":2397},{},[2398],{"type":57,"value":2399},"Then do the honest visual pass: for the 2–3 worst pages, crop source and built at the same width side by side, read both, and itemize the real differences. State plainly where the carry theme still falls short.",{"type":51,"tag":133,"props":2401,"children":2403},{"id":2402},"self-hosting-structure-verify-dont-assume",[2404],{"type":57,"value":2405},"Self-hosting & structure — VERIFY, don't assume",{"type":51,"tag":60,"props":2407,"children":2408},{},[2409,2411,2416,2418,2423,2425,2430,2432,2437,2439,2445,2446,2452,2454,2459,2461,2467,2468,2474,2476,2481,2482,2487,2489,2495,2496,2502,2504,2509,2511,2517,2519,2525],{"type":57,"value":2410},"An earlier version of this skill listed \"media is self-hosted\" as a settled fact you needn't re-check. That was both ",{"type":51,"tag":66,"props":2412,"children":2413},{},[2414],{"type":57,"value":2415},"wrong",{"type":57,"value":2417}," (a Wix carry shipped ~half its gallery images, its whole font library, and dead preload ",{"type":51,"tag":74,"props":2419,"children":2421},{"className":2420},[],[2422],{"type":57,"value":1093},{"type":57,"value":2424},"s still on the builder CDN) and a ",{"type":51,"tag":66,"props":2426,"children":2427},{},[2428],{"type":57,"value":2429},"trap",{"type":57,"value":2431}," — telling the agent not to re-describe it as a gap suppressed the verify-before-claiming discipline ([[feedback_never_guess_always_look]]). So: ",{"type":51,"tag":66,"props":2433,"children":2434},{},[2435],{"type":57,"value":2436},"never assert self-hosting from memory. The reconstruct ASSERTS it and you report the number.",{"type":57,"value":2438}," After all localization the handler runs ",{"type":51,"tag":74,"props":2440,"children":2442},{"className":2441},[],[2443],{"type":57,"value":2444},"findExternalAssetRefs",{"type":57,"value":591},{"type":51,"tag":74,"props":2447,"children":2449},{"className":2448},[],[2450],{"type":57,"value":2451},"src\u002Flib\u002Freplicate\u002Fcarry-cdn-audit.ts",{"type":57,"value":2453},") over the assembled islands + theme CSS\u002Fparts and returns ",{"type":51,"tag":74,"props":2455,"children":2457},{"className":2456},[],[2458],{"type":57,"value":2303},{"type":57,"value":2460}," (+ ",{"type":51,"tag":74,"props":2462,"children":2464},{"className":2463},[],[2465],{"type":57,"value":2466},"residualCdnByHost",{"type":57,"value":941},{"type":51,"tag":74,"props":2469,"children":2471},{"className":2470},[],[2472],{"type":57,"value":2473},"residualCdnSamples",{"type":57,"value":2475},"); the driver prints ",{"type":51,"tag":74,"props":2477,"children":2479},{"className":2478},[],[2480],{"type":57,"value":1832},{"type":57,"value":72},{"type":51,"tag":66,"props":2483,"children":2484},{},[2485],{"type":57,"value":2486},"A clean run is 0",{"type":57,"value":2488}," — put it in the run-report. Anything >0 is a leak to chase (it does not flip the verdict, but it is not \"done\"). The audit scans ASSET positions only (",{"type":51,"tag":74,"props":2490,"children":2492},{"className":2491},[],[2493],{"type":57,"value":2494},"\u003Cimg src>",{"type":57,"value":331},{"type":51,"tag":74,"props":2497,"children":2499},{"className":2498},[],[2500],{"type":57,"value":2501},"srcset",{"type":57,"value":2503},", CSS ",{"type":51,"tag":74,"props":2505,"children":2507},{"className":2506},[],[2508],{"type":57,"value":337},{"type":57,"value":2510},"), so it never false-flags ",{"type":51,"tag":74,"props":2512,"children":2514},{"className":2513},[],[2515],{"type":57,"value":2516},"\u003Ciframe>",{"type":57,"value":2518}," embeds or editorial ",{"type":51,"tag":74,"props":2520,"children":2522},{"className":2521},[],[2523],{"type":57,"value":2524},"\u003Ca href>",{"type":57,"value":2526}," links.",{"type":51,"tag":60,"props":2528,"children":2529},{},[2530],{"type":57,"value":2531},"Self-hosting seams — what closes each leak:",{"type":51,"tag":210,"props":2533,"children":2534},{},[2535,2601,2687,2719,2736,2766,2797],{"type":51,"tag":214,"props":2536,"children":2537},{},[2538,2543,2544,2549,2551,2556,2557,2562,2564,2569,2571,2577,2578,2584,2586,2592,2593,2599],{"type":51,"tag":66,"props":2539,"children":2540},{},[2541],{"type":57,"value":2542},"Images.",{"type":57,"value":744},{"type":51,"tag":74,"props":2545,"children":2547},{"className":2546},[],[2548],{"type":57,"value":517},{"type":57,"value":2550}," installs the run's media and rewrites carried ",{"type":51,"tag":74,"props":2552,"children":2554},{"className":2553},[],[2555],{"type":57,"value":2494},{"type":57,"value":331},{"type":51,"tag":74,"props":2558,"children":2560},{"className":2559},[],[2561],{"type":57,"value":2501},{"type":57,"value":2563}," to the local library. Two former leaks, now closed: (a) responsive\u002Fgallery ",{"type":51,"tag":66,"props":2565,"children":2566},{},[2567],{"type":57,"value":2568},"mobile-crop",{"type":57,"value":2570}," URLs are injected AFTER that rewrite — ",{"type":51,"tag":74,"props":2572,"children":2574},{"className":2573},[],[2575],{"type":57,"value":2576},"assembleResponsiveMobile",{"type":57,"value":591},{"type":51,"tag":74,"props":2579,"children":2581},{"className":2580},[],[2582],{"type":57,"value":2583},"carry-responsive-assemble.ts",{"type":57,"value":2585},") repoints them to the local desktop copy via the Wix media-id alias; (b) images the extraction never downloaded (no local copy to point at) are fetched up front by ",{"type":51,"tag":74,"props":2587,"children":2589},{"className":2588},[],[2590],{"type":57,"value":2591},"fetchMissingCarriedMedia",{"type":57,"value":591},{"type":51,"tag":74,"props":2594,"children":2596},{"className":2595},[],[2597],{"type":57,"value":2598},"carry-missing-media.ts",{"type":57,"value":2600},") before install.",{"type":51,"tag":214,"props":2602,"children":2603},{},[2604,2609,2610,2616,2617,2623,2625,2631,2633,2639,2641,2647,2649,2654,2655,2661,2663,2669,2671,2677,2679,2685],{"type":51,"tag":66,"props":2605,"children":2606},{},[2607],{"type":57,"value":2608},"Fonts.",{"type":57,"value":744},{"type":51,"tag":74,"props":2611,"children":2613},{"className":2612},[],[2614],{"type":57,"value":2615},"localizeCarryFonts",{"type":57,"value":591},{"type":51,"tag":74,"props":2618,"children":2620},{"className":2619},[],[2621],{"type":57,"value":2622},"carry-fonts.ts",{"type":57,"value":2624},") strips ",{"type":51,"tag":74,"props":2626,"children":2628},{"className":2627},[],[2629],{"type":57,"value":2630},"@font-face",{"type":57,"value":2632}," whose family is never applied, downloads the used fonts into the theme's ",{"type":51,"tag":74,"props":2634,"children":2636},{"className":2635},[],[2637],{"type":57,"value":2638},"assets\u002Ffonts\u002F",{"type":57,"value":2640}," (handles protocol-relative ",{"type":51,"tag":74,"props":2642,"children":2644},{"className":2643},[],[2645],{"type":57,"value":2646},"\u002F\u002Fstatic.parastorage.com",{"type":57,"value":2648},", Wix's main font CDN), rewrites ",{"type":51,"tag":74,"props":2650,"children":2652},{"className":2651},[],[2653],{"type":57,"value":337},{"type":57,"value":519},{"type":51,"tag":74,"props":2656,"children":2658},{"className":2657},[],[2659],{"type":57,"value":2660},"..\u002Ffonts\u002F",{"type":57,"value":2662},", and strips dev-only ",{"type":51,"tag":74,"props":2664,"children":2666},{"className":2665},[],[2667],{"type":57,"value":2668},"sourceMappingURL",{"type":57,"value":2670}," CDN comments. Fonts are also kept OUT of media collection upstream (",{"type":51,"tag":74,"props":2672,"children":2674},{"className":2673},[],[2675],{"type":57,"value":2676},"isFontUrl",{"type":57,"value":2678}," in ",{"type":51,"tag":74,"props":2680,"children":2682},{"className":2681},[],[2683],{"type":57,"value":2684},"media.ts",{"type":57,"value":2686},") so they never enter the uploads pipeline.",{"type":51,"tag":214,"props":2688,"children":2689},{},[2690,2695,2696,2702,2704,2710,2712,2717],{"type":51,"tag":66,"props":2691,"children":2692},{},[2693],{"type":57,"value":2694},"Resource-hint links.",{"type":57,"value":744},{"type":51,"tag":74,"props":2697,"children":2699},{"className":2698},[],[2700],{"type":57,"value":2701},"carryHtml",{"type":57,"value":2703}," strips ",{"type":51,"tag":74,"props":2705,"children":2707},{"className":2706},[],[2708],{"type":57,"value":2709},"\u003Clink rel=preload\u002Fprefetch\u002Fmodulepreload\u002Fpreconnect\u002Fdns-prefetch>",{"type":57,"value":2711}," and any ",{"type":51,"tag":74,"props":2713,"children":2715},{"className":2714},[],[2716],{"type":57,"value":1093},{"type":57,"value":2718}," whose href is on a builder CDN — inert in a static carry but a browser would still prefetch them.",{"type":51,"tag":214,"props":2720,"children":2721},{},[2722,2727,2729,2734],{"type":51,"tag":66,"props":2723,"children":2724},{},[2725],{"type":57,"value":2726},"Internal links are local.",{"type":57,"value":2728}," Nav + body hrefs → imported permalinks via the shared ",{"type":51,"tag":74,"props":2730,"children":2732},{"className":2731},[],[2733],{"type":57,"value":482},{"type":57,"value":2735},". Editorial\u002Fexternal links (RSS, social, \"powered by\"\u002Fhelp-article links) are correctly LEFT ALONE — they are content, not asset deps ([[feedback_never_lose_source_content]]).",{"type":51,"tag":214,"props":2737,"children":2738},{},[2739,2744,2745,2750,2752,2757,2759,2764],{"type":51,"tag":66,"props":2740,"children":2741},{},[2742],{"type":57,"value":2743},"Posts are carried.",{"type":57,"value":744},{"type":51,"tag":74,"props":2746,"children":2748},{"className":2747},[],[2749],{"type":57,"value":1143},{"type":57,"value":2751}," scopes via ",{"type":51,"tag":74,"props":2753,"children":2755},{"className":2754},[],[2756],{"type":57,"value":563},{"type":57,"value":2758}," and renders through one shared ",{"type":51,"tag":74,"props":2760,"children":2762},{"className":2761},[],[2763],{"type":57,"value":541},{"type":57,"value":2765},"; per-post CSS still scopes individually by body class.",{"type":51,"tag":214,"props":2767,"children":2768},{},[2769,2774,2775,2781,2783,2788,2790,2795],{"type":51,"tag":66,"props":2770,"children":2771},{},[2772],{"type":57,"value":2773},"It is a real FSE block theme.",{"type":57,"value":744},{"type":51,"tag":74,"props":2776,"children":2778},{"className":2777},[],[2779],{"type":57,"value":2780},"wp_is_block_theme()",{"type":57,"value":2782}," → true (theme.json v3 + block templates + parts). Only the page\u002Fpost ",{"type":51,"tag":695,"props":2784,"children":2785},{},[2786],{"type":57,"value":2787},"body",{"type":57,"value":2789}," is a single ",{"type":51,"tag":74,"props":2791,"children":2793},{"className":2792},[],[2794],{"type":57,"value":104},{"type":57,"value":2796}," island (the deliberate non-block-editable trade).",{"type":51,"tag":214,"props":2798,"children":2799},{},[2800,2805,2807,2813,2814,2820,2822,2828,2830,2839,2841,2847,2849,2858,2860,2866,2867,2873,2874,2880,2881,2887,2888,2894,2895,2901,2902,2908,2910,2916,2918,2927,2929,2935,2937,2942,2944,2949,2951,2957,2959,2965,2967,2973,2975,2981,2983,2988],{"type":51,"tag":66,"props":2801,"children":2802},{},[2803],{"type":57,"value":2804},"WooCommerce store pages get chrome + rich product marketing (v4).",{"type":57,"value":2806}," When the run has products, the reconstruct emits ",{"type":51,"tag":74,"props":2808,"children":2810},{"className":2809},[],[2811],{"type":57,"value":2812},"templates\u002Fsingle-product.html",{"type":57,"value":249},{"type":51,"tag":74,"props":2815,"children":2817},{"className":2816},[],[2818],{"type":57,"value":2819},"templates\u002Farchive-product.html",{"type":57,"value":2821}," wrapped in a dedicated ",{"type":51,"tag":74,"props":2823,"children":2825},{"className":2824},[],[2826],{"type":57,"value":2827},"header-store",{"type":57,"value":2829}," part + canonical footer. ",{"type":51,"tag":66,"props":2831,"children":2832},{},[2833],{"type":51,"tag":74,"props":2834,"children":2836},{"className":2835},[],[2837],{"type":57,"value":2838},"archive-product.html",{"type":57,"value":2840}," wraps ",{"type":51,"tag":74,"props":2842,"children":2844},{"className":2843},[],[2845],{"type":57,"value":2846},"wp:woocommerce\u002Flegacy-template",{"type":57,"value":2848}," (classic shop grid + sorting\u002Fpagination). ",{"type":51,"tag":66,"props":2850,"children":2851},{},[2852],{"type":51,"tag":74,"props":2853,"children":2855},{"className":2854},[],[2856],{"type":57,"value":2857},"single-product.html",{"type":57,"value":2859}," uses MODERN WC product blocks for the buy box (",{"type":51,"tag":74,"props":2861,"children":2863},{"className":2862},[],[2864],{"type":57,"value":2865},"product-image-gallery",{"type":57,"value":249},{"type":51,"tag":74,"props":2868,"children":2870},{"className":2869},[],[2871],{"type":57,"value":2872},"core\u002Fpost-title",{"type":57,"value":249},{"type":51,"tag":74,"props":2875,"children":2877},{"className":2876},[],[2878],{"type":57,"value":2879},"product-rating",{"type":57,"value":249},{"type":51,"tag":74,"props":2882,"children":2884},{"className":2883},[],[2885],{"type":57,"value":2886},"product-price",{"type":57,"value":249},{"type":51,"tag":74,"props":2889,"children":2891},{"className":2890},[],[2892],{"type":57,"value":2893},"product-summary",{"type":57,"value":249},{"type":51,"tag":74,"props":2896,"children":2898},{"className":2897},[],[2899],{"type":57,"value":2900},"add-to-cart-form",{"type":57,"value":249},{"type":51,"tag":74,"props":2903,"children":2905},{"className":2904},[],[2906],{"type":57,"value":2907},"product-meta",{"type":57,"value":2909},") so order is controllable, then renders the product's rich source marketing FULL-WIDTH below via ",{"type":51,"tag":74,"props":2911,"children":2913},{"className":2912},[],[2914],{"type":57,"value":2915},"core\u002Fpost-content",{"type":57,"value":2917},". That post_content is produced by ",{"type":51,"tag":66,"props":2919,"children":2920},{},[2921],{"type":51,"tag":74,"props":2922,"children":2924},{"className":2923},[],[2925],{"type":57,"value":2926},"scripts\u002Fenrich-product-marketing.ts",{"type":57,"value":2928}," (flow step 5a): it reconstructs each product page's marketing sections (everything but the gallery\u002Fhero Woo reproduces + footer chrome) into CORE blocks via the block path's ",{"type":51,"tag":74,"props":2930,"children":2932},{"className":2931},[],[2933],{"type":57,"value":2934},"reconstructPagePattern",{"type":57,"value":2936}," (with a per-section ",{"type":51,"tag":74,"props":2938,"children":2940},{"className":2939},[],[2941],{"type":57,"value":104},{"type":57,"value":2943}," fallback where reconstruction would drop content), and sets the short Shopify blurb as the product excerpt (shown by ",{"type":51,"tag":74,"props":2945,"children":2947},{"className":2946},[],[2948],{"type":57,"value":2893},{"type":57,"value":2950},"). theme.json carries the captured palette\u002Ffont tokens (",{"type":51,"tag":74,"props":2952,"children":2954},{"className":2953},[],[2955],{"type":57,"value":2956},"loadCarryDesignTokens",{"type":57,"value":2958},") so the core blocks resolve their color\u002Ffont references. The source's \"you may also like\" lands at the end of the marketing (the standalone ",{"type":51,"tag":74,"props":2960,"children":2962},{"className":2961},[],[2963],{"type":57,"value":2964},"woocommerce\u002Frelated-products",{"type":57,"value":2966}," block does not render on this template). Provision also sets ",{"type":51,"tag":74,"props":2968,"children":2970},{"className":2969},[],[2971],{"type":57,"value":2972},"woocommerce_coming_soon=no",{"type":57,"value":2974}," (WC 8.x+ ships it ON). If NO header can be isolated, the handler emits a ",{"type":51,"tag":74,"props":2976,"children":2978},{"className":2977},[],[2979],{"type":57,"value":2980},"warnings[]",{"type":57,"value":2982}," entry and store pages fall back to WC's bare defaults. Product ",{"type":51,"tag":695,"props":2984,"children":2985},{},[2986],{"type":57,"value":2987},"data",{"type":57,"value":2989}," fidelity still depends on the extraction tier (Tier 1 = no variant images \u002F collections→categories); marketing fidelity depends on the captured section specs (a JS-rendered comparison table whose columns weren't captured renders sparse).",{"type":51,"tag":133,"props":2991,"children":2993},{"id":2992},"known-limitations-state-these-in-the-report-do-not-let-them-masquerade-as-success",[2994],{"type":57,"value":2995},"Known limitations (state these in the report; do not let them masquerade as success)",{"type":51,"tag":210,"props":2997,"children":2998},{},[2999,3083,3099,3146,3156,3166],{"type":51,"tag":214,"props":3000,"children":3001},{},[3002,3020,3022,3027,3028,3033,3035,3040,3042,3047,3049,3055,3057,3062,3063,3068,3070,3075,3076,3081],{"type":51,"tag":66,"props":3003,"children":3004},{},[3005,3007,3012,3013,3018],{"type":57,"value":3006},"CSS-file ",{"type":51,"tag":74,"props":3008,"children":3010},{"className":3009},[],[3011],{"type":57,"value":337},{"type":57,"value":744},{"type":51,"tag":695,"props":3014,"children":3015},{},[3016],{"type":57,"value":3017},"backgrounds",{"type":57,"value":3019}," only rewrite on exact map-key match.",{"type":57,"value":3021}," Carried HTML ",{"type":51,"tag":74,"props":3023,"children":3025},{"className":3024},[],[3026],{"type":57,"value":329},{"type":57,"value":331},{"type":51,"tag":74,"props":3029,"children":3031},{"className":3030},[],[3032],{"type":57,"value":2501},{"type":57,"value":3034},", font ",{"type":51,"tag":74,"props":3036,"children":3038},{"className":3037},[],[3039],{"type":57,"value":337},{"type":57,"value":3041},"s, and inline ",{"type":51,"tag":74,"props":3043,"children":3045},{"className":3044},[],[3046],{"type":57,"value":337},{"type":57,"value":3048}," self-host robustly (see \"Self-hosting seams\" above — incl. Wix transform URLs via ",{"type":51,"tag":74,"props":3050,"children":3052},{"className":3051},[],[3053],{"type":57,"value":3054},"rewriteMediaUrls",{"type":57,"value":3056},"'s longest-source-first ordering). But ",{"type":51,"tag":695,"props":3058,"children":3059},{},[3060],{"type":57,"value":3061},"background-image",{"type":57,"value":744},{"type":51,"tag":74,"props":3064,"children":3066},{"className":3065},[],[3067],{"type":57,"value":337},{"type":57,"value":3069},"s in the scoped CSS sheets are only rewritten when the exact URL is a map key; a relative\u002Fquery-string background can still point at the source. This is no longer a silent gap: the ",{"type":51,"tag":66,"props":3071,"children":3072},{},[3073],{"type":57,"value":3074},"residual-CDN audit flags any that survive",{"type":57,"value":591},{"type":51,"tag":74,"props":3077,"children":3079},{"className":3078},[],[3080],{"type":57,"value":2303},{"type":57,"value":3082},"), so it shows up in the run-report instead of shipping unnoticed.",{"type":51,"tag":214,"props":3084,"children":3085},{},[3086,3097],{"type":51,"tag":66,"props":3087,"children":3088},{},[3089,3095],{"type":51,"tag":74,"props":3090,"children":3092},{"className":3091},[],[3093],{"type":57,"value":3094},"data-pin-media",{"type":57,"value":3096}," (Pinterest) transform URLs still mangle",{"type":57,"value":3098}," — invisible (not rendered), harmless; the candidate collector doesn't scan that attribute.",{"type":51,"tag":214,"props":3100,"children":3101},{},[3102,3107,3109,3115,3116,3122,3124,3129,3131,3137,3139,3144],{"type":51,"tag":66,"props":3103,"children":3104},{},[3105],{"type":57,"value":3106},"Non-semantic chrome (headers ride inline).",{"type":57,"value":3108}," On sites without top-level ",{"type":51,"tag":74,"props":3110,"children":3112},{"className":3111},[],[3113],{"type":57,"value":3114},"\u003Cheader>",{"type":57,"value":331},{"type":51,"tag":74,"props":3117,"children":3119},{"className":3118},[],[3120],{"type":57,"value":3121},"\u003Cfooter>",{"type":57,"value":3123}," tags (many Wix\u002FSquarespace — and Shopify, whose ",{"type":51,"tag":74,"props":3125,"children":3127},{"className":3126},[],[3128],{"type":57,"value":3114},{"type":57,"value":3130}," is wrapped deeply enough that ",{"type":51,"tag":74,"props":3132,"children":3134},{"className":3133},[],[3135],{"type":57,"value":3136},"splitRegions",{"type":57,"value":3138}," doesn't lift it), the separate header\u002Ffooter parts come back empty and the chrome rides INLINE in each page's main island. Content pages render fine (their island carries the header); WooCommerce store pages — which have no island — instead use the extracted ",{"type":51,"tag":74,"props":3140,"children":3142},{"className":3141},[],[3143],{"type":57,"value":2827},{"type":57,"value":3145}," part (see \"store pages get chrome\" above).",{"type":51,"tag":214,"props":3147,"children":3148},{},[3149,3154],{"type":51,"tag":66,"props":3150,"children":3151},{},[3152],{"type":57,"value":3153},"Dynamic behavior dropped.",{"type":57,"value":3155}," Scripts are stripped; carousels, menus, scroll effects won't animate. Static computed layout is carried.",{"type":51,"tag":214,"props":3157,"children":3158},{},[3159,3164],{"type":51,"tag":66,"props":3160,"children":3161},{},[3162],{"type":57,"value":3163},"Wix scale offset (the dominant fidelity gap).",{"type":57,"value":3165}," Carried Wix layout renders larger than the source capture at the same width (Wix's responsive scaling is JS-driven and absent in static carry), pushing content below the fold. Worst on the homepage. This — not media\u002Flinks — is the open lever.",{"type":51,"tag":214,"props":3167,"children":3168},{},[3169,3174],{"type":51,"tag":66,"props":3170,"children":3171},{},[3172],{"type":57,"value":3173},"CSS weight.",{"type":57,"value":3175}," Per-page sheets carry treeshaken source CSS; on chrome-less Wix the full chrome CSS duplicates into every page\u002Fpost sheet (50 sheets × ~150KB). Acceptable for a parity path.",{"type":51,"tag":133,"props":3177,"children":3179},{"id":3178},"when-you-finish",[3180],{"type":57,"value":3181},"When you finish",{"type":51,"tag":60,"props":3183,"children":3184},{},[3185],{"type":57,"value":3186},"Summarize the carry vs block parity scores side by side and the honest itemized gaps on the worst pages.",{"type":51,"tag":60,"props":3188,"children":3189},{},[3190,3195,3197,3202,3204,3209,3211,3216,3218,3223,3225,3230],{"type":51,"tag":66,"props":3191,"children":3192},{},[3193],{"type":57,"value":3194},"Pixel scores on dynamic (Wix\u002FJS) sites carry real capture noise — quantify it before claiming a win.",{"type":57,"value":3196}," Capturing the SAME built site 2–3 times moved the overall score ±0.02, and individual dynamic content pages (blog feeds, galleries) swung 0.10–0.12 from lazy-load\u002Fanimation timing. On corneliusholmes that spread ",{"type":51,"tag":695,"props":3198,"children":3199},{},[3200],{"type":57,"value":3201},"exceeded",{"type":57,"value":3203}," the carry-vs-block gap → the numeric A\u002FB is a ",{"type":51,"tag":66,"props":3205,"children":3206},{},[3207],{"type":57,"value":3208},"tie",{"type":57,"value":3210},", even though the carried pages are content-faithful. So: report the multi-capture spread, and separate ",{"type":51,"tag":66,"props":3212,"children":3213},{},[3214],{"type":57,"value":3215},"correctness wins",{"type":57,"value":3217}," (self-hosted assets via ",{"type":51,"tag":74,"props":3219,"children":3221},{"className":3220},[],[3222],{"type":57,"value":1850},{"type":57,"value":3224},", local links, posts rendering — verify each visually\u002Fby HTTP, never from memory) from ",{"type":51,"tag":66,"props":3226,"children":3227},{},[3228],{"type":57,"value":3229},"pixel-score wins",{"type":57,"value":3231}," (often within noise). Recommend next steps from the evidence — the Wix scale offset is the highest-leverage open item, not media or links.",{"items":3233,"total":3419},[3234,3255,3272,3286,3301,3316,3330,3345,3362,3373,3388,3404],{"slug":3235,"name":3235,"fn":3236,"description":3237,"org":3238,"tags":3239,"stars":3252,"repoUrl":3253,"updatedAt":3254},"annotate","collect visual feedback with browser annotation tools","Open a browser with visual annotation tools. The user clicks elements on their site and leaves feedback — the agent reads annotations and makes changes. Use this when the user wants to point at specific elements to fix, tweak, or redesign.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3240,3243,3246,3249],{"name":3241,"slug":3242,"type":15},"Frontend","frontend",{"name":3244,"slug":3245,"type":15},"Productivity","productivity",{"name":3247,"slug":3248,"type":15},"UX Copy","ux-copy",{"name":3250,"slug":3251,"type":15},"UX Design","ux-design",484,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fstudio","2026-05-06T05:40:01.516544",{"slug":3256,"name":3256,"fn":3257,"description":3258,"org":3259,"tags":3260,"stars":3252,"repoUrl":3253,"updatedAt":3271},"block-content","write editable WordPress block markup","Write editable WordPress block markup for local Studio sites, including core\u002Fhtml limits, block-theme layout rules, full-width sections, validation, and skeleton-first page\u002FCSS recipes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3261,3264,3267,3270],{"name":3262,"slug":3263,"type":15},"Block Editor","block-editor",{"name":3265,"slug":3266,"type":15},"CSS","css",{"name":3268,"slug":3269,"type":15},"HTML","html",{"name":17,"slug":18,"type":15},"2026-05-27T07:01:55.629681",{"slug":3273,"name":3273,"fn":3274,"description":3275,"org":3276,"tags":3277,"stars":3252,"repoUrl":3253,"updatedAt":3285},"hosting-plans-helper","provide WordPress.com hosting plan information","Answer WordPress.com plan, pricing, upgrade, and feature-tier questions (plan names, what each tier unlocks — plugins, themes, custom code, SSH, hosting — and current prices) from authoritative live data. Load before answering ANY plan, pricing, or feature-gating question; never answer these from memory.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3278,3281,3284],{"name":3279,"slug":3280,"type":15},"Pricing","pricing",{"name":3282,"slug":3283,"type":15},"Reference","reference",{"name":17,"slug":18,"type":15},"2026-07-02T07:42:33.654791",{"slug":3287,"name":3287,"fn":3288,"description":3289,"org":3290,"tags":3291,"stars":3252,"repoUrl":3253,"updatedAt":3300},"liberate","migrate websites to WordPress","Import and rebuild a website from a closed platform (Wix, Squarespace, Webflow, Shopify, GoDaddy, Hostinger, HubSpot, Weebly) into a Studio WordPress site. Extracts pages\u002Fposts\u002Fproducts + media, then reconstructs the design as editable blocks + WooCommerce OR as a high-fidelity replica theme. Invoke when the user wants to migrate, import, liberate, or rebuild a site from one of these platforms.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3292,3295,3296,3299],{"name":3293,"slug":3294,"type":15},"CMS","cms",{"name":20,"slug":21,"type":15},{"name":3297,"slug":3298,"type":15},"Web Development","web-development",{"name":17,"slug":18,"type":15},"2026-07-09T06:47:33.454311",{"slug":3302,"name":3302,"fn":3303,"description":3304,"org":3305,"tags":3306,"stars":3252,"repoUrl":3253,"updatedAt":3315},"need-for-speed","run frontend performance audits for WordPress sites","Run a frontend performance audit on a WordPress site and get actionable optimization recommendations.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3307,3310,3311,3314],{"name":3308,"slug":3309,"type":15},"Audit","audit",{"name":3241,"slug":3242,"type":15},{"name":3312,"slug":3313,"type":15},"Performance","performance",{"name":17,"slug":18,"type":15},"2026-05-06T05:40:06.433267",{"slug":3317,"name":3317,"fn":3318,"description":3319,"org":3320,"tags":3321,"stars":3252,"repoUrl":3253,"updatedAt":3329},"plugin-recommendations","recommend WordPress plugins for site features","Choose recommended plugins and plugin-provided blocks for features core WordPress blocks do not cover - ecommerce (WooCommerce), forms and newsletters (Jetpack), online courses and quizzes (Sensei LMS), polls, surveys and ratings (Crowdsignal), spam protection (Akismet) - while keeping generated content editable and avoiding raw HTML fallbacks. Any request to sell products or build a shop, store, or storefront requires WooCommerce with products.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3322,3325,3328],{"name":3323,"slug":3324,"type":15},"Content Creation","content-creation",{"name":3326,"slug":3327,"type":15},"Plugin Development","plugin-development",{"name":17,"slug":18,"type":15},"2026-05-27T07:01:58.249105",{"slug":3331,"name":3331,"fn":3332,"description":3333,"org":3334,"tags":3335,"stars":3252,"repoUrl":3253,"updatedAt":3344},"rank-me-up","run on-page SEO audits for WordPress sites","Run an on-page SEO audit on a WordPress site and get actionable recommendations to improve search visibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3336,3337,3340,3343],{"name":3308,"slug":3309,"type":15},{"name":3338,"slug":3339,"type":15},"Marketing","marketing",{"name":3341,"slug":3342,"type":15},"SEO","seo",{"name":17,"slug":18,"type":15},"2026-05-06T05:40:05.196367",{"slug":3346,"name":3346,"fn":3347,"description":3348,"org":3349,"tags":3350,"stars":3252,"repoUrl":3253,"updatedAt":3361},"site-spec","gather specifications for new WordPress sites","Gather the site name and layout preference before building a WordPress site. Run this before creating any new site.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3351,3354,3357,3360],{"name":3352,"slug":3353,"type":15},"Design","design",{"name":3355,"slug":3356,"type":15},"Product Management","product-management",{"name":3358,"slug":3359,"type":15},"Specs","specs",{"name":17,"slug":18,"type":15},"2026-05-06T05:40:02.739409",{"slug":3363,"name":3363,"fn":3364,"description":3365,"org":3366,"tags":3367,"stars":3252,"repoUrl":3253,"updatedAt":3372},"studio-cli","manage local WordPress sites with Studio CLI","Use the Studio CLI to manage local WordPress sites, authentication, and preview sites. Invoke this skill when you need to run Studio CLI commands, manage sites, or troubleshoot site issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3368,3371],{"name":3369,"slug":3370,"type":15},"CLI","cli",{"name":17,"slug":18,"type":15},"2026-04-06T18:02:57.150231",{"slug":3374,"name":3374,"fn":3375,"description":3376,"org":3377,"tags":3378,"stars":3252,"repoUrl":3253,"updatedAt":3387},"taxonomist","optimize WordPress category taxonomy","Analyze and optimize a WordPress site's category taxonomy. Exports all posts, uses AI to suggest an improved category structure — merging duplicates, retiring dead categories, creating missing ones, writing descriptions, and re-categorizing posts. Run this when the user wants to clean up or improve their categories.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3379,3382,3385,3386],{"name":3380,"slug":3381,"type":15},"Content Strategy","content-strategy",{"name":3383,"slug":3384,"type":15},"Data Cleaning","data-cleaning",{"name":3341,"slug":3342,"type":15},{"name":17,"slug":18,"type":15},"2026-05-06T05:40:03.966799",{"slug":3389,"name":3389,"fn":3390,"description":3391,"org":3392,"tags":3393,"stars":3252,"repoUrl":3253,"updatedAt":3403},"visual-design","plan and execute visual design direction","Plan and execute high-quality visual direction for site creation, redesign, layout, typography, color, motion, and visual polish.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3394,3397,3398,3401],{"name":3395,"slug":3396,"type":15},"Animation","animation",{"name":3352,"slug":3353,"type":15},{"name":3399,"slug":3400,"type":15},"Typography","typography",{"name":3402,"slug":3389,"type":15},"Visual Design","2026-07-24T05:40:57.887452",{"slug":3405,"name":3405,"fn":3406,"description":3407,"org":3408,"tags":3409,"stars":3252,"repoUrl":3253,"updatedAt":3418},"visual-polish","verify and polish website visual design","Verify and polish a built or redesigned site by diagnosing rendered-DOM issues against intent and fixing them in a planned, batched screenshot-and-fix loop.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3410,3413,3414,3417],{"name":3411,"slug":3412,"type":15},"Debugging","debugging",{"name":3241,"slug":3242,"type":15},{"name":3415,"slug":3416,"type":15},"Screenshots","screenshots",{"name":3402,"slug":3389,"type":15},"2026-06-06T07:09:59.809812",81,{"items":3421,"total":3514},[3422,3437,3448,3459,3470,3485,3501],{"slug":3423,"name":3423,"fn":3424,"description":3425,"org":3426,"tags":3427,"stars":25,"repoUrl":26,"updatedAt":3436},"adapt","build platform adapters for content extraction","Build a new platform adapter to extract content from an unsupported platform (Blogger, Ghost, Tumblr, etc.)",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3428,3431,3432,3435],{"name":3429,"slug":3430,"type":15},"Automation","automation",{"name":3383,"slug":3384,"type":15},{"name":3433,"slug":3434,"type":15},"Data Engineering","data-engineering",{"name":17,"slug":18,"type":15},"2026-05-09T05:32:13.987972",{"slug":3438,"name":3438,"fn":3439,"description":3440,"org":3441,"tags":3442,"stars":25,"repoUrl":26,"updatedAt":3447},"compose-page-blocks","compose WordPress block markup from HTML","Compose a single liberated page's WordPress block-editor markup from its rendered HTML and screenshot. Inputs are a sanitized HTML file, a desktop screenshot, the design-foundation tokens, the URL's archetype (page\u002Fpost\u002Fproduct\u002Fetc.), and the source URL. Output is a string of valid block markup that round-trips through parse_blocks, uses theme tokens (no inlined hex colors), and contains only text drawn from the source HTML. Call per-page during the streaming watch loop after extraction has produced HTML+screenshot for that URL. Use when a freshly-imported page needs `post_content` upgraded from raw HTML into block-editor markup so the replica theme's tokens, gradients, and patterns actually render.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3443,3444,3445,3446],{"name":3262,"slug":3263,"type":15},{"name":3323,"slug":3324,"type":15},{"name":3268,"slug":3269,"type":15},{"name":17,"slug":18,"type":15},"2026-06-08T08:17:34.212397",{"slug":3449,"name":3449,"fn":3450,"description":3451,"org":3452,"tags":3453,"stars":25,"repoUrl":26,"updatedAt":3458},"creating-blocks","create new WordPress blocks","Templates and guidelines for creating new WordPress blocks from scratch — load this before generating block files",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3454,3455,3456,3457],{"name":3262,"slug":3263,"type":15},{"name":13,"slug":14,"type":15},{"name":3326,"slug":3327,"type":15},{"name":17,"slug":18,"type":15},"2026-06-08T08:17:49.413995",{"slug":3460,"name":3460,"fn":3461,"description":3462,"org":3463,"tags":3464,"stars":25,"repoUrl":26,"updatedAt":3469},"creating-themes","create WordPress block themes","Guidelines for creating new WordPress block themes from scratch — load this before generating theme files",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3465,3466,3467,3468],{"name":3262,"slug":3263,"type":15},{"name":13,"slug":14,"type":15},{"name":23,"slug":24,"type":15},{"name":17,"slug":18,"type":15},"2026-06-08T08:17:50.666611",{"slug":3471,"name":3471,"fn":3472,"description":3473,"org":3474,"tags":3475,"stars":25,"repoUrl":26,"updatedAt":3484},"design-foundations","build design foundation JSON from sites","Build a coherent design-foundation JSON from a liberated site — semantic color\u002Ftypography\u002Fspacing roles with evidence trails. Consumes the partial scaffold produced by liberate_design_foundation_scaffold plus aggregate HTML\u002FCSS analysis and representative rendered HTML; produces a complete design-foundation matching the schema. Call after liberation, before theme generation.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3476,3479,3480,3483],{"name":3477,"slug":3478,"type":15},"Data Modeling","data-modeling",{"name":3352,"slug":3353,"type":15},{"name":3481,"slug":3482,"type":15},"Design System","design-system",{"name":3241,"slug":3242,"type":15},"2026-06-08T08:17:44.457834",{"slug":3486,"name":3486,"fn":3487,"description":3488,"org":3489,"tags":3490,"stars":25,"repoUrl":26,"updatedAt":3500},"design-qa","run visual QA on WordPress themes","Visual-QA loop run after replica theme install and content import. Captures replica screenshots, applies a hard responsiveness gate at 390px AND a hard per-section visual-parity gate (measured SectionParity records, verdict computed by buildRunReport), runs qualitative vision review of source\u002Freplica pairs, checks accessibility, and drives a per-section escalation ladder of fixes via editing-themes\u002Fediting-blocks\u002Frebuild-section (R1 CSS → R2 spec-rebuild → R3 re-extract → R4a AI canonical-block rebuild → R4b deterministic styled-island floor) — escalating unresolved divergences to the operator rather than shipping them. Orchestration-internal — invoked by the replicate-with-blocks\u002Fliberate orchestrators, not directly by users.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3491,3494,3495,3498,3499],{"name":3492,"slug":3493,"type":15},"QA","qa",{"name":3415,"slug":3416,"type":15},{"name":3496,"slug":3497,"type":15},"Testing","testing",{"name":23,"slug":24,"type":15},{"name":17,"slug":18,"type":15},"2026-06-08T08:17:45.698278",{"slug":3502,"name":3502,"fn":3503,"description":3504,"org":3505,"tags":3506,"stars":25,"repoUrl":26,"updatedAt":3513},"diagnose","debug failed data extraction processes","Debug failed or low-quality extractions by analyzing logs, probing the source site, and identifying root causes",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3507,3508,3509,3512],{"name":3433,"slug":3434,"type":15},{"name":3411,"slug":3412,"type":15},{"name":3510,"slug":3511,"type":15},"Logs","logs",{"name":3492,"slug":3493,"type":15},"2026-05-10T05:48:11.267642",21]