mcpField
O
openspec-bulk-archive-change

openspec-bulk-archive-change

github.com/fission-ai开发73.3k4.0k 次安装5 天前更新
代码仓库

关于 openspec-bulk-archive-change

用于将多个已完成的 OpenSpec 变更批量归档的技能。它检查任务与产物状态、检测规格路径冲突,并依据代码实现证据决定规格同步方式;变更由用户选择并确认。

主要功能

  1. 01批量归档所选变更
  2. 02检查产物与任务进度
  3. 03检测增量规格路径冲突
  4. 04依据代码证据解决冲突
  5. 05检查归档目标是否重名

适用场景

  1. 01一次归档多个已完成变更
  2. 02归档前检查未完成工作
  3. 03处理规格路径重叠的变更

安装

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

$npx skills add https://github.com/fission-ai/openspec --skill openspec-bulk-archive-change

安装后在 Claude Code 中输入/openspec-bulk-archive-change确认已加载。

详细介绍

一次性归档多个已完成的变更。

此技能可批量归档变更,并通过检查代码库来判断实际实现情况,从而智能处理规格冲突。

存储库选择: 如果用户指定了存储库(存储库是指在此计算机上注册的独立 OpenSpec 仓库),或相关工作位于其中,请运行 openspec store list --json,查找已注册的存储库 ID,然后在读取或写入规格和变更的命令(new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)中传入 --store <id>。选定后,在整个工作流的其余部分都将 --store <id> 视为固定参数。以下未指定存储库的示例命令均为简写:运行前请追加此参数。例如,运行 openspec status --change "<name>" --json --store "<id>",而不是下方所示的未指定存储库版本。其他命令不接受此参数。命令输出的提示中已包含该参数;后续操作时请保留该参数。如果未指定存储库,命令会对最近的本地 openspec/ 根目录执行操作。

项目检查: 以下步骤要求项目已在使用 OpenSpec。在第一个会写入内容的步骤(new change、archive、sync specs 或编写构件文件)之前,请确认项目已有根目录:运行 openspec list --json(如果已选定存储库,则传入 --store <id>,因为此时存储库就是根目录),并读取 root。如果返回根对象,说明项目已完成设置。"root": null 表示项目尚未设置——此处没有 openspec/ 目录,执行 openspec new change 等写入操作会将其作为副作用创建。此命令还会以非零状态码退出,这就是结果,并不代表 CLI 出错;请读取 JSON,不要重试或绕过问题。

一个 "root": null 结果不一定表示项目尚未设置:如果 status 的错误消息以 Declared in 或 Invalid store declaration in 开头,并指出此项目的 openspec/config.yaml(或 config.yml),则表示项目通过其声明的存储库使用 OpenSpec,但此计算机无法解析该存储库(该存储库尚未注册,或 store: 行格式错误)。不要将项目视为尚未初始化,也不要继续执行下方分支:停止写入,并向用户展示错误中的 message 和 fix。

如果没有根目录,接下来的操作取决于此工作流的触发方式:

  • 自动选择:你自行选择了此工作流,用户没有提及 OpenSpec、此技能,也没有运行其斜杠命令。停止使用 OpenSpec,并像未安装 OpenSpec 一样正常回应用户请求。不要询问用户是否要进行设置,也不要提及 OpenSpec 设置。
  • 用户明确请求使用 OpenSpec:用户提及了 OpenSpec、此技能,或运行了其斜杠命令。停止写入,并询问用户如何继续:设置此项目(openspec init)、指定他们已有的存储库(--store <id>),或在本次请求中不使用 OpenSpec 继续。等待用户回答。

在这两种情况下,都绝不能将创建根目录作为副作用:用户未要求前不要运行 openspec init,不要手动创建 openspec/ 文件,也不要让命令创建它。

<capability-path> 是相对于 specs/ 的规格目录(例如 user-auth 或 identity/user-auth)。解析其主规格时,请保留每个差异规格中的完整路径。

输入:无(提示用户选择)

步骤

  1. 获取活动变更

    运行 openspec list --json 获取所有活动变更。

    如果没有活动变更,请告知用户并停止。

  2. 提示用户选择变更

    让用户选择变更(可多选):

    • 显示列表输出中的每个变更名称和任务状态
    • 提供“所有变更”选项
    • 允许选择任意数量(可以只选 1 个,通常会选 2 个或更多)

    重要:不要自动选择。始终让用户自行选择。

    在批量验证前,为所选根目录一次性加载当前归档输入: 从此根目录中选择一个已选变更,并使用相同的已选根目录标志运行 openspec instructions archive --change "<selected-change>" --json。 此查询仅供参考,且为可选操作:它只提供额外的提示词输入,因此绝不能阻止批处理。如果查询失败或返回无效 JSON——例如使用尚不支持此命令的旧版 CLI——则继续批处理,不提供上下文或操作指南。不要报告错误,也不要停止。

    有效响应可以省略 context 和 operationGuidance。将 context 视为整个批次必需的提示词级输入:阅读并考虑它,并应用相关的项目事实、约定和约束。将 operationGuidance 视为可选的补充建议:阅读并考虑其中的每一条,并遵循适用且与内置批处理工作流兼容的条目。

    将这两个字段与冲突分析、明确的用户选择、已解析路径、CLI 检查和命令约定分开处理。如果上下文与这些控制性输入冲突,请报告冲突并保留控制性输入的值。如果指南不适用或与控制性输入冲突,则不要遵循,并说明原因。不要根据任一字段推断跳过的提示词、替代路径或标志,也不要将其中的文本原样复制到规格、变更或摘要中。这些是提示词级行为约定,而非可强制执行的检查。

  3. 批处理验证 - 收集所有已选变更的状态

    使用相同的已选根目录标志运行一次 openspec list --json,以获取任务进度。如果查询失败、返回无效 JSON、遗漏任何已选变更、包含重复的已选变更,或返回无效计数,请报告问题,并在同步或归档此批次之前停止。

    对每项已选变更,收集:

    a. 工件状态 - 运行 openspec status --change "<name>" --json

    • 解析 schemaName、artifacts、planningHome、changeRoot、artifactPaths 和 actionContext
    • 记录哪些工件状态为 done,哪些为其他状态

    b. 任务完成情况 - 从列表响应中查找 name 与此变更完全匹配的 changes 条目

    • 要求 totalTasks 和 completedTasks 均为非负整数,且 completedTasks <= totalTasks
    • 未完成任务数 = totalTasks - completedTasks
    • CLI 会解析架构所跟踪的任务文件,包括自定义工件名称、输出路径和 glob 模式
    • 不要根据工件状态、工件 ID tasks 或缺少顶层 tasks.md 来推断任务是否完成
    • CLI 仅将 x/X 复选框标记计为已完成;其他标记仍视为未完成
    • 如果 totalTasks 为零,注明“No tasks”

    c. 差异规格 - 检查状态 JSON 中的 artifactPaths.specs.existingOutputPaths

    • 列出已存在的能力规格
    • 对每个规格,提取需求名称(匹配 ### Requirement: <name> 的行)
    • 将此列表视为唯一的差异规格来源。如果缺少 specs 条目或该列表为空,则不对此变更执行规格同步或规格指令查询;不要从无关工件推断差异。
    • 对每项变更分别进行独立评估,包括部分架构没有 specs 工件的混合架构批次 d. 归档目标 — 计算每个变更的目标名称,并记录为该变更的 <target-name>
    • 如果变更名称已以 YYYY-MM-DD- 前缀开头,则原样使用;否则在前面加上当前日期,格式为 YYYY-MM-DD-<name>(规则与 openspec archive 相同)
    • 检查 <planningHome.changesDir>/archive/<target-name> 是否已存在
    • 如果已存在,或其他选定变更解析出的目标名称相同,则将所有此类变更标记为 Blocked,并注明 Archive directory already exists
    • 被阻止的变更绝不进行同步或移动:在第 6 步表格中将其显示为 Blocked,将其排除在冲突解决之外(仅使用其他变更解决冲突),并在第 8d 步中将其记录为 Failed
    • 在写入任何主规格之前进行此项检查,与 openspec archive 的行为一致:如果同步后才发现冲突,就会导致主规格已被改写,但归档并未完成
  4. 检测规格冲突

    构建一个以 <capability-path> 为键的映射,该路径是相对于 specs/ 的精确路径:

    identity/user-auth -> [change-a, change-b]  <- CONFLICT (2+ changes)
    billing/user-auth  -> [change-c]            <- OK (different full path)
    

    当 2 个或更多选定变更包含相同 <capability-path> 的增量规格时,即存在冲突。

  5. 通过 Agent 方式解决冲突

    对于每个冲突,调查代码库:

    a. 阅读增量规格,了解每个冲突变更声称要添加或修改的内容

    b. 搜索代码库以查找实现证据:

    • 查找实现各增量规格中要求的代码
    • 检查相关文件、函数或测试

    c. 确定解决方案:

    • 如果实际上只有一个变更已实现,则同步该变更的规格
    • 如果两个变更都已实现,则按时间顺序应用(较早的先应用,较新的覆盖)
    • 如果两个变更都未实现,则跳过规格同步并警告用户

    d. 记录每个冲突的解决方案:

    • 按变更和 <capability-path> 记录每个增量规格的纳入或排除决定
    • 记录要应用的已纳入增量规格及其应用顺序
    • 记录因缺少实现而从同步中排除的增量规格
    • 说明理由(在代码库中发现了什么)
  6. 显示汇总状态表

    显示汇总所有变更的表格:

    | Change              | Artifacts | Tasks | Specs   | Conflicts | Status |
    |---------------------|-----------|-------|---------|-----------|--------|
    | schema-management   | Done      | 5/5   | 2 delta | None      | Ready  |
    | project-config      | Done      | 3/3   | 1 delta | None      | Ready  |
    | add-oauth           | Done      | 4/4   | 1 delta | identity/user-auth (!) | Ready* |
    | add-verify-skill    | 1 left    | 2/5   | None    | None      | Warn   |
    

    对于冲突,显示解决方案:

    * Conflict resolution:
      - identity/user-auth spec: Will apply add-oauth then add-jwt (both implemented, chronological order)
    

    对于未完成的变更,显示警告:

    Warnings:
    - add-verify-skill: 1 incomplete artifact, 3 incomplete tasks
    
  7. 确认批量操作

    向用户询问一个确认问题:

    • “归档 N 个变更?”并根据状态提供选项
    • 选项可能包括:
      • “归档全部 N 个变更”
      • “仅归档 N 个就绪变更(跳过未完成项)”
      • “取消”

    如果存在未完成的变更,请明确说明归档时会附带警告。

    根据用户的意图处理回答,而不是要求标签完全匹配——这些标签是你写的, 因此应根据用户选择进行匹配,而不是拘泥于上述措辞:

    • “取消”——停止,不要归档。报告未归档任何内容,并跳过剩余步骤。
    • 归档全部选项——继续处理所有未被标记为 Blocked 的选定变更
    • 仅归档就绪项选项——仅处理第 6 步表格中标记为 Ready 或 Ready* 的变更,并在第 8d 步中将其余变更记录为 Skipped;但 Blocked 变更除外,这些变更仍标记为 Failed,并注明 Archive directory already exists。如果跳过某个 Ready* 变更的冲突伙伴,则仅使用要归档的变更重新推导该冲突的解决方案。
    • 其他任何回答——重新询问,不要归档 在步骤 8 写入第一个主规范或移动任何变更之前,先为已确认批次获取所有必需的规范规则快照。对于每个将同步具体 artifactPaths.specs.existingOutputPaths 的变更,使用相同的选定根目录标志,恰好运行一次 openspec instructions specs --change "<name>" --json。在首次写入或移动之前获取所有快照。 如果任何查询以非零状态退出,或返回无效的 artifact-instruction JSON, 请指出受影响的变更,报告错误,并在任何主规范写入或变更移动之前停止整个批次。不要将查询失败视为没有规则。没有 rules 的有效响应表示无规则。
  8. 为每个已确认的变更执行归档

    处理前,将步骤 5 中记录的决策(经过步骤 7 的任何重新推导后)归入两个按增量划分的集合:

    • includedDeltas:已确认变更中所有无冲突的增量规范,以及选定用于同步的冲突增量规范
    • excludedDeltas:因缺少实现而从已确认变更中排除的冲突增量规范
    • 单个变更可以同时包含纳入和排除的增量规范。按增量保留决策;不要将其合并为按变更划分的同步标志。

    按确定的顺序处理变更(遵循冲突解决顺序):

    a. 同步纳入的增量规范:

    • 仅对 includedDeltas 中有条目的变更,内联运行 openspec-sync-specs 工作流(由 Agent 驱动的智能合并),仅传入纳入的增量路径,并明确指示其忽略该变更的 excludedDeltas。等待其完成。
    • 如果同步报告任何停止或阻塞条件,则视为同步失败。立即停止处理该变更。在继续处理下一个变更之前,将该变更的结果记为批次结果中的 Failed,并包含同步阻塞条件或错误。
    • 不要执行同步后的内容比较,也不要移动其 changeRoot;保持变更原样。
    • 对于冲突,按解决后的顺序应用。
    • 将该变更获取的规范规则快照传入内联同步;内联同步必须复用该快照,不得再次获取指令。
    • 仅将工件规则应用于该变更生成的主规范。它们不会改变冲突解决、归档行为或 CLI 契约,其文本也不会复制到输出文件中。
    • 不要委派给后台任务——步骤 8c 会在仍有同步任务读取 changeRoot 时将其移走。
    • 如果某个变更没有纳入的增量规范,则不要为其运行同步工作流。

    b. 移动 changeRoot 前验证纳入的增量规范:

    • 仅对 includedDeltas 中的增量规范重新进行比较,并与 <planningHome.root>/openspec/specs/<capability-path>/spec.md 中的主规范比对(使用步骤 3 状态 JSON 中感知存储位置的 planningHome.root,不要使用硬编码的仓库路径)。
    • 验证主规范已更新:
      • 已添加的需求存在
      • 已修改的需求包含增量规范中指定的场景和描述变更,且其他场景保持不变
      • 已移除的需求不再存在——如果此次同步停用了某项能力(移除其最后一个需求,使 ## Requirements 为空),则应删除其主规范,而不是保留空文件。
      • 已重命名的需求使用新名称,且旧名称已不存在
    • 不要验证 excludedDeltas 中的增量规范;它们有意保持未同步状态。
    • 如果同步失败或任何能力未通过验证,则报告差异,并且失败或跳过移动该变更的 changeRoot——不要归档该变更。changeRoot 保持原样。

    c. 执行归档:

    目标名称:使用步骤 3d 中为该变更记录的 <target-name>,不得更改。切勿在此处重新计算:跨越午夜运行的批次可能会在步骤 3 中检查一个日期,却移动到另一个日期。 检查目标是否已存在:

    • 移动前立即再次检查,即使步骤 3 已检查过:目标可能在批处理期间出现
    • 如果已存在:将此变更记录为失败,错误为 Archive directory already exists,将 changeRoot 保留在原处,报告步骤 8a 已为其同步的任何主规格,并继续处理剩余变更
    • 如果不存在:将 changeRoot 移动到归档目录
    mkdir -p "<planningHome.changesDir>/archive"
    mv "<changeRoot>" "<planningHome.changesDir>/archive/<target-name>"
    

    **确认移动时没有嵌套:**即使目标在检查后出现,mv 也会以 0 退出,并将变更移动到该目录内部。如果现在存在 <planningHome.changesDir>/archive/<target-name>/<change-directory-name>(即 changeRoot 的最后一个路径段),则将该目录移回 changeRoot,并将此变更记录为失败,错误为 Archive directory already exists。绝不要将其报告为已归档。

    d. 跟踪每项变更的结果:

    • 成功:已成功归档
    • 失败:归档或规格验证期间出错(记录错误)
    • 已跳过:用户选择不归档(如适用)
    • 跳过同步:对于 excludedDeltas 中的每个增量,报告同步已跳过,并注明变更、<capability-path> 和记录的原因。这与跳过归档不同。
  9. 显示摘要

    显示最终结果:

    ## Bulk Archive Complete
    
    Archived 3 changes:
    - schema-management-cli -> archive/2026-01-19-schema-management-cli/
    - project-config -> archive/2026-01-19-project-config/
    - add-oauth -> archive/2026-01-19-add-oauth/
    
    Skipped 1 change:
    - add-verify-skill (user chose not to archive incomplete)
    
    Spec sync summary:
    - 4 delta specs synced to main specs
    - 1 delta spec sync skipped (add-jwt, identity/user-auth: implementation not found)
    - 1 conflict resolved (identity/user-auth: synced add-oauth, skipped add-jwt)
    

    如果存在失败:

    Failed 1 change:
    - some-change: Archive directory already exists
    

冲突解决示例

示例 1:仅一个已实现

Conflict: <planningHome.root>/openspec/specs/auth/spec.md touched by [add-oauth, add-jwt]

Checking add-oauth:
- Delta adds "OAuth Provider Integration" requirement
- Searching codebase... found src/auth/oauth.ts implementing OAuth flow

Checking add-jwt:
- Delta adds "JWT Token Handling" requirement
- Searching codebase... no JWT implementation found

Resolution: Only add-oauth is implemented. Will sync add-oauth specs only.

示例 2:两者均已实现

Conflict: <planningHome.root>/openspec/specs/api/spec.md touched by [add-rest-api, add-graphql]

Checking add-rest-api (created 2026-01-10):
- Delta adds "REST Endpoints" requirement
- Searching codebase... found src/api/rest.ts

Checking add-graphql (created 2026-01-15):
- Delta adds "GraphQL Schema" requirement
- Searching codebase... found src/api/graphql.ts

Resolution: Both implemented. Will apply add-rest-api specs first,
then add-graphql specs (chronological order, newer takes precedence).

成功时的输出

## Bulk Archive Complete

Archived N changes:
- <change-1> -> archive/<target-name-1>/
- <change-2> -> archive/<target-name-2>/

Spec sync summary:
- N delta specs synced to main specs
- No conflicts (or: M conflicts resolved)

部分成功时的输出

## Bulk Archive Complete (partial)

Archived N changes:
- <change-1> -> archive/<target-name-1>/

Skipped M changes:
- <change-2> (user chose not to archive incomplete)

Failed K changes:
- <change-3>: Archive directory already exists

没有变更时的输出

## No Changes to Archive

No active changes found. Create a new change to get started.

护栏

  • 允许任意数量的变更(1 个或更多均可,典型用例为 2 个或更多)
  • 始终提示用户进行选择,不得自动选择
  • 尽早检测规范冲突,并通过检查代码库解决
  • 当两个变更都已实现时,按时间顺序应用规范
  • 仅当缺少实现时才跳过规范同步(并警告用户)
  • 确认前清晰展示每项变更的状态
  • 整个批次只进行一次确认
  • 用户取消确认后,绝不归档——取消的批次不会归档任何内容
  • 跟踪并报告所有结果(成功/跳过/失败)
  • 移至归档时保留 .openspec.yaml
  • 归档目录目标使用当前日期,该日期在步骤 3d 中计算一次,并在移动时重复使用:YYYY-MM-DD-;如果名称已以 YYYY-MM-DD- 前缀开头,则原样使用(绝不叠加第二个日期)
  • 如果归档目标已存在,则该变更失败,但继续处理其他变更
  • 在步骤 3 中、首次写入主规范之前检查每个归档目标;目标已存在的变更绝不进行同步或移动
  • 如果请求同步,则针对每个包含增量规范的变更,内联运行 openspec-sync-specs 工作流(由 Agent 驱动)
  • 将每个增量规范的 includedDeltas 和 excludedDeltas 决策带入执行流程;只同步和验证已包含的增量规范
  • 将每个已排除的增量规范报告为 sync skipped,但不要因此将归档本身视为已跳过
  • 规范同步仍在进行时,绝不归档变更——内联运行同步,并在移动 changeRoot 前验证 <planningHome.root>/openspec/specs/<capability-path>/spec.md 中的主规范
  • 对每个选定的根目录,只获取一次归档输入,然后再检查规范或移动文件
  • 在批次首次写入或移动主规范之前,获取所有必需的规范规则快照
  • 归档输入查找失败不会阻止批次;继续执行时不使用上下文或指导
  • 规范说明查找失败时,原子性地停止整个批次
  • 没有具体 artifactPaths.specs.existingOutputPaths 的变更继续执行,不进行规范同步
  • 在整个批次中应用相关运行时上下文,并报告冲突
  • 操作指导仅供参考;考虑每一条建议,并解释拒绝采纳的理由
  • 将运行时输入、冲突分析、CLI 推导值和制品规则分开处理
  • 制品规则仅约束写入的规范
  • 绝不将运行时输入或制品规则文本原样复制到输出文件

评论

支持 Markdown