hanzo-mcp 0.8.5__tar.gz → 0.8.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hanzo-mcp might be problematic. Click here for more details.
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/PKG-INFO +1 -1
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/__init__.py +10 -1
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp.egg-info/PKG-INFO +1 -1
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp.egg-info/SOURCES.txt +1 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/pyproject.toml +1 -1
- hanzo_mcp-0.8.7/tests/test_no_stubs.py +288 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/README.md +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/__main__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/analytics/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/analytics/posthog_analytics.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/bridge.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/cli.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/cli_enhanced.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/cli_plugin.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/compute_nodes.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/config/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/config/settings.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/config/tool_config.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/core/base_agent.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/core/model_registry.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/dev_server.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/compact_conversation.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/create_release.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/enhanced_prompts.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/example_custom_prompt.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/project_system.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/project_todo_reminder.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/tool_explorer.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/prompts/utils.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/server.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/server_enhanced.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/agent.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/agent_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/clarification_protocol.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/clarification_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/claude_cli_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/claude_desktop_auth.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/cli_agent_base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/cli_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/code_auth.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/code_auth_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/codex_cli_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/critic_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/gemini_cli_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/grok_cli_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/iching_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/network_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/prompt.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/review_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/swarm_alias.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/swarm_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/tool_adapter.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/agent/unified_cli_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/batch_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/config_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/context.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/context_fix.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/critic_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/decorators.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/enhanced_base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/fastmcp_pagination.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/forgiving_edit.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/mode.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/mode_loader.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/paginated_base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/paginated_response.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/pagination.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/permissions.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/personality.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/plugin_loader.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/stats.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/test_helpers.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/thinking_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/tool_disable.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/tool_enable.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/tool_list.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/truncate.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/common/validation.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/config/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/config/config_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/config/index_config.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/config/mode_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/database_manager.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/graph.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/graph_add.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/graph_query.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/graph_remove.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/graph_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/graph_stats.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/sql.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/sql_query.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/sql_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/database/sql_stats.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/editor/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/editor/neovim_command.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/editor/neovim_edit.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/editor/neovim_session.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/ast_multi_edit.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/ast_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/batch_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/content_replace.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/diff.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/directory_tree.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/directory_tree_paginated.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/edit.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/find.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/find_files.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/git_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/grep.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/multi_edit.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/read.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/rules_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/search_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/symbols_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/tree.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/unix_aliases.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/watch.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/filesystem/write.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/jupyter/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/jupyter/base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/jupyter/jupyter.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/jupyter/notebook_edit.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/jupyter/notebook_read.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/llm/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/llm/consensus_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/llm/llm_manage.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/llm/llm_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/llm/llm_unified.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/llm/provider_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/lsp/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/lsp/lsp_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/mcp/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/mcp/mcp_add.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/mcp/mcp_remove.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/mcp/mcp_stats.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/mcp/mcp_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/memory/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/memory/knowledge_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/memory/memory_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/search/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/search/find_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/search/unified_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/auto_background.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/base_process.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/bash_session.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/bash_session_executor.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/bash_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/command_executor.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/logs.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/npx.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/npx_background.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/npx_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/open.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/pkill.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/process_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/processes.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/run_background.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/run_command.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/run_command_windows.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/session_manager.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/session_storage.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/streaming_command.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/uvx.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/uvx_background.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/uvx_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/shell/zsh_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/todo/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/todo/base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/todo/todo.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/todo/todo_read.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/todo/todo_write.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/__init__.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/ast_analyzer.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/git_ingester.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/index_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/infinity_store.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/mock_infinity.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/project_manager.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/vector.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/vector_index.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/tools/vector/vector_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp/types.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp.egg-info/dependency_links.txt +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp.egg-info/entry_points.txt +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp.egg-info/requires.txt +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/hanzo_mcp.egg-info/top_level.txt +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/setup.cfg +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_agent_tools_ci.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_async_support.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_batch_tool_edge_cases.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_cli.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_cli_agents_consolidated.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_cli_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_e2e_demo.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_e2e_simple.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_failure_cases.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_find_tool_ffind.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_find_tool_integration.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_find_tool_registration.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_git_ingestion.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_hanzo_agents_integration.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_hanzo_mcp_integration.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_hanzo_mcp_local.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_hanzo_mcp_simple.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_hanzo_network_integration.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_litellm_warnings.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_lsp_tool.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_manual.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_memory_base.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_memory_basic.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_memory_consolidated.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_memory_simple.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_memory_utils.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_new_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_performance.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_search_quality.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_shell_features.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_shell_tools.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_simple.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_stdio_protocol.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_stdio_simple.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_streaming_command.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_swarm_simple.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_tools_suite.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_unified_search.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_utils.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_vector_store.py +0 -0
- {hanzo_mcp-0.8.5 → hanzo_mcp-0.8.7}/tests/test_web3_integration.py +0 -0
|
@@ -64,7 +64,16 @@ try: # pragma: no cover
|
|
|
64
64
|
register_memory_tools = None # type: ignore
|
|
65
65
|
except Exception:
|
|
66
66
|
# Minimal surface to allow submodule imports elsewhere
|
|
67
|
-
|
|
67
|
+
# Define stub functions for required imports
|
|
68
|
+
def activate_mode_from_env():
|
|
69
|
+
pass
|
|
70
|
+
class ModeLoader:
|
|
71
|
+
@staticmethod
|
|
72
|
+
def get_enabled_tools_from_mode(base_enabled_tools=None, force_mode=None):
|
|
73
|
+
return base_enabled_tools or {}
|
|
74
|
+
@staticmethod
|
|
75
|
+
def apply_environment_from_mode():
|
|
76
|
+
pass
|
|
68
77
|
|
|
69
78
|
# Try to import LSP tool
|
|
70
79
|
try:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hanzo-mcp"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.7"
|
|
8
8
|
description = "The Zen of Hanzo MCP: One server to rule them all. The ultimate MCP that orchestrates all others."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""Test to ensure no stub/fake/incomplete code exists in production."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List, Tuple
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class StubDetector(ast.NodeVisitor):
|
|
13
|
+
"""AST visitor to detect stub implementations."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, filepath: str):
|
|
16
|
+
self.filepath = filepath
|
|
17
|
+
self.issues: List[Tuple[int, str]] = []
|
|
18
|
+
self.in_test_file = 'test' in filepath or 'mock' in filepath.lower()
|
|
19
|
+
|
|
20
|
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
|
|
21
|
+
"""Check function definitions for stub patterns."""
|
|
22
|
+
# Skip test files for certain checks
|
|
23
|
+
if self.in_test_file and node.name.startswith('test_'):
|
|
24
|
+
self.generic_visit(node)
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
# Check for empty functions with just pass
|
|
28
|
+
if len(node.body) == 1 and isinstance(node.body[0], ast.Pass):
|
|
29
|
+
# Check if there's a comment indicating it's a stub
|
|
30
|
+
if node.body[0].lineno:
|
|
31
|
+
self.issues.append((
|
|
32
|
+
node.lineno,
|
|
33
|
+
f"Function '{node.name}' contains only 'pass' statement"
|
|
34
|
+
))
|
|
35
|
+
|
|
36
|
+
# Check for functions that just raise NotImplementedError
|
|
37
|
+
if len(node.body) == 1 and isinstance(node.body[0], ast.Raise):
|
|
38
|
+
if isinstance(node.body[0].exc, ast.Call):
|
|
39
|
+
if (hasattr(node.body[0].exc.func, 'id') and
|
|
40
|
+
node.body[0].exc.func.id == 'NotImplementedError'):
|
|
41
|
+
self.issues.append((
|
|
42
|
+
node.lineno,
|
|
43
|
+
f"Function '{node.name}' raises NotImplementedError"
|
|
44
|
+
))
|
|
45
|
+
|
|
46
|
+
# Check for functions with only ellipsis
|
|
47
|
+
if len(node.body) == 1 and isinstance(node.body[0], ast.Expr):
|
|
48
|
+
if isinstance(node.body[0].value, ast.Constant):
|
|
49
|
+
if node.body[0].value.value is Ellipsis:
|
|
50
|
+
self.issues.append((
|
|
51
|
+
node.lineno,
|
|
52
|
+
f"Function '{node.name}' contains only ellipsis"
|
|
53
|
+
))
|
|
54
|
+
|
|
55
|
+
self.generic_visit(node)
|
|
56
|
+
|
|
57
|
+
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
|
|
58
|
+
"""Check async function definitions."""
|
|
59
|
+
# Treat async functions same as regular functions
|
|
60
|
+
self.visit_FunctionDef(node)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def find_stub_patterns(filepath: Path) -> List[Tuple[int, str, str]]:
|
|
64
|
+
"""Find stub patterns in a Python file."""
|
|
65
|
+
issues = []
|
|
66
|
+
|
|
67
|
+
# Skip test files for most checks
|
|
68
|
+
is_test_file = 'test' in filepath.name or 'mock' in filepath.name.lower()
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
content = filepath.read_text(encoding='utf-8')
|
|
72
|
+
except Exception:
|
|
73
|
+
return issues
|
|
74
|
+
|
|
75
|
+
# Regex patterns to find stub indicators
|
|
76
|
+
patterns = [
|
|
77
|
+
(r'#\s*(TODO|FIXME|STUB|FAKE|UNFINISHED|HACK|XXX)\s*:?', 'contains {0} comment'),
|
|
78
|
+
(r'raise\s+NotImplementedError', 'raises NotImplementedError'),
|
|
79
|
+
(r'assert\s+False,?\s*["\']Not implemented', 'has "Not implemented" assertion'),
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
# Additional patterns for non-test files
|
|
83
|
+
if not is_test_file:
|
|
84
|
+
patterns.extend([
|
|
85
|
+
(r'pass\s*#\s*(stub|todo|fake)', 'has stub/todo/fake comment after pass'),
|
|
86
|
+
(r'return\s+["\']TODO', 'returns TODO string'),
|
|
87
|
+
(r'return\s+["\']STUB', 'returns STUB string'),
|
|
88
|
+
(r'return\s+None\s*#\s*(TODO|STUB|FAKE)', 'returns None with stub comment'),
|
|
89
|
+
])
|
|
90
|
+
|
|
91
|
+
lines = content.split('\n')
|
|
92
|
+
for line_num, line in enumerate(lines, 1):
|
|
93
|
+
for pattern, message in patterns:
|
|
94
|
+
if match := re.search(pattern, line, re.IGNORECASE):
|
|
95
|
+
keyword = match.group(1) if match.groups() else 'stub pattern'
|
|
96
|
+
issues.append((
|
|
97
|
+
line_num,
|
|
98
|
+
message.format(keyword),
|
|
99
|
+
filepath.name
|
|
100
|
+
))
|
|
101
|
+
|
|
102
|
+
# Parse AST for deeper inspection
|
|
103
|
+
try:
|
|
104
|
+
tree = ast.parse(content)
|
|
105
|
+
detector = StubDetector(str(filepath))
|
|
106
|
+
detector.visit(tree)
|
|
107
|
+
for line_num, message in detector.issues:
|
|
108
|
+
issues.append((line_num, message, filepath.name))
|
|
109
|
+
except SyntaxError:
|
|
110
|
+
pass # Ignore files with syntax errors
|
|
111
|
+
|
|
112
|
+
return issues
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_python_files(root_dir: Path, exclude_dirs: set = None) -> List[Path]:
|
|
116
|
+
"""Get all Python files in directory, excluding certain directories."""
|
|
117
|
+
if exclude_dirs is None:
|
|
118
|
+
exclude_dirs = {
|
|
119
|
+
'__pycache__', '.git', '.tox', '.pytest_cache',
|
|
120
|
+
'build', 'dist', '*.egg-info', '.venv', 'venv',
|
|
121
|
+
'node_modules', '.mypy_cache'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
python_files = []
|
|
125
|
+
for path in root_dir.rglob('*.py'):
|
|
126
|
+
# Skip excluded directories
|
|
127
|
+
if any(excluded in path.parts for excluded in exclude_dirs):
|
|
128
|
+
continue
|
|
129
|
+
python_files.append(path)
|
|
130
|
+
|
|
131
|
+
return python_files
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class TestNoStubs:
|
|
135
|
+
"""Test suite to ensure no stub implementations exist."""
|
|
136
|
+
|
|
137
|
+
def test_no_stub_functions_in_source(self):
|
|
138
|
+
"""Ensure no stub functions exist in source code."""
|
|
139
|
+
# Get the package root
|
|
140
|
+
package_root = Path(__file__).parent.parent / 'hanzo_mcp'
|
|
141
|
+
|
|
142
|
+
if not package_root.exists():
|
|
143
|
+
pytest.skip(f"Package root {package_root} does not exist")
|
|
144
|
+
|
|
145
|
+
all_issues = []
|
|
146
|
+
python_files = get_python_files(package_root)
|
|
147
|
+
|
|
148
|
+
for filepath in python_files:
|
|
149
|
+
issues = find_stub_patterns(filepath)
|
|
150
|
+
for line_num, message, filename in issues:
|
|
151
|
+
all_issues.append(
|
|
152
|
+
f"{filepath.relative_to(package_root.parent)}:{line_num} - {message}"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
if all_issues:
|
|
156
|
+
report = "\n".join(all_issues)
|
|
157
|
+
pytest.fail(
|
|
158
|
+
f"Found {len(all_issues)} stub/incomplete implementations:\n{report}"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def test_critical_functions_implemented(self):
|
|
162
|
+
"""Ensure critical functions are actually implemented."""
|
|
163
|
+
package_root = Path(__file__).parent.parent / 'hanzo_mcp'
|
|
164
|
+
|
|
165
|
+
# Critical modules and functions that must be implemented
|
|
166
|
+
critical_checks = [
|
|
167
|
+
('tools/__init__.py', 'register_all_tools'),
|
|
168
|
+
('server.py', '__init__'),
|
|
169
|
+
('server.py', 'run'),
|
|
170
|
+
('cli.py', 'main'),
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
for module_path, function_name in critical_checks:
|
|
174
|
+
filepath = package_root / module_path
|
|
175
|
+
if not filepath.exists():
|
|
176
|
+
pytest.fail(f"Critical module {module_path} does not exist")
|
|
177
|
+
|
|
178
|
+
content = filepath.read_text()
|
|
179
|
+
# Check function exists and has more than just pass/raise
|
|
180
|
+
pattern = rf'def {function_name}\([^)]*\):[^:]*\n(?:\s+"""[^"]*"""\n)?(\s+.+)'
|
|
181
|
+
match = re.search(pattern, content, re.MULTILINE)
|
|
182
|
+
|
|
183
|
+
if not match:
|
|
184
|
+
pytest.fail(f"Function {function_name} not found in {module_path}")
|
|
185
|
+
|
|
186
|
+
function_body = match.group(1).strip()
|
|
187
|
+
if function_body in ['pass', 'raise NotImplementedError', 'raise NotImplementedError()', '...']:
|
|
188
|
+
pytest.fail(f"Function {function_name} in {module_path} is not implemented")
|
|
189
|
+
|
|
190
|
+
def test_no_pytest_skip_in_non_test_files(self):
|
|
191
|
+
"""Ensure pytest.skip is only used in test files."""
|
|
192
|
+
package_root = Path(__file__).parent.parent / 'hanzo_mcp'
|
|
193
|
+
|
|
194
|
+
for filepath in get_python_files(package_root):
|
|
195
|
+
# Skip test directories
|
|
196
|
+
if 'test' in str(filepath):
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
content = filepath.read_text()
|
|
200
|
+
if 'pytest.skip' in content or '@pytest.mark.skip' in content:
|
|
201
|
+
pytest.fail(f"Found pytest.skip in non-test file: {filepath}")
|
|
202
|
+
|
|
203
|
+
def test_no_mock_implementations_in_production(self):
|
|
204
|
+
"""Ensure no mock implementations exist in production code."""
|
|
205
|
+
package_root = Path(__file__).parent.parent / 'hanzo_mcp'
|
|
206
|
+
|
|
207
|
+
for filepath in get_python_files(package_root):
|
|
208
|
+
# Skip test directories and legitimate mock modules
|
|
209
|
+
if 'test' in str(filepath) or 'mock' in filepath.name:
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
content = filepath.read_text()
|
|
213
|
+
|
|
214
|
+
# Check for mock-related imports in production code
|
|
215
|
+
mock_patterns = [
|
|
216
|
+
r'from unittest\.mock import',
|
|
217
|
+
r'import unittest\.mock',
|
|
218
|
+
r'class Mock',
|
|
219
|
+
r'class Fake',
|
|
220
|
+
r'def fake_',
|
|
221
|
+
r'def mock_',
|
|
222
|
+
r'return\s+["\']fake',
|
|
223
|
+
r'return\s+["\']mock',
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
for pattern in mock_patterns:
|
|
227
|
+
if re.search(pattern, content, re.IGNORECASE):
|
|
228
|
+
pytest.fail(
|
|
229
|
+
f"Found mock/fake pattern '{pattern}' in production file: {filepath}"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def test_all_tool_classes_have_run_method(self):
|
|
233
|
+
"""Ensure all tool classes have a proper run method."""
|
|
234
|
+
package_root = Path(__file__).parent.parent / 'hanzo_mcp' / 'tools'
|
|
235
|
+
|
|
236
|
+
if not package_root.exists():
|
|
237
|
+
pytest.skip("Tools directory does not exist")
|
|
238
|
+
|
|
239
|
+
for filepath in get_python_files(package_root):
|
|
240
|
+
if 'test' in str(filepath) or '__pycache__' in str(filepath):
|
|
241
|
+
continue
|
|
242
|
+
|
|
243
|
+
content = filepath.read_text()
|
|
244
|
+
|
|
245
|
+
# Find all class definitions that inherit from BaseTool or end with Tool
|
|
246
|
+
class_pattern = r'class\s+(\w*Tool\w*)\s*\([^)]*\):'
|
|
247
|
+
classes = re.findall(class_pattern, content)
|
|
248
|
+
|
|
249
|
+
for class_name in classes:
|
|
250
|
+
# Check if class has a run method
|
|
251
|
+
run_pattern = rf'class\s+{class_name}.*?def\s+run\s*\([^)]*\):'
|
|
252
|
+
if not re.search(run_pattern, content, re.DOTALL):
|
|
253
|
+
# Check if it's an abstract base class
|
|
254
|
+
if 'Base' not in class_name and 'Abstract' not in class_name:
|
|
255
|
+
pytest.fail(
|
|
256
|
+
f"Tool class {class_name} in {filepath.name} missing run() method"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
def test_no_debug_prints_in_production(self):
|
|
260
|
+
"""Ensure no debug print statements in production code."""
|
|
261
|
+
package_root = Path(__file__).parent.parent / 'hanzo_mcp'
|
|
262
|
+
|
|
263
|
+
for filepath in get_python_files(package_root):
|
|
264
|
+
# Skip test files
|
|
265
|
+
if 'test' in str(filepath):
|
|
266
|
+
continue
|
|
267
|
+
|
|
268
|
+
content = filepath.read_text()
|
|
269
|
+
|
|
270
|
+
# Check for debug patterns
|
|
271
|
+
debug_patterns = [
|
|
272
|
+
(r'print\s*\([^)]*#\s*DEBUG', 'debug print statement'),
|
|
273
|
+
(r'print\s*\([^)]*#\s*TODO', 'TODO print statement'),
|
|
274
|
+
(r'print\s*\([^)]*#\s*REMOVE', 'REMOVE print statement'),
|
|
275
|
+
(r'console\.log', 'console.log statement'),
|
|
276
|
+
(r'debugger;?', 'debugger statement'),
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
for pattern, description in debug_patterns:
|
|
280
|
+
if re.search(pattern, content, re.IGNORECASE):
|
|
281
|
+
pytest.fail(
|
|
282
|
+
f"Found {description} in production file: {filepath}"
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
if __name__ == '__main__':
|
|
287
|
+
# Run tests directly
|
|
288
|
+
pytest.main([__file__, '-v'])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|