- opencode agent (fitness-trainer) for personal training conversations - fitness-workout skill with programming methodology guidelines - workout.py script (1RM, volume, cycle helpers) - logs/ directory for workout and check-in markdown files - inputs/ with user profile (equipment, goals, medical, Juggernaut history) - google-sheets-automation skill for optional Sheets integration - AGENTS.md with setup documentation
142 lines
4.4 KiB
Python
142 lines
4.4 KiB
Python
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from google.auth.transport.requests import Request
|
|
from google.oauth2.credentials import Credentials
|
|
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
|
|
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
|
|
SERVICE_NAME = "google-sheets-skill-oauth"
|
|
|
|
try:
|
|
import keyring
|
|
HAS_KEYRING = True
|
|
except ImportError:
|
|
HAS_KEYRING = False
|
|
|
|
|
|
def get_token_dir():
|
|
path = os.environ.get("GOOGLE_SHEETS_TOKEN_DIR")
|
|
if path:
|
|
return Path(path)
|
|
default = Path.home() / ".config" / "google-sheets-skill"
|
|
default.mkdir(parents=True, exist_ok=True)
|
|
return default
|
|
|
|
|
|
def _load_creds():
|
|
token_file = get_token_dir() / "token.json"
|
|
if token_file.exists():
|
|
return Credentials.from_authorized_user_file(str(token_file), SCOPES)
|
|
if HAS_KEYRING:
|
|
stored = keyring.get_password(SERVICE_NAME, "token")
|
|
if stored:
|
|
return Credentials.from_authorized_user_info(json.loads(stored), SCOPES)
|
|
return None
|
|
|
|
|
|
def _save_creds(creds):
|
|
get_token_dir().mkdir(parents=True, exist_ok=True)
|
|
token_file = get_token_dir() / "token.json"
|
|
token_file.write_text(creds.to_json())
|
|
token_file.chmod(0o600)
|
|
if HAS_KEYRING:
|
|
keyring.set_password(SERVICE_NAME, "token", creds.to_json())
|
|
|
|
|
|
def _find_creds_file():
|
|
env_path = os.environ.get("GOOGLE_SHEETS_CREDS")
|
|
if env_path:
|
|
return Path(env_path)
|
|
alongside = Path(__file__).parent / "credentials.json"
|
|
if alongside.exists():
|
|
return alongside
|
|
return Path.home() / ".config" / "google-sheets-skill" / "credentials.json"
|
|
|
|
|
|
def cmd_login():
|
|
creds_file = _find_creds_file()
|
|
if not creds_file.exists():
|
|
print(
|
|
f"credentials.json not found at {creds_file}\n"
|
|
"Download it from Google Cloud Console:\n"
|
|
"1. Go to https://console.cloud.google.com/\n"
|
|
"2. Create a project → Enable Sheets API\n"
|
|
"3. Create OAuth 2.0 Client ID → Desktop App\n"
|
|
"4. Download as credentials.json\n"
|
|
"5. Save to: " + str(creds_file) + "\n\n"
|
|
"Or set GOOGLE_SHEETS_CREDS env var to its location."
|
|
)
|
|
sys.exit(1)
|
|
|
|
flow = InstalledAppFlow.from_client_secrets_file(str(creds_file), SCOPES)
|
|
creds = flow.run_local_server(port=0)
|
|
_save_creds(creds)
|
|
print(f"Authenticated successfully. Token saved to {get_token_dir() / 'token.json'}")
|
|
|
|
|
|
def cmd_status():
|
|
creds = _load_creds()
|
|
if not creds:
|
|
print("Not authenticated. Run: python .agents/skills/google-sheets-automation/scripts/auth.py login")
|
|
sys.exit(1)
|
|
if not creds.valid:
|
|
if creds.expired and creds.refresh_token:
|
|
creds.refresh(Request())
|
|
_save_creds(creds)
|
|
print("Token was expired; refreshed successfully.")
|
|
else:
|
|
print("Token is invalid. Re-authenticate: python .agents/skills/google-sheets-automation/scripts/auth.py login")
|
|
sys.exit(1)
|
|
print(f"Authenticated as: {creds.token[:20]}...")
|
|
print(f"Expires at: {creds.expiry}")
|
|
|
|
|
|
def cmd_logout():
|
|
token_file = get_token_dir() / "token.json"
|
|
if token_file.exists():
|
|
token_file.unlink()
|
|
if HAS_KEYRING:
|
|
try:
|
|
keyring.delete_password(SERVICE_NAME, "token")
|
|
except keyring.errors.PasswordDeleteError:
|
|
pass
|
|
print("Logged out. Token deleted.")
|
|
|
|
|
|
def get_credentials():
|
|
creds = _load_creds()
|
|
if not creds:
|
|
print("Not authenticated. Run: python .agents/skills/google-sheets-automation/scripts/auth.py login", file=sys.stderr)
|
|
sys.exit(1)
|
|
if not creds.valid:
|
|
if creds.expired and creds.refresh_token:
|
|
creds.refresh(Request())
|
|
_save_creds(creds)
|
|
else:
|
|
print("Token is invalid. Re-authenticate: python .agents/skills/google-sheets-automation/scripts/auth.py login", file=sys.stderr)
|
|
sys.exit(1)
|
|
return creds
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Google Sheets Auth")
|
|
parser.add_argument("command", choices=["login", "status", "logout"])
|
|
args = parser.parse_args()
|
|
|
|
if args.command == "login":
|
|
cmd_login()
|
|
elif args.command == "status":
|
|
cmd_status()
|
|
elif args.command == "logout":
|
|
cmd_logout()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|