mcp-ticketer 0.1.22__py3-none-any.whl → 0.1.24__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 +1 -1
- mcp_ticketer/adapters/aitrackdown.py +15 -14
- mcp_ticketer/adapters/github.py +21 -20
- mcp_ticketer/adapters/hybrid.py +13 -12
- mcp_ticketer/adapters/jira.py +32 -27
- mcp_ticketer/adapters/linear.py +29 -26
- mcp_ticketer/cache/memory.py +2 -2
- mcp_ticketer/cli/auggie_configure.py +237 -0
- mcp_ticketer/cli/codex_configure.py +257 -0
- mcp_ticketer/cli/gemini_configure.py +261 -0
- mcp_ticketer/cli/main.py +171 -10
- mcp_ticketer/cli/migrate_config.py +3 -7
- mcp_ticketer/cli/utils.py +8 -8
- mcp_ticketer/core/adapter.py +12 -11
- mcp_ticketer/core/config.py +17 -17
- mcp_ticketer/core/env_discovery.py +24 -24
- mcp_ticketer/core/http_client.py +13 -13
- mcp_ticketer/core/mappers.py +25 -25
- mcp_ticketer/core/models.py +10 -10
- mcp_ticketer/core/project_config.py +25 -22
- mcp_ticketer/core/registry.py +7 -7
- mcp_ticketer/mcp/server.py +18 -18
- mcp_ticketer/queue/manager.py +2 -2
- mcp_ticketer/queue/queue.py +7 -7
- mcp_ticketer/queue/worker.py +8 -8
- {mcp_ticketer-0.1.22.dist-info → mcp_ticketer-0.1.24.dist-info}/METADATA +58 -8
- mcp_ticketer-0.1.24.dist-info/RECORD +45 -0
- mcp_ticketer-0.1.22.dist-info/RECORD +0 -42
- {mcp_ticketer-0.1.22.dist-info → mcp_ticketer-0.1.24.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.1.22.dist-info → mcp_ticketer-0.1.24.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.1.22.dist-info → mcp_ticketer-0.1.24.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.1.22.dist-info → mcp_ticketer-0.1.24.dist-info}/top_level.txt +0 -0
mcp_ticketer/adapters/linear.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""Linear adapter implementation using native GraphQL API with full feature support."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import builtins
|
|
4
5
|
import os
|
|
5
6
|
from datetime import date, datetime
|
|
6
7
|
from enum import Enum
|
|
7
|
-
from typing import Any,
|
|
8
|
+
from typing import Any, Optional, Union
|
|
8
9
|
|
|
9
10
|
from gql import Client, gql
|
|
10
11
|
from gql.transport.exceptions import TransportQueryError
|
|
@@ -278,7 +279,7 @@ ISSUE_LIST_FRAGMENTS = (
|
|
|
278
279
|
class LinearAdapter(BaseAdapter[Task]):
|
|
279
280
|
"""Adapter for Linear issue tracking system using native GraphQL API."""
|
|
280
281
|
|
|
281
|
-
def __init__(self, config:
|
|
282
|
+
def __init__(self, config: dict[str, Any]):
|
|
282
283
|
"""Initialize Linear adapter.
|
|
283
284
|
|
|
284
285
|
Args:
|
|
@@ -315,9 +316,9 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
315
316
|
|
|
316
317
|
# Caches for frequently used data
|
|
317
318
|
self._team_id: Optional[str] = None
|
|
318
|
-
self._workflow_states: Optional[
|
|
319
|
-
self._labels: Optional[
|
|
320
|
-
self._users: Optional[
|
|
319
|
+
self._workflow_states: Optional[dict[str, dict[str, Any]]] = None
|
|
320
|
+
self._labels: Optional[dict[str, str]] = None # name -> id
|
|
321
|
+
self._users: Optional[dict[str, str]] = None # email -> id
|
|
321
322
|
|
|
322
323
|
# Initialize state mapping
|
|
323
324
|
self._state_mapping = self._get_state_mapping()
|
|
@@ -435,7 +436,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
435
436
|
|
|
436
437
|
async def _fetch_workflow_states_data(
|
|
437
438
|
self, team_id: str
|
|
438
|
-
) ->
|
|
439
|
+
) -> dict[str, dict[str, Any]]:
|
|
439
440
|
"""Fetch workflow states data."""
|
|
440
441
|
query = gql(
|
|
441
442
|
"""
|
|
@@ -467,7 +468,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
467
468
|
|
|
468
469
|
return workflow_states
|
|
469
470
|
|
|
470
|
-
async def _fetch_labels_data(self, team_id: str) ->
|
|
471
|
+
async def _fetch_labels_data(self, team_id: str) -> dict[str, str]:
|
|
471
472
|
"""Fetch labels data."""
|
|
472
473
|
query = gql(
|
|
473
474
|
"""
|
|
@@ -498,7 +499,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
498
499
|
await self._ensure_initialized()
|
|
499
500
|
return self._team_id
|
|
500
501
|
|
|
501
|
-
async def _get_workflow_states(self) ->
|
|
502
|
+
async def _get_workflow_states(self) -> dict[str, dict[str, Any]]:
|
|
502
503
|
"""Get cached workflow states from Linear."""
|
|
503
504
|
await self._ensure_initialized()
|
|
504
505
|
return self._workflow_states
|
|
@@ -619,7 +620,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
619
620
|
)
|
|
620
621
|
return True, ""
|
|
621
622
|
|
|
622
|
-
def _get_state_mapping(self) ->
|
|
623
|
+
def _get_state_mapping(self) -> dict[TicketState, str]:
|
|
623
624
|
"""Get mapping from universal states to Linear state types.
|
|
624
625
|
|
|
625
626
|
Required by BaseAdapter abstract method.
|
|
@@ -643,7 +644,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
643
644
|
return self._state_mapping.get(state, LinearStateType.BACKLOG)
|
|
644
645
|
|
|
645
646
|
def _map_linear_state(
|
|
646
|
-
self, state_data:
|
|
647
|
+
self, state_data: dict[str, Any], labels: list[str]
|
|
647
648
|
) -> TicketState:
|
|
648
649
|
"""Map Linear state and labels to universal state."""
|
|
649
650
|
state_type = state_data.get("type", "").lower()
|
|
@@ -669,7 +670,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
669
670
|
}
|
|
670
671
|
return state_mapping.get(state_type, TicketState.OPEN)
|
|
671
672
|
|
|
672
|
-
def _task_from_linear_issue(self, issue:
|
|
673
|
+
def _task_from_linear_issue(self, issue: dict[str, Any]) -> Task:
|
|
673
674
|
"""Convert Linear issue to universal Task."""
|
|
674
675
|
# Extract labels
|
|
675
676
|
tags = []
|
|
@@ -786,7 +787,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
786
787
|
metadata=metadata,
|
|
787
788
|
)
|
|
788
789
|
|
|
789
|
-
def _epic_from_linear_project(self, project:
|
|
790
|
+
def _epic_from_linear_project(self, project: dict[str, Any]) -> Epic:
|
|
790
791
|
"""Convert Linear project to universal Epic."""
|
|
791
792
|
# Map project state to ticket state
|
|
792
793
|
project_state = project.get("state", "planned").lower()
|
|
@@ -1005,7 +1006,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1005
1006
|
|
|
1006
1007
|
return None
|
|
1007
1008
|
|
|
1008
|
-
async def update(self, ticket_id: str, updates:
|
|
1009
|
+
async def update(self, ticket_id: str, updates: dict[str, Any]) -> Optional[Task]:
|
|
1009
1010
|
"""Update a Linear issue with comprehensive field support."""
|
|
1010
1011
|
# Validate credentials before attempting operation
|
|
1011
1012
|
is_valid, error_message = self.validate_credentials()
|
|
@@ -1162,8 +1163,8 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1162
1163
|
return result.get("issueArchive", {}).get("success", False)
|
|
1163
1164
|
|
|
1164
1165
|
async def list(
|
|
1165
|
-
self, limit: int = 10, offset: int = 0, filters: Optional[
|
|
1166
|
-
) ->
|
|
1166
|
+
self, limit: int = 10, offset: int = 0, filters: Optional[dict[str, Any]] = None
|
|
1167
|
+
) -> list[Task]:
|
|
1167
1168
|
"""List Linear issues with comprehensive filtering."""
|
|
1168
1169
|
team_id = await self._ensure_team_id()
|
|
1169
1170
|
|
|
@@ -1271,7 +1272,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1271
1272
|
|
|
1272
1273
|
return tasks
|
|
1273
1274
|
|
|
1274
|
-
async def search(self, query: SearchQuery) ->
|
|
1275
|
+
async def search(self, query: SearchQuery) -> builtins.list[Task]:
|
|
1275
1276
|
"""Search Linear issues with advanced filtering and text search."""
|
|
1276
1277
|
team_id = await self._ensure_team_id()
|
|
1277
1278
|
|
|
@@ -1445,7 +1446,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1445
1446
|
|
|
1446
1447
|
async def get_comments(
|
|
1447
1448
|
self, ticket_id: str, limit: int = 10, offset: int = 0
|
|
1448
|
-
) ->
|
|
1449
|
+
) -> builtins.list[Comment]:
|
|
1449
1450
|
"""Get comments for a Linear issue with pagination."""
|
|
1450
1451
|
query = gql(
|
|
1451
1452
|
USER_FRAGMENT
|
|
@@ -1546,7 +1547,9 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1546
1547
|
|
|
1547
1548
|
return result["projectCreate"]["project"]["id"]
|
|
1548
1549
|
|
|
1549
|
-
async def get_cycles(
|
|
1550
|
+
async def get_cycles(
|
|
1551
|
+
self, active_only: bool = True
|
|
1552
|
+
) -> builtins.list[dict[str, Any]]:
|
|
1550
1553
|
"""Get Linear cycles (sprints) for the team."""
|
|
1551
1554
|
team_id = await self._ensure_team_id()
|
|
1552
1555
|
|
|
@@ -1638,7 +1641,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1638
1641
|
ticket_id: str,
|
|
1639
1642
|
pr_url: str,
|
|
1640
1643
|
pr_number: Optional[int] = None,
|
|
1641
|
-
) ->
|
|
1644
|
+
) -> dict[str, Any]:
|
|
1642
1645
|
"""Link a Linear issue to a GitHub pull request.
|
|
1643
1646
|
|
|
1644
1647
|
Args:
|
|
@@ -1741,8 +1744,8 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1741
1744
|
async def create_pull_request_for_issue(
|
|
1742
1745
|
self,
|
|
1743
1746
|
ticket_id: str,
|
|
1744
|
-
github_config:
|
|
1745
|
-
) ->
|
|
1747
|
+
github_config: dict[str, Any],
|
|
1748
|
+
) -> dict[str, Any]:
|
|
1746
1749
|
"""Create a GitHub PR for a Linear issue using GitHub integration.
|
|
1747
1750
|
|
|
1748
1751
|
This requires GitHub integration to be configured in Linear.
|
|
@@ -1837,7 +1840,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1837
1840
|
else:
|
|
1838
1841
|
raise ValueError(f"Failed to update issue {ticket_id} with branch name")
|
|
1839
1842
|
|
|
1840
|
-
async def _search_by_identifier(self, identifier: str) -> Optional[
|
|
1843
|
+
async def _search_by_identifier(self, identifier: str) -> Optional[dict[str, Any]]:
|
|
1841
1844
|
"""Search for an issue by its identifier."""
|
|
1842
1845
|
search_query = gql(
|
|
1843
1846
|
"""
|
|
@@ -1857,7 +1860,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1857
1860
|
search_query, variable_values={"identifier": identifier}
|
|
1858
1861
|
)
|
|
1859
1862
|
return result.get("issue")
|
|
1860
|
-
except:
|
|
1863
|
+
except Exception:
|
|
1861
1864
|
return None
|
|
1862
1865
|
|
|
1863
1866
|
# Epic/Issue/Task Hierarchy Methods (Linear: Project = Epic, Issue = Issue, Sub-issue = Task)
|
|
@@ -1950,7 +1953,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
1950
1953
|
|
|
1951
1954
|
return None
|
|
1952
1955
|
|
|
1953
|
-
async def list_epics(self, **kwargs) ->
|
|
1956
|
+
async def list_epics(self, **kwargs) -> builtins.list[Epic]:
|
|
1954
1957
|
"""List all Linear Projects (Epics).
|
|
1955
1958
|
|
|
1956
1959
|
Args:
|
|
@@ -2037,7 +2040,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
2037
2040
|
# The existing create method handles project association via parent_epic field
|
|
2038
2041
|
return await self.create(task)
|
|
2039
2042
|
|
|
2040
|
-
async def list_issues_by_epic(self, epic_id: str) ->
|
|
2043
|
+
async def list_issues_by_epic(self, epic_id: str) -> builtins.list[Task]:
|
|
2041
2044
|
"""List all issues in a Linear project (epic).
|
|
2042
2045
|
|
|
2043
2046
|
Args:
|
|
@@ -2197,7 +2200,7 @@ class LinearAdapter(BaseAdapter[Task]):
|
|
|
2197
2200
|
created_issue = result["issueCreate"]["issue"]
|
|
2198
2201
|
return self._task_from_linear_issue(created_issue)
|
|
2199
2202
|
|
|
2200
|
-
async def list_tasks_by_issue(self, issue_id: str) ->
|
|
2203
|
+
async def list_tasks_by_issue(self, issue_id: str) -> builtins.list[Task]:
|
|
2201
2204
|
"""List all tasks (sub-issues) under an issue.
|
|
2202
2205
|
|
|
2203
2206
|
Args:
|
mcp_ticketer/cache/memory.py
CHANGED
|
@@ -5,7 +5,7 @@ import hashlib
|
|
|
5
5
|
import json
|
|
6
6
|
import time
|
|
7
7
|
from functools import wraps
|
|
8
|
-
from typing import Any, Callable,
|
|
8
|
+
from typing import Any, Callable, Optional
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class CacheEntry:
|
|
@@ -37,7 +37,7 @@ class MemoryCache:
|
|
|
37
37
|
default_ttl: Default TTL in seconds (5 minutes)
|
|
38
38
|
|
|
39
39
|
"""
|
|
40
|
-
self._cache:
|
|
40
|
+
self._cache: dict[str, CacheEntry] = {}
|
|
41
41
|
self._default_ttl = default_ttl
|
|
42
42
|
self._lock = asyncio.Lock()
|
|
43
43
|
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Auggie CLI configuration for mcp-ticketer integration.
|
|
2
|
+
|
|
3
|
+
IMPORTANT: Auggie CLI ONLY supports global configuration at ~/.augment/settings.json.
|
|
4
|
+
There is no project-level configuration support.
|
|
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 find_mcp_ticketer_binary, load_project_config
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def find_auggie_config() -> Path:
|
|
19
|
+
"""Find or create Auggie CLI configuration file.
|
|
20
|
+
|
|
21
|
+
Auggie CLI only supports global user-level configuration.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Path to Auggie settings file at ~/.augment/settings.json
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
# Global user-level configuration (ONLY option for Auggie)
|
|
28
|
+
config_path = Path.home() / ".augment" / "settings.json"
|
|
29
|
+
return config_path
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def load_auggie_config(config_path: Path) -> dict[str, Any]:
|
|
33
|
+
"""Load existing Auggie configuration or return empty structure.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config_path: Path to Auggie settings file
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Auggie configuration dict
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
if config_path.exists():
|
|
43
|
+
try:
|
|
44
|
+
with open(config_path) as f:
|
|
45
|
+
config: dict[str, Any] = json.load(f)
|
|
46
|
+
return config
|
|
47
|
+
except json.JSONDecodeError as e:
|
|
48
|
+
console.print(
|
|
49
|
+
f"[yellow]⚠ Warning: Could not parse existing config: {e}[/yellow]"
|
|
50
|
+
)
|
|
51
|
+
console.print("[yellow]Creating new configuration...[/yellow]")
|
|
52
|
+
|
|
53
|
+
# Return empty structure with mcpServers section
|
|
54
|
+
return {"mcpServers": {}}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def save_auggie_config(config_path: Path, config: dict[str, Any]) -> None:
|
|
58
|
+
"""Save Auggie configuration to file.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
config_path: Path to Auggie settings file
|
|
62
|
+
config: Configuration to save
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
# Ensure directory exists
|
|
66
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
|
|
68
|
+
# Write with 2-space indentation (JSON standard)
|
|
69
|
+
with open(config_path, "w") as f:
|
|
70
|
+
json.dump(config, f, indent=2)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def create_auggie_server_config(
|
|
74
|
+
binary_path: str, project_config: dict[str, Any]
|
|
75
|
+
) -> dict[str, Any]:
|
|
76
|
+
"""Create Auggie MCP server configuration for mcp-ticketer.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
binary_path: Path to mcp-ticketer binary
|
|
80
|
+
project_config: Project configuration from .mcp-ticketer/config.json
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Auggie MCP server configuration dict
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
# Get adapter configuration
|
|
87
|
+
adapter = project_config.get("default_adapter", "aitrackdown")
|
|
88
|
+
adapters_config = project_config.get("adapters", {})
|
|
89
|
+
adapter_config = adapters_config.get(adapter, {})
|
|
90
|
+
|
|
91
|
+
# Build environment variables
|
|
92
|
+
env_vars = {}
|
|
93
|
+
|
|
94
|
+
# Add adapter type
|
|
95
|
+
env_vars["MCP_TICKETER_ADAPTER"] = adapter
|
|
96
|
+
|
|
97
|
+
# Add adapter-specific environment variables
|
|
98
|
+
if adapter == "aitrackdown":
|
|
99
|
+
# Set base path for local adapter
|
|
100
|
+
base_path = adapter_config.get("base_path", ".aitrackdown")
|
|
101
|
+
# Use absolute path to home directory for global config
|
|
102
|
+
# Since Auggie is global, we can't rely on project-specific paths
|
|
103
|
+
env_vars["MCP_TICKETER_BASE_PATH"] = str(
|
|
104
|
+
Path.home() / ".mcp-ticketer" / base_path
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
elif adapter == "linear":
|
|
108
|
+
if "api_key" in adapter_config:
|
|
109
|
+
env_vars["LINEAR_API_KEY"] = adapter_config["api_key"]
|
|
110
|
+
if "team_id" in adapter_config:
|
|
111
|
+
env_vars["LINEAR_TEAM_ID"] = adapter_config["team_id"]
|
|
112
|
+
|
|
113
|
+
elif adapter == "github":
|
|
114
|
+
if "token" in adapter_config:
|
|
115
|
+
env_vars["GITHUB_TOKEN"] = adapter_config["token"]
|
|
116
|
+
if "owner" in adapter_config:
|
|
117
|
+
env_vars["GITHUB_OWNER"] = adapter_config["owner"]
|
|
118
|
+
if "repo" in adapter_config:
|
|
119
|
+
env_vars["GITHUB_REPO"] = adapter_config["repo"]
|
|
120
|
+
|
|
121
|
+
elif adapter == "jira":
|
|
122
|
+
if "api_token" in adapter_config:
|
|
123
|
+
env_vars["JIRA_API_TOKEN"] = adapter_config["api_token"]
|
|
124
|
+
if "email" in adapter_config:
|
|
125
|
+
env_vars["JIRA_EMAIL"] = adapter_config["email"]
|
|
126
|
+
if "server" in adapter_config:
|
|
127
|
+
env_vars["JIRA_SERVER"] = adapter_config["server"]
|
|
128
|
+
if "project_key" in adapter_config:
|
|
129
|
+
env_vars["JIRA_PROJECT_KEY"] = adapter_config["project_key"]
|
|
130
|
+
|
|
131
|
+
# Create server configuration (simpler than Gemini - no timeout/trust)
|
|
132
|
+
config = {
|
|
133
|
+
"command": binary_path,
|
|
134
|
+
"args": ["serve"],
|
|
135
|
+
"env": env_vars,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return config
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def configure_auggie_mcp(force: bool = False) -> None:
|
|
142
|
+
"""Configure Auggie CLI to use mcp-ticketer.
|
|
143
|
+
|
|
144
|
+
IMPORTANT: Auggie CLI ONLY supports global configuration.
|
|
145
|
+
This will configure ~/.augment/settings.json for all projects.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
force: Overwrite existing configuration
|
|
149
|
+
|
|
150
|
+
Raises:
|
|
151
|
+
FileNotFoundError: If binary or project config not found
|
|
152
|
+
ValueError: If configuration is invalid
|
|
153
|
+
|
|
154
|
+
"""
|
|
155
|
+
# Step 1: Find mcp-ticketer binary
|
|
156
|
+
console.print("[cyan]🔍 Finding mcp-ticketer binary...[/cyan]")
|
|
157
|
+
try:
|
|
158
|
+
binary_path = find_mcp_ticketer_binary()
|
|
159
|
+
console.print(f"[green]✓[/green] Found: {binary_path}")
|
|
160
|
+
except FileNotFoundError as e:
|
|
161
|
+
console.print(f"[red]✗[/red] {e}")
|
|
162
|
+
raise
|
|
163
|
+
|
|
164
|
+
# Step 2: Load project configuration
|
|
165
|
+
console.print("\n[cyan]📖 Reading project configuration...[/cyan]")
|
|
166
|
+
try:
|
|
167
|
+
project_config = load_project_config()
|
|
168
|
+
adapter = project_config.get("default_adapter", "aitrackdown")
|
|
169
|
+
console.print(f"[green]✓[/green] Adapter: {adapter}")
|
|
170
|
+
except (FileNotFoundError, ValueError) as e:
|
|
171
|
+
console.print(f"[red]✗[/red] {e}")
|
|
172
|
+
raise
|
|
173
|
+
|
|
174
|
+
# Step 3: Find Auggie config location
|
|
175
|
+
console.print("\n[cyan]🔧 Configuring global Auggie CLI...[/cyan]")
|
|
176
|
+
console.print(
|
|
177
|
+
"[yellow]⚠ NOTE: Auggie only supports global configuration (affects all projects)[/yellow]"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
auggie_config_path = find_auggie_config()
|
|
181
|
+
console.print(f"[dim]Config location: {auggie_config_path}[/dim]")
|
|
182
|
+
|
|
183
|
+
# Step 4: Load existing Auggie configuration
|
|
184
|
+
auggie_config = load_auggie_config(auggie_config_path)
|
|
185
|
+
|
|
186
|
+
# Step 5: Check if mcp-ticketer already configured
|
|
187
|
+
if "mcp-ticketer" in auggie_config.get("mcpServers", {}):
|
|
188
|
+
if not force:
|
|
189
|
+
console.print("[yellow]⚠ mcp-ticketer is already configured[/yellow]")
|
|
190
|
+
console.print("[dim]Use --force to overwrite existing configuration[/dim]")
|
|
191
|
+
return
|
|
192
|
+
else:
|
|
193
|
+
console.print("[yellow]⚠ Overwriting existing configuration[/yellow]")
|
|
194
|
+
|
|
195
|
+
# Step 6: Create mcp-ticketer server config
|
|
196
|
+
server_config = create_auggie_server_config(
|
|
197
|
+
binary_path=binary_path, project_config=project_config
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Step 7: Update Auggie configuration
|
|
201
|
+
if "mcpServers" not in auggie_config:
|
|
202
|
+
auggie_config["mcpServers"] = {}
|
|
203
|
+
|
|
204
|
+
auggie_config["mcpServers"]["mcp-ticketer"] = server_config
|
|
205
|
+
|
|
206
|
+
# Step 8: Save configuration
|
|
207
|
+
try:
|
|
208
|
+
save_auggie_config(auggie_config_path, auggie_config)
|
|
209
|
+
console.print("\n[green]✓ Successfully configured mcp-ticketer[/green]")
|
|
210
|
+
console.print(f"[dim]Configuration saved to: {auggie_config_path}[/dim]")
|
|
211
|
+
|
|
212
|
+
# Print configuration details
|
|
213
|
+
console.print("\n[bold]Configuration Details:[/bold]")
|
|
214
|
+
console.print(" Server name: mcp-ticketer")
|
|
215
|
+
console.print(f" Adapter: {adapter}")
|
|
216
|
+
console.print(f" Binary: {binary_path}")
|
|
217
|
+
console.print(" Scope: Global (affects all projects)")
|
|
218
|
+
if "env" in server_config:
|
|
219
|
+
console.print(
|
|
220
|
+
f" Environment variables: {list(server_config['env'].keys())}"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Next steps
|
|
224
|
+
console.print("\n[bold cyan]Next Steps:[/bold cyan]")
|
|
225
|
+
console.print("1. Restart Auggie CLI for changes to take effect")
|
|
226
|
+
console.print("2. Run 'auggie' command in any directory")
|
|
227
|
+
console.print("3. mcp-ticketer tools will be available via MCP")
|
|
228
|
+
console.print(
|
|
229
|
+
"\n[yellow]⚠ Warning: This is a global configuration affecting all projects[/yellow]"
|
|
230
|
+
)
|
|
231
|
+
console.print(
|
|
232
|
+
"[dim]If you need project-specific configuration, use Claude or Gemini instead[/dim]"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
except Exception as e:
|
|
236
|
+
console.print(f"\n[red]✗ Failed to save configuration:[/red] {e}")
|
|
237
|
+
raise
|