Fix preset skill description precedence (#2538)

* Fix preset skill description precedence

* Fix skill description precedence during restore

---------

Co-authored-by: root <1647273252@qq.com>
This commit is contained in:
WOLIKIMCHENG
2026-05-15 03:59:38 +08:00
committed by GitHub
parent c87081a50a
commit be382804c7
2 changed files with 151 additions and 6 deletions

View File

@@ -1048,9 +1048,9 @@ class PresetManager:
short_name = cmd_name
if short_name.startswith("speckit."):
short_name = short_name[len("speckit."):]
desc = SKILL_DESCRIPTIONS.get(
desc = fm.get("description", "") or SKILL_DESCRIPTIONS.get(
short_name.replace(".", "-"),
fm.get("description", f"Command: {short_name}"),
f"Command: {short_name}",
)
init_opts = load_init_options(self.project_root)
selected_ai = init_opts.get("ai") if isinstance(init_opts, dict) else ""
@@ -1314,9 +1314,9 @@ class PresetManager:
frontmatter[key] = core_frontmatter[key]
original_desc = frontmatter.get("description", "")
enhanced_desc = SKILL_DESCRIPTIONS.get(
enhanced_desc = original_desc or SKILL_DESCRIPTIONS.get(
short_name,
original_desc or f"Spec-kit workflow command: {short_name}",
f"Spec-kit workflow command: {short_name}",
)
frontmatter = dict(frontmatter)
frontmatter["description"] = enhanced_desc
@@ -1417,9 +1417,9 @@ class PresetManager:
)
original_desc = frontmatter.get("description", "")
enhanced_desc = SKILL_DESCRIPTIONS.get(
enhanced_desc = original_desc or SKILL_DESCRIPTIONS.get(
short_name,
original_desc or f"Spec-kit workflow command: {short_name}",
f"Spec-kit workflow command: {short_name}",
)
frontmatter_data = registrar.build_skill_frontmatter(

View File

@@ -2266,6 +2266,37 @@ class TestPresetSkills:
)
return skill_dir
def _create_command_preset(self, temp_dir, preset_id, command_name, description, body):
preset_dir = temp_dir / preset_id
preset_dir.mkdir()
(preset_dir / "commands").mkdir()
command_file = f"{command_name}.md"
(preset_dir / "commands" / command_file).write_text(
f"---\ndescription: {description}\n---\n\n{body}\n"
)
manifest_data = {
"schema_version": "1.0",
"preset": {
"id": preset_id,
"name": preset_id,
"version": "1.0.0",
"description": "Test",
},
"requires": {"speckit_version": ">=0.1.0"},
"provides": {
"templates": [
{
"type": "command",
"name": command_name,
"file": f"commands/{command_file}",
}
]
},
}
with open(preset_dir / "preset.yml", "w") as f:
yaml.dump(manifest_data, f)
return preset_dir
def test_skill_overridden_on_preset_install(self, project_dir, temp_dir):
"""When --ai-skills was used, a preset command override should update the skill."""
# Simulate --ai-skills having been used: write init-options + create skill
@@ -2290,6 +2321,120 @@ class TestPresetSkills:
metadata = manager.registry.get("self-test")
assert "speckit-specify" in metadata.get("registered_skills", [])
def test_core_command_override_skill_uses_preset_command_description(self, project_dir, temp_dir):
"""Preset skill overrides for core commands should keep preset frontmatter descriptions."""
self._write_init_options(project_dir, ai="claude")
skills_dir = project_dir / ".claude" / "skills"
self._create_skill(skills_dir, "speckit-taskstoissues")
preset_dir = temp_dir / "taskstoissues-description"
preset_dir.mkdir()
(preset_dir / "commands").mkdir()
(preset_dir / "commands" / "speckit.repro.taskstoissues.md").write_text(
"---\n"
"description: COMMAND-FRONTMATTER-DESCRIPTION\n"
"---\n\n"
"# Repro command body\n"
)
manifest_data = {
"schema_version": "1.0",
"preset": {
"id": "taskstoissues-description",
"name": "Taskstoissues Description",
"version": "1.0.0",
"description": "Test",
},
"requires": {"speckit_version": ">=0.1.0"},
"provides": {
"templates": [
{
"type": "command",
"name": "speckit.taskstoissues",
"file": "commands/speckit.repro.taskstoissues.md",
"description": "MANIFEST-DESCRIPTION",
"replaces": "speckit.taskstoissues",
"strategy": "replace",
}
]
},
}
with open(preset_dir / "preset.yml", "w") as f:
yaml.dump(manifest_data, f)
manager = PresetManager(project_dir)
manager.install_from_directory(preset_dir, "0.1.5")
skill_file = skills_dir / "speckit-taskstoissues" / "SKILL.md"
content = skill_file.read_text()
assert "description: COMMAND-FRONTMATTER-DESCRIPTION" in content
assert "Convert tasks from tasks.md into GitHub issues." not in content
assert "source: preset:taskstoissues-description" in content
def test_core_skill_restore_uses_core_command_description(self, project_dir, temp_dir):
"""Core skill restore should keep core command frontmatter descriptions."""
self._write_init_options(project_dir, ai="claude")
skills_dir = project_dir / ".claude" / "skills"
self._create_skill(skills_dir, "speckit-taskstoissues")
core_cmds = project_dir / ".specify" / "templates" / "commands"
core_cmds.mkdir(parents=True, exist_ok=True)
(core_cmds / "taskstoissues.md").write_text(
"---\n"
"description: CORE-FRONTMATTER-DESCRIPTION\n"
"---\n\n"
"core taskstoissues body\n"
)
preset_dir = self._create_command_preset(
temp_dir,
"taskstoissues-restore",
"speckit.taskstoissues",
"PRESET-FRONTMATTER-DESCRIPTION",
"preset taskstoissues body\n",
)
manager = PresetManager(project_dir)
manager.install_from_directory(preset_dir, "0.1.5")
manager.remove("taskstoissues-restore")
skill_file = skills_dir / "speckit-taskstoissues" / "SKILL.md"
content = skill_file.read_text()
assert "description: CORE-FRONTMATTER-DESCRIPTION" in content
assert "Convert tasks from tasks.md into GitHub issues." not in content
assert "source: templates/commands/taskstoissues.md" in content
assert "core taskstoissues body" in content
def test_override_skill_reconcile_uses_override_command_description(self, project_dir, temp_dir):
"""Override skill reconciliation should keep override frontmatter descriptions."""
self._write_init_options(project_dir, ai="claude")
skills_dir = project_dir / ".claude" / "skills"
self._create_skill(skills_dir, "speckit-taskstoissues")
overrides_dir = project_dir / ".specify" / "templates" / "overrides"
overrides_dir.mkdir(parents=True)
(overrides_dir / "speckit.taskstoissues.md").write_text(
"---\n"
"description: OVERRIDE-FRONTMATTER-DESCRIPTION\n"
"---\n\n"
"override taskstoissues body\n"
)
preset_dir = self._create_command_preset(
temp_dir,
"taskstoissues-reconcile",
"speckit.taskstoissues",
"PRESET-FRONTMATTER-DESCRIPTION",
"preset taskstoissues body\n",
)
manager = PresetManager(project_dir)
manager.install_from_directory(preset_dir, "0.1.5")
skill_file = skills_dir / "speckit-taskstoissues" / "SKILL.md"
content = skill_file.read_text()
assert "description: OVERRIDE-FRONTMATTER-DESCRIPTION" in content
assert "Convert tasks from tasks.md into GitHub issues." not in content
assert "source: override:speckit.taskstoissues" in content
assert "override taskstoissues body" in content
def test_skill_not_updated_when_ai_skills_disabled(self, project_dir, temp_dir):
"""When --ai-skills was NOT used, preset install should not touch skills."""
self._write_init_options(project_dir, ai="qwen", ai_skills=False)