Skip to content

Commit c870cb8

Browse files
iamaeroplaneclaude
andcommitted
fix(agents): remove empty skill parent dir on unregister (#2017)
When unregistering a SKILL.md-based command (claude, codex, kimi, agy), the SKILL.md file was unlinked but the now-empty parent directory (e.g. .claude/skills/speckit-myext-run/) was left behind. After unlinking the file, attempt rmdir on the parent — a best-effort cleanup that is silently ignored if the directory is non-empty or already gone. Add test_unregister_skill_removes_parent_directory to cover this. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5a152ea commit c870cb8

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

src/specify_cli/agents.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,14 @@ def unregister_commands(
553553
cmd_file = commands_dir / f"{output_name}{agent_config['extension']}"
554554
if cmd_file.exists():
555555
cmd_file.unlink()
556+
# For SKILL.md agents the file lives in a subdirectory
557+
# (e.g. .claude/skills/speckit-foo/SKILL.md). Remove the
558+
# now-empty parent directory so no orphaned dirs remain.
559+
if agent_config["extension"] == "/SKILL.md":
560+
try:
561+
cmd_file.parent.rmdir()
562+
except OSError:
563+
pass # not empty or already gone — leave it
556564

557565
if agent_name == "copilot":
558566
prompt_file = project_root / ".github" / "prompts" / f"{cmd_name}.prompt.md"

tests/test_extensions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,21 @@ def test_unregister_commands_for_codex_skills_uses_mapped_names(self, project_di
12621262
assert not (skills_dir / "speckit-specify" / "SKILL.md").exists()
12631263
assert not (skills_dir / "speckit-shortcut" / "SKILL.md").exists()
12641264

1265+
def test_unregister_skill_removes_parent_directory(self, project_dir):
1266+
"""Removing a SKILL.md-based command also removes the empty parent directory."""
1267+
skills_dir = project_dir / ".agents" / "skills"
1268+
(skills_dir / "speckit-myext-run").mkdir(parents=True)
1269+
(skills_dir / "speckit-myext-run" / "SKILL.md").write_text("body")
1270+
1271+
registrar = CommandRegistrar()
1272+
registrar.unregister_commands(
1273+
{"codex": ["speckit.myext.run"]},
1274+
project_dir,
1275+
)
1276+
1277+
assert not (skills_dir / "speckit-myext-run" / "SKILL.md").exists()
1278+
assert not (skills_dir / "speckit-myext-run").exists()
1279+
12651280
def test_register_commands_for_all_agents_distinguishes_codex_from_amp(self, extension_dir, project_dir):
12661281
"""A Codex project under .agents/skills should not implicitly activate Amp."""
12671282
skills_dir = project_dir / ".agents" / "skills"

0 commit comments

Comments
 (0)