mirror of
https://github.com/github/spec-kit.git
synced 2026-03-24 14:23:09 +00:00
feat: setup() owns scaffolding and returns actual installed files
- AgentBootstrap._scaffold_project() calls scaffold_from_core_pack, snapshots before/after, returns all new files - finalize_setup() filters agent_files to only track files under the agent's own directory tree (shared .specify/ files not tracked) - All 25 bootstrap setup() methods call _scaffold_project() and return the actual file list instead of [] - --agent init flow routes through setup() for scaffolding instead of calling scaffold_from_core_pack directly - 100 new tests (TestSetupReturnsFiles): verify every agent's setup() returns non-empty, existing, absolute paths including agent-dir files - Parity tests use CliRunner to invoke the real init command - finalize_setup bug fix: skills-migrated agents (agy) now have their skills directory scanned correctly - 1262 tests pass (452 in test_agent_pack.py alone) Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/spec-kit/sessions/054690bb-c048-41e0-b553-377d5cb36b78
This commit is contained in:
committed by
GitHub
parent
d6016ab9db
commit
9b580a536b
@@ -1984,7 +1984,10 @@ def init(
|
||||
"This will become the default in v0.6.0."
|
||||
)
|
||||
|
||||
if use_github:
|
||||
if use_agent_pack:
|
||||
# Pack-based flow: setup() owns scaffolding, always uses bundled assets.
|
||||
tracker.add("scaffold", "Apply bundled assets")
|
||||
elif use_github:
|
||||
for key, label in [
|
||||
("fetch", "Fetch latest release"),
|
||||
("download", "Download template"),
|
||||
@@ -2019,7 +2022,26 @@ def init(
|
||||
verify = not skip_tls
|
||||
local_ssl_context = ssl_context if verify else False
|
||||
|
||||
if use_github:
|
||||
# -- scaffolding ------------------------------------------------
|
||||
# Pack-based flow (--agent): setup() owns scaffolding and
|
||||
# returns every file it created. Legacy flow (--ai): scaffold
|
||||
# directly or download from GitHub.
|
||||
agent_setup_files: list[Path] = []
|
||||
|
||||
if use_agent_pack and agent_bootstrap is not None:
|
||||
tracker.start("scaffold")
|
||||
try:
|
||||
agent_setup_files = agent_bootstrap.setup(
|
||||
project_path, selected_script, {"here": here})
|
||||
tracker.complete(
|
||||
"scaffold",
|
||||
f"{selected_ai} ({len(agent_setup_files)} files)")
|
||||
except Exception as exc:
|
||||
tracker.error("scaffold", str(exc))
|
||||
if not here and project_path.exists():
|
||||
shutil.rmtree(project_path)
|
||||
raise typer.Exit(1)
|
||||
elif use_github:
|
||||
with httpx.Client(verify=local_ssl_context) as local_client:
|
||||
download_and_extract_template(project_path, selected_ai, selected_script, here, verbose=False, tracker=tracker, client=local_client, debug=debug, github_token=github_token)
|
||||
else:
|
||||
@@ -2162,11 +2184,14 @@ def init(
|
||||
tracker.skip("cleanup", "not needed (no download)")
|
||||
|
||||
# When --agent is used, record all installed agent files for
|
||||
# tracked teardown. This runs AFTER the full init pipeline has
|
||||
# finished creating files (scaffolding, skills, presets,
|
||||
# extensions) so finalize_setup captures everything.
|
||||
# tracked teardown. setup() already returned the files it
|
||||
# created; pass them to finalize_setup so the manifest is
|
||||
# accurate. finalize_setup also scans the agent directory
|
||||
# to catch any additional files created by later pipeline
|
||||
# steps (skills, extensions, presets).
|
||||
if use_agent_pack and agent_bootstrap is not None:
|
||||
agent_bootstrap.finalize_setup(project_path)
|
||||
agent_bootstrap.finalize_setup(
|
||||
project_path, agent_files=agent_setup_files)
|
||||
|
||||
tracker.complete("final", "project ready")
|
||||
except (typer.Exit, SystemExit):
|
||||
|
||||
@@ -245,6 +245,57 @@ class AgentBootstrap:
|
||||
"""Return the agent's top-level directory inside the project."""
|
||||
return project_path / self.manifest.commands_dir.split("/")[0]
|
||||
|
||||
def collect_installed_files(self, project_path: Path) -> List[Path]:
|
||||
"""Return every file under the agent's directory tree.
|
||||
|
||||
Subclasses should call this at the end of :meth:`setup` to build
|
||||
the return list. Any files present in the agent directory at
|
||||
that point — whether created by ``setup()`` itself, by the
|
||||
scaffold pipeline, or by a preceding step — are reported.
|
||||
"""
|
||||
root = self.agent_dir(project_path)
|
||||
if not root.is_dir():
|
||||
return []
|
||||
return sorted(p for p in root.rglob("*") if p.is_file())
|
||||
|
||||
def _scaffold_project(
|
||||
self,
|
||||
project_path: Path,
|
||||
script_type: str,
|
||||
is_current_dir: bool = False,
|
||||
) -> List[Path]:
|
||||
"""Run the shared scaffolding pipeline and return new files.
|
||||
|
||||
Calls ``scaffold_from_core_pack`` for this agent and then
|
||||
collects every file that was created. Subclasses should call
|
||||
this from :meth:`setup` when they want to use the shared
|
||||
scaffolding rather than creating files manually.
|
||||
|
||||
Returns:
|
||||
List of absolute paths of **all** files created by the
|
||||
scaffold (agent-specific commands, shared scripts,
|
||||
templates, etc.).
|
||||
"""
|
||||
# Lazy import to avoid circular dependency (agent_pack is
|
||||
# imported by specify_cli.__init__).
|
||||
from specify_cli import scaffold_from_core_pack
|
||||
|
||||
# Snapshot existing files
|
||||
before: set[Path] = set()
|
||||
if project_path.exists():
|
||||
before = {p for p in project_path.rglob("*") if p.is_file()}
|
||||
|
||||
ok = scaffold_from_core_pack(
|
||||
project_path, self.manifest.id, script_type, is_current_dir,
|
||||
)
|
||||
if not ok:
|
||||
raise AgentPackError(
|
||||
f"Scaffolding failed for agent '{self.manifest.id}'")
|
||||
|
||||
# Collect every new file
|
||||
after = {p for p in project_path.rglob("*") if p.is_file()}
|
||||
return sorted(after - before)
|
||||
|
||||
def finalize_setup(
|
||||
self,
|
||||
project_path: Path,
|
||||
@@ -257,25 +308,51 @@ class AgentBootstrap:
|
||||
writing files (commands, context files, extensions) into the
|
||||
project. It combines the files reported by :meth:`setup` with
|
||||
any extra files (e.g. from extension registration), scans the
|
||||
agent's ``commands_dir`` for anything additional, and writes the
|
||||
agent's directory tree for anything additional, and writes the
|
||||
install manifest.
|
||||
|
||||
``setup()`` may return *all* files created by the shared
|
||||
scaffolding (including shared project files in ``.specify/``).
|
||||
Only files under the agent's own directory tree are recorded as
|
||||
``agent_files`` — shared project infrastructure is not tracked
|
||||
per-agent and will not be removed during teardown.
|
||||
|
||||
Args:
|
||||
agent_files: Files reported by :meth:`setup`.
|
||||
extension_files: Files created by extension registration.
|
||||
"""
|
||||
all_agent = list(agent_files or [])
|
||||
all_extension = list(extension_files or [])
|
||||
|
||||
# Also scan the commands directory for files created by the
|
||||
# init pipeline that setup() did not report directly.
|
||||
# Filter agent_files: only keep files under the agent's directory
|
||||
# tree. setup() may return shared project files (e.g. .specify/)
|
||||
# which must not be tracked per-agent.
|
||||
agent_root = self.agent_dir(project_path)
|
||||
agent_root_resolved = agent_root.resolve()
|
||||
all_agent: List[Path] = []
|
||||
for p in (agent_files or []):
|
||||
try:
|
||||
p.resolve().relative_to(agent_root_resolved)
|
||||
all_agent.append(p)
|
||||
except ValueError:
|
||||
pass # shared file — not tracked per-agent
|
||||
|
||||
# Scan the agent's directory tree for files created by the init
|
||||
# pipeline that setup() did not report directly. We scan the
|
||||
# entire agent directory (the parent of commands_dir) because
|
||||
# skills-migrated agents replace the commands directory with a
|
||||
# sibling skills directory during init.
|
||||
if self.manifest.commands_dir:
|
||||
commands_dir = project_path / self.manifest.commands_dir
|
||||
if commands_dir.is_dir():
|
||||
agent_set = {p.resolve() for p in all_agent}
|
||||
for p in commands_dir.rglob("*"):
|
||||
if p.is_file() and p.resolve() not in agent_set:
|
||||
all_agent.append(p)
|
||||
# Scan the agent root (e.g. .claude/) so we catch both
|
||||
# commands and skills directories.
|
||||
agent_root = commands_dir.parent
|
||||
agent_set = {p.resolve() for p in all_agent}
|
||||
for scan_dir in (commands_dir, agent_root):
|
||||
if scan_dir.is_dir():
|
||||
for p in scan_dir.rglob("*"):
|
||||
if p.is_file() and p.resolve() not in agent_set:
|
||||
all_agent.append(p)
|
||||
agent_set.add(p.resolve())
|
||||
|
||||
record_installed_files(
|
||||
project_path,
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Antigravity agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Amp agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Auggie CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove IBM Bob agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Claude Code agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove CodeBuddy agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Codex CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove GitHub Copilot agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Cursor agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Gemini CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove iFlow CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Junie agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Kilo Code agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Kimi Code agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Kiro CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove opencode agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Pi Coding Agent agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Qoder CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Qwen Code agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Roo Code agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove SHAI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Tabnine CLI agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Trae agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Mistral Vibe agent files from the project.
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
return [] # directories only — actual files are created by the init pipeline
|
||||
return self._scaffold_project(project_path, script_type)
|
||||
|
||||
def teardown(self, project_path: Path, *, force: bool = False, files: Optional[Dict[str, str]] = None) -> List[str]:
|
||||
"""Remove Windsurf agent files from the project.
|
||||
|
||||
Reference in New Issue
Block a user