CommunityProgramación y desarrollogithub.com

ethanplusai/astro-conversion-kit

Congela una captura del sitio en una línea base (baseline/) y demuestra que una compilación de Astro coincide con ella: cada ruta, redirección (un solo salto, mediante una simulación del host), campos SEO del head, texto visible, enlaces internos, archivos multimedia, entradas del sitemap, feeds, formularios, scripts de terceros y cabeceras de seguridad, con diferencias aprobadas en exceptions.json y mejoras en proposals.json. Úsalo después de una captura para construir la línea base, al compilar redirects.csv para Vercel o Cloudflare, antes de dar por terminada una conversión de página, cuando una compuerta falla y necesita revisión, o para verificar un despliegue de staging contra la línea base.

¿Qué es astro-conversion-kit?

Este skill, ethanplusai/astro-conversion-kit, proporciona un conjunto de compuertas (gates) de paridad para sitios convertidos a Astro desde otros generadores (como WordPress). Su propósito es garantizar que cada compilación del nuevo sitio Astro sea funcionalmente idéntica al sitio original capturado, cubriendo aspectos como rutas, redirecciones, metadatos SEO, texto visible, enlaces, medios, sitemaps, feeds, formularios, scripts y cabeceras de seguridad. Ofrece un flujo de trabajo claro: primero, construir una línea base (baseline/) a partir de una captura del sitio original; luego, ejecutar diez compuertas (routes, redirects, seo, text, links, media, forms, scripts, sitemaps, headers) que comparan la compilación contra esa línea base. Las diferencias inevitables se registran en exceptions.json y las mejoras en proposals.json. Es compatible con Vercel y Cloudflare, y su diseño modular permite ejecutar compuertas individuales o todas en orden. Es ideal para desarrollar conversiones con confianza, verificar despliegues de staging y garantizar que el sitio Astro se comporte exactamente como el original, incluso después de que el antiguo host haya desaparecido.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ethanplusai/astro-conversion-kit/tree/HEAD/skills/parity-gates

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Compuertas de Paridad (Parity Gates)

Construye la línea base una vez desde capture/, luego verifica cada compilación contra ella hasta que todas las compuertas pasen. Las compuertas solo leen baseline/, nunca el sitio en vivo, por lo que una compilación aún puede verificarse después de que el antiguo host haya desaparecido.

La regla de oro

La compilación por defecto es igual al sitio en vivo, y una compuerta nunca se suaviza. Ninguna bandera convierte un fallo en una advertencia. Cuatro reglas que se derivan de ella:

  1. Nunca edites baseline/ a mano. La única excepción: keep en baseline/scripts.json, que es cómo se elimina un vendor (ponlo en false y registra la decisión).
  2. Una diferencia es una entrada, no una edición. Inevitables: exceptions.json. Una mejora: proposals.json, activa solo con PROPOSALS=on. Ambos están en references/exceptions.md.
  3. Un salto no es un pase. Una compuerta que no pudo verificar algo dice N omitidos (razón) en su línea de resumen. Reporta cada omisión.
  4. Reporta una compuerta incorrecta como un error del kit; nunca cambies la compuerta en el sitio, ni la línea base.

Ejecutando los scripts

Un sitio creado por convert-site tiene los scripts en scripts/; ejecútalos desde la raíz del sitio como los scripts npm a continuación, opciones después de --. Fuera de un sitio andamiado, ejecuta la forma node que se muestra bajo cada paso desde la raíz del sitio, donde <skill-dir> es la ruta absoluta de la carpeta de este skill en una copia del kit donde se haya ejecutado npm install. Cada script imprime --help; ejecútalo en lugar de leer el código fuente. Salida 0 pase, 1 compuerta fallida o desviación, 2 uso o entrada faltante.

1. Línea base (una vez)

npm run baseline
node <skill-dir>/scripts/build-baseline.mjs --capture capture --out baseline    # alternativa

Necesita capture/inventory.json, media.json (el media.mjs de la captura) y templates.json (templates.mjs), y sale con 2 nombrando el paso a ejecutar cuando falta uno. Escribe baseline/{routes,seo,redirects,media,forms,scripts,meta,counts}.json y baseline/text/, y redirects.csv en la raíz del sitio. Un shortlink sin destino se omite y se nombra en stderr. Cada salto intermedio de una cadena capturada obtiene su propia fila directamente al destino final (/old-services → /old-services/ → /services/ también da /old-services/,/services/, nota salto de /old-services), a menos que ese salto sea en sí mismo una ruta construida, por lo que un enlace a cualquier URL de la cadena llega en un salto. Confirma baseline/ y redirects.csv juntos. --check recuenta baseline/ contra counts.json (salida 1 en caso de desviación). La forma de cada archivo está en references/contracts.md.

2. Redirecciones

redirects.csv (desde,hacia,estado,fuente,nota) es la única fuente de las redirecciones del sitio. fuente es crawl, sitemap, shortlink o seed de la captura; una fila que agregues es decision, su nota nombrando el id de la decisión. Nunca edites a mano la salida compilada; compila:

npm run redirects:build
node <skill-dir>/scripts/build-redirects.mjs --csv redirects.csv --host vercel --out vercel.json --trailing-slash always    # alternativa

--host cloudflare --out public/_redirects para Pages (Astro lo copia en dist/). Vercel: la clave redirects es reemplazada, todas las demás claves se mantienen, y trailingSlash se elimina y se escribe como reglas de barra 308 propias del compilador después de las del sitio, por lo que una fuente sin barra sigue siendo un salto. Solo una ruta que termina en una extensión de archivo estática cuenta como archivo para esas reglas, en cualquier caso de letra: los tipos web, de documento, multimedia y archivo que contiene una carpeta de subida (docx, xlsx, csv, mov, wav, heic, gz, ...), y cada extensión encontrada en dist/ (si no, public/), así que vuelve a ejecutarlo después de la compilación; /upgrade-guide/3.5/ es una página y mantiene su barra. Un archivo construido que las reglas redirigirían falla la compuerta de redirecciones como archivo construido redirigido. Cloudflare: una fila de consulta (/?p=7) no puede ser emparejada por _redirects y va a cloudflare-query-redirects.csv, para ser creada como un Single Redirect (un elemento "necesita tu acción"). Una fila de consulta cuyo destino es su propia ruta (/?p=2 a /) es una no operación y se omite en ambos hosts.

Una fila capturada (cualquier fuente excepto decision) es una URL en vivo y no contiene parámetros: para Vercel cada : y * en ella se escapa (/foo:bar/ se escribe /foo\:bar/, y también /trackshttps://www.example.com/x/, un href roto en vivo que la captura siguió); // se mantiene. Solo una fila decision usa parámetros :name y splats *, e incluso allí un : antes de un dígito (un puerto) se escapa. Vercel rechaza un : desnudo, y también lo hace la simulación de las compuertas. Una fuente sin forma válida (sin / inicial, espacio en blanco, un carácter de control; en Cloudflare también un :<name> o * capturado, que _redirects no puede escapar) se descarta, se nombra en stderr y se lista como { source, reason } en redirects-skipped.json. Ese archivo se sitúa junto a redirects.csv (la raíz del sitio), nunca bajo public/, por lo que no se despliega. La compuerta de redirecciones y verify-live cuentan una fila listada como omitida, nunca pasada. Cuando la ruta simplemente no debe tener redirección, registra una excepción de "sin redirección" en su lugar (sección 4): { "kind": "redirect", "path": "<source>", "reason": "...", "action": "none", "approvedBy": "...", "date": "..." }.

3. Verificar

npm run build
npm run verify -- --endpoint https://forms.example.com/f/abc --thank-you /thank-you/
node <skill-dir>/scripts/verify/run-all.mjs --endpoint https://forms.example.com/f/abc --thank-you /thank-you/    # alternativa

run-all ejecuta las diez compuertas en orden alfabético, da a cada una solo las opciones que acepta y se detiene en el primer fallo. Opciones compartidas: --paths (lista separada por comas, * coincide con cualquier cosa), --json, --origin (enlaces, seo, sitemaps: el host para el que es la compilación), --allow-extra (rutas), --endpoint, --honeypot, --thank-you (formularios; --endpoint es obligatorio cuando la línea base tiene un formulario POST), --host, --config (redirecciones, enlaces), --csv (redirecciones), --media-plan (multimedia). Arregla el primer fallo, reconstruye, vuelve a ejecutar. Una compuerta sola: node <skill-dir>/scripts/verify/<compuerta>.mjs.

CompuertaPasa cuandoUna omisión significa
formsCada formulario en vivo está en su página con los mismos nombres de campo en orden y método; la acción de un formulario POST es --endpoint y lleva --honeypot; un formulario GET (un cuadro de búsqueda) mantiene la ruta de acción en vivo y no necesita ninguno ("N formularios GET/búsqueda comparados"); un formulario POST cuya acción en vivo está en otro dominio registrable (un host de lista de correo; www, http, subdominios y manejadores de WordPress como admin-ajax.php o ?wpcf7 cuentan como el sitio) se mantiene tal cual, se compara como un formulario GET por su URL de acción completa, y no necesita --endpoint ("N formularios mantenidos tal cual (publicaciones en )")Sin --thank-you: la página de agradecimiento de los formularios POST no fue verificada
headersLa configuración del host envía nosniff, Referrer-Policy, X-Frame-Options o CSP frame-ancestors en cada ruta, y, cuando no es indexable, X-Robots-Tag: noindex en cada ruta o (Vercel) el meta robots noindex en cada página construida; una regla de host de vista previa (https://*.pages.dev/*) cuenta solo para el host de vista previa; con PUBLIC_INDEXABLE=true noindex en cada ruta está prohibido
linksCada href y src interno resuelve a una página o archivo construido, una fuente de redirección o multimedia de línea base, o aterriza en una página construida en un salto a través de las reglas compiladas (vercel.json o dist/_redirects: las reglas de barra y cada fila de redirects.csv), como lo redirigió en vivo ("N enlaces resueltos a través de redirecciones"); dos saltos o un destino faltante fallan; sin configuración de host, /about donde la compilación sirve /about/ falla
mediaCada archivo multimedia de línea base es servido por la compilación con los mismos bytes (--paths elige un archivo por su ruta o por una página que lo referencia): en dist/ en modo plan repo; bajo el prefix del plan, en el manifiesto de la tienda (store) o todavía en vivo (live-temporary); fuera del prefijo, en dist/ en todos los modos. Con PUBLIC_INDEXABLE=true, live-temporary falla cada archivo bajo el prefijo (una compilación de lanzamiento no puede servir multimedia desde el sitio en vivo; un plan sin prefijo cubre cada archivo) y aún verifica los archivos fuera de él en dist/Modo plan live-temporary en una compilación de staging: los archivos bajo el prefijo se sirven desde el sitio en vivo, no se verifican
redirectsCada redirección de línea base y fila csv responde en un salto con el mismo estado, y el destino responde 200 en dist/ (o es externo, o está bajo un prefijo en baseline/meta.json excluded: entonces solo se verifica el primer salto); ninguna fuente es también un archivo construido; ninguna página o archivo construido es redirigido desde su propia URL (página construida redirigida por la regla <regla>; ninguna excepción la cubre, arregla la regla); una ruta con una excepción de "sin redirección" (kind: "redirect", action: "none") no es redirigida en absolutoUna fila de consulta sin operación, cualquier fila de consulta en Cloudflare, o una fuente sin forma válida que redirects-skipped.json lista con una razón (no compilada)
routesCada página, entrada, archivo y feed a 200 está construido, las rutas noindexable aún dicen noindex, no se construye nada extra (los scripts propios de la captura en baseline/js.json y hojas de estilo en baseline/css.json en sus rutas en vivo, los nombres de sitemap en vivo en baseline/sitemaps.json, y el conjunto de iconos de lanzamiento no son extras); una ruta capturada en cualquier estado que no sea 200, 3xx, 404 o 410 falla como no capturada: <estado> a menos que una excepción routes la omita o nombre su reemplazo construidoUna excepción routes con to: "skip": esa ruta nunca fue capturada
scriptsCada vendor mantenido está exactamente en sus páginas en vivo con los mismos ids; uno eliminado en ninguna; ningún vendor nuevo
seoTítulo, descripción, canónico, robots, lang, h1, h2, og y tipos @type de JSON-LD iguales por página; URLs del sitio en el origen del sitio. A menos que PUBLIC_INDEXABLE=true, robots debe llevar el noindex, nofollow de staging y el resto debe ser igual al de las dos en vivo pasadas; una compilación de lanzamiento compara robots exactamente
sitemapsCada sitemap superior en dist/ (el sitemap-index.xml de Astro, o un nombre en vivo en baseline/sitemaps.json como wp-sitemap.xml o sitemap_index.xml) lista exactamente las páginas 200 indexables en el origen (los escapes de porcentaje comparan sin distinción de mayúsculas: %c3 es %C3); cada línea Sitemap: en robots.txt está en el origen y nombra un archivo en dist/, o es una línea que el robots.txt en vivo (capture/robots.txt) llevaba textualmente; cada feed está construido con tantos elementos
textEl texto visible de cada página es igual a baseline/text/ (diff de palabras, 5 palabras de contexto)

Una captura hecha con --exclude registra sus prefijos de ruta en baseline/meta.json excluded: la compuerta links no verifica un enlace bajo uno (como un enlace a otro host, anotado "N enlaces bajo rutas excluidas ... no verificados"), y la compuerta sitemaps acepta una línea Sitemap: de robots.txt bajo uno cuando el robots.txt en vivo lo llevaba textualmente (el sitemap de un subsitio multisitio en el mismo host).

4. Diferencias y decisiones

Cuando la compilación no puede o no debe coincidir con el sitio en vivo, lee references/exceptions.md. En resumen: una entrada es { path, field, from, to, reason, approvedBy, date }; from: "" registra un valor que la compilación agrega, to: "" uno que elimina; una excepción que ya no coincide, o que nombra una ruta que la compuerta no verifica, falla la compuerta. Cada rareza en el sitio en vivo (un H1 faltante, una etiqueta muerta, un enlace roto) se reproduce por defecto y obtiene una fila de decisión (id, tema, elección, defecto, razón, costo si es incorrecto) que lo dice y cuál sería la solución.

Un registro tiene un kind en lugar de un field: { "kind": "redirect", "path": "<source>", "reason": "...", "action": "none", "approvedBy": "...", "date": "..." } significa "sin redirección para esta ruta, a propósito" (una redirección en vivo registrada para un href roto que nada debería redirigir). Cada clave es obligatoria: elimina un comportamiento en vivo, por lo que está autorizada como cualquier excepción. La compuerta de redirecciones solicita la ruta y pasa solo cuando las reglas no la redirigen; en una ruta que la compuerta no verifica, falla como ruta no verificada; verify-live la omite con la razón. Todas las demás compuertas la ignoran.

5. Compilaciones de staging, propuestas y lanzamiento

PUBLIC_INDEXABLE y PROPOSALS cambian lo que Astro construye, así que ponlas en la compilación, no solo en la ejecución de la compuerta; una ejecución de compuerta en una compilación hecha sin ellas verifica el sitio equivocado. Pasa --origin solo cuando la compilación misma fue hecha para ese host; el site de una compilación andamiada es el origen en vivo, por lo que sus canónicos y sitemap permanecen en él.

npm run build && npm run verify -- --endpoint ... --thank-you ...                                       # staging
PROPOSALS=on npm run build && npm run verify:proposals -- --endpoint ... --thank-you ...                 # propuestas
PUBLIC_INDEXABLE=true npm run build && npm run verify:release -- --endpoint ... --thank-you ...          # lanzamiento

Después de un despliegue de staging, verifícalo sobre HTTP contra la línea base. Un despliegue de lanzamiento se verifica de la misma manera sin --expect-noindex:

npm run verify:live -- --base https://my-site.vercel.app --expect-noindex
node <skill-dir>/scripts/verify-live.mjs --base https://my-site.vercel.app --expect-noindex    # alternativa

--bypass "$VERCEL_AUTOMATION_BYPASS_SECRET" se aplica solo cuando el staging fue deliberadamente protegido (el valor de derivación del entorno, nunca pegado en el chat); un alias de staging público no necesita ninguno.

Verifica cada ruta de línea base a 200 (o una --sample), cada redirección en un salto con el mismo tipo de estado, noindex en páginas si y solo si --expect-noindex, el sitemap, y 20 archivos multimedia por bytes (o --media-manifest, cuyo url puede ser la URL absoluta de la tienda o una ruta del sitio verificada en <base><path>). Una redirección listada en redirects-skipped.json o cubierta por una excepción de "sin redirección" (--skipped, --exceptions; ambos se leen desde la raíz del sitio por defecto) se omite y se nombra con su razón. Cada solicitud expira después de 30 s, un fallo de esa verificación en lugar de un bloqueo. Salida 3 significa que fue bloqueado: espera y vuelve a ejecutar. Salida 3 con deployment protection: significa que Vercel respondió con su redirección de inicio de sesión (302 a vercel.com/sso-api): usa el alias de producción del proyecto (público por defecto) en lugar de la URL de despliegue en bruto; solo cuando el staging fue deliberadamente protegido se necesita el bypass. El comando verify-live no construye nada, solo verifica en vivo.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ethanplusai/astro-conversion-kit

Crawl a live website, read-only and paced, into a capture/ folder that a rebuild is checked against — every page's HTML, text and head tags, redirects with every hop, links, third-party scripts, the media set, stylesheets, fonts, logo and icons, feeds, templates, and live screenshots at three widths. Use before converting or rebuilding a site, when asked to crawl, capture, snapshot or inventory a site, or when a capture stopped on blocks and needs resuming.

ethanplusai/astro-conversion-kit

Convert a live website (WordPress first; Drupal, Webflow, Squarespace, Wix and static sites too) into a static Astro site with the same URLs, content, head tags, media, redirects and look, proven by parity gates and a pixel-level visual review, ending in one pull request, a noindexed staging deploy and a launch runbook. Use when asked to convert, rebuild, migrate or clone a site to Astro, when handed a site URL with this kit's link, to resume a conversion from .conversion/state.json, or with --apply <id> to apply one suggestion as a proposal.

ethanplusai/astro-conversion-kit

Audit a live or staging website and report what would go wrong at launch — crawl and inventory, indexability, redirects for a domain cutover, links, images, forms, accessibility, performance, analytics, content sanity, and full-page screenshots for a visual pass. Use before or right after a site launch, when asked to QA, audit, or review a website, when a site is moving to a new domain, or when somebody asks whether a site is ready to go live. Read-only: it never submits a form, clicks a control, or edits anything.

ethanplusai/astro-conversion-kit

The moment DNS moves and for the thirty days after — verifies the cutover (DNS propagation, certificate, http and www redirects, the noindex, robots and sitemap on the live host, every redirect the audit mapped, forms, analytics, the staging copy, the old host, security headers), diffs production against the pre-launch baseline, and schedules the watch. Use when asked did the launch work, is the site live, what should I check after launch, the domain just switched, or when a site went live in the last month and something looks wrong. It is read-only and exits 0 whatever it finds.

Skills relacionados