mcp-ticketer 0.1.30__py3-none-any.whl → 1.2.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.
Potentially problematic release.
This version of mcp-ticketer might be problematic. Click here for more details.
- mcp_ticketer/__init__.py +10 -10
- mcp_ticketer/__version__.py +3 -3
- mcp_ticketer/adapters/__init__.py +2 -0
- mcp_ticketer/adapters/aitrackdown.py +796 -46
- mcp_ticketer/adapters/asana/__init__.py +15 -0
- mcp_ticketer/adapters/asana/adapter.py +1416 -0
- mcp_ticketer/adapters/asana/client.py +292 -0
- mcp_ticketer/adapters/asana/mappers.py +348 -0
- mcp_ticketer/adapters/asana/types.py +146 -0
- mcp_ticketer/adapters/github.py +879 -129
- mcp_ticketer/adapters/hybrid.py +11 -11
- mcp_ticketer/adapters/jira.py +973 -73
- mcp_ticketer/adapters/linear/__init__.py +24 -0
- mcp_ticketer/adapters/linear/adapter.py +2732 -0
- mcp_ticketer/adapters/linear/client.py +344 -0
- mcp_ticketer/adapters/linear/mappers.py +420 -0
- mcp_ticketer/adapters/linear/queries.py +479 -0
- mcp_ticketer/adapters/linear/types.py +360 -0
- mcp_ticketer/adapters/linear.py +10 -2315
- mcp_ticketer/analysis/__init__.py +23 -0
- mcp_ticketer/analysis/orphaned.py +218 -0
- mcp_ticketer/analysis/similarity.py +224 -0
- mcp_ticketer/analysis/staleness.py +266 -0
- mcp_ticketer/cache/memory.py +9 -8
- mcp_ticketer/cli/adapter_diagnostics.py +421 -0
- mcp_ticketer/cli/auggie_configure.py +116 -15
- mcp_ticketer/cli/codex_configure.py +274 -82
- mcp_ticketer/cli/configure.py +888 -151
- mcp_ticketer/cli/diagnostics.py +400 -157
- mcp_ticketer/cli/discover.py +297 -26
- mcp_ticketer/cli/gemini_configure.py +119 -26
- mcp_ticketer/cli/init_command.py +880 -0
- mcp_ticketer/cli/instruction_commands.py +435 -0
- mcp_ticketer/cli/linear_commands.py +616 -0
- mcp_ticketer/cli/main.py +203 -1165
- mcp_ticketer/cli/mcp_configure.py +474 -90
- mcp_ticketer/cli/mcp_server_commands.py +415 -0
- mcp_ticketer/cli/migrate_config.py +12 -8
- mcp_ticketer/cli/platform_commands.py +123 -0
- mcp_ticketer/cli/platform_detection.py +418 -0
- mcp_ticketer/cli/platform_installer.py +513 -0
- mcp_ticketer/cli/python_detection.py +126 -0
- mcp_ticketer/cli/queue_commands.py +15 -15
- mcp_ticketer/cli/setup_command.py +639 -0
- mcp_ticketer/cli/simple_health.py +90 -65
- mcp_ticketer/cli/ticket_commands.py +1013 -0
- mcp_ticketer/cli/update_checker.py +313 -0
- mcp_ticketer/cli/utils.py +114 -66
- mcp_ticketer/core/__init__.py +24 -1
- mcp_ticketer/core/adapter.py +250 -16
- mcp_ticketer/core/config.py +145 -37
- mcp_ticketer/core/env_discovery.py +101 -22
- mcp_ticketer/core/env_loader.py +349 -0
- mcp_ticketer/core/exceptions.py +160 -0
- mcp_ticketer/core/http_client.py +26 -26
- mcp_ticketer/core/instructions.py +405 -0
- mcp_ticketer/core/label_manager.py +732 -0
- mcp_ticketer/core/mappers.py +42 -30
- mcp_ticketer/core/models.py +280 -28
- mcp_ticketer/core/onepassword_secrets.py +379 -0
- mcp_ticketer/core/project_config.py +183 -49
- mcp_ticketer/core/registry.py +3 -3
- mcp_ticketer/core/session_state.py +171 -0
- mcp_ticketer/core/state_matcher.py +592 -0
- mcp_ticketer/core/url_parser.py +425 -0
- mcp_ticketer/core/validators.py +69 -0
- mcp_ticketer/defaults/ticket_instructions.md +644 -0
- mcp_ticketer/mcp/__init__.py +29 -1
- mcp_ticketer/mcp/__main__.py +60 -0
- mcp_ticketer/mcp/server/__init__.py +25 -0
- mcp_ticketer/mcp/server/__main__.py +60 -0
- mcp_ticketer/mcp/server/constants.py +58 -0
- mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
- mcp_ticketer/mcp/server/dto.py +195 -0
- mcp_ticketer/mcp/server/main.py +1343 -0
- mcp_ticketer/mcp/server/response_builder.py +206 -0
- mcp_ticketer/mcp/server/routing.py +655 -0
- mcp_ticketer/mcp/server/server_sdk.py +151 -0
- mcp_ticketer/mcp/server/tools/__init__.py +56 -0
- mcp_ticketer/mcp/server/tools/analysis_tools.py +495 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +226 -0
- mcp_ticketer/mcp/server/tools/bulk_tools.py +273 -0
- mcp_ticketer/mcp/server/tools/comment_tools.py +152 -0
- mcp_ticketer/mcp/server/tools/config_tools.py +1439 -0
- mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +921 -0
- mcp_ticketer/mcp/server/tools/instruction_tools.py +300 -0
- mcp_ticketer/mcp/server/tools/label_tools.py +948 -0
- mcp_ticketer/mcp/server/tools/pr_tools.py +152 -0
- mcp_ticketer/mcp/server/tools/search_tools.py +215 -0
- mcp_ticketer/mcp/server/tools/session_tools.py +170 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +1268 -0
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +547 -0
- mcp_ticketer/queue/__init__.py +1 -0
- mcp_ticketer/queue/health_monitor.py +168 -136
- mcp_ticketer/queue/manager.py +95 -25
- mcp_ticketer/queue/queue.py +40 -21
- mcp_ticketer/queue/run_worker.py +6 -1
- mcp_ticketer/queue/ticket_registry.py +213 -155
- mcp_ticketer/queue/worker.py +109 -49
- mcp_ticketer-1.2.11.dist-info/METADATA +792 -0
- mcp_ticketer-1.2.11.dist-info/RECORD +110 -0
- mcp_ticketer/mcp/server.py +0 -1895
- mcp_ticketer-0.1.30.dist-info/METADATA +0 -413
- mcp_ticketer-0.1.30.dist-info/RECORD +0 -49
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.1.30.dist-info → mcp_ticketer-1.2.11.dist-info}/top_level.txt +0 -0
mcp_ticketer/cli/utils.py
CHANGED
|
@@ -4,9 +4,10 @@ import asyncio
|
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
|
+
from collections.abc import Callable
|
|
7
8
|
from functools import wraps
|
|
8
9
|
from pathlib import Path
|
|
9
|
-
from typing import Any,
|
|
10
|
+
from typing import Any, TypeVar
|
|
10
11
|
|
|
11
12
|
import typer
|
|
12
13
|
from rich.console import Console
|
|
@@ -31,7 +32,7 @@ class CommonPatterns:
|
|
|
31
32
|
|
|
32
33
|
@staticmethod
|
|
33
34
|
def load_config() -> dict:
|
|
34
|
-
"""Load configuration from project-local config file
|
|
35
|
+
"""Load configuration from project-local config file with environment discovery fallback.
|
|
35
36
|
|
|
36
37
|
SECURITY: This method ONLY reads from the current project directory
|
|
37
38
|
to prevent configuration leakage across projects. It will NEVER read
|
|
@@ -39,7 +40,8 @@ class CommonPatterns:
|
|
|
39
40
|
|
|
40
41
|
Resolution order:
|
|
41
42
|
1. Project-specific config (.mcp-ticketer/config.json in cwd)
|
|
42
|
-
2.
|
|
43
|
+
2. Environment discovery (environment variables and .env files in cwd)
|
|
44
|
+
3. Default to aitrackdown adapter
|
|
43
45
|
|
|
44
46
|
Returns:
|
|
45
47
|
Configuration dictionary with adapter and config keys.
|
|
@@ -77,6 +79,43 @@ class CommonPatterns:
|
|
|
77
79
|
f"[yellow]Warning: Could not load project config: {e}[/yellow]"
|
|
78
80
|
)
|
|
79
81
|
|
|
82
|
+
# Try environment discovery as fallback
|
|
83
|
+
try:
|
|
84
|
+
from ..core.config import ConfigurationManager
|
|
85
|
+
|
|
86
|
+
config_manager = ConfigurationManager()
|
|
87
|
+
app_config = config_manager.load_config()
|
|
88
|
+
|
|
89
|
+
# Convert AppConfig to legacy dict format for CLI compatibility
|
|
90
|
+
enabled_adapters = app_config.get_enabled_adapters()
|
|
91
|
+
if enabled_adapters:
|
|
92
|
+
# Use the first enabled adapter as default
|
|
93
|
+
default_adapter = (
|
|
94
|
+
app_config.default_adapter or list(enabled_adapters.keys())[0]
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Convert to legacy format
|
|
98
|
+
legacy_config = {"default_adapter": default_adapter, "adapters": {}}
|
|
99
|
+
|
|
100
|
+
# Convert adapter configs to dict format
|
|
101
|
+
for name, adapter_config in enabled_adapters.items():
|
|
102
|
+
if hasattr(adapter_config, "model_dump"):
|
|
103
|
+
legacy_config["adapters"][name] = adapter_config.model_dump(
|
|
104
|
+
exclude_none=False
|
|
105
|
+
)
|
|
106
|
+
elif hasattr(adapter_config, "dict"):
|
|
107
|
+
legacy_config["adapters"][name] = adapter_config.dict()
|
|
108
|
+
else:
|
|
109
|
+
legacy_config["adapters"][name] = adapter_config
|
|
110
|
+
|
|
111
|
+
logger.info(
|
|
112
|
+
f"Loaded configuration from environment discovery: {list(enabled_adapters.keys())}"
|
|
113
|
+
)
|
|
114
|
+
return legacy_config
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.warning(f"Environment discovery failed: {e}")
|
|
118
|
+
|
|
80
119
|
# Default to aitrackdown with local base path
|
|
81
120
|
logger.info("No project-local config found, defaulting to aitrackdown adapter")
|
|
82
121
|
return {"adapter": "aitrackdown", "config": {"base_path": ".aitrackdown"}}
|
|
@@ -116,8 +155,8 @@ class CommonPatterns:
|
|
|
116
155
|
|
|
117
156
|
@staticmethod
|
|
118
157
|
def get_adapter(
|
|
119
|
-
override_adapter:
|
|
120
|
-
):
|
|
158
|
+
override_adapter: str | None = None, override_config: dict | None = None
|
|
159
|
+
) -> Any:
|
|
121
160
|
"""Get configured adapter instance with environment variable support."""
|
|
122
161
|
config = CommonPatterns.load_config()
|
|
123
162
|
|
|
@@ -168,7 +207,7 @@ class CommonPatterns:
|
|
|
168
207
|
def queue_operation(
|
|
169
208
|
ticket_data: dict[str, Any],
|
|
170
209
|
operation: str,
|
|
171
|
-
adapter_name:
|
|
210
|
+
adapter_name: str | None = None,
|
|
172
211
|
show_progress: bool = True,
|
|
173
212
|
) -> str:
|
|
174
213
|
"""Queue an operation and optionally start the worker."""
|
|
@@ -176,10 +215,15 @@ class CommonPatterns:
|
|
|
176
215
|
config = CommonPatterns.load_config()
|
|
177
216
|
adapter_name = config.get("default_adapter", "aitrackdown")
|
|
178
217
|
|
|
179
|
-
# Add to queue
|
|
218
|
+
# Add to queue with explicit project directory
|
|
219
|
+
from pathlib import Path
|
|
220
|
+
|
|
180
221
|
queue = Queue()
|
|
181
222
|
queue_id = queue.add(
|
|
182
|
-
ticket_data=ticket_data,
|
|
223
|
+
ticket_data=ticket_data,
|
|
224
|
+
adapter=adapter_name,
|
|
225
|
+
operation=operation,
|
|
226
|
+
project_dir=str(Path.cwd()), # Explicitly pass current project directory
|
|
183
227
|
)
|
|
184
228
|
|
|
185
229
|
if show_progress:
|
|
@@ -222,7 +266,7 @@ class CommonPatterns:
|
|
|
222
266
|
console.print(table)
|
|
223
267
|
|
|
224
268
|
@staticmethod
|
|
225
|
-
def display_ticket_details(ticket: Task, comments:
|
|
269
|
+
def display_ticket_details(ticket: Task, comments: list | None = None) -> None:
|
|
226
270
|
"""Display detailed ticket information."""
|
|
227
271
|
console.print(f"\n[bold]Ticket: {ticket.id}[/bold]")
|
|
228
272
|
console.print(f"Title: {ticket.title}")
|
|
@@ -277,33 +321,35 @@ class CommonPatterns:
|
|
|
277
321
|
)
|
|
278
322
|
|
|
279
323
|
|
|
280
|
-
def async_command(f: Callable[...,
|
|
281
|
-
"""
|
|
324
|
+
def async_command(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
325
|
+
"""Handle async CLI commands via decorator."""
|
|
282
326
|
|
|
283
327
|
@wraps(f)
|
|
284
|
-
def wrapper(*args, **kwargs):
|
|
328
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
285
329
|
return asyncio.run(f(*args, **kwargs))
|
|
286
330
|
|
|
287
331
|
return wrapper
|
|
288
332
|
|
|
289
333
|
|
|
290
|
-
def with_adapter(f: Callable) -> Callable:
|
|
291
|
-
"""
|
|
334
|
+
def with_adapter(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
335
|
+
"""Inject adapter instance into CLI commands via decorator."""
|
|
292
336
|
|
|
293
337
|
@wraps(f)
|
|
294
|
-
def wrapper(adapter:
|
|
338
|
+
def wrapper(adapter: str | None = None, *args: Any, **kwargs: Any) -> Any:
|
|
295
339
|
adapter_instance = CommonPatterns.get_adapter(override_adapter=adapter)
|
|
296
340
|
return f(adapter_instance, *args, **kwargs)
|
|
297
341
|
|
|
298
342
|
return wrapper
|
|
299
343
|
|
|
300
344
|
|
|
301
|
-
def with_progress(
|
|
302
|
-
|
|
345
|
+
def with_progress(
|
|
346
|
+
message: str = "Processing...",
|
|
347
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
348
|
+
"""Show progress spinner for long-running operations via decorator."""
|
|
303
349
|
|
|
304
|
-
def decorator(f: Callable) -> Callable:
|
|
350
|
+
def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
305
351
|
@wraps(f)
|
|
306
|
-
def wrapper(*args, **kwargs):
|
|
352
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
307
353
|
with Progress(
|
|
308
354
|
SpinnerColumn(),
|
|
309
355
|
TextColumn("[progress.description]{task.description}"),
|
|
@@ -317,12 +363,14 @@ def with_progress(message: str = "Processing..."):
|
|
|
317
363
|
return decorator
|
|
318
364
|
|
|
319
365
|
|
|
320
|
-
def validate_required_fields(
|
|
321
|
-
|
|
366
|
+
def validate_required_fields(
|
|
367
|
+
**field_map: str,
|
|
368
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
369
|
+
"""Validate required fields are provided via decorator."""
|
|
322
370
|
|
|
323
|
-
def decorator(f: Callable) -> Callable:
|
|
371
|
+
def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
324
372
|
@wraps(f)
|
|
325
|
-
def wrapper(*args, **kwargs):
|
|
373
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
326
374
|
missing_fields = []
|
|
327
375
|
for field_name, display_name in field_map.items():
|
|
328
376
|
if field_name in kwargs and kwargs[field_name] is None:
|
|
@@ -332,7 +380,7 @@ def validate_required_fields(**field_map):
|
|
|
332
380
|
console.print(
|
|
333
381
|
f"[red]Error:[/red] Missing required fields: {', '.join(missing_fields)}"
|
|
334
382
|
)
|
|
335
|
-
raise typer.Exit(1)
|
|
383
|
+
raise typer.Exit(1) from None
|
|
336
384
|
|
|
337
385
|
return f(*args, **kwargs)
|
|
338
386
|
|
|
@@ -341,24 +389,24 @@ def validate_required_fields(**field_map):
|
|
|
341
389
|
return decorator
|
|
342
390
|
|
|
343
391
|
|
|
344
|
-
def handle_adapter_errors(f: Callable) -> Callable:
|
|
345
|
-
"""
|
|
392
|
+
def handle_adapter_errors(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
393
|
+
"""Handle common adapter errors gracefully via decorator."""
|
|
346
394
|
|
|
347
395
|
@wraps(f)
|
|
348
|
-
def wrapper(*args, **kwargs):
|
|
396
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
349
397
|
try:
|
|
350
398
|
return f(*args, **kwargs)
|
|
351
399
|
except ConnectionError as e:
|
|
352
400
|
console.print(f"[red]Connection Error:[/red] {e}")
|
|
353
401
|
console.print("Check your network connection and adapter configuration")
|
|
354
|
-
raise typer.Exit(1)
|
|
402
|
+
raise typer.Exit(1) from None
|
|
355
403
|
except ValueError as e:
|
|
356
404
|
console.print(f"[red]Configuration Error:[/red] {e}")
|
|
357
405
|
console.print("Run 'mcp-ticketer init' to configure your adapter")
|
|
358
|
-
raise typer.Exit(1)
|
|
406
|
+
raise typer.Exit(1) from None
|
|
359
407
|
except Exception as e:
|
|
360
408
|
console.print(f"[red]Unexpected Error:[/red] {e}")
|
|
361
|
-
raise typer.Exit(1)
|
|
409
|
+
raise typer.Exit(1) from None
|
|
362
410
|
|
|
363
411
|
return wrapper
|
|
364
412
|
|
|
@@ -403,7 +451,7 @@ class ConfigValidator:
|
|
|
403
451
|
return issues
|
|
404
452
|
|
|
405
453
|
@staticmethod
|
|
406
|
-
def _get_env_var(adapter_type: str, field: str) ->
|
|
454
|
+
def _get_env_var(adapter_type: str, field: str) -> str | None:
|
|
407
455
|
"""Get corresponding environment variable name for a config field."""
|
|
408
456
|
env_mapping = {
|
|
409
457
|
"github": {
|
|
@@ -424,39 +472,39 @@ class ConfigValidator:
|
|
|
424
472
|
class CommandBuilder:
|
|
425
473
|
"""Builder for common CLI command patterns."""
|
|
426
474
|
|
|
427
|
-
def __init__(self):
|
|
428
|
-
self._validators = []
|
|
429
|
-
self._handlers = []
|
|
430
|
-
self._decorators = []
|
|
475
|
+
def __init__(self) -> None:
|
|
476
|
+
self._validators: list[Callable[..., Any]] = []
|
|
477
|
+
self._handlers: list[Callable[..., Any]] = []
|
|
478
|
+
self._decorators: list[Callable[..., Any]] = []
|
|
431
479
|
|
|
432
|
-
def with_adapter_validation(self):
|
|
480
|
+
def with_adapter_validation(self) -> "CommandBuilder":
|
|
433
481
|
"""Add adapter configuration validation."""
|
|
434
482
|
self._validators.append(self._validate_adapter)
|
|
435
483
|
return self
|
|
436
484
|
|
|
437
|
-
def with_async_support(self):
|
|
485
|
+
def with_async_support(self) -> "CommandBuilder":
|
|
438
486
|
"""Add async support to command."""
|
|
439
487
|
self._decorators.append(async_command)
|
|
440
488
|
return self
|
|
441
489
|
|
|
442
|
-
def with_error_handling(self):
|
|
490
|
+
def with_error_handling(self) -> "CommandBuilder":
|
|
443
491
|
"""Add error handling decorator."""
|
|
444
492
|
self._decorators.append(handle_adapter_errors)
|
|
445
493
|
return self
|
|
446
494
|
|
|
447
|
-
def with_progress(self, message: str = "Processing..."):
|
|
495
|
+
def with_progress(self, message: str = "Processing...") -> "CommandBuilder":
|
|
448
496
|
"""Add progress spinner."""
|
|
449
497
|
self._decorators.append(with_progress(message))
|
|
450
498
|
return self
|
|
451
499
|
|
|
452
|
-
def build(self, func: Callable) -> Callable:
|
|
500
|
+
def build(self, func: Callable[..., Any]) -> Callable[..., Any]:
|
|
453
501
|
"""Build the decorated function."""
|
|
454
502
|
decorated_func = func
|
|
455
503
|
for decorator in reversed(self._decorators):
|
|
456
504
|
decorated_func = decorator(decorated_func)
|
|
457
505
|
return decorated_func
|
|
458
506
|
|
|
459
|
-
def _validate_adapter(self, *args, **kwargs):
|
|
507
|
+
def _validate_adapter(self, *args: Any, **kwargs: Any) -> None:
|
|
460
508
|
"""Validate adapter configuration."""
|
|
461
509
|
config = CommonPatterns.load_config()
|
|
462
510
|
default_adapter = config.get("default_adapter", "aitrackdown")
|
|
@@ -470,22 +518,22 @@ class CommandBuilder:
|
|
|
470
518
|
for issue in issues:
|
|
471
519
|
console.print(f" • {issue}")
|
|
472
520
|
console.print("Run 'mcp-ticketer init' to fix configuration")
|
|
473
|
-
raise typer.Exit(1)
|
|
521
|
+
raise typer.Exit(1) from None
|
|
474
522
|
|
|
475
523
|
|
|
476
|
-
def create_standard_ticket_command(operation: str):
|
|
524
|
+
def create_standard_ticket_command(operation: str) -> Callable[..., str]:
|
|
477
525
|
"""Create a standard ticket operation command."""
|
|
478
526
|
|
|
479
527
|
def command_template(
|
|
480
|
-
ticket_id:
|
|
481
|
-
title:
|
|
482
|
-
description:
|
|
483
|
-
priority:
|
|
484
|
-
state:
|
|
485
|
-
assignee:
|
|
486
|
-
tags:
|
|
487
|
-
adapter:
|
|
488
|
-
):
|
|
528
|
+
ticket_id: str | None = None,
|
|
529
|
+
title: str | None = None,
|
|
530
|
+
description: str | None = None,
|
|
531
|
+
priority: Priority | None = None,
|
|
532
|
+
state: TicketState | None = None,
|
|
533
|
+
assignee: str | None = None,
|
|
534
|
+
tags: list[str] | None = None,
|
|
535
|
+
adapter: str | None = None,
|
|
536
|
+
) -> str:
|
|
489
537
|
"""Template for ticket commands."""
|
|
490
538
|
# Build ticket data
|
|
491
539
|
ticket_data = {}
|
|
@@ -524,11 +572,11 @@ class TicketCommands:
|
|
|
524
572
|
@async_command
|
|
525
573
|
@handle_adapter_errors
|
|
526
574
|
async def list_tickets(
|
|
527
|
-
adapter_instance,
|
|
528
|
-
state:
|
|
529
|
-
priority:
|
|
575
|
+
adapter_instance: Any,
|
|
576
|
+
state: TicketState | None = None,
|
|
577
|
+
priority: Priority | None = None,
|
|
530
578
|
limit: int = 10,
|
|
531
|
-
):
|
|
579
|
+
) -> None:
|
|
532
580
|
"""List tickets with filters."""
|
|
533
581
|
filters = {}
|
|
534
582
|
if state:
|
|
@@ -543,13 +591,13 @@ class TicketCommands:
|
|
|
543
591
|
@async_command
|
|
544
592
|
@handle_adapter_errors
|
|
545
593
|
async def show_ticket(
|
|
546
|
-
adapter_instance, ticket_id: str, show_comments: bool = False
|
|
547
|
-
):
|
|
594
|
+
adapter_instance: Any, ticket_id: str, show_comments: bool = False
|
|
595
|
+
) -> None:
|
|
548
596
|
"""Show ticket details."""
|
|
549
597
|
ticket = await adapter_instance.read(ticket_id)
|
|
550
598
|
if not ticket:
|
|
551
599
|
console.print(f"[red]✗[/red] Ticket not found: {ticket_id}")
|
|
552
|
-
raise typer.Exit(1)
|
|
600
|
+
raise typer.Exit(1) from None
|
|
553
601
|
|
|
554
602
|
comments = None
|
|
555
603
|
if show_comments:
|
|
@@ -560,11 +608,11 @@ class TicketCommands:
|
|
|
560
608
|
@staticmethod
|
|
561
609
|
def create_ticket(
|
|
562
610
|
title: str,
|
|
563
|
-
description:
|
|
611
|
+
description: str | None = None,
|
|
564
612
|
priority: Priority = Priority.MEDIUM,
|
|
565
|
-
tags:
|
|
566
|
-
assignee:
|
|
567
|
-
adapter:
|
|
613
|
+
tags: list[str] | None = None,
|
|
614
|
+
assignee: str | None = None,
|
|
615
|
+
adapter: str | None = None,
|
|
568
616
|
) -> str:
|
|
569
617
|
"""Create a new ticket."""
|
|
570
618
|
ticket_data = {
|
|
@@ -579,19 +627,19 @@ class TicketCommands:
|
|
|
579
627
|
|
|
580
628
|
@staticmethod
|
|
581
629
|
def update_ticket(
|
|
582
|
-
ticket_id: str, updates: dict[str, Any], adapter:
|
|
630
|
+
ticket_id: str, updates: dict[str, Any], adapter: str | None = None
|
|
583
631
|
) -> str:
|
|
584
632
|
"""Update a ticket."""
|
|
585
633
|
if not updates:
|
|
586
634
|
console.print("[yellow]No updates specified[/yellow]")
|
|
587
|
-
raise typer.Exit(1)
|
|
635
|
+
raise typer.Exit(1) from None
|
|
588
636
|
|
|
589
637
|
updates["ticket_id"] = ticket_id
|
|
590
638
|
return CommonPatterns.queue_operation(updates, "update", adapter)
|
|
591
639
|
|
|
592
640
|
@staticmethod
|
|
593
641
|
def transition_ticket(
|
|
594
|
-
ticket_id: str, state: TicketState, adapter:
|
|
642
|
+
ticket_id: str, state: TicketState, adapter: str | None = None
|
|
595
643
|
) -> str:
|
|
596
644
|
"""Transition ticket state."""
|
|
597
645
|
ticket_data = {
|
mcp_ticketer/core/__init__.py
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
"""Core models and abstractions for MCP Ticketer."""
|
|
2
2
|
|
|
3
3
|
from .adapter import BaseAdapter
|
|
4
|
-
from .
|
|
4
|
+
from .instructions import (
|
|
5
|
+
InstructionsError,
|
|
6
|
+
InstructionsNotFoundError,
|
|
7
|
+
InstructionsValidationError,
|
|
8
|
+
TicketInstructionsManager,
|
|
9
|
+
get_instructions,
|
|
10
|
+
)
|
|
11
|
+
from .models import Attachment, Comment, Epic, Priority, Task, TicketState, TicketType
|
|
5
12
|
from .registry import AdapterRegistry
|
|
13
|
+
from .state_matcher import (
|
|
14
|
+
SemanticStateMatcher,
|
|
15
|
+
StateMatchResult,
|
|
16
|
+
ValidationResult,
|
|
17
|
+
get_state_matcher,
|
|
18
|
+
)
|
|
6
19
|
|
|
7
20
|
__all__ = [
|
|
8
21
|
"Epic",
|
|
9
22
|
"Task",
|
|
10
23
|
"Comment",
|
|
24
|
+
"Attachment",
|
|
11
25
|
"TicketState",
|
|
12
26
|
"Priority",
|
|
13
27
|
"TicketType",
|
|
14
28
|
"BaseAdapter",
|
|
15
29
|
"AdapterRegistry",
|
|
30
|
+
"TicketInstructionsManager",
|
|
31
|
+
"InstructionsError",
|
|
32
|
+
"InstructionsNotFoundError",
|
|
33
|
+
"InstructionsValidationError",
|
|
34
|
+
"get_instructions",
|
|
35
|
+
"SemanticStateMatcher",
|
|
36
|
+
"StateMatchResult",
|
|
37
|
+
"ValidationResult",
|
|
38
|
+
"get_state_matcher",
|
|
16
39
|
]
|