Communitygithub.com

yosegi-dev/yosegi

基于Storybook现有组件的代理驱动屏幕组装工具 — 提供CLI、MCP服务器和Agent能力,无需图形界面。

yosegi 是什么?

Yosegi是一个专注于从宿主项目的现有组件库中组装屏幕的AI代理工具。它的核心价值在于:通过分析TypeScript类型声明来构建组件注册表,精确记录每个组件真实的prop名称、枚举选项、必需参数和函数签名,从而避免开发者凭经验猜测prop而引入缺陷。该工具支持三种运行模式:CLI命令行、MCP服务器和Agent Skill,可以输出为Storybook的CSF故事格式或纯React组件文件。它特别适合在已有设计系统中创建屏幕原型、快速生成可审查的UI草稿,以及在实现前验证组件组合的可行性。平台要求是Node.js 20+和React + TypeScript项目,依赖宿主项目的tsconfig.json和可选的Storybook实例。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add yosegi-dev/yosegi

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Yosegi — 从宿主组件构建屏幕

版本: 2026-08-13。 代理工具可能加载过时的技能副本而不作说明。如果此日期早于仓库中 skills/yosegi/SKILL.md 的版本,说明您正在阅读过期副本 — 请重新安装后再继续。

Yosegi 将宿主项目的组件转化为可构建屏幕的事实依据,并在实现前将屏幕输出为 Story (CSF) 以供审查。它自身既无渲染环境也无图形界面;您通过宿主的 Storybook 查看效果。在未安装 Storybook 的宿主上,交付物变为纯 React 组件文件 (--target component) — 下方步骤 1 分支说明了流程如何变化。

本文档即为操作流程,您是执行者。CLI(以及等效的 MCP 工具)是其使用的工具。

何时使用

  • 从现有设计系统组合屏幕提案或 UI 模型,并以可审查的形式呈现。
  • 在实现前,让新屏幕的第一个草稿在 Storybook 中可见。
  • 在编写任何 UI 之前,查找宿主有哪些组件及其实际接受的 props。
  • 将已批准的 mock Story 转录为真实页面。执行步骤 1 和 2,然后跳至步骤 5。

不适用于:一次性组件修改。

价值所在

注册表职责明确:它是组件 props 的真实来源 — 真实的 prop 名称、真实的枚举选项、哪些是必需的、哪些是插槽 vs children、函数 prop 的调用签名。宿主的组件并非它们所 fork 的库。它们的变体枚举已被重命名,子组件之间的尺寸比例不同,icon prop 接受的是组件引用而非元素,ReactNode prop 是命名插槽而非 children,三个不同的组件共享一个导出名称。这些都无法通过对 React 或上游库的熟悉程度推导出来,而每一项都是如果您按照预期而非注册表实际存在的 prop 编写,就会交付的缺陷。这正是步骤 1 和 2 中 inspect 调用的用途,跳过它们就是让看似合理的 mock 携带缺陷。

注册表不提供屏幕的骨架、组合习惯用语或布局 — 驱动 DataGrid 的网格库 hook 调用、宿主特定的 meta(如 { stickyHeader: true })、组件期望的 wrapper。这些来自宿主自身的 Stories,以及(如果宿主有页面/路由生成器)其 Example 模板(步骤 2)。宿主的模板和 Story 覆盖越丰富,注册表在您实际构建屏幕所需信息中的占比越小 — 这并非缺陷。注册表和宿主自身的示例回答不同的问题,并且各自对其回答的问题都至关重要。

参考资料

在下方步骤要求您查阅时再打开,不要提前。对于 3a 路线(直接编写 Story),可能永远不需要:registry status 和 component inspect 的输出加上本文档正文通常足以构建整个屏幕。但一旦需要,请依据参考资料而非仅凭本文档记忆 — 其细节在此不重复。

文件何时阅读
references/registry.md当 inspect 的输出有无法解释的内容 — 不透明 prop 的 shape: / signature: 行、未文档化的 prop、看起来错误的导入说明符
references/cli.md当命令或标志未在本文档中说明、CLI 无法运行、或需要 MCP 等效命令时
references/screen-json.md仅当您选择 Screen JSON 路线(3b)时。格式及其无法表达的内容
references/errors.md当任何命令打印错误或警告时。每个错误码及其修复方法
references/implementation.md用于步骤 3 中的元模板,以及步骤 5 之前

步骤 1. 构建注册表

Yosegi 需要宿主提供可读的 tsconfig.json(props 来自 TypeScript 类型,这已足够)。Storybook 是 Story 的存放位置以及您确认渲染效果的地方 — 但它并非必需。

如果您无法检测到 Storybook — 没有 .storybook/(或等效)配置目录,宿主 package.json 中没有 storybook 脚本,没有 index.json 可提供给 --index — 交付物为纯 React 组件文件而非 Story(screen generate --target component,references/cli.md)。不要自行选择输出位置或审查方法:在构建任何内容之前,询问用户 (a) 组件文件应放在何处,以及 (b) 他们希望如何确认结果(例如,在宿主应用的临时路由上渲染)。Yosegi 不指定审查界面,猜测任一答案都与猜测 prop 一样违反规则。有了这些答案,以下流程保持不变,仅有三处差异:registry build 运行时不带 --index / --storybook-url(您失去策展,其他不变);在路线 3a 中,您在用户指定的位置编写组件文件;在路线 3b 中,您传递 --target component --out <那个位置>.tsx;步骤 4 的 Storybook 检查被宿主类型检查以及用户命名的确认方法所取代。

  1. 您能运行 CLI 吗? npx yosegi(或 pnpm yosegi、yarn yosegi、bunx yosegi)不带参数会打印所有命令,前提是 @yosegi/yosegi 已是宿主的依赖项 — 如果尚未安装,请先安装(references/cli.md)。需要 Node.js 20 或更新版本,React + TypeScript 宿主。如果命令失败,请参阅 references/cli.md 中的“如果 CLI 无法运行”;最有用的操作是读取 <data-dir>/registry.json 的 builtWithCliPath(如果之前会话中已有注册表)。
  2. 现在就固定一个 --data-dir 并传递给每个命令。使用宿主包根目录下的 .yosegi,这也是默认值;下面的示例仍会写出它,因为默认值跟随您的 cwd,从其他目录运行的命令将找不到您构建的内容。
  3. 是否有注册表,并且是最新的? 首先运行 yosegi registry status --data-dir .yosegi — 它会根据自己记录的输入重新计算注册表版本,并报告 source: current 或 source: stale 以及精确的重建命令,而不需要您通过 component list 的标题来目测。显示“Registry not found”表示首次运行。其 Storybook 索引部分是尽力而为的,可能报告索引不可达,而源判定仍然有效 — 将该部分理解为“无法验证”,而非“过时”或“最新”,不要让不可达的开发服务器阻止您信任 current 的源判定。只要 status 报告为 stale、或打印了 REGISTRY_VERSION_MISMATCH、或 status 报告 source: unknown(因为注册表早于记录输入 built: not recorded) — 那里没有可重新计算的内容,因此年龄是您唯一的信号。还要在命令警告注册表是由与您当前运行的不同 Yosegi 版本构建时重建:较旧的 Yosegi 无法输出当前版本可以输出的字段(例如函数 prop 的调用签名),没有其他信号能显示这一差距 — 版本字符串作为内容哈希保持不变,因此从未更改的宿主重建的注册表会保留相同的版本字符串。注册表是一个快照,过时的比没有更糟。
yosegi registry build \
  --source "app/components/**/*.tsx" \
  --tsconfig <host>/tsconfig.json \
  --index http://localhost:6006/index.json \
  --storybook-url http://localhost:6006 \
  --report tmp/registry-report.json \
  --data-dir .yosegi

上面的 6006 是 Storybook 自身的默认端口,仅在此使用,因为这是首次构建且尚未告知您其他信息 — 它不一定是宿主的端口。在运行此命令前,检查宿主 package.json 中的 Storybook 脚本(或询问)以获取实际运行的端口。首次构建后的每次重建有比猜测更好的来源:component list 的标题会打印一行 rebuild:,其中包含注册表上次构建时使用的精确 --storybook-url(references/cli.md)。

标志和默认值在 references/cli.md 中。--index 是唯一有前提条件的部分:开发服务器 URL 意味着宿主的 Storybook 必须已在运行。没有它您会失去 Story 派生类别和 recommended 标记,其他不变。

阅读其打印的统计信息:

  • files: 0 → glob 未匹配任何内容。命令仍然成功并写入仅包含三个合成原语的注册表,因此不要将“Wrote 3 components”视为成功。
  • files 为正数但 componentCandidates: 0,或 anyShapedProps 较高但 withNodeSlots: 0 → 构建虽然成功但降级了。第一种表示 glob 未覆盖任何 React 组件;第二种表示 @types/react 未解析,因此每个 ReactNode prop 都扁平化为 json,未检测到插槽。两种情况下的 Warning: 行都会指明修复方法 — 解决后重建再继续。
  • propsUnreadable 相对于 extractedComponents 较高 → tsconfig 可能错误。立即解决(references/cli.md,registry metadata);处于该状态的组件稍后会拒绝完全真实的 props。

步骤 2. 查找您打算使用的每个组件

如果页面/路由生成器的 Example 模板是与您构建的屏幕最接近的匹配,请优先阅读它,或与下面的命令一起阅读 — 它决定了骨架和组合习惯用语,注册表然后确认模板留下的确切 props。

yosegi component list --category app/components/ui --data-dir .yosegi
yosegi component list --query card --data-dir .yosegi
yosegi component inspect "app/components/ui/button#Button" --data-dir .yosegi

注册表可能包含数百个条目,因此使用 --category / --query 缩小范围,从摘要中获取方向,然后 inspect 您将要编写的每个组件。**inspect 是权威的,而您的框架知识不是。**阅读 references/registry.md 以了解如何解读其输出 — 枚举选项、不透明 prop 下的 shape: 和 signature: 行、宿主实际编写的导入说明符以及未文档化 prop 的含义。

优先选择标记为 recommended 的组件;它们有自己的 Story。

然后收集宿主的约定。Story 会放入宿主仓库并作为宿主代码进行审查;跳过这一步会产生一个虽然工作但仍会被打回的 UI。

  • 查找数据契约(如果已存在) — OpenAPI/JSON Schema 定义、GraphQL schema、手写的 API 响应 TypeScript 类型,无论宿主数据层使用何种形式。在编造 mock 数据之前阅读它。它决定的不仅仅是组件 props:哪些字段是必需的、可为 null 的(以及 null 对于特定字段的含义 — 例如 null limit 可能意味着“无限制”,而非“未知”)、哪些字段互斥,以及同样有用的是,没有什么(契约中没有排序或搜索字段意味着屏幕也不应发明这些)。这将 mock 从观感提案转变为反映真实数据形状的内容。其位置因宿主而异(openapi/schemas/、.graphql 文件、生成的 types.ts);找到该域存在的那个,并遵循它而非看似合理的猜测。
  • 搜索宿主的路由/页面目录(app/routes/ 或提供页面的任何位置),查找同一域中现有的屏幕。在成熟产品中通常存在一个,找到它可能完全重新定义任务 — 例如,现有的 bookings.calendar._index 路由可能将“制作一个预订屏幕”转变为“针对现有预订流程提出一个横切列表”。这决定了您被要求制作的 mock 是否甚至是要构建的正确内容,因此在下面的检查点之前执行此操作,并让它塑造您在那里提出的问题。
  • 在构建任何内容之前运行 git status 并查看输出目录。 早先未提交的同一屏幕尝试可能已经存在于工作树中 — 在上下文重置和重新发出请求后很常见。与其创建重复文件,不如与之协调。要重做已存在的文件 — 宿主生成器在目标路径已存在时会拒绝,或者早先的尝试需要替换 — 将其移开(重命名)而非删除;您可能无权删除,而重命名无论如何都能清除路径。
  • 检查宿主是否有新页面或屏幕的生成器 — plop/hygen 生成器、bun add-route 风格的脚本,通常记录在宿主的 AGENTS.md 或 package.json 脚本中。对于有此生成器的宿主,从头手写新屏幕文件是错误的:生成器克隆了授权的模板并强制执行文件和命名约定,因此请运行它而不是自行创建文件。这也决定了步骤 3 中内联树 Story 与页面模块加薄包装 Story 之间的选择 — 有这样生成器的宿主几乎总是希望后者。
  • 从仓库根目录向下到输出目录的每一级阅读 AGENTS.md / CLAUDE.md,并遵循它们指向的任何文档。
  • 阅读输出位置附近的一两个现有 Stories。组合多个组件的综合示例是值得模仿页面骨架、间距和组件选择的。**对于组合习惯用语 — 组件实际如何组装,而不仅仅接受哪些 props:驱动 DataGrid 的网格库 hook 调用、宿主特定的 meta(如 { stickyHeader: true })、组件期望的 wrapper — 现有 Story 是真实来源,注册表不是。**注册表不知道如何将组件组合成布局。

步骤 3. 编写 JSON 定义

现在您有注册表组件、宿主 Stories 以及(最好)宿主页面生成器的模板。在屏幕完全组装完成之前,您不会编写任何 React 代码。

…(内容已截断)

相关技能