claude-mpm 4.0.29__py3-none-any.whl → 4.0.31__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.
Files changed (65) hide show
  1. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +48 -3
  2. claude_mpm/agents/BASE_PM.md +20 -15
  3. claude_mpm/agents/INSTRUCTIONS.md +12 -2
  4. claude_mpm/agents/templates/documentation.json +16 -3
  5. claude_mpm/agents/templates/engineer.json +19 -5
  6. claude_mpm/agents/templates/ops.json +19 -5
  7. claude_mpm/agents/templates/qa.json +16 -3
  8. claude_mpm/agents/templates/refactoring_engineer.json +25 -7
  9. claude_mpm/agents/templates/research.json +19 -5
  10. claude_mpm/cli/__init__.py +2 -0
  11. claude_mpm/cli/commands/__init__.py +2 -0
  12. claude_mpm/cli/commands/agent_manager.py +10 -6
  13. claude_mpm/cli/commands/agents.py +2 -1
  14. claude_mpm/cli/commands/cleanup.py +1 -1
  15. claude_mpm/cli/commands/doctor.py +209 -0
  16. claude_mpm/cli/commands/mcp.py +3 -3
  17. claude_mpm/cli/commands/mcp_install_commands.py +12 -30
  18. claude_mpm/cli/commands/mcp_server_commands.py +9 -9
  19. claude_mpm/cli/commands/run.py +31 -2
  20. claude_mpm/cli/commands/run_config_checker.py +1 -1
  21. claude_mpm/cli/parsers/agent_manager_parser.py +3 -3
  22. claude_mpm/cli/parsers/base_parser.py +5 -1
  23. claude_mpm/cli/parsers/mcp_parser.py +1 -1
  24. claude_mpm/cli/parsers/run_parser.py +1 -1
  25. claude_mpm/cli/startup_logging.py +463 -0
  26. claude_mpm/constants.py +1 -0
  27. claude_mpm/core/claude_runner.py +78 -0
  28. claude_mpm/core/framework_loader.py +45 -11
  29. claude_mpm/core/interactive_session.py +82 -3
  30. claude_mpm/core/output_style_manager.py +6 -6
  31. claude_mpm/core/unified_paths.py +128 -0
  32. claude_mpm/scripts/mcp_server.py +2 -2
  33. claude_mpm/services/agents/deployment/agent_validator.py +1 -0
  34. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +69 -1
  35. claude_mpm/services/agents/deployment/system_instructions_deployer.py +2 -2
  36. claude_mpm/services/diagnostics/__init__.py +18 -0
  37. claude_mpm/services/diagnostics/checks/__init__.py +30 -0
  38. claude_mpm/services/diagnostics/checks/agent_check.py +319 -0
  39. claude_mpm/services/diagnostics/checks/base_check.py +64 -0
  40. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +283 -0
  41. claude_mpm/services/diagnostics/checks/common_issues_check.py +354 -0
  42. claude_mpm/services/diagnostics/checks/configuration_check.py +300 -0
  43. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  44. claude_mpm/services/diagnostics/checks/installation_check.py +255 -0
  45. claude_mpm/services/diagnostics/checks/mcp_check.py +315 -0
  46. claude_mpm/services/diagnostics/checks/monitor_check.py +282 -0
  47. claude_mpm/services/diagnostics/checks/startup_log_check.py +322 -0
  48. claude_mpm/services/diagnostics/diagnostic_runner.py +247 -0
  49. claude_mpm/services/diagnostics/doctor_reporter.py +283 -0
  50. claude_mpm/services/diagnostics/models.py +120 -0
  51. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -1
  52. claude_mpm/services/mcp_gateway/main.py +1 -1
  53. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +3 -3
  54. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  55. claude_mpm/services/mcp_gateway/server/stdio_server.py +3 -3
  56. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +2 -2
  57. claude_mpm/services/socketio/handlers/registry.py +39 -7
  58. claude_mpm/services/socketio/server/core.py +72 -22
  59. claude_mpm/validation/frontmatter_validator.py +1 -1
  60. {claude_mpm-4.0.29.dist-info → claude_mpm-4.0.31.dist-info}/METADATA +4 -1
  61. {claude_mpm-4.0.29.dist-info → claude_mpm-4.0.31.dist-info}/RECORD +65 -48
  62. {claude_mpm-4.0.29.dist-info → claude_mpm-4.0.31.dist-info}/WHEEL +0 -0
  63. {claude_mpm-4.0.29.dist-info → claude_mpm-4.0.31.dist-info}/entry_points.txt +0 -0
  64. {claude_mpm-4.0.29.dist-info → claude_mpm-4.0.31.dist-info}/licenses/LICENSE +0 -0
  65. {claude_mpm-4.0.29.dist-info → claude_mpm-4.0.31.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,315 @@
1
+ """
2
+ Check MCP (Model Context Protocol) server status.
3
+
4
+ WHY: Verify that the MCP gateway is properly installed, configured,
5
+ and functioning for enhanced Claude Desktop capabilities.
6
+ """
7
+
8
+ import json
9
+ import subprocess
10
+ from pathlib import Path
11
+ from typing import Dict, Any
12
+
13
+ from ..models import DiagnosticResult, DiagnosticStatus
14
+ from .base_check import BaseDiagnosticCheck
15
+
16
+
17
+ class MCPCheck(BaseDiagnosticCheck):
18
+ """Check MCP server installation and configuration."""
19
+
20
+ @property
21
+ def name(self) -> str:
22
+ return "mcp_check"
23
+
24
+ @property
25
+ def category(self) -> str:
26
+ return "MCP Server"
27
+
28
+ def run(self) -> DiagnosticResult:
29
+ """Run MCP diagnostics."""
30
+ try:
31
+ from ....services.mcp_gateway.core.startup_verification import MCPGatewayStartupVerifier
32
+
33
+ sub_results = []
34
+ details = {}
35
+
36
+ # Check if MCP is installed
37
+ install_result = self._check_installation()
38
+ sub_results.append(install_result)
39
+ details["installed"] = install_result.status == DiagnosticStatus.OK
40
+
41
+ if install_result.status == DiagnosticStatus.OK:
42
+ # Check MCP configuration
43
+ config_result = self._check_configuration()
44
+ sub_results.append(config_result)
45
+ details["configured"] = config_result.status == DiagnosticStatus.OK
46
+
47
+ # Check MCP server status
48
+ status_result = self._check_server_status()
49
+ sub_results.append(status_result)
50
+ details["running"] = status_result.details.get("running", False)
51
+
52
+ # Verify startup
53
+ startup_result = self._check_startup_verification()
54
+ sub_results.append(startup_result)
55
+
56
+ # Determine overall status
57
+ if any(r.status == DiagnosticStatus.ERROR for r in sub_results):
58
+ status = DiagnosticStatus.ERROR
59
+ message = "MCP server has critical issues"
60
+ elif not details.get("installed", False):
61
+ status = DiagnosticStatus.WARNING
62
+ message = "MCP server not installed"
63
+ elif any(r.status == DiagnosticStatus.WARNING for r in sub_results):
64
+ status = DiagnosticStatus.WARNING
65
+ message = "MCP server needs configuration"
66
+ else:
67
+ status = DiagnosticStatus.OK
68
+ message = "MCP server properly configured"
69
+
70
+ return DiagnosticResult(
71
+ category=self.category,
72
+ status=status,
73
+ message=message,
74
+ details=details,
75
+ sub_results=sub_results if self.verbose else []
76
+ )
77
+
78
+ except Exception as e:
79
+ return DiagnosticResult(
80
+ category=self.category,
81
+ status=DiagnosticStatus.ERROR,
82
+ message=f"MCP check failed: {str(e)}",
83
+ details={"error": str(e)}
84
+ )
85
+
86
+ def _check_installation(self) -> DiagnosticResult:
87
+ """Check if MCP server is installed."""
88
+ # Check for MCP binary
89
+ mcp_paths = [
90
+ Path("/usr/local/bin/claude-mpm-mcp"),
91
+ Path.home() / ".local/bin/claude-mpm-mcp",
92
+ Path("/opt/claude-mpm/bin/claude-mpm-mcp")
93
+ ]
94
+
95
+ for mcp_path in mcp_paths:
96
+ if mcp_path.exists():
97
+ return DiagnosticResult(
98
+ category="MCP Installation",
99
+ status=DiagnosticStatus.OK,
100
+ message="MCP server installed",
101
+ details={"path": str(mcp_path), "installed": True}
102
+ )
103
+
104
+ # Check if it's available via command
105
+ try:
106
+ result = subprocess.run(
107
+ ["which", "claude-mpm-mcp"],
108
+ capture_output=True,
109
+ text=True,
110
+ timeout=2
111
+ )
112
+ if result.returncode == 0:
113
+ path = result.stdout.strip()
114
+ return DiagnosticResult(
115
+ category="MCP Installation",
116
+ status=DiagnosticStatus.OK,
117
+ message="MCP server installed",
118
+ details={"path": path, "installed": True}
119
+ )
120
+ except (subprocess.SubprocessError, FileNotFoundError):
121
+ pass
122
+
123
+ return DiagnosticResult(
124
+ category="MCP Installation",
125
+ status=DiagnosticStatus.WARNING,
126
+ message="MCP server not installed",
127
+ details={"installed": False},
128
+ fix_command="claude-mpm mcp install",
129
+ fix_description="Install MCP server for enhanced capabilities"
130
+ )
131
+
132
+ def _check_configuration(self) -> DiagnosticResult:
133
+ """Check MCP configuration in Claude Desktop."""
134
+ config_paths = [
135
+ Path.home() / ".config/claude/claude_desktop_config.json",
136
+ Path.home() / "Library/Application Support/Claude/claude_desktop_config.json",
137
+ Path.home() / "AppData/Roaming/Claude/claude_desktop_config.json"
138
+ ]
139
+
140
+ config_path = None
141
+ for path in config_paths:
142
+ if path.exists():
143
+ config_path = path
144
+ break
145
+
146
+ if not config_path:
147
+ return DiagnosticResult(
148
+ category="MCP Configuration",
149
+ status=DiagnosticStatus.WARNING,
150
+ message="Claude Desktop config not found",
151
+ details={"configured": False},
152
+ fix_command="claude-mpm mcp config",
153
+ fix_description="Configure MCP server in Claude Desktop"
154
+ )
155
+
156
+ try:
157
+ with open(config_path, 'r') as f:
158
+ config = json.load(f)
159
+
160
+ mcp_servers = config.get("mcpServers", {})
161
+ gateway = mcp_servers.get("claude-mpm-gateway", {})
162
+
163
+ if not gateway:
164
+ return DiagnosticResult(
165
+ category="MCP Configuration",
166
+ status=DiagnosticStatus.WARNING,
167
+ message="MCP gateway not configured",
168
+ details={"configured": False, "config_path": str(config_path)},
169
+ fix_command="claude-mpm mcp config",
170
+ fix_description="Add MCP gateway to Claude Desktop configuration"
171
+ )
172
+
173
+ # Check configuration validity
174
+ command = gateway.get("command")
175
+ if not command:
176
+ return DiagnosticResult(
177
+ category="MCP Configuration",
178
+ status=DiagnosticStatus.ERROR,
179
+ message="MCP gateway misconfigured (no command)",
180
+ details={
181
+ "configured": True,
182
+ "valid": False,
183
+ "config_path": str(config_path)
184
+ },
185
+ fix_command="claude-mpm mcp config --force",
186
+ fix_description="Fix MCP gateway configuration"
187
+ )
188
+
189
+ return DiagnosticResult(
190
+ category="MCP Configuration",
191
+ status=DiagnosticStatus.OK,
192
+ message="MCP gateway configured",
193
+ details={
194
+ "configured": True,
195
+ "command": command,
196
+ "config_path": str(config_path)
197
+ }
198
+ )
199
+
200
+ except json.JSONDecodeError as e:
201
+ return DiagnosticResult(
202
+ category="MCP Configuration",
203
+ status=DiagnosticStatus.ERROR,
204
+ message="Invalid JSON in config file",
205
+ details={"error": str(e), "config_path": str(config_path)},
206
+ fix_description="Fix JSON syntax in Claude Desktop config"
207
+ )
208
+ except Exception as e:
209
+ return DiagnosticResult(
210
+ category="MCP Configuration",
211
+ status=DiagnosticStatus.WARNING,
212
+ message=f"Could not check configuration: {str(e)}",
213
+ details={"error": str(e)}
214
+ )
215
+
216
+ def _check_server_status(self) -> DiagnosticResult:
217
+ """Check if MCP server is running."""
218
+ try:
219
+ # Try to connect to the MCP server
220
+ result = subprocess.run(
221
+ ["claude-mpm", "mcp", "status"],
222
+ capture_output=True,
223
+ text=True,
224
+ timeout=5
225
+ )
226
+
227
+ if result.returncode == 0:
228
+ if "running" in result.stdout.lower():
229
+ return DiagnosticResult(
230
+ category="MCP Server Status",
231
+ status=DiagnosticStatus.OK,
232
+ message="MCP server is running",
233
+ details={"running": True}
234
+ )
235
+ else:
236
+ return DiagnosticResult(
237
+ category="MCP Server Status",
238
+ status=DiagnosticStatus.WARNING,
239
+ message="MCP server not running",
240
+ details={"running": False},
241
+ fix_command="claude-mpm mcp start",
242
+ fix_description="Start the MCP server"
243
+ )
244
+ else:
245
+ return DiagnosticResult(
246
+ category="MCP Server Status",
247
+ status=DiagnosticStatus.WARNING,
248
+ message="Could not determine server status",
249
+ details={"running": "unknown", "error": result.stderr}
250
+ )
251
+
252
+ except subprocess.TimeoutExpired:
253
+ return DiagnosticResult(
254
+ category="MCP Server Status",
255
+ status=DiagnosticStatus.WARNING,
256
+ message="Server status check timed out",
257
+ details={"running": "unknown", "error": "timeout"}
258
+ )
259
+ except Exception as e:
260
+ return DiagnosticResult(
261
+ category="MCP Server Status",
262
+ status=DiagnosticStatus.WARNING,
263
+ message=f"Could not check server status: {str(e)}",
264
+ details={"running": "unknown", "error": str(e)}
265
+ )
266
+
267
+ def _check_startup_verification(self) -> DiagnosticResult:
268
+ """Run MCP startup verification."""
269
+ try:
270
+ from ....services.mcp_gateway.core.startup_verification import MCPGatewayStartupVerifier
271
+
272
+ verifier = MCPGatewayStartupVerifier()
273
+ issues = verifier.verify_startup()
274
+
275
+ if not issues:
276
+ return DiagnosticResult(
277
+ category="MCP Startup Verification",
278
+ status=DiagnosticStatus.OK,
279
+ message="Startup verification passed",
280
+ details={"issues": []}
281
+ )
282
+
283
+ # Categorize issues by severity
284
+ errors = [i for i in issues if "error" in i.lower() or "critical" in i.lower()]
285
+ warnings = [i for i in issues if i not in errors]
286
+
287
+ if errors:
288
+ return DiagnosticResult(
289
+ category="MCP Startup Verification",
290
+ status=DiagnosticStatus.ERROR,
291
+ message=f"{len(errors)} critical issue(s) found",
292
+ details={"errors": errors, "warnings": warnings}
293
+ )
294
+ elif warnings:
295
+ return DiagnosticResult(
296
+ category="MCP Startup Verification",
297
+ status=DiagnosticStatus.WARNING,
298
+ message=f"{len(warnings)} warning(s) found",
299
+ details={"warnings": warnings}
300
+ )
301
+ else:
302
+ return DiagnosticResult(
303
+ category="MCP Startup Verification",
304
+ status=DiagnosticStatus.OK,
305
+ message="Startup verification passed",
306
+ details={"issues": []}
307
+ )
308
+
309
+ except Exception as e:
310
+ return DiagnosticResult(
311
+ category="MCP Startup Verification",
312
+ status=DiagnosticStatus.WARNING,
313
+ message=f"Could not verify startup: {str(e)}",
314
+ details={"error": str(e)}
315
+ )
@@ -0,0 +1,282 @@
1
+ """
2
+ Check monitoring and SocketIO server status.
3
+
4
+ WHY: Verify that the monitoring system and SocketIO server are
5
+ properly configured and accessible for real-time updates.
6
+ """
7
+
8
+ import socket
9
+ from typing import Dict, Any
10
+
11
+ from ..models import DiagnosticResult, DiagnosticStatus
12
+ from .base_check import BaseDiagnosticCheck
13
+
14
+
15
+ class MonitorCheck(BaseDiagnosticCheck):
16
+ """Check monitoring and SocketIO server."""
17
+
18
+ @property
19
+ def name(self) -> str:
20
+ return "monitor_check"
21
+
22
+ @property
23
+ def category(self) -> str:
24
+ return "Monitor"
25
+
26
+ def run(self) -> DiagnosticResult:
27
+ """Run monitor diagnostics."""
28
+ try:
29
+ from ....services.port_manager import PortManager
30
+
31
+ sub_results = []
32
+ details = {}
33
+
34
+ # Check SocketIO availability
35
+ socketio_result = self._check_socketio()
36
+ sub_results.append(socketio_result)
37
+ details["socketio_available"] = socketio_result.status == DiagnosticStatus.OK
38
+
39
+ # Check port availability
40
+ port_result = self._check_ports()
41
+ sub_results.append(port_result)
42
+ details["ports"] = port_result.details
43
+
44
+ # Check response logging
45
+ logging_result = self._check_response_logging()
46
+ sub_results.append(logging_result)
47
+ details["response_logging"] = logging_result.details.get("enabled", False)
48
+
49
+ # Check hook service
50
+ hook_result = self._check_hook_service()
51
+ sub_results.append(hook_result)
52
+ details["hooks_enabled"] = hook_result.status == DiagnosticStatus.OK
53
+
54
+ # Determine overall status
55
+ if any(r.status == DiagnosticStatus.ERROR for r in sub_results):
56
+ status = DiagnosticStatus.ERROR
57
+ message = "Monitoring has critical issues"
58
+ elif any(r.status == DiagnosticStatus.WARNING for r in sub_results):
59
+ status = DiagnosticStatus.WARNING
60
+ message = "Monitoring has minor issues"
61
+ else:
62
+ status = DiagnosticStatus.OK
63
+ message = "Monitoring properly configured"
64
+
65
+ return DiagnosticResult(
66
+ category=self.category,
67
+ status=status,
68
+ message=message,
69
+ details=details,
70
+ sub_results=sub_results if self.verbose else []
71
+ )
72
+
73
+ except Exception as e:
74
+ return DiagnosticResult(
75
+ category=self.category,
76
+ status=DiagnosticStatus.ERROR,
77
+ message=f"Monitor check failed: {str(e)}",
78
+ details={"error": str(e)}
79
+ )
80
+
81
+ def _check_socketio(self) -> DiagnosticResult:
82
+ """Check if SocketIO is available."""
83
+ try:
84
+ import socketio
85
+
86
+ return DiagnosticResult(
87
+ category="SocketIO",
88
+ status=DiagnosticStatus.OK,
89
+ message="SocketIO library available",
90
+ details={"available": True, "version": getattr(socketio, "__version__", "unknown")}
91
+ )
92
+ except ImportError:
93
+ return DiagnosticResult(
94
+ category="SocketIO",
95
+ status=DiagnosticStatus.WARNING,
96
+ message="SocketIO not installed",
97
+ details={"available": False},
98
+ fix_command="pip install python-socketio[asyncio]",
99
+ fix_description="Install SocketIO for real-time monitoring"
100
+ )
101
+
102
+ def _check_ports(self) -> DiagnosticResult:
103
+ """Check port availability for monitoring services."""
104
+ try:
105
+ from ....services.port_manager import PortManager
106
+
107
+ port_manager = PortManager()
108
+
109
+ # Check default monitoring port range
110
+ available_ports = []
111
+ blocked_ports = []
112
+
113
+ for port in range(8765, 8786):
114
+ if self._is_port_available(port):
115
+ available_ports.append(port)
116
+ else:
117
+ blocked_ports.append(port)
118
+
119
+ if not available_ports:
120
+ return DiagnosticResult(
121
+ category="Port Availability",
122
+ status=DiagnosticStatus.ERROR,
123
+ message="No monitoring ports available (8765-8785)",
124
+ details={
125
+ "available": [],
126
+ "blocked": blocked_ports,
127
+ "checked_range": "8765-8785"
128
+ },
129
+ fix_description="Free up ports in the 8765-8785 range"
130
+ )
131
+
132
+ # Check if default port is available
133
+ default_port = 8765
134
+ if default_port not in available_ports:
135
+ return DiagnosticResult(
136
+ category="Port Availability",
137
+ status=DiagnosticStatus.WARNING,
138
+ message=f"Default port {default_port} in use, but alternatives available",
139
+ details={
140
+ "available": available_ports,
141
+ "blocked": blocked_ports,
142
+ "default_port": default_port
143
+ }
144
+ )
145
+
146
+ return DiagnosticResult(
147
+ category="Port Availability",
148
+ status=DiagnosticStatus.OK,
149
+ message=f"{len(available_ports)} monitoring port(s) available",
150
+ details={
151
+ "available": available_ports,
152
+ "blocked": blocked_ports,
153
+ "default_port": default_port
154
+ }
155
+ )
156
+
157
+ except Exception as e:
158
+ return DiagnosticResult(
159
+ category="Port Availability",
160
+ status=DiagnosticStatus.WARNING,
161
+ message=f"Could not check ports: {str(e)}",
162
+ details={"error": str(e)}
163
+ )
164
+
165
+ def _is_port_available(self, port: int) -> bool:
166
+ """Check if a specific port is available."""
167
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
168
+ sock.settimeout(0.1)
169
+ try:
170
+ result = sock.connect_ex(('localhost', port))
171
+ return result != 0
172
+ finally:
173
+ sock.close()
174
+
175
+ def _check_response_logging(self) -> DiagnosticResult:
176
+ """Check response logging configuration."""
177
+ from pathlib import Path
178
+ import yaml
179
+
180
+ # Check user config
181
+ config_paths = [
182
+ Path.home() / ".claude" / "claude-mpm.yaml",
183
+ Path.cwd() / ".claude" / "claude-mpm.yaml"
184
+ ]
185
+
186
+ response_logging_enabled = False
187
+ log_path = None
188
+
189
+ for config_path in config_paths:
190
+ if config_path.exists():
191
+ try:
192
+ with open(config_path, 'r') as f:
193
+ config = yaml.safe_load(f)
194
+ if config and isinstance(config, dict):
195
+ response_config = config.get("response_logging", {})
196
+ if response_config.get("enabled", False):
197
+ response_logging_enabled = True
198
+ log_path = response_config.get("path", "~/.claude/responses")
199
+ break
200
+ except Exception:
201
+ pass
202
+
203
+ if not response_logging_enabled:
204
+ return DiagnosticResult(
205
+ category="Response Logging",
206
+ status=DiagnosticStatus.OK,
207
+ message="Response logging disabled (default)",
208
+ details={"enabled": False}
209
+ )
210
+
211
+ # Check log directory
212
+ log_dir = Path(log_path).expanduser()
213
+ if not log_dir.exists():
214
+ return DiagnosticResult(
215
+ category="Response Logging",
216
+ status=DiagnosticStatus.WARNING,
217
+ message="Response logging enabled but directory missing",
218
+ details={
219
+ "enabled": True,
220
+ "path": str(log_dir),
221
+ "exists": False
222
+ },
223
+ fix_command=f"mkdir -p {log_dir}",
224
+ fix_description="Create response logging directory"
225
+ )
226
+
227
+ import os
228
+ if not os.access(log_dir, os.W_OK):
229
+ return DiagnosticResult(
230
+ category="Response Logging",
231
+ status=DiagnosticStatus.WARNING,
232
+ message="Response logging directory not writable",
233
+ details={
234
+ "enabled": True,
235
+ "path": str(log_dir),
236
+ "writable": False
237
+ },
238
+ fix_command=f"chmod 755 {log_dir}",
239
+ fix_description="Fix permissions on logging directory"
240
+ )
241
+
242
+ return DiagnosticResult(
243
+ category="Response Logging",
244
+ status=DiagnosticStatus.OK,
245
+ message="Response logging enabled and configured",
246
+ details={
247
+ "enabled": True,
248
+ "path": str(log_dir),
249
+ "exists": True,
250
+ "writable": True
251
+ }
252
+ )
253
+
254
+ def _check_hook_service(self) -> DiagnosticResult:
255
+ """Check hook service configuration."""
256
+ try:
257
+ from ....services.hook_service import HookService
258
+
259
+ # Try to create hook service instance
260
+ hook_service = HookService()
261
+
262
+ return DiagnosticResult(
263
+ category="Hook Service",
264
+ status=DiagnosticStatus.OK,
265
+ message="Hook service available",
266
+ details={"available": True}
267
+ )
268
+
269
+ except ImportError:
270
+ return DiagnosticResult(
271
+ category="Hook Service",
272
+ status=DiagnosticStatus.WARNING,
273
+ message="Hook service not available",
274
+ details={"available": False}
275
+ )
276
+ except Exception as e:
277
+ return DiagnosticResult(
278
+ category="Hook Service",
279
+ status=DiagnosticStatus.WARNING,
280
+ message=f"Hook service error: {str(e)}",
281
+ details={"available": False, "error": str(e)}
282
+ )