mcpField
R
rs-impl

rs-impl

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

关于 rs-impl

rs-impl 是一种非交互式实现技能,按故事逐项将已验证的 RootSpec 用户故事转化为代码,并通过测试验证。它会评估规格、准备测试基础设施并记录实现进度。

主要功能

  1. 01评估已验证的 RootSpec 规格
  2. 02按阶段和依赖顺序实现故事
  3. 03依据规格搭建 Cypress 测试
  4. 04运行检查并限制测试修复轮次
  5. 05记录迭代及各故事统计

适用场景

  1. 01依据已验证用户故事开发功能
  2. 02继续处理尚未通过的故事
  3. 03从故事定义生成 Cypress 测试

安装

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

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

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

详细介绍

你是一名实现 Agent。你的任务是将经过验证的 RootSpec 规范中的用户故事逐个转化为可运行的代码,并通过测试验证。

这是一项非交互式技能。实现期间不要向开发者提问。请自行做出最佳判断,并在进度报告中说明任何不确定之处。如果发现规范存在问题(缺少故事、验收标准不明确或要求相互矛盾),请报告问题并建议使用 /rs-spec,不要修改规范文件。

统计跟踪: 在最开始记录 STARTED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")。工作期间跟踪迭代次数和每个故事的尝试次数。最后(步骤 4)调用 write-stats.sh。

回合效率: 每次工具调用都会占用一个回合。请积极合并文件读取和写入操作。目标节奏:每个故事约 3 个回合(所有故事共用的设置开销另计)。

硬性规则 — package.json: 绝对不能写入或修改 package.json 的 dependencies 或 devDependencies 字段。任何时候都不行。创建文件、更新文件或安装框架时都不行。请使用 npm install <pkg1> <pkg2> ... 添加软件包,npm 会写入依赖项。只能直接编辑 scripts 字段。如果需要框架,请运行一条命令:npm install astro @astrojs/react react react-dom tailwindcss(或等效命令)。绝不能使用 Write 工具修改依赖项。

硬性规则 — 对等依赖纪律: 安装框架时,只安装框架、框架的专用集成,以及应用代码直接导入的软件包。不要单独安装框架已作为传递依赖引入的工具(如打包器、编译器、测试运行器、CSS 处理器等)。框架的对等依赖约束是这些版本的权威依据;单独指定主要版本会导致升级兼容性问题。具体故障示例:项目在框架通过对等依赖要求 ^5 的情况下指定 vite ^7,而框架自行管理 Vite;下次框架升级时,npm 可能会选错 Vite,导致升级悄然失效。如果你认为需要某个框架所管理工具的特定版本,那说明框架选错了,而不是对等依赖有问题。

步骤 1:评估(约 2 个回合)

在单次脚本调用中,尽早完成所有读取。先找到脚本目录——在项目根目录下查找 .agents/skills/rs-shared/scripts/,或在 skills 目录中搜索 assess.sh。

STARTED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
SHARED_DIR=$(find . -path "*/rs-shared/scripts/assess.sh" -maxdepth 5 2>/dev/null | head -1 | sed 's|/scripts/assess.sh||')
bash "$SHARED_DIR/scripts/assess.sh" . "$SHARED_DIR"

记住 SHARED_DIR 路径;后续步骤会用它调用其他脚本。由于 shell 状态不会在工具调用之间保留,后续需要用到它的 bash 命令开头都要包含 SHARED_DIR=<解析出的路径>。

脚本会以带标签的分区输出所有上下文。请解析这些内容:

  • SCAN_SPEC: 如果 STATUS=no_spec,请说“未找到规范。请运行 /rs-init,然后运行 /rs-spec。”并退出。
  • SPEC_STATUS: 如果 valid 不为 true,请说“规范尚未通过验证。请运行 /rs-spec。”并退出。
  • TESTS_STATUS: 记录哪些故事已经通过——跳过这些故事。
  • YAML: 这些就是用户故事。统计数量,并记录其 ID、阶段和验收标准。
  • CONVENTIONS: 技术栈、模式和视觉令牌。请熟记并遵循。
  • ROOTSPEC_JSON: 提取 devServer 和 validationScript 先决条件。
  • PACKAGE_SCRIPTS: 确定测试命令。优先级:.rootspec.json 中的 validationScript → package.json 中的 test 脚本 → npx cypress run。
  • FRAGMENT:dsl-steps: 核心 DSL 步骤名称。完整的测试模式见本文档的步骤 3。

请宣布:“共找到 X 个故事,分属 N 个阶段。M 个已通过。正在实现[重点内容;或:从第一阶段开始实现所有故事]。”

现在已获得所有上下文。实现期间不要重新读取这些文件。

步骤 2:设置(约 4 个回合)

2a. 筛选用户故事(如提供了关注点)
bash "$SHARED_DIR/scripts/filter-stories.sh" rootspec [focus]

将 [focus] 替换为参数(例如 MVP、US-101、TASK_SYSTEM、failing)。如果未提供关注点,则按阶段顺序处理所有用户故事(从最早的阶段开始)。在每个阶段内,按依赖关系排序——先处理基础流程(主页、身份验证、核心 CRUD),再处理依赖这些流程的功能。

2b. 搭建 Cypress 脚手架(仅首次实现)

如果 tests-status.json 中没有通过的用户故事,则搭建测试基础设施:

bash "$SHARED_DIR/scripts/scaffold-cypress.sh" . "$SHARED_DIR"

这会通过一次调用创建所有 Cypress 文件:配置、支持文件、DSL 步骤、模式和报告器。检查其输出,了解哪些文件已创建,哪些已跳过。

然后根据规格 YAML 生成测试文件:

bash "$SHARED_DIR/scripts/generate-test-file.sh" rootspec cypress/e2e/mvp.cy.ts

这会使用 loadAndRun() 模式生成测试文件,并将所有用户故事嵌入为 YAML 字符串字面量。未采用 DSL 格式的 given/when/then 的用户故事会被跳过,并显示警告——你需要手动为这些用户故事添加测试 YAML。

搭建脚手架后,在一次写入操作中完成自定义。 检查你的用户故事,确认是否包含:

  • loginAs 步骤 → 在 cypress.config.ts 中实现任务主体
  • seedItem 步骤 → 在 cypress.config.ts 中实现任务主体
  • 核心集合中没有的自定义 DSL 步骤 → 扩展 steps.ts 和 schema.ts
  • 应用就绪状态——参见下方的第 2c 步。cypress/support/app-ready.ts 必须根据 CONVENTIONS/technical.md 的 App Readiness 部分编写,而不是反过来。在该部分编写完成前,不要自定义会抛出错误的存根。

在一次多文件操作中写入所有自定义内容。

2c. 填充 dev/preview 包装脚本、约定和开发服务器(合并为一轮)

包装脚本 scripts/dev.sh 和 scripts/preview.sh 初始为空(带有一个会硬失败的递归保护)。在尝试启动服务器之前,根据检测到的技术栈填充 DEV_CMD/PREVIEW_CMD。读取一次,写入一次,然后启动。

eval "$(bash "$SHARED_DIR/scripts/detect-stack.sh" .)"
# DEV_CMD and PREVIEW_CMD are now set (e.g. DEV_CMD='npx astro dev --port 4321').
# If either is empty, the stack is unknown — surface it in the implementation
# report and fall back to manual configuration. Do not start the server.

然后在同一轮中,将 DEV_CMD="..." 和 PREVIEW_CMD="..." 写入包装脚本(编辑 scripts/dev.sh 和 scripts/preview.sh 中现有的空赋值行),并在 CONVENTIONS/technical.md →「Dev Server」中添加两行:检测到的技术栈 + 字面命令。后续的 /rs-impl 运行会以此部分为准——只有当该部分缺失时才重新检测。

填充完成后,启动开发服务器:

./scripts/dev.sh start
sleep 3

开发服务器用于快速迭代(在实现循环中对其运行 npx cypress run)。项目的规范测试运行器是 ./scripts/test.sh,它会遵循 .rootspec.json 中的 prerequisites.testMode(默认值为 "preview":构建 + preview 服务器)。提交前钩子会调用 test.sh,因此无论你如何迭代,检查门槛都采用 preview 模式。不要为了让测试通过而将 testMode 改为 "dev"——应修复实现,使其能通过对构建产物的测试。

如果 rootspec/CONVENTIONS/ 不存在,请在同一轮中通过并行的 Write 调用创建 technical.md 和 visual.md。根据规范、检测到的框架和现有源代码进行编写。对于棕地项目(已有代码、但没有先前约定),请审查代码库并记录观察到的模式——技术栈、文件组织、样式方案、API 模式、组件结构。使用 ## Heading 小节和 - **Label:** value 条目。

如果任何用户故事标记了 MOBILE_* 或 TABLET_* 路径,technical.md 必须包含「Test Viewports」小节。使用 grep -rE "@journey:.*(MOBILE|TABLET)" rootspec/05.IMPLEMENTATION/USER_STORIES 检测。如果存在匹配项,请写入 $SHARED_DIR/viewport-defaults.json 中的框架默认值:

### Test Viewports
- **MOBILE_JOURNEY:** 375x667
- **TABLET_JOURNEY:** 768x1024

这些默认值会用于 generate-test-file.sh 的视口注入。项目级编辑会覆盖默认值;YAML 中每个故事的 setViewport 始终优先。如果项目没有响应式路径,则完全跳过此小节。

technical.md 必须包含「App Readiness」小节,并按以下顺序回答两个问题:

  1. 延迟执行边界。 列出所有在初始文档到达后才加载或执行交互代码的组件、区域或模块。注明文件路径。例如:通过 client:load/client:idle/client:visible/client:only 挂载的组件(Astro)、'use client' 岛(RSC)、React.lazy+<Suspense>、dynamic(...) 导入(Next.js)、defineAsyncComponent(Vue)、Svelte 动态加载。如果项目中没有此类边界,请写「None — fully static」,并附上一行证据。
  2. 就绪信号。 对于每个边界,说明它完全激活时会发出什么可观测信号(例如全局变量、已知节点上的属性、事件、轮询组件状态等)。Cypress 实现中的 cypress/support/app-ready.ts 应据此编写——约定决定代码,而不是反过来。

然后编写 cypress/support/app-ready.ts,断言上述第(2)点中的信号。保持文件简洁:Cypress.Commands.add 主体 + declare global + export {}。不要在实现文件中写解释性注释——推理应放在 technical.md 中,以便根据框架规则进行审查。可以用一行指向约定文档,但不能写多段说明。

如果渲染输出中包含任何延迟执行边界,cy.appReady() 必须观察这些边界——document.readyState、body 存在性和 cy.wrap(true) 都不够,会导致 scripts/check-app-ready.sh 在 Cypress 启动前的预检中硬失败。只有当「App Readiness」小节在第(1)点回答「None — fully static」时,才可以使用空操作或仅检查 document。

2d. 接入 build 脚本

rs-init 创建的 package.json 中包含一个占位脚本:"build": "echo 'No build configured yet'"。安装带有构建命令的框架时,请在同一轮中执行 npm install 并替换此占位脚本。下游评审阶段会运行 npm run build 来扫描渲染后的 HTML——占位脚本会静默地产生空输出,导致评审效果下降。

常见构建命令:

框架scripts.build
Astroastro build
Vitevite build
SvelteKitvite build
Next.jsnext build
Eleventyeleventy
Remixremix vite:build

已有项目:如果 package.json 中已经有实际的 build 脚本,请保持不变。

第 3 步:实现(每个故事约 3 轮)

每个故事最多进行 2 轮测试修复。 如果一个故事花费超过 5 轮,请记录为 FAIL 并继续下一个。

目标节奏:每个故事约 3 轮。 实现规范要求的所有故事——不要提前停止或缩小范围。

实现前:对所有故事进行预检

运行预检脚本,查看需要构建的具体内容:

bash "$SHARED_DIR/scripts/preflight-story.sh" rootspec/05.IMPLEMENTATION/USER_STORIES .

该脚本会输出:

  • ROUTES_NEEDED / ROUTES_MISSING — 需要创建的页面/路由
  • SELECTORS_NEEDED / SELECTORS_MISSING — 需要添加的 data-test 属性
  • CUSTOM_STEPS_NEEDED / CUSTOM_STEPS_MISSING — 需要在 steps.ts 中实现的 DSL 步骤
  • TASKS_NEEDED / TASKS_MISSING — 需要在 cypress.config.ts 中实现的 Cypress 任务

用这些信息规划工作——现在你可以在写下第一行代码之前,了解完整范围。

规划写入批次

通过并行 Write 调用,将文件分组到不同轮次中:

  • 页面组件: 将同一页面上的组件分组(例如,Hero + MetaBanner + ProblemSection → 3 个并行 Write 调用 = 1 轮)
  • 基础设施: Layout + 全局样式 + Header + Footer → 1 轮
  • 数据/配置: 所有数据文件和配置 → 1 轮
  • 交互组件: 复杂的 React/TSX 组件较大时,每轮可处理 1 个
  • 测试文件: 将所有故事 YAML 添加到测试文件中——绝不要推迟添加测试条目

所有应用代码总计应控制在 4-6 轮写入,不要每轮只写一个文件。

实现循环:接线 → 构建 → 针对性测试 → 全量测试
阶段 0:接好基础设施(编写任何应用代码之前)

根据预检输出,在一轮内完成机械性接线:

  • CUSTOM_STEPS_MISSING → 扩展 steps.ts 和 schema.ts
  • TASKS_MISSING → 在 cypress.config.ts 中添加 Cypress 任务实现

这些都是机械性工作——添加类型,并加入实现框架。为所有故事一次性完成。

阶段 A:构建一个批次

选择 2-4 个相关故事。尽可能少用几轮,通过并行 Write 调用编写所有代码和测试 YAML。预检中 SELECTORS_NEEDED 列出的每个 data-test 属性都必须出现在组件代码中。

在任何测试与页面交互之前,应用就绪状态必须已确认。每次 visit 后都会自动调用 cy.appReady()(也可通过 awaitReady DSL 步骤在流程中显式等待)。cypress/support/app-ready.ts 中的实现遵循 CONVENTIONS/technical.md 的「应用就绪」部分(参见步骤 2c)——先在约定中列出边界,Cypress 检查再断言这些边界发出的信号。如果页面包含任何延迟执行边界,检查就必须观察这些边界;document.readyState、body 存在以及 cy.wrap(true) 都属于预检失败。路由无需设置任何特定属性;在遵循此规则的前提下,由项目自行决定如何发出就绪信号。

阶段 B:测试指定的故事

仅运行你已实现的故事的测试:

npx cypress run --spec cypress/e2e/mvp.cy.ts 2>&1 | tail -20; cat rootspec/tests-status.json

如果指定故事的测试失败,请根据预检输出进行诊断——不要猜测:

  • 找不到选择器 → 检查准确的 data-test= 属性是否与预检中的 SELECTORS_NEEDED 相符
  • 路由返回 404 → 检查页面文件路径是否与预检中的 ROUTES_NEEDED 相符
  • 找不到任务 → 检查 cypress.config.ts 是否包含 TASKS_NEEDED 中的任务
  • Zod 验证错误 → 你使用了非核心 DSL 步骤
  • 断言值错误 → 这是实际的功能逻辑问题——修复应用代码

在一轮中修复。每批最多进行 2 轮修复。然后继续。

阶段 C:测试所有故事(回归检查)

指定测试通过后(或你已继续处理后),运行完整测试套件:

npx cypress run 2>&1 | tail -20; cat rootspec/tests-status.json

与本批次开始前通过的测试进行比较。如果之前通过的故事现在失败了,这就是回归。 在实现更多故事前修复回归问题。

回归问题处理方式:

  • 如果所有测试同时失败 → 构建/配置问题。检查框架配置、导入和构建错误,并修复根本原因。
  • 如果特定故事出现回归 → 你的更改产生了冲突。还原冲突部分,或修复交互逻辑。
  • 存在回归问题时,不要继续实现新故事。
测试文件模式(重要)

不要使用 cy.readFile() 加载 YAML 文件。 Cypress 命令不能在 it() 块外运行。请改为在测试文件中将 YAML 嵌入为字符串字面量,并使用 loadAndRun() 函数。

测试文件请使用以下准确模式:

import * as yaml from 'js-yaml';
import { UserStorySchema } from '../support/schema';
import type { UserStory } from '../support/schema';
import { runSetupSteps, runAssertionSteps } from '../support/steps';

function loadAndRun(yamlContent: string) {
  const docs = yaml.loadAll(yamlContent) as UserStory[];
  for (const doc of docs) {
    if (!doc || !doc.id) continue;
    const story = UserStorySchema.parse(doc);
    const describeFn = story.skip ? describe.skip : story.only ? describe.only : describe;
    describeFn(`${story.id}: ${story.title}`, () => {
      for (const ac of story.acceptance_criteria) {
        const itFn = ac.skip ? it.skip : ac.only ? it.only : it;
        itFn(`${ac.id}: ${ac.title}`, () => {
          if (ac.given) runSetupSteps(ac.given);
          if (ac.when) runSetupSteps(ac.when);
          if (ac.then) runAssertionSteps(ac.then);
        });
      }
    });
  }
}

// Embed stories as YAML string literals, separated by ---
const contentStories = `
id: US-101
title: Story title here
acceptance_criteria:
  - id: AC-101-1
    title: Criterion title
    given:
      - visit: '/'
    when: []
    then:
      - shouldExist: { selector: '[data-test=element]' }
`;
loadAndRun(contentStories);

测试文件的关键规则:

  • 每个阶段或逻辑分组使用一个测试文件(例如,mvp.cy.ts)
  • 将每个故事的 YAML 直接嵌入为字符串,多文档 YAML 使用 --- 分隔
  • 从规范 YAML 中复制给定/当/那么步骤,并调整选择器以匹配你的 data-test 属性
  • loadAndRun 函数会创建格式正确的 describe/it 块,供 rootspec-reporter 解析
  • 只能使用核心 DSL 步骤: visit、click、fill、loginAs、seedItem、shouldContain、shouldExist。不要使用 wait、scrollTo、shouldHaveAttribute、reload 或任何其他步骤——它们不在架构中,会导致崩溃。
  • 调试时绝不要重写或缩减测试文件。 只能追加新故事,或编辑特定的 YAML 字符串。重写文件会丢失所有现有的通过测试。
  • 绝不要创建额外的测试文件(不要创建 debug.cy.ts、targeted.cy.ts 等)。所有测试都放在同一个测试文件中。
构建一批故事

不要重新读取 YAML、约定或片段。使用步骤 1 中的上下文。

检查 @phase 注解。 如果 @phase: baseline,只编写/验证 Cypress 测试——不要修改应用代码。

对于非 baseline 故事,每个故事用一轮写入完成:

  • 创建/修改所有应用文件(路由、组件、页面、样式)
  • 将该故事的 YAML 添加到测试文件中(追加至现有测试文件)
  • 使用符合验收标准选择器要求的 data-test 属性

只有当测试 YAML 已写入测试文件后,故事才算实现完成。

示例批次(3 个故事,3 轮):

  • 第 1 轮: 编写 MetaBanner.astro、HeroSection.astro、ProblemSection.astro(并行写入)
  • 第 2 轮: 更新 index.astro,并将 3 个故事的 YAML 添加到测试文件中(并行写入)
  • 第 3 轮: 运行本批次的指定测试(阶段 B)
修复失败

在一轮中使用 Edit 修复特定行。每批最多进行 2 轮修复。

如果遇到困难,请重新运行预检以确认连接配置正确:

bash "$SHARED_DIR/scripts/preflight-story.sh" rootspec/05.IMPLEMENTATION/USER_STORIES .

如果 SELECTORS_MISSING 或 ROUTES_MISSING 不为空,请先修复这些问题——否则测试无法通过。

绝不要:

  • 重写整个测试文件(会丢失已通过的测试)
  • 创建单独的调试/指定测试文件
  • 添加 wait 或 timeout 步骤(DSL 中没有这些步骤)
  • 从测试文件中移除故事
每批完成后

报告:"Batch complete: US-001, US-002, US-003 PASS. Full suite: 6/10 passing, 0 regressions."

如果存在回归问题,请先修复,再开始下一批。所有目标故事都通过测试(或达到每个故事的尝试上限)后,转到第 4 步。

第 4 步:总结并提交(约 3 轮)

更新约定(1 轮)

检查实现是否引入或更改了 rootspec/CONVENTIONS/ 中记录的内容。更新约定文档,使其反映实际构建的内容,例如新依赖、模式、颜色和字体。仅更新实际发生变化的条目。遵循以下格式:使用 ## Heading 小节和 - **Label:** value 条目。

提交并报告(1–2 轮)
COMPLETED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

如果所有目标故事都通过测试: 提交实现,并在提交消息中概述已实现的内容。然后建议运行 /rs-validate 以获取完整报告。

如果有任何故事未通过测试: 不要提交。报告失败情况,并建议继续运行 /rs-impl failing,或使用 /rs-spec 修复规格。未提交的工作会保留在工作区中,供开发者检查。

记录统计信息:

bash "$SHARED_DIR/scripts/write-stats.sh" rootspec/stats.json rs-impl "$STARTED_AT" "$COMPLETED_AT" <iteration-count> '<stories-json>'

其中 <stories-json> 是一个 JSON 对象,例如 {"US-101":{"attempts":2},"US-102":{"attempts":1}},用于记录每个故事经历了多少轮测试。

报告

根据 tests-status.json 生成报告,不要自行评估:

bash "$SHARED_DIR/scripts/generate-test-report.sh" rootspec/tests-status.json rootspec

此操作会根据实际测试结果输出通过、失败和未测试的数量。在总结中包含其输出。

范围焦点

参数用于限定此技能的工作范围:

  • 不指定范围焦点 → 按阶段顺序处理所有故事(从最早阶段开始)
  • "US-101" → 指定故事
  • "TASK_SYSTEM" → 某个系统的故事
  • "MVP"(或任意阶段名称)→ 标记了该阶段的故事
  • "failing" → 重新实现先前未通过测试的故事

范围

  • 可以读取: 所有项目文件
  • 可以写入: 应用代码、测试基础设施、配置文件
  • 可以写入: rootspec/CONVENTIONS/(technical.md、visual.md)
  • 可以更新: rootspec/tests-status.json
  • 不可写入: rootspec/ 中的任何其他文件(规格文件、spec-status.json、00.AXIOMS.md、00.FRAMEWORK.md)
  • 不可写入: package.json 中的 dependencies 或 devDependencies(请使用 npm install)

评论

支持 Markdown