mirror of
https://github.com/github/spec-kit.git
synced 2026-03-22 13:23:08 +00:00
Move file recording to finalize_setup() — called after init pipeline writes files
Address code review: setup() now only creates directories, while finalize_setup() (on base class) scans the agent's commands_dir for all files and records them. This ensures files are tracked after the full init pipeline has written them, not before. - Add AgentBootstrap.finalize_setup() that scans commands_dir - Remove premature record_installed_files() from all 25 setup() methods - agent_switch calls finalize_setup() after setup() completes - Update test helper to match new pattern Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/spec-kit/sessions/779eabf6-21d5-428b-9f01-dd363df4c84a
This commit is contained in:
committed by
GitHub
parent
b5a5e3fc35
commit
a63c248c80
@@ -2604,6 +2604,8 @@ def agent_switch(
|
|||||||
new_bootstrap = load_bootstrap(resolved.path, resolved.manifest)
|
new_bootstrap = load_bootstrap(resolved.path, resolved.manifest)
|
||||||
console.print(f" [dim]Setting up {agent_id}...[/dim]")
|
console.print(f" [dim]Setting up {agent_id}...[/dim]")
|
||||||
new_bootstrap.setup(project_path, script_type, options)
|
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")
|
console.print(f" [green]✓[/green] {agent_id} installed")
|
||||||
except AgentPackError as exc:
|
except AgentPackError as exc:
|
||||||
console.print(f"[red]Error setting up {agent_id}:[/red] {exc}")
|
console.print(f"[red]Error setting up {agent_id}:[/red] {exc}")
|
||||||
|
|||||||
@@ -222,6 +222,22 @@ class AgentBootstrap:
|
|||||||
"""Return the agent's top-level directory inside the project."""
|
"""Return the agent's top-level directory inside the project."""
|
||||||
return project_path / self.manifest.commands_dir.split("/")[0]
|
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
|
# Installed-file tracking
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Agy(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Agy(AgentBootstrap):
|
|||||||
"""Install Antigravity agent files into the project."""
|
"""Install Antigravity agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Antigravity agent files from the project.
|
"""Remove Antigravity agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Amp(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Amp(AgentBootstrap):
|
|||||||
"""Install Amp agent files into the project."""
|
"""Install Amp agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Amp agent files from the project.
|
"""Remove Amp agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Auggie(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Auggie(AgentBootstrap):
|
|||||||
"""Install Auggie CLI agent files into the project."""
|
"""Install Auggie CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Auggie CLI agent files from the project.
|
"""Remove Auggie CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Bob(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Bob(AgentBootstrap):
|
|||||||
"""Install IBM Bob agent files into the project."""
|
"""Install IBM Bob agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove IBM Bob agent files from the project.
|
"""Remove IBM Bob agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Claude(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Claude(AgentBootstrap):
|
|||||||
"""Install Claude Code agent files into the project."""
|
"""Install Claude Code agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Claude Code agent files from the project.
|
"""Remove Claude Code agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Codebuddy(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Codebuddy(AgentBootstrap):
|
|||||||
"""Install CodeBuddy agent files into the project."""
|
"""Install CodeBuddy agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove CodeBuddy agent files from the project.
|
"""Remove CodeBuddy agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Codex(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Codex(AgentBootstrap):
|
|||||||
"""Install Codex CLI agent files into the project."""
|
"""Install Codex CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Codex CLI agent files from the project.
|
"""Remove Codex CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Copilot(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Copilot(AgentBootstrap):
|
|||||||
"""Install GitHub Copilot agent files into the project."""
|
"""Install GitHub Copilot agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove GitHub Copilot agent files from the project.
|
"""Remove GitHub Copilot agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class CursorAgent(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class CursorAgent(AgentBootstrap):
|
|||||||
"""Install Cursor agent files into the project."""
|
"""Install Cursor agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Cursor agent files from the project.
|
"""Remove Cursor agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Gemini(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Gemini(AgentBootstrap):
|
|||||||
"""Install Gemini CLI agent files into the project."""
|
"""Install Gemini CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Gemini CLI agent files from the project.
|
"""Remove Gemini CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Iflow(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Iflow(AgentBootstrap):
|
|||||||
"""Install iFlow CLI agent files into the project."""
|
"""Install iFlow CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove iFlow CLI agent files from the project.
|
"""Remove iFlow CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Junie(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Junie(AgentBootstrap):
|
|||||||
"""Install Junie agent files into the project."""
|
"""Install Junie agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Junie agent files from the project.
|
"""Remove Junie agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Kilocode(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Kilocode(AgentBootstrap):
|
|||||||
"""Install Kilo Code agent files into the project."""
|
"""Install Kilo Code agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Kilo Code agent files from the project.
|
"""Remove Kilo Code agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Kimi(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Kimi(AgentBootstrap):
|
|||||||
"""Install Kimi Code agent files into the project."""
|
"""Install Kimi Code agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Kimi Code agent files from the project.
|
"""Remove Kimi Code agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class KiroCli(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class KiroCli(AgentBootstrap):
|
|||||||
"""Install Kiro CLI agent files into the project."""
|
"""Install Kiro CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Kiro CLI agent files from the project.
|
"""Remove Kiro CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Opencode(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Opencode(AgentBootstrap):
|
|||||||
"""Install opencode agent files into the project."""
|
"""Install opencode agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove opencode agent files from the project.
|
"""Remove opencode agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Pi(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Pi(AgentBootstrap):
|
|||||||
"""Install Pi Coding Agent agent files into the project."""
|
"""Install Pi Coding Agent agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Pi Coding Agent agent files from the project.
|
"""Remove Pi Coding Agent agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Qodercli(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Qodercli(AgentBootstrap):
|
|||||||
"""Install Qoder CLI agent files into the project."""
|
"""Install Qoder CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Qoder CLI agent files from the project.
|
"""Remove Qoder CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Qwen(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Qwen(AgentBootstrap):
|
|||||||
"""Install Qwen Code agent files into the project."""
|
"""Install Qwen Code agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Qwen Code agent files from the project.
|
"""Remove Qwen Code agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Roo(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Roo(AgentBootstrap):
|
|||||||
"""Install Roo Code agent files into the project."""
|
"""Install Roo Code agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Roo Code agent files from the project.
|
"""Remove Roo Code agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Shai(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Shai(AgentBootstrap):
|
|||||||
"""Install SHAI agent files into the project."""
|
"""Install SHAI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove SHAI agent files from the project.
|
"""Remove SHAI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Tabnine(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Tabnine(AgentBootstrap):
|
|||||||
"""Install Tabnine CLI agent files into the project."""
|
"""Install Tabnine CLI agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Tabnine CLI agent files from the project.
|
"""Remove Tabnine CLI agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Trae(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Trae(AgentBootstrap):
|
|||||||
"""Install Trae agent files into the project."""
|
"""Install Trae agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Trae agent files from the project.
|
"""Remove Trae agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Vibe(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Vibe(AgentBootstrap):
|
|||||||
"""Install Mistral Vibe agent files into the project."""
|
"""Install Mistral Vibe agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Mistral Vibe agent files from the project.
|
"""Remove Mistral Vibe agent files from the project.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class Windsurf(AgentBootstrap):
|
||||||
@@ -16,9 +16,6 @@ class Windsurf(AgentBootstrap):
|
|||||||
"""Install Windsurf agent files into the project."""
|
"""Install Windsurf agent files into the project."""
|
||||||
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
commands_dir = project_path / self.AGENT_DIR / self.COMMANDS_SUBDIR
|
||||||
commands_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
"""Remove Windsurf agent files from the project.
|
"""Remove Windsurf agent files from the project.
|
||||||
|
|||||||
@@ -80,16 +80,13 @@ def _write_bootstrap(pack_dir: Path, class_name: str = "TestAgent", agent_dir: s
|
|||||||
bootstrap_file.write_text(textwrap.dedent(f"""\
|
bootstrap_file.write_text(textwrap.dedent(f"""\
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
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):
|
class {class_name}(AgentBootstrap):
|
||||||
AGENT_DIR = "{agent_dir}"
|
AGENT_DIR = "{agent_dir}"
|
||||||
|
|
||||||
def setup(self, project_path: Path, script_type: str, options: Dict[str, Any]) -> None:
|
def setup(self, project_path: Path, script_type: str, options: Dict[str, Any]) -> None:
|
||||||
commands_dir = project_path / self.AGENT_DIR / "commands"
|
(project_path / self.AGENT_DIR / "commands").mkdir(parents=True, exist_ok=True)
|
||||||
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)
|
|
||||||
|
|
||||||
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
def teardown(self, project_path: Path, *, force: bool = False) -> None:
|
||||||
remove_tracked_files(project_path, self.manifest.id, force=force)
|
remove_tracked_files(project_path, self.manifest.id, force=force)
|
||||||
@@ -279,10 +276,17 @@ class TestBootstrapContract:
|
|||||||
b.setup(project, "sh", {})
|
b.setup(project, "sh", {})
|
||||||
assert (project / ".test-agent" / "commands").is_dir()
|
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()
|
assert _manifest_path(project, "test-agent").is_file()
|
||||||
|
|
||||||
b.teardown(project)
|
b.teardown(project)
|
||||||
|
# The tracked file should be removed
|
||||||
|
assert not cmd_file.exists()
|
||||||
# Install manifest itself should be cleaned up
|
# Install manifest itself should be cleaned up
|
||||||
assert not _manifest_path(project, "test-agent").is_file()
|
assert not _manifest_path(project, "test-agent").is_file()
|
||||||
# Directories are preserved (only files are removed)
|
# Directories are preserved (only files are removed)
|
||||||
|
|||||||
Reference in New Issue
Block a user