claude-mpm 4.1.8__py3-none-any.whl → 4.1.11__py3-none-any.whl
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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/INSTRUCTIONS.md +26 -1
- claude_mpm/agents/agents_metadata.py +57 -0
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
- claude_mpm/agents/templates/agent-manager.json +263 -17
- claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
- claude_mpm/agents/templates/code_analyzer.json +18 -8
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/cli/__init__.py +15 -0
- claude_mpm/cli/commands/__init__.py +6 -0
- claude_mpm/cli/commands/analyze.py +548 -0
- claude_mpm/cli/commands/analyze_code.py +524 -0
- claude_mpm/cli/commands/configure.py +78 -28
- claude_mpm/cli/commands/configure_tui.py +62 -60
- claude_mpm/cli/commands/dashboard.py +288 -0
- claude_mpm/cli/commands/debug.py +1386 -0
- claude_mpm/cli/commands/mpm_init.py +427 -0
- claude_mpm/cli/commands/mpm_init_handler.py +83 -0
- claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
- claude_mpm/cli/parsers/analyze_parser.py +135 -0
- claude_mpm/cli/parsers/base_parser.py +44 -0
- claude_mpm/cli/parsers/dashboard_parser.py +113 -0
- claude_mpm/cli/parsers/debug_parser.py +319 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
- claude_mpm/constants.py +13 -1
- claude_mpm/core/framework_loader.py +148 -6
- claude_mpm/core/log_manager.py +16 -13
- claude_mpm/core/logger.py +1 -1
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
- claude_mpm/dashboard/analysis_runner.py +455 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/css/activity.css +549 -0
- claude_mpm/dashboard/static/css/code-tree.css +1175 -0
- claude_mpm/dashboard/static/css/dashboard.css +245 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +1338 -0
- claude_mpm/dashboard/static/js/components/code-tree.js +2535 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +59 -9
- claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
- claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
- claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
- claude_mpm/dashboard/static/js/dashboard.js +51 -0
- claude_mpm/dashboard/static/js/socket-client.js +465 -29
- claude_mpm/dashboard/templates/index.html +182 -4
- claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
- claude_mpm/hooks/claude_hooks/installer.py +386 -113
- claude_mpm/scripts/claude-hook-handler.sh +161 -0
- claude_mpm/scripts/socketio_daemon.py +121 -8
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
- claude_mpm/services/agents/memory/memory_format_service.py +1 -3
- claude_mpm/services/cli/agent_cleanup_service.py +1 -5
- claude_mpm/services/cli/agent_dependency_service.py +1 -1
- claude_mpm/services/cli/agent_validation_service.py +3 -4
- claude_mpm/services/cli/dashboard_launcher.py +2 -3
- claude_mpm/services/cli/startup_checker.py +0 -11
- claude_mpm/services/core/cache_manager.py +1 -3
- claude_mpm/services/core/path_resolver.py +1 -4
- claude_mpm/services/core/service_container.py +2 -2
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
- claude_mpm/services/infrastructure/monitoring.py +11 -11
- claude_mpm/services/project/architecture_analyzer.py +1 -1
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/language_analyzer.py +3 -3
- claude_mpm/services/project/metrics_collector.py +3 -6
- claude_mpm/services/socketio/event_normalizer.py +64 -0
- claude_mpm/services/socketio/handlers/__init__.py +2 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +672 -0
- claude_mpm/services/socketio/handlers/registry.py +2 -0
- claude_mpm/services/socketio/server/connection_manager.py +6 -4
- claude_mpm/services/socketio/server/core.py +100 -11
- claude_mpm/services/socketio/server/main.py +8 -2
- claude_mpm/services/visualization/__init__.py +19 -0
- claude_mpm/services/visualization/mermaid_generator.py +938 -0
- claude_mpm/tools/__main__.py +208 -0
- claude_mpm/tools/code_tree_analyzer.py +1596 -0
- claude_mpm/tools/code_tree_builder.py +631 -0
- claude_mpm/tools/code_tree_events.py +416 -0
- claude_mpm/tools/socketio_debug.py +671 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +110 -74
- claude_mpm/agents/schema/agent_schema.json +0 -314
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Claude MPM Hook Handler Entry Point Script
|
|
4
|
+
#
|
|
5
|
+
# OVERVIEW:
|
|
6
|
+
# This script serves as the bridge between Claude Code hook system and the Python-based
|
|
7
|
+
# Claude MPM hook handler. It is executed directly by Claude Code when events occur
|
|
8
|
+
# and ensures proper environment setup before delegating to the Python handler.
|
|
9
|
+
#
|
|
10
|
+
# ARCHITECTURE:
|
|
11
|
+
# Claude Code → This Script → Python Environment → hook_handler.py → Socket.IO/EventBus
|
|
12
|
+
#
|
|
13
|
+
# KEY RESPONSIBILITIES:
|
|
14
|
+
# - Virtual environment detection and activation
|
|
15
|
+
# - Python executable resolution with fallbacks
|
|
16
|
+
# - Error handling and logging for troubleshooting
|
|
17
|
+
# - Path resolution for cross-platform compatibility
|
|
18
|
+
# - Environment variable propagation
|
|
19
|
+
#
|
|
20
|
+
# DEPLOYMENT:
|
|
21
|
+
# This script is deployed to Claude Code's hooks directory during installation.
|
|
22
|
+
# Location: ~/.claude/hooks/claude-mpm/claude-hook-handler.sh
|
|
23
|
+
# Permissions: Must be executable (chmod +x)
|
|
24
|
+
#
|
|
25
|
+
# ENVIRONMENT VARIABLES:
|
|
26
|
+
# - CLAUDE_MPM_HOOK_DEBUG: Enable debug logging to /tmp/claude-mpm-hook.log
|
|
27
|
+
# - CLAUDE_MPM_ROOT: Override project root detection
|
|
28
|
+
# - VIRTUAL_ENV: Standard virtual environment variable
|
|
29
|
+
# - PYTHONPATH: Extended with src/ directory for imports
|
|
30
|
+
#
|
|
31
|
+
# PERFORMANCE CONSIDERATIONS:
|
|
32
|
+
# - Minimal shell operations to reduce latency (~10ms overhead)
|
|
33
|
+
# - Cached virtual environment detection
|
|
34
|
+
# - Early exit on errors to prevent hanging
|
|
35
|
+
# - Lightweight logging for debugging without performance impact
|
|
36
|
+
#
|
|
37
|
+
# SECURITY:
|
|
38
|
+
# - Restricts Python execution to project virtual environments
|
|
39
|
+
# - Validates paths before execution
|
|
40
|
+
# - No external network access or privileged operations
|
|
41
|
+
# - Logs to temporary files only (no persistent sensitive data)
|
|
42
|
+
#
|
|
43
|
+
# TROUBLESHOOTING:
|
|
44
|
+
# Enable debug logging: export CLAUDE_MPM_HOOK_DEBUG=true
|
|
45
|
+
# Check permissions: ls -la ~/.claude/hooks/claude-mpm/claude-hook-handler.sh
|
|
46
|
+
# Test manually: echo '{"test": "data"}' | ./claude-hook-handler.sh
|
|
47
|
+
#
|
|
48
|
+
# GOTCHAS:
|
|
49
|
+
# - Must activate virtual environment in same shell process
|
|
50
|
+
# - Path resolution differs between development and installed environments
|
|
51
|
+
# - Claude Code passes event data via stdin (not command line arguments)
|
|
52
|
+
# - Exit codes must be 0 for success, non-zero indicates failure to Claude Code
|
|
53
|
+
#
|
|
54
|
+
# @author Claude MPM Development Team
|
|
55
|
+
# @version 1.0
|
|
56
|
+
# @since v4.0.25
|
|
57
|
+
|
|
58
|
+
# Exit on any error
|
|
59
|
+
set -e
|
|
60
|
+
|
|
61
|
+
# Get the directory where this script is located
|
|
62
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
63
|
+
|
|
64
|
+
# Determine the claude-mpm root
|
|
65
|
+
# The script is at src/claude_mpm/scripts/, so we go up 3 levels
|
|
66
|
+
CLAUDE_MPM_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
67
|
+
|
|
68
|
+
# Debug logging (can be enabled via environment variable)
|
|
69
|
+
if [ "${CLAUDE_MPM_HOOK_DEBUG}" = "true" ]; then
|
|
70
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Claude hook handler starting..." >> /tmp/claude-mpm-hook.log
|
|
71
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Script dir: $SCRIPT_DIR" >> /tmp/claude-mpm-hook.log
|
|
72
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Claude MPM root: $CLAUDE_MPM_ROOT" >> /tmp/claude-mpm-hook.log
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Find and return the appropriate Python executable for hook processing.
|
|
77
|
+
#
|
|
78
|
+
# STRATEGY:
|
|
79
|
+
# This function implements a fallback chain to find Python with claude-mpm dependencies:
|
|
80
|
+
# 1. Project-specific virtual environments (venv, .venv)
|
|
81
|
+
# 2. Currently active virtual environment ($VIRTUAL_ENV)
|
|
82
|
+
# 3. System python3 (may lack dependencies)
|
|
83
|
+
# 4. System python (last resort)
|
|
84
|
+
#
|
|
85
|
+
# WHY THIS APPROACH:
|
|
86
|
+
# - Claude MPM requires specific packages (socketio, eventlet) not in system Python
|
|
87
|
+
# - Virtual environments ensure dependency isolation and availability
|
|
88
|
+
# - Multiple naming conventions supported (venv vs .venv)
|
|
89
|
+
# - Graceful degradation to system Python if no venv found
|
|
90
|
+
#
|
|
91
|
+
# ACTIVATION STRATEGY:
|
|
92
|
+
# - Sources activate script to set up environment variables
|
|
93
|
+
# - Returns specific Python path for exec (not just 'python')
|
|
94
|
+
# - Maintains environment in same shell process
|
|
95
|
+
#
|
|
96
|
+
# PERFORMANCE:
|
|
97
|
+
# - Fast path detection using file existence checks
|
|
98
|
+
# - Early returns to minimize overhead
|
|
99
|
+
# - Caches result in process environment
|
|
100
|
+
#
|
|
101
|
+
# RETURNS:
|
|
102
|
+
# Absolute path to Python executable with claude-mpm dependencies
|
|
103
|
+
#
|
|
104
|
+
find_python_command() {
|
|
105
|
+
# 1. Check for project-local virtual environment (common in development)
|
|
106
|
+
if [ -f "$CLAUDE_MPM_ROOT/venv/bin/activate" ]; then
|
|
107
|
+
source "$CLAUDE_MPM_ROOT/venv/bin/activate"
|
|
108
|
+
echo "$CLAUDE_MPM_ROOT/venv/bin/python"
|
|
109
|
+
elif [ -f "$CLAUDE_MPM_ROOT/.venv/bin/activate" ]; then
|
|
110
|
+
source "$CLAUDE_MPM_ROOT/.venv/bin/activate"
|
|
111
|
+
echo "$CLAUDE_MPM_ROOT/.venv/bin/python"
|
|
112
|
+
elif [ -n "$VIRTUAL_ENV" ]; then
|
|
113
|
+
# Already in a virtual environment
|
|
114
|
+
echo "$VIRTUAL_ENV/bin/python"
|
|
115
|
+
elif command -v python3 &> /dev/null; then
|
|
116
|
+
echo "python3"
|
|
117
|
+
else
|
|
118
|
+
echo "python"
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Set up Python command
|
|
123
|
+
PYTHON_CMD=$(find_python_command)
|
|
124
|
+
|
|
125
|
+
# Check if we're in a development environment (has src directory)
|
|
126
|
+
if [ -d "$CLAUDE_MPM_ROOT/src" ]; then
|
|
127
|
+
# Development install - add src to PYTHONPATH
|
|
128
|
+
export PYTHONPATH="$CLAUDE_MPM_ROOT/src:$PYTHONPATH"
|
|
129
|
+
|
|
130
|
+
if [ "${CLAUDE_MPM_HOOK_DEBUG}" = "true" ]; then
|
|
131
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Development environment detected" >> /tmp/claude-mpm-hook.log
|
|
132
|
+
fi
|
|
133
|
+
else
|
|
134
|
+
# Pip install - claude_mpm should be in site-packages
|
|
135
|
+
# No need to modify PYTHONPATH
|
|
136
|
+
if [ "${CLAUDE_MPM_HOOK_DEBUG}" = "true" ]; then
|
|
137
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Pip installation detected" >> /tmp/claude-mpm-hook.log
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Debug logging
|
|
142
|
+
if [ "${CLAUDE_MPM_HOOK_DEBUG}" = "true" ]; then
|
|
143
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] PYTHON_CMD: $PYTHON_CMD" >> /tmp/claude-mpm-hook.log
|
|
144
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] PYTHONPATH: $PYTHONPATH" >> /tmp/claude-mpm-hook.log
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# Set Socket.IO configuration for hook events
|
|
148
|
+
export CLAUDE_MPM_SOCKETIO_PORT="${CLAUDE_MPM_SOCKETIO_PORT:-8765}"
|
|
149
|
+
|
|
150
|
+
# Run the Python hook handler with all input
|
|
151
|
+
# Use exec to replace the shell process with Python
|
|
152
|
+
if ! exec "$PYTHON_CMD" -m claude_mpm.hooks.claude_hooks.hook_handler "$@" 2>/tmp/claude-mpm-hook-error.log; then
|
|
153
|
+
# If the Python handler fails, always return continue to not block Claude
|
|
154
|
+
if [ "${CLAUDE_MPM_HOOK_DEBUG}" = "true" ]; then
|
|
155
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Hook handler failed, see /tmp/claude-mpm-hook-error.log" >> /tmp/claude-mpm-hook.log
|
|
156
|
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Error: $(cat /tmp/claude-mpm-hook-error.log 2>/dev/null | head -5)" >> /tmp/claude-mpm-hook.log
|
|
157
|
+
fi
|
|
158
|
+
# Return continue action to prevent blocking Claude Code
|
|
159
|
+
echo '{"action": "continue"}'
|
|
160
|
+
exit 0
|
|
161
|
+
fi
|
|
@@ -1,7 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Socket.IO Daemon Management for Claude MPM.
|
|
4
|
+
|
|
5
|
+
This module provides pure Python daemon management for the Claude MPM Socket.IO server
|
|
6
|
+
without requiring external process management dependencies. It handles server lifecycle,
|
|
7
|
+
process detection, and virtual environment discovery.
|
|
8
|
+
|
|
9
|
+
Key Features:
|
|
10
|
+
- Pure Python implementation (no external deps)
|
|
11
|
+
- Virtual environment auto-detection
|
|
12
|
+
- Process management with PID tracking
|
|
13
|
+
- Signal handling for clean shutdown
|
|
14
|
+
- Port availability checking
|
|
15
|
+
- Background daemon execution
|
|
16
|
+
|
|
17
|
+
Architecture:
|
|
18
|
+
- Uses subprocess for server execution
|
|
19
|
+
- Implements daemon pattern with double-fork
|
|
20
|
+
- Maintains PID files for process tracking
|
|
21
|
+
- Auto-detects Python environment (venv/conda)
|
|
22
|
+
|
|
23
|
+
Thread Safety:
|
|
24
|
+
- Signal handlers are async-signal-safe
|
|
25
|
+
- PID file operations use atomic writes
|
|
26
|
+
- Process checks use system-level primitives
|
|
27
|
+
|
|
28
|
+
Performance Considerations:
|
|
29
|
+
- Minimal memory footprint for daemon mode
|
|
30
|
+
- Fast process detection using PID files
|
|
31
|
+
- Lazy loading of heavy imports
|
|
32
|
+
- Efficient port scanning
|
|
33
|
+
|
|
34
|
+
Security:
|
|
35
|
+
- Localhost-only binding for server
|
|
36
|
+
- PID file permissions restrict access
|
|
37
|
+
- Process ownership validation
|
|
38
|
+
- Signal handling prevents orphans
|
|
39
|
+
|
|
40
|
+
@author Claude MPM Team
|
|
41
|
+
@version 1.0
|
|
42
|
+
@since v4.0.25
|
|
5
43
|
"""
|
|
6
44
|
|
|
7
45
|
import os
|
|
@@ -13,13 +51,45 @@ from pathlib import Path
|
|
|
13
51
|
|
|
14
52
|
|
|
15
53
|
# Detect and use virtual environment Python if available
|
|
16
|
-
def get_python_executable():
|
|
54
|
+
def get_python_executable() -> str:
|
|
17
55
|
"""
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
56
|
+
Detect and return the appropriate Python executable for Socket.IO daemon.
|
|
57
|
+
|
|
58
|
+
Intelligently detects virtual environments (venv, conda, poetry, pipenv)
|
|
59
|
+
and returns the correct Python path to ensure dependency availability.
|
|
60
|
+
|
|
61
|
+
Detection Strategy:
|
|
62
|
+
1. Check if already running in virtual environment
|
|
63
|
+
2. Look for VIRTUAL_ENV environment variable
|
|
64
|
+
3. Analyze executable path structure
|
|
65
|
+
4. Search for project-specific virtual environments
|
|
66
|
+
5. Fall back to system Python
|
|
67
|
+
|
|
68
|
+
WHY this complex detection:
|
|
69
|
+
- Socket.IO server requires specific Python packages (socketio, eventlet)
|
|
70
|
+
- System Python rarely has these packages installed
|
|
71
|
+
- Virtual environments contain isolated dependencies
|
|
72
|
+
- Multiple venv tools have different conventions
|
|
73
|
+
|
|
74
|
+
Thread Safety:
|
|
75
|
+
- Read-only operations on sys and os modules
|
|
76
|
+
- File system checks are atomic
|
|
77
|
+
- No shared state modification
|
|
78
|
+
|
|
79
|
+
Performance:
|
|
80
|
+
- Early returns for common cases
|
|
81
|
+
- Minimal file system operations
|
|
82
|
+
- Cached in practice by Python import system
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
str: Path to Python executable with required dependencies
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
FileNotFoundError: If no suitable Python executable found
|
|
89
|
+
|
|
90
|
+
Examples:
|
|
91
|
+
>>> python_path = get_python_executable()
|
|
92
|
+
>>> # Returns: '/path/to/venv/bin/python' or '/usr/bin/python3'
|
|
23
93
|
"""
|
|
24
94
|
# First, check if we're already in a virtual environment
|
|
25
95
|
if hasattr(sys, "real_prefix") or (
|
|
@@ -274,6 +344,49 @@ def start_server():
|
|
|
274
344
|
# Start server using synchronous method
|
|
275
345
|
server.start_sync()
|
|
276
346
|
|
|
347
|
+
# Debug: Check if handlers are registered (write to file for daemon)
|
|
348
|
+
with open(LOG_FILE, "a") as f:
|
|
349
|
+
f.write(
|
|
350
|
+
f"\n[{time.strftime('%Y-%m-%d %H:%M:%S')}] Server started, checking handlers...\n"
|
|
351
|
+
)
|
|
352
|
+
if server.event_registry:
|
|
353
|
+
f.write(
|
|
354
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Event registry exists with {len(server.event_registry.handlers)} handlers\n"
|
|
355
|
+
)
|
|
356
|
+
for handler in server.event_registry.handlers:
|
|
357
|
+
f.write(
|
|
358
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] - {handler.__class__.__name__}\n"
|
|
359
|
+
)
|
|
360
|
+
else:
|
|
361
|
+
f.write(
|
|
362
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] WARNING: No event registry found!\n"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# Check Socket.IO events
|
|
366
|
+
if server.core and server.core.sio:
|
|
367
|
+
handlers = getattr(server.core.sio, "handlers", {})
|
|
368
|
+
f.write(
|
|
369
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Socket.IO has {len(handlers)} namespaces\n"
|
|
370
|
+
)
|
|
371
|
+
for namespace, events in handlers.items():
|
|
372
|
+
f.write(
|
|
373
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Namespace '{namespace}': {len(events)} events\n"
|
|
374
|
+
)
|
|
375
|
+
# List all events to debug
|
|
376
|
+
event_list = list(events.keys())
|
|
377
|
+
f.write(
|
|
378
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Events: {event_list}\n"
|
|
379
|
+
)
|
|
380
|
+
if "code:analyze:request" in events:
|
|
381
|
+
f.write(
|
|
382
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] ✅ code:analyze:request is registered!\n"
|
|
383
|
+
)
|
|
384
|
+
else:
|
|
385
|
+
f.write(
|
|
386
|
+
f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] ❌ code:analyze:request NOT found\n"
|
|
387
|
+
)
|
|
388
|
+
f.flush()
|
|
389
|
+
|
|
277
390
|
# Keep running
|
|
278
391
|
try:
|
|
279
392
|
while True:
|
|
@@ -141,7 +141,7 @@ class AgentLifecycleManager(BaseService):
|
|
|
141
141
|
records = await self.record_service.load_records()
|
|
142
142
|
self.state_service.agent_records = records
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
await self.record_service.load_history()
|
|
145
145
|
# Convert history back to operation results if needed
|
|
146
146
|
# For now, we'll start with empty history
|
|
147
147
|
|
|
@@ -299,7 +299,7 @@ class AgentLifecycleManager(BaseService):
|
|
|
299
299
|
# Update state if successful
|
|
300
300
|
if result.success:
|
|
301
301
|
# Create state record
|
|
302
|
-
|
|
302
|
+
self.state_service.create_record(
|
|
303
303
|
agent_name=agent_name,
|
|
304
304
|
tier=tier,
|
|
305
305
|
file_path=result.metadata.get("file_path", ""),
|
|
@@ -217,7 +217,7 @@ class AgentRecordService(BaseService):
|
|
|
217
217
|
Returns:
|
|
218
218
|
Deserialized AgentLifecycleRecord
|
|
219
219
|
"""
|
|
220
|
-
|
|
220
|
+
return AgentLifecycleRecord(
|
|
221
221
|
agent_name=data["agent_name"],
|
|
222
222
|
current_state=LifecycleState(data["current_state"]),
|
|
223
223
|
tier=ModificationTier(data["tier"]),
|
|
@@ -232,7 +232,6 @@ class AgentRecordService(BaseService):
|
|
|
232
232
|
validation_errors=data.get("validation_errors", []),
|
|
233
233
|
metadata=data.get("metadata", {}),
|
|
234
234
|
)
|
|
235
|
-
return record
|
|
236
235
|
|
|
237
236
|
async def export_records(self, output_path: Path, format: str = "json") -> bool:
|
|
238
237
|
"""
|
|
@@ -63,9 +63,7 @@ class MemoryFormatService:
|
|
|
63
63
|
# Skip headers, empty lines, and metadata
|
|
64
64
|
if (
|
|
65
65
|
not line
|
|
66
|
-
or line.startswith("#")
|
|
67
|
-
or line.startswith("Last Updated:")
|
|
68
|
-
or line.startswith("**")
|
|
66
|
+
or line.startswith(("#", "Last Updated:", "**"))
|
|
69
67
|
or line == "---"
|
|
70
68
|
):
|
|
71
69
|
continue
|
|
@@ -233,11 +233,7 @@ class AgentCleanupService(IAgentCleanupService):
|
|
|
233
233
|
all_agents = multi_source_service.discover_agents_from_all_sources()
|
|
234
234
|
|
|
235
235
|
# Detect orphaned agents
|
|
236
|
-
|
|
237
|
-
agents_dir, all_agents
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
return orphaned
|
|
236
|
+
return multi_source_service.detect_orphaned_agents(agents_dir, all_agents)
|
|
241
237
|
|
|
242
238
|
except Exception as e:
|
|
243
239
|
self.logger.error(f"Error finding orphaned agents: {e}", exc_info=True)
|
|
@@ -225,7 +225,7 @@ class AgentDependencyService(IAgentDependencyService):
|
|
|
225
225
|
all_python_deps = set()
|
|
226
226
|
all_system_deps = set()
|
|
227
227
|
|
|
228
|
-
for
|
|
228
|
+
for _agent_id, deps in loader.agent_dependencies.items():
|
|
229
229
|
if "python" in deps:
|
|
230
230
|
all_python_deps.update(deps["python"])
|
|
231
231
|
if "system" in deps:
|
|
@@ -324,10 +324,9 @@ class AgentValidationService(IAgentValidationService):
|
|
|
324
324
|
if fix_result.warnings:
|
|
325
325
|
total_issues += len(fix_result.warnings)
|
|
326
326
|
|
|
327
|
-
if fix_result.corrections:
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
agents_fixed.append(agent_id)
|
|
327
|
+
if fix_result.corrections and not dry_run:
|
|
328
|
+
total_fixed += len(fix_result.corrections)
|
|
329
|
+
agents_fixed.append(agent_id)
|
|
331
330
|
|
|
332
331
|
return {
|
|
333
332
|
"success": True,
|
|
@@ -134,9 +134,8 @@ class DashboardLauncher(IDashboardLauncher):
|
|
|
134
134
|
"""
|
|
135
135
|
try:
|
|
136
136
|
# Verify dependencies for Socket.IO dashboard
|
|
137
|
-
if monitor_mode:
|
|
138
|
-
|
|
139
|
-
return False, False
|
|
137
|
+
if monitor_mode and not self._verify_socketio_dependencies():
|
|
138
|
+
return False, False
|
|
140
139
|
|
|
141
140
|
self.logger.info(
|
|
142
141
|
f"Launching dashboard (port: {port}, monitor: {monitor_mode})"
|
|
@@ -176,17 +176,6 @@ class StartupCheckerService(IStartupChecker):
|
|
|
176
176
|
|
|
177
177
|
try:
|
|
178
178
|
# Check Python version
|
|
179
|
-
import sys
|
|
180
|
-
|
|
181
|
-
if sys.version_info < (3, 8):
|
|
182
|
-
warnings.append(
|
|
183
|
-
StartupWarning(
|
|
184
|
-
category="environment",
|
|
185
|
-
message=f"Python {sys.version_info.major}.{sys.version_info.minor} detected",
|
|
186
|
-
suggestion="Python 3.8+ is recommended for optimal performance",
|
|
187
|
-
severity="info",
|
|
188
|
-
)
|
|
189
|
-
)
|
|
190
179
|
|
|
191
180
|
# Check for common missing directories
|
|
192
181
|
warnings.extend(self._check_required_directories())
|
|
@@ -253,7 +253,7 @@ class CacheManager(ICacheManager):
|
|
|
253
253
|
with self._lock:
|
|
254
254
|
current_time = time.time()
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
return {
|
|
257
257
|
"capabilities": {
|
|
258
258
|
"cached": self._capabilities_cache is not None,
|
|
259
259
|
"age": (
|
|
@@ -307,5 +307,3 @@ class CacheManager(ICacheManager):
|
|
|
307
307
|
},
|
|
308
308
|
"fs_cache": self._fs_cache.get_stats() if self._fs_cache else {},
|
|
309
309
|
}
|
|
310
|
-
|
|
311
|
-
return stats
|
|
@@ -91,10 +91,7 @@ class PathResolver(IPathResolver):
|
|
|
91
91
|
resolved = path.resolve()
|
|
92
92
|
|
|
93
93
|
# Check if path exists if required
|
|
94
|
-
|
|
95
|
-
return False
|
|
96
|
-
|
|
97
|
-
return True
|
|
94
|
+
return not (must_exist and not resolved.exists())
|
|
98
95
|
except (OSError, ValueError):
|
|
99
96
|
return False
|
|
100
97
|
|
|
@@ -244,7 +244,7 @@ class ServiceContainer:
|
|
|
244
244
|
|
|
245
245
|
# Check for circular dependencies
|
|
246
246
|
if service_type in self._resolution_stack.stack:
|
|
247
|
-
raise CircularDependencyError(self._resolution_stack.stack
|
|
247
|
+
raise CircularDependencyError([*self._resolution_stack.stack, service_type])
|
|
248
248
|
|
|
249
249
|
try:
|
|
250
250
|
# Add to resolution stack
|
|
@@ -287,7 +287,7 @@ class ServiceContainer:
|
|
|
287
287
|
results = []
|
|
288
288
|
|
|
289
289
|
with self._lock:
|
|
290
|
-
for registered_type,
|
|
290
|
+
for registered_type, _descriptor in self._services.items():
|
|
291
291
|
# Check if registered type is subclass of requested type
|
|
292
292
|
if self._is_assignable(registered_type, service_type):
|
|
293
293
|
try:
|
|
@@ -197,7 +197,6 @@ class InstructionsCheck(BaseDiagnosticCheck):
|
|
|
197
197
|
)
|
|
198
198
|
|
|
199
199
|
# Calculate content hashes
|
|
200
|
-
content_hashes = {}
|
|
201
200
|
content_snippets = defaultdict(list)
|
|
202
201
|
|
|
203
202
|
for path in files:
|
|
@@ -265,7 +264,7 @@ class InstructionsCheck(BaseDiagnosticCheck):
|
|
|
265
264
|
for description, occurrences in pattern_occurrences.items():
|
|
266
265
|
if len(occurrences) > 1:
|
|
267
266
|
files_info = []
|
|
268
|
-
for path, count,
|
|
267
|
+
for path, count, _snippet in occurrences:
|
|
269
268
|
rel_path = (
|
|
270
269
|
path.relative_to(Path.cwd())
|
|
271
270
|
if Path.cwd() in path.parents or path.parent == Path.cwd()
|
|
@@ -24,20 +24,20 @@ from .resources import ResourceMonitorService
|
|
|
24
24
|
from .service import ServiceHealthService
|
|
25
25
|
|
|
26
26
|
__all__ = [
|
|
27
|
-
|
|
28
|
-
"ResourceMonitorService",
|
|
29
|
-
"ProcessHealthService",
|
|
30
|
-
"ServiceHealthService",
|
|
31
|
-
"NetworkHealthService",
|
|
32
|
-
"MonitoringAggregatorService",
|
|
33
|
-
# Base components
|
|
34
|
-
"HealthStatus",
|
|
35
|
-
"HealthMetric",
|
|
27
|
+
"AdvancedHealthMonitor",
|
|
36
28
|
"HealthCheckResult",
|
|
37
29
|
"HealthChecker",
|
|
30
|
+
"HealthMetric",
|
|
31
|
+
# Base components
|
|
32
|
+
"HealthStatus",
|
|
33
|
+
"MonitoringAggregatorService",
|
|
34
|
+
"NetworkConnectivityChecker",
|
|
35
|
+
"NetworkHealthService",
|
|
36
|
+
"ProcessHealthService",
|
|
38
37
|
# Legacy compatibility
|
|
39
38
|
"ProcessResourceChecker",
|
|
40
|
-
|
|
39
|
+
# New service-based API
|
|
40
|
+
"ResourceMonitorService",
|
|
41
41
|
"ServiceHealthChecker",
|
|
42
|
-
"
|
|
42
|
+
"ServiceHealthService",
|
|
43
43
|
]
|
|
@@ -47,22 +47,22 @@ from .monitoring import ( # noqa: F401; New service-based API; Base components;
|
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
__all__ = [
|
|
50
|
-
|
|
51
|
-
"ResourceMonitorService",
|
|
52
|
-
"ProcessHealthService",
|
|
53
|
-
"ServiceHealthService",
|
|
54
|
-
"NetworkHealthService",
|
|
55
|
-
"MonitoringAggregatorService",
|
|
56
|
-
# Base components
|
|
57
|
-
"HealthStatus",
|
|
58
|
-
"HealthMetric",
|
|
50
|
+
"AdvancedHealthMonitor",
|
|
59
51
|
"HealthCheckResult",
|
|
60
52
|
"HealthChecker",
|
|
53
|
+
"HealthMetric",
|
|
54
|
+
# Base components
|
|
55
|
+
"HealthStatus",
|
|
56
|
+
"MonitoringAggregatorService",
|
|
57
|
+
"NetworkConnectivityChecker",
|
|
58
|
+
"NetworkHealthService",
|
|
59
|
+
"ProcessHealthService",
|
|
61
60
|
# Legacy compatibility
|
|
62
61
|
"ProcessResourceChecker",
|
|
63
|
-
|
|
62
|
+
# New service-based API
|
|
63
|
+
"ResourceMonitorService",
|
|
64
64
|
"ServiceHealthChecker",
|
|
65
|
-
"
|
|
65
|
+
"ServiceHealthService",
|
|
66
66
|
]
|
|
67
67
|
|
|
68
68
|
# Module metadata
|
|
@@ -224,7 +224,7 @@ class ArchitectureAnalyzerService:
|
|
|
224
224
|
existing_dirs = set()
|
|
225
225
|
|
|
226
226
|
# Collect all directory names
|
|
227
|
-
for
|
|
227
|
+
for _dirpath, dirnames, _ in self.working_directory.walk():
|
|
228
228
|
for dirname in dirnames:
|
|
229
229
|
if not dirname.startswith("."):
|
|
230
230
|
existing_dirs.add(dirname.lower())
|
|
@@ -171,7 +171,7 @@ class DependencyAnalyzerService:
|
|
|
171
171
|
if any(pkg in dep_lower for pkg in db_packages):
|
|
172
172
|
databases.add(db_name)
|
|
173
173
|
|
|
174
|
-
return sorted(
|
|
174
|
+
return sorted(databases)
|
|
175
175
|
|
|
176
176
|
def detect_testing_frameworks(
|
|
177
177
|
self, dependencies: Optional[List[str]] = None
|
|
@@ -201,7 +201,7 @@ class DependencyAnalyzerService:
|
|
|
201
201
|
testing_frameworks.add(dep)
|
|
202
202
|
break
|
|
203
203
|
|
|
204
|
-
return sorted(
|
|
204
|
+
return sorted(testing_frameworks)
|
|
205
205
|
|
|
206
206
|
def detect_web_frameworks(self, dependencies: List[str]) -> List[str]:
|
|
207
207
|
"""Detect web frameworks from dependencies.
|
|
@@ -343,7 +343,7 @@ class DependencyAnalyzerService:
|
|
|
343
343
|
for dep in all_deps:
|
|
344
344
|
dep_lower = dep.lower()
|
|
345
345
|
# Check for database packages
|
|
346
|
-
for
|
|
346
|
+
for _db_name, db_packages in self.DATABASE_PACKAGES.items():
|
|
347
347
|
if any(pkg in dep_lower for pkg in db_packages):
|
|
348
348
|
dependencies["databases"].append(dep)
|
|
349
349
|
|
|
@@ -407,7 +407,7 @@ class DependencyAnalyzerService:
|
|
|
407
407
|
dep_lower = dep.lower()
|
|
408
408
|
|
|
409
409
|
# Check databases
|
|
410
|
-
for
|
|
410
|
+
for _db_name, db_packages in self.DATABASE_PACKAGES.items():
|
|
411
411
|
if any(pkg in dep_lower for pkg in db_packages):
|
|
412
412
|
dependencies["databases"].append(dep)
|
|
413
413
|
|
|
@@ -109,7 +109,7 @@ class LanguageAnalyzerService:
|
|
|
109
109
|
if files:
|
|
110
110
|
languages.add(lang)
|
|
111
111
|
|
|
112
|
-
return sorted(
|
|
112
|
+
return sorted(languages)
|
|
113
113
|
|
|
114
114
|
def detect_primary_language(
|
|
115
115
|
self, file_counts: Optional[Dict[str, int]] = None
|
|
@@ -229,7 +229,7 @@ class LanguageAnalyzerService:
|
|
|
229
229
|
"""Count files by extension in the project."""
|
|
230
230
|
counts = Counter()
|
|
231
231
|
|
|
232
|
-
for ext in self.FILE_EXTENSIONS
|
|
232
|
+
for ext in self.FILE_EXTENSIONS:
|
|
233
233
|
files = list(self.working_directory.rglob(f"*{ext}"))
|
|
234
234
|
# Filter out vendor directories
|
|
235
235
|
files = [
|
|
@@ -249,7 +249,7 @@ class LanguageAnalyzerService:
|
|
|
249
249
|
"""Get a sample of source files for analysis."""
|
|
250
250
|
source_files = []
|
|
251
251
|
|
|
252
|
-
for ext in self.FILE_EXTENSIONS
|
|
252
|
+
for ext in self.FILE_EXTENSIONS:
|
|
253
253
|
files = list(self.working_directory.rglob(f"*{ext}"))
|
|
254
254
|
# Filter out vendor directories
|
|
255
255
|
files = [
|
|
@@ -166,7 +166,7 @@ class MetricsCollectorService:
|
|
|
166
166
|
|
|
167
167
|
for file_path in self._iter_code_files():
|
|
168
168
|
try:
|
|
169
|
-
|
|
169
|
+
file_path.stat().st_size
|
|
170
170
|
lines = len(
|
|
171
171
|
file_path.read_text(encoding="utf-8", errors="ignore").splitlines()
|
|
172
172
|
)
|
|
@@ -377,7 +377,7 @@ class MetricsCollectorService:
|
|
|
377
377
|
|
|
378
378
|
# Count directories
|
|
379
379
|
dir_count = 0
|
|
380
|
-
for
|
|
380
|
+
for _dirpath, dirnames, _ in self.working_directory.walk():
|
|
381
381
|
dirnames[:] = [d for d in dirnames if d not in self.EXCLUDE_DIRS]
|
|
382
382
|
dir_count += len(dirnames)
|
|
383
383
|
|
|
@@ -404,7 +404,4 @@ class MetricsCollectorService:
|
|
|
404
404
|
def _should_analyze_file(self, file_path: Path) -> bool:
|
|
405
405
|
"""Check if a file should be analyzed."""
|
|
406
406
|
# Skip files in excluded directories
|
|
407
|
-
for part in file_path.parts
|
|
408
|
-
if part in self.EXCLUDE_DIRS:
|
|
409
|
-
return False
|
|
410
|
-
return True
|
|
407
|
+
return all(part not in self.EXCLUDE_DIRS for part in file_path.parts)
|