mcp-ticketer 0.4.2__py3-none-any.whl → 0.4.3__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 +3 -12
- mcp_ticketer/__version__.py +1 -1
- mcp_ticketer/adapters/aitrackdown.py +243 -11
- mcp_ticketer/adapters/github.py +15 -14
- mcp_ticketer/adapters/hybrid.py +11 -11
- mcp_ticketer/adapters/jira.py +22 -25
- mcp_ticketer/adapters/linear/adapter.py +9 -21
- mcp_ticketer/adapters/linear/client.py +2 -1
- mcp_ticketer/adapters/linear/mappers.py +2 -1
- mcp_ticketer/cache/memory.py +6 -5
- mcp_ticketer/cli/adapter_diagnostics.py +4 -2
- mcp_ticketer/cli/codex_configure.py +2 -2
- mcp_ticketer/cli/configure.py +7 -14
- mcp_ticketer/cli/diagnostics.py +2 -2
- mcp_ticketer/cli/discover.py +6 -11
- mcp_ticketer/cli/gemini_configure.py +2 -2
- mcp_ticketer/cli/linear_commands.py +6 -7
- mcp_ticketer/cli/main.py +218 -242
- mcp_ticketer/cli/mcp_configure.py +1 -2
- mcp_ticketer/cli/ticket_commands.py +27 -30
- mcp_ticketer/cli/utils.py +23 -22
- mcp_ticketer/core/__init__.py +3 -1
- mcp_ticketer/core/adapter.py +82 -13
- mcp_ticketer/core/config.py +27 -29
- mcp_ticketer/core/env_discovery.py +10 -10
- mcp_ticketer/core/env_loader.py +8 -8
- mcp_ticketer/core/http_client.py +16 -16
- mcp_ticketer/core/mappers.py +10 -10
- mcp_ticketer/core/models.py +50 -20
- mcp_ticketer/core/project_config.py +40 -34
- mcp_ticketer/core/registry.py +2 -2
- mcp_ticketer/mcp/dto.py +32 -32
- mcp_ticketer/mcp/response_builder.py +2 -2
- mcp_ticketer/mcp/server.py +17 -37
- mcp_ticketer/mcp/server_sdk.py +2 -2
- mcp_ticketer/mcp/tools/__init__.py +7 -9
- mcp_ticketer/mcp/tools/attachment_tools.py +3 -4
- mcp_ticketer/mcp/tools/comment_tools.py +2 -2
- mcp_ticketer/mcp/tools/hierarchy_tools.py +8 -8
- mcp_ticketer/mcp/tools/pr_tools.py +2 -2
- mcp_ticketer/mcp/tools/search_tools.py +6 -6
- mcp_ticketer/mcp/tools/ticket_tools.py +12 -12
- mcp_ticketer/queue/health_monitor.py +4 -4
- mcp_ticketer/queue/manager.py +2 -2
- mcp_ticketer/queue/queue.py +16 -16
- mcp_ticketer/queue/ticket_registry.py +7 -7
- mcp_ticketer/queue/worker.py +2 -2
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.3.dist-info}/METADATA +61 -2
- mcp_ticketer-0.4.3.dist-info/RECORD +73 -0
- mcp_ticketer-0.4.2.dist-info/RECORD +0 -73
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.3.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.3.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.4.2.dist-info → mcp_ticketer-0.4.3.dist-info}/top_level.txt +0 -0
mcp_ticketer/cli/main.py
CHANGED
|
@@ -5,7 +5,6 @@ import json
|
|
|
5
5
|
import os
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import typer
|
|
11
10
|
from dotenv import load_dotenv
|
|
@@ -21,7 +20,8 @@ from ..core.models import Comment, SearchQuery
|
|
|
21
20
|
from ..queue import Queue, QueueStatus, WorkerManager
|
|
22
21
|
from ..queue.health_monitor import HealthStatus, QueueHealthMonitor
|
|
23
22
|
from ..queue.ticket_registry import TicketRegistry
|
|
24
|
-
from .configure import configure_wizard, set_adapter_config,
|
|
23
|
+
from .configure import (configure_wizard, set_adapter_config,
|
|
24
|
+
show_current_config)
|
|
25
25
|
from .diagnostics import run_diagnostics
|
|
26
26
|
from .discover import app as discover_app
|
|
27
27
|
from .migrate_config import migrate_config_command
|
|
@@ -84,7 +84,7 @@ class AdapterType(str, Enum):
|
|
|
84
84
|
GITHUB = "github"
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def load_config(project_dir:
|
|
87
|
+
def load_config(project_dir: Path | None = None) -> dict:
|
|
88
88
|
"""Load configuration from project-local config file ONLY.
|
|
89
89
|
|
|
90
90
|
SECURITY: This method ONLY reads from the current project directory
|
|
@@ -146,7 +146,7 @@ def load_config(project_dir: Optional[Path] = None) -> dict:
|
|
|
146
146
|
return {"adapter": "aitrackdown", "config": {"base_path": ".aitrackdown"}}
|
|
147
147
|
|
|
148
148
|
|
|
149
|
-
def _discover_from_env_files() ->
|
|
149
|
+
def _discover_from_env_files() -> str | None:
|
|
150
150
|
"""Discover adapter configuration from .env or .env.local files.
|
|
151
151
|
|
|
152
152
|
Returns:
|
|
@@ -270,7 +270,7 @@ def merge_config(updates: dict) -> dict:
|
|
|
270
270
|
|
|
271
271
|
|
|
272
272
|
def get_adapter(
|
|
273
|
-
override_adapter:
|
|
273
|
+
override_adapter: str | None = None, override_config: dict | None = None
|
|
274
274
|
):
|
|
275
275
|
"""Get configured adapter instance.
|
|
276
276
|
|
|
@@ -387,13 +387,13 @@ def _prompt_for_adapter_selection(console: Console) -> str:
|
|
|
387
387
|
|
|
388
388
|
@app.command()
|
|
389
389
|
def setup(
|
|
390
|
-
adapter:
|
|
390
|
+
adapter: str | None = typer.Option(
|
|
391
391
|
None,
|
|
392
392
|
"--adapter",
|
|
393
393
|
"-a",
|
|
394
394
|
help="Adapter type to use (interactive prompt if not specified)",
|
|
395
395
|
),
|
|
396
|
-
project_path:
|
|
396
|
+
project_path: str | None = typer.Option(
|
|
397
397
|
None, "--path", help="Project path (default: current directory)"
|
|
398
398
|
),
|
|
399
399
|
global_config: bool = typer.Option(
|
|
@@ -402,36 +402,36 @@ def setup(
|
|
|
402
402
|
"-g",
|
|
403
403
|
help="Save to global config instead of project-specific",
|
|
404
404
|
),
|
|
405
|
-
base_path:
|
|
405
|
+
base_path: str | None = typer.Option(
|
|
406
406
|
None,
|
|
407
407
|
"--base-path",
|
|
408
408
|
"-p",
|
|
409
409
|
help="Base path for ticket storage (AITrackdown only)",
|
|
410
410
|
),
|
|
411
|
-
api_key:
|
|
411
|
+
api_key: str | None = typer.Option(
|
|
412
412
|
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
413
413
|
),
|
|
414
|
-
team_id:
|
|
414
|
+
team_id: str | None = typer.Option(
|
|
415
415
|
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
416
416
|
),
|
|
417
|
-
jira_server:
|
|
417
|
+
jira_server: str | None = typer.Option(
|
|
418
418
|
None,
|
|
419
419
|
"--jira-server",
|
|
420
420
|
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
421
421
|
),
|
|
422
|
-
jira_email:
|
|
422
|
+
jira_email: str | None = typer.Option(
|
|
423
423
|
None, "--jira-email", help="JIRA user email for authentication"
|
|
424
424
|
),
|
|
425
|
-
jira_project:
|
|
425
|
+
jira_project: str | None = typer.Option(
|
|
426
426
|
None, "--jira-project", help="Default JIRA project key"
|
|
427
427
|
),
|
|
428
|
-
github_owner:
|
|
428
|
+
github_owner: str | None = typer.Option(
|
|
429
429
|
None, "--github-owner", help="GitHub repository owner"
|
|
430
430
|
),
|
|
431
|
-
github_repo:
|
|
431
|
+
github_repo: str | None = typer.Option(
|
|
432
432
|
None, "--github-repo", help="GitHub repository name"
|
|
433
433
|
),
|
|
434
|
-
github_token:
|
|
434
|
+
github_token: str | None = typer.Option(
|
|
435
435
|
None, "--github-token", help="GitHub Personal Access Token"
|
|
436
436
|
),
|
|
437
437
|
) -> None:
|
|
@@ -471,13 +471,13 @@ def setup(
|
|
|
471
471
|
|
|
472
472
|
@app.command()
|
|
473
473
|
def init(
|
|
474
|
-
adapter:
|
|
474
|
+
adapter: str | None = typer.Option(
|
|
475
475
|
None,
|
|
476
476
|
"--adapter",
|
|
477
477
|
"-a",
|
|
478
478
|
help="Adapter type to use (interactive prompt if not specified)",
|
|
479
479
|
),
|
|
480
|
-
project_path:
|
|
480
|
+
project_path: str | None = typer.Option(
|
|
481
481
|
None, "--path", help="Project path (default: current directory)"
|
|
482
482
|
),
|
|
483
483
|
global_config: bool = typer.Option(
|
|
@@ -486,40 +486,40 @@ def init(
|
|
|
486
486
|
"-g",
|
|
487
487
|
help="Save to global config instead of project-specific",
|
|
488
488
|
),
|
|
489
|
-
base_path:
|
|
489
|
+
base_path: str | None = typer.Option(
|
|
490
490
|
None,
|
|
491
491
|
"--base-path",
|
|
492
492
|
"-p",
|
|
493
493
|
help="Base path for ticket storage (AITrackdown only)",
|
|
494
494
|
),
|
|
495
|
-
api_key:
|
|
495
|
+
api_key: str | None = typer.Option(
|
|
496
496
|
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
497
497
|
),
|
|
498
|
-
team_id:
|
|
498
|
+
team_id: str | None = typer.Option(
|
|
499
499
|
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
500
500
|
),
|
|
501
|
-
jira_server:
|
|
501
|
+
jira_server: str | None = typer.Option(
|
|
502
502
|
None,
|
|
503
503
|
"--jira-server",
|
|
504
504
|
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
505
505
|
),
|
|
506
|
-
jira_email:
|
|
506
|
+
jira_email: str | None = typer.Option(
|
|
507
507
|
None, "--jira-email", help="JIRA user email for authentication"
|
|
508
508
|
),
|
|
509
|
-
jira_project:
|
|
509
|
+
jira_project: str | None = typer.Option(
|
|
510
510
|
None, "--jira-project", help="Default JIRA project key"
|
|
511
511
|
),
|
|
512
|
-
github_owner:
|
|
512
|
+
github_owner: str | None = typer.Option(
|
|
513
513
|
None, "--github-owner", help="GitHub repository owner"
|
|
514
514
|
),
|
|
515
|
-
github_repo:
|
|
515
|
+
github_repo: str | None = typer.Option(
|
|
516
516
|
None, "--github-repo", help="GitHub repository name"
|
|
517
517
|
),
|
|
518
|
-
github_token:
|
|
518
|
+
github_token: str | None = typer.Option(
|
|
519
519
|
None, "--github-token", help="GitHub Personal Access Token"
|
|
520
520
|
),
|
|
521
521
|
) -> None:
|
|
522
|
-
"""Initialize mcp-ticketer for the current project.
|
|
522
|
+
"""Initialize mcp-ticketer for the current project (synonymous with 'install' and 'setup').
|
|
523
523
|
|
|
524
524
|
This command sets up MCP Ticketer configuration with interactive prompts
|
|
525
525
|
to guide you through the process. It auto-detects adapter configuration
|
|
@@ -528,11 +528,13 @@ def init(
|
|
|
528
528
|
Creates .mcp-ticketer/config.json in the current directory with
|
|
529
529
|
auto-detected or specified adapter configuration.
|
|
530
530
|
|
|
531
|
-
Note: '
|
|
531
|
+
Note: 'init', 'install', and 'setup' are all synonyms - use whichever feels natural.
|
|
532
532
|
|
|
533
533
|
Examples:
|
|
534
|
-
# Interactive setup (
|
|
534
|
+
# Interactive setup (all three commands are identical)
|
|
535
535
|
mcp-ticketer init
|
|
536
|
+
mcp-ticketer install
|
|
537
|
+
mcp-ticketer setup
|
|
536
538
|
|
|
537
539
|
# Force specific adapter
|
|
538
540
|
mcp-ticketer init --adapter linear
|
|
@@ -669,20 +671,29 @@ def init(
|
|
|
669
671
|
if linear_api_key:
|
|
670
672
|
linear_config["api_key"] = linear_api_key
|
|
671
673
|
|
|
672
|
-
# Team ID
|
|
674
|
+
# Team ID or Team Key
|
|
675
|
+
# Try environment variables first
|
|
676
|
+
linear_team_key = os.getenv("LINEAR_TEAM_KEY")
|
|
673
677
|
linear_team_id = team_id or os.getenv("LINEAR_TEAM_ID")
|
|
674
|
-
if not linear_team_id and not discovered:
|
|
675
|
-
console.print("\nYou need your Linear team ID.")
|
|
676
|
-
console.print("[dim]Find it in Linear settings or team URL[/dim]\n")
|
|
677
678
|
|
|
678
|
-
|
|
679
|
+
if not linear_team_key and not linear_team_id and not discovered:
|
|
680
|
+
console.print("\n[bold]Linear Team Configuration[/bold]")
|
|
681
|
+
console.print("Enter your team key (e.g., 'ENG', 'DESIGN', 'PRODUCT')")
|
|
682
|
+
console.print("[dim]Find it in: Linear Settings → Teams → Your Team → Key field[/dim]\n")
|
|
683
|
+
|
|
684
|
+
linear_team_key = typer.prompt("Team key")
|
|
679
685
|
|
|
686
|
+
# Save whichever was provided
|
|
687
|
+
if linear_team_key:
|
|
688
|
+
linear_config["team_key"] = linear_team_key
|
|
680
689
|
if linear_team_id:
|
|
681
690
|
linear_config["team_id"] = linear_team_id
|
|
682
691
|
|
|
683
|
-
if not linear_config.get("api_key") or
|
|
692
|
+
if not linear_config.get("api_key") or (
|
|
693
|
+
not linear_config.get("team_id") and not linear_config.get("team_key")
|
|
694
|
+
):
|
|
684
695
|
console.print(
|
|
685
|
-
"[red]Error:[/red] Linear requires both API key and team ID"
|
|
696
|
+
"[red]Error:[/red] Linear requires both API key and team ID/key"
|
|
686
697
|
)
|
|
687
698
|
console.print(
|
|
688
699
|
"Run 'mcp-ticketer init --adapter linear' with proper credentials"
|
|
@@ -891,98 +902,20 @@ def _show_next_steps(
|
|
|
891
902
|
console.print("[dim]Run 'mcp-ticketer --help' for more commands[/dim]")
|
|
892
903
|
|
|
893
904
|
|
|
894
|
-
# Keep the old install command as deprecated alias to init
|
|
895
|
-
@app.command(deprecated=True, hidden=True)
|
|
896
|
-
def install(
|
|
897
|
-
adapter: Optional[str] = typer.Option(
|
|
898
|
-
None,
|
|
899
|
-
"--adapter",
|
|
900
|
-
"-a",
|
|
901
|
-
help="Adapter type to use (auto-detected from .env if not specified)",
|
|
902
|
-
),
|
|
903
|
-
project_path: Optional[str] = typer.Option(
|
|
904
|
-
None, "--path", help="Project path (default: current directory)"
|
|
905
|
-
),
|
|
906
|
-
global_config: bool = typer.Option(
|
|
907
|
-
False,
|
|
908
|
-
"--global",
|
|
909
|
-
"-g",
|
|
910
|
-
help="Save to global config instead of project-specific",
|
|
911
|
-
),
|
|
912
|
-
base_path: Optional[str] = typer.Option(
|
|
913
|
-
None,
|
|
914
|
-
"--base-path",
|
|
915
|
-
"-p",
|
|
916
|
-
help="Base path for ticket storage (AITrackdown only)",
|
|
917
|
-
),
|
|
918
|
-
api_key: Optional[str] = typer.Option(
|
|
919
|
-
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
920
|
-
),
|
|
921
|
-
team_id: Optional[str] = typer.Option(
|
|
922
|
-
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
923
|
-
),
|
|
924
|
-
jira_server: Optional[str] = typer.Option(
|
|
925
|
-
None,
|
|
926
|
-
"--jira-server",
|
|
927
|
-
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
928
|
-
),
|
|
929
|
-
jira_email: Optional[str] = typer.Option(
|
|
930
|
-
None, "--jira-email", help="JIRA user email for authentication"
|
|
931
|
-
),
|
|
932
|
-
jira_project: Optional[str] = typer.Option(
|
|
933
|
-
None, "--jira-project", help="Default JIRA project key"
|
|
934
|
-
),
|
|
935
|
-
github_owner: Optional[str] = typer.Option(
|
|
936
|
-
None, "--github-owner", help="GitHub repository owner"
|
|
937
|
-
),
|
|
938
|
-
github_repo: Optional[str] = typer.Option(
|
|
939
|
-
None, "--github-repo", help="GitHub repository name"
|
|
940
|
-
),
|
|
941
|
-
github_token: Optional[str] = typer.Option(
|
|
942
|
-
None, "--github-token", help="GitHub Personal Access Token"
|
|
943
|
-
),
|
|
944
|
-
) -> None:
|
|
945
|
-
"""DEPRECATED: Use 'mcp-ticketer init' instead.
|
|
946
|
-
|
|
947
|
-
This command is deprecated. Use 'mcp-ticketer init' for project initialization.
|
|
948
|
-
|
|
949
|
-
"""
|
|
950
|
-
console.print(
|
|
951
|
-
"[yellow]⚠️ 'install' is deprecated. Use 'mcp-ticketer init' instead.[/yellow]\n"
|
|
952
|
-
)
|
|
953
|
-
# Call init with all parameters
|
|
954
|
-
init(
|
|
955
|
-
adapter=adapter,
|
|
956
|
-
project_path=project_path,
|
|
957
|
-
global_config=global_config,
|
|
958
|
-
base_path=base_path,
|
|
959
|
-
api_key=api_key,
|
|
960
|
-
team_id=team_id,
|
|
961
|
-
jira_server=jira_server,
|
|
962
|
-
jira_email=jira_email,
|
|
963
|
-
jira_project=jira_project,
|
|
964
|
-
github_owner=github_owner,
|
|
965
|
-
github_repo=github_repo,
|
|
966
|
-
github_token=github_token,
|
|
967
|
-
)
|
|
968
|
-
|
|
969
|
-
|
|
970
905
|
@app.command("set")
|
|
971
906
|
def set_config(
|
|
972
|
-
adapter:
|
|
907
|
+
adapter: AdapterType | None = typer.Option(
|
|
973
908
|
None, "--adapter", "-a", help="Set default adapter"
|
|
974
909
|
),
|
|
975
|
-
team_key:
|
|
910
|
+
team_key: str | None = typer.Option(
|
|
976
911
|
None, "--team-key", help="Linear team key (e.g., BTA)"
|
|
977
912
|
),
|
|
978
|
-
team_id:
|
|
979
|
-
owner:
|
|
980
|
-
|
|
981
|
-
),
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
project: Optional[str] = typer.Option(None, "--project", help="JIRA project key"),
|
|
985
|
-
base_path: Optional[str] = typer.Option(
|
|
913
|
+
team_id: str | None = typer.Option(None, "--team-id", help="Linear team ID"),
|
|
914
|
+
owner: str | None = typer.Option(None, "--owner", help="GitHub repository owner"),
|
|
915
|
+
repo: str | None = typer.Option(None, "--repo", help="GitHub repository name"),
|
|
916
|
+
server: str | None = typer.Option(None, "--server", help="JIRA server URL"),
|
|
917
|
+
project: str | None = typer.Option(None, "--project", help="JIRA project key"),
|
|
918
|
+
base_path: str | None = typer.Option(
|
|
986
919
|
None, "--base-path", help="AITrackdown base path"
|
|
987
920
|
),
|
|
988
921
|
) -> None:
|
|
@@ -1072,16 +1005,12 @@ def set_config(
|
|
|
1072
1005
|
@app.command("configure")
|
|
1073
1006
|
def configure_command(
|
|
1074
1007
|
show: bool = typer.Option(False, "--show", help="Show current configuration"),
|
|
1075
|
-
adapter:
|
|
1008
|
+
adapter: str | None = typer.Option(
|
|
1076
1009
|
None, "--adapter", help="Set default adapter type"
|
|
1077
1010
|
),
|
|
1078
|
-
api_key:
|
|
1079
|
-
project_id:
|
|
1080
|
-
|
|
1081
|
-
),
|
|
1082
|
-
team_id: Optional[str] = typer.Option(
|
|
1083
|
-
None, "--team-id", help="Set team ID (Linear)"
|
|
1084
|
-
),
|
|
1011
|
+
api_key: str | None = typer.Option(None, "--api-key", help="Set API key/token"),
|
|
1012
|
+
project_id: str | None = typer.Option(None, "--project-id", help="Set project ID"),
|
|
1013
|
+
team_id: str | None = typer.Option(None, "--team-id", help="Set team ID (Linear)"),
|
|
1085
1014
|
global_scope: bool = typer.Option(
|
|
1086
1015
|
False,
|
|
1087
1016
|
"--global",
|
|
@@ -1257,29 +1186,29 @@ def old_queue_health_command(
|
|
|
1257
1186
|
@app.command(deprecated=True, hidden=True)
|
|
1258
1187
|
def create(
|
|
1259
1188
|
title: str = typer.Argument(..., help="Ticket title"),
|
|
1260
|
-
description:
|
|
1189
|
+
description: str | None = typer.Option(
|
|
1261
1190
|
None, "--description", "-d", help="Ticket description"
|
|
1262
1191
|
),
|
|
1263
1192
|
priority: Priority = typer.Option(
|
|
1264
1193
|
Priority.MEDIUM, "--priority", "-p", help="Priority level"
|
|
1265
1194
|
),
|
|
1266
|
-
tags:
|
|
1195
|
+
tags: list[str] | None = typer.Option(
|
|
1267
1196
|
None, "--tag", "-t", help="Tags (can be specified multiple times)"
|
|
1268
1197
|
),
|
|
1269
|
-
assignee:
|
|
1198
|
+
assignee: str | None = typer.Option(
|
|
1270
1199
|
None, "--assignee", "-a", help="Assignee username"
|
|
1271
1200
|
),
|
|
1272
|
-
project:
|
|
1201
|
+
project: str | None = typer.Option(
|
|
1273
1202
|
None,
|
|
1274
1203
|
"--project",
|
|
1275
1204
|
help="Parent project/epic ID (synonym for --epic)",
|
|
1276
1205
|
),
|
|
1277
|
-
epic:
|
|
1206
|
+
epic: str | None = typer.Option(
|
|
1278
1207
|
None,
|
|
1279
1208
|
"--epic",
|
|
1280
1209
|
help="Parent epic/project ID (synonym for --project)",
|
|
1281
1210
|
),
|
|
1282
|
-
adapter:
|
|
1211
|
+
adapter: AdapterType | None = typer.Option(
|
|
1283
1212
|
None, "--adapter", help="Override default adapter"
|
|
1284
1213
|
),
|
|
1285
1214
|
) -> None:
|
|
@@ -1488,14 +1417,14 @@ def create(
|
|
|
1488
1417
|
|
|
1489
1418
|
@app.command("list", deprecated=True, hidden=True)
|
|
1490
1419
|
def list_tickets(
|
|
1491
|
-
state:
|
|
1420
|
+
state: TicketState | None = typer.Option(
|
|
1492
1421
|
None, "--state", "-s", help="Filter by state"
|
|
1493
1422
|
),
|
|
1494
|
-
priority:
|
|
1423
|
+
priority: Priority | None = typer.Option(
|
|
1495
1424
|
None, "--priority", "-p", help="Filter by priority"
|
|
1496
1425
|
),
|
|
1497
1426
|
limit: int = typer.Option(10, "--limit", "-l", help="Maximum number of tickets"),
|
|
1498
|
-
adapter:
|
|
1427
|
+
adapter: AdapterType | None = typer.Option(
|
|
1499
1428
|
None, "--adapter", help="Override default adapter"
|
|
1500
1429
|
),
|
|
1501
1430
|
) -> None:
|
|
@@ -1551,7 +1480,7 @@ def list_tickets(
|
|
|
1551
1480
|
def show(
|
|
1552
1481
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1553
1482
|
comments: bool = typer.Option(False, "--comments", "-c", help="Show comments"),
|
|
1554
|
-
adapter:
|
|
1483
|
+
adapter: AdapterType | None = typer.Option(
|
|
1555
1484
|
None, "--adapter", help="Override default adapter"
|
|
1556
1485
|
),
|
|
1557
1486
|
) -> None:
|
|
@@ -1607,7 +1536,7 @@ def show(
|
|
|
1607
1536
|
def comment(
|
|
1608
1537
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1609
1538
|
content: str = typer.Argument(..., help="Comment content"),
|
|
1610
|
-
adapter:
|
|
1539
|
+
adapter: AdapterType | None = typer.Option(
|
|
1611
1540
|
None, "--adapter", help="Override default adapter"
|
|
1612
1541
|
),
|
|
1613
1542
|
) -> None:
|
|
@@ -1648,17 +1577,15 @@ def comment(
|
|
|
1648
1577
|
@app.command(deprecated=True, hidden=True)
|
|
1649
1578
|
def update(
|
|
1650
1579
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1651
|
-
title:
|
|
1652
|
-
description:
|
|
1580
|
+
title: str | None = typer.Option(None, "--title", help="New title"),
|
|
1581
|
+
description: str | None = typer.Option(
|
|
1653
1582
|
None, "--description", "-d", help="New description"
|
|
1654
1583
|
),
|
|
1655
|
-
priority:
|
|
1584
|
+
priority: Priority | None = typer.Option(
|
|
1656
1585
|
None, "--priority", "-p", help="New priority"
|
|
1657
1586
|
),
|
|
1658
|
-
assignee:
|
|
1659
|
-
|
|
1660
|
-
),
|
|
1661
|
-
adapter: Optional[AdapterType] = typer.Option(
|
|
1587
|
+
assignee: str | None = typer.Option(None, "--assignee", "-a", help="New assignee"),
|
|
1588
|
+
adapter: AdapterType | None = typer.Option(
|
|
1662
1589
|
None, "--adapter", help="Override default adapter"
|
|
1663
1590
|
),
|
|
1664
1591
|
) -> None:
|
|
@@ -1718,13 +1645,13 @@ def update(
|
|
|
1718
1645
|
@app.command(deprecated=True, hidden=True)
|
|
1719
1646
|
def transition(
|
|
1720
1647
|
ticket_id: str = typer.Argument(..., help="Ticket ID"),
|
|
1721
|
-
state_positional:
|
|
1648
|
+
state_positional: TicketState | None = typer.Argument(
|
|
1722
1649
|
None, help="Target state (positional - deprecated, use --state instead)"
|
|
1723
1650
|
),
|
|
1724
|
-
state:
|
|
1651
|
+
state: TicketState | None = typer.Option(
|
|
1725
1652
|
None, "--state", "-s", help="Target state (recommended)"
|
|
1726
1653
|
),
|
|
1727
|
-
adapter:
|
|
1654
|
+
adapter: AdapterType | None = typer.Option(
|
|
1728
1655
|
None, "--adapter", help="Override default adapter"
|
|
1729
1656
|
),
|
|
1730
1657
|
) -> None:
|
|
@@ -1789,12 +1716,12 @@ def transition(
|
|
|
1789
1716
|
|
|
1790
1717
|
@app.command(deprecated=True, hidden=True)
|
|
1791
1718
|
def search(
|
|
1792
|
-
query:
|
|
1793
|
-
state:
|
|
1794
|
-
priority:
|
|
1795
|
-
assignee:
|
|
1719
|
+
query: str | None = typer.Argument(None, help="Search query"),
|
|
1720
|
+
state: TicketState | None = typer.Option(None, "--state", "-s"),
|
|
1721
|
+
priority: Priority | None = typer.Option(None, "--priority", "-p"),
|
|
1722
|
+
assignee: str | None = typer.Option(None, "--assignee", "-a"),
|
|
1796
1723
|
limit: int = typer.Option(10, "--limit", "-l"),
|
|
1797
|
-
adapter:
|
|
1724
|
+
adapter: AdapterType | None = typer.Option(
|
|
1798
1725
|
None, "--adapter", help="Override default adapter"
|
|
1799
1726
|
),
|
|
1800
1727
|
) -> None:
|
|
@@ -1852,7 +1779,7 @@ app.add_typer(discover_app, name="discover")
|
|
|
1852
1779
|
# Add diagnostics command
|
|
1853
1780
|
@app.command("diagnose")
|
|
1854
1781
|
def diagnose_command(
|
|
1855
|
-
output_file:
|
|
1782
|
+
output_file: str | None = typer.Option(
|
|
1856
1783
|
None, "--output", "-o", help="Save full report to file"
|
|
1857
1784
|
),
|
|
1858
1785
|
json_output: bool = typer.Option(
|
|
@@ -1899,7 +1826,7 @@ def diagnose_command(
|
|
|
1899
1826
|
|
|
1900
1827
|
@app.command("doctor")
|
|
1901
1828
|
def doctor_alias(
|
|
1902
|
-
output_file:
|
|
1829
|
+
output_file: str | None = typer.Option(
|
|
1903
1830
|
None, "--output", "-o", help="Save full report to file"
|
|
1904
1831
|
),
|
|
1905
1832
|
json_output: bool = typer.Option(
|
|
@@ -1944,111 +1871,160 @@ mcp_app = typer.Typer(
|
|
|
1944
1871
|
|
|
1945
1872
|
@app.command()
|
|
1946
1873
|
def install(
|
|
1947
|
-
|
|
1874
|
+
adapter: str | None = typer.Option(
|
|
1948
1875
|
None,
|
|
1949
|
-
|
|
1876
|
+
"--adapter",
|
|
1877
|
+
"-a",
|
|
1878
|
+
help="Adapter type to use (interactive prompt if not specified)",
|
|
1879
|
+
),
|
|
1880
|
+
project_path: str | None = typer.Option(
|
|
1881
|
+
None, "--path", help="Project path (default: current directory)"
|
|
1882
|
+
),
|
|
1883
|
+
global_config: bool = typer.Option(
|
|
1884
|
+
False,
|
|
1885
|
+
"--global",
|
|
1886
|
+
"-g",
|
|
1887
|
+
help="Save to global config instead of project-specific",
|
|
1888
|
+
),
|
|
1889
|
+
base_path: str | None = typer.Option(
|
|
1890
|
+
None,
|
|
1891
|
+
"--base-path",
|
|
1892
|
+
"-p",
|
|
1893
|
+
help="Base path for ticket storage (AITrackdown only)",
|
|
1894
|
+
),
|
|
1895
|
+
api_key: str | None = typer.Option(
|
|
1896
|
+
None, "--api-key", help="API key for Linear or API token for JIRA"
|
|
1897
|
+
),
|
|
1898
|
+
team_id: str | None = typer.Option(
|
|
1899
|
+
None, "--team-id", help="Linear team ID (required for Linear adapter)"
|
|
1900
|
+
),
|
|
1901
|
+
jira_server: str | None = typer.Option(
|
|
1902
|
+
None,
|
|
1903
|
+
"--jira-server",
|
|
1904
|
+
help="JIRA server URL (e.g., https://company.atlassian.net)",
|
|
1905
|
+
),
|
|
1906
|
+
jira_email: str | None = typer.Option(
|
|
1907
|
+
None, "--jira-email", help="JIRA user email for authentication"
|
|
1908
|
+
),
|
|
1909
|
+
jira_project: str | None = typer.Option(
|
|
1910
|
+
None, "--jira-project", help="Default JIRA project key"
|
|
1911
|
+
),
|
|
1912
|
+
github_owner: str | None = typer.Option(
|
|
1913
|
+
None, "--github-owner", help="GitHub repository owner"
|
|
1914
|
+
),
|
|
1915
|
+
github_repo: str | None = typer.Option(
|
|
1916
|
+
None, "--github-repo", help="GitHub repository name"
|
|
1917
|
+
),
|
|
1918
|
+
github_token: str | None = typer.Option(
|
|
1919
|
+
None, "--github-token", help="GitHub Personal Access Token"
|
|
1920
|
+
),
|
|
1921
|
+
platform: str | None = typer.Option(
|
|
1922
|
+
None,
|
|
1923
|
+
"--platform",
|
|
1924
|
+
help="Platform to configure MCP for (claude-code, claude-desktop, auggie, gemini, codex)",
|
|
1950
1925
|
),
|
|
1951
1926
|
dry_run: bool = typer.Option(
|
|
1952
|
-
False,
|
|
1927
|
+
False,
|
|
1928
|
+
"--dry-run",
|
|
1929
|
+
help="Show what would be done without making changes (for platform installation)",
|
|
1953
1930
|
),
|
|
1954
1931
|
) -> None:
|
|
1955
|
-
"""Install mcp-ticketer
|
|
1932
|
+
"""Install and initialize mcp-ticketer (synonymous with 'init' and 'setup').
|
|
1956
1933
|
|
|
1957
|
-
Without arguments,
|
|
1958
|
-
With
|
|
1934
|
+
Without arguments, runs interactive setup wizard to configure your ticket adapter.
|
|
1935
|
+
With --platform, installs MCP configuration for AI platforms.
|
|
1959
1936
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
- auggie: Project-level MCP server
|
|
1964
|
-
- gemini: Project-level MCP server
|
|
1965
|
-
- codex: Project-level MCP server
|
|
1937
|
+
This command serves two purposes:
|
|
1938
|
+
1. Adapter initialization (same as 'init' and 'setup')
|
|
1939
|
+
2. Platform MCP configuration (when using --platform flag)
|
|
1966
1940
|
|
|
1967
1941
|
Examples:
|
|
1968
|
-
#
|
|
1942
|
+
# Interactive setup (same as 'init' and 'setup')
|
|
1969
1943
|
mcp-ticketer install
|
|
1970
1944
|
|
|
1971
|
-
#
|
|
1972
|
-
mcp-ticketer install
|
|
1973
|
-
|
|
1974
|
-
# Install for Claude Desktop (global)
|
|
1975
|
-
mcp-ticketer install claude-desktop
|
|
1945
|
+
# Setup with specific adapter
|
|
1946
|
+
mcp-ticketer install --adapter linear
|
|
1976
1947
|
|
|
1977
|
-
# Install for
|
|
1978
|
-
mcp-ticketer install
|
|
1948
|
+
# Install MCP for Claude Code
|
|
1949
|
+
mcp-ticketer install --platform claude-code
|
|
1979
1950
|
|
|
1980
|
-
#
|
|
1981
|
-
mcp-ticketer install claude-
|
|
1951
|
+
# Install MCP for Claude Desktop
|
|
1952
|
+
mcp-ticketer install --platform claude-desktop
|
|
1982
1953
|
|
|
1983
1954
|
"""
|
|
1984
|
-
# If
|
|
1985
|
-
if platform is None:
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
1955
|
+
# If platform flag is provided, handle MCP platform installation
|
|
1956
|
+
if platform is not None:
|
|
1957
|
+
# Import configuration functions
|
|
1958
|
+
from .auggie_configure import configure_auggie_mcp
|
|
1959
|
+
from .codex_configure import configure_codex_mcp
|
|
1960
|
+
from .gemini_configure import configure_gemini_mcp
|
|
1961
|
+
from .mcp_configure import configure_claude_mcp
|
|
1962
|
+
|
|
1963
|
+
# Map platform names to configuration functions
|
|
1964
|
+
platform_mapping = {
|
|
1965
|
+
"claude-code": {
|
|
1966
|
+
"func": lambda: configure_claude_mcp(global_config=False, force=True),
|
|
1967
|
+
"name": "Claude Code",
|
|
1968
|
+
},
|
|
1969
|
+
"claude-desktop": {
|
|
1970
|
+
"func": lambda: configure_claude_mcp(global_config=True, force=True),
|
|
1971
|
+
"name": "Claude Desktop",
|
|
1972
|
+
},
|
|
1973
|
+
"auggie": {
|
|
1974
|
+
"func": lambda: configure_auggie_mcp(force=True),
|
|
1975
|
+
"name": "Auggie",
|
|
1976
|
+
},
|
|
1977
|
+
"gemini": {
|
|
1978
|
+
"func": lambda: configure_gemini_mcp(scope="project", force=True),
|
|
1979
|
+
"name": "Gemini CLI",
|
|
1980
|
+
},
|
|
1981
|
+
"codex": {
|
|
1982
|
+
"func": lambda: configure_codex_mcp(force=True),
|
|
1983
|
+
"name": "Codex",
|
|
1984
|
+
},
|
|
1985
|
+
}
|
|
2004
1986
|
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
"claude-desktop": {
|
|
2012
|
-
"func": lambda: configure_claude_mcp(global_config=True, force=True),
|
|
2013
|
-
"name": "Claude Desktop",
|
|
2014
|
-
},
|
|
2015
|
-
"auggie": {
|
|
2016
|
-
"func": lambda: configure_auggie_mcp(force=True),
|
|
2017
|
-
"name": "Auggie",
|
|
2018
|
-
},
|
|
2019
|
-
"gemini": {
|
|
2020
|
-
"func": lambda: configure_gemini_mcp(scope="project", force=True),
|
|
2021
|
-
"name": "Gemini CLI",
|
|
2022
|
-
},
|
|
2023
|
-
"codex": {
|
|
2024
|
-
"func": lambda: configure_codex_mcp(force=True),
|
|
2025
|
-
"name": "Codex",
|
|
2026
|
-
},
|
|
2027
|
-
}
|
|
1987
|
+
if platform not in platform_mapping:
|
|
1988
|
+
console.print(f"[red]Unknown platform: {platform}[/red]")
|
|
1989
|
+
console.print("\n[bold]Available platforms:[/bold]")
|
|
1990
|
+
for p in platform_mapping.keys():
|
|
1991
|
+
console.print(f" • {p}")
|
|
1992
|
+
raise typer.Exit(1)
|
|
2028
1993
|
|
|
2029
|
-
|
|
2030
|
-
console.print(f"[red]Unknown platform: {platform}[/red]")
|
|
2031
|
-
console.print("\n[bold]Available platforms:[/bold]")
|
|
2032
|
-
for p in platform_mapping.keys():
|
|
2033
|
-
console.print(f" • {p}")
|
|
2034
|
-
raise typer.Exit(1)
|
|
1994
|
+
config = platform_mapping[platform]
|
|
2035
1995
|
|
|
2036
|
-
|
|
1996
|
+
if dry_run:
|
|
1997
|
+
console.print(f"[cyan]DRY RUN - Would install for {config['name']}[/cyan]")
|
|
1998
|
+
return
|
|
2037
1999
|
|
|
2038
|
-
|
|
2039
|
-
|
|
2000
|
+
try:
|
|
2001
|
+
config["func"]()
|
|
2002
|
+
except Exception as e:
|
|
2003
|
+
console.print(f"[red]Installation failed: {e}[/red]")
|
|
2004
|
+
raise typer.Exit(1)
|
|
2040
2005
|
return
|
|
2041
2006
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2007
|
+
# Otherwise, delegate to init for adapter initialization
|
|
2008
|
+
# This makes 'install' and 'init' synonymous when called without --platform
|
|
2009
|
+
init(
|
|
2010
|
+
adapter=adapter,
|
|
2011
|
+
project_path=project_path,
|
|
2012
|
+
global_config=global_config,
|
|
2013
|
+
base_path=base_path,
|
|
2014
|
+
api_key=api_key,
|
|
2015
|
+
team_id=team_id,
|
|
2016
|
+
jira_server=jira_server,
|
|
2017
|
+
jira_email=jira_email,
|
|
2018
|
+
jira_project=jira_project,
|
|
2019
|
+
github_owner=github_owner,
|
|
2020
|
+
github_repo=github_repo,
|
|
2021
|
+
github_token=github_token,
|
|
2022
|
+
)
|
|
2047
2023
|
|
|
2048
2024
|
|
|
2049
2025
|
@app.command()
|
|
2050
2026
|
def remove(
|
|
2051
|
-
platform:
|
|
2027
|
+
platform: str | None = typer.Argument(
|
|
2052
2028
|
None,
|
|
2053
2029
|
help="Platform to remove (claude-code, claude-desktop, auggie, gemini, codex)",
|
|
2054
2030
|
),
|
|
@@ -2135,7 +2111,7 @@ def remove(
|
|
|
2135
2111
|
|
|
2136
2112
|
@app.command()
|
|
2137
2113
|
def uninstall(
|
|
2138
|
-
platform:
|
|
2114
|
+
platform: str | None = typer.Argument(
|
|
2139
2115
|
None,
|
|
2140
2116
|
help="Platform to uninstall (claude-code, claude-desktop, auggie, gemini, codex)",
|
|
2141
2117
|
),
|
|
@@ -2218,10 +2194,10 @@ def check(queue_id: str = typer.Argument(..., help="Queue ID to check")):
|
|
|
2218
2194
|
|
|
2219
2195
|
@mcp_app.command(name="serve")
|
|
2220
2196
|
def mcp_serve(
|
|
2221
|
-
adapter:
|
|
2197
|
+
adapter: AdapterType | None = typer.Option(
|
|
2222
2198
|
None, "--adapter", "-a", help="Override default adapter type"
|
|
2223
2199
|
),
|
|
2224
|
-
base_path:
|
|
2200
|
+
base_path: str | None = typer.Option(
|
|
2225
2201
|
None, "--base-path", help="Base path for AITrackdown adapter"
|
|
2226
2202
|
),
|
|
2227
2203
|
):
|