feat(knowledge): 新增分层项目交接 Skill
This commit is contained in:
@@ -57,7 +57,7 @@
|
||||
2. `doc/docx-to-md`:多来源合并、脚本、依赖和生成物样本,已完成。
|
||||
3. `git/commit-msg`:只读 Git 状态分析样本,已完成。
|
||||
4. `git/branch`:修改仓库状态和二次授权边界样本,已完成。
|
||||
5. `knowledge/handoff`:模板化文档与项目上下文样本。
|
||||
5. `knowledge/handoff`:模板化文档与项目上下文样本,已完成。
|
||||
6. `skill/guidance`:大型参考资料、索引和渐进式加载样本。
|
||||
7. `skill/migrate`:脚本、检查、同步和状态追踪组成的复合工作流样本。
|
||||
|
||||
@@ -228,5 +228,6 @@ plan-change
|
||||
- [x] 迁移并验证脚本型特殊样本 `doc/docx-to-md`。
|
||||
- [x] 迁移并验证只读 Git 特殊样本 `git/commit-msg`。
|
||||
- [x] 迁移并验证有副作用 Git 特殊样本 `git/branch`。
|
||||
- [x] 迁移并验证模板化交接特殊样本 `knowledge/handoff`。
|
||||
- [ ] 完成其余特殊样本并总结批量迁移规则。
|
||||
- [ ] 按插件和风险类型推进同质批量迁移。
|
||||
|
||||
@@ -280,7 +280,10 @@
|
||||
"source-b:f58c6cd52bc983e8": {
|
||||
"sourcePathHash": "f58c6cd52bc983e87d265308ade0da8d89bd74d5d4f1e96fc463ef299a9fe94a",
|
||||
"sourceSha256": "98392eb0fe65dab6877495e6863a6722cd2777f5767dfd95b3a829ed7798a5e7",
|
||||
"status": "pending"
|
||||
"status": "migrated",
|
||||
"target": "plugins/knowledge/skills/handoff",
|
||||
"targetVersion": "0.1.0",
|
||||
"reviewedAt": "2026-08-25"
|
||||
},
|
||||
"source-b:258ee10299925494": {
|
||||
"sourcePathHash": "258ee1029992549420c8465c8de2d63c1bfaf9334b812d6b79a07a9823b49733",
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class LocalStateTest(unittest.TestCase):
|
||||
"""验证 `.craftkit/` 能同时承载共享资料和本地状态。"""
|
||||
|
||||
def run_git(self, root: Path, *args: str) -> subprocess.CompletedProcess[str]:
|
||||
"""在隔离仓库执行 Git,并保留输出供断言使用。"""
|
||||
|
||||
return subprocess.run(
|
||||
["git", "-C", str(root), *args],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
def test_nested_gitignore_separates_shared_and_local_content(self) -> None:
|
||||
"""共享资料应可提交,本地目录和缓存应由嵌套规则排除。"""
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
root = Path(temp)
|
||||
initialized = self.run_git(root, "init")
|
||||
self.assertEqual(initialized.returncode, 0, initialized.stderr)
|
||||
|
||||
craftkit = root / ".craftkit"
|
||||
craftkit.mkdir()
|
||||
(craftkit / ".gitignore").write_text(
|
||||
"# Local CraftKit data\n/local/\n/cache/\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(craftkit / "README.md").write_text("# 项目资料\n", encoding="utf-8")
|
||||
shared = craftkit / "standards" / "coding" / "rules.md"
|
||||
shared.parent.mkdir(parents=True)
|
||||
shared.write_text("# 编码规范\n", encoding="utf-8")
|
||||
local = craftkit / "local" / "handoff" / "current.md"
|
||||
local.parent.mkdir(parents=True)
|
||||
local.write_text("# 本地交接\n", encoding="utf-8")
|
||||
cache = craftkit / "cache" / "result.json"
|
||||
cache.parent.mkdir(parents=True)
|
||||
cache.write_text("{}\n", encoding="utf-8")
|
||||
|
||||
ignored = self.run_git(
|
||||
root,
|
||||
"check-ignore",
|
||||
"--no-index",
|
||||
"-v",
|
||||
".craftkit/local/handoff/current.md",
|
||||
)
|
||||
self.assertEqual(ignored.returncode, 0, ignored.stderr)
|
||||
self.assertIn(".craftkit/.gitignore", ignored.stdout.replace("\\", "/"))
|
||||
|
||||
cache_ignored = self.run_git(
|
||||
root,
|
||||
"check-ignore",
|
||||
"--no-index",
|
||||
".craftkit/cache/result.json",
|
||||
)
|
||||
self.assertEqual(cache_ignored.returncode, 0, cache_ignored.stderr)
|
||||
|
||||
status = self.run_git(root, "status", "--short", "--untracked-files=all")
|
||||
self.assertEqual(status.returncode, 0, status.stderr)
|
||||
normalized = status.stdout.replace("\\", "/")
|
||||
self.assertIn(".craftkit/.gitignore", normalized)
|
||||
self.assertIn(".craftkit/README.md", normalized)
|
||||
self.assertIn(".craftkit/standards/coding/rules.md", normalized)
|
||||
self.assertNotIn(".craftkit/local", normalized)
|
||||
self.assertNotIn(".craftkit/cache", normalized)
|
||||
self.assertFalse((root / ".gitignore").exists())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user