refactor: merge internal/sync into internal/garmin, regroup api files and routes
Garmin auth/sync routes move under /api/garmin/*; sync.Service becomes garmin.Sync with garmin.SyncConfig/ClientConfig; applog becomes internal/log; the test mock moves into the garmin package as MockClient (breaking the test-only import cycle the merge created); stale test URLs and type names updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,25 +17,25 @@
|
||||
- `GARMIN_WRAPPER_PYTHON` is optional, defaulting to `"python3"` (resolved via `PATH`) — `MCP_GARMIN_PYTHON`/`MCP_GARMIN_SERVER` are retired entirely, not renamed.
|
||||
- `garminconnect`'s actual method kwargs must be used exactly: `get_activities_by_date(startdate, enddate)`, `get_activity_splits(activity_id)`, `get_activity_details(activity_id)`, `get_workout_by_id(workout_id)` (confirmed via `inspect.signature` against the installed package — note `startdate`/`enddate`, not `start_date`/`end_date`).
|
||||
- `gofmt -l .` must report nothing; `go build ./...`, `go vet ./...`, and `go test ./...` must all pass before the final commit.
|
||||
- `pytest` must pass in `backend/internal/garmin/pyscript/`.
|
||||
- `pytest` must pass in `../../../backend/internal/garmin/wrapper/`.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Python wrapper (`wrapper.py`) with its own test suite
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/internal/garmin/pyscript/wrapper.py`
|
||||
- Create: `backend/internal/garmin/pyscript/pyproject.toml`
|
||||
- Create: `backend/internal/garmin/pyscript/.gitignore`
|
||||
- Test: `backend/internal/garmin/pyscript/tests/__init__.py`
|
||||
- Test: `backend/internal/garmin/pyscript/tests/test_wrapper.py`
|
||||
- Create: `../../../backend/internal/garmin/wrapper/wrapper.py`
|
||||
- Create: `../../../backend/internal/garmin/wrapper/pyproject.toml`
|
||||
- Create: `../../../backend/internal/garmin/wrapper/.gitignore`
|
||||
- Test: `../../../backend/internal/garmin/wrapper/tests/__init__.py`
|
||||
- Test: `../../../backend/internal/garmin/wrapper/tests/test_wrapper.py`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: `wrapper.dispatch(req: dict) -> dict` — the single entry point Go's subprocess talks to indirectly via stdin/stdout; also `wrapper._auth_state`, `wrapper._client`, `wrapper._mfa_input_queue`, `wrapper._login_result_queue`, `wrapper.Garmin` (re-exported name, patchable in tests), used only within this task's own test suite.
|
||||
|
||||
- [ ] **Step 1: Create the Python project manifest**
|
||||
|
||||
`backend/internal/garmin/pyscript/pyproject.toml`:
|
||||
`../../../backend/internal/garmin/wrapper/pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[project]
|
||||
@@ -55,7 +55,7 @@ requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
```
|
||||
|
||||
`backend/internal/garmin/pyscript/.gitignore`:
|
||||
`../../../backend/internal/garmin/wrapper/.gitignore`:
|
||||
|
||||
```
|
||||
.venv/
|
||||
@@ -68,7 +68,7 @@ __pycache__/
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd backend/internal/garmin/pyscript
|
||||
cd backend/internal/garmin/wrapper
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install -e ".[dev]"
|
||||
```
|
||||
@@ -76,9 +76,9 @@ Expected: installs `garminconnect` and `pytest` into `.venv` with no errors.
|
||||
|
||||
- [ ] **Step 3: Write the failing test suite**
|
||||
|
||||
`backend/internal/garmin/pyscript/tests/__init__.py`: empty file.
|
||||
`../../../backend/internal/garmin/wrapper/tests/__init__.py`: empty file.
|
||||
|
||||
`backend/internal/garmin/pyscript/tests/test_wrapper.py`:
|
||||
`../../../backend/internal/garmin/wrapper/tests/test_wrapper.py`:
|
||||
|
||||
```python
|
||||
import os
|
||||
@@ -216,7 +216,7 @@ Expected: `ModuleNotFoundError: No module named 'wrapper'` (or collection failur
|
||||
|
||||
- [ ] **Step 5: Write `wrapper.py`**
|
||||
|
||||
`backend/internal/garmin/pyscript/wrapper.py`:
|
||||
`../../../backend/internal/garmin/wrapper/wrapper.py`:
|
||||
|
||||
```python
|
||||
"""Subprocess wrapper around garminconnect, spoken to over newline-delimited
|
||||
@@ -393,7 +393,7 @@ Expected: all tests PASS.
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/internal/garmin/pyscript
|
||||
git add backend/internal/garmin/wrapper
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(garmin): add direct garminconnect wrapper script
|
||||
|
||||
@@ -584,7 +584,7 @@ Expected: compile failure — `subprocessClient`, `wireResponse`, `roundTrip`, `
|
||||
|
||||
```go
|
||||
// Package garmin wraps a direct garminconnect subprocess (see
|
||||
// pyscript/wrapper.py) as a narrow Go client interface, so the rest of
|
||||
// wrapper/wrapper.py) as a narrow Go client interface, so the rest of
|
||||
// geniusrun never deals with the wire protocol directly.
|
||||
package garmin
|
||||
|
||||
@@ -861,7 +861,7 @@ git add backend/internal/garmin/client.go backend/internal/garmin/client_test.go
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(garmin): replace mcp-go transport with a JSON-lines subprocess client
|
||||
|
||||
subprocessClient spawns the embedded pyscript/wrapper.py over os/exec and
|
||||
subprocessClient spawns the embedded wrapper/wrapper.py over os/exec and
|
||||
speaks newline-delimited JSON instead of MCP. Auth/data methods land in
|
||||
follow-up commits; this is the transport + lifecycle plumbing only.
|
||||
|
||||
@@ -1370,8 +1370,8 @@ EOF
|
||||
### Task 5: Update `internal/config` (drop server-path env var, default the python path)
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/internal/config/config.go`
|
||||
- Modify: `backend/internal/config/config_test.go`
|
||||
- Modify: `../../../backend/internal/config/envconfig.go`
|
||||
- Modify: `../../../backend/internal/config/envconfig_test.go`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: nothing from Tasks 1–4.
|
||||
@@ -1379,7 +1379,7 @@ EOF
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
In `backend/internal/config/config_test.go`, update `setRequiredEnv` (remove the two now-optional lines):
|
||||
In `../../../backend/internal/config/envconfig_test.go`, update `setRequiredEnv` (remove the two now-optional lines):
|
||||
|
||||
```go
|
||||
func setRequiredEnv(t *testing.T) {
|
||||
@@ -1425,11 +1425,11 @@ func TestLoad_GarminPythonPathExplicitOverridesDefault(t *testing.T) {
|
||||
- [ ] **Step 2: Run the tests to verify they fail**
|
||||
|
||||
Run: `cd backend && go test ./internal/config/... -v`
|
||||
Expected: `TestLoad_GarminPythonPathDefaultsToPython3` fails (`GarminPythonPath` is currently `""`, and `Load()` currently errors out entirely since `MCP_GARMIN_PYTHON`/`MCP_GARMIN_SERVER` are no longer set by the trimmed `setRequiredEnv`) — every other test in the package should also now fail with "MCP_GARMIN_PYTHON is required", confirming the removed env vars were the only thing missing.
|
||||
Expected: `TestLoad_GarminPythonPathDefaultsToPython3` fails (`PythonPath` is currently `""`, and `Load()` currently errors out entirely since `MCP_GARMIN_PYTHON`/`MCP_GARMIN_SERVER` are no longer set by the trimmed `setRequiredEnv`) — every other test in the package should also now fail with "MCP_GARMIN_PYTHON is required", confirming the removed env vars were the only thing missing.
|
||||
|
||||
- [ ] **Step 3: Update `config.go`**
|
||||
- [ ] **Step 3: Update `envconfig.go`**
|
||||
|
||||
In `backend/internal/config/config.go`, replace the two Garmin subprocess-path fields:
|
||||
In `../../../backend/internal/config/envconfig.go`, replace the two Garmin subprocess-path fields:
|
||||
|
||||
```go
|
||||
// GarminPythonPath is mcp-garmin's venv python executable.
|
||||
@@ -1479,7 +1479,7 @@ Expected: all tests PASS.
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/internal/config/config.go backend/internal/config/config_test.go
|
||||
git add backend/internal/config/envconfig.go backend/internal/config/envconfig_test.go
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(config): drop MCP_GARMIN_SERVER, default GARMIN_WRAPPER_PYTHON
|
||||
|
||||
@@ -1528,7 +1528,7 @@ to:
|
||||
}, appsync.Config{
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update the `GarminBase` doc comment in `server.go`**
|
||||
- [ ] **Step 2: Update the `ClientConfig` doc comment in `server.go`**
|
||||
|
||||
In `backend/internal/api/server.go`, change:
|
||||
|
||||
@@ -1749,4 +1749,4 @@ EOF
|
||||
|
||||
## Follow-up note (not a task in this plan)
|
||||
|
||||
The standalone `mcp-garmin` repo (`/Users/kriss/Dev/scm/scm.vilanet.fr/kriss/mcp-garmin`) is superseded by `backend/internal/garmin/pyscript/` and can be archived once this plan lands — that's a separate-repo action for you to do directly (e.g. marking it archived on your SCM host), not something this plan's tasks touch.
|
||||
The standalone `mcp-garmin` repo (`/Users/kriss/Dev/scm/scm.vilanet.fr/kriss/mcp-garmin`) is superseded by `../../../backend/internal/garmin/wrapper/` and can be archived once this plan lands — that's a separate-repo action for you to do directly (e.g. marking it archived on your SCM host), not something this plan's tasks touch.
|
||||
|
||||
Reference in New Issue
Block a user