diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index b2e905bc..049aca95 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -2604,6 +2604,8 @@ def agent_switch( new_bootstrap = load_bootstrap(resolved.path, resolved.manifest) console.print(f" [dim]Setting up {agent_id}...[/dim]") new_bootstrap.setup(project_path, script_type, options) + # Record all installed files for tracked teardown + new_bootstrap.finalize_setup(project_path) console.print(f" [green]✓[/green] {agent_id} installed") except AgentPackError as exc: console.print(f"[red]Error setting up {agent_id}:[/red] {exc}") diff --git a/src/specify_cli/agent_pack.py b/src/specify_cli/agent_pack.py index e5fe05ca..dac6a569 100644 --- a/src/specify_cli/agent_pack.py +++ b/src/specify_cli/agent_pack.py @@ -222,6 +222,22 @@ class AgentBootstrap: """Return the agent's top-level directory inside the project.""" return project_path / self.manifest.commands_dir.split("/")[0] + def finalize_setup(self, project_path: Path) -> None: + """Record all files in the agent directory for tracked teardown. + + This must be called **after** the full init pipeline has finished + writing files (commands, context files, etc.) into the agent + directory. It scans ``self.manifest.commands_dir`` and records + every file with its SHA-256 hash so that :meth:`teardown` can + detect user modifications. + """ + if not self.manifest.commands_dir: + return + commands_dir = project_path / self.manifest.commands_dir + if commands_dir.is_dir(): + installed = [p for p in commands_dir.rglob("*") if p.is_file()] + record_installed_files(project_path, self.manifest.id, installed) + # --------------------------------------------------------------------------- # Installed-file tracking diff --git a/src/specify_cli/core_pack/agents/agy/bootstrap.py b/src/specify_cli/core_pack/agents/agy/bootstrap.py index 33bd5ba5..21e5be32 100644 --- a/src/specify_cli/core_pack/agents/agy/bootstrap.py +++ b/src/specify_cli/core_pack/agents/agy/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Agy(AgentBootstrap): @@ -16,9 +16,6 @@ class Agy(AgentBootstrap): """Install Antigravity agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Antigravity agent files from the project. diff --git a/src/specify_cli/core_pack/agents/amp/bootstrap.py b/src/specify_cli/core_pack/agents/amp/bootstrap.py index 236ec1c8..3eebd24c 100644 --- a/src/specify_cli/core_pack/agents/amp/bootstrap.py +++ b/src/specify_cli/core_pack/agents/amp/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Amp(AgentBootstrap): @@ -16,9 +16,6 @@ class Amp(AgentBootstrap): """Install Amp agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Amp agent files from the project. diff --git a/src/specify_cli/core_pack/agents/auggie/bootstrap.py b/src/specify_cli/core_pack/agents/auggie/bootstrap.py index d05b3a3b..c7c15a4f 100644 --- a/src/specify_cli/core_pack/agents/auggie/bootstrap.py +++ b/src/specify_cli/core_pack/agents/auggie/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Auggie(AgentBootstrap): @@ -16,9 +16,6 @@ class Auggie(AgentBootstrap): """Install Auggie CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Auggie CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/bob/bootstrap.py b/src/specify_cli/core_pack/agents/bob/bootstrap.py index 876882b0..bac8f9c2 100644 --- a/src/specify_cli/core_pack/agents/bob/bootstrap.py +++ b/src/specify_cli/core_pack/agents/bob/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Bob(AgentBootstrap): @@ -16,9 +16,6 @@ class Bob(AgentBootstrap): """Install IBM Bob agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove IBM Bob agent files from the project. diff --git a/src/specify_cli/core_pack/agents/claude/bootstrap.py b/src/specify_cli/core_pack/agents/claude/bootstrap.py index d4c255f2..9a3fb0c7 100644 --- a/src/specify_cli/core_pack/agents/claude/bootstrap.py +++ b/src/specify_cli/core_pack/agents/claude/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Claude(AgentBootstrap): @@ -16,9 +16,6 @@ class Claude(AgentBootstrap): """Install Claude Code agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Claude Code agent files from the project. diff --git a/src/specify_cli/core_pack/agents/codebuddy/bootstrap.py b/src/specify_cli/core_pack/agents/codebuddy/bootstrap.py index 760741c1..fbcc6439 100644 --- a/src/specify_cli/core_pack/agents/codebuddy/bootstrap.py +++ b/src/specify_cli/core_pack/agents/codebuddy/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Codebuddy(AgentBootstrap): @@ -16,9 +16,6 @@ class Codebuddy(AgentBootstrap): """Install CodeBuddy agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove CodeBuddy agent files from the project. diff --git a/src/specify_cli/core_pack/agents/codex/bootstrap.py b/src/specify_cli/core_pack/agents/codex/bootstrap.py index ac7d2917..7ecbef17 100644 --- a/src/specify_cli/core_pack/agents/codex/bootstrap.py +++ b/src/specify_cli/core_pack/agents/codex/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Codex(AgentBootstrap): @@ -16,9 +16,6 @@ class Codex(AgentBootstrap): """Install Codex CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Codex CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/copilot/bootstrap.py b/src/specify_cli/core_pack/agents/copilot/bootstrap.py index 0eaa0dc4..63a28661 100644 --- a/src/specify_cli/core_pack/agents/copilot/bootstrap.py +++ b/src/specify_cli/core_pack/agents/copilot/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Copilot(AgentBootstrap): @@ -16,9 +16,6 @@ class Copilot(AgentBootstrap): """Install GitHub Copilot agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove GitHub Copilot agent files from the project. diff --git a/src/specify_cli/core_pack/agents/cursor-agent/bootstrap.py b/src/specify_cli/core_pack/agents/cursor-agent/bootstrap.py index b2573acd..e01062df 100644 --- a/src/specify_cli/core_pack/agents/cursor-agent/bootstrap.py +++ b/src/specify_cli/core_pack/agents/cursor-agent/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class CursorAgent(AgentBootstrap): @@ -16,9 +16,6 @@ class CursorAgent(AgentBootstrap): """Install Cursor agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Cursor agent files from the project. diff --git a/src/specify_cli/core_pack/agents/gemini/bootstrap.py b/src/specify_cli/core_pack/agents/gemini/bootstrap.py index 5f20e31a..eab6ad7e 100644 --- a/src/specify_cli/core_pack/agents/gemini/bootstrap.py +++ b/src/specify_cli/core_pack/agents/gemini/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Gemini(AgentBootstrap): @@ -16,9 +16,6 @@ class Gemini(AgentBootstrap): """Install Gemini CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Gemini CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/iflow/bootstrap.py b/src/specify_cli/core_pack/agents/iflow/bootstrap.py index 506cb79b..eea1e1bd 100644 --- a/src/specify_cli/core_pack/agents/iflow/bootstrap.py +++ b/src/specify_cli/core_pack/agents/iflow/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Iflow(AgentBootstrap): @@ -16,9 +16,6 @@ class Iflow(AgentBootstrap): """Install iFlow CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove iFlow CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/junie/bootstrap.py b/src/specify_cli/core_pack/agents/junie/bootstrap.py index 5b3b1417..e8650a3b 100644 --- a/src/specify_cli/core_pack/agents/junie/bootstrap.py +++ b/src/specify_cli/core_pack/agents/junie/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Junie(AgentBootstrap): @@ -16,9 +16,6 @@ class Junie(AgentBootstrap): """Install Junie agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Junie agent files from the project. diff --git a/src/specify_cli/core_pack/agents/kilocode/bootstrap.py b/src/specify_cli/core_pack/agents/kilocode/bootstrap.py index 6b15f502..44a8a007 100644 --- a/src/specify_cli/core_pack/agents/kilocode/bootstrap.py +++ b/src/specify_cli/core_pack/agents/kilocode/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Kilocode(AgentBootstrap): @@ -16,9 +16,6 @@ class Kilocode(AgentBootstrap): """Install Kilo Code agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Kilo Code agent files from the project. diff --git a/src/specify_cli/core_pack/agents/kimi/bootstrap.py b/src/specify_cli/core_pack/agents/kimi/bootstrap.py index 6dbd5019..0f7136a5 100644 --- a/src/specify_cli/core_pack/agents/kimi/bootstrap.py +++ b/src/specify_cli/core_pack/agents/kimi/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Kimi(AgentBootstrap): @@ -16,9 +16,6 @@ class Kimi(AgentBootstrap): """Install Kimi Code agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Kimi Code agent files from the project. diff --git a/src/specify_cli/core_pack/agents/kiro-cli/bootstrap.py b/src/specify_cli/core_pack/agents/kiro-cli/bootstrap.py index b13a3669..d51b4b6c 100644 --- a/src/specify_cli/core_pack/agents/kiro-cli/bootstrap.py +++ b/src/specify_cli/core_pack/agents/kiro-cli/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class KiroCli(AgentBootstrap): @@ -16,9 +16,6 @@ class KiroCli(AgentBootstrap): """Install Kiro CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Kiro CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/opencode/bootstrap.py b/src/specify_cli/core_pack/agents/opencode/bootstrap.py index 4a94a3ee..fbd76f53 100644 --- a/src/specify_cli/core_pack/agents/opencode/bootstrap.py +++ b/src/specify_cli/core_pack/agents/opencode/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Opencode(AgentBootstrap): @@ -16,9 +16,6 @@ class Opencode(AgentBootstrap): """Install opencode agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove opencode agent files from the project. diff --git a/src/specify_cli/core_pack/agents/pi/bootstrap.py b/src/specify_cli/core_pack/agents/pi/bootstrap.py index 103f094c..591a0d86 100644 --- a/src/specify_cli/core_pack/agents/pi/bootstrap.py +++ b/src/specify_cli/core_pack/agents/pi/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Pi(AgentBootstrap): @@ -16,9 +16,6 @@ class Pi(AgentBootstrap): """Install Pi Coding Agent agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Pi Coding Agent agent files from the project. diff --git a/src/specify_cli/core_pack/agents/qodercli/bootstrap.py b/src/specify_cli/core_pack/agents/qodercli/bootstrap.py index af170c99..40e892f0 100644 --- a/src/specify_cli/core_pack/agents/qodercli/bootstrap.py +++ b/src/specify_cli/core_pack/agents/qodercli/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Qodercli(AgentBootstrap): @@ -16,9 +16,6 @@ class Qodercli(AgentBootstrap): """Install Qoder CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Qoder CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/qwen/bootstrap.py b/src/specify_cli/core_pack/agents/qwen/bootstrap.py index 018ec1ae..8e2d5902 100644 --- a/src/specify_cli/core_pack/agents/qwen/bootstrap.py +++ b/src/specify_cli/core_pack/agents/qwen/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Qwen(AgentBootstrap): @@ -16,9 +16,6 @@ class Qwen(AgentBootstrap): """Install Qwen Code agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Qwen Code agent files from the project. diff --git a/src/specify_cli/core_pack/agents/roo/bootstrap.py b/src/specify_cli/core_pack/agents/roo/bootstrap.py index c9cbcb37..fd8b66f2 100644 --- a/src/specify_cli/core_pack/agents/roo/bootstrap.py +++ b/src/specify_cli/core_pack/agents/roo/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Roo(AgentBootstrap): @@ -16,9 +16,6 @@ class Roo(AgentBootstrap): """Install Roo Code agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Roo Code agent files from the project. diff --git a/src/specify_cli/core_pack/agents/shai/bootstrap.py b/src/specify_cli/core_pack/agents/shai/bootstrap.py index 49a45e82..ed3c45b2 100644 --- a/src/specify_cli/core_pack/agents/shai/bootstrap.py +++ b/src/specify_cli/core_pack/agents/shai/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Shai(AgentBootstrap): @@ -16,9 +16,6 @@ class Shai(AgentBootstrap): """Install SHAI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove SHAI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/tabnine/bootstrap.py b/src/specify_cli/core_pack/agents/tabnine/bootstrap.py index 29780dfa..0e79eff3 100644 --- a/src/specify_cli/core_pack/agents/tabnine/bootstrap.py +++ b/src/specify_cli/core_pack/agents/tabnine/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Tabnine(AgentBootstrap): @@ -16,9 +16,6 @@ class Tabnine(AgentBootstrap): """Install Tabnine CLI agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Tabnine CLI agent files from the project. diff --git a/src/specify_cli/core_pack/agents/trae/bootstrap.py b/src/specify_cli/core_pack/agents/trae/bootstrap.py index 43c58b60..3846b4dc 100644 --- a/src/specify_cli/core_pack/agents/trae/bootstrap.py +++ b/src/specify_cli/core_pack/agents/trae/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Trae(AgentBootstrap): @@ -16,9 +16,6 @@ class Trae(AgentBootstrap): """Install Trae agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Trae agent files from the project. diff --git a/src/specify_cli/core_pack/agents/vibe/bootstrap.py b/src/specify_cli/core_pack/agents/vibe/bootstrap.py index cb0ca8b5..1ae353b4 100644 --- a/src/specify_cli/core_pack/agents/vibe/bootstrap.py +++ b/src/specify_cli/core_pack/agents/vibe/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Vibe(AgentBootstrap): @@ -16,9 +16,6 @@ class Vibe(AgentBootstrap): """Install Mistral Vibe agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Mistral Vibe agent files from the project. diff --git a/src/specify_cli/core_pack/agents/windsurf/bootstrap.py b/src/specify_cli/core_pack/agents/windsurf/bootstrap.py index 1f8e4722..fccbae3a 100644 --- a/src/specify_cli/core_pack/agents/windsurf/bootstrap.py +++ b/src/specify_cli/core_pack/agents/windsurf/bootstrap.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any, Dict -from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files +from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class Windsurf(AgentBootstrap): @@ -16,9 +16,6 @@ class Windsurf(AgentBootstrap): """Install Windsurf agent files into the project.""" commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR commands_dir.mkdir(parents=True, exist_ok=True) - # Record installed files for tracked teardown - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) def teardown(self, project_path: Path, *, force: bool = False) -> None: """Remove Windsurf agent files from the project. diff --git a/tests/test_agent_pack.py b/tests/test_agent_pack.py index 7df69a5c..bc3f4bb4 100644 --- a/tests/test_agent_pack.py +++ b/tests/test_agent_pack.py @@ -80,16 +80,13 @@ def _write_bootstrap(pack_dir: Path, class_name: str = "TestAgent", agent_dir: s bootstrap_file.write_text(textwrap.dedent(f"""\ from pathlib import Path from typing import Any, Dict - from specify_cli.agent_pack import AgentBootstrap, record_installed_files, remove_tracked_files + from specify_cli.agent_pack import AgentBootstrap, remove_tracked_files class {class_name}(AgentBootstrap): AGENT_DIR = "{agent_dir}" def setup(self, project_path: Path, script_type: str, options: Dict[str, Any]) -> None: - commands_dir = project_path / self.AGENT_DIR / "commands" - commands_dir.mkdir(parents=True, exist_ok=True) - installed = [p for p in commands_dir.rglob("*") if p.is_file()] - record_installed_files(project_path, self.manifest.id, installed) + (project_path / self.AGENT_DIR / "commands").mkdir(parents=True, exist_ok=True) def teardown(self, project_path: Path, *, force: bool = False) -> None: remove_tracked_files(project_path, self.manifest.id, force=force) @@ -279,10 +276,17 @@ class TestBootstrapContract: b.setup(project, "sh", {}) assert (project / ".test-agent" / "commands").is_dir() - # The install manifest should exist in .specify/ + # Simulate the init pipeline writing a file + cmd_file = project / ".test-agent" / "commands" / "hello.md" + cmd_file.write_text("hello", encoding="utf-8") + + # finalize_setup records files for tracking + b.finalize_setup(project) assert _manifest_path(project, "test-agent").is_file() b.teardown(project) + # The tracked file should be removed + assert not cmd_file.exists() # Install manifest itself should be cleaned up assert not _manifest_path(project, "test-agent").is_file() # Directories are preserved (only files are removed)