Files
zeekayandHanzo Dev d3110e47ea Major refactor: Unified tools, palette system, dev mode, and shell improvements (v0.6.0)
🎨 **Tool Palette System**
- Created palette system for organizing development tools by ecosystem
- Pre-defined palettes: Python (Guido), Ruby (Matz), JavaScript, Go, Rust, DevOps, Full Stack, Minimal
- `palette` tool to list, activate, and manage tool sets
- Environment variables applied from active palette
- Keeps MCP interface clean while supporting specialized workflows

🔧 **Unified Process Tools with OO Design**
- Refactored all process execution to use clean base class hierarchy
- `BaseProcessTool`, `BaseBinaryTool`, `BaseScriptTool` for consistent interface
- Unified `bash`, `npx`, `uvx` tools with action-based approach (run/background)
- `process` tool for managing background processes
- All tools use same execution pipeline internally

🐚 **Smart Shell Detection**
- Shell tool now detects user's preferred shell from $SHELL environment
- Automatically uses zsh if .zshrc exists (perfect for your setup\!)
- Falls back to bash if no special configuration found
- All zsh aliases, functions, and configurations now available in MCP

🚀 **Development Mode with Hot Reload**
- Added `--dev` flag to hanzo-mcp CLI for development mode
- File watching with automatic reload detection using watchdog
- `hanzo-mcp-dev` command for dedicated dev server
- Watches Python files and config changes
- Debounced reloading to prevent spam

🛠️ **New Tools Added**
- `open`: Opens files/URLs in default application (platform-aware)
- `watch`: Monitors files/directories for changes with pattern matching
- `diff`: Compares files with unified/context diff formats
- `config`: Git-style configuration management

📚 **Documentation & Infrastructure**
- Comprehensive Sphinx documentation with black theme
- Automated deployment to mcp.hanzo.ai via Cloudflare Pages
- GitHub Actions workflow for docs deployment
- 25+ documentation pages organized by category

⚙️ **Configuration Improvements**
- Tool enable/disable system with palette override
- Per-project vs global indexing configuration
- Environment variable management through palettes
- Clean separation of concerns in tool registration

This release provides a much cleaner, more extensible architecture while
maintaining backward compatibility. The palette system makes it easy to
switch between development environments, and the unified process tools
eliminate code duplication while providing consistent behavior.

Co-authored-by: Hanzo Dev <[email protected]>
2025-06-26 17:59:24 -04:00

122 lines
3.7 KiB
Python

"""Base functionality for filesystem tools.
This module provides common functionality for filesystem tools including path handling,
error formatting, and shared utilities for file operations.
"""
from abc import ABC
from pathlib import Path
from typing import Any
from mcp.server.fastmcp import Context as MCPContext
from hanzo_mcp.tools.common.base import FileSystemTool
from hanzo_mcp.tools.common.context import ToolContext, create_tool_context
class FilesystemBaseTool(FileSystemTool, ABC):
"""Enhanced base class for all filesystem tools.
Provides additional utilities specific to filesystem operations beyond
the base functionality in FileSystemTool.
"""
async def check_path_allowed(
self, path: str, tool_ctx: Any, error_prefix: str = "Error"
) -> tuple[bool, str]:
"""Check if a path is allowed and log an error if not.
Args:
path: Path to check
tool_ctx: Tool context for logging
error_prefix: Prefix for error messages
Returns:
tuple of (is_allowed, error_message)
"""
if not self.is_path_allowed(path):
message = f"Access denied - path outside allowed directories: {path}"
await tool_ctx.error(message)
return False, f"{error_prefix}: {message}"
return True, ""
async def check_path_exists(
self, path: str, tool_ctx: Any, error_prefix: str = "Error"
) -> tuple[bool, str]:
"""Check if a path exists and log an error if not.
Args:
path: Path to check
tool_ctx: Tool context for logging
error_prefix: Prefix for error messages
Returns:
tuple of (exists, error_message)
"""
file_path = Path(path)
if not file_path.exists():
message = f"Path does not exist: {path}"
await tool_ctx.error(message)
return False, f"{error_prefix}: {message}"
return True, ""
async def check_is_file(
self, path: str, tool_ctx: Any, error_prefix: str = "Error"
) -> tuple[bool, str]:
"""Check if a path is a file and log an error if not.
Args:
path: Path to check
tool_ctx: Tool context for logging
error_prefix: Prefix for error messages
Returns:
tuple of (is_file, error_message)
"""
file_path = Path(path)
if not file_path.is_file():
message = f"Path is not a file: {path}"
await tool_ctx.error(message)
return False, f"{error_prefix}: {message}"
return True, ""
async def check_is_directory(
self, path: str, tool_ctx: Any, error_prefix: str = "Error"
) -> tuple[bool, str]:
"""Check if a path is a directory and log an error if not.
Args:
path: Path to check
tool_ctx: Tool context for logging
error_prefix: Prefix for error messages
Returns:
tuple of (is_directory, error_message)
"""
dir_path = Path(path)
if not dir_path.is_dir():
message = f"Path is not a directory: {path}"
await tool_ctx.error(message)
return False, f"{error_prefix}: {message}"
return True, ""
def create_tool_context(self, ctx: MCPContext) -> ToolContext:
"""Create a tool context with the tool name.
Args:
ctx: MCP context
Returns:
Tool context
"""
tool_ctx = create_tool_context(ctx)
return tool_ctx
def set_tool_context_info(self, tool_ctx: ToolContext) -> None:
"""Set the tool info on the context.
Args:
tool_ctx: Tool context
"""
tool_ctx.set_tool_info(self.name)