Add cmdforge remove command for project dependencies
- `cmdforge remove <tool>` removes a dependency from cmdforge.yaml - Matches by exact name or short name (e.g., both "eli5" and "official/eli5" work) - Returns exit code 1 if dependency not found - Complements `cmdforge add` for full manifest management Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
df29b28167
commit
93797a450a
|
|
@ -12,7 +12,7 @@ from .tool_commands import (
|
||||||
from .provider_commands import cmd_providers
|
from .provider_commands import cmd_providers
|
||||||
from .registry_commands import cmd_registry
|
from .registry_commands import cmd_registry
|
||||||
from .collections_commands import cmd_collections
|
from .collections_commands import cmd_collections
|
||||||
from .project_commands import cmd_deps, cmd_deps_tree, cmd_install_deps, cmd_add, cmd_init, cmd_lock, cmd_verify
|
from .project_commands import cmd_deps, cmd_deps_tree, cmd_install_deps, cmd_add, cmd_remove, cmd_init, cmd_lock, cmd_verify
|
||||||
from .config_commands import cmd_config
|
from .config_commands import cmd_config
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -323,6 +323,11 @@ def main():
|
||||||
p_add.add_argument("--no-install", action="store_true", help="Don't install after adding")
|
p_add.add_argument("--no-install", action="store_true", help="Don't install after adding")
|
||||||
p_add.set_defaults(func=cmd_add)
|
p_add.set_defaults(func=cmd_add)
|
||||||
|
|
||||||
|
# 'remove' command
|
||||||
|
p_remove = subparsers.add_parser("remove", help="Remove a tool from project dependencies")
|
||||||
|
p_remove.add_argument("tool", help="Tool to remove (owner/name or just name)")
|
||||||
|
p_remove.set_defaults(func=cmd_remove)
|
||||||
|
|
||||||
# 'init' command
|
# 'init' command
|
||||||
p_init = subparsers.add_parser("init", help="Initialize cmdforge.yaml")
|
p_init = subparsers.add_parser("init", help="Initialize cmdforge.yaml")
|
||||||
p_init.add_argument("-n", "--name", help="Project name")
|
p_init.add_argument("-n", "--name", help="Project name")
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,39 @@ def cmd_add(args):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_remove(args):
|
||||||
|
"""Remove a tool from project dependencies."""
|
||||||
|
tool_spec = args.tool
|
||||||
|
|
||||||
|
# Find manifest
|
||||||
|
manifest_path = find_manifest()
|
||||||
|
if not manifest_path:
|
||||||
|
print("No cmdforge.yaml found in current project.")
|
||||||
|
print("Nothing to remove.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
manifest = load_manifest(manifest_path)
|
||||||
|
|
||||||
|
# Parse tool spec to get the name
|
||||||
|
parsed = ToolSpec.parse(tool_spec)
|
||||||
|
tool_name = parsed.full_name
|
||||||
|
|
||||||
|
# Remove from manifest
|
||||||
|
if manifest.remove_dependency(tool_name):
|
||||||
|
save_manifest(manifest, manifest_path)
|
||||||
|
print(f"Removed {tool_name} from {manifest_path.name}")
|
||||||
|
else:
|
||||||
|
# Try without owner prefix
|
||||||
|
if manifest.remove_dependency(parsed.name):
|
||||||
|
save_manifest(manifest, manifest_path)
|
||||||
|
print(f"Removed {parsed.name} from {manifest_path.name}")
|
||||||
|
else:
|
||||||
|
print(f"Dependency '{tool_name}' not found in {manifest_path.name}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def cmd_init(args):
|
def cmd_init(args):
|
||||||
"""Initialize a new cmdforge.yaml."""
|
"""Initialize a new cmdforge.yaml."""
|
||||||
manifest_path = Path.cwd() / MANIFEST_FILENAME
|
manifest_path = Path.cwd() / MANIFEST_FILENAME
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,31 @@ class Manifest:
|
||||||
|
|
||||||
self.dependencies.append(Dependency(name=name, version=version))
|
self.dependencies.append(Dependency(name=name, version=version))
|
||||||
|
|
||||||
|
def remove_dependency(self, name: str) -> bool:
|
||||||
|
"""Remove a dependency by name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Tool name (can be qualified like 'official/tool' or just 'tool')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if dependency was removed, False if not found
|
||||||
|
"""
|
||||||
|
# Try exact match first
|
||||||
|
for i, dep in enumerate(self.dependencies):
|
||||||
|
if dep.name == name:
|
||||||
|
self.dependencies.pop(i)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Try matching just the tool name part (without owner)
|
||||||
|
short_name = name.split("/")[-1] if "/" in name else name
|
||||||
|
for i, dep in enumerate(self.dependencies):
|
||||||
|
dep_short = dep.name.split("/")[-1] if "/" in dep.name else dep.name
|
||||||
|
if dep_short == short_name:
|
||||||
|
self.dependencies.pop(i)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def find_manifest(start_dir: Optional[Path] = None) -> Optional[Path]:
|
def find_manifest(start_dir: Optional[Path] = None) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue