mcp-ticketer 0.4.11__py3-none-any.whl → 2.0.1__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.

Potentially problematic release.


This version of mcp-ticketer might be problematic. Click here for more details.

Files changed (111) hide show
  1. mcp_ticketer/__init__.py +10 -10
  2. mcp_ticketer/__version__.py +3 -3
  3. mcp_ticketer/adapters/__init__.py +2 -0
  4. mcp_ticketer/adapters/aitrackdown.py +394 -9
  5. mcp_ticketer/adapters/asana/__init__.py +15 -0
  6. mcp_ticketer/adapters/asana/adapter.py +1416 -0
  7. mcp_ticketer/adapters/asana/client.py +292 -0
  8. mcp_ticketer/adapters/asana/mappers.py +348 -0
  9. mcp_ticketer/adapters/asana/types.py +146 -0
  10. mcp_ticketer/adapters/github.py +836 -105
  11. mcp_ticketer/adapters/hybrid.py +47 -5
  12. mcp_ticketer/adapters/jira.py +772 -1
  13. mcp_ticketer/adapters/linear/adapter.py +2293 -108
  14. mcp_ticketer/adapters/linear/client.py +146 -12
  15. mcp_ticketer/adapters/linear/mappers.py +105 -11
  16. mcp_ticketer/adapters/linear/queries.py +168 -1
  17. mcp_ticketer/adapters/linear/types.py +80 -4
  18. mcp_ticketer/analysis/__init__.py +56 -0
  19. mcp_ticketer/analysis/dependency_graph.py +255 -0
  20. mcp_ticketer/analysis/health_assessment.py +304 -0
  21. mcp_ticketer/analysis/orphaned.py +218 -0
  22. mcp_ticketer/analysis/project_status.py +594 -0
  23. mcp_ticketer/analysis/similarity.py +224 -0
  24. mcp_ticketer/analysis/staleness.py +266 -0
  25. mcp_ticketer/automation/__init__.py +11 -0
  26. mcp_ticketer/automation/project_updates.py +378 -0
  27. mcp_ticketer/cache/memory.py +3 -3
  28. mcp_ticketer/cli/adapter_diagnostics.py +4 -2
  29. mcp_ticketer/cli/auggie_configure.py +18 -6
  30. mcp_ticketer/cli/codex_configure.py +175 -60
  31. mcp_ticketer/cli/configure.py +884 -146
  32. mcp_ticketer/cli/cursor_configure.py +314 -0
  33. mcp_ticketer/cli/diagnostics.py +31 -28
  34. mcp_ticketer/cli/discover.py +293 -21
  35. mcp_ticketer/cli/gemini_configure.py +18 -6
  36. mcp_ticketer/cli/init_command.py +880 -0
  37. mcp_ticketer/cli/instruction_commands.py +435 -0
  38. mcp_ticketer/cli/linear_commands.py +99 -15
  39. mcp_ticketer/cli/main.py +109 -2055
  40. mcp_ticketer/cli/mcp_configure.py +673 -99
  41. mcp_ticketer/cli/mcp_server_commands.py +415 -0
  42. mcp_ticketer/cli/migrate_config.py +12 -8
  43. mcp_ticketer/cli/platform_commands.py +6 -6
  44. mcp_ticketer/cli/platform_detection.py +477 -0
  45. mcp_ticketer/cli/platform_installer.py +536 -0
  46. mcp_ticketer/cli/project_update_commands.py +350 -0
  47. mcp_ticketer/cli/queue_commands.py +15 -15
  48. mcp_ticketer/cli/setup_command.py +639 -0
  49. mcp_ticketer/cli/simple_health.py +13 -11
  50. mcp_ticketer/cli/ticket_commands.py +277 -36
  51. mcp_ticketer/cli/update_checker.py +313 -0
  52. mcp_ticketer/cli/utils.py +45 -41
  53. mcp_ticketer/core/__init__.py +35 -1
  54. mcp_ticketer/core/adapter.py +170 -5
  55. mcp_ticketer/core/config.py +38 -31
  56. mcp_ticketer/core/env_discovery.py +33 -3
  57. mcp_ticketer/core/env_loader.py +7 -6
  58. mcp_ticketer/core/exceptions.py +10 -4
  59. mcp_ticketer/core/http_client.py +10 -10
  60. mcp_ticketer/core/instructions.py +405 -0
  61. mcp_ticketer/core/label_manager.py +732 -0
  62. mcp_ticketer/core/mappers.py +32 -20
  63. mcp_ticketer/core/models.py +136 -1
  64. mcp_ticketer/core/onepassword_secrets.py +379 -0
  65. mcp_ticketer/core/priority_matcher.py +463 -0
  66. mcp_ticketer/core/project_config.py +148 -14
  67. mcp_ticketer/core/registry.py +1 -1
  68. mcp_ticketer/core/session_state.py +171 -0
  69. mcp_ticketer/core/state_matcher.py +592 -0
  70. mcp_ticketer/core/url_parser.py +425 -0
  71. mcp_ticketer/core/validators.py +69 -0
  72. mcp_ticketer/defaults/ticket_instructions.md +644 -0
  73. mcp_ticketer/mcp/__init__.py +2 -2
  74. mcp_ticketer/mcp/server/__init__.py +2 -2
  75. mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
  76. mcp_ticketer/mcp/server/main.py +187 -93
  77. mcp_ticketer/mcp/server/routing.py +655 -0
  78. mcp_ticketer/mcp/server/server_sdk.py +58 -0
  79. mcp_ticketer/mcp/server/tools/__init__.py +37 -9
  80. mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
  81. mcp_ticketer/mcp/server/tools/attachment_tools.py +65 -20
  82. mcp_ticketer/mcp/server/tools/bulk_tools.py +259 -202
  83. mcp_ticketer/mcp/server/tools/comment_tools.py +74 -12
  84. mcp_ticketer/mcp/server/tools/config_tools.py +1429 -0
  85. mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
  86. mcp_ticketer/mcp/server/tools/hierarchy_tools.py +878 -319
  87. mcp_ticketer/mcp/server/tools/instruction_tools.py +295 -0
  88. mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
  89. mcp_ticketer/mcp/server/tools/pr_tools.py +3 -7
  90. mcp_ticketer/mcp/server/tools/project_status_tools.py +158 -0
  91. mcp_ticketer/mcp/server/tools/project_update_tools.py +473 -0
  92. mcp_ticketer/mcp/server/tools/search_tools.py +180 -97
  93. mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
  94. mcp_ticketer/mcp/server/tools/ticket_tools.py +1182 -82
  95. mcp_ticketer/mcp/server/tools/user_ticket_tools.py +364 -0
  96. mcp_ticketer/queue/health_monitor.py +1 -0
  97. mcp_ticketer/queue/manager.py +4 -4
  98. mcp_ticketer/queue/queue.py +3 -3
  99. mcp_ticketer/queue/run_worker.py +1 -1
  100. mcp_ticketer/queue/ticket_registry.py +2 -2
  101. mcp_ticketer/queue/worker.py +15 -13
  102. mcp_ticketer/utils/__init__.py +5 -0
  103. mcp_ticketer/utils/token_utils.py +246 -0
  104. mcp_ticketer-2.0.1.dist-info/METADATA +1366 -0
  105. mcp_ticketer-2.0.1.dist-info/RECORD +122 -0
  106. mcp_ticketer-0.4.11.dist-info/METADATA +0 -496
  107. mcp_ticketer-0.4.11.dist-info/RECORD +0 -77
  108. {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/WHEEL +0 -0
  109. {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/entry_points.txt +0 -0
  110. {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/licenses/LICENSE +0 -0
  111. {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,314 @@
1
+ """Cursor code editor configuration for mcp-ticketer integration.
2
+
3
+ Cursor uses project-level MCP configuration at ~/.cursor/mcp.json
4
+ with a flat mcpServers structure (similar to Claude Code's global config).
5
+ """
6
+
7
+ import json
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from rich.console import Console
12
+
13
+ from .mcp_configure import load_project_config
14
+ from .python_detection import get_mcp_ticketer_python
15
+
16
+ console = Console()
17
+
18
+
19
+ def find_cursor_config() -> Path:
20
+ """Find or create Cursor MCP configuration file.
21
+
22
+ Cursor uses global MCP configuration with flat structure.
23
+
24
+ Returns:
25
+ Path to Cursor MCP config file at ~/.cursor/mcp.json
26
+
27
+ """
28
+ config_path = Path.home() / ".cursor" / "mcp.json"
29
+ return config_path
30
+
31
+
32
+ def load_cursor_config(config_path: Path) -> dict[str, Any]:
33
+ """Load existing Cursor configuration or return empty structure.
34
+
35
+ Args:
36
+ config_path: Path to Cursor MCP config file
37
+
38
+ Returns:
39
+ Cursor MCP configuration dict
40
+
41
+ """
42
+ if config_path.exists():
43
+ try:
44
+ with open(config_path) as f:
45
+ content = f.read().strip()
46
+ if not content:
47
+ return {"mcpServers": {}}
48
+ config: dict[str, Any] = json.load(f)
49
+ return config
50
+ except json.JSONDecodeError as e:
51
+ console.print(
52
+ f"[yellow]⚠ Warning: Invalid JSON in {config_path}, creating new config[/yellow]"
53
+ )
54
+ console.print(f"[dim]Error: {e}[/dim]")
55
+
56
+ # Return empty structure with mcpServers section
57
+ return {"mcpServers": {}}
58
+
59
+
60
+ def save_cursor_config(config_path: Path, config: dict[str, Any]) -> None:
61
+ """Save Cursor MCP configuration to file.
62
+
63
+ Args:
64
+ config_path: Path to Cursor MCP config file
65
+ config: Configuration to save
66
+
67
+ """
68
+ # Ensure directory exists
69
+ config_path.parent.mkdir(parents=True, exist_ok=True)
70
+
71
+ # Write with 2-space indentation (JSON standard)
72
+ with open(config_path, "w") as f:
73
+ json.dump(config, f, indent=2)
74
+
75
+
76
+ def create_cursor_server_config(
77
+ python_path: str,
78
+ project_config: dict[str, Any],
79
+ project_path: str | None = None,
80
+ ) -> dict[str, Any]:
81
+ """Create Cursor MCP server configuration for mcp-ticketer.
82
+
83
+ Uses the CLI command (mcp-ticketer mcp) which implements proper
84
+ Content-Length framing via FastMCP SDK, required for modern MCP clients.
85
+
86
+ Args:
87
+ python_path: Path to Python executable in mcp-ticketer venv
88
+ project_config: Project configuration from .mcp-ticketer/config.json
89
+ project_path: Project directory path (optional, for project-specific config)
90
+
91
+ Returns:
92
+ Cursor MCP server configuration dict
93
+
94
+ """
95
+ # IMPORTANT: Use CLI command, NOT Python module invocation
96
+ # The CLI uses FastMCP SDK which implements proper Content-Length framing
97
+ from pathlib import Path
98
+
99
+ # Get adapter configuration
100
+ adapter = project_config.get("default_adapter", "aitrackdown")
101
+ adapters_config = project_config.get("adapters", {})
102
+ adapter_config = adapters_config.get(adapter, {})
103
+
104
+ # Get mcp-ticketer CLI path from Python path
105
+ python_dir = Path(python_path).parent
106
+ cli_path = str(python_dir / "mcp-ticketer")
107
+
108
+ # Build CLI arguments
109
+ args = ["mcp"]
110
+ if project_path:
111
+ args.extend(["--path", project_path])
112
+
113
+ # Build environment variables
114
+ env_vars = {}
115
+
116
+ # Add PYTHONPATH for project context
117
+ if project_path:
118
+ env_vars["PYTHONPATH"] = project_path
119
+
120
+ # Add adapter type
121
+ env_vars["MCP_TICKETER_ADAPTER"] = adapter
122
+
123
+ # Add adapter-specific environment variables
124
+ if adapter == "linear" and "api_key" in adapter_config:
125
+ env_vars["LINEAR_API_KEY"] = adapter_config["api_key"]
126
+ if "team_id" in adapter_config:
127
+ env_vars["LINEAR_TEAM_ID"] = adapter_config["team_id"]
128
+ elif adapter == "github" and "token" in adapter_config:
129
+ env_vars["GITHUB_TOKEN"] = adapter_config["token"]
130
+ if "owner" in adapter_config:
131
+ env_vars["GITHUB_OWNER"] = adapter_config["owner"]
132
+ if "repo" in adapter_config:
133
+ env_vars["GITHUB_REPO"] = adapter_config["repo"]
134
+ elif adapter == "jira":
135
+ if "api_token" in adapter_config:
136
+ env_vars["JIRA_API_TOKEN"] = adapter_config["api_token"]
137
+ if "email" in adapter_config:
138
+ env_vars["JIRA_EMAIL"] = adapter_config["email"]
139
+
140
+ # Create server configuration with Cursor-specific fields
141
+ config = {
142
+ "type": "stdio", # Cursor requires explicit type
143
+ "command": cli_path,
144
+ "args": args,
145
+ "env": env_vars,
146
+ }
147
+
148
+ # Add working directory for project-specific configs
149
+ if project_path:
150
+ config["cwd"] = project_path
151
+
152
+ return config
153
+
154
+
155
+ def remove_cursor_mcp(dry_run: bool = False) -> None:
156
+ """Remove mcp-ticketer from Cursor configuration.
157
+
158
+ Args:
159
+ dry_run: Show what would be removed without making changes
160
+
161
+ """
162
+ # Step 1: Find Cursor config location
163
+ console.print("[cyan]šŸ” Removing Cursor MCP configuration...[/cyan]")
164
+
165
+ cursor_config_path = find_cursor_config()
166
+ console.print(f"[dim]Config location: {cursor_config_path}[/dim]")
167
+
168
+ # Step 2: Check if config file exists
169
+ if not cursor_config_path.exists():
170
+ console.print(
171
+ f"[yellow]⚠ No configuration found at {cursor_config_path}[/yellow]"
172
+ )
173
+ console.print("[dim]mcp-ticketer is not configured for Cursor[/dim]")
174
+ return
175
+
176
+ # Step 3: Load existing Cursor configuration
177
+ cursor_config = load_cursor_config(cursor_config_path)
178
+
179
+ # Step 4: Check if mcp-ticketer is configured
180
+ if "mcp-ticketer" not in cursor_config.get("mcpServers", {}):
181
+ console.print("[yellow]⚠ mcp-ticketer is not configured[/yellow]")
182
+ console.print(f"[dim]No mcp-ticketer entry found in {cursor_config_path}[/dim]")
183
+ return
184
+
185
+ # Show what would be removed (dry run)
186
+ if dry_run:
187
+ console.print(
188
+ f"\n[cyan]DRY RUN - Would remove from: {cursor_config_path}[/cyan]"
189
+ )
190
+ console.print(" Server name: mcp-ticketer")
191
+ return
192
+
193
+ # Step 5: Remove mcp-ticketer from configuration
194
+ del cursor_config["mcpServers"]["mcp-ticketer"]
195
+
196
+ # Step 6: Save updated configuration
197
+ try:
198
+ save_cursor_config(cursor_config_path, cursor_config)
199
+ console.print("\n[green]āœ“ Successfully removed mcp-ticketer[/green]")
200
+ console.print(f"[dim]Updated {cursor_config_path}[/dim]")
201
+
202
+ # Next steps
203
+ console.print("\n[bold cyan]Next Steps:[/bold cyan]")
204
+ console.print("1. Restart Cursor editor")
205
+ console.print("2. mcp-ticketer will no longer be available in MCP menu")
206
+ except Exception as e:
207
+ console.print(f"\n[red]āœ— Failed to save configuration:[/red] {e}")
208
+ raise
209
+
210
+
211
+ def configure_cursor_mcp(force: bool = False) -> None:
212
+ """Configure Cursor to use mcp-ticketer.
213
+
214
+ Args:
215
+ force: Overwrite existing configuration
216
+
217
+ Raises:
218
+ FileNotFoundError: If Python executable or project config not found
219
+ ValueError: If configuration is invalid
220
+
221
+ """
222
+ # Determine project path
223
+ project_path = Path.cwd()
224
+
225
+ # Step 1: Find Python executable
226
+ console.print("[cyan]šŸ” Finding mcp-ticketer Python executable...[/cyan]")
227
+ try:
228
+ python_path = get_mcp_ticketer_python(project_path=project_path)
229
+ console.print(f"[green]āœ“[/green] Found: {python_path}")
230
+
231
+ # Show if using project venv or fallback
232
+ if str(project_path / ".venv") in python_path:
233
+ console.print("[dim]Using project-specific venv[/dim]")
234
+ else:
235
+ console.print("[dim]Using pipx/system Python[/dim]")
236
+ except Exception as e:
237
+ console.print(f"[red]āœ—[/red] Could not find Python executable: {e}")
238
+ raise FileNotFoundError(
239
+ "Could not find mcp-ticketer Python executable. "
240
+ "Please ensure mcp-ticketer is installed.\n"
241
+ "Install with: pip install mcp-ticketer or pipx install mcp-ticketer"
242
+ ) from e
243
+
244
+ # Step 2: Load project configuration
245
+ console.print("\n[cyan]šŸ“– Reading project configuration...[/cyan]")
246
+ try:
247
+ mcp_project_config = load_project_config()
248
+ adapter = mcp_project_config.get("default_adapter", "aitrackdown")
249
+ console.print(f"[green]āœ“[/green] Adapter: {adapter}")
250
+ except (FileNotFoundError, ValueError) as e:
251
+ console.print(f"[red]āœ—[/red] {e}")
252
+ raise
253
+
254
+ # Step 3: Find Cursor MCP config location
255
+ console.print("\n[cyan]šŸ”§ Configuring Cursor MCP...[/cyan]")
256
+
257
+ cursor_config_path = find_cursor_config()
258
+ console.print(f"[dim]Config path: {cursor_config_path}[/dim]")
259
+
260
+ # Step 4: Load existing MCP configuration
261
+ cursor_config = load_cursor_config(cursor_config_path)
262
+
263
+ # Step 5: Check if mcp-ticketer already configured
264
+ already_configured = "mcp-ticketer" in cursor_config.get("mcpServers", {})
265
+
266
+ if already_configured:
267
+ if not force:
268
+ console.print("[yellow]⚠ mcp-ticketer is already configured[/yellow]")
269
+ console.print("[dim]Use --force to overwrite existing configuration[/dim]")
270
+ return
271
+ else:
272
+ console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
273
+
274
+ # Step 6: Create mcp-ticketer server config
275
+ server_config = create_cursor_server_config(
276
+ python_path=python_path,
277
+ project_config=mcp_project_config,
278
+ project_path=str(project_path.resolve()),
279
+ )
280
+
281
+ # Step 7: Update MCP configuration
282
+ if "mcpServers" not in cursor_config:
283
+ cursor_config["mcpServers"] = {}
284
+ cursor_config["mcpServers"]["mcp-ticketer"] = server_config
285
+
286
+ # Step 8: Save configuration
287
+ try:
288
+ save_cursor_config(cursor_config_path, cursor_config)
289
+ console.print("\n[green]āœ“ Successfully configured mcp-ticketer[/green]")
290
+ console.print(f"[dim]Configuration saved to: {cursor_config_path}[/dim]")
291
+
292
+ # Print configuration details
293
+ console.print("\n[bold]Configuration Details:[/bold]")
294
+ console.print(" Server name: mcp-ticketer")
295
+ console.print(f" Adapter: {adapter}")
296
+ console.print(f" Python: {python_path}")
297
+ console.print(f" Command: {server_config.get('command')}")
298
+ console.print(f" Args: {server_config.get('args')}")
299
+ console.print(" Protocol: Content-Length framing (FastMCP SDK)")
300
+ console.print(f" Project path: {project_path}")
301
+ if "env" in server_config:
302
+ console.print(
303
+ f" Environment variables: {list(server_config['env'].keys())}"
304
+ )
305
+
306
+ # Next steps
307
+ console.print("\n[bold cyan]Next Steps:[/bold cyan]")
308
+ console.print("1. Restart Cursor editor")
309
+ console.print("2. Open this project in Cursor")
310
+ console.print("3. mcp-ticketer tools will be available in the MCP menu")
311
+
312
+ except Exception as e:
313
+ console.print(f"\n[red]āœ— Failed to save configuration:[/red] {e}")
314
+ raise
@@ -12,7 +12,7 @@ from rich.console import Console
12
12
  from rich.table import Table
13
13
 
14
14
 
15
- def get_config():
15
+ def get_config() -> Any:
16
16
  """Get configuration using the real configuration system."""
17
17
  from ..core.config import ConfigurationManager
18
18
 
@@ -20,7 +20,7 @@ def get_config():
20
20
  return config_manager.load_config()
21
21
 
22
22
 
23
- def safe_import_registry():
23
+ def safe_import_registry() -> type:
24
24
  """Safely import adapter registry with fallback."""
25
25
  try:
26
26
  from ..core.registry import AdapterRegistry
@@ -30,13 +30,13 @@ def safe_import_registry():
30
30
 
31
31
  class MockRegistry:
32
32
  @staticmethod
33
- def get_adapter(adapter_type):
33
+ def get_adapter(adapter_type: str) -> None:
34
34
  raise ImportError(f"Adapter {adapter_type} not available")
35
35
 
36
36
  return MockRegistry
37
37
 
38
38
 
39
- def safe_import_queue_manager():
39
+ def safe_import_queue_manager() -> type:
40
40
  """Safely import worker manager with fallback."""
41
41
  try:
42
42
  from ..queue.manager import WorkerManager as RealWorkerManager
@@ -55,16 +55,16 @@ def safe_import_queue_manager():
55
55
  pass
56
56
 
57
57
  class MockWorkerManager:
58
- def get_status(self):
58
+ def get_status(self) -> dict[str, Any]:
59
59
  return {"running": False, "pid": None, "status": "fallback_mode"}
60
60
 
61
- def get_worker_status(self):
61
+ def get_worker_status(self) -> dict[str, Any]:
62
62
  return {"running": False, "pid": None, "status": "fallback_mode"}
63
63
 
64
- def get_queue_stats(self):
64
+ def get_queue_stats(self) -> dict[str, Any]:
65
65
  return {"total": 0, "failed": 0, "pending": 0, "completed": 0}
66
66
 
67
- def health_check(self):
67
+ def health_check(self) -> dict[str, Any]:
68
68
  return {
69
69
  "status": "degraded",
70
70
  "score": 50,
@@ -85,11 +85,11 @@ logger = logging.getLogger(__name__)
85
85
  class SystemDiagnostics:
86
86
  """Comprehensive system diagnostics and health reporting."""
87
87
 
88
- def __init__(self):
88
+ def __init__(self) -> None:
89
89
  # Initialize lists first
90
- self.issues = []
91
- self.warnings = []
92
- self.successes = []
90
+ self.issues: list[str] = []
91
+ self.warnings: list[str] = []
92
+ self.successes: list[str] = []
93
93
 
94
94
  try:
95
95
  self.config = get_config()
@@ -154,7 +154,7 @@ class SystemDiagnostics:
154
154
  """Diagnose configuration issues."""
155
155
  console.print("\nšŸ“‹ [yellow]Configuration Analysis[/yellow]")
156
156
 
157
- config_status = {
157
+ config_status: dict[str, Any] = {
158
158
  "status": "healthy",
159
159
  "adapters_configured": 0,
160
160
  "default_adapter": None,
@@ -260,7 +260,7 @@ class SystemDiagnostics:
260
260
  """Diagnose adapter functionality."""
261
261
  console.print("\nšŸ”Œ [yellow]Adapter Diagnosis[/yellow]")
262
262
 
263
- adapter_status = {
263
+ adapter_status: dict[str, Any] = {
264
264
  "total_adapters": 0,
265
265
  "healthy_adapters": 0,
266
266
  "failed_adapters": 0,
@@ -278,7 +278,7 @@ class SystemDiagnostics:
278
278
  for name, adapter_config in adapters_config.items():
279
279
  adapter_type = adapter_config.get("type", name)
280
280
 
281
- details = {
281
+ details: dict[str, Any] = {
282
282
  "type": adapter_type,
283
283
  "status": "unknown",
284
284
  "last_test": None,
@@ -330,7 +330,7 @@ class SystemDiagnostics:
330
330
  """Diagnose queue system health with active testing."""
331
331
  console.print("\n⚔ [yellow]Queue System Diagnosis[/yellow]")
332
332
 
333
- queue_status = {
333
+ queue_status: dict[str, Any] = {
334
334
  "worker_running": False,
335
335
  "worker_pid": None,
336
336
  "queue_stats": {},
@@ -455,7 +455,7 @@ class SystemDiagnostics:
455
455
 
456
456
  async def _test_worker_startup(self) -> dict[str, Any]:
457
457
  """Test starting a queue worker."""
458
- test_result = {
458
+ test_result: dict[str, Any] = {
459
459
  "attempted": True,
460
460
  "success": False,
461
461
  "error": None,
@@ -497,7 +497,7 @@ class SystemDiagnostics:
497
497
 
498
498
  async def _test_queue_operations(self) -> dict[str, Any]:
499
499
  """Test basic queue operations."""
500
- test_result = {
500
+ test_result: dict[str, Any] = {
501
501
  "attempted": True,
502
502
  "success": False,
503
503
  "error": None,
@@ -509,7 +509,7 @@ class SystemDiagnostics:
509
509
  from ..core.models import Priority, Task
510
510
  from ..queue.queue import Queue
511
511
 
512
- test_task = Task(
512
+ test_task = Task( # type: ignore[call-arg]
513
513
  title="[DIAGNOSTIC TEST] Queue functionality test",
514
514
  description="This is a diagnostic test - safe to ignore",
515
515
  priority=Priority.LOW,
@@ -532,7 +532,7 @@ class SystemDiagnostics:
532
532
 
533
533
  async def _test_basic_queue_functionality(self) -> dict[str, Any]:
534
534
  """Test basic queue functionality in fallback mode."""
535
- test_result = {
535
+ test_result: dict[str, Any] = {
536
536
  "attempted": True,
537
537
  "success": False,
538
538
  "error": None,
@@ -544,7 +544,7 @@ class SystemDiagnostics:
544
544
  from ..adapters.aitrackdown import AITrackdownAdapter
545
545
  from ..core.models import Priority, Task
546
546
 
547
- test_task = Task(
547
+ test_task = Task( # type: ignore[call-arg]
548
548
  title="[DIAGNOSTIC TEST] Direct adapter test",
549
549
  description="Testing direct adapter functionality",
550
550
  priority=Priority.LOW,
@@ -564,7 +564,8 @@ class SystemDiagnostics:
564
564
  test_result["details"] = f"Direct adapter test passed: {result.id}"
565
565
 
566
566
  # Clean up test
567
- await adapter.delete(result.id)
567
+ if result.id:
568
+ await adapter.delete(result.id)
568
569
 
569
570
  except Exception as e:
570
571
  test_result["error"] = str(e)
@@ -575,7 +576,7 @@ class SystemDiagnostics:
575
576
  """Analyze recent log entries for issues."""
576
577
  console.print("\nšŸ“ [yellow]Recent Log Analysis[/yellow]")
577
578
 
578
- log_analysis = {
579
+ log_analysis: dict[str, Any] = {
579
580
  "log_files_found": [],
580
581
  "recent_errors": [],
581
582
  "recent_warnings": [],
@@ -611,7 +612,7 @@ class SystemDiagnostics:
611
612
 
612
613
  async def _analyze_log_directory(
613
614
  self, log_path: Path, log_analysis: dict[str, Any]
614
- ):
615
+ ) -> None:
615
616
  """Analyze logs in a specific directory."""
616
617
  try:
617
618
  for log_file in log_path.glob("*.log"):
@@ -623,7 +624,9 @@ class SystemDiagnostics:
623
624
  except Exception as e:
624
625
  self.warnings.append(f"Could not analyze logs in {log_path}: {str(e)}")
625
626
 
626
- async def _parse_log_file(self, log_file: Path, log_analysis: dict[str, Any]):
627
+ async def _parse_log_file(
628
+ self, log_file: Path, log_analysis: dict[str, Any]
629
+ ) -> None:
627
630
  """Parse individual log file for issues."""
628
631
  try:
629
632
  with open(log_file) as f:
@@ -642,7 +645,7 @@ class SystemDiagnostics:
642
645
  """Analyze system performance metrics."""
643
646
  console.print("\n⚔ [yellow]Performance Analysis[/yellow]")
644
647
 
645
- performance = {
648
+ performance: dict[str, Any] = {
646
649
  "response_times": {},
647
650
  "throughput": {},
648
651
  "resource_usage": {},
@@ -672,7 +675,7 @@ class SystemDiagnostics:
672
675
 
673
676
  def _generate_recommendations(self) -> list[str]:
674
677
  """Generate actionable recommendations based on diagnosis."""
675
- recommendations = []
678
+ recommendations: list[str] = []
676
679
 
677
680
  if self.issues:
678
681
  recommendations.append(
@@ -705,7 +708,7 @@ class SystemDiagnostics:
705
708
 
706
709
  return recommendations
707
710
 
708
- def _display_diagnosis_summary(self, report: dict[str, Any]):
711
+ def _display_diagnosis_summary(self, report: dict[str, Any]) -> None:
709
712
  """Display a comprehensive diagnosis summary."""
710
713
  console.print("\n" + "=" * 60)
711
714
  console.print("šŸ“‹ [bold green]DIAGNOSIS SUMMARY[/bold green]")