feat(skill): 新增项目规范与初始化 Skill

This commit is contained in:
zhiye.sun
2026-08-25 14:52:43 +08:00
parent ac189b8395
commit dbc2f65154
40 changed files with 587 additions and 19 deletions
+7 -6
View File
@@ -58,8 +58,9 @@
3. `git/commit-msg`:只读 Git 状态分析样本,已完成。
4. `git/branch`:修改仓库状态和二次授权边界样本,已完成。
5. `knowledge/handoff`:模板化文档与项目上下文样本,已完成。
6. `skill/guidance`:大型参考资料、索引和渐进式加载样本。
7. `skill/migrate`:脚本、检查、同步和状态追踪组成的复合工作流样本。
6. `skill/guidance`:大型参考资料、索引和渐进式加载样本,已完成;只检索项目资料和基于公开一级资料独立重建的中性公共基线。
7. `knowledge/init`:成熟项目与空项目双模式初始化、参考项目提炼和共享/本地信息边界样本,已完成。
8. `skill/migrate`:脚本、检查、同步和状态追踪组成的复合工作流样本。
完成门槛:每种样本均通过对应验证,并形成可复用的命名、目录、独立实现、测试、扫描和状态同步规则。出现未覆盖的新结构或权限类型时,应补充样本,不直接扩批。
@@ -102,7 +103,7 @@
2. `distill-task`
3. `maintain-lessons`
4. `summarize-worklog`
5. `init-agents`
5. `init`
来源中与经验初始化、提升和回扫相关的多个能力统一合并为 `maintain-lessons`,通过模式区分具体工作。
@@ -138,8 +139,8 @@ plan-change
1. `dev/select-component`
2. `dev/design-style`
3. `dev/design-form`
4. `skill/retrieve-guidance`
5. `skill/maintain-guidance`
4. `skill/guidance`(特殊样本已完成)
5. `skill/guidance-edit`
这里只实现读取和维护“当前项目自身规范”的机制,不随 CraftKit 提供任何来源项目规范。
@@ -186,7 +187,7 @@ plan-change
| 多套前端实现 | `implement-frontend` |
| 多套 Word 转 Markdown | `docx-to-md` |
| 经验初始化、提升、回扫 | `maintain-lessons` |
| 规范检索和索引维护 | `retrieve-guidance`、`maintain-guidance` |
| 规范检索和索引维护 | `guidance`、`guidance-edit` |
目标 Skill 总量不设硬指标,预期控制在约 30 个,避免细碎能力和重复触发。
+10 -3
View File
@@ -128,7 +128,10 @@
"source-b:eb730c56bc7a4a15": {
"sourcePathHash": "eb730c56bc7a4a158ddec74c7497a10fdea2d0b628783b968e3ee9ee4572b15c",
"sourceSha256": "89aa46526fa7531958df46be4b162a9f7b9ea597e3e9121991cf25e9f25158f5",
"status": "pending"
"status": "migrated",
"target": "plugins/skill/skills/guidance",
"targetVersion": "0.1.0",
"reviewedAt": "2026-08-25"
},
"source-b:422174b0c00bbd65": {
"sourcePathHash": "422174b0c00bbd657f4c08415d4a722584556cfa5f3edc997b11e8ab0ef8656a",
@@ -250,7 +253,10 @@
"source-b:0b917cc63232dff3": {
"sourcePathHash": "0b917cc63232dff38c375d3bec3fabe57390201c34c3ce96f7885eb23bca91d7",
"sourceSha256": "5ecfa8040f5d71f347cfcfb89040a5cbfdb96f71867fb11b750b78d4aa17d66a",
"status": "pending"
"status": "migrated",
"target": "plugins/knowledge/skills/init",
"targetVersion": "0.1.0",
"reviewedAt": "2026-08-25"
},
"source-b:905e74ea51281da1": {
"sourcePathHash": "905e74ea51281da179c1eb31677af71569a95139a74fb139d39dadd52db2ce62",
@@ -328,7 +334,8 @@
"source-b:31dec2fa162b06d3": {
"sourcePathHash": "31dec2fa162b06d379aa676d426d2de01c3b082061ff15adb7a8c721cd5635af",
"sourceSha256": "a146d79ccfec7b1f9275cda8e6cf3ab1190430d0c3bc11886a722ce1d6fabc90",
"status": "pending"
"status": "specified",
"target": "plugins/skill/skills/guidance-edit"
},
"source-b:988b200efd0b8be0": {
"sourcePathHash": "988b200efd0b8be024060e0785da2f864bf7ee30d7c7b434fde7ab1e4cdcc9d8",
+92
View File
@@ -0,0 +1,92 @@
import json
import unittest
from pathlib import Path
ROOT = Path(__file__).parents[2]
GUIDANCE = ROOT / "plugins" / "skill" / "skills" / "guidance"
INIT = ROOT / "plugins" / "knowledge" / "skills" / "init"
class GuidanceInitTest(unittest.TestCase):
"""验证规范检索和项目初始化之间的职责边界。"""
def test_guidance_is_read_only_and_uses_progressive_sources(self) -> None:
"""检索 Skill 应声明项目优先、渐进读取且不隐式初始化。"""
content = (GUIDANCE / "SKILL.md").read_text(encoding="utf-8")
self.assertIn("以只读方式", content)
self.assertIn("不得先递归加载整个知识库", content)
self.assertIn("不得在检索过程中隐式初始化", content)
self.assertIn(".craftkit/project.json", content)
def test_public_baseline_routes_frontend_and_backend(self) -> None:
"""公共基线应提供前后端入口,并让索引引用实际规则文件。"""
root = GUIDANCE / "references" / "guidance"
index = (root / "index.md").read_text(encoding="utf-8")
self.assertIn("frontend/index.md", index)
self.assertIn("backend/index.md", index)
self.assertEqual(6, len(list((root / "frontend").glob("*.md"))))
self.assertEqual(6, len(list((root / "backend").glob("*.md"))))
sources = (root / "sources.md").read_text(encoding="utf-8")
for authority in ("RFC 9110", "WCAG 2.2", "OWASP", "MDN Fetch API"):
self.assertIn(authority, sources)
def test_framework_profiles_are_selected_by_project_version(self) -> None:
"""普通任务只能使用当前 profile,且不存在的 profile 不得被猜测。"""
routing = (GUIDANCE / "references" / "profile-routing.md").read_text(
encoding="utf-8"
)
self.assertIn("普通开发任务只加载当前 profile", routing)
self.assertIn("升级、迁移或版本比较", routing)
self.assertIn("不默认最新版本", routing)
self.assertIn("不创建空目录", routing)
init = (INIT / "SKILL.md").read_text(encoding="utf-8")
config = (INIT / "references" / "project-config.md").read_text(
encoding="utf-8"
)
self.assertIn("精确版本、公共 profile", init)
for field in ('"name"', '"version"', '"profile"'):
self.assertIn(field, config)
def test_init_supports_existing_and_new_projects(self) -> None:
"""初始化 Skill 应同时包含成熟项目与空项目流程。"""
content = (INIT / "SKILL.md").read_text(encoding="utf-8")
self.assertIn("成熟项目", content)
self.assertIn("空项目", content)
self.assertIn("参考项目", content)
self.assertTrue((INIT / "references" / "existing.md").is_file())
self.assertTrue((INIT / "references" / "new.md").is_file())
def test_project_template_has_safe_shared_fields(self) -> None:
"""项目模板应包含检索入口,且不得预置内部标识或机器路径。"""
path = INIT / "assets" / "project.json"
payload = json.loads(path.read_text(encoding="utf-8"))
self.assertEqual(1, payload["schemaVersion"])
self.assertIn(payload["initialization"]["mode"], {"existing", "new"})
self.assertEqual([], payload["dependencies"]["internal"])
self.assertEqual(
".craftkit/standards/index.md",
payload["guidance"]["standardsIndex"],
)
serialized = json.dumps(payload, ensure_ascii=False)
self.assertNotIn(":\\", serialized)
def test_local_directories_are_the_only_nested_ignores(self) -> None:
"""初始化模板只排除本地状态和缓存,不得排除共享资料。"""
rules = (INIT / "assets" / "craftkit.gitignore").read_text(
encoding="utf-8"
)
active = [line for line in rules.splitlines() if line and not line.startswith("#")]
self.assertEqual(["/local/", "/cache/"], active)
if __name__ == "__main__":
unittest.main()