Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Kiro Lag Fixer - автоматическая диагностика и исправление лагов. | |
| Проверяет: | |
| 1. Hardware acceleration (SwiftShader = медленно) | |
| 2. Тяжёлые расширения | |
| 3. Утечки памяти в webview | |
| 4. Файловые watcher'ы (node_modules и т.д.) | |
| 5. Telemetry и другие фоновые процессы | |
| Usage: | |
| python kiro_fix_lags.py --diagnose # Только диагностика | |
| python kiro_fix_lags.py --fix # Применить исправления | |
| """ | |
| import argparse | |
| import json | |
| import os | |
| import subprocess | |
| import sys | |
| from dataclasses import dataclass | |
| from pathlib import Path | |
| from typing import Optional | |
| try: | |
| import psutil | |
| except ImportError: | |
| print("❌ Установи psutil: pip install psutil") | |
| sys.exit(1) | |
| class DiagnosticResult: | |
| """Результат диагностики.""" | |
| issue: str | |
| severity: str # "critical", "warning", "info" | |
| description: str | |
| fix: Optional[str] = None | |
| auto_fixable: bool = False | |
| class KiroLagDiagnostic: | |
| """Диагностика и исправление лагов Kiro.""" | |
| def __init__(self): | |
| self.kiro_data = Path.home() / "AppData" / "Roaming" / "Kiro" | |
| self.settings_file = self.kiro_data / "User" / "settings.json" | |
| self.argv_file = self.kiro_data / "argv.json" | |
| self.results: list[DiagnosticResult] = [] | |
| def get_kiro_processes(self) -> list[psutil.Process]: | |
| """Получает все процессы Kiro.""" | |
| processes = [] | |
| for proc in psutil.process_iter(['name', 'cmdline', 'memory_info', 'cpu_times']): | |
| try: | |
| if proc.info['name'] and 'kiro' in proc.info['name'].lower(): | |
| processes.append(proc) | |
| except (psutil.NoSuchProcess, psutil.AccessDenied): | |
| continue | |
| return processes | |
| def check_memory_usage(self): | |
| """Проверка потребления памяти.""" | |
| processes = self.get_kiro_processes() | |
| total_mem_gb = sum(p.memory_info().rss for p in processes) / (1024**3) | |
| if total_mem_gb > 8: | |
| self.results.append(DiagnosticResult( | |
| issue="Критическое потребление памяти", | |
| severity="critical", | |
| description=f"Kiro использует {total_mem_gb:.1f} GB RAM. Это ненормально!", | |
| fix="Перезапусти Kiro или закрой лишние окна/расширения", | |
| auto_fixable=False | |
| )) | |
| elif total_mem_gb > 4: | |
| self.results.append(DiagnosticResult( | |
| issue="Высокое потребление памяти", | |
| severity="warning", | |
| description=f"Kiro использует {total_mem_gb:.1f} GB RAM", | |
| fix="Рекомендуется перезапустить Extension Host (Ctrl+Shift+P → Restart Extension Host)", | |
| auto_fixable=False | |
| )) | |
| def check_gpu_acceleration(self): | |
| """Проверка hardware acceleration.""" | |
| processes = self.get_kiro_processes() | |
| for proc in processes: | |
| try: | |
| cmdline = " ".join(proc.cmdline()).lower() | |
| if "--type=gpu-process" in cmdline and "swiftshader" in cmdline: | |
| self.results.append(DiagnosticResult( | |
| issue="Software rendering (SwiftShader)", | |
| severity="critical", | |
| description="GPU acceleration отключён! Kiro использует медленный software rendering", | |
| fix="Включить hardware acceleration в argv.json", | |
| auto_fixable=True | |
| )) | |
| return | |
| except (psutil.NoSuchProcess, psutil.AccessDenied): | |
| continue | |
| def check_settings(self): | |
| """Проверка settings.json на проблемные настройки.""" | |
| if not self.settings_file.exists(): | |
| return | |
| try: | |
| with open(self.settings_file, 'r', encoding='utf-8') as f: | |
| settings = json.load(f) | |
| # Hardware acceleration | |
| if settings.get("disable-hardware-acceleration") is True: | |
| self.results.append(DiagnosticResult( | |
| issue="Hardware acceleration отключён", | |
| severity="critical", | |
| description="В настройках отключено аппаратное ускорение", | |
| fix='Удалить "disable-hardware-acceleration": true из settings.json', | |
| auto_fixable=True | |
| )) | |
| # Telemetry | |
| if settings.get("telemetry.telemetryLevel") != "off": | |
| self.results.append(DiagnosticResult( | |
| issue="Telemetry включена", | |
| severity="info", | |
| description="Телеметрия может замедлять работу", | |
| fix='Установить "telemetry.telemetryLevel": "off"', | |
| auto_fixable=True | |
| )) | |
| # File watchers | |
| watcher_exclude = settings.get("files.watcherExclude", {}) | |
| if "**/node_modules/**" not in watcher_exclude: | |
| self.results.append(DiagnosticResult( | |
| issue="node_modules не исключены из watcher", | |
| severity="warning", | |
| description="Kiro следит за изменениями в node_modules (медленно!)", | |
| fix='Добавить "**/node_modules/**": true в files.watcherExclude', | |
| auto_fixable=True | |
| )) | |
| except Exception as e: | |
| print(f"⚠️ Не удалось прочитать settings.json: {e}") | |
| def check_argv(self): | |
| """Проверка argv.json.""" | |
| if not self.argv_file.exists(): | |
| return | |
| try: | |
| with open(self.argv_file, 'r', encoding='utf-8') as f: | |
| argv = json.load(f) | |
| # Проверка на disable-gpu | |
| if argv.get("disable-gpu") is True: | |
| self.results.append(DiagnosticResult( | |
| issue="GPU полностью отключён", | |
| severity="critical", | |
| description="В argv.json установлен disable-gpu", | |
| fix='Удалить "disable-gpu": true из argv.json', | |
| auto_fixable=True | |
| )) | |
| except Exception as e: | |
| print(f"⚠️ Не удалось прочитать argv.json: {e}") | |
| def check_extension_host(self): | |
| """Проверка Extension Host на утечки памяти.""" | |
| processes = self.get_kiro_processes() | |
| for proc in processes: | |
| try: | |
| cmdline = " ".join(proc.cmdline()).lower() | |
| if "node.mojom.nodeservice" in cmdline: | |
| mem_mb = proc.memory_info().rss / (1024**2) | |
| if mem_mb > 1500: | |
| self.results.append(DiagnosticResult( | |
| issue="Extension Host утечка памяти", | |
| severity="critical", | |
| description=f"Extension Host использует {mem_mb:.0f} MB (PID {proc.pid})", | |
| fix="Проверь расширения: Ctrl+Shift+P → Developer: Show Running Extensions", | |
| auto_fixable=False | |
| )) | |
| elif mem_mb > 800: | |
| self.results.append(DiagnosticResult( | |
| issue="Extension Host тяжёлый", | |
| severity="warning", | |
| description=f"Extension Host использует {mem_mb:.0f} MB", | |
| fix="Отключи ненужные расширения", | |
| auto_fixable=False | |
| )) | |
| except (psutil.NoSuchProcess, psutil.AccessDenied): | |
| continue | |
| def apply_fixes(self): | |
| """Применяет автоматические исправления.""" | |
| fixed = [] | |
| # Исправление settings.json | |
| if self.settings_file.exists(): | |
| try: | |
| with open(self.settings_file, 'r', encoding='utf-8') as f: | |
| settings = json.load(f) | |
| modified = False | |
| # Удалить disable-hardware-acceleration | |
| if settings.get("disable-hardware-acceleration") is True: | |
| del settings["disable-hardware-acceleration"] | |
| modified = True | |
| fixed.append("✅ Включён hardware acceleration") | |
| # Отключить telemetry | |
| if settings.get("telemetry.telemetryLevel") != "off": | |
| settings["telemetry.telemetryLevel"] = "off" | |
| modified = True | |
| fixed.append("✅ Отключена telemetry") | |
| # Исключить node_modules из watcher | |
| if "files.watcherExclude" not in settings: | |
| settings["files.watcherExclude"] = {} | |
| watcher_exclude = settings["files.watcherExclude"] | |
| if "**/node_modules/**" not in watcher_exclude: | |
| watcher_exclude["**/node_modules/**"] = True | |
| watcher_exclude["**/.git/objects/**"] = True | |
| watcher_exclude["**/.git/subtree-cache/**"] = True | |
| watcher_exclude["**/node_modules/*/**"] = True | |
| modified = True | |
| fixed.append("✅ Исключены node_modules из file watcher") | |
| if modified: | |
| # Бэкап | |
| backup = self.settings_file.with_suffix('.json.backup') | |
| with open(backup, 'w', encoding='utf-8') as f: | |
| json.dump(settings, f, indent=2) | |
| # Сохранить | |
| with open(self.settings_file, 'w', encoding='utf-8') as f: | |
| json.dump(settings, f, indent=2) | |
| print(f"📝 Бэкап сохранён: {backup}") | |
| except Exception as e: | |
| print(f"❌ Ошибка при исправлении settings.json: {e}") | |
| # Исправление argv.json | |
| if self.argv_file.exists(): | |
| try: | |
| with open(self.argv_file, 'r', encoding='utf-8') as f: | |
| argv = json.load(f) | |
| if argv.get("disable-gpu") is True: | |
| del argv["disable-gpu"] | |
| with open(self.argv_file, 'w', encoding='utf-8') as f: | |
| json.dump(argv, f, indent=2) | |
| fixed.append("✅ Включён GPU в argv.json") | |
| except Exception as e: | |
| print(f"❌ Ошибка при исправлении argv.json: {e}") | |
| return fixed | |
| def run_diagnosis(self): | |
| """Запускает полную диагностику.""" | |
| print("🔍 Диагностика лагов Kiro...\n") | |
| self.check_memory_usage() | |
| self.check_gpu_acceleration() | |
| self.check_settings() | |
| self.check_argv() | |
| self.check_extension_host() | |
| return self.results | |
| def print_results(self): | |
| """Выводит результаты диагностики.""" | |
| if not self.results: | |
| print("✅ Проблем не обнаружено!") | |
| return | |
| critical = [r for r in self.results if r.severity == "critical"] | |
| warnings = [r for r in self.results if r.severity == "warning"] | |
| info = [r for r in self.results if r.severity == "info"] | |
| if critical: | |
| print("🔴 КРИТИЧЕСКИЕ ПРОБЛЕМЫ:") | |
| for r in critical: | |
| print(f"\n • {r.issue}") | |
| print(f" {r.description}") | |
| if r.fix: | |
| print(f" 💡 {r.fix}") | |
| if r.auto_fixable: | |
| print(f" ⚡ Можно исправить автоматически") | |
| if warnings: | |
| print("\n🟡 ПРЕДУПРЕЖДЕНИЯ:") | |
| for r in warnings: | |
| print(f"\n • {r.issue}") | |
| print(f" {r.description}") | |
| if r.fix: | |
| print(f" 💡 {r.fix}") | |
| if info: | |
| print("\n🔵 ИНФОРМАЦИЯ:") | |
| for r in info: | |
| print(f"\n • {r.issue}") | |
| print(f" {r.description}") | |
| if r.fix: | |
| print(f" 💡 {r.fix}") | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Kiro Lag Diagnostic & Fixer") | |
| parser.add_argument('--diagnose', action='store_true', help='Только диагностика') | |
| parser.add_argument('--fix', action='store_true', help='Применить исправления') | |
| args = parser.parse_args() | |
| diagnostic = KiroLagDiagnostic() | |
| diagnostic.run_diagnosis() | |
| diagnostic.print_results() | |
| if args.fix: | |
| print("\n" + "="*60) | |
| print("🔧 Применение исправлений...") | |
| print("="*60 + "\n") | |
| fixed = diagnostic.apply_fixes() | |
| if fixed: | |
| for fix in fixed: | |
| print(fix) | |
| print("\n⚠️ ВАЖНО: Перезапусти Kiro чтобы изменения вступили в силу!") | |
| else: | |
| print("Нет автоматических исправлений для применения") | |
| elif not args.diagnose: | |
| # По умолчанию только диагностика | |
| auto_fixable = [r for r in diagnostic.results if r.auto_fixable] | |
| if auto_fixable: | |
| print("\n" + "="*60) | |
| print(f"💡 Найдено {len(auto_fixable)} проблем с автоматическим исправлением") | |
| print(" Запусти с --fix чтобы применить исправления") | |
| print("="*60) | |
| if __name__ == "__main__": | |
| main() | |