Spaces:
Sleeping
Sleeping
| """ | |
| System API - Kiro status, paths, configuration | |
| """ | |
| from fastapi import APIRouter, HTTPException | |
| from pydantic import BaseModel | |
| from typing import Optional, List | |
| import platform | |
| import os | |
| from services.kiro_service import KiroService | |
| from core.kiro_config import get_kiro_info, get_kiro_version, get_machine_id | |
| from core.paths import get_paths | |
| from core.config import get_config | |
| router = APIRouter() | |
| kiro_service = KiroService() | |
| class KiroStatus(BaseModel): | |
| installed: bool | |
| running: bool | |
| version: Optional[str] = None | |
| installPath: Optional[str] = None | |
| currentAccount: Optional[str] = None | |
| tokenValid: bool = False | |
| class SystemInfo(BaseModel): | |
| platform: str | |
| osVersion: str | |
| kiroVersion: str | |
| machineId: str | |
| userAgent: str | |
| storagePath: Optional[str] = None | |
| tokensPath: str | |
| backupsPath: str | |
| class PathsInfo(BaseModel): | |
| tokensDir: str | |
| backupsDir: str | |
| kiroStorage: Optional[str] = None | |
| kiroStateDb: Optional[str] = None | |
| customMachineIdFile: str | |
| async def get_kiro_status(): | |
| """Get Kiro IDE status""" | |
| status = kiro_service.get_status() | |
| return KiroStatus( | |
| installed=status.installed, | |
| running=status.running, | |
| version=status.version, | |
| installPath=str(status.install_path) if status.install_path else None, | |
| currentAccount=status.current_account, | |
| tokenValid=status.token_valid | |
| ) | |
| async def start_kiro(): | |
| """Start Kiro IDE""" | |
| try: | |
| kiro_service.start() | |
| return {"success": True, "message": "Kiro started"} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def stop_kiro(): | |
| """Stop Kiro IDE""" | |
| if kiro_service.stop(): | |
| return {"success": True, "message": "Kiro stopped"} | |
| else: | |
| raise HTTPException(status_code=500, detail="Failed to stop Kiro") | |
| async def restart_kiro(): | |
| """Restart Kiro IDE""" | |
| try: | |
| kiro_service.restart() | |
| return {"success": True, "message": "Kiro restarted"} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_system_info(): | |
| """Get system and Kiro configuration info""" | |
| paths = get_paths() | |
| kiro_info = get_kiro_info() | |
| return SystemInfo( | |
| platform=platform.system(), | |
| osVersion=platform.version(), | |
| kiroVersion=kiro_info['version'], | |
| machineId=kiro_info['machine_id'], | |
| userAgent=kiro_info['user_agent'], | |
| storagePath=kiro_info['storage_path'], | |
| tokensPath=str(paths.tokens_dir), | |
| backupsPath=str(paths.backups_dir) | |
| ) | |
| async def get_paths_info(): | |
| """Get all relevant paths""" | |
| paths = get_paths() | |
| from core.kiro_config import get_custom_machine_id_path | |
| return PathsInfo( | |
| tokensDir=str(paths.tokens_dir), | |
| backupsDir=str(paths.backups_dir), | |
| kiroStorage=str(paths.kiro_storage_json) if paths.kiro_storage_json else None, | |
| kiroStateDb=str(paths.kiro_state_db) if paths.kiro_state_db else None, | |
| customMachineIdFile=str(get_custom_machine_id_path()) | |
| ) | |
| async def health_check(): | |
| """Health check with detailed status""" | |
| paths = get_paths() | |
| kiro_status = kiro_service.get_status() | |
| return { | |
| "status": "ok", | |
| "kiro": { | |
| "installed": kiro_status.installed, | |
| "running": kiro_status.running, | |
| "version": kiro_status.version | |
| }, | |
| "paths": { | |
| "tokensExist": paths.tokens_dir.exists(), | |
| "backupsExist": paths.backups_dir.exists() | |
| } | |
| } | |
| class ImapSettings(BaseModel): | |
| server: str | |
| user: str | |
| password: str | |
| domain: str | |
| hasDefaults: bool | |
| async def get_imap_defaults(): | |
| """ | |
| Get default IMAP settings from .env file. | |
| Used when user hasn't configured their own catch-all. | |
| """ | |
| config = get_config() | |
| # Get from environment (loaded from .env) | |
| server = os.environ.get('IMAP_SERVER', config.imap.host) | |
| user = os.environ.get('IMAP_USER', config.imap.email) | |
| password = os.environ.get('IMAP_PASSWORD', config.imap.password) | |
| domain = os.environ.get('EMAIL_DOMAIN', config.registration.email_domain) | |
| has_defaults = bool(server and user and password and domain) | |
| return ImapSettings( | |
| server=server or '', | |
| user=user or '', | |
| password=password or '', | |
| domain=domain or '', | |
| hasDefaults=has_defaults | |
| ) | |
| class ImapSettingsUpdate(BaseModel): | |
| server: str | |
| user: str | |
| password: str | |
| domain: str | |
| async def save_imap_settings(settings: ImapSettingsUpdate): | |
| """ | |
| Save IMAP settings to .env file. | |
| This allows web UI to persist settings. | |
| """ | |
| from pathlib import Path | |
| # Get .env path | |
| autoreg_dir = Path(__file__).parent.parent.parent | |
| env_file = autoreg_dir / '.env' | |
| # Read existing .env or create new | |
| env_content = {} | |
| if env_file.exists(): | |
| with open(env_file, 'r') as f: | |
| for line in f: | |
| line = line.strip() | |
| if line and not line.startswith('#') and '=' in line: | |
| key, value = line.split('=', 1) | |
| env_content[key.strip()] = value.strip() | |
| # Update with new settings | |
| env_content['IMAP_SERVER'] = settings.server | |
| env_content['IMAP_USER'] = settings.user | |
| env_content['IMAP_PASSWORD'] = settings.password | |
| env_content['EMAIL_DOMAIN'] = settings.domain | |
| # Write back | |
| with open(env_file, 'w') as f: | |
| for key, value in env_content.items(): | |
| f.write(f'{key}={value}\n') | |
| # Update environment variables for current session | |
| os.environ['IMAP_SERVER'] = settings.server | |
| os.environ['IMAP_USER'] = settings.user | |
| os.environ['IMAP_PASSWORD'] = settings.password | |
| os.environ['EMAIL_DOMAIN'] = settings.domain | |
| return {"success": True, "message": "Settings saved"} | |