mcpField
R
rs-update

rs-update

github.com/rootspec开发055 次安装27 周前更新
代码仓库

关于 rs-update

rs-update 用于升级 RootSpec 项目并对齐当前框架规则,面向项目维护者。它提供交互式审查流程,也支持事务式 CI 模式。

主要功能

  1. 01分析框架版本差距
  2. 02交互式制定升级计划
  3. 03事务式 CI 升级
  4. 04更新前置条件与配置
  5. 05协调框架规则

适用场景

  1. 01应用升级前审查 RootSpec 项目
  2. 02在 CI 流水线中自动执行安全升级

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rootspec/rootspec --skill rs-update

安装后在 Claude Code 中输入/rs-update确认已加载。

附带文件UPDATE.md

详细介绍

你正在将一个 RootSpec 项目升级到最新框架版本。首先,告诉开发者你接下来要做什么:

“我会检查你的项目是否符合最新框架版本,并升级所需内容——框架文件、前置条件和配置。”

模式

此技能以以下两种模式之一运行:

  • 交互模式(默认)——展示计划,等待确认,并与开发者逐项处理违规情况。适用于有人参与的运行场景。
  • CI 模式——无需提示,自动应用计划;针对每项违规采用“推荐”路径;整个运行过程具有事务性(所有预检均通过,或者不修改任何文件)。适用于 CI 流水线中的 claude -p 调用、计划重建或任何无人值守场景。

可通过以下任一信号检测 CI 模式:

if [[ "${CI_FOCUS:-}" == "ci" || -n "${ROOTSPEC_CI:-}" || "${CI:-}" == "true" ]]; then
  CI_MODE="true"
else
  CI_MODE="false"
fi

(此处的 CI_FOCUS 表示将字面字符串 ci 作为此技能的 focus 参数传入——/rs-update ci。)大多数 CI 运行器会自动设置 CI=true;希望在本地使用 CI 模式的用户可以导出 ROOTSPEC_CI=1。

当 CI_MODE=true 时,请遵循本文中的 CI 行为说明,并跳过所有确认提示。否则,请按所述交互流程操作。

第 1 步:检测差异

运行扫描和差异分析脚本:

bash "$(dirname "$0")/../rs-shared/scripts/scan-spec.sh" .
bash "$(dirname "$0")/../rs-shared/scripts/gap-analysis.sh" .

如果这些路径无法解析,请在技能目录中搜索 gap-analysis.sh 来查找脚本。

根据输出:

  • GAP=no_project——未找到 .rootspec.json。告知开发者:“未找到 RootSpec 项目。请先运行 /rs-init。”然后退出。
  • GAP=none——已使用最新框架版本。如果 RULE_VIOLATIONS 为空,告知开发者:“项目使用的是版本 X.Y.Z,且符合当前框架规则。无需更新。”然后退出。如果 RULE_VIOLATIONS 不为空,则项目早于一项或多项框架规则——跳过第 2 至第 4 步,转到第 5 步(协调框架规则)。
  • GAP=patch|minor|major——需要升级。继续。(升级后仍需执行第 5 步中的协调。)

第 2 步:展示变更内容

阅读更新指南:

skills/rs-update/UPDATE.md

相对于此技能文件查找指南:"$(dirname "$0")/UPDATE.md"

提取 PROJECT_VERSION(不含)和 BUNDLED_VERSION(含)之间的所有版本章节。展示:

  • 版本差异(例如,“6.2.1 → 6.2.3”)
  • 各版本变更摘要
  • 任何手动操作说明
  • 是否存在破坏性变更

第 3 步:展示升级计划

根据差异分析输出,展示清晰的计划:

Upgrade plan (6.2.1 → 6.2.3):

Will update:
  - rootspec/00.FRAMEWORK.md (replace with vX.Y.Z)
  - rootspec/00.AXIOMS.md (replace with latest)
  - .rootspec.json version field

Will create (new prerequisites):
  - [list from NEW_PREREQUISITES, if any]

Needs reconciliation (changed prerequisites):
  - [list from CHANGED_PREREQUISITES, if any]

Will NOT touch:
  - Spec files (01.PHILOSOPHY.md through 05.IMPLEMENTATION/)
  - CONVENTIONS/ (owned by /rs-impl)

[If HAS_BREAKING=true]
⚠ Breaking changes detected — see details above.

**交互模式:**等待开发者确认。开发者可以排除部分项目(例如,“跳过 dev.sh”)。

CI 模式:跳过确认。在应用任何内容之前,先运行下文所述的事务性预检。如果预检失败,则使用结构化报告中止整个运行;否则应用完整计划。

事务性预检(仅限 CI)

写入任何文件之前,验证每项计划操作。如果任何检查失败,则输出中止报告(步骤 6 的 CI 格式)并以 1 退出——不执行任何部分操作。

对于 RULE_VIOLATIONS 中的每个条目,运行其预检:

违规项预检失败时 →
baseUrl_has_path对所有 visit: 引用进行分类;相对路径(不以 / 开头)需要人工判断中止
testmode_implicit_dev无——自动选择“保留当前行为”通过
previewServer_missing无——只会增加内容通过
legacy_body_readycypress/support/app-ready.ts 存在,且不包含 'cy.appReady() is not implemented',并且 check-app-ready.sh 对其检查通过中止
shallow_app_ready无——框架规则禁止自动重写中止
dev_cmd_recursivedetect-stack.sh 返回非空的 DEV_CMD(如果 preview 也递归,则还需返回 PREVIEW_CMD)未检测到时中止
viewport_missing无——文件编辑具有幂等性;绝不删除测试文件通过

中止消息必须包含违规项标记、检查内容、失败原因,以及开发者在重新运行前需要执行的操作。具体错误模板:

  • legacy_body_ready 预检失败:

    无法应用 legacy_body_ready 迁移:cy.appReady() 尚未实现 (或实现过于浅显)。请按照 CONVENTIONS/technical.md → App Readiness 的要求实现 cypress/support/app-ready.ts,然后重新运行 /rs-update ci。

    将 safeVisit 连接到会抛出错误的 cy.appReady() 属于已知的错误状态, 我们拒绝发布这种状态。

  • shallow_app_ready 预检失败:逐字转达 check-app-ready.sh 的错误,并说明 CI 模式不会自动重写——请按照 CONVENTIONS/technical.md → App Readiness 的要求实现,然后重新运行。

  • dev_cmd_recursive 预检失败(未检测到框架):

    无法协调 dev_cmd_recursive:detect-stack.sh 未找到任何框架 (没有 astro/vite/next/nuxt 等配置或 devDependency)。请在 scripts/dev.sh / scripts/preview.sh 中手动设置 DEV_CMD 和 PREVIEW_CMD,然后重新运行。

如果任何预检失败:不写入任何内容,输出中止报告,并以 1 退出。

步骤 4:执行升级

对于已确认计划中的每个项目:

框架文件
  1. 00.FRAMEWORK.md — 从 ../rs-shared/00.FRAMEWORK.md(相对于此技能)读取,并写入 {specDirectory}/00.FRAMEWORK.md。
  2. 00.AXIOMS.md — 从 ../rs-shared/00.AXIOMS.md 读取,并写入 {specDirectory}/00.AXIOMS.md。
配置
  1. .rootspec.json — 读取当前文件,仅将 version 字段更新为 BUNDLED_VERSION。保留所有其他字段(specDirectory、prerequisites)。
新增前置条件
  1. 对于 NEW_PREREQUISITES 中的每个条目,检查项目中是否已存在对应文件/配置。如果不存在,则使用与 /rs-init 相同的逻辑创建。读取 ../rs-shared/fragments/prerequisites.md,了解创建说明。
已变更的前置条件
  1. 对于 CHANGED_PREREQUISITES 中的每个条目:该前置条件已存在,但要求已更新。向开发者说明发生了什么变化以及原因(来自 UPDATE.md)。不要自动覆盖——开发者的副本可能包含项目特定的自定义内容。

    对于模板脚本(例如 scripts/dev.sh):显示项目副本与捆绑模板之间的差异。由开发者决定如何协调。

    对于配置接线(例如 cypress.config.ts):说明所需变更,并让开发者确认后再应用。

规格状态
  1. 运行 write-spec-status.sh,更新 spec-status.json 中的版本:
bash "$(dirname "$0")/../rs-shared/scripts/write-spec-status.sh" {specDirectory}

如果检测到重大变更(HAS_BREAKING=true):将 false 作为第二个参数传入,以将规格标记为无效,并告知开发者重新运行 /rs-spec。

bash "$(dirname "$0")/../rs-shared/scripts/write-spec-status.sh" {specDirectory} false

步骤 5:协调框架规则

当 gap-analysis 中的 RULE_VIOLATIONS 非空时运行。每个标记都表示某个项目状态早于一项框架规则。

交互模式: 对每个违规项,展示修复方案并在应用前征求确认——这些操作都不会自动重写用户代码。CI: 根据下表中的策略自动应用推荐方案;每项都已在步骤 3 的预检中验证。

CI 策略摘要
违规项CI 行为
baseUrl_has_path自动从 baseUrl 中移除路径;自动为未添加前缀的访问引用添加前缀(相对引用已在预检中中止)。
testmode_implicit_dev自动选择 “保留当前行为” —— 添加 "testMode": "dev"。此方案较为保守,因为切换到 preview 可能导致行为意外改变。之后如有需要,可由人工切换。
previewServer_missing自动添加 "previewServer": "./scripts/preview.sh";如果模板缺失,则复制随附的模板。
legacy_body_ready始终执行完整迁移。 预检已确认 cy.appReady() 已实现。
shallow_app_ready绝不自动重写 —— 预检已中止运行。(此行仅作提醒;存在此违规项时,CI 永远不会进入 Apply 阶段。)
dev_cmd_recursive自动通过 detect-stack.sh 填充 DEV_CMD/PREVIEW_CMD,并用随附模板覆盖包装脚本(以确保发布递归防护)。预检已确认检测成功。
viewport_missing自动扩展 cypress/support/schema.ts 和 steps.ts,加入 setViewport 和几何断言(可幂等执行);如果 CONVENTIONS/technical.md 中缺少 Test Viewports 章节,则自动添加。绝不删除现有的 .cy.ts 文件;输出 WARN=cypress_e2e_needs_regen,以便开发者知道需要重新生成。
baseUrl_has_path

项目的 cypress.config.ts 中包含 baseUrl: 'http://host:port/some/path'。框架现在要求 baseUrl 仅包含主机和端口;部署路径应放在 visit: 目标和 cy.visit() 调用中。两者拼接后会产生类似 /some/path/some/path/ 的 404 错误。

向开发者展示:

  1. 当前的 baseUrl 行,以及需要移除的路径(例如 /some/path)。
  2. 在 cypress/ 和 rootspec/05.IMPLEMENTATION/USER_STORIES/ 中搜索 visit: 和 cy.visit( 引用的结果。
  3. 对访问引用进行分类:
    • 已添加前缀(以该路径开头)——保持不变;移除 baseUrl 中的路径后即可正常工作。
    • 未添加前缀(以 / 开头,但不是以该路径开头)——询问是否要在前面添加该路径。
    • 相对路径(不以 / 开头)——标记为需要人工检查;相对路径在新旧两种约定下都会失效。

交互模式: 仅应用开发者确认的修改。完成后:重新运行 /rs-validate 进行确认。 CI: 自动移除路径;自动为未添加前缀的访问引用添加路径前缀;相对引用已在预检中中止。

testmode_implicit_dev

项目的 scripts/test.sh 会启动开发服务器,但 .rootspec.json 中没有 prerequisites.testMode。旧项目会默认隐式使用开发模式进行端到端测试;框架现在默认使用预览模式(构建产物 + 预览服务器),以减少不稳定因素。

提供两种方案:

  • 保留当前行为 — 在 .rootspec.json 的 prerequisites 中添加 "testMode": "dev"。无需其他更改。项目会按开发者的明确选择继续以开发模式运行端到端测试。
  • 切换到预览模式默认配置(推荐) — 从捆绑包中复制 scripts/preview.sh(参见下文的 previewServer_missing),将 scripts/test.sh 重写为支持 testMode 的模板(参见 bootstrap-init.sh),并在 .rootspec.json 中添加 "testMode": "preview" 和 "previewServer": "./scripts/preview.sh"。提交前验证 npm run build 可以正常运行。

如果开发者选择“切换”,请提醒他们项目可能需要实现应用就绪检测(参见 framework-rules.md 中的 App Readiness)——预览模式会暴露开发模式下被掩盖的水合时序问题。

**CI:**自动选择“保留当前行为”(添加 "testMode": "dev")。切换到预览模式可能会改变运行时行为;CI 的任务是安全升级,而不是更改行为默认值。之后人工可以再切换。

legacy_body_ready

项目的 cypress/support/steps.ts 会在每次访问后等待 <body data-ready="true">(7.6.0 之前的约定)。框架现在要求使用 cy.appReady()——由项目在 cypress/support/app-ready.ts 中定义的就绪检测。页面级就绪检测无法观察各个岛屿的水合情况;对于包含异步岛屿的技术栈,测试可能在页面就绪后通过,然后却点击到尚不可交互的 DOM。

提供两种方案:

  • 仅添加存根(最小改动) — 使用会抛出错误的默认实现生成 cypress/support/app-ready.ts,并在 cypress/support/e2e.ts 中添加 import './app-ready';。暂时保留 steps.ts 不变。开发者之后可以按故事逐步采用 cy.appReady()。现有测试会继续使用页面级等待。
  • 完整迁移(推荐) — 执行与“仅添加存根”相同的操作,并重写 steps.ts 中的 safeVisit:将 cy.get('body').should('have.attr', 'data-ready', 'true') 这一行替换为 cy.appReady()。将 awaitReady 步骤添加到 runSetupSteps 和架构定义中。随后,开发者必须实现 cy.appReady()(对于静态站点,可使用一行空操作实现;对于水合过程较多的站点,则需要进行实际检查)。现有设置了 body[data-ready] 的页面不受影响——可以继续这样做,也可以停止这样做,框架不再依赖它。

如果选择完整迁移,请提醒开发者,第一次运行 npx cypress run 会因“未实现 cy.appReady()”而失败——这是约定开始生效,并非回归问题。

**CI:**始终执行完整迁移。预检已确认 cy.appReady() 已实现(不是会抛出错误的存根,也未在延迟执行边界处进行浅层检查)。将 safeVisit 接入会抛出错误的存根是已知的错误状态,预检会拒绝该状态,而不会悄然发布。

shallow_app_ready

项目的 cypress/support/app-ready.ts 会在文档级别信号(document.readyState、body 存在、cy.wrap(true) 等)出现时解析,但项目挂载了延迟执行边界——也就是交互代码会在初始文档到达 之后 才运行的组件或模块(Astro client:*、RSC 'use client'、React.lazy/Suspense、Next.js dynamic()、Vue defineAsyncComponent 等)。浅层检查会在这些边界可交互之前触发;测试时而通过,时而在首次点击尚未完成水合的组件时失败。这与 7.6.0 合约原本要防止的问题相同,只是发生在更底层。

向开发者展示:

  1. 当前 cypress/support/app-ready.ts 的内容,以及它匹配的浅层模式。
  2. 在项目中找到的延迟执行标记(文件路径 + 匹配到的指令/导入)。
  3. 所需修复:重写 cy.appReady(),使其等待这些边界完全激活时发出的信号(框架或应用在水合后设置的全局变量、已知节点上的属性、轮询组件状态、事件等)。在 CONVENTIONS/technical.md → App Readiness 中记录所选机制,包括:(a) 第 2 步中列出的边界;(b) 每个边界激活时发出的信号。

不要自动重写 app-ready.ts——具体选择取决于应用实际使用的水合机制。先引导开发者完成 conventions 章节,再据此实现。

如果项目还缺少 scripts/check-app-ready.sh,请从随附的 rs-shared/scripts/ 中复制,以便今后的测试运行都受到相同规则的检查。重写后,运行 ./scripts/check-app-ready.sh . 确认检查通过。

**CI:**绝不自动重写。预检会以原样输出 check-app-ready.sh 的错误,并中止整个运行。按照 CONVENTIONS/technical.md → App Readiness 实现后,重新运行。

dev_cmd_recursive

项目的 scripts/dev.sh 和/或 scripts/preview.sh 将 DEV_CMD/PREVIEW_CMD 设置成递归模式(npm run dev、./scripts/dev.sh 等效命令),而且 package.json 通过包装脚本调用其 dev/preview 脚本。一旦有人输入 npm run dev,就会陷入无限循环。有些项目中用于掩盖此问题的绕过方式(package.json 直接调用框架二进制文件,跳过包装脚本)会破坏包装脚本对端口的处理和单实例保证。

运行 detect-stack.sh 以确定框架二进制命令:

eval "$(bash "$(dirname "$0")/../rs-shared/scripts/detect-stack.sh" .)"
echo "Detected: $STACK"
echo "DEV_CMD=$DEV_CMD"
echo "PREVIEW_CMD=$PREVIEW_CMD"

detect-stack.sh 会优先使用 .rootspec.json prerequisites.detected 中捕获的原始配置(项目引导前的 package.json 脚本),然后回退到检查框架配置文件是否存在,最后检查 package.json 中的 devDependency。

**交互模式:**向开发者展示检测到的 DEV_CMD/PREVIEW_CMD 值并征求确认。开发者可能希望修改这些值(例如,添加 --host 0.0.0.0 或更改端口)。仅应用开发者确认的修改。如果 STACK=unknown,请引导开发者手动识别框架二进制文件。

**CI:**如果 DEV_CMD 非空,则自动应用(预检已完成验证)。如果 STACK=unknown,则中止运行(预检失败)。

应用阶段:

  1. 使用 ../rs-shared/scripts/dev.sh 中随附的模板覆盖 scripts/dev.sh(此模板包含新的递归保护)。
  2. 使用 ../rs-shared/scripts/preview.sh 中随附的模板覆盖 scripts/preview.sh。
  3. 将包装脚本中的空行 DEV_CMD="" 替换为 DEV_CMD="<detected command>"。对 PREVIEW_CMD="" 执行相同操作。
  4. 确认 package.json 中的 dev/preview 脚本通过包装脚本运行(触发此违规时,它们应该已经如此)。如果不是,则重写这些脚本。
  5. 在 CONVENTIONS/technical.md → Dev Server 中记录所选命令。
viewport_missing

项目至少有一个标记为 @journey: MOBILE_* 或 @journey: TABLET_* 的用户故事,已生成 cypress/e2e/*.cy.ts 文件,并且这些测试文件中都不包含 cy.viewport(。7.8.0 之前的生成器不支持视口感知——无论用户旅程如何,这些测试都会以 Cypress 的 1000×660 默认视口运行。“在 375px 宽度下没有水平滚动”的验收标准在桌面宽度的视口下会空通过。

应用阶段(交互模式和 CI 模式相同):

  1. 扩展 cypress/support/schema.ts — 将 setViewport 添加到 Step 联合类型中(如果缺少 shouldHaveNoOverflowX/shouldFitViewport,也一并添加)。此操作幂等;跳过已存在的行。

  2. 扩展 cypress/support/steps.ts — 在 runSetupSteps 中添加 else if ('setViewport' in s) cy.viewport(s.setViewport.width, s.setViewport.height);;在 runAssertionSteps 中添加几何断言分支。此操作幂等。

  3. 将 Test Viewports 添加到 CONVENTIONS/technical.md — 如果缺少该部分,则在 Testing 下追加,并使用 ../rs-shared/viewport-defaults.json 中的框架默认值:

    ### Test Viewports
    - **MOBILE_JOURNEY:** 375x667
    - **TABLET_JOURNEY:** 768x1024
    
  4. 告知开发者,现有的 cypress/e2e/*.cy.ts 文件是在支持视口感知之前生成的,需要重新生成:

    面向移动端/平板端用户旅程故事的现有测试是在支持视口感知之前生成的。请删除受影响的 cypress/e2e/*.cy.ts 文件,并重新运行 /rs-impl,以便注入 setViewport 后重新生成。(我们不会自动删除用户拥有的测试文件。)

交互模式: 确认后再编辑每个文件;最后询问是否重新生成测试文件。 CI 模式: 自动应用步骤 1–3(幂等文件编辑,属于框架自有机制),跳过重新生成步骤(CI 不会删除用户文件),并在结构化报告中包含 WARN=cypress_e2e_needs_regen,以便下一次由开发者主导的运行处理此问题。

previewServer_missing

项目的 .rootspec.json 缺少 previewServer 条目。如果正在通过“切换”路径处理 testmode_implicit_dev,则在同一步中修复此问题。否则,添加指向 ./scripts/preview.sh 的条目(如果缺少,则复制捆绑的模板),以记录此先决条件——即使项目仍使用 dev 模式,也能从可用的预览基础设施中受益。

报告

对于每个违规项,在第 6 步的报告中说明已协调的内容(或应开发者要求跳过的内容)。

第 6 步:报告

交互模式

总结已完成的工作:

Update complete (6.2.1 → 6.2.3).

Updated:
  - rootspec/00.FRAMEWORK.md
  - rootspec/00.AXIOMS.md
  - .rootspec.json version

Created:
  - [any new prerequisites]

Flagged for review:
  - [any changed prerequisites with reconciliation notes]

Next steps:
  - [Re-run /rs-impl to update conventions if needed]
  - [Any manual instructions from UPDATE.md]
CI 模式

输出结构化的 key=value 报告,以便 CI 脚本进行检索:

RESULT=success
APPLIED=baseUrl_has_path,previewServer_missing,legacy_body_ready
SKIPPED=
ABORTED_ON=
WARN=
EXIT=0

当 viewport_missing 位于 APPLIED 中时,还要输出 WARN=cypress_e2e_needs_regen,以便 CI 脚本得知这些测试文件需要由下一次开发者主导的 /rs-impl 删除并重新生成。多个警告以逗号分隔。

中止时:

RESULT=aborted
APPLIED=
SKIPPED=
ABORTED_ON=shallow_app_ready
EXIT=1

字段含义:

  • RESULT — success(所有违规项均已解决或不存在)或 aborted(一个或多个预检失败;未应用任何更改——事务性约定)。
  • APPLIED — 本次运行中已协调的违规项标记,以逗号分隔。
  • SKIPPED — 因开发者(在交互模式下)拒绝而未应用的标记;在 CI 中始终为空。
  • ABORTED_ON — 预检失败的违规项标记,以逗号分隔。成功时为空。
  • EXIT — 0 表示成功,1 表示中止。技能以此代码退出。

将报告输出到标准输出,并在前后换行,以便 CI 通过管道将其传给解析器。

重点

如果开发者传入参数:

  • "ci" → 激活 CI 模式(参见 Mode 部分):无需确认,针对每个违规项采用建议路径,执行事务性预检,并输出结构化 key=value 报告。等同于设置 ROOTSPEC_CI=1。
  • 版本号(例如 "6.2.2")→ 仅显示该特定版本的变更
  • "check" → 仅运行差距分析,不执行任何更改(试运行)
  • "prerequisites" → 仅处理先决条件更新(跳过框架文件)

范围

  • 可以读取: 所有项目文件、所有捆绑的技能文件
  • 可以写入: {specDirectory}/00.FRAMEWORK.md、{specDirectory}/00.AXIOMS.md、{specDirectory}/spec-status.json、.rootspec.json、新的前置文件
  • 不应写入: 规范文件(01-05)、应用程序源代码、现有测试文件
  • 不应覆盖: 未经开发者确认的现有前置文件

评论

支持 Markdown