This repository has been archived on 2026-07-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mission-control/app.py
T
Hitonabi e02a1889b2 feat(memory): v7 — Gedächtnis-Layer mit MCP-Integration
SQLite-basiertes Memory-System fuer persistentes Gedaechtnis ueber Sessions.
Cline, OpenCode und Claude Code teilen denselben Speicher via MCP-Server.

- routers/memory.py: CRUD + Export-Endpoint (GET/POST/PUT/DELETE /api/memory)
- mcp_memory.py: stdio MCP-Server — Tools: get/add/search/update/delete_memory
- MemoryPanel.svelte: Gedaechtnis-Tab mit Filter, Inline-Edit, Add-Formular
- ConnectPanel.svelte: Gedaechtnis-MCP Setup-Guide (Cline/OpenCode/Bosgame)
- Temporaere Eintraege (ephemeral) nach 7 Tagen automatisch geloescht

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 13:30:47 +02:00

82 lines
2.8 KiB
Python

"""
Mission Control - eine schlanke Steuerzentrale fuer einen lokalen llama-swap Stack.
Dieser Einstieg haelt nur noch das Geruest zusammen: er baut die FastAPI-App,
haengt die Router ein und liefert das statische UI aus. Die eigentliche Logik
liegt nach Concern getrennt in:
- config.py Env-Vars / Konstanten
- auth.py optionale Token-Auth
- jobengine.py Hintergrund-Jobs mit Live-Log
- llamaswap.py Reden mit llama-swap + config.yaml lesen/schreiben
- routers/* ein Router je Bereich (models, jobs, maintenance, ...)
Bewusst KISS: kein Build-Schritt, kein Framework ueber FastAPI hinaus, keine DB.
Neue Bereiche kommen als routers/<bereich>.py + static/js/panels/<bereich>.js dazu.
"""
from pathlib import Path
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse, JSONResponse, Response
from fastapi.staticfiles import StaticFiles
from routers import jobs, maintenance, memory, models, system, cookbook, integration, news
app = FastAPI(title="Mission Control")
@app.middleware("http")
async def _no_cache_static(request, call_next):
"""UI + statische Module immer revalidieren lassen (304 wenn unveraendert),
damit Aenderungen nach einem rsync sofort wirken und kein Stale-JS haengen bleibt."""
response = await call_next(request)
path = request.url.path
if path == "/" or path.startswith("/static"):
response.headers["Cache-Control"] = "no-cache"
return response
app.include_router(models.router)
app.include_router(jobs.router)
app.include_router(maintenance.router)
app.include_router(system.router)
app.include_router(cookbook.router)
app.include_router(integration.router)
app.include_router(news.router)
app.include_router(memory.router)
_STATIC = Path(__file__).parent / "static"
@app.get("/")
def index():
return FileResponse(_STATIC / "index.html")
_FAVICON = (
b"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>"
b"<rect width='32' height='32' rx='7' fill='#0f1720'/>"
b"<circle cx='16' cy='16' r='8' fill='none' stroke='#2dd4bf' stroke-width='3'/>"
b"<circle cx='16' cy='16' r='2.5' fill='#2dd4bf'/></svg>"
)
@app.get("/favicon.ico")
def favicon():
return Response(content=_FAVICON, media_type="image/svg+xml")
app.mount("/static", StaticFiles(directory=_STATIC), name="static")
@app.exception_handler(HTTPException)
def _http_exc(_req, exc: HTTPException):
return JSONResponse(status_code=exc.status_code, content={"error": exc.detail})
@app.exception_handler(Exception)
def _any_exc(_req, exc: Exception):
"""Unerwartete Fehler als lesbare Meldung ans (vertrauenswuerdige LAN-)UI geben,
statt nur einen generischen 500 ohne Hinweis. Erleichtert Anfaengern die Diagnose."""
return JSONResponse(status_code=500, content={"error": str(exc) or exc.__class__.__name__})