from __future__ import annotations import os import subprocess import sys import tempfile import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] class SkillInitTests(unittest.TestCase): def setUp(self) -> None: self.temp_dir = tempfile.TemporaryDirectory() self.home = Path(self.temp_dir.name) self.skills_home = self.home / ".skills" skill = self.skills_home / "skills" / "ack" (skill / "templates").mkdir(parents=True) (skill / "scripts").mkdir() (skill / "SKILL.md").write_text("---\nname: ack\n---\n", encoding="utf-8") (skill / "VERSION").write_text("1.2.3\n", encoding="utf-8") (skill / "templates" / "project.template.md").write_text( "# \nversion=\npath=\n", encoding="utf-8", ) (skill / "templates" / "tasks.template.yaml").write_text( 'updatedAt: ""\n' 'ackVersion: "<接入时的 ack skill 版本>"\n' 'project:\n' ' name: ""\n' ' repoPath: ""\n' ' devWorktree: ""\n', encoding="utf-8", ) def tearDown(self) -> None: self.temp_dir.cleanup() def run_skiff(self, *args: str) -> subprocess.CompletedProcess[str]: env = os.environ.copy() env["HOME"] = str(self.home) env["PYTHONPATH"] = str(REPO_ROOT) return subprocess.run( [sys.executable, "-m", "skiff", *args], cwd=REPO_ROOT, env=env, text=True, capture_output=True, check=False, ) def test_init_creates_only_rendered_project_files(self) -> None: project = self.home / "sample-app" project.mkdir() result = self.run_skiff("init", "ack", "--project", str(project)) self.assertEqual(result.returncode, 0, result.stderr) target = project / "docs" / "ack" self.assertFalse((target / "kit").exists()) self.assertFalse((target / "framework").exists()) project_content = (target / "project.md").read_text(encoding="utf-8") tasks_content = (target / "tasks.yaml").read_text(encoding="utf-8") self.assertIn("# sample-app", project_content) self.assertIn("version=1.2.3", project_content) self.assertIn(f'repoPath: "{project}"', tasks_content) self.assertNotIn("", tasks_content) def test_init_refuses_to_overwrite_existing_files(self) -> None: project = self.home / "existing-app" target = project / "docs" / "ack" target.mkdir(parents=True) existing = target / "project.md" existing.write_text("keep me", encoding="utf-8") result = self.run_skiff("init", "ack", "--project", str(project)) self.assertNotEqual(result.returncode, 0) self.assertIn("拒绝覆盖已有路径", result.stderr) self.assertEqual(existing.read_text(encoding="utf-8"), "keep me") self.assertFalse((target / "tasks.yaml").exists()) def test_init_rejects_missing_project_directory(self) -> None: project = self.home / "missing-app" result = self.run_skiff("init", "ack", "--project", str(project)) self.assertNotEqual(result.returncode, 0) self.assertIn("项目目录不存在", result.stderr) self.assertFalse(project.exists()) def test_legacy_kit_command_is_not_exposed(self) -> None: result = self.run_skiff("kit", "init", "ack") self.assertNotEqual(result.returncode, 0) self.assertIn("invalid choice", result.stderr) if __name__ == "__main__": unittest.main()