Skip to content

Commit 7904482

Browse files
committed
fix: address PR review round 2 — legacy rmtree confirmation, agent_pack flag, registrar alias, manifest ID validation
- Legacy rmtree: prompt user before deleting agent directory in legacy fallback path (both no-manifest and AgentPackError cases), respects --force - Set options['agent_pack'] = True during agent_switch so projects originally created with --ai reflect pack-based management after switch - Add cursor-agent alias in CommandRegistrar.AGENT_CONFIGS so extension re-registration works when switching to/from cursor-agent - Validate manifest.id matches agent_id in resolve_agent_pack() to prevent malicious override packs from injecting different IDs
1 parent b94e541 commit 7904482

3 files changed

Lines changed: 27 additions & 0 deletions

File tree

src/specify_cli/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,12 @@ def agent_switch(
26972697
if agent_folder:
26982698
agent_dir = project_path / agent_folder.rstrip("/")
26992699
if agent_dir.is_dir():
2700+
if not force:
2701+
console.print(f"[yellow]No install manifest found for '{current_agent}' (legacy project).[/yellow]")
2702+
console.print(f" Directory to remove: {agent_dir}")
2703+
if not typer.confirm("Remove this directory?"):
2704+
console.print("[dim]Aborted. Use --force to skip this check.[/dim]")
2705+
raise typer.Exit(0)
27002706
shutil.rmtree(agent_dir)
27012707
console.print(f" [green]✓[/green] {current_agent} directory removed (legacy)")
27022708
else:
@@ -2708,6 +2714,12 @@ def agent_switch(
27082714
if agent_folder:
27092715
agent_dir = project_path / agent_folder.rstrip("/")
27102716
if agent_dir.is_dir():
2717+
if not force:
2718+
console.print(f"[yellow]No agent pack found for '{current_agent}' (legacy project).[/yellow]")
2719+
console.print(f" Directory to remove: {agent_dir}")
2720+
if not typer.confirm("Remove this directory?"):
2721+
console.print("[dim]Aborted. Use --force to skip this check.[/dim]")
2722+
raise typer.Exit(0)
27112723
shutil.rmtree(agent_dir)
27122724
console.print(f" [green]✓[/green] {current_agent} directory removed (legacy)")
27132725

@@ -2757,6 +2769,7 @@ def agent_switch(
27572769

27582770
# Update init options
27592771
options["ai"] = agent_id
2772+
options["agent_pack"] = True
27602773
options.pop("agent_switch_error", None) # clear any previous error
27612774
init_options_file.write_text(json.dumps(options, indent=2), encoding="utf-8")
27622775

src/specify_cli/agent_pack.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,14 @@ def resolve_agent_pack(
721721
manifest_file = pack_dir / MANIFEST_FILENAME
722722
if manifest_file.is_file():
723723
manifest = AgentManifest.from_yaml(manifest_file)
724+
# Verify the manifest's declared ID matches the requested
725+
# agent_id to prevent a malicious override from injecting
726+
# a different ID (used for file paths and module names).
727+
if manifest.id != agent_id:
728+
raise PackResolutionError(
729+
f"Agent pack manifest ID '{manifest.id}' does not match "
730+
f"requested ID '{agent_id}' (in {pack_dir})."
731+
)
724732
if source == "embedded":
725733
embedded_manifest = manifest
726734

src/specify_cli/agents.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ class CommandRegistrar:
4747
"args": "$ARGUMENTS",
4848
"extension": ".md"
4949
},
50+
"cursor-agent": {
51+
"dir": ".cursor/commands",
52+
"format": "markdown",
53+
"args": "$ARGUMENTS",
54+
"extension": ".md"
55+
},
5056
"qwen": {
5157
"dir": ".qwen/commands",
5258
"format": "markdown",

0 commit comments

Comments
 (0)