1
0

完成一个简易的全局skill、command管理器

This commit is contained in:
2026-02-25 14:33:56 +08:00
parent f4cb809f9d
commit 2d327b5af8
60 changed files with 6053 additions and 1 deletions

View File

@@ -0,0 +1,95 @@
## ADDED Requirements
### Requirement: 用户可以安装命令组到全局目录
工具必须支持将整个命令组commands 目录下的子目录)安装到平台配置目录。
#### Scenario: 全局安装命令组到 Claude Code
- **WHEN** 用户执行 `skillmgr install command <group> --platform claude --global`
- **THEN** 系统将 `commands/<group>/` 下所有 .md 文件复制到 `~/.claude/commands/<group>/`
#### Scenario: 全局安装命令组到 OpenCode
- **WHEN** 用户执行 `skillmgr install command <group> --platform opencode --global`
- **THEN** 系统将 `commands/<group>/` 下所有 .md 文件重命名为 `<group>-<action>.md` 并复制到 `~/.opencode/command/`
---
### Requirement: 用户可以安装命令组到项目目录
工具必须支持将命令组安装到当前项目的平台配置目录。
#### Scenario: 项目级安装命令组到 Claude Code
- **WHEN** 用户在项目目录执行 `skillmgr install command <group> --platform claude`
- **THEN** 系统将命令组复制到 `./.claude/commands/<group>/`
#### Scenario: 项目级安装命令组到 OpenCode
- **WHEN** 用户在项目目录执行 `skillmgr install command <group> --platform opencode`
- **THEN** 系统将命令组扁平化复制到 `./.opencode/command/`
---
### Requirement: 系统必须在所有源仓库中查找命令组
工具必须在所有已配置源仓库的 `commands/` 目录中搜索指定命令组。
#### Scenario: 找到命令组
- **WHEN** 源仓库包含 `commands/<group>/` 目录且内有 .md 文件
- **THEN** 系统使用该命令组进行安装
#### Scenario: 命令组不存在
- **WHEN** 所有源仓库都不包含指定命令组
- **THEN** 系统报错"command '<group>' not found in any repository"
#### Scenario: 命令组目录为空
- **WHEN** 找到命令组目录但其中没有 .md 文件
- **THEN** 系统报错"command group '<group>' contains no command files"
---
### Requirement: OpenCode 平台必须扁平化命令文件名
工具必须在安装到 OpenCode 平台时,将命令文件重命名为 `<group>-<action>.md` 格式。
#### Scenario: 转换命令文件名
- **WHEN** 安装 `commands/lyxy-kb/init.md` 到 OpenCode
- **THEN** 文件被重命名为 `lyxy-kb-init.md`
#### Scenario: 保留 .md 扩展名
- **WHEN** 转换文件名时
- **THEN** 系统保留 `.md` 扩展名
---
### Requirement: 系统必须处理命令组目录冲突
工具必须在安装前检查目标目录或文件是否已存在。
#### Scenario: Claude Code 命令组目录冲突
- **WHEN** `~/.claude/commands/<group>/` 目录已存在
- **THEN** 系统询问用户是否覆盖
#### Scenario: OpenCode 命令文件冲突
- **WHEN** 目标 `~/.opencode/command/` 中已存在同名的 `<group>-*.md` 文件
- **THEN** 系统询问用户是否覆盖所有冲突文件
---
### Requirement: 系统必须记录命令组安装
工具必须在成功安装后将记录写入 install.json。
#### Scenario: 记录命令组安装信息
- **WHEN** 命令组安装成功
- **THEN** 系统在 install.json 中添加 type 为 "command"、包含命令组名称和安装路径的记录

View File

@@ -0,0 +1,124 @@
## ADDED Requirements
### Requirement: 系统必须持久化安装记录
工具必须在每次成功安装后,将安装信息写入 `~/.skillmgr/install.json`
#### Scenario: 创建新记录
- **WHEN** 首次安装某个 skill/command
- **THEN** 系统在 install.json 的 installations 数组中添加新记录
#### Scenario: 记录包含必要字段
- **WHEN** 创建安装记录
- **THEN** 记录必须包含 type、name、source_repo、platform、scope、install_path、installed_at、updated_at
---
### Requirement: 用户可以查询已安装项
工具必须提供命令列出所有已安装的 skills 和 commands。
#### Scenario: 列出所有已安装项
- **WHEN** 用户执行 `skillmgr list` 命令
- **THEN** 系统显示所有 install.json 中的记录
#### Scenario: 按类型过滤
- **WHEN** 用户执行 `skillmgr list --type skill``--type command`
- **THEN** 系统仅显示对应类型的安装记录
#### Scenario: 按平台过滤
- **WHEN** 用户执行 `skillmgr list --platform claude``--platform opencode`
- **THEN** 系统仅显示对应平台的安装记录
#### Scenario: 按作用域过滤
- **WHEN** 用户执行 `skillmgr list --global` 或省略该参数
- **THEN** 系统仅显示对应作用域的安装记录
#### Scenario: 无已安装项
- **WHEN** install.json 为空或不存在
- **THEN** 系统提示"无已安装的 skills/commands"
---
### Requirement: 用户可以卸载已安装项
工具必须提供卸载功能,删除文件并移除安装记录。
#### Scenario: 卸载 skill
- **WHEN** 用户执行 `skillmgr uninstall skill <name> --platform <platform> --global`
- **THEN** 系统从 install.json 查找记录,删除对应目录,移除记录
#### Scenario: 卸载 command
- **WHEN** 用户执行 `skillmgr uninstall command <group> --platform <platform> --global`
- **THEN** 系统删除对应的命令文件或目录,移除记录
#### Scenario: 卸载不存在的项
- **WHEN** install.json 中无对应记录
- **THEN** 系统提示"未找到安装记录",不执行删除
#### Scenario: 安装路径已被手动删除
- **WHEN** install.json 有记录但文件已不存在
- **THEN** 系统仅移除记录,不报错
---
### Requirement: 用户可以更新已安装项
工具必须提供更新功能,重新从源仓库安装最新版本。
#### Scenario: 更新单个 skill
- **WHEN** 用户执行 `skillmgr update skill <name> --platform <platform> --global`
- **THEN** 系统从源重新安装到原路径,更新 updated_at 字段
#### Scenario: 更新单个 command
- **WHEN** 用户执行 `skillmgr update command <group> --platform <platform> --global`
- **THEN** 系统从源重新安装到原路径,更新 updated_at 字段
#### Scenario: 更新所有已安装项
- **WHEN** 用户执行 `skillmgr update --all`
- **THEN** 系统遍历 install.json 中所有记录,逐个更新
#### Scenario: 源仓库找不到原始项
- **WHEN** 更新时源仓库中不再存在该 skill/command
- **THEN** 系统报错,不修改已安装文件和记录
---
### Requirement: 用户可以清理孤立记录
工具必须提供命令扫描并清理 install.json 中文件路径已不存在的记录。
#### Scenario: 扫描孤立记录
- **WHEN** 用户执行 `skillmgr clean` 命令
- **THEN** 系统遍历 install.json 中所有记录,检查 install_path 是否存在
#### Scenario: 清理孤立记录
- **WHEN** 发现安装路径不存在的记录
- **THEN** 系统列出这些记录并从 install.json 中删除
#### Scenario: 无孤立记录
- **WHEN** 所有记录的安装路径都存在
- **THEN** 系统提示"无孤立记录"
#### Scenario: 显示清理结果
- **WHEN** 清理完成
- **THEN** 系统显示清理的记录数量和详情type、name、platform、scope、路径

View File

@@ -0,0 +1,104 @@
## ADDED Requirements
### Requirement: 系统必须支持 Claude Code 平台
工具必须内置 Claude Code 平台的目录结构和命名规则。
#### Scenario: Skill 安装路径
- **WHEN** 安装 skill 到 Claude Code
- **THEN** 目标路径为 `<base>/.claude/skills/<skill-name>/`
#### Scenario: Command 安装路径
- **WHEN** 安装 command 到 Claude Code
- **THEN** 目标路径为 `<base>/.claude/commands/<command-group>/`
#### Scenario: 保持源目录结构
- **WHEN** 复制文件到 Claude Code
- **THEN** 系统保持源仓库的目录结构不变
---
### Requirement: 系统必须支持 OpenCode 平台
工具必须内置 OpenCode 平台的目录结构和命名规则。
#### Scenario: Skill 全局安装路径
- **WHEN** 全局安装 skill 到 OpenCode
- **THEN** 目标路径为 `~/.config/opencode/skills/<skill-name>/`
#### Scenario: Skill 项目级安装路径
- **WHEN** 项目级安装 skill 到 OpenCode
- **THEN** 目标路径为 `./.opencode/skills/<skill-name>/`
#### Scenario: Command 全局安装路径
- **WHEN** 全局安装 command 到 OpenCode
- **THEN** 目标路径为 `~/.config/opencode/commands/`
#### Scenario: Command 项目级安装路径
- **WHEN** 项目级安装 command 到 OpenCode
- **THEN** 目标路径为 `./.opencode/commands/`
#### Scenario: Skill 保持结构
- **WHEN** 复制 skill 到 OpenCode
- **THEN** 系统保持源目录结构
#### Scenario: Command 扁平化
- **WHEN** 复制 command 到 OpenCode
- **THEN** 系统将文件重命名为 `<group>-<action>.md` 并放置在 commands/ 目录下
---
### Requirement: 系统必须根据作用域确定基础路径
工具必须根据全局/项目作用域计算正确的基础路径。
#### Scenario: 全局作用域
- **WHEN** 用户指定 `--global` 参数
- **THEN** 基础路径为用户主目录(`~``$HOME`
#### Scenario: 项目作用域
- **WHEN** 用户未指定 `--global` 参数
- **THEN** 基础路径为当前工作目录
---
### Requirement: 系统必须生成文件映射表
适配器必须生成源文件到目标文件的完整映射表,供事务性安装使用。
#### Scenario: Skill 文件映射
- **WHEN** 适配 skill 文件
- **THEN** 系统返回源路径到目标路径的 map包括所有子目录和文件
#### Scenario: Command 文件映射Claude
- **WHEN** 适配 command 到 Claude Code
- **THEN** 系统返回 `commands/<group>/<action>.md``<base>/.claude/commands/<group>/<action>.md` 的映射
#### Scenario: Command 文件映射OpenCode
- **WHEN** 适配 command 到 OpenCode
- **THEN** 系统返回 `commands/<group>/<action>.md``<base>/commands/<group>-<action>.md` 的映射(全局时 base 为 `~/.config/opencode`,项目级时为 `./.opencode`
---
### Requirement: 系统必须处理不支持的平台
工具必须拒绝处理未实现的平台。
#### Scenario: 不支持的平台参数
- **WHEN** 用户指定未实现的平台(如 `--platform cursor`
- **THEN** 系统报错"unsupported platform: cursor"

View File

@@ -0,0 +1,78 @@
## ADDED Requirements
### Requirement: 用户可以添加源仓库
工具必须允许用户添加 git 仓库作为 skills/commands 的源,并将配置持久化到 `~/.skillmgr/repository.json`
#### Scenario: 成功添加新仓库
- **WHEN** 用户执行 `skillmgr add <git-url>` 命令
- **THEN** 系统克隆仓库到 `~/.skillmgr/cache/` 并将配置写入 repository.json
#### Scenario: 添加已存在的仓库
- **WHEN** 用户添加已存在的仓库(同名)
- **THEN** 系统提示"仓库名称已存在,请先使用 `skillmgr remove <name>` 移除",拒绝添加
#### Scenario: 指定仓库别名
- **WHEN** 用户使用 `--name` 参数指定仓库别名
- **THEN** 系统使用指定的别名作为仓库名称
#### Scenario: 指定分支
- **WHEN** 用户使用 `--branch` 参数指定分支
- **THEN** 系统克隆指定分支而非默认分支
---
### Requirement: 用户可以移除源仓库
工具必须允许用户从配置中移除已添加的源仓库。
#### Scenario: 成功移除仓库
- **WHEN** 用户执行 `skillmgr remove <name>` 命令
- **THEN** 系统从 repository.json 中删除对应配置
#### Scenario: 移除不存在的仓库
- **WHEN** 用户尝试移除不存在的仓库名称
- **THEN** 系统提示仓库不存在,不报错
---
### Requirement: 用户可以列出已配置的源仓库
工具必须提供命令列出所有已添加的源仓库及其信息。
#### Scenario: 列出所有仓库
- **WHEN** 用户执行 `skillmgr list-repos` 命令
- **THEN** 系统显示所有仓库的名称、URL、分支和添加时间
#### Scenario: 无已配置仓库
- **WHEN** 用户执行列表命令但 repository.json 为空
- **THEN** 系统提示"无已配置的源仓库"
---
### Requirement: 用户可以同步源仓库
工具必须提供命令从远程拉取最新代码,更新本地缓存。
#### Scenario: 同步单个仓库
- **WHEN** 用户执行 `skillmgr sync <name>` 命令
- **THEN** 系统对指定仓库执行 `git pull`
#### Scenario: 同步所有仓库
- **WHEN** 用户执行 `skillmgr sync` 不带参数
- **THEN** 系统对所有已配置仓库执行 `git pull`
#### Scenario: Git 操作失败
- **WHEN** git pull 失败(网络错误、冲突等)
- **THEN** 系统显示 git 错误信息并继续处理其他仓库

View File

@@ -0,0 +1,95 @@
## ADDED Requirements
### Requirement: 用户可以安装 skill 到全局目录
工具必须支持将 skill 安装到用户主目录下的平台配置目录(如 `~/.claude/skills/`)。
#### Scenario: 全局安装到 Claude Code
- **WHEN** 用户执行 `skillmgr install skill <name> --platform claude --global`
- **THEN** 系统将 skill 复制到 `~/.claude/skills/<name>/`
#### Scenario: 全局安装到 OpenCode
- **WHEN** 用户执行 `skillmgr install skill <name> --platform opencode --global`
- **THEN** 系统将 skill 复制到 `~/.config/opencode/skills/<name>/`
---
### Requirement: 用户可以安装 skill 到项目目录
工具必须支持将 skill 安装到当前项目目录下的平台配置目录。
#### Scenario: 项目级安装到 Claude Code
- **WHEN** 用户在项目目录执行 `skillmgr install skill <name> --platform claude`
- **THEN** 系统将 skill 复制到 `./claude/skills/<name>/`
#### Scenario: 项目级安装到 OpenCode
- **WHEN** 用户在项目目录执行 `skillmgr install skill <name> --platform opencode`
- **THEN** 系统将 skill 复制到 `./.opencode/skills/<name>/`
---
### Requirement: 系统必须在所有源仓库中查找 skill
工具必须在所有已配置的源仓库缓存中搜索指定的 skill。
#### Scenario: 在第一个仓库找到
- **WHEN** 第一个仓库包含目标 skill
- **THEN** 系统使用该仓库的 skill 进行安装
#### Scenario: 在后续仓库找到
- **WHEN** 前面的仓库不包含目标 skill但后续仓库包含
- **THEN** 系统使用找到的第一个匹配仓库
#### Scenario: 所有仓库都不包含
- **WHEN** 所有源仓库都不包含目标 skill
- **THEN** 系统报错"skill '<name>' not found in any repository"
---
### Requirement: 用户可以临时指定源仓库
工具必须支持通过 `--from` 参数临时指定源仓库 URL不保存到配置文件。
#### Scenario: 使用临时仓库安装
- **WHEN** 用户执行 `skillmgr install skill <name> --platform claude --global --from <git-url>`
- **THEN** 系统从指定 URL 拉取仓库并安装,不修改 repository.json
---
### Requirement: 系统必须处理目录已存在的情况
工具必须在安装前检查目标目录是否已存在,并根据情况处理。
#### Scenario: install.json 有记录且目录存在
- **WHEN** 目标 skill 已通过 skillmgr 安装
- **THEN** 系统询问用户是否覆盖,默认为否
#### Scenario: install.json 无记录但目录存在
- **WHEN** 目标目录存在但不在 install.json 中
- **THEN** 系统询问用户是否覆盖该目录,默认为否
#### Scenario: 用户拒绝覆盖
- **WHEN** 用户选择不覆盖
- **THEN** 系统取消安装,不修改任何文件
---
### Requirement: 系统必须记录安装操作
工具必须在成功安装后将记录写入 `~/.skillmgr/install.json`
#### Scenario: 记录包含完整信息
- **WHEN** 安装成功完成
- **THEN** 系统在 install.json 中添加包含 type、name、platform、scope、install_path、installed_at、updated_at 的记录

View File

@@ -0,0 +1,153 @@
## ADDED Requirements
### Requirement: 测试必须不污染用户环境
工具的所有测试必须通过环境变量隔离配置和安装目录,不影响用户的实际数据和系统配置。
#### Scenario: 配置目录隔离
- **WHEN** 测试运行时设置 `SKILLMGR_TEST_ROOT` 环境变量
- **THEN** 系统使用该环境变量指定的目录作为配置根目录,而非 `~/.skillmgr/`
#### Scenario: 安装目标目录隔离
- **WHEN** 测试运行时设置 `SKILLMGR_TEST_BASE` 环境变量
- **THEN** 系统使用该环境变量指定的目录作为全局/项目基础路径,而非用户主目录或当前工作目录
#### Scenario: 生产模式不受影响
- **WHEN** 环境变量未设置(生产模式)
- **THEN** 系统使用默认路径(`~/.skillmgr/``~/.claude/` 等)
---
### Requirement: 测试必须自动清理临时资源
所有测试创建的临时目录、文件和 git 仓库必须在测试结束后自动清理,不留垃圾文件。
#### Scenario: 使用 Go 测试框架自动清理
- **WHEN** 测试使用 `t.TempDir()` 创建临时目录
- **THEN** Go 测试框架在测试结束时自动删除该目录及其所有内容
#### Scenario: 测试失败时也清理
- **WHEN** 测试失败或 panic
- **THEN** 临时资源仍然被自动清理
---
### Requirement: 测试必须支持并行执行
测试设计必须允许多个测试并行运行,互不干扰,充分利用多核性能。
#### Scenario: 独立测试环境
- **WHEN** 使用 `go test -parallel N` 并行运行多个测试
- **THEN** 每个测试使用独立的临时目录,不产生竞态条件
#### Scenario: 配置隔离
- **WHEN** 多个测试同时设置环境变量
- **THEN** 每个测试的环境变量设置独立生效(通过 t.Setenv 或 defer os.Unsetenv
---
### Requirement: 用户交互必须可 mock
所有涉及用户输入的功能必须支持测试时注入 mock 输入,不依赖真实的标准输入。
#### Scenario: Mock 用户确认输入
- **WHEN** 测试需要模拟用户输入 "y" 或 "n"
- **THEN** `prompt.ConfirmWithReader` 函数接受 `io.Reader` 参数,测试时传入 `strings.NewReader("y\n")`
#### Scenario: 生产模式使用真实输入
- **WHEN** 生产代码调用 `prompt.Confirm`
- **THEN** 内部调用 `ConfirmWithReader(message, os.Stdin)` 读取真实用户输入
---
### Requirement: 测试必须使用真实文件系统
测试应使用真实的文件系统操作和 git 命令,而非 mock以确保行为与生产一致。
#### Scenario: 真实文件复制测试
- **WHEN** 测试文件复制功能
- **THEN** 在临时目录中创建真实文件,执行复制,验证结果
#### Scenario: 真实 git 操作测试
- **WHEN** 测试 git clone/pull 功能
- **THEN** 在临时目录中初始化真实的 git 仓库,执行 git 命令
---
### Requirement: 测试数据必须可复用
测试应提供标准的 fixture 数据和辅助函数,避免每个测试重复构建测试环境。
#### Scenario: Fixture 仓库
- **WHEN** 测试需要一个标准的 skills/commands 仓库
- **THEN** 从 `testdata/fixtures/test-repo/` 复制 fixture 并初始化为 git 仓库
#### Scenario: 测试辅助函数
- **WHEN** 测试需要设置隔离环境
- **THEN** 调用 `setupTestEnv(t)` 函数自动设置环境变量和临时目录
---
### Requirement: 测试覆盖必须全面
测试必须覆盖所有核心模块、关键路径和边界条件。
#### Scenario: 单元测试覆盖
- **WHEN** 实现任何核心函数config、adapter、repo、installer
- **THEN** 必须编写对应的单元测试,覆盖正常和异常情况
#### Scenario: 集成测试覆盖
- **WHEN** 实现跨模块功能(完整安装流程)
- **THEN** 必须编写集成测试,验证端到端行为
#### Scenario: 平台兼容性测试
- **WHEN** 支持多个平台Claude Code、OpenCode
- **THEN** 每个平台都必须有独立的兼容性测试
---
### Requirement: 测试脚本必须简化运行
必须提供自动化脚本,简化测试环境设置和测试执行。
#### Scenario: 自动化测试脚本
- **WHEN** 开发者运行 `./scripts/test.sh`
- **THEN** 脚本自动设置测试环境变量、运行所有测试、清理临时资源
#### Scenario: 沙盒测试环境
- **WHEN** 开发者运行 `./scripts/sandbox.sh`
- **THEN** 脚本创建隔离的沙盒环境,允许手动测试而不影响系统
---
### Requirement: CI/CD 集成必须无缝
测试必须能在 CI/CD 环境中稳定运行,不依赖本地环境配置。
#### Scenario: GitHub Actions 集成
- **WHEN** 在 CI 中运行测试
- **THEN** 通过环境变量设置测试路径,所有测试通过且自动清理
#### Scenario: 测试失败报告
- **WHEN** 测试失败
- **THEN** CI 系统捕获失败信息、日志和覆盖率报告

View File

@@ -0,0 +1,126 @@
## ADDED Requirements
### Requirement: 系统必须使用临时目录进行 staging
工具必须在系统临时目录中创建 staging 区域,组装完整的目标文件树后再移动到最终位置。
#### Scenario: 创建 staging 目录
- **WHEN** 开始安装事务
- **THEN** 系统在 `/tmp/``os.TempDir()` 创建唯一的临时目录(如 `skillmgr-xxxxx/`
#### Scenario: Staging 目录结构与目标一致
- **WHEN** 在 staging 中组装文件
- **THEN** staging 目录结构必须与最终目标目录结构完全一致
---
### Requirement: 系统必须先完整复制到 staging
工具必须将所有源文件完整复制到 staging 目录,应用平台适配规则。
#### Scenario: 复制所有文件到 staging
- **WHEN** 执行 Stage 阶段
- **THEN** 系统根据平台适配器返回的文件映射,将所有文件复制到 staging
#### Scenario: 复制失败回滚
- **WHEN** 复制过程中任何文件失败
- **THEN** 系统删除 staging 目录,报错终止,不影响目标目录
---
### Requirement: 系统必须验证 staging 完整性
工具必须在提交前验证 staging 目录中的文件完整性。
#### Scenario: 验证文件数量
- **WHEN** 所有文件复制到 staging
- **THEN** 系统验证 staging 中文件数量与预期映射表一致
---
### Requirement: 系统必须原子性提交 staging
工具必须在 staging 验证通过后,将整个 staging 目录移动到目标位置。
#### Scenario: 同文件系统移动
- **WHEN** staging 和目标在同一文件系统
- **THEN** 系统使用 `os.Rename()` 原子性移动
#### Scenario: 跨文件系统复制
- **WHEN** `os.Rename()` 失败(跨文件系统)
- **THEN** 系统 fallback 到递归复制 + 删除 staging
#### Scenario: 覆盖已存在目录
- **WHEN** 目标目录已存在(用户已确认覆盖)
- **THEN** 系统先删除目标目录,再移动 staging
---
### Requirement: 系统必须在失败时自动回滚
工具必须在任何阶段失败时,自动清理 staging 目录,不留垃圾文件。
#### Scenario: Stage 阶段失败
- **WHEN** 文件复制到 staging 失败
- **THEN** 系统删除 staging 目录,不修改目标
#### Scenario: Commit 阶段失败
- **WHEN** 移动 staging 到目标失败
- **THEN** 系统删除 staging 目录,目标目录保持原状(或已删除的状态)
#### Scenario: defer 确保清理
- **WHEN** 事务对象被销毁
- **THEN** 系统使用 defer 确保 staging 目录被清理
---
### Requirement: 系统必须提供事务接口
工具必须提供清晰的事务接口,包含 Stage、Commit、Rollback 方法。
#### Scenario: 创建事务对象
- **WHEN** 开始安装流程
- **THEN** 系统创建 Transaction 对象,包含 stagingDir、targetDir、fileMap 字段
#### Scenario: 调用 Stage 方法
- **WHEN** 调用 `transaction.Stage()`
- **THEN** 系统执行文件复制到 staging
#### Scenario: 调用 Commit 方法
- **WHEN** 调用 `transaction.Commit()`
- **THEN** 系统将 staging 移动到目标
#### Scenario: 调用 Rollback 方法
- **WHEN** 调用 `transaction.Rollback()`
- **THEN** 系统删除 staging 目录
---
### Requirement: 系统必须确保目标目录的父目录存在
工具必须在提交前确保目标目录的父目录已创建。
#### Scenario: 创建父目录
- **WHEN** 提交 staging 到目标
- **THEN** 系统先创建目标目录的父目录(如 `~/.claude/skills/`
#### Scenario: 父目录创建失败
- **WHEN** 父目录创建失败(权限不足等)
- **THEN** 系统报错,回滚 staging