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.
- mcp_ticketer/__init__.py +10 -10
- mcp_ticketer/__version__.py +3 -3
- mcp_ticketer/adapters/__init__.py +2 -0
- mcp_ticketer/adapters/aitrackdown.py +394 -9
- 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 +836 -105
- mcp_ticketer/adapters/hybrid.py +47 -5
- mcp_ticketer/adapters/jira.py +772 -1
- mcp_ticketer/adapters/linear/adapter.py +2293 -108
- mcp_ticketer/adapters/linear/client.py +146 -12
- mcp_ticketer/adapters/linear/mappers.py +105 -11
- mcp_ticketer/adapters/linear/queries.py +168 -1
- mcp_ticketer/adapters/linear/types.py +80 -4
- mcp_ticketer/analysis/__init__.py +56 -0
- mcp_ticketer/analysis/dependency_graph.py +255 -0
- mcp_ticketer/analysis/health_assessment.py +304 -0
- mcp_ticketer/analysis/orphaned.py +218 -0
- mcp_ticketer/analysis/project_status.py +594 -0
- mcp_ticketer/analysis/similarity.py +224 -0
- mcp_ticketer/analysis/staleness.py +266 -0
- mcp_ticketer/automation/__init__.py +11 -0
- mcp_ticketer/automation/project_updates.py +378 -0
- mcp_ticketer/cache/memory.py +3 -3
- mcp_ticketer/cli/adapter_diagnostics.py +4 -2
- mcp_ticketer/cli/auggie_configure.py +18 -6
- mcp_ticketer/cli/codex_configure.py +175 -60
- mcp_ticketer/cli/configure.py +884 -146
- mcp_ticketer/cli/cursor_configure.py +314 -0
- mcp_ticketer/cli/diagnostics.py +31 -28
- mcp_ticketer/cli/discover.py +293 -21
- mcp_ticketer/cli/gemini_configure.py +18 -6
- mcp_ticketer/cli/init_command.py +880 -0
- mcp_ticketer/cli/instruction_commands.py +435 -0
- mcp_ticketer/cli/linear_commands.py +99 -15
- mcp_ticketer/cli/main.py +109 -2055
- mcp_ticketer/cli/mcp_configure.py +673 -99
- mcp_ticketer/cli/mcp_server_commands.py +415 -0
- mcp_ticketer/cli/migrate_config.py +12 -8
- mcp_ticketer/cli/platform_commands.py +6 -6
- mcp_ticketer/cli/platform_detection.py +477 -0
- mcp_ticketer/cli/platform_installer.py +536 -0
- mcp_ticketer/cli/project_update_commands.py +350 -0
- mcp_ticketer/cli/queue_commands.py +15 -15
- mcp_ticketer/cli/setup_command.py +639 -0
- mcp_ticketer/cli/simple_health.py +13 -11
- mcp_ticketer/cli/ticket_commands.py +277 -36
- mcp_ticketer/cli/update_checker.py +313 -0
- mcp_ticketer/cli/utils.py +45 -41
- mcp_ticketer/core/__init__.py +35 -1
- mcp_ticketer/core/adapter.py +170 -5
- mcp_ticketer/core/config.py +38 -31
- mcp_ticketer/core/env_discovery.py +33 -3
- mcp_ticketer/core/env_loader.py +7 -6
- mcp_ticketer/core/exceptions.py +10 -4
- mcp_ticketer/core/http_client.py +10 -10
- mcp_ticketer/core/instructions.py +405 -0
- mcp_ticketer/core/label_manager.py +732 -0
- mcp_ticketer/core/mappers.py +32 -20
- mcp_ticketer/core/models.py +136 -1
- mcp_ticketer/core/onepassword_secrets.py +379 -0
- mcp_ticketer/core/priority_matcher.py +463 -0
- mcp_ticketer/core/project_config.py +148 -14
- mcp_ticketer/core/registry.py +1 -1
- 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 +2 -2
- mcp_ticketer/mcp/server/__init__.py +2 -2
- mcp_ticketer/mcp/server/diagnostic_helper.py +175 -0
- mcp_ticketer/mcp/server/main.py +187 -93
- mcp_ticketer/mcp/server/routing.py +655 -0
- mcp_ticketer/mcp/server/server_sdk.py +58 -0
- mcp_ticketer/mcp/server/tools/__init__.py +37 -9
- mcp_ticketer/mcp/server/tools/analysis_tools.py +854 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +65 -20
- mcp_ticketer/mcp/server/tools/bulk_tools.py +259 -202
- mcp_ticketer/mcp/server/tools/comment_tools.py +74 -12
- mcp_ticketer/mcp/server/tools/config_tools.py +1429 -0
- mcp_ticketer/mcp/server/tools/diagnostic_tools.py +211 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +878 -319
- mcp_ticketer/mcp/server/tools/instruction_tools.py +295 -0
- mcp_ticketer/mcp/server/tools/label_tools.py +942 -0
- mcp_ticketer/mcp/server/tools/pr_tools.py +3 -7
- mcp_ticketer/mcp/server/tools/project_status_tools.py +158 -0
- mcp_ticketer/mcp/server/tools/project_update_tools.py +473 -0
- mcp_ticketer/mcp/server/tools/search_tools.py +180 -97
- mcp_ticketer/mcp/server/tools/session_tools.py +308 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +1182 -82
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +364 -0
- mcp_ticketer/queue/health_monitor.py +1 -0
- mcp_ticketer/queue/manager.py +4 -4
- mcp_ticketer/queue/queue.py +3 -3
- mcp_ticketer/queue/run_worker.py +1 -1
- mcp_ticketer/queue/ticket_registry.py +2 -2
- mcp_ticketer/queue/worker.py +15 -13
- mcp_ticketer/utils/__init__.py +5 -0
- mcp_ticketer/utils/token_utils.py +246 -0
- mcp_ticketer-2.0.1.dist-info/METADATA +1366 -0
- mcp_ticketer-2.0.1.dist-info/RECORD +122 -0
- mcp_ticketer-0.4.11.dist-info/METADATA +0 -496
- mcp_ticketer-0.4.11.dist-info/RECORD +0 -77
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-2.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"""MCP server management commands for mcp-ticketer."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
# Create MCP configuration command group
|
|
13
|
+
mcp_app = typer.Typer(
|
|
14
|
+
name="mcp",
|
|
15
|
+
help="Configure MCP integration for AI clients (Claude, Gemini, Codex, Auggie)",
|
|
16
|
+
add_completion=False,
|
|
17
|
+
invoke_without_command=True,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@mcp_app.callback()
|
|
22
|
+
def mcp_callback(
|
|
23
|
+
ctx: typer.Context,
|
|
24
|
+
project_path: str | None = typer.Option(
|
|
25
|
+
None, "--path", "-p", help="Project directory path (default: current directory)"
|
|
26
|
+
),
|
|
27
|
+
) -> None:
|
|
28
|
+
"""MCP command group - runs MCP server if no subcommand provided.
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
--------
|
|
32
|
+
mcp-ticketer mcp # Start server in current directory
|
|
33
|
+
mcp-ticketer mcp --path /dir # Start server in specific directory
|
|
34
|
+
mcp-ticketer mcp -p /dir # Start server (short form)
|
|
35
|
+
mcp-ticketer mcp status # Check MCP status
|
|
36
|
+
mcp-ticketer mcp serve # Explicitly start server
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
if ctx.invoked_subcommand is None:
|
|
40
|
+
# No subcommand provided, run the serve command
|
|
41
|
+
# Change to project directory if provided
|
|
42
|
+
if project_path:
|
|
43
|
+
import os
|
|
44
|
+
|
|
45
|
+
os.chdir(project_path)
|
|
46
|
+
# Invoke the serve command through context
|
|
47
|
+
ctx.invoke(mcp_serve, adapter=None, base_path=None)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@mcp_app.command(name="serve")
|
|
51
|
+
def mcp_serve(
|
|
52
|
+
adapter: str | None = typer.Option(
|
|
53
|
+
None, "--adapter", "-a", help="Override default adapter type"
|
|
54
|
+
),
|
|
55
|
+
base_path: str | None = typer.Option(
|
|
56
|
+
None, "--base-path", help="Base path for AITrackdown adapter"
|
|
57
|
+
),
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Start MCP server for JSON-RPC communication over stdio.
|
|
60
|
+
|
|
61
|
+
This command is used by Claude Code/Desktop when connecting to the MCP server.
|
|
62
|
+
You typically don't need to run this manually - use 'mcp-ticketer install add' to configure.
|
|
63
|
+
|
|
64
|
+
Configuration Resolution:
|
|
65
|
+
- When MCP server starts, it uses the current working directory (cwd)
|
|
66
|
+
- The cwd is set by Claude Code/Desktop from the 'cwd' field in .mcp/config.json
|
|
67
|
+
- Configuration is loaded with this priority:
|
|
68
|
+
1. Project-specific: .mcp-ticketer/config.json in cwd
|
|
69
|
+
2. Global: ~/.mcp-ticketer/config.json
|
|
70
|
+
3. Default: aitrackdown adapter with .aitrackdown base path
|
|
71
|
+
"""
|
|
72
|
+
# Local imports to avoid circular dependency
|
|
73
|
+
from ..mcp.server.server_sdk import configure_adapter
|
|
74
|
+
from ..mcp.server.server_sdk import main as sdk_main
|
|
75
|
+
|
|
76
|
+
# Import load_config locally to avoid circular import
|
|
77
|
+
# (main.py imports this module, so we can't import from main at module level)
|
|
78
|
+
from .ticket_commands import load_config
|
|
79
|
+
|
|
80
|
+
# Load configuration (respects project-specific config in cwd)
|
|
81
|
+
config = load_config()
|
|
82
|
+
|
|
83
|
+
# Determine adapter type with priority: CLI arg > config > .env files > default
|
|
84
|
+
if adapter:
|
|
85
|
+
# Priority 1: Command line argument
|
|
86
|
+
adapter_type = adapter
|
|
87
|
+
# Get base config from config file
|
|
88
|
+
adapters_config = config.get("adapters", {})
|
|
89
|
+
adapter_config = adapters_config.get(adapter_type, {})
|
|
90
|
+
else:
|
|
91
|
+
# Priority 2: Configuration file (project-specific)
|
|
92
|
+
adapter_type = config.get("default_adapter")
|
|
93
|
+
if adapter_type:
|
|
94
|
+
adapters_config = config.get("adapters", {})
|
|
95
|
+
adapter_config = adapters_config.get(adapter_type, {})
|
|
96
|
+
else:
|
|
97
|
+
# Priority 3: .env files (auto-detection fallback)
|
|
98
|
+
from ..mcp.server.main import _load_env_configuration
|
|
99
|
+
|
|
100
|
+
env_config = _load_env_configuration()
|
|
101
|
+
if env_config:
|
|
102
|
+
adapter_type = env_config["adapter_type"]
|
|
103
|
+
adapter_config = env_config["adapter_config"]
|
|
104
|
+
else:
|
|
105
|
+
# Priority 4: Default fallback
|
|
106
|
+
adapter_type = "aitrackdown"
|
|
107
|
+
adapters_config = config.get("adapters", {})
|
|
108
|
+
adapter_config = adapters_config.get(adapter_type, {})
|
|
109
|
+
|
|
110
|
+
# Override with command line options if provided (highest priority)
|
|
111
|
+
if base_path and adapter_type == "aitrackdown":
|
|
112
|
+
adapter_config["base_path"] = base_path
|
|
113
|
+
|
|
114
|
+
# Fallback to legacy config format
|
|
115
|
+
if not adapter_config and "config" in config:
|
|
116
|
+
adapter_config = config["config"]
|
|
117
|
+
|
|
118
|
+
# MCP server uses stdio for JSON-RPC, so we can't print to stdout
|
|
119
|
+
# Only print to stderr to avoid interfering with the protocol
|
|
120
|
+
if sys.stderr.isatty():
|
|
121
|
+
# Only print if stderr is a terminal (not redirected)
|
|
122
|
+
console.file = sys.stderr
|
|
123
|
+
console.print(
|
|
124
|
+
f"[green]Starting MCP SDK server[/green] with {adapter_type} adapter"
|
|
125
|
+
)
|
|
126
|
+
console.print(
|
|
127
|
+
"[dim]Server running on stdio. Send JSON-RPC requests via stdin.[/dim]"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Configure adapter and run SDK server
|
|
131
|
+
try:
|
|
132
|
+
configure_adapter(adapter_type, adapter_config)
|
|
133
|
+
sdk_main()
|
|
134
|
+
except KeyboardInterrupt:
|
|
135
|
+
# Send this to stderr
|
|
136
|
+
if sys.stderr.isatty():
|
|
137
|
+
console.print("\n[yellow]Server stopped by user[/yellow]")
|
|
138
|
+
sys.exit(0)
|
|
139
|
+
except Exception as e:
|
|
140
|
+
# Log error to stderr
|
|
141
|
+
sys.stderr.write(f"MCP server error: {e}\n")
|
|
142
|
+
sys.exit(1)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@mcp_app.command(name="claude")
|
|
146
|
+
def mcp_claude(
|
|
147
|
+
global_config: bool = typer.Option(
|
|
148
|
+
False,
|
|
149
|
+
"--global",
|
|
150
|
+
"-g",
|
|
151
|
+
help="Configure Claude Desktop instead of project-level",
|
|
152
|
+
),
|
|
153
|
+
force: bool = typer.Option(
|
|
154
|
+
False, "--force", "-f", help="Overwrite existing configuration"
|
|
155
|
+
),
|
|
156
|
+
) -> None:
|
|
157
|
+
"""Configure Claude Code to use mcp-ticketer MCP server.
|
|
158
|
+
|
|
159
|
+
Reads configuration from .mcp-ticketer/config.json and updates
|
|
160
|
+
Claude Code's MCP settings accordingly.
|
|
161
|
+
|
|
162
|
+
By default, configures project-level (.mcp/config.json).
|
|
163
|
+
Use --global to configure Claude Desktop instead.
|
|
164
|
+
|
|
165
|
+
Examples:
|
|
166
|
+
--------
|
|
167
|
+
# Configure for current project (default)
|
|
168
|
+
mcp-ticketer mcp claude
|
|
169
|
+
|
|
170
|
+
# Configure Claude Desktop globally
|
|
171
|
+
mcp-ticketer mcp claude --global
|
|
172
|
+
|
|
173
|
+
# Force overwrite existing configuration
|
|
174
|
+
mcp-ticketer mcp claude --force
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
from ..cli.mcp_configure import configure_claude_mcp
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
configure_claude_mcp(global_config=global_config, force=force)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
console.print(f"[red]✗ Configuration failed:[/red] {e}")
|
|
183
|
+
raise typer.Exit(1) from e
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@mcp_app.command(name="gemini")
|
|
187
|
+
def mcp_gemini(
|
|
188
|
+
scope: str = typer.Option(
|
|
189
|
+
"project",
|
|
190
|
+
"--scope",
|
|
191
|
+
"-s",
|
|
192
|
+
help="Configuration scope: 'project' (default) or 'user'",
|
|
193
|
+
),
|
|
194
|
+
force: bool = typer.Option(
|
|
195
|
+
False, "--force", "-f", help="Overwrite existing configuration"
|
|
196
|
+
),
|
|
197
|
+
) -> None:
|
|
198
|
+
"""Configure Gemini CLI to use mcp-ticketer MCP server.
|
|
199
|
+
|
|
200
|
+
Reads configuration from .mcp-ticketer/config.json and creates
|
|
201
|
+
Gemini CLI settings file with mcp-ticketer configuration.
|
|
202
|
+
|
|
203
|
+
By default, configures project-level (.gemini/settings.json).
|
|
204
|
+
Use --scope user to configure user-level (~/.gemini/settings.json).
|
|
205
|
+
|
|
206
|
+
Examples:
|
|
207
|
+
--------
|
|
208
|
+
# Configure for current project (default)
|
|
209
|
+
mcp-ticketer mcp gemini
|
|
210
|
+
|
|
211
|
+
# Configure at user level
|
|
212
|
+
mcp-ticketer mcp gemini --scope user
|
|
213
|
+
|
|
214
|
+
# Force overwrite existing configuration
|
|
215
|
+
mcp-ticketer mcp gemini --force
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
from ..cli.gemini_configure import configure_gemini_mcp
|
|
219
|
+
|
|
220
|
+
# Validate scope parameter
|
|
221
|
+
if scope not in ["project", "user"]:
|
|
222
|
+
console.print(
|
|
223
|
+
f"[red]✗ Invalid scope:[/red] '{scope}'. Must be 'project' or 'user'"
|
|
224
|
+
)
|
|
225
|
+
raise typer.Exit(1) from None
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
configure_gemini_mcp(scope=scope, force=force) # type: ignore
|
|
229
|
+
except Exception as e:
|
|
230
|
+
console.print(f"[red]✗ Configuration failed:[/red] {e}")
|
|
231
|
+
raise typer.Exit(1) from e
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@mcp_app.command(name="codex")
|
|
235
|
+
def mcp_codex(
|
|
236
|
+
force: bool = typer.Option(
|
|
237
|
+
False, "--force", "-f", help="Overwrite existing configuration"
|
|
238
|
+
),
|
|
239
|
+
) -> None:
|
|
240
|
+
"""Configure Codex CLI to use mcp-ticketer MCP server.
|
|
241
|
+
|
|
242
|
+
Reads configuration from .mcp-ticketer/config.json and creates
|
|
243
|
+
Codex CLI config.toml with mcp-ticketer configuration.
|
|
244
|
+
|
|
245
|
+
IMPORTANT: Codex CLI ONLY supports global configuration at ~/.codex/config.toml.
|
|
246
|
+
There is no project-level configuration support. After configuration,
|
|
247
|
+
you must restart Codex CLI for changes to take effect.
|
|
248
|
+
|
|
249
|
+
Examples:
|
|
250
|
+
--------
|
|
251
|
+
# Configure Codex CLI globally
|
|
252
|
+
mcp-ticketer mcp codex
|
|
253
|
+
|
|
254
|
+
# Force overwrite existing configuration
|
|
255
|
+
mcp-ticketer mcp codex --force
|
|
256
|
+
|
|
257
|
+
"""
|
|
258
|
+
from ..cli.codex_configure import configure_codex_mcp
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
configure_codex_mcp(force=force)
|
|
262
|
+
except Exception as e:
|
|
263
|
+
console.print(f"[red]✗ Configuration failed:[/red] {e}")
|
|
264
|
+
raise typer.Exit(1) from e
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@mcp_app.command(name="auggie")
|
|
268
|
+
def mcp_auggie(
|
|
269
|
+
force: bool = typer.Option(
|
|
270
|
+
False, "--force", "-f", help="Overwrite existing configuration"
|
|
271
|
+
),
|
|
272
|
+
) -> None:
|
|
273
|
+
"""Configure Auggie CLI to use mcp-ticketer MCP server.
|
|
274
|
+
|
|
275
|
+
Reads configuration from .mcp-ticketer/config.json and creates
|
|
276
|
+
Auggie CLI settings.json with mcp-ticketer configuration.
|
|
277
|
+
|
|
278
|
+
IMPORTANT: Auggie CLI ONLY supports global configuration at ~/.augment/settings.json.
|
|
279
|
+
There is no project-level configuration support. After configuration,
|
|
280
|
+
you must restart Auggie CLI for changes to take effect.
|
|
281
|
+
|
|
282
|
+
Examples:
|
|
283
|
+
--------
|
|
284
|
+
# Configure Auggie CLI globally
|
|
285
|
+
mcp-ticketer mcp auggie
|
|
286
|
+
|
|
287
|
+
# Force overwrite existing configuration
|
|
288
|
+
mcp-ticketer mcp auggie --force
|
|
289
|
+
|
|
290
|
+
"""
|
|
291
|
+
from ..cli.auggie_configure import configure_auggie_mcp
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
configure_auggie_mcp(force=force)
|
|
295
|
+
except Exception as e:
|
|
296
|
+
console.print(f"[red]✗ Configuration failed:[/red] {e}")
|
|
297
|
+
raise typer.Exit(1) from e
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@mcp_app.command(name="status")
|
|
301
|
+
def mcp_status() -> None:
|
|
302
|
+
"""Check MCP server status.
|
|
303
|
+
|
|
304
|
+
Shows whether the MCP server is configured and running for various platforms.
|
|
305
|
+
|
|
306
|
+
Examples:
|
|
307
|
+
--------
|
|
308
|
+
mcp-ticketer mcp status
|
|
309
|
+
|
|
310
|
+
"""
|
|
311
|
+
console.print("[bold]MCP Server Status[/bold]\n")
|
|
312
|
+
|
|
313
|
+
# Check project-level configuration
|
|
314
|
+
project_config = Path.cwd() / ".mcp-ticketer" / "config.json"
|
|
315
|
+
if project_config.exists():
|
|
316
|
+
console.print(f"[green]✓[/green] Project config found: {project_config}")
|
|
317
|
+
try:
|
|
318
|
+
with open(project_config) as f:
|
|
319
|
+
config = json.load(f)
|
|
320
|
+
adapter = config.get("default_adapter", "aitrackdown")
|
|
321
|
+
console.print(f" Default adapter: [cyan]{adapter}[/cyan]")
|
|
322
|
+
except Exception as e:
|
|
323
|
+
console.print(f" [yellow]Warning: Could not read config: {e}[/yellow]")
|
|
324
|
+
else:
|
|
325
|
+
console.print("[yellow]○[/yellow] No project config found")
|
|
326
|
+
|
|
327
|
+
# Check Claude Code configuration
|
|
328
|
+
claude_code_config = Path.cwd() / ".mcp" / "config.json"
|
|
329
|
+
if claude_code_config.exists():
|
|
330
|
+
console.print(
|
|
331
|
+
f"\n[green]✓[/green] Claude Code configured: {claude_code_config}"
|
|
332
|
+
)
|
|
333
|
+
else:
|
|
334
|
+
console.print("\n[yellow]○[/yellow] Claude Code not configured")
|
|
335
|
+
|
|
336
|
+
# Check Claude Desktop configuration
|
|
337
|
+
claude_desktop_config = (
|
|
338
|
+
Path.home()
|
|
339
|
+
/ "Library"
|
|
340
|
+
/ "Application Support"
|
|
341
|
+
/ "Claude"
|
|
342
|
+
/ "claude_desktop_config.json"
|
|
343
|
+
)
|
|
344
|
+
if claude_desktop_config.exists():
|
|
345
|
+
try:
|
|
346
|
+
with open(claude_desktop_config) as f:
|
|
347
|
+
config = json.load(f)
|
|
348
|
+
if "mcpServers" in config and "mcp-ticketer" in config["mcpServers"]:
|
|
349
|
+
console.print(
|
|
350
|
+
f"[green]✓[/green] Claude Desktop configured: {claude_desktop_config}"
|
|
351
|
+
)
|
|
352
|
+
else:
|
|
353
|
+
console.print(
|
|
354
|
+
"[yellow]○[/yellow] Claude Desktop config exists but mcp-ticketer not found"
|
|
355
|
+
)
|
|
356
|
+
except Exception:
|
|
357
|
+
console.print(
|
|
358
|
+
"[yellow]○[/yellow] Claude Desktop config exists but could not be read"
|
|
359
|
+
)
|
|
360
|
+
else:
|
|
361
|
+
console.print("[yellow]○[/yellow] Claude Desktop not configured")
|
|
362
|
+
|
|
363
|
+
# Check Gemini configuration
|
|
364
|
+
gemini_project_config = Path.cwd() / ".gemini" / "settings.json"
|
|
365
|
+
gemini_user_config = Path.home() / ".gemini" / "settings.json"
|
|
366
|
+
if gemini_project_config.exists():
|
|
367
|
+
console.print(
|
|
368
|
+
f"\n[green]✓[/green] Gemini (project) configured: {gemini_project_config}"
|
|
369
|
+
)
|
|
370
|
+
elif gemini_user_config.exists():
|
|
371
|
+
console.print(
|
|
372
|
+
f"\n[green]✓[/green] Gemini (user) configured: {gemini_user_config}"
|
|
373
|
+
)
|
|
374
|
+
else:
|
|
375
|
+
console.print("\n[yellow]○[/yellow] Gemini not configured")
|
|
376
|
+
|
|
377
|
+
# Check Codex configuration
|
|
378
|
+
codex_config = Path.home() / ".codex" / "config.toml"
|
|
379
|
+
if codex_config.exists():
|
|
380
|
+
console.print(f"[green]✓[/green] Codex configured: {codex_config}")
|
|
381
|
+
else:
|
|
382
|
+
console.print("[yellow]○[/yellow] Codex not configured")
|
|
383
|
+
|
|
384
|
+
# Check Auggie configuration
|
|
385
|
+
auggie_config = Path.home() / ".augment" / "settings.json"
|
|
386
|
+
if auggie_config.exists():
|
|
387
|
+
console.print(f"[green]✓[/green] Auggie configured: {auggie_config}")
|
|
388
|
+
else:
|
|
389
|
+
console.print("[yellow]○[/yellow] Auggie not configured")
|
|
390
|
+
|
|
391
|
+
console.print(
|
|
392
|
+
"\n[dim]Run 'mcp-ticketer install <platform>' to configure a platform[/dim]"
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
@mcp_app.command(name="stop")
|
|
397
|
+
def mcp_stop() -> None:
|
|
398
|
+
"""Stop MCP server (placeholder - MCP runs on-demand via stdio).
|
|
399
|
+
|
|
400
|
+
Note: The MCP server runs on-demand when AI clients connect via stdio.
|
|
401
|
+
It doesn't run as a persistent background service, so there's nothing to stop.
|
|
402
|
+
This command is provided for consistency but has no effect.
|
|
403
|
+
|
|
404
|
+
Examples:
|
|
405
|
+
--------
|
|
406
|
+
mcp-ticketer mcp stop
|
|
407
|
+
|
|
408
|
+
"""
|
|
409
|
+
console.print(
|
|
410
|
+
"[yellow]ℹ[/yellow] MCP server runs on-demand via stdio (not as a background service)"
|
|
411
|
+
)
|
|
412
|
+
console.print("There is no persistent server process to stop.")
|
|
413
|
+
console.print(
|
|
414
|
+
"\n[dim]The server starts automatically when AI clients connect and stops when they disconnect.[/dim]"
|
|
415
|
+
)
|
|
@@ -22,14 +22,17 @@ def migrate_config_command(dry_run: bool = False) -> None:
|
|
|
22
22
|
"""
|
|
23
23
|
resolver = ConfigResolver()
|
|
24
24
|
|
|
25
|
+
# Get project config path (project-local only for security)
|
|
26
|
+
project_config_path = resolver.project_path / resolver.PROJECT_CONFIG_SUBPATH
|
|
27
|
+
|
|
25
28
|
# Check if old config exists
|
|
26
|
-
if not
|
|
29
|
+
if not project_config_path.exists():
|
|
27
30
|
console.print("[yellow]No configuration found to migrate[/yellow]")
|
|
28
31
|
return
|
|
29
32
|
|
|
30
33
|
# Load old config
|
|
31
34
|
try:
|
|
32
|
-
with open(
|
|
35
|
+
with open(project_config_path) as f:
|
|
33
36
|
old_config = json.load(f)
|
|
34
37
|
except Exception as e:
|
|
35
38
|
console.print(f"[red]Failed to load config: {e}[/red]")
|
|
@@ -71,22 +74,23 @@ def migrate_config_command(dry_run: bool = False) -> None:
|
|
|
71
74
|
return
|
|
72
75
|
|
|
73
76
|
# Backup old config
|
|
74
|
-
|
|
77
|
+
project_config_path = resolver.project_path / resolver.PROJECT_CONFIG_SUBPATH
|
|
78
|
+
backup_path = project_config_path.with_suffix(".json.bak")
|
|
75
79
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
76
|
-
backup_path =
|
|
80
|
+
backup_path = project_config_path.parent / f"config.{timestamp}.bak"
|
|
77
81
|
|
|
78
82
|
try:
|
|
79
|
-
shutil.copy(
|
|
83
|
+
shutil.copy(project_config_path, backup_path)
|
|
80
84
|
console.print(f"[green]✓[/green] Backed up old config to: {backup_path}")
|
|
81
85
|
except Exception as e:
|
|
82
86
|
console.print(f"[red]Failed to backup config: {e}[/red]")
|
|
83
87
|
return
|
|
84
88
|
|
|
85
|
-
# Save new config
|
|
89
|
+
# Save new config (to project-local config)
|
|
86
90
|
try:
|
|
87
|
-
resolver.
|
|
91
|
+
resolver.save_project_config(new_config)
|
|
88
92
|
console.print("[green]✓[/green] Migration complete!")
|
|
89
|
-
console.print(f"[dim]New config saved to: {
|
|
93
|
+
console.print(f"[dim]New config saved to: {project_config_path}[/dim]")
|
|
90
94
|
except Exception as e:
|
|
91
95
|
console.print(f"[red]Failed to save new config: {e}[/red]")
|
|
92
96
|
console.print(f"[yellow]Old config backed up at: {backup_path}[/yellow]")
|
|
@@ -24,7 +24,7 @@ jira_app = typer.Typer(
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
@jira_app.command("projects")
|
|
27
|
-
def jira_list_projects():
|
|
27
|
+
def jira_list_projects() -> None:
|
|
28
28
|
"""List JIRA projects (placeholder - not yet implemented)."""
|
|
29
29
|
from rich.console import Console
|
|
30
30
|
|
|
@@ -38,7 +38,7 @@ def jira_list_projects():
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
@jira_app.command("configure")
|
|
41
|
-
def jira_configure():
|
|
41
|
+
def jira_configure() -> None:
|
|
42
42
|
"""Configure JIRA adapter (placeholder - not yet implemented)."""
|
|
43
43
|
from rich.console import Console
|
|
44
44
|
|
|
@@ -55,7 +55,7 @@ github_app = typer.Typer(
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
@github_app.command("repos")
|
|
58
|
-
def github_list_repos():
|
|
58
|
+
def github_list_repos() -> None:
|
|
59
59
|
"""List GitHub repositories (placeholder - not yet implemented)."""
|
|
60
60
|
from rich.console import Console
|
|
61
61
|
|
|
@@ -69,7 +69,7 @@ def github_list_repos():
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
@github_app.command("configure")
|
|
72
|
-
def github_configure():
|
|
72
|
+
def github_configure() -> None:
|
|
73
73
|
"""Configure GitHub adapter (placeholder - not yet implemented)."""
|
|
74
74
|
from rich.console import Console
|
|
75
75
|
|
|
@@ -88,7 +88,7 @@ aitrackdown_app = typer.Typer(
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
@aitrackdown_app.command("info")
|
|
91
|
-
def aitrackdown_info():
|
|
91
|
+
def aitrackdown_info() -> None:
|
|
92
92
|
"""Show AITrackdown storage information (placeholder - not yet implemented)."""
|
|
93
93
|
from rich.console import Console
|
|
94
94
|
|
|
@@ -104,7 +104,7 @@ def aitrackdown_info():
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
@aitrackdown_app.command("configure")
|
|
107
|
-
def aitrackdown_configure():
|
|
107
|
+
def aitrackdown_configure() -> None:
|
|
108
108
|
"""Configure AITrackdown adapter (placeholder - not yet implemented)."""
|
|
109
109
|
from rich.console import Console
|
|
110
110
|
|