golf-mcp 0.1.20__py3-none-any.whl → 0.2.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 golf-mcp might be problematic. Click here for more details.
- golf/__init__.py +9 -1
- golf/_endpoints.py +6 -0
- golf/_endpoints_fallback.py +10 -0
- golf/auth/__init__.py +188 -84
- golf/auth/api_key.py +6 -14
- golf/auth/factory.py +333 -0
- golf/auth/helpers.py +12 -42
- golf/auth/providers.py +396 -0
- golf/auth/registry.py +256 -0
- golf/cli/branding.py +192 -0
- golf/cli/main.py +28 -69
- golf/commands/__init__.py +2 -0
- golf/commands/build.py +4 -7
- golf/commands/init.py +30 -53
- golf/commands/run.py +50 -20
- golf/core/builder.py +355 -414
- golf/core/builder_auth.py +63 -144
- golf/core/builder_telemetry.py +26 -3
- golf/core/config.py +38 -59
- golf/core/parser.py +132 -139
- golf/core/platform.py +12 -10
- golf/core/telemetry.py +11 -19
- golf/core/transformer.py +38 -15
- golf/examples/__pycache__/__init__.cpython-311.pyc +0 -0
- golf/examples/basic/.coverage +0 -0
- golf/examples/basic/.env.example +8 -4
- golf/examples/basic/README.md +117 -45
- golf/examples/basic/__pycache__/auth.cpython-311.pyc +0 -0
- golf/examples/basic/auth.py +76 -0
- golf/examples/basic/golf.json +2 -5
- golf/examples/basic/htmlcov/.gitignore +2 -0
- golf/examples/basic/htmlcov/class_index.html +547 -0
- golf/examples/basic/htmlcov/coverage_html_cb_6fb7b396.js +733 -0
- golf/examples/basic/htmlcov/favicon_32_cb_58284776.png +0 -0
- golf/examples/basic/htmlcov/function_index.html +2091 -0
- golf/examples/basic/htmlcov/index.html +349 -0
- golf/examples/basic/htmlcov/keybd_closed_cb_ce680311.png +0 -0
- golf/examples/basic/htmlcov/status.json +1 -0
- golf/examples/basic/htmlcov/style_cb_8e611ae1.css +337 -0
- golf/examples/basic/htmlcov/z_1c9a91c0e91c8496___init___py.html +323 -0
- golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_api_key_py.html +170 -0
- golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_factory_py.html +430 -0
- golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_helpers_py.html +288 -0
- golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_providers_py.html +493 -0
- golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_registry_py.html +353 -0
- golf/examples/basic/htmlcov/z_3ec3b3f490dc0950___init___py.html +120 -0
- golf/examples/basic/htmlcov/z_3ec3b3f490dc0950_instrumentation_py.html +1535 -0
- golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db___init___py.html +98 -0
- golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_branding_py.html +289 -0
- golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_main_py.html +476 -0
- golf/examples/basic/htmlcov/z_5a6c4e6bcc86fb2f___init___py.html +97 -0
- golf/examples/basic/htmlcov/z_6cadab9ec0df475d___init___py.html +102 -0
- golf/examples/basic/htmlcov/z_6cadab9ec0df475d_build_py.html +178 -0
- golf/examples/basic/htmlcov/z_6cadab9ec0df475d_init_py.html +387 -0
- golf/examples/basic/htmlcov/z_6cadab9ec0df475d_run_py.html +222 -0
- golf/examples/basic/htmlcov/z_6fcdee0582ba84e4___init___py.html +106 -0
- golf/examples/basic/htmlcov/z_6fcdee0582ba84e4__endpoints_fallback_py.html +107 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217___init___py.html +98 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_auth_py.html +306 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_metrics_py.html +329 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_py.html +1471 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_telemetry_py.html +186 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_config_py.html +315 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_parser_py.html +1149 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_platform_py.html +279 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_telemetry_py.html +589 -0
- golf/examples/basic/htmlcov/z_7ba499ed22986217_transformer_py.html +286 -0
- golf/examples/basic/htmlcov/z_7d7da37693a43688___init___py.html +107 -0
- golf/examples/basic/htmlcov/z_7d7da37693a43688_collector_py.html +417 -0
- golf/examples/basic/htmlcov/z_7d7da37693a43688_registry_py.html +109 -0
- golf/examples/basic/htmlcov/z_abe733142b40ad4e___init___py.html +109 -0
- golf/examples/basic/htmlcov/z_abe733142b40ad4e_context_py.html +150 -0
- golf/examples/basic/htmlcov/z_abe733142b40ad4e_elicitation_py.html +267 -0
- golf/examples/basic/htmlcov/z_abe733142b40ad4e_sampling_py.html +318 -0
- golf/examples/basic/prompts/__pycache__/welcome.cpython-311.pyc +0 -0
- golf/examples/basic/prompts/welcome.py +3 -5
- golf/examples/basic/resources/__pycache__/current_time.cpython-311.pyc +0 -0
- golf/examples/basic/resources/__pycache__/info.cpython-311.pyc +0 -0
- golf/examples/basic/resources/current_time.py +5 -13
- golf/examples/basic/resources/weather/__pycache__/common.cpython-311.pyc +0 -0
- golf/examples/basic/resources/weather/__pycache__/current.cpython-311.pyc +0 -0
- golf/examples/basic/resources/weather/__pycache__/forecast.cpython-311.pyc +0 -0
- golf/examples/basic/resources/weather/city.py +46 -0
- golf/examples/basic/resources/weather/common.py +4 -11
- golf/examples/basic/resources/weather/current.py +5 -5
- golf/examples/basic/resources/weather/forecast.py +5 -5
- golf/examples/basic/tools/__pycache__/calculator.cpython-311.pyc +0 -0
- golf/examples/basic/tools/calculator.py +94 -0
- golf/examples/basic/tools/say/__pycache__/hello.cpython-311.pyc +0 -0
- golf/examples/basic/tools/say/hello.py +65 -0
- golf/metrics/collector.py +100 -19
- golf/telemetry/__init__.py +4 -0
- golf/telemetry/instrumentation.py +484 -178
- golf/utilities/__init__.py +12 -0
- golf/utilities/context.py +53 -0
- golf/utilities/elicitation.py +170 -0
- golf/utilities/sampling.py +221 -0
- {golf_mcp-0.1.20.dist-info → golf_mcp-0.2.0.dist-info}/METADATA +51 -104
- golf_mcp-0.2.0.dist-info/RECORD +110 -0
- golf/auth/oauth.py +0 -861
- golf/auth/provider.py +0 -115
- golf/examples/api_key/.env +0 -2
- golf/examples/api_key/.env.example +0 -1
- golf/examples/api_key/README.md +0 -84
- golf/examples/api_key/golf.json +0 -8
- golf/examples/api_key/pre_build.py +0 -11
- golf/examples/api_key/tools/issues/create.py +0 -93
- golf/examples/api_key/tools/issues/list.py +0 -92
- golf/examples/api_key/tools/repos/list.py +0 -111
- golf/examples/api_key/tools/search/code.py +0 -106
- golf/examples/api_key/tools/users/get.py +0 -82
- golf/examples/basic/.env +0 -5
- golf/examples/basic/pre_build.py +0 -28
- golf/examples/basic/tools/github_user.py +0 -65
- golf/examples/basic/tools/hello.py +0 -34
- golf/examples/basic/tools/payments/charge.py +0 -70
- golf/examples/basic/tools/payments/common.py +0 -36
- golf/examples/basic/tools/payments/refund.py +0 -61
- golf_mcp-0.1.20.dist-info/RECORD +0 -60
- {golf_mcp-0.1.20.dist-info → golf_mcp-0.2.0.dist-info}/WHEEL +0 -0
- {golf_mcp-0.1.20.dist-info → golf_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.1.20.dist-info → golf_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.1.20.dist-info → golf_mcp-0.2.0.dist-info}/top_level.txt +0 -0
golf/cli/branding.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Golf CLI branding and visual utilities."""
|
|
2
|
+
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
from rich.text import Text
|
|
6
|
+
from rich.align import Align
|
|
7
|
+
|
|
8
|
+
# Golf brand colors (official brand colors)
|
|
9
|
+
GOLF_BLUE = "#2969FD" # Primary blue from brand: rgb(41, 105, 253)
|
|
10
|
+
GOLF_ORANGE = "#F97728" # Secondary orange from brand: rgb(249, 119, 40)
|
|
11
|
+
GOLF_GREEN = "#10B981" # Success green
|
|
12
|
+
GOLF_WHITE = "#FFFFFF"
|
|
13
|
+
|
|
14
|
+
# Simple GolfMCP text logo
|
|
15
|
+
GOLF_LOGO = """
|
|
16
|
+
██████╗ ██████╗ ██╗ ███████╗███╗ ███╗ ██████╗██████╗
|
|
17
|
+
██╔════╝ ██╔═══██╗██║ ██╔════╝████╗ ████║██╔════╝██╔══██╗
|
|
18
|
+
██║ ███╗██║ ██║██║ █████╗ ██╔████╔██║██║ ██████╔╝
|
|
19
|
+
██║ ██║██║ ██║██║ ██╔══╝ ██║╚██╔╝██║██║ ██╔═══╝
|
|
20
|
+
╚██████╔╝╚██████╔╝███████╗██║ ██║ ╚═╝ ██║╚██████╗██║
|
|
21
|
+
╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# Simplified version for smaller spaces
|
|
25
|
+
GOLF_LOGO_SMALL = "Golf"
|
|
26
|
+
|
|
27
|
+
# Status icons with consistent styling
|
|
28
|
+
STATUS_ICONS = {
|
|
29
|
+
"success": "✓",
|
|
30
|
+
"error": "✗",
|
|
31
|
+
"warning": "⚠",
|
|
32
|
+
"info": "ℹ",
|
|
33
|
+
"building": "🔨",
|
|
34
|
+
"generating": "⚙️",
|
|
35
|
+
"packaging": "📦",
|
|
36
|
+
"platform": "⛳",
|
|
37
|
+
"server": "🚀",
|
|
38
|
+
"loading": "⭕",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def create_welcome_banner(version: str, console: Console) -> None:
|
|
43
|
+
"""Create the main Golf welcome banner."""
|
|
44
|
+
# Create the logo with Golf in blue and MCP in orange
|
|
45
|
+
logo_lines = GOLF_LOGO.strip().split("\n")
|
|
46
|
+
logo_content = Text()
|
|
47
|
+
|
|
48
|
+
for line in logo_lines:
|
|
49
|
+
if line.strip(): # Only process non-empty lines
|
|
50
|
+
# Find where "MCP" starts (roughly at position 32 in the ASCII art)
|
|
51
|
+
golf_part = line[:32] # First part is "Golf"
|
|
52
|
+
mcp_part = line[32:] # Last part is "MCP"
|
|
53
|
+
|
|
54
|
+
logo_content.append(golf_part, style=f"bold {GOLF_BLUE}")
|
|
55
|
+
logo_content.append(mcp_part, style=f"bold {GOLF_ORANGE}")
|
|
56
|
+
logo_content.append("\n")
|
|
57
|
+
|
|
58
|
+
# Create version line
|
|
59
|
+
version_text = Text()
|
|
60
|
+
version_text.append("🚀 ", style=f"bold {GOLF_ORANGE}")
|
|
61
|
+
version_text.append(f"Golf v{version}", style=f"bold {GOLF_BLUE}")
|
|
62
|
+
version_text.append(" 🚀", style=f"bold {GOLF_ORANGE}")
|
|
63
|
+
|
|
64
|
+
# Create tagline
|
|
65
|
+
tagline_text = Text("✨ Easiest way to build production-ready MCP servers ✨", style="bold white")
|
|
66
|
+
|
|
67
|
+
# Create the full content using a renderable group approach
|
|
68
|
+
from rich.console import Group
|
|
69
|
+
|
|
70
|
+
content_group = Group(
|
|
71
|
+
Align.center(logo_content),
|
|
72
|
+
"", # Empty line for spacing
|
|
73
|
+
Align.center(version_text),
|
|
74
|
+
Align.center(tagline_text),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
panel = Panel(
|
|
78
|
+
content_group,
|
|
79
|
+
border_style=GOLF_BLUE,
|
|
80
|
+
padding=(1, 2),
|
|
81
|
+
title="[bold]🏌️ Welcome to Golf 🏌️[/bold]",
|
|
82
|
+
title_align="center",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
console.print(panel)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def create_command_header(title: str, subtitle: str = "", console: Console | None = None) -> None:
|
|
89
|
+
"""Create a styled command header."""
|
|
90
|
+
if console is None:
|
|
91
|
+
console = Console()
|
|
92
|
+
|
|
93
|
+
header = Text()
|
|
94
|
+
header.append("🏌️ ", style=f"bold {GOLF_ORANGE}")
|
|
95
|
+
header.append(title, style=f"bold {GOLF_BLUE}")
|
|
96
|
+
|
|
97
|
+
if subtitle:
|
|
98
|
+
header.append(f" → {subtitle}", style=f"bold {GOLF_ORANGE}")
|
|
99
|
+
|
|
100
|
+
# Create a stylish panel for the header
|
|
101
|
+
panel = Panel(
|
|
102
|
+
Align.center(header),
|
|
103
|
+
border_style=GOLF_BLUE,
|
|
104
|
+
padding=(0, 2),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
console.print(panel)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def create_success_message(message: str, console: Console | None = None) -> None:
|
|
111
|
+
"""Create a styled success message."""
|
|
112
|
+
if console is None:
|
|
113
|
+
console = Console()
|
|
114
|
+
|
|
115
|
+
success_content = Text()
|
|
116
|
+
success_content.append("🎉 ", style=f"bold {GOLF_ORANGE}")
|
|
117
|
+
success_content.append(f"{STATUS_ICONS['success']} {message}", style=f"bold {GOLF_GREEN}")
|
|
118
|
+
success_content.append(" 🎉", style=f"bold {GOLF_ORANGE}")
|
|
119
|
+
|
|
120
|
+
success_panel = Panel(
|
|
121
|
+
Align.center(success_content),
|
|
122
|
+
border_style=GOLF_GREEN,
|
|
123
|
+
padding=(0, 2),
|
|
124
|
+
title="[bold green]SUCCESS[/bold green]",
|
|
125
|
+
title_align="center",
|
|
126
|
+
)
|
|
127
|
+
console.print(success_panel)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def create_info_panel(title: str, content: str, console: Console | None = None) -> None:
|
|
131
|
+
"""Create a styled info panel."""
|
|
132
|
+
if console is None:
|
|
133
|
+
console = Console()
|
|
134
|
+
|
|
135
|
+
# Add some visual flair to the content
|
|
136
|
+
styled_content = Text()
|
|
137
|
+
for line in content.split("\n"):
|
|
138
|
+
if line.strip():
|
|
139
|
+
styled_content.append("▶ ", style=f"bold {GOLF_ORANGE}")
|
|
140
|
+
styled_content.append(line, style="bold white")
|
|
141
|
+
styled_content.append("\n")
|
|
142
|
+
|
|
143
|
+
panel = Panel(
|
|
144
|
+
styled_content,
|
|
145
|
+
title=f"[bold {GOLF_BLUE}]🔧 {title} 🔧[/bold {GOLF_BLUE}]",
|
|
146
|
+
border_style=GOLF_BLUE,
|
|
147
|
+
padding=(1, 2),
|
|
148
|
+
)
|
|
149
|
+
console.print(panel)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_status_text(status: str, message: str, style: str = "") -> Text:
|
|
153
|
+
"""Get formatted status text with icon."""
|
|
154
|
+
icon = STATUS_ICONS.get(status, "•")
|
|
155
|
+
text = Text()
|
|
156
|
+
|
|
157
|
+
if status == "success":
|
|
158
|
+
text.append("🎉 ", style=f"bold {GOLF_ORANGE}")
|
|
159
|
+
text.append(f"{icon} {message}", style=f"bold {GOLF_GREEN}")
|
|
160
|
+
elif status == "error":
|
|
161
|
+
text.append("💥 ", style=f"bold {GOLF_ORANGE}")
|
|
162
|
+
text.append(f"{icon} {message}", style="bold red")
|
|
163
|
+
elif status == "warning":
|
|
164
|
+
text.append("⚡ ", style=f"bold {GOLF_ORANGE}")
|
|
165
|
+
text.append(f"{icon} {message}", style=f"bold {GOLF_ORANGE}")
|
|
166
|
+
elif status in ["building", "generating", "packaging", "platform"]:
|
|
167
|
+
text.append("🔥 ", style=f"bold {GOLF_ORANGE}")
|
|
168
|
+
text.append(f"{icon} {message}", style=f"bold {GOLF_BLUE}")
|
|
169
|
+
else:
|
|
170
|
+
text.append("💡 ", style=f"bold {GOLF_ORANGE}")
|
|
171
|
+
text.append(f"{icon} {message}", style=f"bold {GOLF_BLUE}")
|
|
172
|
+
|
|
173
|
+
return text
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def create_build_header(project_name: str, environment: str, console: Console) -> None:
|
|
177
|
+
"""Create a styled build process header."""
|
|
178
|
+
title = Text()
|
|
179
|
+
title.append("🔨 Building ", style=f"bold {GOLF_ORANGE}")
|
|
180
|
+
title.append(project_name, style=f"bold {GOLF_BLUE}")
|
|
181
|
+
title.append(f" ({environment} environment)", style=f"bold {GOLF_GREEN}")
|
|
182
|
+
|
|
183
|
+
# Create a flashy build panel
|
|
184
|
+
panel = Panel(
|
|
185
|
+
Align.center(title),
|
|
186
|
+
border_style=GOLF_ORANGE,
|
|
187
|
+
padding=(0, 2),
|
|
188
|
+
title="[bold]🚧 BUILD IN PROGRESS 🚧[/bold]",
|
|
189
|
+
title_align="center",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
console.print(panel)
|
golf/cli/main.py
CHANGED
|
@@ -6,9 +6,9 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
8
|
from rich.console import Console
|
|
9
|
-
from rich.panel import Panel
|
|
10
9
|
|
|
11
10
|
from golf import __version__
|
|
11
|
+
from golf.cli.branding import create_welcome_banner, create_command_header
|
|
12
12
|
from golf.core.config import find_project_root, load_settings
|
|
13
13
|
from golf.core.telemetry import (
|
|
14
14
|
is_telemetry_enabled,
|
|
@@ -35,7 +35,7 @@ atexit.register(shutdown)
|
|
|
35
35
|
def _version_callback(value: bool) -> None:
|
|
36
36
|
"""Print version and exit if --version flag is used."""
|
|
37
37
|
if value:
|
|
38
|
-
|
|
38
|
+
create_welcome_banner(__version__, console)
|
|
39
39
|
raise typer.Exit()
|
|
40
40
|
|
|
41
41
|
|
|
@@ -49,9 +49,7 @@ def callback(
|
|
|
49
49
|
callback=_version_callback,
|
|
50
50
|
is_eager=True,
|
|
51
51
|
),
|
|
52
|
-
verbose: bool = typer.Option(
|
|
53
|
-
False, "--verbose", "-v", help="Increase verbosity of output."
|
|
54
|
-
),
|
|
52
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Increase verbosity of output."),
|
|
55
53
|
no_telemetry: bool = typer.Option(
|
|
56
54
|
False,
|
|
57
55
|
"--no-telemetry",
|
|
@@ -77,26 +75,24 @@ def callback(
|
|
|
77
75
|
# Set telemetry preference if flag is used (permanent)
|
|
78
76
|
if no_telemetry:
|
|
79
77
|
set_telemetry_enabled(False, persist=True)
|
|
80
|
-
console.print(
|
|
81
|
-
"[dim]Telemetry has been disabled. You can re-enable it with: golf telemetry enable[/dim]"
|
|
82
|
-
)
|
|
78
|
+
console.print("[dim]Telemetry has been disabled. You can re-enable it with: golf telemetry enable[/dim]")
|
|
83
79
|
|
|
84
80
|
|
|
85
81
|
@app.command()
|
|
86
82
|
def init(
|
|
87
83
|
project_name: str = typer.Argument(..., help="Name of the project to create"),
|
|
88
|
-
output_dir: Path | None = typer.Option(
|
|
89
|
-
None, "--output-dir", "-o", help="Directory to create the project in"
|
|
90
|
-
),
|
|
91
|
-
template: str = typer.Option(
|
|
92
|
-
"basic", "--template", "-t", help="Template to use (basic or api_key)"
|
|
93
|
-
),
|
|
84
|
+
output_dir: Path | None = typer.Option(None, "--output-dir", "-o", help="Directory to create the project in"),
|
|
94
85
|
) -> None:
|
|
95
86
|
"""Initialize a new GolfMCP project.
|
|
96
87
|
|
|
97
88
|
Creates a new directory with the project scaffold, including
|
|
98
89
|
examples for tools, resources, and prompts.
|
|
99
90
|
"""
|
|
91
|
+
# Show the Golf logo for project initialization
|
|
92
|
+
create_welcome_banner(__version__, console)
|
|
93
|
+
console.print()
|
|
94
|
+
create_command_header("Initialize Project", f"Creating {project_name}", console)
|
|
95
|
+
|
|
100
96
|
# Import here to avoid circular imports
|
|
101
97
|
from golf.commands.init import initialize_project
|
|
102
98
|
|
|
@@ -105,9 +101,7 @@ def init(
|
|
|
105
101
|
output_dir = Path.cwd() / project_name
|
|
106
102
|
|
|
107
103
|
# Execute the initialization command (it handles its own tracking)
|
|
108
|
-
initialize_project(
|
|
109
|
-
project_name=project_name, output_dir=output_dir, template=template
|
|
110
|
-
)
|
|
104
|
+
initialize_project(project_name=project_name, output_dir=output_dir)
|
|
111
105
|
|
|
112
106
|
|
|
113
107
|
# Create a build group with subcommands
|
|
@@ -117,9 +111,7 @@ app.add_typer(build_app, name="build")
|
|
|
117
111
|
|
|
118
112
|
@build_app.command("dev")
|
|
119
113
|
def build_dev(
|
|
120
|
-
output_dir: str | None = typer.Option(
|
|
121
|
-
None, "--output-dir", "-o", help="Directory to output the built project"
|
|
122
|
-
),
|
|
114
|
+
output_dir: str | None = typer.Option(None, "--output-dir", "-o", help="Directory to output the built project"),
|
|
123
115
|
) -> None:
|
|
124
116
|
"""Build a development version with app environment variables copied.
|
|
125
117
|
|
|
@@ -155,9 +147,7 @@ def build_dev(
|
|
|
155
147
|
# Build the project with environment variables copied
|
|
156
148
|
from golf.commands.build import build_project
|
|
157
149
|
|
|
158
|
-
build_project(
|
|
159
|
-
project_root, settings, output_dir, build_env="dev", copy_env=True
|
|
160
|
-
)
|
|
150
|
+
build_project(project_root, settings, output_dir, build_env="dev", copy_env=True)
|
|
161
151
|
# Track successful build with environment
|
|
162
152
|
track_event("cli_build_success", {"success": True, "environment": "dev"})
|
|
163
153
|
except Exception as e:
|
|
@@ -173,9 +163,7 @@ def build_dev(
|
|
|
173
163
|
|
|
174
164
|
@build_app.command("prod")
|
|
175
165
|
def build_prod(
|
|
176
|
-
output_dir: str | None = typer.Option(
|
|
177
|
-
None, "--output-dir", "-o", help="Directory to output the built project"
|
|
178
|
-
),
|
|
166
|
+
output_dir: str | None = typer.Option(None, "--output-dir", "-o", help="Directory to output the built project"),
|
|
179
167
|
) -> None:
|
|
180
168
|
"""Build a production version for deployment.
|
|
181
169
|
|
|
@@ -214,9 +202,7 @@ def build_prod(
|
|
|
214
202
|
# Build the project without copying environment variables
|
|
215
203
|
from golf.commands.build import build_project
|
|
216
204
|
|
|
217
|
-
build_project(
|
|
218
|
-
project_root, settings, output_dir, build_env="prod", copy_env=False
|
|
219
|
-
)
|
|
205
|
+
build_project(project_root, settings, output_dir, build_env="prod", copy_env=False)
|
|
220
206
|
# Track successful build with environment
|
|
221
207
|
track_event("cli_build_success", {"success": True, "environment": "prod"})
|
|
222
208
|
except Exception as e:
|
|
@@ -232,18 +218,10 @@ def build_prod(
|
|
|
232
218
|
|
|
233
219
|
@app.command()
|
|
234
220
|
def run(
|
|
235
|
-
dist_dir: str | None = typer.Option(
|
|
236
|
-
|
|
237
|
-
),
|
|
238
|
-
|
|
239
|
-
None, "--host", "-h", help="Host to bind to (overrides settings)"
|
|
240
|
-
),
|
|
241
|
-
port: int | None = typer.Option(
|
|
242
|
-
None, "--port", "-p", help="Port to bind to (overrides settings)"
|
|
243
|
-
),
|
|
244
|
-
build_first: bool = typer.Option(
|
|
245
|
-
True, "--build/--no-build", help="Build the project before running"
|
|
246
|
-
),
|
|
221
|
+
dist_dir: str | None = typer.Option(None, "--dist-dir", "-d", help="Directory containing the built server"),
|
|
222
|
+
host: str | None = typer.Option(None, "--host", "-h", help="Host to bind to (overrides settings)"),
|
|
223
|
+
port: int | None = typer.Option(None, "--port", "-p", help="Port to bind to (overrides settings)"),
|
|
224
|
+
build_first: bool = typer.Option(True, "--build/--no-build", help="Build the project before running"),
|
|
247
225
|
) -> None:
|
|
248
226
|
"""Run the built FastMCP server.
|
|
249
227
|
|
|
@@ -277,9 +255,7 @@ def run(
|
|
|
277
255
|
# Check if dist directory exists
|
|
278
256
|
if not dist_dir.exists():
|
|
279
257
|
if build_first:
|
|
280
|
-
console.print(
|
|
281
|
-
f"[yellow]Dist directory {dist_dir} not found. Building first...[/yellow]"
|
|
282
|
-
)
|
|
258
|
+
console.print(f"[yellow]Dist directory {dist_dir} not found. Building first...[/yellow]")
|
|
283
259
|
try:
|
|
284
260
|
# Build the project
|
|
285
261
|
from golf.commands.build import build_project
|
|
@@ -296,12 +272,8 @@ def run(
|
|
|
296
272
|
)
|
|
297
273
|
raise
|
|
298
274
|
else:
|
|
299
|
-
console.print(
|
|
300
|
-
|
|
301
|
-
)
|
|
302
|
-
console.print(
|
|
303
|
-
"Run 'golf build' first or use --build to build automatically."
|
|
304
|
-
)
|
|
275
|
+
console.print(f"[bold red]Error: Dist directory {dist_dir} not found.[/bold red]")
|
|
276
|
+
console.print("Run 'golf build' first or use --build to build automatically.")
|
|
305
277
|
track_event(
|
|
306
278
|
"cli_run_failed",
|
|
307
279
|
{
|
|
@@ -355,7 +327,7 @@ def run(
|
|
|
355
327
|
{
|
|
356
328
|
"success": False,
|
|
357
329
|
"error_type": "UnexpectedExit",
|
|
358
|
-
"error_message": f"Server process exited unexpectedly with code {return_code}",
|
|
330
|
+
"error_message": (f"Server process exited unexpectedly with code {return_code}"),
|
|
359
331
|
"exit_code": return_code,
|
|
360
332
|
"operation": "server_process_execution",
|
|
361
333
|
"context": "Server process terminated with unexpected exit code",
|
|
@@ -384,36 +356,23 @@ def telemetry(
|
|
|
384
356
|
"""Manage telemetry settings."""
|
|
385
357
|
if action.lower() == "enable":
|
|
386
358
|
set_telemetry_enabled(True, persist=True)
|
|
387
|
-
console.print(
|
|
388
|
-
"[green]✓[/green] Telemetry enabled. Thank you for helping improve Golf!"
|
|
389
|
-
)
|
|
359
|
+
console.print("[green]✓[/green] Telemetry enabled. Thank you for helping improve Golf!")
|
|
390
360
|
elif action.lower() == "disable":
|
|
391
361
|
set_telemetry_enabled(False, persist=True)
|
|
392
|
-
console.print(
|
|
393
|
-
"[yellow]Telemetry disabled.[/yellow] You can re-enable it anytime with: golf telemetry enable"
|
|
394
|
-
)
|
|
362
|
+
console.print("[yellow]Telemetry disabled.[/yellow] You can re-enable it anytime with: golf telemetry enable")
|
|
395
363
|
else:
|
|
396
|
-
console.print(
|
|
397
|
-
f"[red]Unknown action '{action}'. Use 'enable' or 'disable'.[/red]"
|
|
398
|
-
)
|
|
364
|
+
console.print(f"[red]Unknown action '{action}'. Use 'enable' or 'disable'.[/red]")
|
|
399
365
|
raise typer.Exit(code=1)
|
|
400
366
|
|
|
401
367
|
|
|
402
368
|
if __name__ == "__main__":
|
|
403
369
|
# Show welcome banner when run directly
|
|
404
|
-
console
|
|
405
|
-
Panel.fit(
|
|
406
|
-
f"[bold green]GolfMCP[/bold green] v{__version__}\n"
|
|
407
|
-
"[dim]A Pythonic framework for building MCP servers[/dim]",
|
|
408
|
-
border_style="green",
|
|
409
|
-
)
|
|
410
|
-
)
|
|
370
|
+
create_welcome_banner(__version__, console)
|
|
411
371
|
|
|
412
372
|
# Add telemetry notice if enabled
|
|
413
373
|
if is_telemetry_enabled():
|
|
414
374
|
console.print(
|
|
415
|
-
"[dim]📊 Anonymous usage data is collected to improve Golf. "
|
|
416
|
-
"Disable with: golf telemetry disable[/dim]\n"
|
|
375
|
+
"[dim]📊 Anonymous usage data is collected to improve Golf. Disable with: golf telemetry disable[/dim]\n"
|
|
417
376
|
)
|
|
418
377
|
|
|
419
378
|
# Run the CLI app
|
golf/commands/__init__.py
CHANGED
golf/commands/build.py
CHANGED
|
@@ -32,16 +32,13 @@ def build_project(
|
|
|
32
32
|
copy_env: Whether to copy environment variables to the built app
|
|
33
33
|
"""
|
|
34
34
|
# Call the centralized build function from core.builder
|
|
35
|
-
core_build_project(
|
|
36
|
-
project_path, settings, output_dir, build_env=build_env, copy_env=copy_env
|
|
37
|
-
)
|
|
35
|
+
core_build_project(project_path, settings, output_dir, build_env=build_env, copy_env=copy_env)
|
|
38
36
|
|
|
39
37
|
|
|
40
|
-
# Add a main section to run the build_project function when this module is
|
|
38
|
+
# Add a main section to run the build_project function when this module is
|
|
39
|
+
# executed directly
|
|
41
40
|
if __name__ == "__main__":
|
|
42
|
-
parser = argparse.ArgumentParser(
|
|
43
|
-
description="Build a standalone FastMCP application"
|
|
44
|
-
)
|
|
41
|
+
parser = argparse.ArgumentParser(description="Build a standalone FastMCP application")
|
|
45
42
|
parser.add_argument(
|
|
46
43
|
"--project-path",
|
|
47
44
|
"-p",
|
golf/commands/init.py
CHANGED
|
@@ -7,6 +7,13 @@ from rich.console import Console
|
|
|
7
7
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
8
8
|
from rich.prompt import Confirm
|
|
9
9
|
|
|
10
|
+
from golf.cli.branding import (
|
|
11
|
+
create_success_message,
|
|
12
|
+
create_info_panel,
|
|
13
|
+
STATUS_ICONS,
|
|
14
|
+
GOLF_ORANGE,
|
|
15
|
+
)
|
|
16
|
+
|
|
10
17
|
from golf.core.telemetry import (
|
|
11
18
|
track_command,
|
|
12
19
|
track_event,
|
|
@@ -20,35 +27,21 @@ console = Console()
|
|
|
20
27
|
def initialize_project(
|
|
21
28
|
project_name: str,
|
|
22
29
|
output_dir: Path,
|
|
23
|
-
template: str = "basic",
|
|
24
30
|
) -> None:
|
|
25
|
-
"""Initialize a new GolfMCP project
|
|
31
|
+
"""Initialize a new GolfMCP project.
|
|
26
32
|
|
|
27
33
|
Args:
|
|
28
34
|
project_name: Name of the project
|
|
29
35
|
output_dir: Directory where the project will be created
|
|
30
|
-
template: Template to use (basic or api_key)
|
|
31
36
|
"""
|
|
32
37
|
try:
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
if template not in valid_templates:
|
|
36
|
-
console.print(f"[bold red]Error:[/bold red] Unknown template '{template}'")
|
|
37
|
-
console.print(f"Available templates: {', '.join(valid_templates)}")
|
|
38
|
-
track_command(
|
|
39
|
-
"init",
|
|
40
|
-
success=False,
|
|
41
|
-
error_type="InvalidTemplate",
|
|
42
|
-
error_message=f"Unknown template: {template}",
|
|
43
|
-
)
|
|
44
|
-
return
|
|
38
|
+
# Use the basic template by default
|
|
39
|
+
template = "basic"
|
|
45
40
|
|
|
46
41
|
# Check if directory exists
|
|
47
42
|
if output_dir.exists():
|
|
48
43
|
if not output_dir.is_dir():
|
|
49
|
-
console.print(
|
|
50
|
-
f"[bold red]Error:[/bold red] '{output_dir}' exists but is not a directory."
|
|
51
|
-
)
|
|
44
|
+
console.print(f"[bold red]Error:[/bold red] '{output_dir}' exists but is not a directory.")
|
|
52
45
|
track_command(
|
|
53
46
|
"init",
|
|
54
47
|
success=False,
|
|
@@ -78,9 +71,7 @@ def initialize_project(
|
|
|
78
71
|
template_dir = package_init_file.parent / "examples" / template
|
|
79
72
|
|
|
80
73
|
if not template_dir.exists():
|
|
81
|
-
console.print(
|
|
82
|
-
f"[bold red]Error:[/bold red] Could not find template '{template}'"
|
|
83
|
-
)
|
|
74
|
+
console.print(f"[bold red]Error:[/bold red] Could not find template '{template}'")
|
|
84
75
|
track_command(
|
|
85
76
|
"init",
|
|
86
77
|
success=False,
|
|
@@ -92,7 +83,9 @@ def initialize_project(
|
|
|
92
83
|
# Copy template files
|
|
93
84
|
with Progress(
|
|
94
85
|
SpinnerColumn(),
|
|
95
|
-
TextColumn(
|
|
86
|
+
TextColumn(
|
|
87
|
+
f"[bold {GOLF_ORANGE}]{STATUS_ICONS['building']} Creating project structure...[/bold {GOLF_ORANGE}]"
|
|
88
|
+
),
|
|
96
89
|
transient=True,
|
|
97
90
|
) as progress:
|
|
98
91
|
progress.add_task("copying", total=None)
|
|
@@ -103,11 +96,13 @@ def initialize_project(
|
|
|
103
96
|
# Ask for telemetry consent
|
|
104
97
|
_prompt_for_telemetry_consent()
|
|
105
98
|
|
|
106
|
-
#
|
|
107
|
-
console.print(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
# Show success message
|
|
100
|
+
console.print()
|
|
101
|
+
create_success_message("Project initialized successfully!", console)
|
|
102
|
+
|
|
103
|
+
# Show next steps
|
|
104
|
+
next_steps = f"cd {output_dir.name}\ngolf build dev\ngolf run"
|
|
105
|
+
create_info_panel("Next Steps", next_steps, console)
|
|
111
106
|
|
|
112
107
|
# Track successful initialization
|
|
113
108
|
track_event("cli_init_success", {"success": True, "template": template})
|
|
@@ -116,12 +111,8 @@ def initialize_project(
|
|
|
116
111
|
error_type = type(e).__name__
|
|
117
112
|
error_message = str(e)
|
|
118
113
|
|
|
119
|
-
console.print(
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
track_command(
|
|
123
|
-
"init", success=False, error_type=error_type, error_message=error_message
|
|
124
|
-
)
|
|
114
|
+
console.print(f"[bold red]Error during initialization:[/bold red] {error_message}")
|
|
115
|
+
track_command("init", success=False, error_type=error_type, error_message=error_message)
|
|
125
116
|
|
|
126
117
|
# Re-raise to maintain existing behavior
|
|
127
118
|
raise
|
|
@@ -160,9 +151,7 @@ def _copy_template(source_dir: Path, target_dir: Path, project_name: str) -> Non
|
|
|
160
151
|
|
|
161
152
|
# Replace template variables
|
|
162
153
|
content = content.replace("{{project_name}}", project_name)
|
|
163
|
-
content = content.replace(
|
|
164
|
-
"{{project_name_lowercase}}", project_name.lower()
|
|
165
|
-
)
|
|
154
|
+
content = content.replace("{{project_name_lowercase}}", project_name.lower())
|
|
166
155
|
|
|
167
156
|
with open(target_path, "w", encoding="utf-8") as f:
|
|
168
157
|
f.write(content)
|
|
@@ -170,13 +159,6 @@ def _copy_template(source_dir: Path, target_dir: Path, project_name: str) -> Non
|
|
|
170
159
|
# Binary file, just copy
|
|
171
160
|
shutil.copy2(source_path, target_path)
|
|
172
161
|
|
|
173
|
-
# Create .env file
|
|
174
|
-
env_file = target_dir / ".env"
|
|
175
|
-
with open(env_file, "w", encoding="utf-8") as f:
|
|
176
|
-
f.write(f"GOLF_NAME={project_name}\n")
|
|
177
|
-
f.write("GOLF_HOST=127.0.0.1\n")
|
|
178
|
-
f.write("GOLF_PORT=3000\n")
|
|
179
|
-
|
|
180
162
|
# Create a .gitignore if it doesn't exist
|
|
181
163
|
gitignore_file = target_dir / ".gitignore"
|
|
182
164
|
if not gitignore_file.exists():
|
|
@@ -219,7 +201,8 @@ def _prompt_for_telemetry_consent() -> None:
|
|
|
219
201
|
"""Prompt user for telemetry consent and save their preference."""
|
|
220
202
|
import os
|
|
221
203
|
|
|
222
|
-
# Skip prompt in test mode, when telemetry is explicitly disabled, or if
|
|
204
|
+
# Skip prompt in test mode, when telemetry is explicitly disabled, or if
|
|
205
|
+
# preference already exists
|
|
223
206
|
if os.environ.get("GOLF_TEST_MODE", "").lower() in ("1", "true", "yes", "on"):
|
|
224
207
|
return
|
|
225
208
|
|
|
@@ -235,9 +218,7 @@ def _prompt_for_telemetry_consent() -> None:
|
|
|
235
218
|
console.print()
|
|
236
219
|
console.rule("[bold blue]Anonymous usage analytics[/bold blue]", style="blue")
|
|
237
220
|
console.print()
|
|
238
|
-
console.print(
|
|
239
|
-
"Golf can collect [bold]anonymous usage analytics[/bold] to help improve the tool."
|
|
240
|
-
)
|
|
221
|
+
console.print("Golf can collect [bold]anonymous usage analytics[/bold] to help improve the tool.")
|
|
241
222
|
console.print()
|
|
242
223
|
console.print("[dim]What we collect:[/dim]")
|
|
243
224
|
console.print(" • Command usage (init, build, run)")
|
|
@@ -251,14 +232,10 @@ def _prompt_for_telemetry_consent() -> None:
|
|
|
251
232
|
console.print(" • Personal information")
|
|
252
233
|
console.print(" • IP addresses")
|
|
253
234
|
console.print()
|
|
254
|
-
console.print(
|
|
255
|
-
"You can change this anytime by setting GOLF_TELEMETRY=0 in your environment."
|
|
256
|
-
)
|
|
235
|
+
console.print("You can change this anytime by setting GOLF_TELEMETRY=0 in your environment.")
|
|
257
236
|
console.print()
|
|
258
237
|
|
|
259
|
-
enable_telemetry = Confirm.ask(
|
|
260
|
-
"[bold]Enable anonymous usage analytics?[/bold]", default=False
|
|
261
|
-
)
|
|
238
|
+
enable_telemetry = Confirm.ask("[bold]Enable anonymous usage analytics?[/bold]", default=False)
|
|
262
239
|
|
|
263
240
|
set_telemetry_enabled(enable_telemetry, persist=True)
|
|
264
241
|
|