convert-site
Orchestrator(编排器)。它一次性提出一组问题,然后按顺序执行所有其他技能,不再中断,最后生成一个由用户合并的拉取请求和一份供用户启动上线流程的运行手册。
黄金法则
- 一次问答,之后不再停止。 每个问题都带有默认值。后续任何需要你尚未拥有的账户、登录密码或令牌的操作,都会被添加到“需要你处理”列表(
state.needsYou和docs/LAUNCH.md的 A 部分),而转换流程继续执行。 - 在线网站是只读的。 只有以下脚本以限速方式读取它:抓取脚本、
shoot.mjs、styles.mjs(在线上运行)、css-coverage.mjs、launch-audit --old-url和pre-launch --predecessor-url。它们加载在线页面时会屏蔽分析代码,因此不会产生访问统计。切勿在在线网站上提交表单、登录或手动获取页面以填补空白。 - 默认构建应与在线网站一致,包括缺陷。 内容从抓取到的标记中搬移,从不重新输入或整理。任何异常都应记录为一条决策记录,说明“默认情况是复现在线表现”。强制性的差异是例外;改进则是提案(仅在
PROPOSALS=on时启用)。 - 每次提交都有门控,绝不放宽。 切勿编辑
baseline/目录使门控通过(仅使用baseline/scripts.json中的keep标志)。跳过不等于通过;“未覆盖”绝不等于通过。 main分支只包含脚手架提交。 在新的空仓库上,init-site在main分支上生成一次提交,这是唯一一次向main提交的例外情况:拉取请求需要一个基础分支。之后的所有工作都在astro-rebuild分支上,通过一个拉取请求完成。绝不强制推送、绝不合并、绝不触碰 DNS、旧主机或仪表盘设置。- 聊天室和仓库中不含机密。 绝不要要求用户粘贴令牌。凭据来自环境变量或 CLI 自身的登录流程。
下文使用的名称
KIT 是本工具包的绝对路径(包含 skills/ 和 package.json 的文件夹)。
LIVE 是在线网站的源地址。
SITE 是新站点仓库的绝对路径(默认值为 <当前文件夹>/<slug>);抓取内容和运行状态从一开始就写入该目录,init-site.mjs 在其基础上搭建脚手架。所有命令都从 SITE 目录运行。每个脚本都支持 --help;优先运行该选项而不是阅读源码。每个 Node 命令在一个全新的 shell 中以 source ~/.nvm/nvm.sh && nvm use 22.23.4 开头(或运行在读取 .nvmrc 的 shell 中)。
步骤 0a:确保工具包可运行
这些脚本从工具包的 node_modules 中导入 parse5、playwright 等。如果 $KIT/package.json 或 $KIT/node_modules 缺失(例如安装时只复制了技能目录),请克隆工具包并安装依赖,然后将克隆的目录作为 KIT:
git clone https://github.com/ethanplusai/astro-conversion-kit <folder>/astro-conversion-kit
npm install --prefix <folder>/astro-conversion-kit
步骤 0:预检和指纹采集(在问答消息之前)
node $KIT/skills/convert-site/scripts/preflight.mjs --json
node $KIT/skills/capture-site/scripts/fingerprint.mjs $LIVE
安装缺失但你可以自行安装的内容,无需询问:当 playwright.chromium 为 false 时运行 npx playwright install chromium;vercel 和 wrangler 通过 npx 运行。已安装但未登录的 CLI 需要用户自行登录:在问答消息中指明命令(gh auth login、npx vercel login、npx wrangler login),并在脚手架阶段再次检查。
experience 设置影响你的沟通风格,而非实际操作。new:每个阶段用一句简单的话说明做什么和为什么,每个术语解释一次,安装静默完成。some:每个阶段一行说明。experienced:只输出命令和结果。Shopify 指纹会识别为一个商店:停止转换并告知用户。
步骤 1:问答(一次性消息)
发送 references/intake.md 中的模板,填充预检和指纹采集的结果:每个问题及其默认值,以及“缺少什么以及会发生什么”列表。如果用户不回答,则使用默认值。绝不发送第二条问答消息。
各阶段
顺序遵循 docs/process.md;references/phases.md 包含每个命令及其验证条件。在每个阶段边界运行 node $KIT/skills/convert-site/scripts/state.mjs --dir $SITE phase <名称>;在上一阶段的验证条件通过之前,不要开始新阶段。每次只运行一个 state.mjs 调用,不要用 && 链式调用:每次调用都会重写 state.json,链式调用中途失败会导致状态不一致。
| # | 阶段(<名称>) | 发生什么 | 完成条件 |
|---|---|---|---|
| 1 | intake | 预检、指纹采集、一次性问答消息 | 用户回答,或使用默认值 |
| 2 | capture | capture-site 抓取到 $SITE/capture/,CSS 覆盖率 | 每个 URL 都已保存或记录其状态;Notes 已写入 |
| 3 | plan | 决定托管平台、URL 形式、媒体模式、模板;决策写入 state;草稿放在 .conversion/ 下 | 每个模板、计数、异常和超出范围的功能都有决策 |
| 4 | scaffold | 仓库、init-site.mjs 围绕抓取内容搭建脚手架,然后生成 docs/plan.md 和 docs/media-plan.json | 构建后输出为空;main 分支持有唯一的脚手架提交 |
| 5 | baseline | npm run baseline(templates.json 已存在) | build-baseline.mjs --check 退出码为 0 |
| 6 | build | 布局和共享部分,每个模板一个页面,模板设计锁定,然后生成所有页面 | npm run build 通过;模板门控逐路径通过 |
| 7 | gates | 完整门控 | npm run verify 退出码为 0 |
| 8 | visual | 每个模板在 390、768、1440 宽度下;每个页面在 390 和 1440 宽度下 | 每对都通过 |
| 9 | components | 可选,默认关闭(references/components-optional.md) | 门控和差异仍然通过,作为一次单独的提交 |
| 10 | prelaunch | pre-launch、预发布部署、verify-live、launch-audit、一次测试提交 | prelaunch-reconcile.mjs 退出码为 0(references/phases.md §10);审计阻塞项已修复或已列出 |
| 11 | suggestions | 使用 gates.json 和 review/ 执行 suggest-improvements | 生成 docs/suggestions.md,包含“From the review”章节 |
| 12 | pr | 运行手册、推送、拉取请求、最终报告 | 拉取请求正文包含门控输出和所有“Not covered”章节 |
| 13 | launch | 用户执行,依据 docs/LAUNCH.md | post-launch 检查切换并监控 30 天 |
各阶段使用的技能及其规则:capture-site(阶段 2)、parity-gates(阶段 5 至 7)、visual-review(阶段 6、8)、pre-launch 和 launch-audit(阶段 10)、suggest-improvements(阶段 11)、post-launch(运行手册中)。在执行每个阶段前,请阅读对应技能的 SKILL.md。
构建,一句话总结
references/build-rules.md 是强制性的。布局、共享头部、导航和页脚始终是组件;内容块是从抓取到的标记中搬移的,由脚本处理。媒体保持原始路径,字体自托管,CSS 通过覆盖率裁剪(css-coverage.mjs 然后是 css-prune.mjs),绝不重写。表单遵循 references/forms.md,第三方脚本遵循 references/third-party.md。redirects.csv 是唯一的重定向来源:新增重定向就是添加一行,其 source 为 decision,note 指向决策 ID,然后运行 npm run redirects:build;切勿手动编辑生成的重定向规则。每个模板一个提交(feat: <template> template,在其路径级门控通过后提交),绝不一次提交所有构建。设计在模板上锁定(通过视觉审查)之后再推广到所有页面。如果使用子代理,每个模板或门控修复由一个人实现,绝不让两个人同时修改同一个文件;每个任务简报包含绝对路径和 build-rules.md,你在进入下一阶段前审查他们的提交。
决策、例外、提案
本节是规则;参考文献引用于此。
- 决策。在线网站的任何异常行为,以及你应用的每个默认值,都需要通过
state.mjs decision '{"topic":…,"choice":…,"default":…,"reason":…,"costIfWrong":…}'记录,该命令会输出一个 ID(d1、d2……)。唯一的记录是docs/plan.md中的决策表:ID、日期、主题、选择、默认值、原因、错误代价。在脚手架搭建之前,决策存放在.conversion/state.json中;在init-site之后,计划表会从该文件写入。默认值始终是“复现在线表现”。 - 例外(
exceptions.json,结构:{ path, field, from, to, reason, approvedBy, date }):静态构建无法避免的差异;门控程序会为该路径上的该字段用to替换from。approvedBy在用户通过拉取请求签署之前为"default, <decision id>"。表单和脚本不是例外字段(它们有自己的标志)。routes类型:抓取无法读取的路由:from是其状态的字符串表示,to是"skip"或构建后的替换路径。 - 提案(
proposals.json,结构与例外相同,额外包含id、决策 ID,以及approvedBy: "proposed";多个记录可共享同一个 ID):改进项。代码通过proposalOn(id)启用它;它只在PROPOSALS=on的构建中生效,并由npm run verify:proposals门控。任何门控无法衡量的变更(如重写的 href)使用field: "markup",且不进行比较。当用户批准时,记录移至exceptions.json(approvedBy更新)。
托管
默认为 Vercel,可应要求使用 Cloudflare Pages:参见 references/hosting-vercel.md 和 references/hosting-cloudflare.md。每个页面都带有 noindex,除非生产构建设置了 PUBLIC_INDEXABLE=true。媒体模式为 repo、store(media-upload.mjs)或 live-temporary(仅预发布阶段;DNS 切换前移除),由 media-plan.mjs 决定(references/phases.md §3)。
计划阶段后的一条消息
在阶段 3 之后,发送一条简短的状态消息(非问题):平台、页面和模板数量、媒体决策、超出范围的功能及其选项、已做出的默认决策,以及当前的“需要你处理”列表。在非交互式运行中也需要发送(已有默认答案,无人回复):进度行不能替代它。然后继续执行,无需等待回复。
拉取请求(阶段 12)
推送 astro-rebuild 分支(main 分支在脚手架阶段已推送),然后运行 gh pr create --base main --head astro-rebuild --title "Astro rebuild of <host>" --body-file .conversion/pr-body.md。如果 pre-launch 因 placeholders.form-id 失败(尚未提供表单 ID),则添加 --draft,最终报告将该问题列为阻塞项。如果没有登录 gh,则正文保留在该文件中,并将“推送并创建拉取请求”添加到“需要你处理”列表。拉取请求正文按以下顺序组织:
## What changed 一段话:平台、转换了什么、主机、媒体模式
## Counts 页面、模板、重定向、媒体文件数量和大小、表单、保留/移除的供应商
## Exceptions applied 每个 exceptions.json 条目:路径、字段、原因、决策 ID
## Proposals open 每个 proposals.json 中的 ID:路径、内容、原因(仅当 PROPOSALS=on 时生效)
## Decisions docs/plan.md 中的决策表,以及所有非默认选择
## Gate output `npm run verify` 的输出,原样,放在代码块中,包含所有跳过的行;
然后是 prelaunch-reconcile 接受的每一行,格式为“reproduced from live (dN)”
## Visual review `npm run review:check` 的输出,每个 docs/visual-overrides.json 条目
(路由、ID、阈值、原因),每个 bannerClosed 和 heightMismatch;联系单位于
review/index.html 和 review/all.html(本地;npm run review:sheet)
## Staging 预发布 URL、verify-live 结果、launch-audit 阻塞项及其状态
## Suggestions 按类别统计数量、中高风险的条目、可应用的 ID
## Not covered pre-launch 和 launch-audit 的“Not covered”章节,原样,每个在其自己的标题下;
然后是 capture-site、visual-review 和 suggestions 的“Not covered”章节
## Waiting on you 每个 state.needsYou 条目,按运行手册顺序排列
最终报告(给用户)
首先提供拉取请求链接(如果是草稿,则注明“draft: waiting on the form id”),然后说明:转换了什么(计数)、门控和视觉审查各用一行说明、预发布 URL、Waiting on you 下的“需要你处理”列表(通过 state.mjs --dir $SITE get needsYou 读取,每个条目包含确切的命令或点击操作,按运行手册顺序),最后是每个“Not covered”章节的原样内容。告知“PR open, waiting on your merge”,切勿说“完成”或“上线”。停止你启动的任何审查服务器(npm run review:serve -- --stop,如果使用了预览功能则运行 npx astro preview stop),然后停止。
中断后恢复
在新的会话中,读取 node $KIT/skills/convert-site/scripts/state.mjs --dir $SITE get 并从 phase 阶段继续:首先重新运行该阶段的验证条件;如果通过,则开始下一阶段。抓取可以通过 --resume 参数恢复。绝不重复问答消息。稍后应用建议可使用 convert-site --apply <id>(references/apply-suggestion.md),这不属于运行本身的一部分。
参考文献
| 文件 | 内容 |
|---|---|
references/intake.md | 一次性消息:问题、默认值、缺少什么以及会发生什么 |
references/phases.md | 每个阶段:确切的命令、完成验证条件、需要记录的内容 |
references/build-rules.md | 如何构建布局、内容、CSS、媒体、字体、懒加载图片和重定向 |
references/forms.md | Formspree 连接、字段名称、蜜罐、感谢页、表单 ID、一次测试提交 |
references/third-party.md | baseline/scripts.json 中的 keep 白名单和 docs/third-party.md |
references/hosting-vercel.md | 项目、公共带 noindex 的预发布、索引、Blob 媒体、可选保护 |
references/hosting-cloudflare.md | Pages 项目、_redirects、_headers、R2 媒体函数、查询重定向 |
references/runbook.md | docs/LAUNCH.md:A 需要你处理、B 收尾、C 上线日、D 30 天监控 |
references/components-optional.md | 可选的组件阶段 |
references/apply-suggestion.md | --apply <id>:提案记录、分支提交、门控、联系单 |