convert-site
L'orchestrateur. Il pose un seul message de questions, puis exécute toutes les autres compétences dans l'ordre sans s'arrêter, et se termine par une pull request que la personne fusionne et un runbook qu'elle lance.
Les règles d'or
- Un seul message d'accueil, puis aucun arrêt. Chaque question a une valeur par défaut. Tout ce qui nécessite plus tard un compte, une connexion ou un jeton que vous n'avez pas va dans la liste « a besoin de vous » (
state.needsYouetdocs/LAUNCH.mdsection A) et l'exécution continue. - Le site live est en lecture seule. Seuls ces éléments le lisent, à un rythme mesuré : les scripts de capture,
shoot.mjsetstyles.mjssur le live,css-coverage.mjs,launch-audit --old-urletpre-launch --predecessor-url. Les analytics sont bloqués lors de leurs chargements de pages live, donc aucune visite n'est comptée. Ne soumettez jamais de formulaire, ne vous connectez pas, et ne récupérez pas de page à la main pour combler un manque. - La construction par défaut est égale au live, défauts compris. Le contenu est déplacé à partir du balisage capturé, jamais ressaisi ou nettoyé. Chaque bizarrerie est une ligne de décision qui dit « reproduire le live par défaut ». Une différence forcée est une exception ; une amélioration est une proposition (
PROPOSALS=onuniquement). - Portes sur chaque commit, jamais assouplies. Ne modifiez jamais
baseline/pour réussir (seuls les drapeauxkeepdansbaseline/scripts.jsonsont autorisés). Un saut n'est pas une réussite ; « Non couvert » n'est jamais une réussite. mainreçoit le commit d'échafaudage et rien d'autre. Sur un dépôt nouveau et vide,init-sitecrée un commit surmain, l'exception à la règle « ne jamais commiter sur main » : la PR a besoin d'une base. Tout le reste est surastro-rebuild, une seule PR. Ne forcez jamais un push, ne fusionnez jamais, ne touchez jamais au DNS, à l'ancien hébergeur ou à un paramètre de tableau de bord.- Aucun secret dans le chat ou dans le dépôt. Ne demandez jamais à la personne de coller un jeton. Les identifiants viennent de l'environnement ou de la propre connexion d'un CLI.
Noms utilisés ci-dessous
KIT est le chemin absolu de ce kit (le dossier contenant skills/ et package.json).
LIVE est l'origine live. SITE est le chemin absolu du nouveau dépôt du site (par défaut <dossier actuel>/<slug>). La capture et l'état d'exécution y sont écrits dès le début, et init-site.mjs échafaude autour d'eux. Exécutez chaque commande depuis SITE. Chaque script affiche --help ; exécutez cela plutôt que de lire le source. Chaque commande Node dans un nouveau shell commence par source ~/.nvm/nvm.sh && nvm use 22.23.4 (ou s'exécute dans un shell qui lit .nvmrc).
Étape 0a : un kit qui peut s'exécuter
Les scripts importent parse5, playwright et le reste depuis les node_modules du kit. Si $KIT/package.json ou $KIT/node_modules est manquant (une installation qui n'a copié que les dossiers de compétences n'a ni l'un ni l'autre), clonez le kit et installez-le, puis utilisez le clone comme KIT :
git clone https://github.com/ethanplusai/astro-conversion-kit <dossier>/astro-conversion-kit
npm install --prefix <dossier>/astro-conversion-kit
Étape 0 : pré-vol et empreinte (avant le message d'accueil)
node $KIT/skills/convert-site/scripts/preflight.mjs --json
node $KIT/skills/capture-site/scripts/fingerprint.mjs $LIVE
Installez ce qui manque et que vous pouvez installer vous-même, sans demander : npx playwright install chromium lorsque playwright.chromium est faux ; vercel et wrangler s'exécutent via npx. Un CLI présent mais non connecté doit être connecté par la personne : nommez la commande (gh auth login, npx vercel login, npx wrangler login) dans le message d'accueil et vérifiez à nouveau lors de l'échafaudage.
experience détermine comment vous parlez, pas ce que vous faites. new : une phrase simple par phase sur ce qu'elle fait et pourquoi, chaque terme expliqué une fois, les installations faites en silence. some : une ligne par phase. experienced : uniquement les commandes et les résultats. Une empreinte Shopify est une boutique : arrêtez-vous et dites-le.
Étape 1 : accueil (le message unique)
Envoyez le modèle de references/intake.md, rempli avec ce que le pré-vol et l'empreinte ont trouvé : chaque question avec sa valeur par défaut, et la liste « ce qui manque et ce qui se passe ». Si la personne ne répond pas, les valeurs par défaut s'appliquent. N'envoyez jamais un second message de question.
Les phases
L'ordre est celui de docs/process.md ; references/phases.md contient chaque commande et chaque preuve. À chaque frontière, exécutez node $KIT/skills/convert-site/scripts/state.mjs --dir $SITE phase <nom> ; ne commencez pas une phase tant que la preuve de la phase précédente n'est pas vérifiée. Exécutez les appels state.mjs un à la fois, jamais chaînés avec && : chacun réécrit state.json, et un chaînage qui échoue en cours de route le laisse désynchronisé.
| # | Phase (<nom>) | Ce qui se passe | Terminé quand |
|---|---|---|---|
| 1 | intake | Pré-vol, empreinte, le message unique | Répondu, ou valeurs par défaut appliquées |
| 2 | capture | capture-site dans $SITE/capture/, couverture CSS | Chaque URL enregistrée ou enregistrée avec son statut ; Notes écrites |
| 3 | plan | Décider de l'hébergement, du format d'URL, du mode média, des modèles ; décisions dans l'état ; brouillons sous .conversion/ | Chaque modèle, compte, bizarrerie et fonctionnalité hors scope a une décision |
| 4 | scaffold | Dépôt, init-site.mjs autour de la capture, puis docs/plan.md et docs/media-plan.json | Il se construit vide ; main contient le seul commit d'échafaudage |
| 5 | baseline | npm run baseline (templates.json existe déjà) | build-baseline.mjs --check se termine avec le code 0 |
| 6 | build | Layouts et parties partagées, une page par modèle, verrouillage du design sur les modèles, puis chaque page | npm run build réussit ; les portes du modèle passent chemin par chemin |
| 7 | gates | Les portes complètes | npm run verify se termine avec le code 0 |
| 8 | visual | Chaque modèle à 390, 768, 1440 ; chaque page à 390 et 1440 | Chaque paire réussit |
| 9 | components | Optionnel, désactivé par défaut (references/components-optional.md) | Les portes et les diffs réussissent toujours, un commit séparé |
| 10 | prelaunch | pre-launch, déploiement de staging, verify-live, launch-audit, une soumission de test | prelaunch-reconcile.mjs se termine avec le code 0 (references/phases.md §10) ; les bloqueurs d'audit corrigés ou listés |
| 11 | suggestions | suggest-improvements avec gates.json et review/ | docs/suggestions.md avec sa section « De la revue » |
| 12 | pr | Runbook, push, PR, rapport final | La PR cite la sortie des portes et chaque section « Non couvert » |
| 13 | launch | Celle de la personne, depuis docs/LAUNCH.md | post-launch vérifie le basculement et surveille 30 jours |
Les compétences utilisées par chaque phase, avec leurs propres règles : capture-site (2), parity-gates (5 à 7), visual-review (6, 8), pre-launch et launch-audit (10), suggest-improvements (11), post-launch (dans le runbook). Lisez le SKILL.md de chaque compétence avant sa phase.
La construction, en un paragraphe
references/build-rules.md est contraignant. Les layouts et l'en-tête, la navigation et le pied de page partagés sont toujours des composants ; les blocs de contenu sont le balisage capturé, déplacé par un script. Médias à leurs chemins d'origine, polices auto-hébergées, CSS par élagage de couverture (css-coverage.mjs puis css-prune.mjs), jamais de réécriture. Formulaires selon references/forms.md, scripts tiers selon references/third-party.md. redirects.csv est la source unique de redirection : une nouvelle redirection est une ligne dont source est decision et dont note nomme l'id de la décision, puis npm run redirects:build ; ne modifiez jamais à la main les règles générées. Un commit par modèle (feat: <modèle> template, une fois que ses portes par chemin réussissent), jamais un pour l'ensemble de la construction. Le design est verrouillé sur les modèles (visual-review) avant le déploiement vers chaque page. Avec des sous-agents, un implémenteur par modèle ou correction de porte, jamais deux sur un même fichier ; chaque brief porte les chemins absolus et build-rules.md, et vous vérifiez leurs commits avant la phase suivante.
Décisions, exceptions, propositions
Cette section fait règle ; les références y renvoient.
- Décision. Tout ce que le site live fait de manière étrange, et chaque valeur par défaut que vous appliquez, reçoit
state.mjs decision '{"topic":…,"choice":…,"default":…,"reason":…,"costIfWrong":…}', qui affiche son id (d1,d2, …). Le registre unique est le tableau des décisions dansdocs/plan.md: id, date, sujet, choix, défaut, raison, coût si erreur. Avant l'échafaudage, les décisions vivent dans.conversion/state.json; le tableau du plan est écrit à partir d'elles juste aprèsinit-site. La valeur par défaut est toujours « reproduire le live ». - Exception (
exceptions.json,{ path, field, from, to, reason, approvedBy, date }) : une différence que la construction statique ne peut pas éviter ; les portes substituenttoàfrompour ce champ sur ce chemin.approvedByest"default, <id_de_décision>"jusqu'à ce qu'une personne le valide dans la PR. Les formulaires et les scripts ne sont pas des champs d'exception (ils ont leurs propres drapeaux).routesest : une route que la capture n'a pas pu lire :fromest son statut sous forme de chaîne,toest"skip"ou le chemin de remplacement construit. - Proposition (
proposals.json, de la même forme plusid, l'id de décision, etapprovedBy: "proposed"; plusieurs enregistrements peuvent partager le même id) : une amélioration. Le code la bascule avecproposalOn(id); elle n'est livrée que dans une constructionPROPOSALS=on, vérifiée parnpm run verify:proposals. Un changement qu'aucune porte ne mesure (hrefs réécrits) estfield: "markup", jamais comparé. Lorsqu'une personne l'approuve, les enregistrements passent dansexceptions.json(approvedBy).
Hébergement
Vercel par défaut, Cloudflare Pages sur demande : references/hosting-vercel.md et references/hosting-cloudflare.md. Chaque page porte noindex sauf si la construction de production définit PUBLIC_INDEXABLE=true. Les médias sont repo, store (media-upload.mjs) ou live-temporary (staging uniquement ; disparu avant le changement DNS), comme décidé par media-plan.mjs (references/phases.md §3).
Le message unique après le plan
Après la phase 3, envoyez un court statut (pas une question) : plateforme, nombre de pages et de modèles, décision média, fonctionnalités hors scope et options, décisions prises par défaut, et la liste des besoins jusqu'à présent. C'est obligatoire aussi dans une exécution non interactive (réponses préétablies, personne ne répond) : les lignes de progression ne le remplacent pas. Ensuite, continuez sans attendre.
La pull request (phase 12)
Poussez astro-rebuild (main a été poussé lors de l'échafaudage), puis gh pr create --base main --head astro-rebuild --title "Reconstruction Astro de <hôte>" --body-file .conversion/pr-body.md. Tant que pre-launch échoue sur placeholders.form-id (pas encore d'id de formulaire), ajoutez --draft, et le rapport final le nomme comme bloqueur. Sans connexion gh, le corps reste dans ce fichier et « pousser et ouvrir la PR » va dans la liste des besoins. Le corps, dans cet ordre :
## Ce qui a changé un paragraphe : plateforme, ce qui a été converti, hôte, mode média
## Comptes pages, modèles, redirections, fichiers médias et taille, formulaires, fournisseurs conservés/supprimés
## Exceptions appliquées chaque entrée de exceptions.json : chemin, champ, raison, id de décision
## Propositions ouvertes chaque id de proposals.json : chemins, quoi, pourquoi (livré uniquement avec PROPOSALS=on)
## Décisions le tableau des décisions de docs/plan.md, et chaque choix non par défaut
## Sortie des portes sortie de `npm run verify`, textuellement, dans un bloc de code, avec chaque ligne sautée ;
puis chaque ligne que prelaunch-reconcile a acceptée, comme « reproduit depuis le live (dN) »
## Revue visuelle sortie de `npm run review:check`, chaque entrée de docs/visual-overrides.json
(route, id, seuil, raison), chaque bannerClosed et heightMismatch ; les feuilles de contact sont
review/index.html et review/all.html (local ; npm run review:sheet)
## Staging l'URL de staging, le résultat de verify-live, les bloqueurs de launch-audit et leur état
## Suggestions comptes par catégorie, les éléments à risque moyen et élevé, les ids applicables
## Non couvert les sections « Non couvert » de pre-launch et launch-audit, textuellement, chacune
sous son propre titre ; puis celles de capture-site, visual-review et suggestions
## En attente de vous chaque élément de state.needsYou, dans l'ordre du runbook
Le rapport final (à la personne)
Commencez par le lien de la PR (et « brouillon : en attente de l'id du formulaire » le cas échéant), puis : ce qui a été converti (comptes), portes et revue visuelle en une ligne chacune, l'URL de staging, la liste des besoins sous En attente de vous lue depuis state.mjs --dir $SITE get needsYou (chaque élément avec la commande ou le clic exact, dans l'ordre du runbook), puis chaque section « Non couvert » textuellement. Dites « PR ouverte, en attente de votre fusion », jamais « terminé » ou « en ligne ». Arrêtez tout serveur de revue que vous avez démarré (npm run review:serve -- --stop, et npx astro preview stop si vous avez utilisé la prévisualisation), puis arrêtez-vous.
Reprise
Dans une nouvelle session, lisez node $KIT/skills/convert-site/scripts/state.mjs --dir $SITE get et continuez à partir de phase : vérifiez d'abord la preuve de cette phase ; si elle tient, commencez la phase suivante. La capture reprend avec --resume. Ne répétez jamais l'accueil. Appliquer une suggestion plus tard se fait avec convert-site --apply <id> (references/apply-suggestion.md), jamais dans le cadre de l'exécution elle-même.
Références
| Fichier | Couvre |
|---|---|
references/intake.md | Le message unique : questions, valeurs par défaut, ce qui manque et ce qui se passe |
references/phases.md | Chaque phase : commandes exactes, preuve de terminaison, quoi enregistrer |
references/build-rules.md | Comment les layouts, le contenu, le CSS, les médias, les polices, les images paresseuses et les redirections sont construits |
references/forms.md | Câblage Formspree, noms de champs, honeypot, page de remerciement, id du formulaire, la soumission de test unique |
references/third-party.md | La liste blanche keep dans baseline/scripts.json et docs/third-party.md |
references/hosting-vercel.md | Projet, staging public non indexé, indexation, médias Blob, protection opt-in |
references/hosting-cloudflare.md | Projet Pages, _redirects, _headers, fonction médias R2, redirections de requête |
references/runbook.md | docs/LAUNCH.md : A besoins, B clôture, C jour de lancement, D surveillance 30 jours |
references/components-optional.md | La passe de composants optionnelle |
references/apply-suggestion.md | --apply <id> : enregistrements de proposition, commit de branche, portes, feuille |