mcp-ticketer 0.4.11__py3-none-any.whl → 0.12.0__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/__version__.py +3 -3
- mcp_ticketer/adapters/__init__.py +2 -0
- mcp_ticketer/adapters/aitrackdown.py +9 -3
- mcp_ticketer/adapters/asana/__init__.py +15 -0
- mcp_ticketer/adapters/asana/adapter.py +1308 -0
- mcp_ticketer/adapters/asana/client.py +292 -0
- mcp_ticketer/adapters/asana/mappers.py +334 -0
- mcp_ticketer/adapters/asana/types.py +146 -0
- mcp_ticketer/adapters/github.py +313 -96
- mcp_ticketer/adapters/jira.py +251 -1
- mcp_ticketer/adapters/linear/adapter.py +524 -22
- mcp_ticketer/adapters/linear/client.py +61 -9
- mcp_ticketer/adapters/linear/mappers.py +9 -3
- mcp_ticketer/cache/memory.py +3 -3
- mcp_ticketer/cli/adapter_diagnostics.py +1 -1
- mcp_ticketer/cli/auggie_configure.py +1 -1
- mcp_ticketer/cli/codex_configure.py +80 -1
- mcp_ticketer/cli/configure.py +33 -43
- mcp_ticketer/cli/diagnostics.py +18 -16
- mcp_ticketer/cli/discover.py +288 -21
- mcp_ticketer/cli/gemini_configure.py +1 -1
- mcp_ticketer/cli/instruction_commands.py +429 -0
- mcp_ticketer/cli/linear_commands.py +99 -15
- mcp_ticketer/cli/main.py +1199 -227
- mcp_ticketer/cli/mcp_configure.py +1 -1
- mcp_ticketer/cli/migrate_config.py +12 -8
- mcp_ticketer/cli/platform_commands.py +6 -6
- mcp_ticketer/cli/platform_detection.py +412 -0
- mcp_ticketer/cli/queue_commands.py +15 -15
- mcp_ticketer/cli/simple_health.py +1 -1
- mcp_ticketer/cli/ticket_commands.py +14 -13
- mcp_ticketer/cli/update_checker.py +313 -0
- mcp_ticketer/cli/utils.py +45 -41
- mcp_ticketer/core/__init__.py +12 -0
- mcp_ticketer/core/adapter.py +4 -4
- mcp_ticketer/core/config.py +17 -10
- mcp_ticketer/core/env_discovery.py +33 -3
- mcp_ticketer/core/env_loader.py +7 -6
- mcp_ticketer/core/exceptions.py +3 -3
- mcp_ticketer/core/http_client.py +10 -10
- mcp_ticketer/core/instructions.py +405 -0
- mcp_ticketer/core/mappers.py +1 -1
- mcp_ticketer/core/models.py +1 -1
- mcp_ticketer/core/onepassword_secrets.py +379 -0
- mcp_ticketer/core/project_config.py +17 -1
- mcp_ticketer/core/registry.py +1 -1
- 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/main.py +82 -69
- mcp_ticketer/mcp/server/tools/__init__.py +9 -0
- mcp_ticketer/mcp/server/tools/attachment_tools.py +63 -16
- mcp_ticketer/mcp/server/tools/config_tools.py +381 -0
- mcp_ticketer/mcp/server/tools/hierarchy_tools.py +154 -5
- mcp_ticketer/mcp/server/tools/instruction_tools.py +293 -0
- mcp_ticketer/mcp/server/tools/ticket_tools.py +157 -4
- mcp_ticketer/mcp/server/tools/user_ticket_tools.py +382 -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 +14 -12
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-0.12.0.dist-info}/METADATA +106 -52
- mcp_ticketer-0.12.0.dist-info/RECORD +91 -0
- mcp_ticketer-0.4.11.dist-info/RECORD +0 -77
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-0.12.0.dist-info}/WHEEL +0 -0
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-0.12.0.dist-info}/entry_points.txt +0 -0
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-0.12.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_ticketer-0.4.11.dist-info → mcp_ticketer-0.12.0.dist-info}/top_level.txt +0 -0
mcp_ticketer/cli/discover.py
CHANGED
|
@@ -4,8 +4,15 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
import typer
|
|
6
6
|
from rich.console import Console
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.table import Table
|
|
7
9
|
|
|
8
10
|
from ..core.env_discovery import DiscoveredAdapter, EnvDiscovery
|
|
11
|
+
from ..core.onepassword_secrets import (
|
|
12
|
+
OnePasswordConfig,
|
|
13
|
+
OnePasswordSecretsLoader,
|
|
14
|
+
check_op_cli_status,
|
|
15
|
+
)
|
|
9
16
|
from ..core.project_config import (
|
|
10
17
|
AdapterConfig,
|
|
11
18
|
ConfigResolver,
|
|
@@ -181,7 +188,7 @@ def save(
|
|
|
181
188
|
console.print(
|
|
182
189
|
"[dim]Make sure your .env file contains adapter credentials[/dim]"
|
|
183
190
|
)
|
|
184
|
-
raise typer.Exit(1)
|
|
191
|
+
raise typer.Exit(1) from None
|
|
185
192
|
|
|
186
193
|
# Determine which adapter to save
|
|
187
194
|
if adapter:
|
|
@@ -191,13 +198,13 @@ def save(
|
|
|
191
198
|
console.print(
|
|
192
199
|
f"[dim]Available: {', '.join(a.adapter_type for a in result.adapters)}[/dim]"
|
|
193
200
|
)
|
|
194
|
-
raise typer.Exit(1)
|
|
201
|
+
raise typer.Exit(1) from None
|
|
195
202
|
else:
|
|
196
203
|
# Use recommended adapter
|
|
197
204
|
discovered_adapter = result.get_primary_adapter()
|
|
198
205
|
if not discovered_adapter:
|
|
199
206
|
console.print("[red]Could not determine recommended adapter[/red]")
|
|
200
|
-
raise typer.Exit(1)
|
|
207
|
+
raise typer.Exit(1) from None
|
|
201
208
|
|
|
202
209
|
console.print(
|
|
203
210
|
f"[bold]Using recommended adapter:[/bold] {discovered_adapter.adapter_type}"
|
|
@@ -216,7 +223,7 @@ def save(
|
|
|
216
223
|
console.print(
|
|
217
224
|
"[dim]Fix the configuration in your .env file and try again[/dim]"
|
|
218
225
|
)
|
|
219
|
-
raise typer.Exit(1)
|
|
226
|
+
raise typer.Exit(1) from None
|
|
220
227
|
|
|
221
228
|
if dry_run:
|
|
222
229
|
console.print("\n[yellow]Dry run - no changes made[/yellow]")
|
|
@@ -239,14 +246,15 @@ def save(
|
|
|
239
246
|
# Add to config
|
|
240
247
|
config.adapters[discovered_adapter.adapter_type] = adapter_config
|
|
241
248
|
|
|
242
|
-
# Save
|
|
249
|
+
# Save (always to project config for security)
|
|
243
250
|
try:
|
|
251
|
+
resolver.save_project_config(config, proj_path)
|
|
252
|
+
config_location = proj_path / resolver.PROJECT_CONFIG_SUBPATH
|
|
253
|
+
|
|
244
254
|
if global_config:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
resolver.save_project_config(config, proj_path)
|
|
249
|
-
config_location = proj_path / resolver.PROJECT_CONFIG_SUBPATH
|
|
255
|
+
console.print(
|
|
256
|
+
"[yellow]Note: Global config deprecated for security. Saved to project config instead.[/yellow]"
|
|
257
|
+
)
|
|
250
258
|
|
|
251
259
|
console.print(f"\n[green]✅ Configuration saved to:[/green] {config_location}")
|
|
252
260
|
console.print(
|
|
@@ -255,7 +263,7 @@ def save(
|
|
|
255
263
|
|
|
256
264
|
except Exception as e:
|
|
257
265
|
console.print(f"\n[red]Failed to save configuration:[/red] {e}")
|
|
258
|
-
raise typer.Exit(1)
|
|
266
|
+
raise typer.Exit(1) from None
|
|
259
267
|
|
|
260
268
|
|
|
261
269
|
@app.command()
|
|
@@ -283,7 +291,7 @@ def interactive(
|
|
|
283
291
|
console.print(f" ✅ {env_file}")
|
|
284
292
|
else:
|
|
285
293
|
console.print("[red]No .env files found[/red]")
|
|
286
|
-
raise typer.Exit(1)
|
|
294
|
+
raise typer.Exit(1) from None
|
|
287
295
|
|
|
288
296
|
# Show discovered adapters
|
|
289
297
|
if not result.adapters:
|
|
@@ -291,7 +299,7 @@ def interactive(
|
|
|
291
299
|
console.print(
|
|
292
300
|
"[dim]Make sure your .env file contains adapter credentials[/dim]"
|
|
293
301
|
)
|
|
294
|
-
raise typer.Exit(1)
|
|
302
|
+
raise typer.Exit(1) from None
|
|
295
303
|
|
|
296
304
|
console.print("\n[bold]Detected adapter configurations:[/bold]")
|
|
297
305
|
for i, adapter in enumerate(result.adapters, 1):
|
|
@@ -331,7 +339,7 @@ def interactive(
|
|
|
331
339
|
if choice in [1, 2]:
|
|
332
340
|
if not primary:
|
|
333
341
|
console.print("[red]No recommended adapter found[/red]")
|
|
334
|
-
raise typer.Exit(1)
|
|
342
|
+
raise typer.Exit(1) from None
|
|
335
343
|
adapters_to_save = [primary]
|
|
336
344
|
default_adapter = primary.adapter_type
|
|
337
345
|
elif choice == 3:
|
|
@@ -347,7 +355,7 @@ def interactive(
|
|
|
347
355
|
default_adapter = selected.adapter_type
|
|
348
356
|
else:
|
|
349
357
|
console.print("[red]Invalid choice[/red]")
|
|
350
|
-
raise typer.Exit(1)
|
|
358
|
+
raise typer.Exit(1) from None
|
|
351
359
|
else: # choice == 4
|
|
352
360
|
adapters_to_save = result.adapters
|
|
353
361
|
default_adapter = (
|
|
@@ -388,22 +396,281 @@ def interactive(
|
|
|
388
396
|
|
|
389
397
|
console.print(f" ✅ Added {discovered_adapter.adapter_type}")
|
|
390
398
|
|
|
391
|
-
# Save
|
|
399
|
+
# Save (always to project config for security)
|
|
392
400
|
try:
|
|
401
|
+
resolver.save_project_config(config, proj_path)
|
|
402
|
+
config_location = proj_path / resolver.PROJECT_CONFIG_SUBPATH
|
|
403
|
+
|
|
393
404
|
if save_global:
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
resolver.save_project_config(config, proj_path)
|
|
398
|
-
config_location = proj_path / resolver.PROJECT_CONFIG_SUBPATH
|
|
405
|
+
console.print(
|
|
406
|
+
"[yellow]Note: Global config deprecated for security. Saved to project config instead.[/yellow]"
|
|
407
|
+
)
|
|
399
408
|
|
|
400
409
|
console.print(f"\n[green]✅ Configuration saved to:[/green] {config_location}")
|
|
401
410
|
console.print(f"[green]✅ Default adapter:[/green] {config.default_adapter}")
|
|
402
411
|
|
|
403
412
|
except Exception as e:
|
|
404
413
|
console.print(f"\n[red]Failed to save configuration:[/red] {e}")
|
|
414
|
+
raise typer.Exit(1) from None
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
@app.command(name="1password-status")
|
|
418
|
+
def onepassword_status() -> None:
|
|
419
|
+
"""Check 1Password CLI installation and authentication status."""
|
|
420
|
+
console.print(
|
|
421
|
+
Panel.fit(
|
|
422
|
+
"[bold cyan]1Password CLI Status[/bold cyan]\n"
|
|
423
|
+
"Checking 1Password integration...",
|
|
424
|
+
border_style="cyan",
|
|
425
|
+
)
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
status = check_op_cli_status()
|
|
429
|
+
|
|
430
|
+
# Create status table
|
|
431
|
+
table = Table(title="1Password CLI Status")
|
|
432
|
+
table.add_column("Component", style="cyan")
|
|
433
|
+
table.add_column("Status", style="white")
|
|
434
|
+
|
|
435
|
+
# CLI installed
|
|
436
|
+
if status["installed"]:
|
|
437
|
+
table.add_row(
|
|
438
|
+
"CLI Installed", f"[green]✓ Yes[/green] (version {status['version']})"
|
|
439
|
+
)
|
|
440
|
+
else:
|
|
441
|
+
table.add_row("CLI Installed", "[red]✗ No[/red]")
|
|
442
|
+
console.print(table)
|
|
443
|
+
console.print(
|
|
444
|
+
"\n[yellow]Install 1Password CLI:[/yellow]\n"
|
|
445
|
+
" macOS: brew install 1password-cli\n"
|
|
446
|
+
" Linux: See https://developer.1password.com/docs/cli/get-started/\n"
|
|
447
|
+
" Windows: See https://developer.1password.com/docs/cli/get-started/"
|
|
448
|
+
)
|
|
449
|
+
return
|
|
450
|
+
|
|
451
|
+
# Authentication
|
|
452
|
+
if status["authenticated"]:
|
|
453
|
+
table.add_row("Authentication", "[green]✓ Signed in[/green]")
|
|
454
|
+
|
|
455
|
+
# Show accounts
|
|
456
|
+
if status["accounts"]:
|
|
457
|
+
for account in status["accounts"]:
|
|
458
|
+
account_url = account.get("url", "N/A")
|
|
459
|
+
account_email = account.get("email", "N/A")
|
|
460
|
+
table.add_row(" Account", f"{account_email} ({account_url})")
|
|
461
|
+
else:
|
|
462
|
+
table.add_row("Authentication", "[yellow]⚠ Not signed in[/yellow]")
|
|
463
|
+
|
|
464
|
+
console.print(table)
|
|
465
|
+
|
|
466
|
+
if not status["authenticated"]:
|
|
467
|
+
console.print("\n[yellow]Sign in to 1Password:[/yellow]\n" " Run: op signin\n")
|
|
468
|
+
else:
|
|
469
|
+
console.print(
|
|
470
|
+
"\n[green]✓ 1Password CLI is ready to use![/green]\n\n"
|
|
471
|
+
"You can now use .env files with op:// secret references.\n"
|
|
472
|
+
"Run 'mcp-ticketer discover 1password-template' to create template files."
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
@app.command(name="1password-template")
|
|
477
|
+
def onepassword_template(
|
|
478
|
+
adapter: str = typer.Argument(
|
|
479
|
+
...,
|
|
480
|
+
help="Adapter type (linear, github, jira, aitrackdown)",
|
|
481
|
+
),
|
|
482
|
+
vault: str = typer.Option(
|
|
483
|
+
"Development",
|
|
484
|
+
"--vault",
|
|
485
|
+
"-v",
|
|
486
|
+
help="1Password vault name for secret references",
|
|
487
|
+
),
|
|
488
|
+
item: str | None = typer.Option(
|
|
489
|
+
None,
|
|
490
|
+
"--item",
|
|
491
|
+
"-i",
|
|
492
|
+
help="1Password item name (defaults to adapter name)",
|
|
493
|
+
),
|
|
494
|
+
output: Path | None = typer.Option(
|
|
495
|
+
None,
|
|
496
|
+
"--output",
|
|
497
|
+
"-o",
|
|
498
|
+
help="Output file path (defaults to .env.1password)",
|
|
499
|
+
),
|
|
500
|
+
) -> None:
|
|
501
|
+
"""Create a .env template file with 1Password secret references.
|
|
502
|
+
|
|
503
|
+
This creates a template file that uses op:// secret references,
|
|
504
|
+
which can be used with: op run --env-file=.env.1password -- <command>
|
|
505
|
+
|
|
506
|
+
Examples:
|
|
507
|
+
# Create Linear template
|
|
508
|
+
mcp-ticketer discover 1password-template linear
|
|
509
|
+
|
|
510
|
+
# Create GitHub template with custom vault
|
|
511
|
+
mcp-ticketer discover 1password-template github --vault=Production
|
|
512
|
+
|
|
513
|
+
# Create template with custom item name
|
|
514
|
+
mcp-ticketer discover 1password-template jira --item="JIRA API Keys"
|
|
515
|
+
|
|
516
|
+
"""
|
|
517
|
+
# Check if op CLI is available
|
|
518
|
+
status = check_op_cli_status()
|
|
519
|
+
if not status["installed"]:
|
|
520
|
+
console.print(
|
|
521
|
+
"[red]1Password CLI not installed.[/red]\n\n"
|
|
522
|
+
"Install it first:\n"
|
|
523
|
+
" macOS: brew install 1password-cli\n"
|
|
524
|
+
" Other: https://developer.1password.com/docs/cli/get-started/"
|
|
525
|
+
)
|
|
405
526
|
raise typer.Exit(1)
|
|
406
527
|
|
|
528
|
+
# Set default output path
|
|
529
|
+
if output is None:
|
|
530
|
+
output = Path(f".env.1password.{adapter.lower()}")
|
|
531
|
+
|
|
532
|
+
# Create loader and generate template
|
|
533
|
+
loader = OnePasswordSecretsLoader(OnePasswordConfig())
|
|
534
|
+
loader.create_template_file(output, adapter, vault, item)
|
|
535
|
+
|
|
536
|
+
console.print(
|
|
537
|
+
Panel.fit(
|
|
538
|
+
f"[bold green]✓ Template created![/bold green]\n\n"
|
|
539
|
+
f"File: {output}\n"
|
|
540
|
+
f"Vault: {vault}\n"
|
|
541
|
+
f"Item: {item or adapter.upper()}\n\n"
|
|
542
|
+
f"[bold]Next steps:[/bold]\n"
|
|
543
|
+
f"1. Create item '{item or adapter.upper()}' in 1Password vault '{vault}'\n"
|
|
544
|
+
f"2. Add the required fields to the item\n"
|
|
545
|
+
f"3. Test with: op run --env-file={output} -- mcp-ticketer discover show\n"
|
|
546
|
+
f"4. Save config: op run --env-file={output} -- mcp-ticketer discover save",
|
|
547
|
+
border_style="green",
|
|
548
|
+
)
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
# Show template contents
|
|
552
|
+
console.print("\n[bold]Template contents:[/bold]\n")
|
|
553
|
+
console.print(Panel(output.read_text(), border_style="dim"))
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
@app.command(name="1password-test")
|
|
557
|
+
def onepassword_test(
|
|
558
|
+
env_file: Path = typer.Option(
|
|
559
|
+
".env.1password",
|
|
560
|
+
"--file",
|
|
561
|
+
"-f",
|
|
562
|
+
help="Path to .env file with op:// references",
|
|
563
|
+
),
|
|
564
|
+
) -> None:
|
|
565
|
+
"""Test 1Password secret resolution from .env file.
|
|
566
|
+
|
|
567
|
+
This command loads secrets from the specified .env file and
|
|
568
|
+
displays the resolved values (with sensitive data masked).
|
|
569
|
+
|
|
570
|
+
Example:
|
|
571
|
+
mcp-ticketer discover 1password-test --file=.env.1password.linear
|
|
572
|
+
|
|
573
|
+
"""
|
|
574
|
+
# Check if file exists
|
|
575
|
+
if not env_file.exists():
|
|
576
|
+
console.print(f"[red]File not found:[/red] {env_file}")
|
|
577
|
+
raise typer.Exit(1)
|
|
578
|
+
|
|
579
|
+
# Check if op CLI is available and authenticated
|
|
580
|
+
status = check_op_cli_status()
|
|
581
|
+
if not status["installed"]:
|
|
582
|
+
console.print("[red]1Password CLI not installed.[/red]")
|
|
583
|
+
raise typer.Exit(1)
|
|
584
|
+
|
|
585
|
+
if not status["authenticated"]:
|
|
586
|
+
console.print(
|
|
587
|
+
"[red]1Password CLI not authenticated.[/red]\n\n" "Run: op signin"
|
|
588
|
+
)
|
|
589
|
+
raise typer.Exit(1)
|
|
590
|
+
|
|
591
|
+
console.print(
|
|
592
|
+
Panel.fit(
|
|
593
|
+
f"[bold cyan]Testing 1Password Secret Resolution[/bold cyan]\n"
|
|
594
|
+
f"File: {env_file}",
|
|
595
|
+
border_style="cyan",
|
|
596
|
+
)
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
# Load secrets
|
|
600
|
+
loader = OnePasswordSecretsLoader(OnePasswordConfig())
|
|
601
|
+
|
|
602
|
+
try:
|
|
603
|
+
secrets = loader.load_secrets_from_env_file(env_file)
|
|
604
|
+
|
|
605
|
+
# Display resolved secrets
|
|
606
|
+
table = Table(title="Resolved Secrets")
|
|
607
|
+
table.add_column("Variable", style="cyan")
|
|
608
|
+
table.add_column("Value", style="green")
|
|
609
|
+
|
|
610
|
+
for key, value in secrets.items():
|
|
611
|
+
# Mask sensitive values
|
|
612
|
+
display_value = _mask_sensitive(value, key)
|
|
613
|
+
table.add_row(key, display_value)
|
|
614
|
+
|
|
615
|
+
console.print(table)
|
|
616
|
+
|
|
617
|
+
console.print(
|
|
618
|
+
f"\n[green]✓ Successfully resolved {len(secrets)} secrets![/green]"
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
# Test discovery with these secrets
|
|
622
|
+
console.print("\n[bold]Testing configuration discovery...[/bold]")
|
|
623
|
+
EnvDiscovery(enable_1password=False) # Already resolved
|
|
624
|
+
|
|
625
|
+
# Temporarily write resolved secrets to test discovery
|
|
626
|
+
import tempfile
|
|
627
|
+
|
|
628
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as tmp:
|
|
629
|
+
for key, value in secrets.items():
|
|
630
|
+
tmp.write(f"{key}={value}\n")
|
|
631
|
+
tmp_path = Path(tmp.name)
|
|
632
|
+
|
|
633
|
+
try:
|
|
634
|
+
# Mock the env file loading by directly providing secrets
|
|
635
|
+
from ..core.env_discovery import DiscoveryResult
|
|
636
|
+
|
|
637
|
+
DiscoveryResult()
|
|
638
|
+
|
|
639
|
+
# Try to detect adapters from the resolved secrets
|
|
640
|
+
from ..core.env_discovery import EnvDiscovery as ED
|
|
641
|
+
|
|
642
|
+
ed = ED(enable_1password=False)
|
|
643
|
+
ed.project_path = Path.cwd()
|
|
644
|
+
|
|
645
|
+
# Manually detect from secrets dict
|
|
646
|
+
linear_adapter = ed._detect_linear(secrets, str(env_file))
|
|
647
|
+
if linear_adapter:
|
|
648
|
+
console.print("\n[green]✓ Detected Linear configuration[/green]")
|
|
649
|
+
_display_discovered_adapter(linear_adapter, ed)
|
|
650
|
+
|
|
651
|
+
github_adapter = ed._detect_github(secrets, str(env_file))
|
|
652
|
+
if github_adapter:
|
|
653
|
+
console.print("\n[green]✓ Detected GitHub configuration[/green]")
|
|
654
|
+
_display_discovered_adapter(github_adapter, ed)
|
|
655
|
+
|
|
656
|
+
jira_adapter = ed._detect_jira(secrets, str(env_file))
|
|
657
|
+
if jira_adapter:
|
|
658
|
+
console.print("\n[green]✓ Detected JIRA configuration[/green]")
|
|
659
|
+
_display_discovered_adapter(jira_adapter, ed)
|
|
660
|
+
finally:
|
|
661
|
+
tmp_path.unlink()
|
|
662
|
+
|
|
663
|
+
except Exception as e:
|
|
664
|
+
console.print(f"\n[red]Failed to resolve secrets:[/red] {e}")
|
|
665
|
+
console.print(
|
|
666
|
+
"\n[yellow]Troubleshooting:[/yellow]\n"
|
|
667
|
+
"1. Check that the item exists in 1Password\n"
|
|
668
|
+
"2. Verify the vault name is correct\n"
|
|
669
|
+
"3. Ensure all field names match\n"
|
|
670
|
+
f"4. Run: op inject --in-file={env_file} (to see detailed errors)"
|
|
671
|
+
)
|
|
672
|
+
raise typer.Exit(1) from None
|
|
673
|
+
|
|
407
674
|
|
|
408
675
|
if __name__ == "__main__":
|
|
409
676
|
app()
|
|
@@ -246,7 +246,7 @@ def configure_gemini_mcp(
|
|
|
246
246
|
"Could not find mcp-ticketer Python executable. "
|
|
247
247
|
"Please ensure mcp-ticketer is installed.\n"
|
|
248
248
|
"Install with: pip install mcp-ticketer or pipx install mcp-ticketer"
|
|
249
|
-
)
|
|
249
|
+
) from e
|
|
250
250
|
|
|
251
251
|
# Step 2: Load project configuration
|
|
252
252
|
console.print("\n[cyan]📖 Reading project configuration...[/cyan]")
|