ethanplusai/astro-conversion-kit

Congele uma captura do site em baseline/ e prove que uma build Astro corresponde a ela — cada rota, redirecionamento (um hop, através de uma simulação do host), campos SEO, texto visível, link interno, arquivo de mídia, entrada de sitemap, feed, formulário, script de terceiros e cabeçalho de segurança — com diferenças aprovadas em exceptions.json e melhorias em proposals.json.

O que é astro-conversion-kit?

Este kit de habilidade fornece um conjunto de gates de verificação (parity gates) para garantir que uma build do Astro seja idêntica à versão ao vivo de um site capturado. Ele primeiro cria uma baseline a partir de uma captura do site, incluindo rotas, redirecionamentos, SEO, mídia, formulários, scripts e cabeçalhos. Em seguida, cada build subsequente é verificada contra essa baseline usando dez gates especializados (formulários, cabeçalhos, links, mídia, redirecionamentos, rotas, scripts, SEO, sitemaps e texto). A habilidade é útil para migrações de site, onde é crítico provar que a nova versão não quebrou nada. Ela suporta deploys no Vercel e Cloudflare, simula o comportamento de redirecionamento do host, e permite diferenças aprovadas (exceções) e melhorias propostas. O fluxo de trabalho é rígido: a baseline nunca é editada manualmente, e nenhum gate pode ser amenizado — diferenças são registradas como entradas em arquivos JSON, e falhas são sempre relatadas.

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

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Gates de Paridade (parity-gates)

Construa a baseline uma vez a partir de capture/, então aplique os gates em cada build até que todos os gates passem. Os gates leem apenas baseline/, nunca o site ao vivo, então uma build ainda pode ser verificada depois que o host antigo desapareceu.

A regra de ouro

A build padrão equivale ao site ao vivo, e um gate nunca é amenizado. Nenhuma flag transforma uma falha em um aviso. Mais quatro que decorrem disso:

  1. Nunca edite baseline/ manualmente. A única exceção: keep em baseline/scripts.json, que é como um fornecedor é removido (defina como false e registre a decisão).
  2. Uma diferença é uma entrada, não uma edição. Inevitável: exceptions.json. Uma melhoria: proposals.json, ativo apenas com PROPOSALS=on. Ambos estão em references/exceptions.md.
  3. Um pulo não é uma aprovação. Um gate que não pôde verificar algo diz N pulado (motivo) em sua linha de resumo. Reporte cada pulo.
  4. Reporte um gate errado como um bug do kit; nunca altere o gate no site, nem na baseline.

Executando os scripts

Um site criado por convert-site tem os scripts em scripts/; execute-os a partir da raiz do site como os npm scripts abaixo, opções após --. Fora de um site scaffolded, execute a forma node mostrada sob cada etapa a partir da raiz do site, onde <skill-dir> é o caminho absoluto da pasta desta habilidade em uma cópia do kit onde npm install foi executado. Cada script imprime --help; execute-o em vez de ler o código-fonte. Saída 0 para aprovação, 1 para gate falhou ou desvio (drift), 2 para uso ou entrada faltando.

1. Baseline (uma vez)

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

Ela precisa de capture/inventory.json, media.json (capture's media.mjs) e templates.json (templates.mjs), e sai com código 2 nomeando a etapa a ser executada quando uma está faltando. Ela escreve baseline/{routes,seo,redirects,media,forms,scripts,meta,counts}.json e baseline/text/, e redirects.csv na raiz do site. Um shortlink sem destino é omitido e nomeado no stderr. Cada hop intermediário de uma cadeia capturada ganha sua própria linha direta ao destino final (/old-services → /old-services/ → /services/ também dá /old-services/,/services/, note hop of /old-services), a menos que esse hop seja em si uma rota construída, então um link para qualquer URL da cadeia chega em um hop. Commite baseline/ e redirects.csv juntos. --check recontabiliza baseline/ contra counts.json (saída 1 em caso de desvio). A forma de cada arquivo está em references/contracts.md.

2. Redirecionamentos

redirects.csv (from,to,status,source,note) é a única fonte dos redirecionamentos do site. source é crawl, sitemap, shortlink ou seed da captura; uma linha que você adiciona é decision, seu note nomeando o id da decisão. Nunca edite manualmente a saída compilada; compile:

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

--host cloudflare --out public/_redirects para Pages (Astro copia para dist/). Vercel: a chave redirects é substituída, toda outra chave é mantida, e trailingSlash é removido e escrito como as próprias regras de slash 308 do compilador após as do site, então uma fonte sem barra ainda é um hop. Apenas um caminho terminando em uma extensão de arquivo estático conta como um arquivo para essas regras, em qualquer letra maiúscula/minúscula: os tipos web, os tipos de documento, mídia e arquivo que uma pasta de upload armazena (docx, xlsx, csv, mov, wav, heic, gz, ...), e toda extensão encontrada em dist/ (senão public/), então reexecute-o após a build; /upgrade-guide/3.5/ é uma página e mantém sua barra. Um arquivo construído que as regras ainda redirecionariam falha no gate de redirecionamentos como arquivo construído redirecionado. Cloudflare: uma linha de query (/?p=7) não pode ser correspondida por _redirects e vai para cloudflare-query-redirects.csv, para ser criado como um Single Redirect (um item "precisa de você"). Uma linha de query cujo destino é seu próprio caminho (/?p=2 para /) é uma não-operação e é omitida em ambos os hosts.

Uma linha capturada (qualquer source exceto decision) é uma URL ao vivo e não contém parâmetros: para Vercel, cada : e * nela é escapado (/foo:bar/ é escrito /foo\:bar/, e o mesmo para /trackshttps://www.example.com/x/, um href ao vivo quebrado que a captura seguiu); // é mantido. Apenas uma linha decision usa parâmetros :name e splats *, e mesmo assim um : antes de um dígito (uma porta) é escapado. Vercel rejeita um : simples, e o mesmo faz a simulação dos gates. Uma fonte sem forma válida (sem / inicial, espaço em branco, caractere de controle; no Cloudflare também um :<name> ou * capturado, que _redirects não pode escapar) é descartada, nomeada no stderr e listada como { source, reason } em redirects-skipped.json. Esse arquivo fica ao lado de redirects.csv (raiz do site), nunca sob public/, então não é implantado. O gate de redirecionamentos e verify-live contam uma linha listada como pulada, nunca aprovada. Quando o caminho simplesmente não deve ter redirecionamento, registre uma exceção "sem redirecionamento" (seção 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/    # fallback

run-all executa os dez gates em ordem alfabética, dá a cada um apenas as opções que aceita, e para na primeira falha. Opções compartilhadas: --paths (lista separada por vírgulas, * corresponde a qualquer coisa), --json, --origin (links, seo, sitemaps: o host para o qual a build é), --allow-extra (rotas), --endpoint, --honeypot, --thank-you (formulários; --endpoint é obrigatório quando a baseline tem um formulário POST), --host, --config (redirecionamentos, links), --csv (redirecionamentos), --media-plan (mídia). Corrija a primeira falha, reconstrua, reexecute. Um gate sozinho: node <skill-dir>/scripts/verify/<gate>.mjs.

GatePassa quandoUm pulo significa
formsCada formulário ao vivo está em sua página com os mesmos nomes de campos em ordem e método; a ação de um formulário POST é --endpoint e ele carrega --honeypot; um formulário GET (uma caixa de busca) mantém o caminho da ação ao vivo e não precisa de nenhum ("N formulários GET/search comparados"); um formulário POST cuja ação ao vivo está em outro domínio registrável (um host de lista de newsletter; www, http, subdomínios e manipuladores WordPress como admin-ajax.php ou ?wpcf7 contam como o site) é mantido como está, comparado como um formulário GET pela URL completa da ação, e não precisa de --endpoint ("N formulários mantidos como estão (postam para )")Sem --thank-you: a página de agradecimento dos formulários POST não foi verificada
headersA configuração do host envia nosniff, Referrer-Policy, X-Frame-Options ou CSP frame-ancestors em cada caminho, e, quando não indexável, X-Robots-Tag: noindex em cada caminho ou (Vercel) o meta robots noindex em cada página construída; uma regra de host de preview (https://*.pages.dev/*) conta apenas para o host de preview; com PUBLIC_INDEXABLE=true noindex em cada caminho é proibido
linksCada href e src interno resolve para uma página ou arquivo construído, uma fonte de redirecionamento ou mídia da baseline, ou chega a uma página construída em um hop através das regras compiladas (vercel.json ou dist/_redirects: as regras de slash e cada linha de redirects.csv), como foi redirecionado ao vivo ("N links resolvidos através de redirecionamentos"); dois hops ou um destino ausente falham; sem configuração de host, /about onde a build serve /about/ falha
mediaCada arquivo de mídia da baseline é servido pela build com os mesmos bytes (--paths seleciona um arquivo por seu caminho ou por uma página que o referencia): em dist/ no modo de plano repo; sob o prefix do plano, no manifesto da loja (store) ou ainda ao vivo (live-temporary); fora do prefixo, em dist/ em todos os modos. Com PUBLIC_INDEXABLE=true, live-temporary falha para cada arquivo sob o prefixo (uma build de release não pode servir mídia do site ao vivo; um plano sem prefixo cobre cada arquivo) e ainda verifica os arquivos fora dele em dist/Modo de plano live-temporary em uma build de staging: arquivos sob o prefixo são servidos ao vivo, não verificados
redirectsCada redirecionamento da baseline e linha do csv responde em um hop com o mesmo status, e o destino responde 200 em dist/ (ou é externo, ou está sob um prefixo em baseline/meta.json excluded: então apenas o primeiro hop é verificado); nenhuma fonte é também um arquivo construído; nenhuma página ou arquivo construído é redirecionado de sua própria URL (página construída redirecionada pela regra <rule>; nenhuma exceção a cobre, corrija a regra); um caminho com uma exceção "sem redirecionamento" (kind: "redirect", action: "none") não é redirecionado de forma algumaUma linha de query sem operação, qualquer linha de query no Cloudflare, ou uma fonte sem forma válida que redirects-skipped.json lista com um motivo (não compilado)
routesCada página, post, archive e feed em 200 é construído, rotas noindex ainda dizem noindex, nada extra é construído (os próprios scripts da captura em baseline/js.json e folhas de estilo em baseline/css.json em seus caminhos ao vivo, os nomes de sitemap ao vivo em baseline/sitemaps.json, e o conjunto de ícones de lançamento não são extras); uma rota capturada em qualquer status diferente de 200, 3xx, 404 ou 410 falha como não capturada: <status> a menos que uma exceção routes a pule ou nomeie seu substituto construídoUma exceção routes com to: "skip": essa rota nunca foi capturada
scriptsCada fornecedor mantido está exatamente em suas páginas ao vivo com os mesmos ids; um removido em nenhuma; nenhum novo fornecedor
seoTitle, description, canonical, robots, lang, h1, h2, og e JSON-LD @types iguais por página; URLs do site na origem do site. A menos que PUBLIC_INDEXABLE=true, robots deve carregar o staging noindex, nofollow e o resto dele igual ao ao vivo além desses dois; uma build de release compara robots exatamente
sitemapsCada sitemap top-level em dist/ (o sitemap-index.xml do Astro, ou um nome ao vivo em baseline/sitemaps.json como wp-sitemap.xml ou sitemap_index.xml) lista exatamente as páginas 200 indexáveis na origem (escapes de porcentagem comparam sem distinção de maiúsculas/minúsculas: %c3 é %C3); cada linha Sitemap: do robots.txt está na origem e nomeia um arquivo em dist/, ou é uma linha que o robots.txt ao vivo (capture/robots.txt) carregava literalmente; cada feed é construído com tantos itens
textO texto visível de cada página é igual a baseline/text/ (diff de palavras, 5 palavras de contexto)

Uma captura feita com --exclude registra seus prefixos de caminho em baseline/meta.json excluded: o gate links não verifica um link sob um deles (como um link para outro host, observado "N links sob caminhos excluídos... não verificados"), e o gate sitemaps aceita uma linha Sitemap: do robots.txt sob um deles quando o robots.txt ao vivo a carregava literalmente (um sitemap de sub-site de multisite no mesmo host).

4. Diferenças e decisões

Quando a build não pode ou não deve corresponder ao site ao vivo, leia references/exceptions.md. Resumindo: uma entrada é { path, field, from, to, reason, approvedBy, date }; from: "" registra um valor que a build adiciona, to: "" um que ela remove; uma exceção que não corresponde mais, ou nomeia um caminho que o gate não verifica, falha o gate. Cada peculiaridade no site ao vivo (um H1 ausente, uma tag morta, um link quebrado) é reproduzida por padrão e ganha uma linha de decisão (id, tópico, escolha, padrão, motivo, custo se errado) dizendo isso e qual seria a correção.

Um registro tem um kind em vez de um field: { "kind": "redirect", "path": "<source>", "reason": "...", "action": "none", "approvedBy": "...", "date": "..." } significa "sem redirecionamento para este caminho, de propósito" (um redirecionamento ao vivo registrado para um href quebrado que nada deve redirecionar). Cada chave é obrigatória: ele remove um comportamento ao vivo, então é aprovado como qualquer exceção. O gate de redirecionamentos solicita o caminho e passa apenas quando as regras não o redirecionam; em um caminho que o gate não verifica, falha como caminho não verificado; verify-live o pula com o motivo. Todo outro gate o ignora.

5. Builds de staging, propostas e release

PUBLIC_INDEXABLE e PROPOSALS mudam o que o Astro constrói, então defina-os na build, não apenas na execução do gate; uma execução de gate em uma build feita sem eles verifica o site errado. Passe --origin apenas quando a própria build foi feita para aquele host; o site de uma build scaffolded é a origem ao vivo, então seus canônicos e sitemap permanecem nela.

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

Após um deploy de staging, verifique-o via HTTP contra a baseline. Um deploy de release é verificado da mesma forma sem --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    # fallback

--bypass "$VERCEL_AUTOMATION_BYPASS_SECRET" aplica-se apenas quando o staging foi deliberadamente protegido (o valor de bypass do ambiente, nunca colado no chat); um alias de staging público não precisa de nenhum.

Ele verifica cada rota da baseline em 200 (ou uma --sample), cada redirecionamento em um hop com o mesmo tipo de status, noindex em páginas se e somente se --expect-noindex, o sitemap, e 20 arquivos de mídia por bytes (ou --media-manifest, cujo url pode ser a URL absoluta da loja ou um caminho do site verificado em <base><path>). Um redirecionamento listado em redirects-skipped.json ou coberto por uma exceção "sem redirecionamento" (--skipped, --exceptions; ambos lidos da raiz do site por padrão) é pulado e nomeado com seu motivo. Cada requisição expira após 30 s, uma falha dessa verificação em vez de um bloqueio. Saída 3 significa que foi bloqueado: espere e reexecute. Saída 3 com deployment protection: significa que o Vercel respondeu com seu redirecionamento de login (302 para vercel.com/sso-api): use o alias de produção do projeto (público por padrão) em vez da URL de deploy bruta; apenas quando o staging foi deliberadamente protegido e você tem o segredo de bypass você pode contorná-lo com --bypass.

6. Aplicações de habilidades adjacentes

convert-site mira em quem está migrando (WordPress → Astro, ou de um SSG para Astro); astro-conversion-kit mira em quem já migrou e precisa provar que a nova build é correta. O kit é executado durante o desenvolvimento e em CI, garantindo que cada alteração no código não quebre nenhuma das características do site ao vivo original. Ele é ideal para migrações onde a precisão total é necessária, como sites governamentais, de comércio eletrônico ou com muitos redirecionamentos complexos.

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.

Habilidades Relacionadas