Fix linting violations for v1.0.0 release preparation
- Apply black formatting to all Python files - Fix various flake8 violations in agent system code - Clean up imports and whitespace issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -730,7 +730,7 @@ release-check: $(VENV)/bin/activate
|
|||||||
echo "📋 Release Readiness Checklist:"; \
|
echo "📋 Release Readiness Checklist:"; \
|
||||||
echo "==============================="; \
|
echo "==============================="; \
|
||||||
echo " • Version Consistency:"; \
|
echo " • Version Consistency:"; \
|
||||||
CHANGELOG_VERSION=$$(grep '^## \[' CHANGELOG.md | head -1 | sed 's/## \[\(.*\)\].*/\1/' | grep -v "Unreleased" || echo ""); \
|
CHANGELOG_VERSION=$$(grep '^## \[' CHANGELOG.md | grep -v "Unreleased" | head -1 | sed 's/## \[\(.*\)\].*/\1/' || echo ""); \
|
||||||
PYPROJECT_VERSION=$$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/' || echo ""); \
|
PYPROJECT_VERSION=$$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/' || echo ""); \
|
||||||
if [ "$$CHANGELOG_VERSION" = "$$PYPROJECT_VERSION" ] && [ -n "$$CHANGELOG_VERSION" ]; then \
|
if [ "$$CHANGELOG_VERSION" = "$$PYPROJECT_VERSION" ] && [ -n "$$CHANGELOG_VERSION" ]; then \
|
||||||
echo " ✅ Versions consistent: $$CHANGELOG_VERSION"; \
|
echo " ✅ Versions consistent: $$CHANGELOG_VERSION"; \
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ def cli():
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--category',
|
@click.option(
|
||||||
type=click.Choice([c.value for c in AgentCategory]),
|
"--category",
|
||||||
help='Filter by category')
|
type=click.Choice([c.value for c in AgentCategory]),
|
||||||
@click.option('--verbose', '-v', is_flag=True, help='Show detailed information')
|
help="Filter by category",
|
||||||
|
)
|
||||||
|
@click.option("--verbose", "-v", is_flag=True, help="Show detailed information")
|
||||||
def list(category: Optional[str], verbose: bool):
|
def list(category: Optional[str], verbose: bool):
|
||||||
"""List available agents."""
|
"""List available agents."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -34,7 +36,9 @@ def list(category: Optional[str], verbose: bool):
|
|||||||
if verbose:
|
if verbose:
|
||||||
categories = registry.get_categories()
|
categories = registry.get_categories()
|
||||||
for cat, agents in categories.items():
|
for cat, agents in categories.items():
|
||||||
click.echo(f"\n{cat.value.replace('-', ' ').title()} ({len(agents)} agents):")
|
click.echo(
|
||||||
|
f"\n{cat.value.replace('-', ' ').title()} ({len(agents)} agents):"
|
||||||
|
)
|
||||||
click.echo("=" * 50)
|
click.echo("=" * 50)
|
||||||
for agent in agents:
|
for agent in agents:
|
||||||
click.echo(f" • {agent.name}: {agent.description}")
|
click.echo(f" • {agent.name}: {agent.description}")
|
||||||
@@ -56,10 +60,10 @@ def list(category: Optional[str], verbose: bool):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument('agents', nargs=-1, required=True)
|
@click.argument("agents", nargs=-1, required=True)
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.option('--no-backup', is_flag=True, help='Skip creating backup')
|
@click.option("--no-backup", is_flag=True, help="Skip creating backup")
|
||||||
@click.option('--no-docs', is_flag=True, help='Skip updating documentation')
|
@click.option("--no-docs", is_flag=True, help="Skip updating documentation")
|
||||||
def install(agents: List[str], target: str, no_backup: bool, no_docs: bool):
|
def install(agents: List[str], target: str, no_backup: bool, no_docs: bool):
|
||||||
"""Install agents into a project."""
|
"""Install agents into a project."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -72,7 +76,7 @@ def install(agents: List[str], target: str, no_backup: bool, no_docs: bool):
|
|||||||
claude_config_path=target_path / "CLAUDE.md",
|
claude_config_path=target_path / "CLAUDE.md",
|
||||||
makefile_path=target_path / "Makefile",
|
makefile_path=target_path / "Makefile",
|
||||||
update_docs=not no_docs,
|
update_docs=not no_docs,
|
||||||
create_backup=not no_backup
|
create_backup=not no_backup,
|
||||||
)
|
)
|
||||||
|
|
||||||
click.echo(f"Installing agents to: {target_path}")
|
click.echo(f"Installing agents to: {target_path}")
|
||||||
@@ -98,8 +102,8 @@ def install(agents: List[str], target: str, no_backup: bool, no_docs: bool):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.argument('agents', nargs=-1)
|
@click.argument("agents", nargs=-1)
|
||||||
def update(target: str, agents: List[str]):
|
def update(target: str, agents: List[str]):
|
||||||
"""Update installed agents."""
|
"""Update installed agents."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -131,8 +135,8 @@ def update(target: str, agents: List[str]):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument('agents', nargs=-1, required=True)
|
@click.argument("agents", nargs=-1, required=True)
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
def remove(agents: List[str], target: str):
|
def remove(agents: List[str], target: str):
|
||||||
"""Remove agents from a project."""
|
"""Remove agents from a project."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -154,11 +158,17 @@ def remove(agents: List[str], target: str):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument('project_name')
|
@click.argument("project_name")
|
||||||
@click.option('--template', '-t', default='python-basic',
|
@click.option(
|
||||||
help='Project template (python-basic, python-web, python-cli, python-data)')
|
"--template",
|
||||||
@click.option('--agents', '-a', help='Comma-separated list of agents to install')
|
"-t",
|
||||||
@click.option('--parent-dir', default='.', help='Parent directory for project (default: current)')
|
default="python-basic",
|
||||||
|
help="Project template (python-basic, python-web, python-cli, python-data)",
|
||||||
|
)
|
||||||
|
@click.option("--agents", "-a", help="Comma-separated list of agents to install")
|
||||||
|
@click.option(
|
||||||
|
"--parent-dir", default=".", help="Parent directory for project (default: current)"
|
||||||
|
)
|
||||||
def init(project_name: str, template: str, agents: Optional[str], parent_dir: str):
|
def init(project_name: str, template: str, agents: Optional[str], parent_dir: str):
|
||||||
"""Initialize a new project with agents."""
|
"""Initialize a new project with agents."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -173,7 +183,7 @@ def init(project_name: str, template: str, agents: Optional[str], parent_dir: st
|
|||||||
# Parse agent list
|
# Parse agent list
|
||||||
agent_list = None
|
agent_list = None
|
||||||
if agents:
|
if agents:
|
||||||
agent_list = [a.strip() for a in agents.split(',')]
|
agent_list = [a.strip() for a in agents.split(",")]
|
||||||
|
|
||||||
click.echo(f"Initializing project: {project_name}")
|
click.echo(f"Initializing project: {project_name}")
|
||||||
click.echo(f"Template: {template}")
|
click.echo(f"Template: {template}")
|
||||||
@@ -204,7 +214,7 @@ def init(project_name: str, template: str, agents: Optional[str], parent_dir: st
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
def validate(target: str):
|
def validate(target: str):
|
||||||
"""Validate agents in a project."""
|
"""Validate agents in a project."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -263,7 +273,7 @@ def templates():
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
def status(target: str):
|
def status(target: str):
|
||||||
"""Show status of agents in a project."""
|
"""Show status of agents in a project."""
|
||||||
registry = _get_registry()
|
registry = _get_registry()
|
||||||
@@ -321,8 +331,8 @@ def status(target: str):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.option('--detailed', '-d', is_flag=True, help='Show detailed analysis')
|
@click.option("--detailed", "-d", is_flag=True, help="Show detailed analysis")
|
||||||
def detect(target: str, detailed: bool):
|
def detect(target: str, detailed: bool):
|
||||||
"""Detect existing agent systems in a project."""
|
"""Detect existing agent systems in a project."""
|
||||||
from .detection import AgentSystemDetector
|
from .detection import AgentSystemDetector
|
||||||
@@ -372,11 +382,13 @@ def detect(target: str, detailed: bool):
|
|||||||
|
|
||||||
# Show integration strategy
|
# Show integration strategy
|
||||||
if result.integration_strategy:
|
if result.integration_strategy:
|
||||||
click.echo(f"\n💡 Recommended Integration Strategy: {result.integration_strategy}")
|
click.echo(
|
||||||
|
f"\n💡 Recommended Integration Strategy: {result.integration_strategy}"
|
||||||
|
)
|
||||||
|
|
||||||
# Show migration recommendations
|
# Show migration recommendations
|
||||||
if result.migration_recommendations:
|
if result.migration_recommendations:
|
||||||
click.echo(f"\n📋 Migration Recommendations:")
|
click.echo("\n📋 Migration Recommendations:")
|
||||||
for recommendation in result.migration_recommendations:
|
for recommendation in result.migration_recommendations:
|
||||||
if recommendation.startswith(" "):
|
if recommendation.startswith(" "):
|
||||||
click.echo(f" {recommendation}")
|
click.echo(f" {recommendation}")
|
||||||
@@ -384,14 +396,18 @@ def detect(target: str, detailed: bool):
|
|||||||
click.echo(f" • {recommendation}")
|
click.echo(f" • {recommendation}")
|
||||||
|
|
||||||
if not result.detected_systems:
|
if not result.detected_systems:
|
||||||
click.echo(f"\n✨ This project is ready for Kaizen Agentic installation!")
|
click.echo("\n✨ This project is ready for Kaizen Agentic installation!")
|
||||||
click.echo(f" Run: kaizen-agentic install <agent-names>")
|
click.echo(" Run: kaizen-agentic install <agent-names>")
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.option('--dry-run', '-n', is_flag=True, help='Show what would be done without executing')
|
@click.option(
|
||||||
@click.option('--auto-resolve', '-a', is_flag=True, help='Automatically resolve simple conflicts')
|
"--dry-run", "-n", is_flag=True, help="Show what would be done without executing"
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--auto-resolve", "-a", is_flag=True, help="Automatically resolve simple conflicts"
|
||||||
|
)
|
||||||
def migrate(target: str, dry_run: bool, auto_resolve: bool):
|
def migrate(target: str, dry_run: bool, auto_resolve: bool):
|
||||||
"""Create migration plan for integrating Kaizen agents into existing project."""
|
"""Create migration plan for integrating Kaizen agents into existing project."""
|
||||||
from .migration import AgentMigrationPlanner, AgentMigrator
|
from .migration import AgentMigrationPlanner, AgentMigrator
|
||||||
@@ -408,7 +424,10 @@ def migrate(target: str, dry_run: bool, auto_resolve: bool):
|
|||||||
planner = AgentMigrationPlanner()
|
planner = AgentMigrationPlanner()
|
||||||
integration_plan = planner.create_integration_plan(target_path)
|
integration_plan = planner.create_integration_plan(target_path)
|
||||||
|
|
||||||
if not integration_plan.migration_plans and not integration_plan.conflict_resolutions:
|
if (
|
||||||
|
not integration_plan.migration_plans
|
||||||
|
and not integration_plan.conflict_resolutions
|
||||||
|
):
|
||||||
click.echo("✨ No migration needed - project is ready for Kaizen agents!")
|
click.echo("✨ No migration needed - project is ready for Kaizen agents!")
|
||||||
click.echo(" Run: kaizen-agentic install <agent-names>")
|
click.echo(" Run: kaizen-agentic install <agent-names>")
|
||||||
return
|
return
|
||||||
@@ -418,12 +437,17 @@ def migrate(target: str, dry_run: bool, auto_resolve: bool):
|
|||||||
click.echo(f"\n🔄 Migration Plans ({len(integration_plan.migration_plans)}):")
|
click.echo(f"\n🔄 Migration Plans ({len(integration_plan.migration_plans)}):")
|
||||||
for plan in integration_plan.migration_plans:
|
for plan in integration_plan.migration_plans:
|
||||||
strategy_emoji = {
|
strategy_emoji = {
|
||||||
"replace": "🔄", "extend": "🔗", "preserve": "💾",
|
"replace": "🔄",
|
||||||
"merge": "🔀", "remove": "🗑️"
|
"extend": "🔗",
|
||||||
|
"preserve": "💾",
|
||||||
|
"merge": "🔀",
|
||||||
|
"remove": "🗑️",
|
||||||
}
|
}
|
||||||
emoji = strategy_emoji.get(plan.strategy.value, "❓")
|
emoji = strategy_emoji.get(plan.strategy.value, "❓")
|
||||||
|
|
||||||
click.echo(f" {emoji} {plan.source_agent.name} ({plan.source_agent.type.value})")
|
click.echo(
|
||||||
|
f" {emoji} {plan.source_agent.name} ({plan.source_agent.type.value})"
|
||||||
|
)
|
||||||
click.echo(f" Strategy: {plan.strategy.value}")
|
click.echo(f" Strategy: {plan.strategy.value}")
|
||||||
if plan.target_agent:
|
if plan.target_agent:
|
||||||
click.echo(f" Target: {plan.target_agent}")
|
click.echo(f" Target: {plan.target_agent}")
|
||||||
@@ -433,7 +457,9 @@ def migrate(target: str, dry_run: bool, auto_resolve: bool):
|
|||||||
|
|
||||||
# Show conflict resolutions
|
# Show conflict resolutions
|
||||||
if integration_plan.conflict_resolutions:
|
if integration_plan.conflict_resolutions:
|
||||||
click.echo(f"\n⚠️ Conflict Resolutions ({len(integration_plan.conflict_resolutions)}):")
|
click.echo(
|
||||||
|
f"\n⚠️ Conflict Resolutions ({len(integration_plan.conflict_resolutions)}):"
|
||||||
|
)
|
||||||
for resolution in integration_plan.conflict_resolutions:
|
for resolution in integration_plan.conflict_resolutions:
|
||||||
click.echo(f" • {resolution.agent1} vs {resolution.agent2}")
|
click.echo(f" • {resolution.agent1} vs {resolution.agent2}")
|
||||||
click.echo(f" Resolution: {resolution.resolution.value}")
|
click.echo(f" Resolution: {resolution.resolution.value}")
|
||||||
@@ -443,31 +469,35 @@ def migrate(target: str, dry_run: bool, auto_resolve: bool):
|
|||||||
|
|
||||||
# Show integration order
|
# Show integration order
|
||||||
if integration_plan.integration_order:
|
if integration_plan.integration_order:
|
||||||
click.echo(f"\n📋 Integration Order:")
|
click.echo("\n📋 Integration Order:")
|
||||||
for i, agent_name in enumerate(integration_plan.integration_order, 1):
|
for i, agent_name in enumerate(integration_plan.integration_order, 1):
|
||||||
click.echo(f" {i}. {agent_name}")
|
click.echo(f" {i}. {agent_name}")
|
||||||
|
|
||||||
# Show post-migration tasks
|
# Show post-migration tasks
|
||||||
if integration_plan.post_migration_tasks:
|
if integration_plan.post_migration_tasks:
|
||||||
click.echo(f"\n✅ Post-Migration Tasks:")
|
click.echo("\n✅ Post-Migration Tasks:")
|
||||||
for task in integration_plan.post_migration_tasks:
|
for task in integration_plan.post_migration_tasks:
|
||||||
click.echo(f" • {task}")
|
click.echo(f" • {task}")
|
||||||
|
|
||||||
# Execute migration if requested
|
# Execute migration if requested
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
click.echo(f"\n🚀 Executing migration...")
|
click.echo("\n🚀 Executing migration...")
|
||||||
migrator = AgentMigrator()
|
migrator = AgentMigrator()
|
||||||
results = migrator.execute_migration(integration_plan, dry_run=False)
|
results = migrator.execute_migration(integration_plan, dry_run=False)
|
||||||
|
|
||||||
click.echo(f"\n📊 Migration Results:")
|
click.echo("\n📊 Migration Results:")
|
||||||
for agent, result in results.items():
|
for agent, result in results.items():
|
||||||
status_emoji = "✅" if "ERROR" not in result else "❌"
|
status_emoji = "✅" if "ERROR" not in result else "❌"
|
||||||
click.echo(f" {status_emoji} {agent}: {result}")
|
click.echo(f" {status_emoji} {agent}: {result}")
|
||||||
|
|
||||||
click.echo(f"\n💾 Backup created at: {integration_plan.backup_directory}")
|
click.echo(f"\n💾 Backup created at: {integration_plan.backup_directory}")
|
||||||
else:
|
else:
|
||||||
click.echo(f"\n🔍 This was a dry run. Use --no-dry-run to execute the migration.")
|
click.echo(
|
||||||
click.echo(f" Backup would be created at: {integration_plan.backup_directory}")
|
"\n🔍 This was a dry run. Use --no-dry-run to execute the migration."
|
||||||
|
)
|
||||||
|
click.echo(
|
||||||
|
f" Backup would be created at: {integration_plan.backup_directory}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@cli.group()
|
@cli.group()
|
||||||
@@ -477,8 +507,8 @@ def extensions():
|
|||||||
|
|
||||||
|
|
||||||
@extensions.command()
|
@extensions.command()
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.option('--base-agent', '-b', help='Filter by base agent')
|
@click.option("--base-agent", "-b", help="Filter by base agent")
|
||||||
def list_extensions(target: str, base_agent: Optional[str]):
|
def list_extensions(target: str, base_agent: Optional[str]):
|
||||||
"""List installed extensions."""
|
"""List installed extensions."""
|
||||||
from .extensions import ExtensionManager
|
from .extensions import ExtensionManager
|
||||||
@@ -510,12 +540,14 @@ def list_extensions(target: str, base_agent: Optional[str]):
|
|||||||
|
|
||||||
|
|
||||||
@extensions.command()
|
@extensions.command()
|
||||||
@click.argument('name')
|
@click.argument("name")
|
||||||
@click.argument('base_agent')
|
@click.argument("base_agent")
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.option('--description', '-d', help='Extension description')
|
@click.option("--description", "-d", help="Extension description")
|
||||||
@click.option('--template', default='basic', help='Template type (basic, advanced)')
|
@click.option("--template", default="basic", help="Template type (basic, advanced)")
|
||||||
def create(name: str, base_agent: str, target: str, description: Optional[str], template: str):
|
def create(
|
||||||
|
name: str, base_agent: str, target: str, description: Optional[str], template: str
|
||||||
|
):
|
||||||
"""Create a new agent extension."""
|
"""Create a new agent extension."""
|
||||||
from .extensions import ExtensionManager, ExtensionType, create_extension_template
|
from .extensions import ExtensionManager, ExtensionType, create_extension_template
|
||||||
|
|
||||||
@@ -523,7 +555,9 @@ def create(name: str, base_agent: str, target: str, description: Optional[str],
|
|||||||
manager = ExtensionManager(target_path)
|
manager = ExtensionManager(target_path)
|
||||||
|
|
||||||
# Generate template
|
# Generate template
|
||||||
template_content = create_extension_template(name, base_agent, target_path, template)
|
template_content = create_extension_template(
|
||||||
|
name, base_agent, target_path, template
|
||||||
|
)
|
||||||
|
|
||||||
# Save template to file
|
# Save template to file
|
||||||
template_dir = target_path / ".kaizen" / "extensions" / name
|
template_dir = target_path / ".kaizen" / "extensions" / name
|
||||||
@@ -537,18 +571,20 @@ def create(name: str, base_agent: str, target: str, description: Optional[str],
|
|||||||
name=name,
|
name=name,
|
||||||
base_agent=base_agent,
|
base_agent=base_agent,
|
||||||
extension_type=ExtensionType.FUNCTIONAL_EXTENSION,
|
extension_type=ExtensionType.FUNCTIONAL_EXTENSION,
|
||||||
description=description or f"Custom extension for {base_agent}"
|
description=description or f"Custom extension for {base_agent}",
|
||||||
)
|
)
|
||||||
|
|
||||||
click.echo(f"✅ Created extension: {name}")
|
click.echo(f"✅ Created extension: {name}")
|
||||||
click.echo(f" Base agent: {base_agent}")
|
click.echo(f" Base agent: {base_agent}")
|
||||||
click.echo(f" Template saved to: {template_file}")
|
click.echo(f" Template saved to: {template_file}")
|
||||||
click.echo(f" Edit the configuration and run: kaizen-agentic extensions enable {name}")
|
click.echo(
|
||||||
|
f" Edit the configuration and run: kaizen-agentic extensions enable {name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@extensions.command()
|
@extensions.command()
|
||||||
@click.argument('name')
|
@click.argument("name")
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
def enable(name: str, target: str):
|
def enable(name: str, target: str):
|
||||||
"""Enable an extension."""
|
"""Enable an extension."""
|
||||||
from .extensions import ExtensionManager
|
from .extensions import ExtensionManager
|
||||||
@@ -563,8 +599,8 @@ def enable(name: str, target: str):
|
|||||||
|
|
||||||
|
|
||||||
@extensions.command()
|
@extensions.command()
|
||||||
@click.argument('name')
|
@click.argument("name")
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
def disable(name: str, target: str):
|
def disable(name: str, target: str):
|
||||||
"""Disable an extension."""
|
"""Disable an extension."""
|
||||||
from .extensions import ExtensionManager
|
from .extensions import ExtensionManager
|
||||||
@@ -579,9 +615,9 @@ def disable(name: str, target: str):
|
|||||||
|
|
||||||
|
|
||||||
@extensions.command()
|
@extensions.command()
|
||||||
@click.argument('name')
|
@click.argument("name")
|
||||||
@click.option('--target', '-t', default='.', help='Target directory (default: current)')
|
@click.option("--target", "-t", default=".", help="Target directory (default: current)")
|
||||||
@click.confirmation_option(prompt='Are you sure you want to remove this extension?')
|
@click.confirmation_option(prompt="Are you sure you want to remove this extension?")
|
||||||
def remove(name: str, target: str):
|
def remove(name: str, target: str):
|
||||||
"""Remove an extension."""
|
"""Remove an extension."""
|
||||||
from .extensions import ExtensionManager
|
from .extensions import ExtensionManager
|
||||||
@@ -610,6 +646,7 @@ def _get_registry() -> AgentRegistry:
|
|||||||
# Try to find installed package
|
# Try to find installed package
|
||||||
try:
|
try:
|
||||||
import kaizen_agentic
|
import kaizen_agentic
|
||||||
|
|
||||||
package_dir = Path(kaizen_agentic.__file__).parent.parent.parent
|
package_dir = Path(kaizen_agentic.__file__).parent.parent.parent
|
||||||
agents_dir = package_dir / "agents"
|
agents_dir = package_dir / "agents"
|
||||||
if not agents_dir.exists():
|
if not agents_dir.exists():
|
||||||
@@ -617,7 +654,9 @@ def _get_registry() -> AgentRegistry:
|
|||||||
agents_dir = Path(kaizen_agentic.__file__).parent / "data" / "agents"
|
agents_dir = Path(kaizen_agentic.__file__).parent / "data" / "agents"
|
||||||
except ImportError:
|
except ImportError:
|
||||||
click.echo("Error: Could not find agents directory")
|
click.echo("Error: Could not find agents directory")
|
||||||
click.echo("Make sure you're in a kaizen-agentic project or have the package installed")
|
click.echo(
|
||||||
|
"Make sure you're in a kaizen-agentic project or have the package installed"
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not agents_dir.exists():
|
if not agents_dir.exists():
|
||||||
@@ -627,5 +666,5 @@ def _get_registry() -> AgentRegistry:
|
|||||||
return AgentRegistry(agents_dir)
|
return AgentRegistry(agents_dir)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
cli()
|
cli()
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
"""Detection and analysis of existing agent systems in projects."""
|
"""Detection and analysis of existing agent systems in projects."""
|
||||||
|
|
||||||
import json
|
|
||||||
import yaml
|
import yaml
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Set, Tuple
|
from typing import List, Optional, Set, Tuple
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class AgentSystemType(Enum):
|
class AgentSystemType(Enum):
|
||||||
"""Types of existing agent systems that might be found."""
|
"""Types of existing agent systems that might be found."""
|
||||||
|
|
||||||
KAIZEN_AGENTIC = "kaizen-agentic"
|
KAIZEN_AGENTIC = "kaizen-agentic"
|
||||||
CLAUDE_CODE = "claude-code"
|
CLAUDE_CODE = "claude-code"
|
||||||
GITHUB_COPILOT = "github-copilot"
|
GITHUB_COPILOT = "github-copilot"
|
||||||
@@ -25,6 +25,7 @@ class AgentSystemType(Enum):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class DetectedAgent:
|
class DetectedAgent:
|
||||||
"""Information about a detected agent."""
|
"""Information about a detected agent."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
type: AgentSystemType
|
type: AgentSystemType
|
||||||
file_path: Path
|
file_path: Path
|
||||||
@@ -44,6 +45,7 @@ class DetectedAgent:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class AgentSystemDetectionResult:
|
class AgentSystemDetectionResult:
|
||||||
"""Result of agent system detection in a project."""
|
"""Result of agent system detection in a project."""
|
||||||
|
|
||||||
project_path: Path
|
project_path: Path
|
||||||
detected_systems: List[AgentSystemType]
|
detected_systems: List[AgentSystemType]
|
||||||
agents: List[DetectedAgent]
|
agents: List[DetectedAgent]
|
||||||
@@ -197,33 +199,37 @@ class AgentSystemDetector:
|
|||||||
agents.append(agent)
|
agents.append(agent)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Create a detected agent with error info
|
# Create a detected agent with error info
|
||||||
agents.append(DetectedAgent(
|
agents.append(
|
||||||
name=agent_file.stem.replace("agent-", ""),
|
DetectedAgent(
|
||||||
type=AgentSystemType.KAIZEN_AGENTIC,
|
name=agent_file.stem.replace("agent-", ""),
|
||||||
file_path=agent_file,
|
type=AgentSystemType.KAIZEN_AGENTIC,
|
||||||
can_migrate=False,
|
file_path=agent_file,
|
||||||
migration_notes=f"Parse error: {e}"
|
can_migrate=False,
|
||||||
))
|
migration_notes=f"Parse error: {e}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return agents
|
return agents
|
||||||
|
|
||||||
def _parse_kaizen_agent_file(self, agent_file: Path) -> Optional[DetectedAgent]:
|
def _parse_kaizen_agent_file(self, agent_file: Path) -> Optional[DetectedAgent]:
|
||||||
"""Parse a Kaizen Agentic agent file."""
|
"""Parse a Kaizen Agentic agent file."""
|
||||||
try:
|
try:
|
||||||
content = agent_file.read_text(encoding='utf-8')
|
content = agent_file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
# Extract YAML frontmatter
|
# Extract YAML frontmatter
|
||||||
if content.startswith('---'):
|
if content.startswith("---"):
|
||||||
parts = content.split('---', 2)
|
parts = content.split("---", 2)
|
||||||
if len(parts) >= 3:
|
if len(parts) >= 3:
|
||||||
frontmatter = yaml.safe_load(parts[1])
|
frontmatter = yaml.safe_load(parts[1])
|
||||||
|
|
||||||
return DetectedAgent(
|
return DetectedAgent(
|
||||||
name=frontmatter.get('name', agent_file.stem.replace("agent-", "")),
|
name=frontmatter.get(
|
||||||
|
"name", agent_file.stem.replace("agent-", "")
|
||||||
|
),
|
||||||
type=AgentSystemType.KAIZEN_AGENTIC,
|
type=AgentSystemType.KAIZEN_AGENTIC,
|
||||||
file_path=agent_file,
|
file_path=agent_file,
|
||||||
description=frontmatter.get('description'),
|
description=frontmatter.get("description"),
|
||||||
dependencies=set(frontmatter.get('dependencies', []))
|
dependencies=set(frontmatter.get("dependencies", [])),
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -238,12 +244,14 @@ class AgentSystemDetector:
|
|||||||
if claude_file.exists():
|
if claude_file.exists():
|
||||||
# Claude Code typically doesn't have separate agent files
|
# Claude Code typically doesn't have separate agent files
|
||||||
# but might reference agent usage in CLAUDE.md
|
# but might reference agent usage in CLAUDE.md
|
||||||
agents.append(DetectedAgent(
|
agents.append(
|
||||||
name="claude-integration",
|
DetectedAgent(
|
||||||
type=AgentSystemType.CLAUDE_CODE,
|
name="claude-integration",
|
||||||
file_path=claude_file,
|
type=AgentSystemType.CLAUDE_CODE,
|
||||||
description="Claude Code integration configuration"
|
file_path=claude_file,
|
||||||
))
|
description="Claude Code integration configuration",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return agents
|
return agents
|
||||||
|
|
||||||
@@ -261,15 +269,20 @@ class AgentSystemDetector:
|
|||||||
for pattern in ["*.py", "*.yml", "*.yaml", "*.json", "*.md"]:
|
for pattern in ["*.py", "*.yml", "*.yaml", "*.json", "*.md"]:
|
||||||
for agent_file in agent_dir.glob(pattern):
|
for agent_file in agent_dir.glob(pattern):
|
||||||
# Skip kaizen-agentic files
|
# Skip kaizen-agentic files
|
||||||
if agent_file.name.startswith("agent-") and agent_file.suffix == ".md":
|
if (
|
||||||
|
agent_file.name.startswith("agent-")
|
||||||
|
and agent_file.suffix == ".md"
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
agents.append(DetectedAgent(
|
agents.append(
|
||||||
name=agent_file.stem,
|
DetectedAgent(
|
||||||
type=AgentSystemType.CUSTOM_AGENTS,
|
name=agent_file.stem,
|
||||||
file_path=agent_file,
|
type=AgentSystemType.CUSTOM_AGENTS,
|
||||||
description=f"Custom agent in {dir_name}/"
|
file_path=agent_file,
|
||||||
))
|
description=f"Custom agent in {dir_name}/",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return agents
|
return agents
|
||||||
|
|
||||||
@@ -286,7 +299,9 @@ class AgentSystemDetector:
|
|||||||
|
|
||||||
return config_files
|
return config_files
|
||||||
|
|
||||||
def _analyze_conflicts(self, agents: List[DetectedAgent]) -> List[Tuple[str, str, str]]:
|
def _analyze_conflicts(
|
||||||
|
self, agents: List[DetectedAgent]
|
||||||
|
) -> List[Tuple[str, str, str]]:
|
||||||
"""Analyze potential conflicts between agents."""
|
"""Analyze potential conflicts between agents."""
|
||||||
conflicts = []
|
conflicts = []
|
||||||
|
|
||||||
@@ -298,15 +313,16 @@ class AgentSystemDetector:
|
|||||||
agents_by_type[agent.type].append(agent)
|
agents_by_type[agent.type].append(agent)
|
||||||
|
|
||||||
# Check for naming conflicts
|
# Check for naming conflicts
|
||||||
all_names = [agent.name for agent in agents]
|
|
||||||
for i, agent1 in enumerate(agents):
|
for i, agent1 in enumerate(agents):
|
||||||
for j, agent2 in enumerate(agents[i+1:], i+1):
|
for j, agent2 in enumerate(agents[i + 1 :], i + 1):
|
||||||
if agent1.name == agent2.name and agent1.type != agent2.type:
|
if agent1.name == agent2.name and agent1.type != agent2.type:
|
||||||
conflicts.append((
|
conflicts.append(
|
||||||
agent1.name,
|
(
|
||||||
agent2.name,
|
agent1.name,
|
||||||
f"Name conflict between {agent1.type.value} and {agent2.type.value}"
|
agent2.name,
|
||||||
))
|
f"Name conflict between {agent1.type.value} and {agent2.type.value}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Check for functional overlaps
|
# Check for functional overlaps
|
||||||
functional_conflicts = {
|
functional_conflicts = {
|
||||||
@@ -324,12 +340,14 @@ class AgentSystemDetector:
|
|||||||
|
|
||||||
if len(matching_agents) > 1:
|
if len(matching_agents) > 1:
|
||||||
for i, agent1 in enumerate(matching_agents):
|
for i, agent1 in enumerate(matching_agents):
|
||||||
for agent2 in matching_agents[i+1:]:
|
for agent2 in matching_agents[i + 1 :]:
|
||||||
conflicts.append((
|
conflicts.append(
|
||||||
agent1.name,
|
(
|
||||||
agent2.name,
|
agent1.name,
|
||||||
f"Functional overlap: {conflict_type}"
|
agent2.name,
|
||||||
))
|
f"Functional overlap: {conflict_type}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return conflicts
|
return conflicts
|
||||||
|
|
||||||
@@ -343,7 +361,10 @@ class AgentSystemDetector:
|
|||||||
if AgentSystemType.KAIZEN_AGENTIC in detected_systems:
|
if AgentSystemType.KAIZEN_AGENTIC in detected_systems:
|
||||||
return "update_existing"
|
return "update_existing"
|
||||||
|
|
||||||
if len(detected_systems) == 1 and detected_systems[0] == AgentSystemType.CLAUDE_CODE:
|
if (
|
||||||
|
len(detected_systems) == 1
|
||||||
|
and detected_systems[0] == AgentSystemType.CLAUDE_CODE
|
||||||
|
):
|
||||||
return "claude_compatible"
|
return "claude_compatible"
|
||||||
|
|
||||||
if len([a for a in agents if a.type == AgentSystemType.CUSTOM_AGENTS]) > 5:
|
if len([a for a in agents if a.type == AgentSystemType.CUSTOM_AGENTS]) > 5:
|
||||||
@@ -355,13 +376,15 @@ class AgentSystemDetector:
|
|||||||
self,
|
self,
|
||||||
detected_systems: List[AgentSystemType],
|
detected_systems: List[AgentSystemType],
|
||||||
agents: List[DetectedAgent],
|
agents: List[DetectedAgent],
|
||||||
conflicts: List[Tuple[str, str, str]]
|
conflicts: List[Tuple[str, str, str]],
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
"""Generate migration recommendations."""
|
"""Generate migration recommendations."""
|
||||||
recommendations = []
|
recommendations = []
|
||||||
|
|
||||||
if not detected_systems:
|
if not detected_systems:
|
||||||
recommendations.append("Clean installation - no existing agent systems detected")
|
recommendations.append(
|
||||||
|
"Clean installation - no existing agent systems detected"
|
||||||
|
)
|
||||||
return recommendations
|
return recommendations
|
||||||
|
|
||||||
if AgentSystemType.KAIZEN_AGENTIC in detected_systems:
|
if AgentSystemType.KAIZEN_AGENTIC in detected_systems:
|
||||||
@@ -369,18 +392,26 @@ class AgentSystemDetector:
|
|||||||
recommendations.append("Run 'kaizen-agentic update' to get latest agents")
|
recommendations.append("Run 'kaizen-agentic update' to get latest agents")
|
||||||
|
|
||||||
if conflicts:
|
if conflicts:
|
||||||
recommendations.append(f"Resolve {len(conflicts)} naming/functional conflicts")
|
recommendations.append(
|
||||||
|
f"Resolve {len(conflicts)} naming/functional conflicts"
|
||||||
|
)
|
||||||
for agent1, agent2, reason in conflicts:
|
for agent1, agent2, reason in conflicts:
|
||||||
recommendations.append(f" - Conflict: {agent1} vs {agent2} ({reason})")
|
recommendations.append(f" - Conflict: {agent1} vs {agent2} ({reason})")
|
||||||
|
|
||||||
custom_agents = [a for a in agents if a.type == AgentSystemType.CUSTOM_AGENTS]
|
custom_agents = [a for a in agents if a.type == AgentSystemType.CUSTOM_AGENTS]
|
||||||
if custom_agents:
|
if custom_agents:
|
||||||
recommendations.append(f"Consider migrating {len(custom_agents)} custom agents")
|
recommendations.append(
|
||||||
recommendations.append(" - Review custom agents for Kaizen Agentic equivalents")
|
f"Consider migrating {len(custom_agents)} custom agents"
|
||||||
recommendations.append(" - Create project-specific extensions for unique functionality")
|
)
|
||||||
|
recommendations.append(
|
||||||
|
" - Review custom agents for Kaizen Agentic equivalents"
|
||||||
|
)
|
||||||
|
recommendations.append(
|
||||||
|
" - Create project-specific extensions for unique functionality"
|
||||||
|
)
|
||||||
|
|
||||||
if AgentSystemType.CLAUDE_CODE in detected_systems:
|
if AgentSystemType.CLAUDE_CODE in detected_systems:
|
||||||
recommendations.append("Maintain Claude Code compatibility")
|
recommendations.append("Maintain Claude Code compatibility")
|
||||||
recommendations.append(" - Update CLAUDE.md with new agent references")
|
recommendations.append(" - Update CLAUDE.md with new agent references")
|
||||||
|
|
||||||
return recommendations
|
return recommendations
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
import json
|
import json
|
||||||
import yaml
|
import yaml
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Any, Union
|
from typing import Dict, List, Optional, Any
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class ExtensionType(Enum):
|
class ExtensionType(Enum):
|
||||||
"""Types of agent extensions."""
|
"""Types of agent extensions."""
|
||||||
|
|
||||||
CONFIGURATION_OVERLAY = "config_overlay" # Override default configurations
|
CONFIGURATION_OVERLAY = "config_overlay" # Override default configurations
|
||||||
FUNCTIONAL_EXTENSION = "functional_extension" # Add new functionality
|
FUNCTIONAL_EXTENSION = "functional_extension" # Add new functionality
|
||||||
WORKFLOW_INTEGRATION = "workflow_integration" # Integrate with project workflows
|
WORKFLOW_INTEGRATION = "workflow_integration" # Integrate with project workflows
|
||||||
@@ -21,6 +22,7 @@ class ExtensionType(Enum):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class AgentExtension:
|
class AgentExtension:
|
||||||
"""Defines an extension to a Kaizen agent."""
|
"""Defines an extension to a Kaizen agent."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
base_agent: str # The Kaizen agent this extends
|
base_agent: str # The Kaizen agent this extends
|
||||||
extension_type: ExtensionType
|
extension_type: ExtensionType
|
||||||
@@ -44,6 +46,7 @@ class AgentExtension:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class ProjectExtensionRegistry:
|
class ProjectExtensionRegistry:
|
||||||
"""Registry of extensions for a project."""
|
"""Registry of extensions for a project."""
|
||||||
|
|
||||||
project_path: Path
|
project_path: Path
|
||||||
extensions: List[AgentExtension] = field(default_factory=list)
|
extensions: List[AgentExtension] = field(default_factory=list)
|
||||||
global_config: Dict[str, Any] = field(default_factory=dict)
|
global_config: Dict[str, Any] = field(default_factory=dict)
|
||||||
@@ -63,7 +66,7 @@ class ExtensionManager:
|
|||||||
base_agent: str,
|
base_agent: str,
|
||||||
extension_type: ExtensionType,
|
extension_type: ExtensionType,
|
||||||
description: str,
|
description: str,
|
||||||
**kwargs
|
**kwargs,
|
||||||
) -> AgentExtension:
|
) -> AgentExtension:
|
||||||
"""Create a new agent extension."""
|
"""Create a new agent extension."""
|
||||||
extension = AgentExtension(
|
extension = AgentExtension(
|
||||||
@@ -71,7 +74,7 @@ class ExtensionManager:
|
|||||||
base_agent=base_agent,
|
base_agent=base_agent,
|
||||||
extension_type=extension_type,
|
extension_type=extension_type,
|
||||||
description=description,
|
description=description,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
self._save_extension(extension)
|
self._save_extension(extension)
|
||||||
@@ -79,14 +82,16 @@ class ExtensionManager:
|
|||||||
|
|
||||||
def install_extension(self, extension_path: Path) -> AgentExtension:
|
def install_extension(self, extension_path: Path) -> AgentExtension:
|
||||||
"""Install an extension from a file."""
|
"""Install an extension from a file."""
|
||||||
if extension_path.suffix == '.json':
|
if extension_path.suffix == ".json":
|
||||||
with open(extension_path) as f:
|
with open(extension_path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
elif extension_path.suffix in ['.yml', '.yaml']:
|
elif extension_path.suffix in [".yml", ".yaml"]:
|
||||||
with open(extension_path) as f:
|
with open(extension_path) as f:
|
||||||
data = yaml.safe_load(f)
|
data = yaml.safe_load(f)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unsupported extension file format: {extension_path.suffix}")
|
raise ValueError(
|
||||||
|
f"Unsupported extension file format: {extension_path.suffix}"
|
||||||
|
)
|
||||||
|
|
||||||
extension = AgentExtension(**data)
|
extension = AgentExtension(**data)
|
||||||
self._save_extension(extension)
|
self._save_extension(extension)
|
||||||
@@ -127,6 +132,7 @@ class ExtensionManager:
|
|||||||
extension_dir = self.extensions_dir / name
|
extension_dir = self.extensions_dir / name
|
||||||
if extension_dir.exists():
|
if extension_dir.exists():
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
shutil.rmtree(extension_dir)
|
shutil.rmtree(extension_dir)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -136,8 +142,11 @@ class ExtensionManager:
|
|||||||
def get_effective_config(self, base_agent: str) -> Dict[str, Any]:
|
def get_effective_config(self, base_agent: str) -> Dict[str, Any]:
|
||||||
"""Get the effective configuration for an agent with all extensions applied."""
|
"""Get the effective configuration for an agent with all extensions applied."""
|
||||||
base_config = self._get_base_agent_config(base_agent)
|
base_config = self._get_base_agent_config(base_agent)
|
||||||
extensions = [ext for ext in self._load_extensions()
|
extensions = [
|
||||||
if ext.base_agent == base_agent and ext.enabled]
|
ext
|
||||||
|
for ext in self._load_extensions()
|
||||||
|
if ext.base_agent == base_agent and ext.enabled
|
||||||
|
]
|
||||||
|
|
||||||
# Apply extensions in order
|
# Apply extensions in order
|
||||||
for extension in extensions:
|
for extension in extensions:
|
||||||
@@ -151,7 +160,7 @@ class ExtensionManager:
|
|||||||
base_agent: str,
|
base_agent: str,
|
||||||
custom_instructions: str,
|
custom_instructions: str,
|
||||||
custom_commands: Optional[Dict[str, str]] = None,
|
custom_commands: Optional[Dict[str, str]] = None,
|
||||||
environment_config: Optional[Dict[str, Any]] = None
|
environment_config: Optional[Dict[str, Any]] = None,
|
||||||
) -> AgentExtension:
|
) -> AgentExtension:
|
||||||
"""Create a project-specific agent based on a Kaizen agent."""
|
"""Create a project-specific agent based on a Kaizen agent."""
|
||||||
|
|
||||||
@@ -161,8 +170,8 @@ class ExtensionManager:
|
|||||||
"project_context": {
|
"project_context": {
|
||||||
"name": self.project_path.name,
|
"name": self.project_path.name,
|
||||||
"path": str(self.project_path),
|
"path": str(self.project_path),
|
||||||
"type": self._detect_project_type()
|
"type": self._detect_project_type(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if environment_config:
|
if environment_config:
|
||||||
@@ -175,7 +184,7 @@ class ExtensionManager:
|
|||||||
description=f"Project-specific extension of {base_agent} for {self.project_path.name}",
|
description=f"Project-specific extension of {base_agent} for {self.project_path.name}",
|
||||||
configuration=config,
|
configuration=config,
|
||||||
custom_commands=custom_commands or {},
|
custom_commands=custom_commands or {},
|
||||||
environment_overrides=environment_config or {}
|
environment_overrides=environment_config or {},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create agent file
|
# Create agent file
|
||||||
@@ -187,7 +196,7 @@ class ExtensionManager:
|
|||||||
self,
|
self,
|
||||||
legacy_agent_path: Path,
|
legacy_agent_path: Path,
|
||||||
target_kaizen_agent: str,
|
target_kaizen_agent: str,
|
||||||
migration_strategy: str = "preserve_functionality"
|
migration_strategy: str = "preserve_functionality",
|
||||||
) -> AgentExtension:
|
) -> AgentExtension:
|
||||||
"""Integrate a legacy agent as an extension to a Kaizen agent."""
|
"""Integrate a legacy agent as an extension to a Kaizen agent."""
|
||||||
|
|
||||||
@@ -201,7 +210,7 @@ class ExtensionManager:
|
|||||||
"legacy_source": str(legacy_agent_path),
|
"legacy_source": str(legacy_agent_path),
|
||||||
"migration_strategy": migration_strategy,
|
"migration_strategy": migration_strategy,
|
||||||
"preserved_functionality": legacy_analysis.get("functionality", []),
|
"preserved_functionality": legacy_analysis.get("functionality", []),
|
||||||
"custom_config": legacy_analysis.get("config", {})
|
"custom_config": legacy_analysis.get("config", {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
extension = self.create_extension(
|
extension = self.create_extension(
|
||||||
@@ -209,7 +218,7 @@ class ExtensionManager:
|
|||||||
base_agent=target_kaizen_agent,
|
base_agent=target_kaizen_agent,
|
||||||
extension_type=ExtensionType.WORKFLOW_INTEGRATION,
|
extension_type=ExtensionType.WORKFLOW_INTEGRATION,
|
||||||
description=f"Legacy integration of {legacy_agent_path.name}",
|
description=f"Legacy integration of {legacy_agent_path.name}",
|
||||||
configuration=config
|
configuration=config,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create migration wrapper
|
# Create migration wrapper
|
||||||
@@ -232,23 +241,23 @@ class ExtensionManager:
|
|||||||
extension_dir.mkdir(parents=True, exist_ok=True)
|
extension_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# Save extension definition
|
# Save extension definition
|
||||||
with open(extension_dir / "extension.yml", 'w') as f:
|
with open(extension_dir / "extension.yml", "w") as f:
|
||||||
# Convert dataclass to dict for YAML serialization
|
# Convert dataclass to dict for YAML serialization
|
||||||
data = {
|
data = {
|
||||||
'name': extension.name,
|
"name": extension.name,
|
||||||
'base_agent': extension.base_agent,
|
"base_agent": extension.base_agent,
|
||||||
'extension_type': extension.extension_type.value,
|
"extension_type": extension.extension_type.value,
|
||||||
'description': extension.description,
|
"description": extension.description,
|
||||||
'version': extension.version,
|
"version": extension.version,
|
||||||
'author': extension.author,
|
"author": extension.author,
|
||||||
'configuration': extension.configuration,
|
"configuration": extension.configuration,
|
||||||
'custom_commands': extension.custom_commands,
|
"custom_commands": extension.custom_commands,
|
||||||
'workflow_hooks': extension.workflow_hooks,
|
"workflow_hooks": extension.workflow_hooks,
|
||||||
'data_transformations': extension.data_transformations,
|
"data_transformations": extension.data_transformations,
|
||||||
'environment_overrides': extension.environment_overrides,
|
"environment_overrides": extension.environment_overrides,
|
||||||
'dependencies': extension.dependencies,
|
"dependencies": extension.dependencies,
|
||||||
'compatibility': extension.compatibility,
|
"compatibility": extension.compatibility,
|
||||||
'enabled': extension.enabled
|
"enabled": extension.enabled,
|
||||||
}
|
}
|
||||||
yaml.dump(data, f, default_flow_style=False)
|
yaml.dump(data, f, default_flow_style=False)
|
||||||
|
|
||||||
@@ -262,9 +271,9 @@ class ExtensionManager:
|
|||||||
data = yaml.safe_load(f) or {}
|
data = yaml.safe_load(f) or {}
|
||||||
|
|
||||||
extensions = []
|
extensions = []
|
||||||
for ext_data in data.get('extensions', []):
|
for ext_data in data.get("extensions", []):
|
||||||
# Convert string back to enum
|
# Convert string back to enum
|
||||||
ext_data['extension_type'] = ExtensionType(ext_data['extension_type'])
|
ext_data["extension_type"] = ExtensionType(ext_data["extension_type"])
|
||||||
extensions.append(AgentExtension(**ext_data))
|
extensions.append(AgentExtension(**ext_data))
|
||||||
|
|
||||||
return extensions
|
return extensions
|
||||||
@@ -277,28 +286,28 @@ class ExtensionManager:
|
|||||||
|
|
||||||
# Convert to serializable format
|
# Convert to serializable format
|
||||||
data = {
|
data = {
|
||||||
'extensions': [
|
"extensions": [
|
||||||
{
|
{
|
||||||
'name': ext.name,
|
"name": ext.name,
|
||||||
'base_agent': ext.base_agent,
|
"base_agent": ext.base_agent,
|
||||||
'extension_type': ext.extension_type.value,
|
"extension_type": ext.extension_type.value,
|
||||||
'description': ext.description,
|
"description": ext.description,
|
||||||
'version': ext.version,
|
"version": ext.version,
|
||||||
'author': ext.author,
|
"author": ext.author,
|
||||||
'configuration': ext.configuration,
|
"configuration": ext.configuration,
|
||||||
'custom_commands': ext.custom_commands,
|
"custom_commands": ext.custom_commands,
|
||||||
'workflow_hooks': ext.workflow_hooks,
|
"workflow_hooks": ext.workflow_hooks,
|
||||||
'data_transformations': ext.data_transformations,
|
"data_transformations": ext.data_transformations,
|
||||||
'environment_overrides': ext.environment_overrides,
|
"environment_overrides": ext.environment_overrides,
|
||||||
'dependencies': ext.dependencies,
|
"dependencies": ext.dependencies,
|
||||||
'compatibility': ext.compatibility,
|
"compatibility": ext.compatibility,
|
||||||
'enabled': ext.enabled
|
"enabled": ext.enabled,
|
||||||
}
|
}
|
||||||
for ext in extensions
|
for ext in extensions
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
with open(self.config_file, 'w') as f:
|
with open(self.config_file, "w") as f:
|
||||||
yaml.dump(data, f, default_flow_style=False)
|
yaml.dump(data, f, default_flow_style=False)
|
||||||
|
|
||||||
def _toggle_extension(self, name: str, enabled: bool) -> bool:
|
def _toggle_extension(self, name: str, enabled: bool) -> bool:
|
||||||
@@ -321,7 +330,7 @@ class ExtensionManager:
|
|||||||
"name": base_agent,
|
"name": base_agent,
|
||||||
"type": "kaizen_agent",
|
"type": "kaizen_agent",
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
"config": {}
|
"config": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
def _apply_extension_config(
|
def _apply_extension_config(
|
||||||
@@ -343,11 +352,13 @@ class ExtensionManager:
|
|||||||
config.setdefault("environment", {}).update(extension.environment_overrides)
|
config.setdefault("environment", {}).update(extension.environment_overrides)
|
||||||
|
|
||||||
# Add extension metadata
|
# Add extension metadata
|
||||||
config.setdefault("extensions", []).append({
|
config.setdefault("extensions", []).append(
|
||||||
"name": extension.name,
|
{
|
||||||
"type": extension.extension_type.value,
|
"name": extension.name,
|
||||||
"version": extension.version
|
"type": extension.extension_type.value,
|
||||||
})
|
"version": extension.version,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
@@ -370,7 +381,7 @@ class ExtensionManager:
|
|||||||
"functionality": [],
|
"functionality": [],
|
||||||
"config": {},
|
"config": {},
|
||||||
"commands": [],
|
"commands": [],
|
||||||
"dependencies": []
|
"dependencies": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent_path.suffix == ".py":
|
if agent_path.suffix == ".py":
|
||||||
@@ -379,8 +390,9 @@ class ExtensionManager:
|
|||||||
|
|
||||||
# Simple analysis - look for class and function definitions
|
# Simple analysis - look for class and function definitions
|
||||||
import re
|
import re
|
||||||
classes = re.findall(r'class\s+(\w+)', content)
|
|
||||||
functions = re.findall(r'def\s+(\w+)', content)
|
classes = re.findall(r"class\s+(\w+)", content)
|
||||||
|
functions = re.findall(r"def\s+(\w+)", content)
|
||||||
|
|
||||||
analysis["functionality"] = classes + functions
|
analysis["functionality"] = classes + functions
|
||||||
|
|
||||||
@@ -487,10 +499,7 @@ class LegacyWrapper:
|
|||||||
|
|
||||||
|
|
||||||
def create_extension_template(
|
def create_extension_template(
|
||||||
name: str,
|
name: str, base_agent: str, project_path: Path, template_type: str = "basic"
|
||||||
base_agent: str,
|
|
||||||
project_path: Path,
|
|
||||||
template_type: str = "basic"
|
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Create a template for a new agent extension."""
|
"""Create a template for a new agent extension."""
|
||||||
|
|
||||||
@@ -535,7 +544,6 @@ Save this as `.kaizen/extensions/{name}/extension.yml` and run:
|
|||||||
kaizen-agentic extensions install {name}
|
kaizen-agentic extensions install {name}
|
||||||
```
|
```
|
||||||
""",
|
""",
|
||||||
|
|
||||||
"advanced": f"""# Advanced Extension Template: {name}
|
"advanced": f"""# Advanced Extension Template: {name}
|
||||||
|
|
||||||
This template provides advanced customization options for the {base_agent} agent.
|
This template provides advanced customization options for the {base_agent} agent.
|
||||||
@@ -610,7 +618,7 @@ Create these files in `.kaizen/extensions/{name}/scripts/`:
|
|||||||
1. Save the configuration as `.kaizen/extensions/{name}/extension.yml`
|
1. Save the configuration as `.kaizen/extensions/{name}/extension.yml`
|
||||||
2. Add any custom scripts to the scripts directory
|
2. Add any custom scripts to the scripts directory
|
||||||
3. Install with: `kaizen-agentic extensions install {name}`
|
3. Install with: `kaizen-agentic extensions install {name}`
|
||||||
"""
|
""",
|
||||||
}
|
}
|
||||||
|
|
||||||
return templates.get(template_type, templates["basic"])
|
return templates.get(template_type, templates["basic"])
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from .registry import AgentRegistry
|
|||||||
@dataclass
|
@dataclass
|
||||||
class InstallationConfig:
|
class InstallationConfig:
|
||||||
"""Configuration for agent installation."""
|
"""Configuration for agent installation."""
|
||||||
|
|
||||||
target_dir: Path
|
target_dir: Path
|
||||||
claude_config_path: Optional[Path] = None
|
claude_config_path: Optional[Path] = None
|
||||||
makefile_path: Optional[Path] = None
|
makefile_path: Optional[Path] = None
|
||||||
@@ -26,9 +27,7 @@ class AgentInstaller:
|
|||||||
self.registry = registry
|
self.registry = registry
|
||||||
|
|
||||||
def install_agents(
|
def install_agents(
|
||||||
self,
|
self, agent_names: List[str], config: InstallationConfig
|
||||||
agent_names: List[str],
|
|
||||||
config: InstallationConfig
|
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
"""Install agents into a project.
|
"""Install agents into a project.
|
||||||
|
|
||||||
@@ -89,9 +88,7 @@ class AgentInstaller:
|
|||||||
return sorted(installed)
|
return sorted(installed)
|
||||||
|
|
||||||
def update_agents(
|
def update_agents(
|
||||||
self,
|
self, project_dir: Path, agent_names: Optional[List[str]] = None
|
||||||
project_dir: Path,
|
|
||||||
agent_names: Optional[List[str]] = None
|
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
"""Update installed agents to latest versions."""
|
"""Update installed agents to latest versions."""
|
||||||
if agent_names is None:
|
if agent_names is None:
|
||||||
@@ -101,9 +98,7 @@ class AgentInstaller:
|
|||||||
return self.install_agents(agent_names, config)
|
return self.install_agents(agent_names, config)
|
||||||
|
|
||||||
def remove_agents(
|
def remove_agents(
|
||||||
self,
|
self, agent_names: List[str], project_dir: Path
|
||||||
agent_names: List[str],
|
|
||||||
project_dir: Path
|
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
"""Remove agents from a project."""
|
"""Remove agents from a project."""
|
||||||
results = {}
|
results = {}
|
||||||
@@ -162,7 +157,10 @@ class AgentInstaller:
|
|||||||
counter = 0
|
counter = 0
|
||||||
while backup_dir.exists():
|
while backup_dir.exists():
|
||||||
counter += 1
|
counter += 1
|
||||||
backup_dir = agents_dir.parent / f"agents_backup_{timestamp}_{microseconds}_{counter}"
|
backup_dir = (
|
||||||
|
agents_dir.parent
|
||||||
|
/ f"agents_backup_{timestamp}_{microseconds}_{counter}"
|
||||||
|
)
|
||||||
|
|
||||||
shutil.copytree(agents_dir, backup_dir)
|
shutil.copytree(agents_dir, backup_dir)
|
||||||
print(f"Created backup at: {backup_dir}")
|
print(f"Created backup at: {backup_dir}")
|
||||||
@@ -173,22 +171,22 @@ class AgentInstaller:
|
|||||||
# Read existing config
|
# Read existing config
|
||||||
config = {}
|
config = {}
|
||||||
if config_path.exists():
|
if config_path.exists():
|
||||||
with open(config_path, 'r') as f:
|
with open(config_path, "r") as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
|
||||||
# Ensure agents section exists
|
# Ensure agents section exists
|
||||||
if 'agents' not in config:
|
if "agents" not in config:
|
||||||
config['agents'] = {}
|
config["agents"] = {}
|
||||||
|
|
||||||
# Add agent references
|
# Add agent references
|
||||||
for agent_name in agent_names:
|
for agent_name in agent_names:
|
||||||
config['agents'][agent_name] = {
|
config["agents"][agent_name] = {
|
||||||
"path": f"agents/agent-{agent_name}.md",
|
"path": f"agents/agent-{agent_name}.md",
|
||||||
"enabled": True
|
"enabled": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Write updated config
|
# Write updated config
|
||||||
with open(config_path, 'w') as f:
|
with open(config_path, "w") as f:
|
||||||
json.dump(config, f, indent=2)
|
json.dump(config, f, indent=2)
|
||||||
|
|
||||||
print(f"Updated Claude configuration: {config_path}")
|
print(f"Updated Claude configuration: {config_path}")
|
||||||
@@ -200,7 +198,7 @@ class AgentInstaller:
|
|||||||
"""Update Makefile with agent-specific targets."""
|
"""Update Makefile with agent-specific targets."""
|
||||||
try:
|
try:
|
||||||
# Read existing Makefile
|
# Read existing Makefile
|
||||||
with open(makefile_path, 'r') as f:
|
with open(makefile_path, "r") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
# Add agent management targets if not present
|
# Add agent management targets if not present
|
||||||
@@ -224,7 +222,7 @@ agents-validate:
|
|||||||
content += agent_targets
|
content += agent_targets
|
||||||
|
|
||||||
# Write updated Makefile
|
# Write updated Makefile
|
||||||
with open(makefile_path, 'w') as f:
|
with open(makefile_path, "w") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
|
|
||||||
print(f"Updated Makefile: {makefile_path}")
|
print(f"Updated Makefile: {makefile_path}")
|
||||||
@@ -238,7 +236,9 @@ agents-validate:
|
|||||||
claude_md = project_dir / "CLAUDE.md"
|
claude_md = project_dir / "CLAUDE.md"
|
||||||
|
|
||||||
agent_section = "## Installed Agents\n\n"
|
agent_section = "## Installed Agents\n\n"
|
||||||
agent_section += "This project includes the following specialized agents:\n\n"
|
agent_section += (
|
||||||
|
"This project includes the following specialized agents:\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
# Group agents by category
|
# Group agents by category
|
||||||
categories = {}
|
categories = {}
|
||||||
@@ -257,34 +257,37 @@ agents-validate:
|
|||||||
agent_section += f"- **{agent.name}**: {agent.description}\n"
|
agent_section += f"- **{agent.name}**: {agent.description}\n"
|
||||||
agent_section += "\n"
|
agent_section += "\n"
|
||||||
|
|
||||||
agent_section += ("Use these agents by referencing them in your "
|
agent_section += (
|
||||||
"Claude Code interactions.\n\n")
|
"Use these agents by referencing them in your "
|
||||||
|
"Claude Code interactions.\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
# Update or create CLAUDE.md
|
# Update or create CLAUDE.md
|
||||||
if claude_md.exists():
|
if claude_md.exists():
|
||||||
with open(claude_md, 'r') as f:
|
with open(claude_md, "r") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
# Replace existing agent section or append
|
# Replace existing agent section or append
|
||||||
if "## Installed Agents" in content:
|
if "## Installed Agents" in content:
|
||||||
import re
|
import re
|
||||||
|
|
||||||
content = re.sub(
|
content = re.sub(
|
||||||
r'## Installed Agents.*?(?=##|\Z)',
|
r"## Installed Agents.*?(?=##|\Z)",
|
||||||
agent_section,
|
agent_section,
|
||||||
content,
|
content,
|
||||||
flags=re.DOTALL
|
flags=re.DOTALL,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
content += "\n" + agent_section
|
content += "\n" + agent_section
|
||||||
|
|
||||||
with open(claude_md, 'w') as f:
|
with open(claude_md, "w") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
else:
|
else:
|
||||||
# Create new CLAUDE.md
|
# Create new CLAUDE.md
|
||||||
header = "# Claude Code Configuration\n\n"
|
header = "# Claude Code Configuration\n\n"
|
||||||
header += "This file contains Claude Code configuration and agent information.\n\n"
|
header += "This file contains Claude Code configuration and agent information.\n\n"
|
||||||
|
|
||||||
with open(claude_md, 'w') as f:
|
with open(claude_md, "w") as f:
|
||||||
f.write(header + agent_section)
|
f.write(header + agent_section)
|
||||||
|
|
||||||
print(f"Updated documentation: {claude_md}")
|
print(f"Updated documentation: {claude_md}")
|
||||||
@@ -304,7 +307,7 @@ class ProjectInitializer:
|
|||||||
project_dir: Path,
|
project_dir: Path,
|
||||||
template: str = "python-basic",
|
template: str = "python-basic",
|
||||||
agent_names: Optional[List[str]] = None,
|
agent_names: Optional[List[str]] = None,
|
||||||
project_name: Optional[str] = None
|
project_name: Optional[str] = None,
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
"""Initialize a new project with agents and structure."""
|
"""Initialize a new project with agents and structure."""
|
||||||
results = {}
|
results = {}
|
||||||
@@ -325,7 +328,7 @@ class ProjectInitializer:
|
|||||||
config = InstallationConfig(
|
config = InstallationConfig(
|
||||||
target_dir=project_dir,
|
target_dir=project_dir,
|
||||||
claude_config_path=project_dir / "CLAUDE.md",
|
claude_config_path=project_dir / "CLAUDE.md",
|
||||||
makefile_path=project_dir / "Makefile"
|
makefile_path=project_dir / "Makefile",
|
||||||
)
|
)
|
||||||
|
|
||||||
installer = AgentInstaller(self.registry)
|
installer = AgentInstaller(self.registry)
|
||||||
@@ -337,12 +340,16 @@ class ProjectInitializer:
|
|||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _create_project_structure(self, project_dir: Path, project_name: str, template: str):
|
def _create_project_structure(
|
||||||
|
self, project_dir: Path, project_name: str, template: str
|
||||||
|
):
|
||||||
"""Create basic project structure based on template."""
|
"""Create basic project structure based on template."""
|
||||||
# Create directories
|
# Create directories
|
||||||
dirs_to_create = ["src", "tests", "docs"]
|
dirs_to_create = ["src", "tests", "docs"]
|
||||||
if template.startswith("python"):
|
if template.startswith("python"):
|
||||||
dirs_to_create.extend([f"src/{project_name.replace('-', '_')}", ".github/workflows"])
|
dirs_to_create.extend(
|
||||||
|
[f"src/{project_name.replace('-', '_')}", ".github/workflows"]
|
||||||
|
)
|
||||||
|
|
||||||
for dir_name in dirs_to_create:
|
for dir_name in dirs_to_create:
|
||||||
(project_dir / dir_name).mkdir(parents=True, exist_ok=True)
|
(project_dir / dir_name).mkdir(parents=True, exist_ok=True)
|
||||||
@@ -501,7 +508,7 @@ python_functions = ["test_*"]
|
|||||||
|
|
||||||
def _create_init_py(self, project_dir: Path, project_name: str):
|
def _create_init_py(self, project_dir: Path, project_name: str):
|
||||||
"""Create package __init__.py file."""
|
"""Create package __init__.py file."""
|
||||||
package_name = project_name.replace('-', '_')
|
package_name = project_name.replace("-", "_")
|
||||||
init_content = f'''"""
|
init_content = f'''"""
|
||||||
{project_name} - A Python project with Kaizen Agentic agents.
|
{project_name} - A Python project with Kaizen Agentic agents.
|
||||||
"""
|
"""
|
||||||
@@ -512,7 +519,7 @@ __version__ = "0.1.0"
|
|||||||
|
|
||||||
def _create_makefile(self, project_dir: Path, project_name: str):
|
def _create_makefile(self, project_dir: Path, project_name: str):
|
||||||
"""Create Makefile with standard targets."""
|
"""Create Makefile with standard targets."""
|
||||||
package_name = project_name.replace('-', '_')
|
package_name = project_name.replace("-", "_")
|
||||||
makefile_content = f"""# {project_name} - Makefile for development workflow
|
makefile_content = f"""# {project_name} - Makefile for development workflow
|
||||||
# Generated by Kaizen Agentic
|
# Generated by Kaizen Agentic
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from .detection import AgentSystemDetector, DetectedAgent, AgentSystemType
|
|||||||
|
|
||||||
class MigrationStrategy(Enum):
|
class MigrationStrategy(Enum):
|
||||||
"""Strategies for migrating existing agents."""
|
"""Strategies for migrating existing agents."""
|
||||||
|
|
||||||
REPLACE = "replace" # Replace with Kaizen equivalent
|
REPLACE = "replace" # Replace with Kaizen equivalent
|
||||||
EXTEND = "extend" # Extend Kaizen agent with custom functionality
|
EXTEND = "extend" # Extend Kaizen agent with custom functionality
|
||||||
PRESERVE = "preserve" # Keep custom agent alongside Kaizen agents
|
PRESERVE = "preserve" # Keep custom agent alongside Kaizen agents
|
||||||
@@ -22,6 +23,7 @@ class MigrationStrategy(Enum):
|
|||||||
|
|
||||||
class ConflictResolution(Enum):
|
class ConflictResolution(Enum):
|
||||||
"""Ways to resolve conflicts between agents."""
|
"""Ways to resolve conflicts between agents."""
|
||||||
|
|
||||||
RENAME = "rename" # Rename one of the conflicting agents
|
RENAME = "rename" # Rename one of the conflicting agents
|
||||||
NAMESPACE = "namespace" # Put agents in different namespaces
|
NAMESPACE = "namespace" # Put agents in different namespaces
|
||||||
MERGE_FUNCTIONALITY = "merge" # Combine functionality
|
MERGE_FUNCTIONALITY = "merge" # Combine functionality
|
||||||
@@ -33,6 +35,7 @@ class ConflictResolution(Enum):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class MigrationPlan:
|
class MigrationPlan:
|
||||||
"""Plan for migrating an existing agent."""
|
"""Plan for migrating an existing agent."""
|
||||||
|
|
||||||
source_agent: DetectedAgent
|
source_agent: DetectedAgent
|
||||||
strategy: MigrationStrategy
|
strategy: MigrationStrategy
|
||||||
target_agent: Optional[str] = None # Kaizen agent name if applicable
|
target_agent: Optional[str] = None # Kaizen agent name if applicable
|
||||||
@@ -48,6 +51,7 @@ class MigrationPlan:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class ConflictResolutionPlan:
|
class ConflictResolutionPlan:
|
||||||
"""Plan for resolving a conflict between agents."""
|
"""Plan for resolving a conflict between agents."""
|
||||||
|
|
||||||
agent1: str
|
agent1: str
|
||||||
agent2: str
|
agent2: str
|
||||||
conflict_type: str
|
conflict_type: str
|
||||||
@@ -62,6 +66,7 @@ class ConflictResolutionPlan:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class IntegrationPlan:
|
class IntegrationPlan:
|
||||||
"""Complete plan for integrating Kaizen agents into an existing project."""
|
"""Complete plan for integrating Kaizen agents into an existing project."""
|
||||||
|
|
||||||
project_path: Path
|
project_path: Path
|
||||||
migration_plans: List[MigrationPlan]
|
migration_plans: List[MigrationPlan]
|
||||||
conflict_resolutions: List[ConflictResolutionPlan]
|
conflict_resolutions: List[ConflictResolutionPlan]
|
||||||
@@ -104,10 +109,18 @@ class AgentMigrationPlanner:
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.functional_categories = {
|
self.functional_categories = {
|
||||||
"project_management": ["keepaTodofile", "project-management", "priority-evaluation"],
|
"project_management": [
|
||||||
|
"keepaTodofile",
|
||||||
|
"project-management",
|
||||||
|
"priority-evaluation",
|
||||||
|
],
|
||||||
"testing": ["testing-efficiency", "test-maintenance", "tdd-workflow"],
|
"testing": ["testing-efficiency", "test-maintenance", "tdd-workflow"],
|
||||||
"documentation": ["claude-documentation", "keepaContributingfile"],
|
"documentation": ["claude-documentation", "keepaContributingfile"],
|
||||||
"code_quality": ["code-refactoring", "datamodel-optimization", "optimization"],
|
"code_quality": [
|
||||||
|
"code-refactoring",
|
||||||
|
"datamodel-optimization",
|
||||||
|
"optimization",
|
||||||
|
],
|
||||||
"infrastructure": ["setupRepository", "tooling-optimization"],
|
"infrastructure": ["setupRepository", "tooling-optimization"],
|
||||||
"version_control": ["keepaChangelog"],
|
"version_control": ["keepaChangelog"],
|
||||||
}
|
}
|
||||||
@@ -118,7 +131,9 @@ class AgentMigrationPlanner:
|
|||||||
detection_result = detector.detect_agent_systems(project_path)
|
detection_result = detector.detect_agent_systems(project_path)
|
||||||
|
|
||||||
# Create backup directory
|
# Create backup directory
|
||||||
backup_dir = project_path / f".kaizen-migration-backup-{int(Path().stat().st_mtime)}"
|
backup_dir = (
|
||||||
|
project_path / f".kaizen-migration-backup-{int(Path().stat().st_mtime)}"
|
||||||
|
)
|
||||||
|
|
||||||
# Create migration plans for each detected agent
|
# Create migration plans for each detected agent
|
||||||
migration_plans = []
|
migration_plans = []
|
||||||
@@ -145,7 +160,7 @@ class AgentMigrationPlanner:
|
|||||||
conflict_resolutions=conflict_resolutions,
|
conflict_resolutions=conflict_resolutions,
|
||||||
backup_directory=backup_dir,
|
backup_directory=backup_dir,
|
||||||
integration_order=integration_order,
|
integration_order=integration_order,
|
||||||
post_migration_tasks=post_migration_tasks
|
post_migration_tasks=post_migration_tasks,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _create_migration_plan(
|
def _create_migration_plan(
|
||||||
@@ -190,7 +205,7 @@ class AgentMigrationPlanner:
|
|||||||
strategy=strategy,
|
strategy=strategy,
|
||||||
target_agent=target_agent,
|
target_agent=target_agent,
|
||||||
backup_path=backup_path,
|
backup_path=backup_path,
|
||||||
migration_notes=notes
|
migration_notes=notes,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _has_unique_functionality(self, agent: DetectedAgent) -> bool:
|
def _has_unique_functionality(self, agent: DetectedAgent) -> bool:
|
||||||
@@ -203,8 +218,18 @@ class AgentMigrationPlanner:
|
|||||||
"""Check if a custom agent is essential to the project."""
|
"""Check if a custom agent is essential to the project."""
|
||||||
# Heuristics for essential agents
|
# Heuristics for essential agents
|
||||||
essential_patterns = [
|
essential_patterns = [
|
||||||
"deploy", "ci", "cd", "build", "release", "secret", "auth",
|
"deploy",
|
||||||
"database", "api", "server", "client", "integration"
|
"ci",
|
||||||
|
"cd",
|
||||||
|
"build",
|
||||||
|
"release",
|
||||||
|
"secret",
|
||||||
|
"auth",
|
||||||
|
"database",
|
||||||
|
"api",
|
||||||
|
"server",
|
||||||
|
"client",
|
||||||
|
"integration",
|
||||||
]
|
]
|
||||||
|
|
||||||
agent_name_lower = agent.name.lower()
|
agent_name_lower = agent.name.lower()
|
||||||
@@ -230,7 +255,7 @@ class AgentMigrationPlanner:
|
|||||||
resolution = ConflictResolution.RENAME
|
resolution = ConflictResolution.RENAME
|
||||||
action_details = {
|
action_details = {
|
||||||
"rename_agent": agent2, # Rename the second agent
|
"rename_agent": agent2, # Rename the second agent
|
||||||
"new_name": f"{agent2}_custom"
|
"new_name": f"{agent2}_custom",
|
||||||
}
|
}
|
||||||
elif "Functional overlap" in reason:
|
elif "Functional overlap" in reason:
|
||||||
# Check if one is a Kaizen agent
|
# Check if one is a Kaizen agent
|
||||||
@@ -252,10 +277,12 @@ class AgentMigrationPlanner:
|
|||||||
agent2=agent2,
|
agent2=agent2,
|
||||||
conflict_type=reason,
|
conflict_type=reason,
|
||||||
resolution=resolution,
|
resolution=resolution,
|
||||||
action_details=action_details
|
action_details=action_details,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _determine_integration_order(self, migration_plans: List[MigrationPlan]) -> List[str]:
|
def _determine_integration_order(
|
||||||
|
self, migration_plans: List[MigrationPlan]
|
||||||
|
) -> List[str]:
|
||||||
"""Determine the order to perform migrations."""
|
"""Determine the order to perform migrations."""
|
||||||
# Order by dependency and risk
|
# Order by dependency and risk
|
||||||
order = []
|
order = []
|
||||||
@@ -265,7 +292,11 @@ class AgentMigrationPlanner:
|
|||||||
order.extend([p.source_agent.name for p in infra_agents])
|
order.extend([p.source_agent.name for p in infra_agents])
|
||||||
|
|
||||||
# 2. Core functionality agents
|
# 2. Core functionality agents
|
||||||
core_agents = [p for p in migration_plans if self._is_core_agent(p) and p not in infra_agents]
|
core_agents = [
|
||||||
|
p
|
||||||
|
for p in migration_plans
|
||||||
|
if self._is_core_agent(p) and p not in infra_agents
|
||||||
|
]
|
||||||
order.extend([p.source_agent.name for p in core_agents])
|
order.extend([p.source_agent.name for p in core_agents])
|
||||||
|
|
||||||
# 3. Optional/enhancement agents last
|
# 3. Optional/enhancement agents last
|
||||||
@@ -287,7 +318,10 @@ class AgentMigrationPlanner:
|
|||||||
return any(keyword in agent_name for keyword in core_keywords)
|
return any(keyword in agent_name for keyword in core_keywords)
|
||||||
|
|
||||||
def _generate_migration_notes(
|
def _generate_migration_notes(
|
||||||
self, agent: DetectedAgent, strategy: MigrationStrategy, target_agent: Optional[str]
|
self,
|
||||||
|
agent: DetectedAgent,
|
||||||
|
strategy: MigrationStrategy,
|
||||||
|
target_agent: Optional[str],
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
"""Generate helpful notes for the migration."""
|
"""Generate helpful notes for the migration."""
|
||||||
notes = []
|
notes = []
|
||||||
@@ -332,13 +366,15 @@ class AgentMigrationPlanner:
|
|||||||
if detection_result.config_files:
|
if detection_result.config_files:
|
||||||
tasks.append("Verify all configuration files are updated")
|
tasks.append("Verify all configuration files are updated")
|
||||||
|
|
||||||
tasks.extend([
|
tasks.extend(
|
||||||
"Run 'kaizen-agentic validate' to verify installation",
|
[
|
||||||
"Test all agent functionality",
|
"Run 'kaizen-agentic validate' to verify installation",
|
||||||
"Update project documentation",
|
"Test all agent functionality",
|
||||||
"Train team on new agent workflows",
|
"Update project documentation",
|
||||||
"Archive or remove backup files after verification"
|
"Train team on new agent workflows",
|
||||||
])
|
"Archive or remove backup files after verification",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
return tasks
|
return tasks
|
||||||
|
|
||||||
@@ -349,7 +385,9 @@ class AgentMigrator:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.planner = AgentMigrationPlanner()
|
self.planner = AgentMigrationPlanner()
|
||||||
|
|
||||||
def execute_migration(self, plan: IntegrationPlan, dry_run: bool = True) -> Dict[str, str]:
|
def execute_migration(
|
||||||
|
self, plan: IntegrationPlan, dry_run: bool = True
|
||||||
|
) -> Dict[str, str]:
|
||||||
"""Execute a migration plan."""
|
"""Execute a migration plan."""
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
@@ -361,7 +399,7 @@ class AgentMigrator:
|
|||||||
for agent_name in plan.integration_order:
|
for agent_name in plan.integration_order:
|
||||||
migration_plan = next(
|
migration_plan = next(
|
||||||
(p for p in plan.migration_plans if p.source_agent.name == agent_name),
|
(p for p in plan.migration_plans if p.source_agent.name == agent_name),
|
||||||
None
|
None,
|
||||||
)
|
)
|
||||||
if migration_plan:
|
if migration_plan:
|
||||||
result = self._execute_single_migration(migration_plan, dry_run)
|
result = self._execute_single_migration(migration_plan, dry_run)
|
||||||
@@ -413,11 +451,14 @@ class AgentMigrator:
|
|||||||
extension_config = {
|
extension_config = {
|
||||||
"base_agent": plan.target_agent,
|
"base_agent": plan.target_agent,
|
||||||
"custom_source": str(plan.source_agent.file_path),
|
"custom_source": str(plan.source_agent.file_path),
|
||||||
"extension_type": "functional_overlay"
|
"extension_type": "functional_overlay",
|
||||||
}
|
}
|
||||||
|
|
||||||
extension_path = plan.source_agent.file_path.parent / f"{plan.source_agent.name}_extension.json"
|
extension_path = (
|
||||||
with open(extension_path, 'w') as f:
|
plan.source_agent.file_path.parent
|
||||||
|
/ f"{plan.source_agent.name}_extension.json"
|
||||||
|
)
|
||||||
|
with open(extension_path, "w") as f:
|
||||||
json.dump(extension_config, f, indent=2)
|
json.dump(extension_config, f, indent=2)
|
||||||
|
|
||||||
return f"EXTENDED: {plan.target_agent} with {plan.source_agent.name}"
|
return f"EXTENDED: {plan.target_agent} with {plan.source_agent.name}"
|
||||||
@@ -427,7 +468,10 @@ class AgentMigrator:
|
|||||||
# Rename if necessary to avoid conflicts
|
# Rename if necessary to avoid conflicts
|
||||||
if plan.source_agent.name in ["todo", "changelog", "test"]:
|
if plan.source_agent.name in ["todo", "changelog", "test"]:
|
||||||
new_name = f"{plan.source_agent.name}_custom"
|
new_name = f"{plan.source_agent.name}_custom"
|
||||||
new_path = plan.source_agent.file_path.parent / f"{new_name}{plan.source_agent.file_path.suffix}"
|
new_path = (
|
||||||
|
plan.source_agent.file_path.parent
|
||||||
|
/ f"{new_name}{plan.source_agent.file_path.suffix}"
|
||||||
|
)
|
||||||
shutil.move(plan.source_agent.file_path, new_path)
|
shutil.move(plan.source_agent.file_path, new_path)
|
||||||
return f"PRESERVED: {plan.source_agent.name} -> {new_name}"
|
return f"PRESERVED: {plan.source_agent.name} -> {new_name}"
|
||||||
|
|
||||||
@@ -458,4 +502,4 @@ class AgentMigrator:
|
|||||||
elif plan.resolution == ConflictResolution.CHOOSE_KAIZEN:
|
elif plan.resolution == ConflictResolution.CHOOSE_KAIZEN:
|
||||||
return f"RESOLVED: Chose Kaizen agent {plan.action_details['keep']}"
|
return f"RESOLVED: Chose Kaizen agent {plan.action_details['keep']}"
|
||||||
else:
|
else:
|
||||||
return f"RESOLUTION_PLANNED: {plan.resolution.value}"
|
return f"RESOLUTION_PLANNED: {plan.resolution.value}"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from enum import Enum
|
|||||||
|
|
||||||
class AgentCategory(Enum):
|
class AgentCategory(Enum):
|
||||||
"""Categories of agents for organization."""
|
"""Categories of agents for organization."""
|
||||||
|
|
||||||
PROJECT_MANAGEMENT = "project-management"
|
PROJECT_MANAGEMENT = "project-management"
|
||||||
DEVELOPMENT_PROCESS = "development-process"
|
DEVELOPMENT_PROCESS = "development-process"
|
||||||
CODE_QUALITY = "code-quality"
|
CODE_QUALITY = "code-quality"
|
||||||
@@ -21,6 +22,7 @@ class AgentCategory(Enum):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class AgentDefinition:
|
class AgentDefinition:
|
||||||
"""Represents an agent definition with metadata."""
|
"""Represents an agent definition with metadata."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
description: str
|
description: str
|
||||||
file_path: Path
|
file_path: Path
|
||||||
@@ -31,11 +33,11 @@ class AgentDefinition:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_file(cls, file_path: Path) -> "AgentDefinition":
|
def from_file(cls, file_path: Path) -> "AgentDefinition":
|
||||||
"""Create AgentDefinition from a markdown file."""
|
"""Create AgentDefinition from a markdown file."""
|
||||||
with open(file_path, 'r', encoding='utf-8') as f:
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
# Extract YAML frontmatter
|
# Extract YAML frontmatter
|
||||||
frontmatter_match = re.match(r'^---\n(.*?)\n---\n', content, re.DOTALL)
|
frontmatter_match = re.match(r"^---\n(.*?)\n---\n", content, re.DOTALL)
|
||||||
if not frontmatter_match:
|
if not frontmatter_match:
|
||||||
raise ValueError(f"No YAML frontmatter found in {file_path}")
|
raise ValueError(f"No YAML frontmatter found in {file_path}")
|
||||||
|
|
||||||
@@ -45,15 +47,15 @@ class AgentDefinition:
|
|||||||
dependencies = cls._extract_dependencies(content, frontmatter)
|
dependencies = cls._extract_dependencies(content, frontmatter)
|
||||||
|
|
||||||
# Determine category from name or content
|
# Determine category from name or content
|
||||||
category = cls._determine_category(frontmatter['name'], content)
|
category = cls._determine_category(frontmatter["name"], content)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
name=frontmatter['name'],
|
name=frontmatter["name"],
|
||||||
description=frontmatter['description'],
|
description=frontmatter["description"],
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
category=category,
|
category=category,
|
||||||
dependencies=dependencies,
|
dependencies=dependencies,
|
||||||
model=frontmatter.get('model')
|
model=frontmatter.get("model"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -62,42 +64,42 @@ class AgentDefinition:
|
|||||||
dependencies = set()
|
dependencies = set()
|
||||||
|
|
||||||
# Check frontmatter for explicit dependencies
|
# Check frontmatter for explicit dependencies
|
||||||
for key in ['dependencies', 'depends_on', 'requires']:
|
for key in ["dependencies", "depends_on", "requires"]:
|
||||||
if key in frontmatter:
|
if key in frontmatter:
|
||||||
deps = frontmatter[key]
|
deps = frontmatter[key]
|
||||||
if isinstance(deps, list):
|
if isinstance(deps, list):
|
||||||
dependencies.update(deps)
|
dependencies.update(deps)
|
||||||
elif isinstance(deps, str):
|
elif isinstance(deps, str):
|
||||||
# Handle comma-separated string
|
# Handle comma-separated string
|
||||||
dependencies.update([d.strip() for d in deps.split(',')])
|
dependencies.update([d.strip() for d in deps.split(",")])
|
||||||
|
|
||||||
# Look for explicit dependencies in content
|
# Look for explicit dependencies in content
|
||||||
dep_patterns = [
|
dep_patterns = [
|
||||||
r'depends_on:\s*\[(.*?)\]',
|
r"depends_on:\s*\[(.*?)\]",
|
||||||
r'requires:\s*\[(.*?)\]',
|
r"requires:\s*\[(.*?)\]",
|
||||||
r'dependencies:\s*\[(.*?)\]',
|
r"dependencies:\s*\[(.*?)\]",
|
||||||
]
|
]
|
||||||
|
|
||||||
for pattern in dep_patterns:
|
for pattern in dep_patterns:
|
||||||
matches = re.findall(pattern, content, re.IGNORECASE)
|
matches = re.findall(pattern, content, re.IGNORECASE)
|
||||||
for match in matches:
|
for match in matches:
|
||||||
if isinstance(match, str):
|
if isinstance(match, str):
|
||||||
deps = [d.strip().strip('"\'') for d in match.split(',')]
|
deps = [d.strip().strip("\"'") for d in match.split(",")]
|
||||||
dependencies.update(deps)
|
dependencies.update(deps)
|
||||||
|
|
||||||
# Look for specific agent references in content (more precise)
|
# Look for specific agent references in content (more precise)
|
||||||
# Only look for full agent names like "todo-keeper agent" or "uses changelog-keeper"
|
# Only look for full agent names like "todo-keeper agent" or "uses changelog-keeper"
|
||||||
agent_patterns = [
|
agent_patterns = [
|
||||||
r'uses?\s+(\w+(?:-\w+)*-(?:keeper|agent|workflow|helper|manager))',
|
r"uses?\s+(\w+(?:-\w+)*-(?:keeper|agent|workflow|helper|manager))",
|
||||||
r'depends?\s+on\s+(\w+(?:-\w+)*-(?:keeper|agent|workflow|helper|manager))',
|
r"depends?\s+on\s+(\w+(?:-\w+)*-(?:keeper|agent|workflow|helper|manager))",
|
||||||
r'requires?\s+(\w+(?:-\w+)*-(?:keeper|agent|workflow|helper|manager))',
|
r"requires?\s+(\w+(?:-\w+)*-(?:keeper|agent|workflow|helper|manager))",
|
||||||
]
|
]
|
||||||
|
|
||||||
for pattern in agent_patterns:
|
for pattern in agent_patterns:
|
||||||
matches = re.findall(pattern, content.lower())
|
matches = re.findall(pattern, content.lower())
|
||||||
for match in matches:
|
for match in matches:
|
||||||
if match not in ['optimization', 'agentic', 'driven', 'assisted']:
|
if match not in ["optimization", "agentic", "driven", "assisted"]:
|
||||||
dependencies.add(match.replace('-', '_'))
|
dependencies.add(match.replace("-", "_"))
|
||||||
|
|
||||||
return dependencies
|
return dependencies
|
||||||
|
|
||||||
@@ -107,28 +109,33 @@ class AgentDefinition:
|
|||||||
name_lower = name.lower()
|
name_lower = name.lower()
|
||||||
|
|
||||||
# Project management agents
|
# Project management agents
|
||||||
project_keywords = ['todo', 'changelog', 'contributing', 'project']
|
project_keywords = ["todo", "changelog", "contributing", "project"]
|
||||||
if any(keyword in name_lower for keyword in project_keywords):
|
if any(keyword in name_lower for keyword in project_keywords):
|
||||||
return AgentCategory.PROJECT_MANAGEMENT
|
return AgentCategory.PROJECT_MANAGEMENT
|
||||||
|
|
||||||
# Testing agents
|
# Testing agents
|
||||||
if any(keyword in name_lower for keyword in ['test', 'tdd']):
|
if any(keyword in name_lower for keyword in ["test", "tdd"]):
|
||||||
return AgentCategory.TESTING
|
return AgentCategory.TESTING
|
||||||
|
|
||||||
# Code quality agents
|
# Code quality agents
|
||||||
if any(keyword in name_lower for keyword in ['refactor', 'optimization', 'code']):
|
if any(
|
||||||
|
keyword in name_lower for keyword in ["refactor", "optimization", "code"]
|
||||||
|
):
|
||||||
return AgentCategory.CODE_QUALITY
|
return AgentCategory.CODE_QUALITY
|
||||||
|
|
||||||
# Documentation agents
|
# Documentation agents
|
||||||
if any(keyword in name_lower for keyword in ['documentation', 'claude']):
|
if any(keyword in name_lower for keyword in ["documentation", "claude"]):
|
||||||
return AgentCategory.DOCUMENTATION
|
return AgentCategory.DOCUMENTATION
|
||||||
|
|
||||||
# Infrastructure agents
|
# Infrastructure agents
|
||||||
if any(keyword in name_lower for keyword in ['setup', 'repository', 'tooling']):
|
if any(keyword in name_lower for keyword in ["setup", "repository", "tooling"]):
|
||||||
return AgentCategory.INFRASTRUCTURE
|
return AgentCategory.INFRASTRUCTURE
|
||||||
|
|
||||||
# Development process agents
|
# Development process agents
|
||||||
if any(keyword in name_lower for keyword in ['workflow', 'requirements', 'maintenance']):
|
if any(
|
||||||
|
keyword in name_lower
|
||||||
|
for keyword in ["workflow", "requirements", "maintenance"]
|
||||||
|
):
|
||||||
return AgentCategory.DEVELOPMENT_PROCESS
|
return AgentCategory.DEVELOPMENT_PROCESS
|
||||||
|
|
||||||
# Default fallback
|
# Default fallback
|
||||||
@@ -159,7 +166,9 @@ class AgentRegistry:
|
|||||||
"""Get agent definition by name."""
|
"""Get agent definition by name."""
|
||||||
return self._agents.get(name)
|
return self._agents.get(name)
|
||||||
|
|
||||||
def list_agents(self, category: Optional[AgentCategory] = None) -> List[AgentDefinition]:
|
def list_agents(
|
||||||
|
self, category: Optional[AgentCategory] = None
|
||||||
|
) -> List[AgentDefinition]:
|
||||||
"""List all agents, optionally filtered by category."""
|
"""List all agents, optionally filtered by category."""
|
||||||
agents = list(self._agents.values())
|
agents = list(self._agents.values())
|
||||||
if category:
|
if category:
|
||||||
@@ -232,7 +241,9 @@ class AgentRegistry:
|
|||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
def _has_circular_dependency(self, agent_name: str, visited: Optional[Set[str]] = None) -> bool:
|
def _has_circular_dependency(
|
||||||
|
self, agent_name: str, visited: Optional[Set[str]] = None
|
||||||
|
) -> bool:
|
||||||
"""Check if an agent has circular dependencies."""
|
"""Check if an agent has circular dependencies."""
|
||||||
if visited is None:
|
if visited is None:
|
||||||
visited = set()
|
visited = set()
|
||||||
@@ -255,18 +266,14 @@ class AgentRegistry:
|
|||||||
def get_agent_templates(self) -> Dict[str, List[str]]:
|
def get_agent_templates(self) -> Dict[str, List[str]]:
|
||||||
"""Get predefined agent templates for different project types."""
|
"""Get predefined agent templates for different project types."""
|
||||||
return {
|
return {
|
||||||
"python-basic": [
|
"python-basic": ["setupRepository", "keepaTodofile", "keepaChangelog"],
|
||||||
"setupRepository",
|
|
||||||
"keepaTodofile",
|
|
||||||
"keepaChangelog"
|
|
||||||
],
|
|
||||||
"python-web": [
|
"python-web": [
|
||||||
"setupRepository",
|
"setupRepository",
|
||||||
"tdd-workflow",
|
"tdd-workflow",
|
||||||
"code-refactoring",
|
"code-refactoring",
|
||||||
"keepaTodofile",
|
"keepaTodofile",
|
||||||
"keepaChangelog",
|
"keepaChangelog",
|
||||||
"keepaContributingfile"
|
"keepaContributingfile",
|
||||||
],
|
],
|
||||||
"python-cli": [
|
"python-cli": [
|
||||||
"setupRepository",
|
"setupRepository",
|
||||||
@@ -274,7 +281,7 @@ class AgentRegistry:
|
|||||||
"testing-efficiency",
|
"testing-efficiency",
|
||||||
"claude-documentation",
|
"claude-documentation",
|
||||||
"keepaTodofile",
|
"keepaTodofile",
|
||||||
"keepaChangelog"
|
"keepaChangelog",
|
||||||
],
|
],
|
||||||
"python-data": [
|
"python-data": [
|
||||||
"setupRepository",
|
"setupRepository",
|
||||||
@@ -282,9 +289,7 @@ class AgentRegistry:
|
|||||||
"testing-efficiency",
|
"testing-efficiency",
|
||||||
"requirements-engineering",
|
"requirements-engineering",
|
||||||
"keepaTodofile",
|
"keepaTodofile",
|
||||||
"keepaChangelog"
|
"keepaChangelog",
|
||||||
],
|
],
|
||||||
"comprehensive": [
|
"comprehensive": [agent.name for agent in self.list_agents()],
|
||||||
agent.name for agent in self.list_agents()
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,11 @@
|
|||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from kaizen_agentic.installer import AgentInstaller, ProjectInitializer, InstallationConfig
|
from kaizen_agentic.installer import (
|
||||||
|
AgentInstaller,
|
||||||
|
ProjectInitializer,
|
||||||
|
InstallationConfig,
|
||||||
|
)
|
||||||
from kaizen_agentic.registry import AgentRegistry
|
from kaizen_agentic.registry import AgentRegistry
|
||||||
|
|
||||||
|
|
||||||
@@ -72,9 +76,7 @@ def test_install_agents(test_registry, tmp_path):
|
|||||||
project_dir = tmp_path / "test_project"
|
project_dir = tmp_path / "test_project"
|
||||||
|
|
||||||
config = InstallationConfig(
|
config = InstallationConfig(
|
||||||
target_dir=project_dir,
|
target_dir=project_dir, create_backup=False, update_docs=False
|
||||||
create_backup=False,
|
|
||||||
update_docs=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
results = installer.install_agents(["base-agent"], config)
|
results = installer.install_agents(["base-agent"], config)
|
||||||
@@ -89,9 +91,7 @@ def test_install_agents_with_dependencies(test_registry, tmp_path):
|
|||||||
project_dir = tmp_path / "test_project"
|
project_dir = tmp_path / "test_project"
|
||||||
|
|
||||||
config = InstallationConfig(
|
config = InstallationConfig(
|
||||||
target_dir=project_dir,
|
target_dir=project_dir, create_backup=False, update_docs=False
|
||||||
create_backup=False,
|
|
||||||
update_docs=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install an agent that depends on others
|
# Install an agent that depends on others
|
||||||
@@ -111,7 +111,9 @@ def test_list_installed_agents(test_registry, tmp_path):
|
|||||||
assert installed == []
|
assert installed == []
|
||||||
|
|
||||||
# Install some agents
|
# Install some agents
|
||||||
config = InstallationConfig(target_dir=project_dir, create_backup=False, update_docs=False)
|
config = InstallationConfig(
|
||||||
|
target_dir=project_dir, create_backup=False, update_docs=False
|
||||||
|
)
|
||||||
installer.install_agents(["base-agent", "keepaTodofile"], config)
|
installer.install_agents(["base-agent", "keepaTodofile"], config)
|
||||||
|
|
||||||
# Check installed agents
|
# Check installed agents
|
||||||
@@ -127,7 +129,9 @@ def test_update_agents(test_registry, tmp_path):
|
|||||||
project_dir = tmp_path / "test_project"
|
project_dir = tmp_path / "test_project"
|
||||||
|
|
||||||
# Install initial agents
|
# Install initial agents
|
||||||
config = InstallationConfig(target_dir=project_dir, create_backup=False, update_docs=False)
|
config = InstallationConfig(
|
||||||
|
target_dir=project_dir, create_backup=False, update_docs=False
|
||||||
|
)
|
||||||
installer.install_agents(["base-agent"], config)
|
installer.install_agents(["base-agent"], config)
|
||||||
|
|
||||||
# Update all agents
|
# Update all agents
|
||||||
@@ -146,7 +150,9 @@ def test_remove_agents(test_registry, tmp_path):
|
|||||||
project_dir = tmp_path / "test_project"
|
project_dir = tmp_path / "test_project"
|
||||||
|
|
||||||
# Install agents first
|
# Install agents first
|
||||||
config = InstallationConfig(target_dir=project_dir, create_backup=False, update_docs=False)
|
config = InstallationConfig(
|
||||||
|
target_dir=project_dir, create_backup=False, update_docs=False
|
||||||
|
)
|
||||||
installer.install_agents(["base-agent", "keepaTodofile"], config)
|
installer.install_agents(["base-agent", "keepaTodofile"], config)
|
||||||
|
|
||||||
# Remove an agent
|
# Remove an agent
|
||||||
@@ -170,7 +176,9 @@ def test_validate_installation(test_registry, tmp_path):
|
|||||||
assert "No agents directory found" in errors["project"]
|
assert "No agents directory found" in errors["project"]
|
||||||
|
|
||||||
# Install agents and validate
|
# Install agents and validate
|
||||||
config = InstallationConfig(target_dir=project_dir, create_backup=False, update_docs=False)
|
config = InstallationConfig(
|
||||||
|
target_dir=project_dir, create_backup=False, update_docs=False
|
||||||
|
)
|
||||||
installer.install_agents(["base-agent"], config)
|
installer.install_agents(["base-agent"], config)
|
||||||
|
|
||||||
errors = installer.validate_installation(project_dir)
|
errors = installer.validate_installation(project_dir)
|
||||||
@@ -187,7 +195,7 @@ def test_update_claude_config(test_registry, tmp_path):
|
|||||||
target_dir=project_dir,
|
target_dir=project_dir,
|
||||||
claude_config_path=claude_config,
|
claude_config_path=claude_config,
|
||||||
create_backup=False,
|
create_backup=False,
|
||||||
update_docs=False
|
update_docs=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
installer.install_agents(["base-agent"], config)
|
installer.install_agents(["base-agent"], config)
|
||||||
@@ -208,9 +216,7 @@ def test_project_initializer(test_registry, tmp_path):
|
|||||||
project_dir = tmp_path / "new_project"
|
project_dir = tmp_path / "new_project"
|
||||||
|
|
||||||
initializer.init_project(
|
initializer.init_project(
|
||||||
project_dir,
|
project_dir, template="python-basic", project_name="new_project"
|
||||||
template="python-basic",
|
|
||||||
project_name="new_project"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check that project structure was created
|
# Check that project structure was created
|
||||||
@@ -236,7 +242,7 @@ def test_project_initializer_custom_agents(test_registry, tmp_path):
|
|||||||
project_dir,
|
project_dir,
|
||||||
template="python-basic",
|
template="python-basic",
|
||||||
agent_names=["base-agent", "keepaTodofile"],
|
agent_names=["base-agent", "keepaTodofile"],
|
||||||
project_name="custom_project"
|
project_name="custom_project",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check that specific agents were installed
|
# Check that specific agents were installed
|
||||||
@@ -251,7 +257,7 @@ def test_installation_config():
|
|||||||
claude_config_path=Path("/tmp/test/claude.json"),
|
claude_config_path=Path("/tmp/test/claude.json"),
|
||||||
makefile_path=Path("/tmp/test/Makefile"),
|
makefile_path=Path("/tmp/test/Makefile"),
|
||||||
update_docs=True,
|
update_docs=True,
|
||||||
create_backup=False
|
create_backup=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert config.target_dir == Path("/tmp/test")
|
assert config.target_dir == Path("/tmp/test")
|
||||||
|
|||||||
@@ -158,7 +158,10 @@ This agent uses both base-agent and dependent-agent.
|
|||||||
|
|
||||||
# Test complex dependency resolution
|
# Test complex dependency resolution
|
||||||
resolved = registry.resolve_dependencies(["complex-agent"])
|
resolved = registry.resolve_dependencies(["complex-agent"])
|
||||||
assert all(agent in resolved for agent in ["base-agent", "dependent-agent", "complex-agent"])
|
assert all(
|
||||||
|
agent in resolved
|
||||||
|
for agent in ["base-agent", "dependent-agent", "complex-agent"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_agent_registry_get_templates(tmp_path):
|
def test_agent_registry_get_templates(tmp_path):
|
||||||
|
|||||||
Reference in New Issue
Block a user