golf-mcp 0.1.16__tar.gz → 0.1.18__tar.gz
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_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/docs.md +2 -2
- {golf_mcp-0.1.16/src/golf_mcp.egg-info → golf_mcp-0.1.18}/PKG-INFO +10 -3
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/README.md +6 -1
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/pyproject.toml +9 -4
- golf_mcp-0.1.18/src/golf/__init__.py +1 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/cli/main.py +13 -2
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/commands/init.py +63 -1
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/builder.py +220 -59
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/builder_auth.py +5 -0
- golf_mcp-0.1.18/src/golf/core/builder_metrics.py +232 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/config.py +12 -0
- golf_mcp-0.1.18/src/golf/core/parser.py +1059 -0
- golf_mcp-0.1.18/src/golf/core/platform.py +180 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/telemetry.py +28 -8
- golf_mcp-0.1.18/src/golf/examples/api_key/.env.example +1 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/README.md +10 -10
- golf_mcp-0.1.18/src/golf/examples/api_key/golf.json +8 -0
- golf_mcp-0.1.18/src/golf/examples/basic/.env.example +4 -0
- golf_mcp-0.1.18/src/golf/examples/basic/golf.json +8 -0
- golf_mcp-0.1.18/src/golf/metrics/__init__.py +10 -0
- golf_mcp-0.1.18/src/golf/metrics/collector.py +239 -0
- golf_mcp-0.1.18/src/golf/metrics/registry.py +12 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/telemetry/instrumentation.py +177 -144
- {golf_mcp-0.1.16 → golf_mcp-0.1.18/src/golf_mcp.egg-info}/PKG-INFO +10 -3
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf_mcp.egg-info/SOURCES.txt +5 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf_mcp.egg-info/requires.txt +4 -1
- golf_mcp-0.1.16/src/golf/__init__.py +0 -1
- golf_mcp-0.1.16/src/golf/core/parser.py +0 -560
- golf_mcp-0.1.16/src/golf/examples/api_key/.env.example +0 -5
- golf_mcp-0.1.16/src/golf/examples/api_key/golf.json +0 -12
- golf_mcp-0.1.16/src/golf/examples/basic/.env.example +0 -5
- golf_mcp-0.1.16/src/golf/examples/basic/golf.json +0 -12
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/fast-mcp.md +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/fastmcp-example-1.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/fastmcp-example-2.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/mcp.md +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/oauth-implementation.md +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/.docs/oauth.md +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/LICENSE +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/MANIFEST.in +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/setup.cfg +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/auth/__init__.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/auth/api_key.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/auth/helpers.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/auth/oauth.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/auth/provider.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/cli/__init__.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/commands/__init__.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/commands/build.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/commands/run.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/__init__.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/builder_telemetry.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/core/transformer.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/__init__.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/.env +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/pre_build.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/tools/issues/create.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/tools/issues/list.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/tools/repos/list.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/tools/search/code.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/api_key/tools/users/get.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/.env +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/README.md +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/pre_build.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/prompts/welcome.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/resources/current_time.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/resources/info.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/resources/weather/common.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/resources/weather/current.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/resources/weather/forecast.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/tools/github_user.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/tools/hello.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/tools/payments/charge.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/tools/payments/common.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/examples/basic/tools/payments/refund.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf/telemetry/__init__.py +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf_mcp.egg-info/dependency_links.txt +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf_mcp.egg-info/entry_points.txt +0 -0
- {golf_mcp-0.1.16 → golf_mcp-0.1.18}/src/golf_mcp.egg-info/top_level.txt +0 -0
|
@@ -49,7 +49,7 @@ Given a component file `C` with absolute path
|
|
|
49
49
|
let `PathRev = [pₙ, …, p₁]` (reverse order of parent dirs under the category). The **ID** is
|
|
50
50
|
|
|
51
51
|
```
|
|
52
|
-
<filename> + ("
|
|
52
|
+
<filename> + ("_" + "_".join(PathRev) if PathRev else "")
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
### Formal Definition (BNF)
|
|
@@ -190,7 +190,7 @@ def run(charge_id: str, amount: int) -> dict:
|
|
|
190
190
|
from tools.payments.refund import submit as _submit
|
|
191
191
|
|
|
192
192
|
mcp.tool(
|
|
193
|
-
name="
|
|
193
|
+
name="submit_refund_payments",
|
|
194
194
|
description="Submit a refund request to Stripe."
|
|
195
195
|
)(_submit.run)
|
|
196
196
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: golf-mcp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.18
|
|
4
4
|
Summary: Framework for building MCP servers
|
|
5
5
|
Author-email: Antoni Gmitruk <antoni@golf.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -21,7 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: typer>=0.15.4
|
|
23
23
|
Requires-Dist: rich>=14.0.0
|
|
24
|
-
Requires-Dist: fastmcp
|
|
24
|
+
Requires-Dist: fastmcp<2.6.0,>=2.0.0
|
|
25
25
|
Requires-Dist: pydantic>=2.11.0
|
|
26
26
|
Requires-Dist: python-dotenv>=1.1.0
|
|
27
27
|
Requires-Dist: black>=24.10.0
|
|
@@ -34,6 +34,8 @@ Requires-Dist: opentelemetry-sdk>=1.33.1; extra == "telemetry"
|
|
|
34
34
|
Requires-Dist: opentelemetry-instrumentation-asgi>=0.40b0; extra == "telemetry"
|
|
35
35
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=0.40b0; extra == "telemetry"
|
|
36
36
|
Requires-Dist: wrapt>=1.17.0; extra == "telemetry"
|
|
37
|
+
Provides-Extra: metrics
|
|
38
|
+
Requires-Dist: prometheus-client>=0.22.1; extra == "metrics"
|
|
37
39
|
Dynamic: license-file
|
|
38
40
|
|
|
39
41
|
<div align="center">
|
|
@@ -128,7 +130,7 @@ A Golf project initialized with `golf init` will have a structure similar to thi
|
|
|
128
130
|
|
|
129
131
|
- **`golf.json`**: Configures server name, port, transport, telemetry, and other build settings.
|
|
130
132
|
- **`tools/`**, **`resources/`**, **`prompts/`**: Contain your Python files, each defining a single component. These directories can also contain nested subdirectories to further organize your components (e.g., `tools/payments/charge.py`). The module docstring of each file serves as the component's description.
|
|
131
|
-
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `
|
|
133
|
+
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `submit_payments` (filename, followed by reversed parent directories under the main category, joined by underscores).
|
|
132
134
|
- **`common.py`** (not shown, but can be placed in subdirectories like `tools/payments/common.py`): Used to share code (clients, models, etc.) among components in the same subdirectory.
|
|
133
135
|
|
|
134
136
|
## Example: Defining a Tool
|
|
@@ -178,6 +180,10 @@ The `golf.json` file is the heart of your Golf project configuration. Here's wha
|
|
|
178
180
|
// - "streamable-http": HTTP with streaming support
|
|
179
181
|
// - "stdio": Standard I/O (for CLI integration)
|
|
180
182
|
|
|
183
|
+
// HTTP Transport Configuration (optional)
|
|
184
|
+
"stateless_http": false, // Make streamable-http transport stateless (new session per request)
|
|
185
|
+
// When true, server restarts won't break existing client connections
|
|
186
|
+
|
|
181
187
|
// Health Check Configuration (optional)
|
|
182
188
|
"health_check_enabled": false, // Enable health check endpoint for Kubernetes/load balancers
|
|
183
189
|
"health_check_path": "/health", // HTTP path for health check endpoint
|
|
@@ -198,6 +204,7 @@ The `golf.json` file is the heart of your Golf project configuration. Here's wha
|
|
|
198
204
|
- `"streamable-http"` provides HTTP streaming for traditional API clients
|
|
199
205
|
- `"stdio"` enables integration with command-line tools and scripts
|
|
200
206
|
- **`host` & `port`**: Control where your server listens. Use `"127.0.0.1"` for local development or `"0.0.0.0"` to accept external connections.
|
|
207
|
+
- **`stateless_http`**: When true, makes the streamable-http transport stateless by creating a new session for each request. This ensures that server restarts don't break existing client connections, making the server truly stateless.
|
|
201
208
|
- **`health_check_enabled`**: When true, enables a health check endpoint for Kubernetes readiness/liveness probes and load balancers
|
|
202
209
|
- **`health_check_path`**: Customizable path for the health check endpoint (defaults to "/health")
|
|
203
210
|
- **`health_check_response`**: Customizable response text for successful health checks (defaults to "OK")
|
|
@@ -90,7 +90,7 @@ A Golf project initialized with `golf init` will have a structure similar to thi
|
|
|
90
90
|
|
|
91
91
|
- **`golf.json`**: Configures server name, port, transport, telemetry, and other build settings.
|
|
92
92
|
- **`tools/`**, **`resources/`**, **`prompts/`**: Contain your Python files, each defining a single component. These directories can also contain nested subdirectories to further organize your components (e.g., `tools/payments/charge.py`). The module docstring of each file serves as the component's description.
|
|
93
|
-
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `
|
|
93
|
+
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `submit_payments` (filename, followed by reversed parent directories under the main category, joined by underscores).
|
|
94
94
|
- **`common.py`** (not shown, but can be placed in subdirectories like `tools/payments/common.py`): Used to share code (clients, models, etc.) among components in the same subdirectory.
|
|
95
95
|
|
|
96
96
|
## Example: Defining a Tool
|
|
@@ -140,6 +140,10 @@ The `golf.json` file is the heart of your Golf project configuration. Here's wha
|
|
|
140
140
|
// - "streamable-http": HTTP with streaming support
|
|
141
141
|
// - "stdio": Standard I/O (for CLI integration)
|
|
142
142
|
|
|
143
|
+
// HTTP Transport Configuration (optional)
|
|
144
|
+
"stateless_http": false, // Make streamable-http transport stateless (new session per request)
|
|
145
|
+
// When true, server restarts won't break existing client connections
|
|
146
|
+
|
|
143
147
|
// Health Check Configuration (optional)
|
|
144
148
|
"health_check_enabled": false, // Enable health check endpoint for Kubernetes/load balancers
|
|
145
149
|
"health_check_path": "/health", // HTTP path for health check endpoint
|
|
@@ -160,6 +164,7 @@ The `golf.json` file is the heart of your Golf project configuration. Here's wha
|
|
|
160
164
|
- `"streamable-http"` provides HTTP streaming for traditional API clients
|
|
161
165
|
- `"stdio"` enables integration with command-line tools and scripts
|
|
162
166
|
- **`host` & `port`**: Control where your server listens. Use `"127.0.0.1"` for local development or `"0.0.0.0"` to accept external connections.
|
|
167
|
+
- **`stateless_http`**: When true, makes the streamable-http transport stateless by creating a new session for each request. This ensures that server restarts don't break existing client connections, making the server truly stateless.
|
|
163
168
|
- **`health_check_enabled`**: When true, enables a health check endpoint for Kubernetes readiness/liveness probes and load balancers
|
|
164
169
|
- **`health_check_path`**: Customizable path for the health check endpoint (defaults to "/health")
|
|
165
170
|
- **`health_check_response`**: Customizable response text for successful health checks (defaults to "OK")
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "golf-mcp"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.18"
|
|
8
8
|
description = "Framework for building MCP servers"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Antoni Gmitruk", email = "antoni@golf.dev"}
|
|
@@ -28,7 +28,7 @@ classifiers = [
|
|
|
28
28
|
dependencies = [
|
|
29
29
|
"typer>=0.15.4",
|
|
30
30
|
"rich>=14.0.0",
|
|
31
|
-
"fastmcp>=2.0.0",
|
|
31
|
+
"fastmcp>=2.0.0,<2.6.0",
|
|
32
32
|
"pydantic>=2.11.0",
|
|
33
33
|
"python-dotenv>=1.1.0",
|
|
34
34
|
"black>=24.10.0",
|
|
@@ -45,6 +45,9 @@ telemetry = [
|
|
|
45
45
|
"opentelemetry-exporter-otlp-proto-http>=0.40b0",
|
|
46
46
|
"wrapt>=1.17.0"
|
|
47
47
|
]
|
|
48
|
+
metrics = [
|
|
49
|
+
"prometheus-client>=0.22.1"
|
|
50
|
+
]
|
|
48
51
|
|
|
49
52
|
[project.scripts]
|
|
50
53
|
golf = "golf.cli.main:app"
|
|
@@ -64,7 +67,7 @@ golf = ["examples/**/*"]
|
|
|
64
67
|
|
|
65
68
|
[tool.poetry]
|
|
66
69
|
name = "golf-mcp"
|
|
67
|
-
version = "0.1.
|
|
70
|
+
version = "0.1.18"
|
|
68
71
|
description = "Framework for building MCP servers with zero boilerplate"
|
|
69
72
|
authors = ["Antoni Gmitruk <antoni@golf.dev>"]
|
|
70
73
|
license = "Apache-2.0"
|
|
@@ -86,7 +89,7 @@ classifiers = [
|
|
|
86
89
|
|
|
87
90
|
[tool.poetry.dependencies]
|
|
88
91
|
python = ">=3.8" # Match requires-python
|
|
89
|
-
fastmcp = ">=2.0.0"
|
|
92
|
+
fastmcp = ">=2.0.0,<2.6.0"
|
|
90
93
|
typer = {extras = ["all"], version = ">=0.15.4"}
|
|
91
94
|
pydantic = ">=2.11.0"
|
|
92
95
|
rich = ">=14.0.0"
|
|
@@ -100,9 +103,11 @@ opentelemetry-sdk = {version = ">=1.33.1", optional = true}
|
|
|
100
103
|
opentelemetry-instrumentation-asgi = {version = ">=0.40b0", optional = true}
|
|
101
104
|
opentelemetry-exporter-otlp-proto-http = {version = ">=0.40b0", optional = true}
|
|
102
105
|
wrapt = {version = ">=1.17.0", optional = true}
|
|
106
|
+
prometheus-client = {version = ">=0.22.1", optional = true}
|
|
103
107
|
|
|
104
108
|
[tool.poetry.extras]
|
|
105
109
|
telemetry = ["opentelemetry-api", "opentelemetry-sdk", "opentelemetry-instrumentation-asgi", "opentelemetry-exporter-otlp-proto-http", "wrapt"]
|
|
110
|
+
metrics = ["prometheus-client"]
|
|
106
111
|
|
|
107
112
|
[tool.poetry.group.dev.dependencies]
|
|
108
113
|
pytest = "^7.4.0"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.18"
|
|
@@ -121,7 +121,11 @@ def build_dev(
|
|
|
121
121
|
None, "--output-dir", "-o", help="Directory to output the built project"
|
|
122
122
|
),
|
|
123
123
|
) -> None:
|
|
124
|
-
"""Build a development version with environment variables copied.
|
|
124
|
+
"""Build a development version with app environment variables copied.
|
|
125
|
+
|
|
126
|
+
Golf credentials (GOLF_*) are always loaded from .env for build operations.
|
|
127
|
+
All environment variables are copied to the built project for development.
|
|
128
|
+
"""
|
|
125
129
|
# Find project root directory
|
|
126
130
|
project_root, config_path = find_project_root()
|
|
127
131
|
|
|
@@ -173,7 +177,14 @@ def build_prod(
|
|
|
173
177
|
None, "--output-dir", "-o", help="Directory to output the built project"
|
|
174
178
|
),
|
|
175
179
|
) -> None:
|
|
176
|
-
"""Build a production version
|
|
180
|
+
"""Build a production version for deployment.
|
|
181
|
+
|
|
182
|
+
Golf credentials (GOLF_*) are always loaded from .env for build operations
|
|
183
|
+
(platform registration, resource updates). App environment variables are
|
|
184
|
+
NOT copied for security - provide them in your deployment environment.
|
|
185
|
+
|
|
186
|
+
Your production deployment must include GOLF_* vars for runtime telemetry.
|
|
187
|
+
"""
|
|
177
188
|
# Find project root directory
|
|
178
189
|
project_root, config_path = find_project_root()
|
|
179
190
|
|
|
@@ -7,7 +7,12 @@ 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.core.telemetry import
|
|
10
|
+
from golf.core.telemetry import (
|
|
11
|
+
track_command,
|
|
12
|
+
track_event,
|
|
13
|
+
set_telemetry_enabled,
|
|
14
|
+
load_telemetry_preference,
|
|
15
|
+
)
|
|
11
16
|
|
|
12
17
|
console = Console()
|
|
13
18
|
|
|
@@ -95,6 +100,9 @@ def initialize_project(
|
|
|
95
100
|
# Copy directory structure
|
|
96
101
|
_copy_template(template_dir, output_dir, project_name)
|
|
97
102
|
|
|
103
|
+
# Ask for telemetry consent
|
|
104
|
+
_prompt_for_telemetry_consent()
|
|
105
|
+
|
|
98
106
|
# Create virtual environment
|
|
99
107
|
console.print("[bold green]Project initialized successfully![/bold green]")
|
|
100
108
|
console.print("\nTo get started, run:")
|
|
@@ -207,6 +215,60 @@ def _copy_template(source_dir: Path, target_dir: Path, project_name: str) -> Non
|
|
|
207
215
|
f.write("dist/\n")
|
|
208
216
|
|
|
209
217
|
|
|
218
|
+
def _prompt_for_telemetry_consent() -> None:
|
|
219
|
+
"""Prompt user for telemetry consent and save their preference."""
|
|
220
|
+
import os
|
|
221
|
+
|
|
222
|
+
# Skip prompt in test mode, when telemetry is explicitly disabled, or if preference already exists
|
|
223
|
+
if os.environ.get("GOLF_TEST_MODE", "").lower() in ("1", "true", "yes", "on"):
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
# Skip if telemetry is explicitly disabled in environment
|
|
227
|
+
if os.environ.get("GOLF_TELEMETRY", "").lower() in ("0", "false", "no", "off"):
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
# Check if user already has a saved preference
|
|
231
|
+
existing_preference = load_telemetry_preference()
|
|
232
|
+
if existing_preference is not None:
|
|
233
|
+
return # User already made a choice
|
|
234
|
+
|
|
235
|
+
console.print()
|
|
236
|
+
console.rule("[bold blue]Anonymous usage analytics[/bold blue]", style="blue")
|
|
237
|
+
console.print()
|
|
238
|
+
console.print(
|
|
239
|
+
"Golf can collect [bold]anonymous usage analytics[/bold] to help improve the tool."
|
|
240
|
+
)
|
|
241
|
+
console.print()
|
|
242
|
+
console.print("[dim]What we collect:[/dim]")
|
|
243
|
+
console.print(" • Command usage (init, build, run)")
|
|
244
|
+
console.print(" • Error types (to fix bugs)")
|
|
245
|
+
console.print(" • Golf version and Python version")
|
|
246
|
+
console.print(" • Operating system type")
|
|
247
|
+
console.print()
|
|
248
|
+
console.print("[dim]What we DON'T collect:[/dim]")
|
|
249
|
+
console.print(" • Your code or project content")
|
|
250
|
+
console.print(" • File paths or project names")
|
|
251
|
+
console.print(" • Personal information")
|
|
252
|
+
console.print(" • IP addresses")
|
|
253
|
+
console.print()
|
|
254
|
+
console.print(
|
|
255
|
+
"You can change this anytime by setting GOLF_TELEMETRY=0 in your environment."
|
|
256
|
+
)
|
|
257
|
+
console.print()
|
|
258
|
+
|
|
259
|
+
enable_telemetry = Confirm.ask(
|
|
260
|
+
"[bold]Enable anonymous usage analytics?[/bold]", default=False
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
set_telemetry_enabled(enable_telemetry, persist=True)
|
|
264
|
+
|
|
265
|
+
if enable_telemetry:
|
|
266
|
+
console.print("[green]✓[/green] Anonymous analytics enabled")
|
|
267
|
+
else:
|
|
268
|
+
console.print("[yellow]○[/yellow] Anonymous analytics disabled")
|
|
269
|
+
console.print()
|
|
270
|
+
|
|
271
|
+
|
|
210
272
|
def _is_text_file(path: Path) -> bool:
|
|
211
273
|
"""Check if a file is a text file that needs variable substitution.
|
|
212
274
|
|