Dieser Commit ist enthalten in:
Claude Project Manager
2025-09-20 21:31:04 +02:00
Commit 6b9b6d4f20
1821 geänderte Dateien mit 348527 neuen und 0 gelöschten Zeilen

206
main.py Normale Datei
Datei anzeigen

@ -0,0 +1,206 @@
#!/usr/bin/env python3
"""
SkillMate - Windows-optimierter Haupteinstiegspunkt
"""
import os
import sys
import subprocess
import time
import webbrowser
import signal
import atexit
import argparse
from pathlib import Path
from typing import Optional, List
class SkillMateStarter:
def __init__(self, mode: str = 'dev'):
self.processes = []
self.base_dir = Path(__file__).parent.absolute()
self.mode = mode # 'dev' oder 'prod'
# Ports (Backend/Frontend/Admin)
self.backend_port = int(os.environ.get('PORT', '3004'))
self.frontend_port = 5173
self.admin_port = 5174
# Registriere Cleanup-Handler
atexit.register(self.cleanup)
if sys.platform != 'win32':
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
def signal_handler(self, signum, frame):
"""Handle Strg+C und andere Signale"""
print("\n\n🛑 SkillMate wird beendet...")
self.cleanup()
sys.exit(0)
def cleanup(self):
"""Beende alle gestarteten Prozesse"""
for process in self.processes:
try:
if process.poll() is None: # Prozess läuft noch
if sys.platform == 'win32':
subprocess.call(['taskkill', '/F', '/T', '/PID', str(process.pid)],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
else:
process.terminate()
process.wait(timeout=5)
except:
pass
# Sicherheitshalber Ports freigeben, falls noch Prozesse hängen
if sys.platform == 'win32':
for p in [self.backend_port, self.frontend_port, self.admin_port]:
self._free_port_windows(p)
def _popen_new_console(self, workdir: Path, command: str) -> Optional[subprocess.Popen]:
try:
creationflag = getattr(subprocess, 'CREATE_NEW_CONSOLE', 0x00000010)
p = subprocess.Popen(
["cmd", "/k", command],
cwd=str(workdir),
creationflags=creationflag,
)
self.processes.append(p)
return p
except Exception as e:
print(f"❌ Konnte Konsole nicht starten: {e}")
return None
def _free_port_windows(self, port: int):
"""Versucht Prozesse auf Port zu beenden (Windows)."""
try:
# Finde Zeilen mit Port
out = subprocess.check_output(f'netstat -ano | findstr :{port}', shell=True, text=True, stderr=subprocess.DEVNULL)
pids: List[str] = []
for line in out.splitlines():
parts = line.split()
if parts:
pid = parts[-1]
if pid.isdigit():
pids.append(pid)
# Einzigartige PIDs killen
for pid in sorted(set(pids)):
try:
subprocess.call(["taskkill", "/PID", pid, "/F"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception:
pass
except subprocess.CalledProcessError:
# Kein Treffer → Port frei
pass
def check_node_npm(self):
"""Prüfe ob Node.js und npm installiert sind"""
try:
# Windows-spezifische Prüfung
if sys.platform == 'win32':
subprocess.run(["node", "--version"],
capture_output=True,
check=True,
shell=True)
subprocess.run(["npm", "--version"],
capture_output=True,
check=True,
shell=True)
else:
subprocess.run(["node", "--version"], capture_output=True, check=True)
subprocess.run(["npm", "--version"], capture_output=True, check=True)
return True
except (subprocess.CalledProcessError, FileNotFoundError):
print("❌ Node.js und npm müssen installiert sein!")
print(" Bitte installieren Sie Node.js von: https://nodejs.org/")
return False
def start_services_windows(self):
"""Starte alle Services in Windows mit separaten CMD-Fenstern"""
print("🚀 Starte SkillMate Services...")
# Ports freimachen (wenn vorherige Läufe hingen blieben)
for p in [self.backend_port, self.frontend_port, self.admin_port]:
self._free_port_windows(p)
# Backend
backend_dir = self.base_dir / "backend"
if self.mode == 'dev':
self._popen_new_console(backend_dir, "npm run dev")
else:
# Produktionsstart: Build & Start
self._popen_new_console(backend_dir, "cmd /c npm run build && npm start")
# Warte bis Backend bereit ist
print(" Warte auf Backend...")
time.sleep(5)
# Frontend
frontend_dir = self.base_dir / "frontend"
if self.mode == 'dev':
self._popen_new_console(frontend_dir, f"npm run dev -- --port {self.frontend_port}")
else:
self._popen_new_console(frontend_dir, f"cmd /c npm run build && npm run preview -- --port {self.frontend_port}")
# Admin Panel (optional)
admin_dir = self.base_dir / "admin-panel"
if admin_dir.exists():
if self.mode == 'dev':
self._popen_new_console(admin_dir, f"npm run dev -- --port {self.admin_port}")
else:
self._popen_new_console(admin_dir, f"cmd /c npm run build && npm run preview -- --port {self.admin_port}")
print("\n✨ SkillMate läuft!")
print("\n📍 Zugriff:")
print(f" - Frontend: http://localhost:{self.frontend_port}")
print(f" - Backend: http://localhost:{self.backend_port}")
if admin_dir.exists():
print(f" - Admin: http://localhost:{self.admin_port}")
# Öffne Frontend im Browser
time.sleep(3)
webbrowser.open(f"http://localhost:{self.frontend_port}")
print("\n⚡ Schließen Sie dieses Fenster, um SkillMate zu beenden")
def run(self):
"""Hauptausführungsmethode"""
print("🎯 SkillMate wird gestartet...\n")
# Prüfe Voraussetzungen
if not self.check_node_npm():
return False
# Windows-spezifischer Start
if sys.platform == 'win32':
self.start_services_windows()
# Halte das Hauptfenster offen
try:
input("\nDrücken Sie Enter zum Beenden...")
except KeyboardInterrupt:
pass
else:
print("❌ Dieses Skript ist für Windows optimiert.")
print(" Nutzen Sie 'python main.py' für andere Systeme.")
return False
return True
def main():
"""Haupteinstiegspunkt"""
parser = argparse.ArgumentParser(description='SkillMate Starter')
parser.add_argument('--mode', choices=['dev', 'prod'], default='dev', help='Startmodus: dev oder prod')
args = parser.parse_args()
starter = SkillMateStarter(mode=args.mode)
try:
success = starter.run()
if not success:
sys.exit(1)
except Exception as e:
print(f"\n❌ Unerwarteter Fehler: {e}")
starter.cleanup()
sys.exit(1)
if __name__ == "__main__":
main()