feat(skills): add uncle-bob-craft third-party skill

This commit is contained in:
csh 2026-05-31 13:43:49 +08:00
parent 7db5e4a697
commit 7656ee2907
8 changed files with 146 additions and 5 deletions

View File

@ -69,6 +69,16 @@
"source_list": "skills/thirdparty/.sources/codebase-migrate.list", "source_list": "skills/thirdparty/.sources/codebase-migrate.list",
"skills_subdir": ".", "skills_subdir": ".",
"include_skill_dirs": ["codebase-migrate"] "include_skill_dirs": ["codebase-migrate"]
},
{
"id": "uncle-bob-craft",
"upstream_repo": "https://github.com/sickn33/antigravity-awesome-skills.git",
"upstream_ref": "main",
"snapshot_dir": "antigravity-awesome-skills",
"sync_mode": "copy_skill_dirs",
"source_list": "skills/thirdparty/.sources/uncle-bob-craft.list",
"skills_subdir": "skills",
"include_skill_dirs": ["uncle-bob-craft"]
} }
] ]
} }

View File

@ -186,11 +186,15 @@ python <deploy_root>/scripts/playbook.py -config playbook.toml
- `superpowers.list` - `superpowers.list`
- `ui-ux-pro-max.list` - `ui-ux-pro-max.list`
- `andrej-karpathy-skills.list` - `andrej-karpathy-skills.list`
- `brooks-lint.list`
- `codebase-recon.list`
- `codebase-migrate.list`
- `uncle-bob-craft.list`
部署链路: 部署链路:
- `thirdparty/skill` 分支保存上游快照 `andrej-karpathy-skills/` - `thirdparty/skill` 分支保存上游快照,例如 `andrej-karpathy-skills/`、`awesome-codex-skills/`、`antigravity-awesome-skills/`
- 自动同步后,`karpathy-guidelines/` 会落到仓库内 `skills/thirdparty/karpathy-guidelines/` - 自动同步后,选中的下游 skill 会落到仓库内 `skills/thirdparty/<skill-name>/`
- 运行 `[install_skills]` 时,再复制到目标平台 skills 目录(`~/.agents/skills/` 或 `~/.claude/skills/` - 运行 `[install_skills]` 时,再复制到目标平台 skills 目录(`~/.agents/skills/` 或 `~/.claude/skills/`
- 该 skill 本身不依赖 Playbook 文档路径重写,也不需要像 `ui-ux-pro-max` 那样额外渲染 - 该 skill 本身不依赖 Playbook 文档路径重写,也不需要像 `ui-ux-pro-max` 那样额外渲染

View File

@ -79,3 +79,22 @@
| Skill | 来源 | 作用 | | Skill | 来源 | 作用 |
| --- | --- | --- | | --- | --- | --- |
| `codebase-migrate` | `awesome-codex-skills` | 大代码库迁移、多文件 refactor、分批变更与 CI 验证工作流 | | `codebase-migrate` | `awesome-codex-skills` | 大代码库迁移、多文件 refactor、分批变更与 CI 验证工作流 |
| `uncle-bob-craft` | `antigravity-awesome-skills` | Clean Architecture、SOLID、设计模式误用和代码工匠实践审查 |
#### `uncle-bob-craft` 定位
`uncle-bob-craft` 是原则型补强 skill不替代现有 `brooks-*`
`codebase-*` 主流程。它适合在问题明确聚焦 Clean Architecture、SOLID、
职责拆分、依赖方向、设计模式是否滥用、代码工匠实践时使用。
| 对比项 | 分工 |
| --- | --- |
| `codebase-recon` | 负责重构前侦察、热点分析和影响面判断;`uncle-bob-craft` 不负责代码库级侦察 |
| `brooks-audit` | 负责架构边界、模块职责和长期维护性审查;`uncle-bob-craft` 只作为 Clean Architecture / SOLID 视角补强 |
| `codebase-migrate` | 负责大规模迁移、多文件 refactor 和 CI 验证节奏;`uncle-bob-craft` 不负责迁移编排 |
| `brooks-review` | 负责 PR / diff 级代码审查;`uncle-bob-craft` 仅在审查重点是 SOLID、职责拆分或设计模式误用时配合使用 |
| `brooks-test` | 负责测试质量、断言边界和测试脆弱性审查;`uncle-bob-craft` 不负责测试质量专项审查 |
推荐触发方式:有明确 Clean Architecture、SOLID、Uncle Bob、职责拆分、
依赖方向或设计模式误用问题时使用;普通 PR 审查仍优先 `brooks-review`
架构级审查仍优先 `brooks-audit`

View File

@ -57,3 +57,20 @@ skills:
- CI-verified migration workflows - CI-verified migration workflows
notes: notes:
- Sourced from awesome-codex-skills. - Sourced from awesome-codex-skills.
- id: uncle-bob-craft
sync: enabled
upstream_repo: https://github.com/sickn33/antigravity-awesome-skills
upstream_ref: main
upstream_path: skills/uncle-bob-craft
upstream_layout: single_skill_from_suite
selected_for:
- Clean Architecture review
- SOLID review
- design-pattern misuse checks
- architecture-boundary refactoring
- code craftsmanship review
playbook_fit: architecture and code-quality craft review support
notes:
- Upstream skill includes references for Clean Architecture, Clean Coder, Clean Agile, and design-pattern discipline.
- Registered as a single selected skill from a larger community skill suite.

View File

@ -1,3 +1,5 @@
import json
import shutil
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
@ -380,6 +382,34 @@ skills = ["brainstorming"]
) )
self.assertEqual(clone_mirror.returncode, 0, msg=clone_mirror.stderr) self.assertEqual(clone_mirror.returncode, 0, msg=clone_mirror.stderr)
thirdparty_ref = subprocess.run(
[
"git",
f"--git-dir={mirror}",
"rev-parse",
"refs/remotes/origin/thirdparty/skill",
],
capture_output=True,
text=True,
)
self.assertEqual(thirdparty_ref.returncode, 0, msg=thirdparty_ref.stderr)
expose_thirdparty_branch = subprocess.run(
[
"git",
f"--git-dir={mirror}",
"update-ref",
"refs/heads/thirdparty/skill",
thirdparty_ref.stdout.strip(),
],
capture_output=True,
text=True,
)
self.assertEqual(
expose_thirdparty_branch.returncode,
0,
msg=expose_thirdparty_branch.stderr,
)
clone_repo = subprocess.run( clone_repo = subprocess.run(
["git", "clone", str(mirror), str(repo)], ["git", "clone", str(mirror), str(repo)],
capture_output=True, capture_output=True,
@ -396,10 +426,19 @@ skills = ["brainstorming"]
manifest_src = ROOT / ".gitea" / "ci" / "thirdparty_skills.json" manifest_src = ROOT / ".gitea" / "ci" / "thirdparty_skills.json"
manifest_dst = repo / ".gitea" / "ci" / "thirdparty_skills.json" manifest_dst = repo / ".gitea" / "ci" / "thirdparty_skills.json"
manifest_dst.write_text(manifest_src.read_text(encoding="utf-8"), encoding="utf-8") manifest_data = json.loads(manifest_src.read_text(encoding="utf-8"))
manifest_data["sources"] = [
entry
for entry in manifest_data["sources"]
if entry["id"] == "andrej-karpathy-skills"
]
manifest_dst.write_text(
json.dumps(manifest_data, indent=2) + "\n",
encoding="utf-8",
)
sync_src = ROOT / ".gitea" / "ci" / "sync_thirdparty_skills.sh" sync_src = ROOT / ".gitea" / "ci" / "sync_thirdparty_skills.sh"
sync_dst = repo / ".gitea" / "ci" / "sync_thirdparty_skills.sh" sync_dst = repo / ".gitea" / "ci" / "sync_thirdparty_skills.sh"
sync_dst.write_text(sync_src.read_text(encoding="utf-8"), encoding="utf-8") shutil.copy2(sync_src, sync_dst)
sync_result = subprocess.run( sync_result = subprocess.run(
["bash", ".gitea/ci/sync_thirdparty_skills.sh"], ["bash", ".gitea/ci/sync_thirdparty_skills.sh"],

View File

@ -38,6 +38,7 @@ class SkillsReadmeTests(unittest.TestCase):
self.assertIn("codebase-recon", text) self.assertIn("codebase-recon", text)
self.assertIn("pathfinding", text) self.assertIn("pathfinding", text)
self.assertIn("codebase-migrate", text) self.assertIn("codebase-migrate", text)
self.assertIn("uncle-bob-craft", text)
self.assertIn("已登记待同步", text) self.assertIn("已登记待同步", text)

View File

@ -32,6 +32,11 @@ class ThirdpartySkillCurationTests(unittest.TestCase):
self.assertIn("upstream_path: codebase-migrate", text) self.assertIn("upstream_path: codebase-migrate", text)
self.assertIn("large codebase migrations", text) self.assertIn("large codebase migrations", text)
self.assertIn("id: uncle-bob-craft", text)
self.assertIn("upstream_repo: https://github.com/sickn33/antigravity-awesome-skills", text)
self.assertIn("upstream_path: skills/uncle-bob-craft", text)
self.assertIn("design-pattern misuse checks", text)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -56,6 +56,7 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
"brooks-lint", "brooks-lint",
"codebase-recon", "codebase-recon",
"codebase-migrate", "codebase-migrate",
"uncle-bob-craft",
], ],
) )
@ -115,6 +116,22 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
) )
self.assertEqual(migrate["include_skill_dirs"], ["codebase-migrate"]) self.assertEqual(migrate["include_skill_dirs"], ["codebase-migrate"])
craft = next(
item for item in data["sources"] if item["id"] == "uncle-bob-craft"
)
self.assertEqual(
craft["upstream_repo"],
"https://github.com/sickn33/antigravity-awesome-skills.git",
)
self.assertEqual(craft["upstream_ref"], "main")
self.assertEqual(craft["sync_mode"], "copy_skill_dirs")
self.assertEqual(craft["snapshot_dir"], "antigravity-awesome-skills")
self.assertEqual(craft["skills_subdir"], "skills")
self.assertEqual(
craft["source_list"], "skills/thirdparty/.sources/uncle-bob-craft.list"
)
self.assertEqual(craft["include_skill_dirs"], ["uncle-bob-craft"])
def test_superpowers_manifest_prunes_non_superpowers_paths(self): def test_superpowers_manifest_prunes_non_superpowers_paths(self):
data = load_manifest() data = load_manifest()
superpowers = next(item for item in data["sources"] if item["id"] == "superpowers") superpowers = next(item for item in data["sources"] if item["id"] == "superpowers")
@ -209,6 +226,26 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
clone_mirror = run_command("git", "clone", "--mirror", str(ROOT), str(mirror)) clone_mirror = run_command("git", "clone", "--mirror", str(ROOT), str(mirror))
self.assertEqual(clone_mirror.returncode, 0, msg=clone_mirror.stderr) self.assertEqual(clone_mirror.returncode, 0, msg=clone_mirror.stderr)
thirdparty_ref = run_command(
"git",
f"--git-dir={mirror}",
"rev-parse",
"refs/remotes/origin/thirdparty/skill",
)
self.assertEqual(thirdparty_ref.returncode, 0, msg=thirdparty_ref.stderr)
expose_thirdparty_branch = run_command(
"git",
f"--git-dir={mirror}",
"update-ref",
"refs/heads/thirdparty/skill",
thirdparty_ref.stdout.strip(),
)
self.assertEqual(
expose_thirdparty_branch.returncode,
0,
msg=expose_thirdparty_branch.stderr,
)
clone_work = run_command("git", "clone", str(mirror), str(work)) clone_work = run_command("git", "clone", str(mirror), str(work))
self.assertEqual(clone_work.returncode, 0, msg=clone_work.stderr) self.assertEqual(clone_work.returncode, 0, msg=clone_work.stderr)
@ -217,7 +254,16 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
) )
self.assertEqual(set_remote.returncode, 0, msg=set_remote.stderr) self.assertEqual(set_remote.returncode, 0, msg=set_remote.stderr)
shutil.copy2(MANIFEST, work / ".gitea" / "ci" / "thirdparty_skills.json") manifest_data = load_manifest()
manifest_data["sources"] = [
entry
for entry in manifest_data["sources"]
if entry["id"] == "andrej-karpathy-skills"
]
(work / ".gitea" / "ci" / "thirdparty_skills.json").write_text(
json.dumps(manifest_data, indent=2) + "\n",
encoding="utf-8",
)
shutil.copy2(SYNC_SCRIPT, work / ".gitea" / "ci" / "sync_thirdparty_skills.sh") shutil.copy2(SYNC_SCRIPT, work / ".gitea" / "ci" / "sync_thirdparty_skills.sh")
sync_result = run_command("bash", ".gitea/ci/sync_thirdparty_skills.sh", cwd=work) sync_result = run_command("bash", ".gitea/ci/sync_thirdparty_skills.sh", cwd=work)