feat: 添加 skill 打包脚本 build.py
新增 build.py 实现 skill 自动化打包: - 一键完成 skill/SKILL.md 和 scripts/ 打包到 build/ - 时间戳版本号格式 YYYYMMDD_HHMMSS - 仅复制 .py 文件,避免创建空目录 - 添加 skill-packaging spec 文档
This commit is contained in:
134
build.py
Normal file
134
build.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Skill 打包构建脚本
|
||||
将 skill/SKILL.md 和 scripts/ 目录打包到 build/ 目录
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def generate_timestamp() -> str:
|
||||
"""
|
||||
生成 YYYYMMDD_HHMMSS 格式的时间戳
|
||||
|
||||
Returns:
|
||||
时间戳字符串
|
||||
"""
|
||||
return datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
|
||||
def clean_and_create_build_dir(build_dir: str) -> None:
|
||||
"""
|
||||
删除旧 build 目录并创建新的空目录
|
||||
|
||||
Args:
|
||||
build_dir: 构建目录路径
|
||||
"""
|
||||
if os.path.exists(build_dir):
|
||||
print(f"清理旧构建目录: {build_dir}")
|
||||
shutil.rmtree(build_dir)
|
||||
os.makedirs(build_dir)
|
||||
print(f"创建构建目录: {build_dir}")
|
||||
|
||||
|
||||
def copy_skill_md(source_path: str, target_dir: str) -> None:
|
||||
"""
|
||||
复制 skill/SKILL.md 到 build/SKILL.md
|
||||
|
||||
Args:
|
||||
source_path: 源 SKILL.md 路径
|
||||
target_dir: 目标目录
|
||||
"""
|
||||
target_path = os.path.join(target_dir, "SKILL.md")
|
||||
shutil.copy2(source_path, target_path)
|
||||
print(f"复制: {source_path} -> {target_path}")
|
||||
|
||||
|
||||
def copy_scripts_dir(source_dir: str, target_dir: str) -> int:
|
||||
"""
|
||||
递归复制 scripts/ 目录,仅复制 .py 文件
|
||||
|
||||
Args:
|
||||
source_dir: 源目录
|
||||
target_dir: 目标目录
|
||||
|
||||
Returns:
|
||||
复制的文件数量
|
||||
"""
|
||||
file_count = 0
|
||||
|
||||
for root, dirs, files in os.walk(source_dir):
|
||||
# 计算相对路径
|
||||
rel_path = os.path.relpath(root, source_dir)
|
||||
# 处理相对路径为 "." 的情况
|
||||
if rel_path == ".":
|
||||
target_root = target_dir
|
||||
else:
|
||||
target_root = os.path.join(target_dir, rel_path)
|
||||
|
||||
# 检查此目录下是否有 .py 文件需要复制
|
||||
has_py_files = any(file.endswith(".py") for file in files)
|
||||
|
||||
# 只有当有 .py 文件需要复制时才创建目录并复制
|
||||
if has_py_files:
|
||||
if not os.path.exists(target_root):
|
||||
os.makedirs(target_root)
|
||||
|
||||
# 只复制 .py 文件
|
||||
for file in files:
|
||||
if file.endswith(".py"):
|
||||
source_file = os.path.join(root, file)
|
||||
target_file = os.path.join(target_root, file)
|
||||
shutil.copy2(source_file, target_file)
|
||||
file_count += 1
|
||||
print(f"复制: {source_file} -> {target_file}")
|
||||
|
||||
return file_count
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
主函数:执行完整的打包流程
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("Skill 打包构建")
|
||||
print("=" * 60)
|
||||
|
||||
# 路径配置
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
skill_md_path = os.path.join(project_root, "skill", "SKILL.md")
|
||||
scripts_source_dir = os.path.join(project_root, "scripts")
|
||||
build_dir = os.path.join(project_root, "build")
|
||||
scripts_target_dir = os.path.join(build_dir, "scripts")
|
||||
|
||||
# 生成时间戳
|
||||
version = generate_timestamp()
|
||||
print(f"版本号: {version}")
|
||||
print()
|
||||
|
||||
# 清理并创建 build 目录
|
||||
clean_and_create_build_dir(build_dir)
|
||||
print()
|
||||
|
||||
# 复制 SKILL.md
|
||||
copy_skill_md(skill_md_path, build_dir)
|
||||
print()
|
||||
|
||||
# 复制 scripts 目录
|
||||
print("复制 scripts/ 目录(仅 .py 文件):")
|
||||
file_count = copy_scripts_dir(scripts_source_dir, scripts_target_dir)
|
||||
print()
|
||||
|
||||
# 完成信息
|
||||
print("=" * 60)
|
||||
print("构建完成!")
|
||||
print(f"版本号: {version}")
|
||||
print(f"复制文件数: {file_count}")
|
||||
print(f"输出目录: {build_dir}")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
54
openspec/specs/skill-packaging/spec.md
Normal file
54
openspec/specs/skill-packaging/spec.md
Normal file
@@ -0,0 +1,54 @@
|
||||
## Purpose
|
||||
|
||||
提供自动化的 skill 打包能力,将 skill/SKILL.md 和 scripts/ 目录打包到 build/ 目录,便于 skill 分发。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: build.py 一键打包
|
||||
系统 SHALL 提供 build.py 脚本,运行后完成 skill 的完整打包流程。
|
||||
|
||||
#### Scenario: 运行 build.py 成功
|
||||
- **WHEN** 用户执行 `uv run python build.py`
|
||||
- **THEN** 脚本完成所有打包步骤并输出成功信息
|
||||
|
||||
### Requirement: 构建目录清理重建
|
||||
系统 SHALL 在每次构建前删除整个 build 目录,然后重建空的 build 目录。
|
||||
|
||||
#### Scenario: 删除并重建 build 目录
|
||||
- **WHEN** 构建开始
|
||||
- **THEN** 脚本删除整个 build 目录(如有),然后创建新的空 build 目录
|
||||
|
||||
### Requirement: SKILL.md 复制
|
||||
系统 SHALL 将 skill/SKILL.md 直接复制到 build/SKILL.md,不保留 skill 这一级目录。
|
||||
|
||||
#### Scenario: SKILL.md 成功复制
|
||||
- **WHEN** 构建执行
|
||||
- **THEN** build/SKILL.md 文件存在且内容与 skill/SKILL.md 一致
|
||||
|
||||
### Requirement: scripts 目录复制
|
||||
系统 SHALL 将 scripts/ 目录完整复制到 build/scripts/,保持目录结构。
|
||||
|
||||
#### Scenario: scripts 目录结构保留
|
||||
- **WHEN** 构建执行
|
||||
- **THEN** build/scripts/ 下的子目录结构与原 scripts/ 一致
|
||||
|
||||
### Requirement: 仅复制 Python 文件
|
||||
系统 SHALL 只复制 .py 扩展名的文件,其他文件类型自然被过滤。
|
||||
|
||||
#### Scenario: 只保留 py 文件
|
||||
- **WHEN** 原目录包含多种文件类型
|
||||
- **THEN** build/scripts/ 中只存在 .py 文件
|
||||
|
||||
### Requirement: 时间戳版本号
|
||||
系统 SHALL 生成 YYYYMMDD_HHMMSS 格式的时间戳作为构建版本标识。
|
||||
|
||||
#### Scenario: 时间戳格式正确
|
||||
- **WHEN** 构建在 2025年3月9日 14点30分22秒执行
|
||||
- **THEN** 生成的版本号为 20250309_143022
|
||||
|
||||
### Requirement: 输出构建信息
|
||||
系统 SHALL 在构建完成后打印版本号和构建结果信息。
|
||||
|
||||
#### Scenario: 显示构建信息
|
||||
- **WHEN** 构建成功完成
|
||||
- **THEN** 控制台输出版本号和构建文件清单
|
||||
Reference in New Issue
Block a user