diff --git a/Makefile b/Makefile index ce4bec8..4517aca 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile for Kaizen Agentic development tasks -.PHONY: help setup-complete setup-structure setup-python setup-tools setup-docs setup-tests setup-verify ensure-project-structure install-dev standards-check standards-fix standards-test test test-all build clean lint format venv-status list-agents update-agents validate-agents agent-status install-agent-cli +.PHONY: help setup-complete setup-structure setup-python setup-tools setup-docs setup-tests setup-verify ensure-project-structure install-dev standards-check standards-fix standards-test test test-all build clean lint format venv-status agents-list agents-update agents-validate agents-status agents-install-cli # Variables VENV = .venv @@ -32,11 +32,11 @@ help: @echo " standards-test - Run repository standards compliance tests" @echo "" @echo "Agent Management:" - @echo " list-agents - List installed agents" - @echo " update-agents - Update agents to latest versions" - @echo " validate-agents - Validate agent definitions" - @echo " agent-status - Show agent status and project info" - @echo " install-agent-cli - Install kaizen-agentic CLI tool" + @echo " agents-list - List installed agents" + @echo " agents-update - Update agents to latest versions" + @echo " agents-validate - Validate agent definitions" + @echo " agents-status - Show agent status and project info" + @echo " agents-install-cli - Install kaizen-agentic CLI tool" @echo "" @echo "Development:" @echo " test - Run unit tests only (fast)" @@ -50,7 +50,7 @@ help: @echo " make setup-complete # Set up new repository" @echo " make test-all # Run full test suite" @echo " make standards-check # Audit repository compliance" - @echo " make agent-status # Check installed agents" + @echo " make agents-status # Check installed agents" # Virtual environment status check venv-status: @@ -660,7 +660,7 @@ standards-test: $(VENV)/bin/activate # ============================================================================ # List installed agents -list-agents: +agents-list: @echo "🤖 Installed agents:" @if [ -d "agents" ]; then \ ls agents/ 2>/dev/null | grep agent- | sed 's/agent-//g' | sed 's/.md//g' | sort || echo "No agents installed"; \ @@ -669,7 +669,7 @@ list-agents: fi # Update installed agents to latest versions -update-agents: $(VENV)/bin/activate +agents-update: $(VENV)/bin/activate @echo "🔄 Updating agents..." @if command -v kaizen-agentic >/dev/null 2>&1; then \ kaizen-agentic update; \ @@ -678,7 +678,7 @@ update-agents: $(VENV)/bin/activate fi # Validate installed agents -validate-agents: +agents-validate: @echo "✅ Validating agents..." @if command -v kaizen-agentic >/dev/null 2>&1; then \ kaizen-agentic validate; \ @@ -687,7 +687,7 @@ validate-agents: fi # Show agent status and project information -agent-status: +agents-status: @echo "📊 Agent status:" @if command -v kaizen-agentic >/dev/null 2>&1; then \ kaizen-agentic status; \ @@ -703,7 +703,7 @@ agent-status: fi # Install agent distribution CLI -install-agent-cli: $(VENV)/bin/activate +agents-install-cli: $(VENV)/bin/activate @echo "📦 Installing Kaizen Agentic CLI..." @$(VENV_PIP) install -e . @echo "✅ CLI installed. Use 'kaizen-agentic --help' for usage." \ No newline at end of file diff --git a/docs/AGENT_DISTRIBUTION.md b/docs/AGENT_DISTRIBUTION.md index 4e4bbe4..eac5593 100644 --- a/docs/AGENT_DISTRIBUTION.md +++ b/docs/AGENT_DISTRIBUTION.md @@ -219,9 +219,9 @@ Agents automatically integrate with Claude Code: The CLI automatically adds agent management targets: ```bash -make list-agents # List installed agents -make update-agents # Update to latest versions -make validate-agents # Validate agent definitions +make agents-list # List installed agents +make agents-update # Update to latest versions +make agents-validate # Validate agent definitions ``` ### Documentation Integration diff --git a/docs/CLI_CHEAT_SHEET.md b/docs/CLI_CHEAT_SHEET.md index 834e3fc..cf0586f 100644 --- a/docs/CLI_CHEAT_SHEET.md +++ b/docs/CLI_CHEAT_SHEET.md @@ -123,9 +123,9 @@ cat CLAUDE.md # Read agent documentation ### Without Makefile ```bash # Direct CLI usage when Makefile targets aren't available -kaizen-agentic status # Instead of: make list-agents -kaizen-agentic update # Instead of: make update-agents -kaizen-agentic validate # Instead of: make validate-agents +kaizen-agentic status # Instead of: make agents-list +kaizen-agentic update # Instead of: make agents-update +kaizen-agentic validate # Instead of: make agents-validate ``` ### With Build Tools @@ -142,10 +142,10 @@ kaizen-agentic validate # Instead of: make validate-agents **Make targets (auto-added):** ```bash -make list-agents # List installed agents -make update-agents # Update agents -make validate-agents # Validate agents -make agent-status # Show detailed status +make agents-list # List installed agents +make agents-update # Update agents +make agents-validate # Validate agents +make agents-status # Show detailed status ``` ## Troubleshooting diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 9deb4df..e87cc42 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -81,17 +81,17 @@ The agents will create/update files, but you need to integrate with your build s cat >> Makefile << 'EOF' # Agent Management (added by kaizen-agentic) -list-agents: +agents-list: @echo "Installed agents:" @ls agents/ 2>/dev/null | grep agent- | sed 's/agent-//g' | sed 's/.md//g' | sort -update-agents: +agents-update: @kaizen-agentic update -validate-agents: +agents-validate: @kaizen-agentic validate -agent-status: +agents-status: @kaizen-agentic status EOF ``` @@ -144,13 +144,13 @@ If you're in a project without the Kaizen Agentic Makefile targets, you can stil ### Direct CLI Usage ```bash -# Instead of 'make list-agents' +# Instead of 'make agents-list' kaizen-agentic status -# Instead of 'make update-agents' +# Instead of 'make agents-update' kaizen-agentic update -# Instead of 'make validate-agents' +# Instead of 'make agents-validate' kaizen-agentic validate # Install new agents diff --git a/src/kaizen_agentic/installer.py b/src/kaizen_agentic/installer.py index 2958ed3..7aa11d8 100644 --- a/src/kaizen_agentic/installer.py +++ b/src/kaizen_agentic/installer.py @@ -150,15 +150,23 @@ class AgentInstaller: def _create_backup(self, agents_dir: Path): """Create a backup of the existing agents directory.""" - backup_dir = agents_dir.parent / f"agents_backup_{self._get_timestamp()}" + import datetime + import time + + # Add microseconds to avoid collisions in tests + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + microseconds = int(time.time() * 1000000) % 1000000 + backup_dir = agents_dir.parent / f"agents_backup_{timestamp}_{microseconds}" + + # Ensure unique backup directory + counter = 0 + while backup_dir.exists(): + counter += 1 + backup_dir = agents_dir.parent / f"agents_backup_{timestamp}_{microseconds}_{counter}" + shutil.copytree(agents_dir, backup_dir) print(f"Created backup at: {backup_dir}") - def _get_timestamp(self) -> str: - """Get current timestamp for backup naming.""" - import datetime - return datetime.datetime.now().strftime("%Y%m%d_%H%M%S") - def _update_claude_config(self, agent_names: List[str], config_path: Path): """Update Claude Code configuration with agent references.""" try: @@ -198,20 +206,20 @@ class AgentInstaller: # Add agent management targets if not present agent_targets = """ # Agent Management Targets -list-agents: +agents-list: \t@echo "Installed agents:" \t@ls agents/ 2>/dev/null | grep agent- | sed 's/agent-//g' | sed 's/.md//g' || echo "No agents installed" -update-agents: +agents-update: \t@echo "Updating agents..." \t@kaizen-agentic update -validate-agents: +agents-validate: \t@echo "Validating agents..." \t@kaizen-agentic validate agents/ """ - if "list-agents:" not in content: + if "agents-list:" not in content: content += agent_targets # Write updated Makefile diff --git a/src/kaizen_agentic/registry.py b/src/kaizen_agentic/registry.py index 745e490..f0b8b08 100644 --- a/src/kaizen_agentic/registry.py +++ b/src/kaizen_agentic/registry.py @@ -42,8 +42,8 @@ class AgentDefinition: frontmatter = yaml.safe_load(frontmatter_match.group(1)) - # Extract dependencies from content - dependencies = cls._extract_dependencies(content) + # Extract dependencies from frontmatter and content + dependencies = cls._extract_dependencies(content, frontmatter) # Determine category from name or content category = cls._determine_category(frontmatter['name'], content) @@ -58,21 +58,25 @@ class AgentDefinition: ) @staticmethod - def _extract_dependencies(content: str) -> Set[str]: - """Extract agent dependencies from content.""" + def _extract_dependencies(content: str, frontmatter: dict) -> Set[str]: + """Extract agent dependencies from frontmatter and content.""" dependencies = set() - # Look for references to other agents - agent_refs = re.findall(r'(?:agent-|-)(\w+(?:-\w+)*)', content.lower()) - for ref in agent_refs: - if ref not in ['optimization', 'agentic', 'driven', 'assisted']: - dependencies.add(ref.replace('-', '_')) + # Check frontmatter for explicit dependencies + for key in ['dependencies', 'depends_on', 'requires']: + if key in frontmatter: + deps = frontmatter[key] + if isinstance(deps, list): + dependencies.update(deps) + elif isinstance(deps, str): + # Handle comma-separated string + dependencies.update([d.strip() for d in deps.split(',')]) - # Look for explicit dependencies in frontmatter or content + # Look for explicit dependencies in content dep_patterns = [ r'depends_on:\s*\[(.*?)\]', r'requires:\s*\[(.*?)\]', - r'uses:\s*(\w+(?:-\w+)*)', + r'dependencies:\s*\[(.*?)\]', ] for pattern in dep_patterns: @@ -82,6 +86,20 @@ class AgentDefinition: deps = [d.strip().strip('"\'') for d in match.split(',')] dependencies.update(deps) + # Look for specific agent references in content (more precise) + # Only look for full agent names like "todo-keeper agent" or "uses changelog-keeper" + agent_patterns = [ + r'uses?\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))', + ] + + for pattern in agent_patterns: + matches = re.findall(pattern, content.lower()) + for match in matches: + if match not in ['optimization', 'agentic', 'driven', 'assisted']: + dependencies.add(match.replace('-', '_')) + return dependencies @staticmethod diff --git a/tests/test_registry.py b/tests/test_registry.py index 7aa804a..67f72cf 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -128,6 +128,7 @@ description: Base agent with no dependencies dependent_agent = """--- name: dependent-agent description: Agent that depends on base-agent +dependencies: ["base-agent"] --- # Dependent Agent @@ -138,6 +139,7 @@ This agent uses base-agent for functionality. complex_agent = """--- name: complex-agent description: Agent with multiple dependencies +dependencies: ["base-agent", "dependent-agent"] --- # Complex Agent @@ -188,23 +190,26 @@ description: A valid agent # Valid Agent """ - # Create invalid agent (missing required fields) - invalid_agent = """--- -description: Missing name field + # Create agent with missing dependency + missing_dep_agent = """--- +name: missing-dep-agent +description: Agent with missing dependency +dependencies: ["non-existent-agent"] --- -# Invalid Agent +# Missing Dependency Agent """ (tmp_path / "agent-valid-agent.md").write_text(valid_agent) - (tmp_path / "agent-invalid-agent.md").write_text(invalid_agent) + (tmp_path / "agent-missing-dep-agent.md").write_text(missing_dep_agent) registry = AgentRegistry(tmp_path) errors = registry.validate_agents() - # The invalid agent should not be loaded, so no validation errors - # (it fails during loading) - assert len(errors) == 0 # Because invalid agents aren't loaded + # Should have one error for missing dependency + assert len(errors) == 1 + assert "missing-dep-agent" in errors + assert "Missing dependency: non-existent-agent" in errors["missing-dep-agent"] def test_agent_category_determination():