Commit Graph
216 Commits
Author SHA1 Message Date
duffyduckandClaude Opus 5.5 c511a6b5ae feat(diagnostic): eigene Dialoge statt alert/confirm/prompt
Alle 43 confirm(), 7 prompt() und 71 alert() der Diagnostic laufen jetzt
ueber uiConfirm/uiPrompt/uiAlert — gleicher Stil wie der Aufteilen-Dialog:
erster Absatz als Ueberschrift, Rest als Erklaerung, Esc/Klick daneben =
Abbrechen, Enter = OK. Rueckfragen zu Loeschen/Entfernen/Zuruecksetzen
bekommen einen roten "Ja, ausfuehren"-Knopf. Nebenbei faellt die Browser-
Sperre "weitere Dialoge verhindern" weg, an der runDiskCleanup frueher hing.

Die 16 Funktionen, die noch nicht async waren, sind es jetzt (alles
onclick/onchange-Handler, kein Aufrufer nutzt einen Rueckgabewert).
Getestet in headless Chromium: OK/Abbrechen/Esc/Enter, Eingabe, Hinweis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:31:28 +01:00
duffyduckandClaude Opus 5.5 87f521ee61 feat(llm): Downloads parallel, abbrechbar; heruntergeladene Modelle loeschen
llm-adapter:
- Paralleler Download: llama.cpp zieht ueber EINE Verbindung (oft 1-50 MB/s,
  auch bei 1 Gbit). Die Box holt fehlende Dateien jetzt vorher selbst in
  64-MB-Stuecken ueber LLM_DOWNLOAD_CONNECTIONS (Standard 8) Verbindungen,
  prueft die sha256 und legt sie im HF-Cache-Layout ab, das llama.cpp selbst
  benutzt (blobs/<sha256>, snapshots/<commit>/<datei>, refs/main). Die Karte
  bleibt waehrenddessen beim alten Modell. Scheitert es, laedt llama.cpp wie
  bisher selbst. Fortschritt zaehlt bei sparse-Dateien nur geschriebene Bytes.
- Abbrechen: llm_remove_model mit cancel=true (kein neuer Typ → RVS-Allow-List
  unveraendert). Waehrend des Downloads: Stopp + halbe Datei weg, Karte
  unveraendert. Waehrend llama.cpp laedt: wie ein Fehlschlag → Karte zurueck.
  Laeuft nichts mehr, schliesst die Antwort den haengenden Eintrag.
- Loeschen: llm_remove_model mit deleteFiles=true entfernt das Repo aus dem
  Cache — nicht, solange es auf einer Karte liegt oder geladen wird.
- worker_hello meldet "disk": freier Platz + heruntergeladene Modelle je Repo.

Diagnostic: Abbrechen-Knopf je laufendem Download; im Katalog "auf ki-box ·
18,6 GB" mit Loeschen-Knopf und eine Zeile mit dem freien Platz je Box.

Getestet gegen HuggingFace (ggml-org/tiny-llamas, 4 Verbindungen, 2-MB-
Stuecke: Layout + Pruefsumme + Abbruch) und Loeschen inkl. Sperren.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:21:04 +01:00
duffyduckandClaude Opus 5.5 739ab85deb feat(llm): Speicherplatz vor dem Download pruefen, klarer Aufteilen-Dialog
llm-adapter: Vor jeder Aenderung an Registry/Belegung rechnet die Box aus,
was vom Modell noch fehlt (fertige Blobs zaehlen nicht), und vergleicht es
mit dem freien Platz minus Puffer (LLM_DISK_RESERVE_GB, Standard 2). Reicht
es nicht, werden halbe Downloads, an denen seit 30 min niemand schreibt,
geloescht und neu gerechnet; reicht es dann immer noch nicht, bricht das
Laden mit klarer Meldung im Download-Fenster ab ("braucht ca. X GB, frei
sind Y GB"). Frueher brach llama.cpp mitten im Download ab, und der Grund
kam ueber llama-swap nicht an.

Diagnostic: Die MoE-Frage war ein confirm(), bei dem "Abbrechen" "ganz auf
die Karte laden" hiess. Jetzt ein Dialog mit drei Knoepfen: Aufteilen
(empfohlen) / Ganz auf die Karte / Abbrechen (laedt nichts). Esc und Klick
daneben brechen ab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:12:42 +01:00
duffyduckandClaude Opus 5.5 1e5afe7f65 feat(diagnostic): Karten-Modellwahl als Liste mit Suchfeld oben drin
Statt Suchfeld neben einem normalen Dropdown (Tippen → Liste oeffnen →
passt nicht → zurueck ins Feld) oeffnet ein Klick jetzt eine Liste mit dem
Suchfeld oben. Tippen filtert sofort, Auswahl per Klick oder Pfeiltasten +
Enter, Esc / Klick daneben / Scrollen schliesst. Das versteckte <select>
haelt weiter Wert und onchange (onLlmCardSelect unveraendert).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:03:09 +01:00
duffyduckandClaude Opus 5.5 e219382a51 feat(diagnostic): Suche im Modell-Katalog und in den Karten-Dropdowns
- Modell-Katalog: Suchfeld (erscheint, sobald die Liste geladen ist),
  Teilsuche ueber Name, Beschreibung, Repo und Quantisierung; mehrere
  Woerter muessen alle vorkommen.
- LLM-Karten: Suchfeld ueber jedem Modell-Dropdown blendet nicht passende
  Modelle aus; "— leer —" und das geladene Modell bleiben sichtbar.
- Fix: Ein offenes Karten-Dropdown klappte nach ein paar Sekunden zu, weil
  jedes worker_update die Liste neu zeichnete. Solange ein Dropdown oder
  Suchfeld darin den Fokus hat, wird das Neuzeichnen aufgeschoben und beim
  Verlassen nachgeholt (gilt auch fuer die Ziel-Karte im Katalog).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 14:56:03 +01:00
duffyduckandClaude Opus 5.5 8576d4676e feat(diagnostic): Bestenlisten — Never Code Alone (lokale Coder-Modelle) ergaenzt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 10:23:33 +01:00
duffyduckandClaude Opus 5.5 dd5d1fd2cb feat(llm): grosse MoE-Modelle auf kleinen Karten — Experten in den Arbeitsspeicher
Bei MoE-Modellen (z.B. Qwen3-Coder-30B-A3B: 18,6 GB, davon 16,35 GB
Experten) rechnet pro Wort nur ein kleiner Teil. llama.cpp kann die
Experten in den RAM legen (--cpu-moe / --n-cpu-moe N), der Rest bleibt auf
der Karte.

Adapter:
- Registry-Feld cpuMoe: 0 = Karte, -1 = alle Experten in den RAM,
  N = die der ersten N Schichten; -2 beim Laden = automatisch aufteilen.
- Automatisch: liest nur den Kopf der GGUF bei HuggingFace (HTTP-Range,
  Tensor-Verzeichnis), rechnet Experten je Schicht + KV-Cache gegen den
  VRAM der Karte und legt so viele Experten auf die Karte wie passen
  (12 GB/32k: 16 von 48 Schichten auf der Karte, 32 im RAM).
- Kontext-Auswahl: GB-Schaetzung fuer die Karte ohne ausgelagerte Experten;
  slot meldet moe, cpuMoe, ramMB. KV-Rechnung als _kv_bytes() geteilt.

Diagnostic: MoE-Modell zu gross fuer die Karte → Rueckfrage "Experten
automatisch aufteilen?"; pro Karte Auswahl Experten: Karte / automatisch /
Arbeitsspeicher. Kontextwechsel rechnet die Aufteilung neu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 17:24:41 +01:00
duffyduckandClaude Opus 5.5 26ad872c6c feat: Belege — jede ARIA-Antwort zeigt, was sie wirklich ausgefuehrt hat
Was ARIA selbst im Proxy ausfuehrt (Bash/ssh, Read, Edit …), war nur live
sichtbar — ob sie fuer "auf Prod nachgesehen" wirklich nachgesehen hat (und
wo), liess sich hinterher nicht pruefen. Das Befehlslog gab es nur fuer die
Host-Agenten.

Proxy (proxy-patches/routes.js): start/tool_use/tool_result/end zusaetzlich
dauerhaft nach /shared/logs/aria-tools/<tag>.jsonl (30 Tage), Passwoerter,
Tokens, API-Keys, private Schluessel und Zugangsdaten in URLs geschwaerzt.

Diagnostic: 🔍 an jeder ARIA-Bubble → alle Werkzeug-Aufrufe zwischen Stefans
Frage und dieser Antwort (Befehl + Ausgabe). Hat sie nichts ausgefuehrt,
sagt das Fenster es deutlich (Stand kommt dann aus Verlauf/Gedaechtnis).
GET /api/aria-proof?ts=&project=.

Deploy: proxy --force-recreate (Patch wirkt nur beim Start), diagnostic --build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 15:42:49 +01:00
duffyduckandClaude Opus 5.5 4d590df866 docs(diagnostic): Kontext-Info genauer — Zeichen statt Seiten, grosser Kontext != besser
32k als Zeichen-Spanne (Text vs. Code, ~2,3 Zeichen je Token bei HTML/JS)
statt pauschal 20–25 Seiten. Neu: in sehr langen Verlaeufen uebersehen
Modelle eher etwas (Mitte) und jede Anfrage wird langsamer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:17:57 +01:00
duffyduckandClaude Opus 5.5 b93b62eea9 feat(brain): Compacting fuer ARIAs lokalen Modus + Erklaerung in der Info-Box
Lokal bekam ARIA starr die letzten 8 Nachrichten — alles davor war fuer das
lokale Modell weg. Neu (local_compact.py):
- Fenster nach Tokens: so viele der letzten Nachrichten, wie in ~75 % des
  Kontextfensters der Karte passen (Systemprompt + Antwort abgezogen), max.
  LOCAL_MAX_TURNS (12). Kontextfenster vom Cluster (Bridge /internal/llm-models).
- Was herausfaellt, fasst das lokale Modell im Hintergrund zum laufenden
  Notizzettel zusammen (pro Projekt, /data/local_summaries.json); er geht als
  "Bisheriger Verlauf" in den lokalen Systemprompt. Destillat ins Gedaechtnis
  laeuft unveraendert weiter. Reset des Gespraechs loescht auch den Zettel.
- Bridge/local_llm: optionale laengere Frist fuer Hintergrund-Aufrufe
  (Compacting 180 s statt der 30 s fuer schnelle Antworten).

Diagnostic: Info-Box zum Kontext erklaert Kuerzen / Compacting / Gedaechtnis
und was ARIA davon nutzt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:10:18 +01:00
duffyduckandClaude Opus 5.5 c1b06aa26a feat(diagnostic): Bestenlisten — Ranglisten + HF-Trends direkt in den Katalog
Modell-Katalog → "🏆 Bestenlisten": Fenster mit laufend gepflegten
Ranglisten nach Kategorie (Allgemein, Programmieren, Bilder erzeugen,
Lokal/Community — Arena, Artificial Analysis, LiveBench, Aider, SWE-bench,
Vellum, r/LocalLLaMA, HF), darunter "Gerade im Trend auf HuggingFace" pro
Kategorie (Allgemein / Programmieren / Bilder verstehen): nur Repos mit
ladbarem GGUF, echte Groesse + Quantisierung, "passt / zu gross" gegen die
groesste LLM-Karte, standardmaessig nur bekannte Anbieter (Trend != gut).
"In Katalog" uebernimmt das Repo; geladen wird wie gewohnt im Katalog.

Server: GET /api/llm-discover (HF trendingScore, 30 min Cache),
POST /api/llm-catalog/add.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:56:37 +01:00
duffyduckandClaude Opus 5.5 12f3cd3e55 feat(diagnostic): i-Button erklaert das Kontextfenster
Hinter jeder Token-Auswahl bei den LLM-Karten ein kleines i: oeffnet eine
Erklaerung — Arbeitsgedaechtnis pro Anfrage statt Sitzungsgedaechtnis, was
beim Ueberlauf passiert, Bild Schreibtisch/Aktenordner/Archiv, Speicherbedarf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:40:41 +01:00
duffyduckandClaude Opus 5.5 f7f9275b31 feat(diagnostic): Karten-Auslastung auch pro Box aus der Compute-Flotte
Neben "Auslastung" bei jeder Box ein "📊 Karten"-Button: dasselbe Fenster,
nur fuer diese Box (Titel zeigt den Namen).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:37:10 +01:00
duffyduckandClaude Opus 5.5 294917fe36 feat(diagnostic): Auslastung aller Grafikkarten aller KI-Boxen auf einen Blick
LLM-Karten → "📊 Auslastung": Fenster mit jeder Box und jeder Karte, live
jede Sekunde — Rechenlast, Speicher (belegt/gesamt), Temperatur, Strom,
Verlauf der letzten 2 min und was auf der Karte laeuft (LLM-Modell mit
Kontext, Whisper, F5-TTS, Voxtral).

node_stats (alle GPU-Dienste, identische Kopie) meldet im Live-Stream jetzt
zusaetzlich die Werte PRO Karte (mit uuid). Pro Box streamt bevorzugt der
LLM-Adapter (sieht alle Karten mit echter Nummer); Boxen ohne ihn: jeder
GPU-Dienst seine Karte, Nummer aus worker.gpus. Streams werden erneuert,
solange das Fenster offen ist, und beim Schliessen beendet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:36:02 +01:00
duffyduckandClaude Opus 5.5 d3f36d8292 feat(llm): Kontext-Auswahl zeigt den Grafikspeicher und geht bis zum Modell-Maximum
Der Adapter liest den Kopf der GGUF-Datei (nur Metadaten): trainiertes
Maximum (context_length) und KV-Cache pro Token — bei Sliding-Window-Modellen
(Gemma) waechst nur der globale Teil mit dem Kontext. Daraus pro Stufe eine
Schaetzung Modell + mmproj + KV (f16) + 1,4 GB Aufschlag (gemessen: Gemma 4
12B @32k geschaetzt 8,8 GB, belegt 8,77 GB).

Diagnostic: Liste kommt von der Box (statt fest 4k..128k), bis zum Maximum
des Modells (auch krumme wie 40960), mit "ca. X GB" und "passt nicht",
wenn es die Karte sprengt. Alte Box ohne Angaben: feste Liste wie bisher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:28:32 +01:00
duffyduckandClaude Opus 5.5 7b4a1f4429 feat(diagnostic): Liste, wer gerade mit dem RVS-Raum verbunden ist
Einstellungen, zwischen Runtime-Konfiguration und App-Onboarding: alle
Verbindungen im Raum des konfigurierten Tokens — Art, Name, Details,
Adresse, verbunden seit, zuletzt aktiv.

RVS merkt sich pro Verbindung, wer sie ist: aus Nachrichten, die ohnehin
fliessen (sat_hello, host_hello, worker_hello, update_check der App,
llm_cluster_*), oder aus dem neuen client_hello (Bridge, Diagnostic, App
mit Geraetename). Adresse aus X-Forwarded-For hinter einem Reverse-Proxy.
room_clients_query liefert NUR den eigenen Raum; room_clients von Clients
wird nicht weitergereicht. Typen in der Allow-List ergaenzt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:34:14 +01:00
duffyduckandClaude Opus 5.5 79a901089b feat(llm): Kontextfenster pro Karte einstellbar + Fehlerart context_exceeded
Anlass: die Software-Schmiede bekam "request (8274 tokens) exceeds the
available context size (8192 tokens)". Sie holt ctx vom Cluster zwar ab,
kuerzt aber nach einem eigenen, von Hand eingetragenen Wert (32768).

ARIA-Seite:
- Neue Fehlerart context_exceeded (statt model_error) mit promptTokens und ctx
  — Programme koennen automatisch kuerzen und nochmal senden, statt Text
  auszuwerten. llm-adapter liest es aus llama.cpps exceed_context_size_error,
  der Cluster-Router reicht es durch und wiederholt es nicht anderswo.
- Diagnostic → LLM-Karten: Kontextfenster pro Karte (4k … 128k). Laedt das
  Modell mit neuem -c; Programme sehen den neuen Wert ueber ctx. Passt es
  nicht in den Grafikspeicher, setzt die Box zurueck — jetzt inkl. Registry
  (vorher blieb bei einem Fehlschlag der zu grosse ctx in aria_models.json
  stehen und waere beim naechsten Start wieder gescheitert).
- Doku: context_exceeded, ctx kann sich aendern, "danach kuerzen, nicht nur
  anzeigen".

Getestet gegen llama-swap: Kontext 512 → 1024 (gleiche Karte), Fehlschlag
bei 65536 → Registry + Config wieder 1024, zu langer Verlauf →
context_exceeded mit promptTokens=6030, ctx=1024.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:32:37 +02:00
duffyduckandClaude Opus 5.5 9be14eef5e fix(diagnostic): Karten kommen im Browser an, lokales Modell springt nicht zurueck
1. "Die LLM-Box meldet noch keine Karten": die Box schickte die Karten-
   Belegung, aber workerList() im Diagnostic-Server gibt nur eine feste
   Feldliste an den Browser — slots stand nicht drauf. Meine UI-Tests haben
   die Flotte direkt im Browser gesetzt und sind an genau dieser Stelle
   vorbeigelaufen. Jetzt Ende-zu-Ende getestet: echter Diagnostic-Server +
   RVS + Box-Meldung → Browser (per DevTools-Protokoll gelesen).

2. Lokales Modell sprang auf "Qwen3 8B" zurueck: die Auswahl wurde gespeichert,
   aber die Seite behielt intern das alte Modell und stellte das Dropdown beim
   naechsten Lebenszeichen der Box (10 s) darauf zurueck. Dazu wie gewuenscht
   umgebaut: nur Modelle, die im Cluster geladen sind, jedes einmal, ohne
   Karte. Ist das gewaehlte gerade nirgends geladen: "(offline)" — geht
   automatisch weiter, sobald eine Box es hat. Nichts da: "kein Modell
   verfuegbar". Waehrend die Auswahl offen ist, wird nicht umgebaut.

3. "Bereit", aber Karte leer: der llm-adapter meldet pro Karte den belegten
   VRAM. Laeuft ein Modell "ready" und die Karte bleibt unter 400 MB, rechnet
   llama.cpp auf der CPU (Treiber zu alt fuer das CUDA im Image) — das sagt
   llama.cpp nicht nach aussen. Diagnostic zeigt es jetzt in Flotte,
   LLM-Karten und Modell-Auswahl ("laeuft auf der CPU").

4. bootstrap.sh: der normale Lauf meldete "✓ Treiber aktiv", auch wenn er fuer
   das LLM zu alt ist. Jetzt Warnung mit Version und dem Befehl
   (--upgrade-driver), wenn das LLM-Profil aktiv ist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:11:02 +02:00
duffyduckandClaude Opus 5.5 60f2d2e087 feat(diagnostic): pro LLM-Karte ein Dropdown — und Kontextfenster an Clients melden
Einstellungen → Modelle & KI → "LLM-Karten": fuer jede Karte, die auf einer
Box fuers LLM vorgesehen ist, ein Dropdown mit den Katalog-Modellen und
"— leer —" (entlaedt die Karte). Nur echte LLM-Karten erscheinen. Modelle,
die auf derselben Box schon auf einer anderen Karte liegen, werden nicht
angeboten; zu grosse (Katalog-Groesse > VRAM der Karte) sind als "passt
nicht" markiert. Waehrend eines Ladevorgangs ist das Dropdown gesperrt und
zeigt den Fortschritt.

Box meldet dafuer pro Karte den VRAM (nvidia-smi memory.total) und das
Kontextfenster, mit dem llama-server das Modell startet (-c).

Kontext an Clients: llm_models enthaelt jetzt "ctx". Anlass: die Software-
Schmiede rechnete mit 32768 Tokens, die Box startet die Modelle mit 8192 —
lange Auftraege waeren gescheitert oder falsch gekuerzt worden, und der Client
konnte es nicht wissen. Doku entsprechend ergaenzt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:22:06 +02:00
duffyduckandClaude Opus 5.5 a1aa90177d fix(diagnostic): Status-Meldung unten rechts immer wegklickbar
Das X war absichtlich versteckt, sobald ein Dienst einen Fehler meldete — es
erschien nur, wenn alles gruen war. Gerade eine Fehlermeldung blieb also
stehen. Jetzt ist das X immer da; Wegklicken vergisst Fehler- und
Fertig-Meldungen (sonst kaemen sie mit der naechsten Statusmeldung eines
anderen Dienstes wieder hoch), ein laufender Ladevorgang darf wiederkommen.

Dazu: httpx haengt an jeden Fehler "For more information check: <Mozilla-
Link>" — raus, in der Anzeige und im llm-adapter an der Quelle. Bei nur einer
Meldung stand das ❌ doppelt (grosses Symbol + Zeile) — jetzt einmal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 16:46:25 +02:00
duffyduckandClaude Opus 5.5 ae79d9e8f6 fix(llm): Modelle mit anderer Quantisierung laden (Gemma 4 von unsloth)
Laden von unsloth/gemma-4-12B-it-qat-GGUF scheiterte mit "500": der Katalog
trug pauschal Q4_K_M ein, das Repo hat aber nur UD-Q4_K_XL. llama-server fand
die Datei nicht und beendete sich sofort; llama-swap reicht den Grund nicht
weiter ("upstream command exited prematurely"), es kam nur "500" an.

llm-adapter: fragt vor dem Laden die Dateiliste des Repos ab. Gibt es die
gewuenschte Quantisierung nicht, nimmt er die naechstbeste aus einer festen
Reihenfolge (Q4_K_M, UD-Q4_K_XL, Q4_K_XL, Q4_K_S, IQ4_XS, …) und sagt das im
Download-Fenster an. Kein ladbares GGUF im Repo → sofortige Absage, die Karte
bleibt unberuehrt. Bild-Projektor (mmproj), MTP-Zusatzdateien und imatrix
zaehlen nicht als Modell. Endet llama-server trotzdem sofort, nennt die
Meldung die haeufigsten Gruende statt nur "500".

Diagnostic: "Von HuggingFace aktualisieren" traegt pro HF-Repo die tatsaechlich
vorhandene Quantisierung und die echte Groesse ein (bisher 0 GB) — auch bei
schon vorhandenen HF-Eintraegen. Repos ohne ladbares Modell kommen nicht mehr
in den Katalog bzw. werden als "nicht ladbar" markiert. Katalog zeigt die
Quantisierung pro Modell.

Gemma 4 selbst: llama.cpp kann es seit Juni (#24077), der Stand auf der Box ist
vom 14.08. — es lag nur an der Datei.

Getestet gegen echte HF-Repos (Gemma → UD-Q4_K_XL 6,7 GB, Qwen/Mistral bleiben
Q4_K_M) in Adapter und Diagnostic identisch, und gegen llama-swap: Ausweichen
angesagt + geladen; Repo ohne GGUF → Absage ohne Download.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 16:43:55 +02:00
duffyduckandClaude Opus 5.5 23feb3ba2d feat(llm): ein Modell pro Karte, Clients waehlen nur aus — und Doku fuer Drittprogramme
Bisher konnte jeder Client per Modellname llama-swap zum Wechseln bringen —
ein Fremdprogramm haette ARIA das Modell unter den Fuessen weggetauscht.
Jetzt:

- Jede LLM-Karte einer Box (LLM_GPUS=1,2, alt LLM_GPU=1) haelt GENAU ein
  Modell, dauerhaft. Welches, legt nur die Diagnostic fest. Karten, die nicht
  fuers LLM vorgesehen sind, tauchen beim LLM nicht auf und werden als Ziel
  abgelehnt.
- Clients (ARIA, Fremdprogramme ueber RVS, OpenHands ueber den OpenAI-Port)
  sehen nur die geladenen Modelle und laden nie: Anfrage fuer ein anderes →
  model_not_loaded mit Liste des Geladenen (RVS) bzw. HTTP 404 (OpenAI-Port).
  Nichts wird verdraengt.
- Mehrere Clients koennen dasselbe Modell gleichzeitig nutzen.

llm-adapter: Belegung in /models/aria_slots.json. Die llama-swap-Config
enthaelt nur belegte Karten: pro Modell CUDA_VISIBLE_DEVICES=<Karte>, ttl 0,
groups.swap=false, hooks.on_startup.preload. Alles gegen llama-swap
ausprobiert (zwei Modelle gleichzeitig ready, keins verdraengt, Unbekanntes
404, env kommt beim jeweiligen llama-server an). llama-swap laeuft mit
--watch-config; die frueher aufgerufenen Reload-Endpunkte (/reload,
/api/config/reload) gibt es nicht (404). Neu: llm_unload_model (Karte leeren),
llm_models_request → llm_models (Erkundung, jede Box antwortet einzeln).
Fehlgeschlagenes Laden setzt die Karte auf ihr vorheriges Modell zurueck,
sonst risse jedes Neuladen die anderen Karten mit. Uebernahme: ohne
Belegungsdatei landet LLM_MODEL auf der ersten LLM-Karte.

Compose: llama-swap sieht alle Karten (NVIDIA_VISIBLE_DEVICES=all) und
zaehlt sie wie nvidia-smi (CUDA_DEVICE_ORDER=PCI_BUS_ID); das Pinnen pro
Modell macht der Adapter.

Bridge: uebernimmt models/slots auch aus worker_ping (nach "Entladen" sonst
30 s veraltet) und sagt sofort ab, wenn das Modell auf keiner Box liegt,
statt per Broadcast in den Timeout zu laufen.

Diagnostic: Flotte zeigt pro LLM-Karte Modell + Zustand + "Entladen";
Katalog waehlt eine Ziel-KARTE (leere vorausgewaehlt, Ersetzen mit
Rueckfrage); Download-Fenster nennt Karte und was ersetzt wird.

RVS: llm_unload_model, llm_models_request, llm_models freigegeben.

docs/LLM-SCHNITTSTELLE.md: Schnittstelle fuer Drittprogramme (RVS + OpenAI-
Port), Fehlercodes, Gleichzeitigkeit, Python-Beispiel.

Tests: 23 gegen llama-swap (Adapter direkt) + Ende-zu-Ende ueber den echten
RVS mit dem Adapter als Prozess: Laden per RVS mit Fortschritt, das
Doku-Beispiel unveraendert (nur Adresse) findet beide Karten und bekommt eine
Antwort, Absage/Schweigen wie dokumentiert, zwei Clients parallel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 16:04:24 +02:00
duffyduckandClaude Opus 5.5 89cb3a765b feat(llm): Diagnostic zeigt, welches Modell gerade in der Karte liegt
Die Flotte listete "qwen3-4b, qwen3-8b" — das sind die Modelle, die die Box
fahren KANN (llama-swap /v1/models), nicht die geladenen. Ohne groups-Config
liegt immer nur eins in der Karte; ein anderes anzufragen entlaedt es
(gegen llama-swap ausprobiert: A laden, B anfragen → A unloaded).

Der Adapter fragt jetzt llama-swap /running und schickt das Ergebnis in jedem
worker_ping (10 s) und im worker_hello mit; nach einem Modellwechsel sofort.
None = llama-swap nicht erreichbar, [] = nichts geladen — die Anzeige
unterscheidet das ("geladen: ?" vs. "keins geladen").

Diagnostic: das geladene Modell gruen mit "● geladen", die anderen grau mit
Hinweis, dass sie beim ersten Aufruf laden und das geladene verdraengen.

"GPU void": die LLM-Zeile zeigt jetzt LLM_GPU (die Karte von llama-swap) statt
der NVIDIA_VISIBLE_DEVICES des Adapters, die mit der Modell-Karte nichts zu
tun hat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:40:17 +02:00
duffyduckandClaude Opus 5.5 864237ff2c feat(llm): Download-Fortschritt beim Modell-Laden — und "Laden" kommt endlich an
Eigentlicher Fehler zuerst: llm_provision_model/_result und llm_remove_model
standen nie in der RVS-Allow-List. Der RVS verwirft unbekannte Typen mit einem
stillen return — jeder Klick auf "Laden" im Modell-Katalog ist seit Stage D
(19.09.) an dieser Liste gestorben, die Box hat nie davon erfahren. Laden
liessen sich nur die Modelle aus der Basis-Config der Box.

Gefunden, weil grep rvs/server.js fuer eine Binaerdatei hielt und still
uebersprang: in Zeile 164 stand seit a7998bcd ein ECHTES Nullbyte im
Template-String statt eines Escapes. Node stoert das nicht, aber git zeigte
fuer jede Aenderung am RVS nur noch "Binary files differ". Jetzt \u0000 —
zur Laufzeit derselbe String.

Fortschritt: llama.cpp zieht das GGUF per -hf selbst und meldet nichts. Der
llm-adapter fragt vorab bei Hugging Face, welche Dateien (Groesse, sha256)
kommen, und misst genau diese im HF-Cache-Layout, das llama.cpp verwendet:
  /models/models--org--repo/blobs/<sha256>.downloadInProgress  (waechst)
  /models/models--org--repo/blobs/<sha256>                     (fertig)
Layout gegen den echten llama.cpp-Server ausprobiert, nicht angenommen. Geht
auch bei gesplitteten Modellen und zwei Downloads gleichzeitig; Fallback fuer
aeltere Layouts ueber alle *.downloadInProgress. Phasen: queued → start →
download (%, MB/s, Restzeit) → load ("laedt in die Karte") → ready ("in Karte
N geladen", Name + VRAM aus nvidia-smi) bzw. error.

Mitgefixt: der Warmup wartete LLM_TIMEOUT_SEC (Default 60 s). Ein Modell mit
mehreren GB meldete deshalb "Fehler", waehrend llama-swap weiterlud. Jetzt
LLM_WARMUP_TIMEOUT_S (1900 s, ueber llama-swaps healthCheckTimeout).

Diagnostic: Knopf "⬇ Downloads" neben "Von HuggingFace aktualisieren" mit
Zaehler fuer laufende; "Laden" oeffnet das Fenster direkt. Der Server merkt
sich den Stand pro (Box, Modell), ein spaeter geoeffneter Tab sieht laufende
Downloads. Antwortet die Box nicht, steht nach 30 s eine Warnung da statt
nichts.

Compose (KI-Box): llm-adapter bekommt LLM_GPU (Karte fuer die Meldung) und
HF_TOKEN (Dateiliste gesperrter Repos).

Test: Fortschritt gegen einen echten llama.cpp-Download (Qwen2.5-0.5B Q8,
676 MB): Prozent steigend 0 → 91.6, dann load; zweiter Lauf aus dem Cache
direkt load mit cached=true.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:33:54 +02:00
duffyduckandClaude Opus 5.5 d684bbb5f0 feat: ARIA kann E-Mails lesen und senden
IMAP/SMTP mit SSL/TLS, STARTTLS oder unverschluesselt. Senden mit Text, HTML,
Anhaengen und eingebetteten Bildern (cid:), Antworten mit In-Reply-To. Lesen,
Suchen, Ordner anlegen (auch Unterordner), Mails verschieben.
Tools: email_status/send/list/read/folders/folder_create/move.

Whitelist als harte Grenze im Sendepfad, nicht im Prompt: alles, was nicht
drinsteht, ist gesperrt, leer = nirgendwohin. Jeder Empfaenger zaehlt (An, Cc,
Bcc), ein fremder blockiert die ganze Mail. Genau eine Schreibweise:
name@domain, '*' nur als *@domain, *@*.domain oder *@*. '*hacker-net.de' liest
sich, als passte es auf 'evilhacker-net.de' — solche Kurzformen lehnt das
Speichern mit Korrekturvorschlag ab. Verglichen wird die Domain als Ganzes.

Zugangsdaten sieht ARIA nie:
- liegen im Brain unter /data. NICHT in /shared — das ist in ARIAs Container
  eingehaengt, /data nicht.
- keine Schnittstelle gibt das Passwort zurueck, nur password_set.
- Brain-Export laesst email_secret.json + email_admin.key aus (GNU- und
  busybox-tar geprueft, der Diagnostic-Container ist Alpine).
- Anhangspfade nach realpath geprueft: ein Symlink in /shared/uploads auf die
  Geheimnis-Datei wuerde sonst im Brain aufgeloest und verschickt.
- Konfiguration nur mit Admin-Schluessel (X-Aria-Admin, liegt in /data). Die
  Diagnostic haengt ihn an, weist aber Anfragen aus ARIAs Container ab —
  sonst koennte eine eingehende Mail sie per curl die Whitelist oeffnen lassen.
Grenze: ARIAs Container hat SSH auf die VM. Gegen einen gezielten Einbruch
schuetzt das nicht, nur dagegen, dass Zugangsdaten von selbst auftauchen.

Eingehende Mails sind fuer ARIA als Daten markiert, nicht als Anweisungen.

Diagnostic: Einstellungen → Integrationen → ARIA E-Mail, plus
"📬 Postfach oeffnen" — ARIAs ganzes Postfach in eigenem Fenster, Unterordner
eingerueckt, Posteingang + Gesendet oben. Nur lesend, markiert nichts als
gelesen. Mail-HTML in einem Rahmen ohne Skripte und ohne Nachladen von aussen
(kein Tracking-Pixel); eingebettete Bilder kommen als data: mit. Jede
gesendete Mail landet als Kopie in "Gesendet" — fehlt der Ordner, wird er
angelegt, statt die Kopie still zu verlieren.

Tests: 65 Einheitstests (Whitelist inkl. evilhacker-net.de, MIME-Aufbau,
Header-Injection, Symlink-Ausbruch, Geheimnis nie in Ausgaben) + 50 gegen einen
echten Mailserver (GreenMail): TLS-Login, Senden mit Anhang + Bild, Flags,
Suche mit Umlaut, Gesendet-Kopie, In-Reply-To, Ordner mit Umlaut, MOVE und
der Fallback ohne MOVE (der keine fremden geloeschten Mails mitreisst).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 18:14:31 +02:00
duffyduckandClaude Opus 5.5 6d978d72b3 feat: Modell pro Chat waehlen — und sehen, welches gerade laeuft
Nach einem Sicherheitsfilter-Treffer fuhr ein Projekt still auf dem
Ausweich-Modell weiter, und nirgends war zu sehen, auf welchem. Zurueck ging
nur ueber "Liste leeren" im Filter-Panel, und das gleich fuer alle Chats.

Jetzt drei Ebenen (aria-brain/context_model.py):
  Einstellung (brainModel) < pro Chat < Ausweich (Sicherheitsfilter)

- Pro Chat: Hauptchat und jedes Projekt koennen ein eigenes Modell haben, in
  /shared/config/context_models.json. Bewusst kein Feld im Projekt-Manifest —
  der Hauptchat ist kein Projekt und waere sonst aussen vor.
- "↩ zurueck" pro Chat: loescht nur die Filter-Vermerke DIESES Chats. Blockt
  der Filter erneut, weicht das Brain eben wieder aus.
- Angezeigt wird, was wirklich laeuft: chat() gibt das Modell aus modelUsage
  der CLI zurueck (aufgeloeste Version statt Alias) samt Grund; Brain → Bridge
  → chat_backup + Live-Payload → App und Diagnostic. Als Grundeinstellung
  zaehlt das Modell, mit dem das Brain laeuft, nicht der Dateiwert — so faellt
  ein ausstehender Neustart nach brainModel-Aenderung auf.

Diagnostic: 🧠-Auswahl neben "+ Projekt" fuer den fokussierten Chat, Modell im
Untertitel jeder Kontext-Karte, Modell statt "Claude" am Bubble-Badge (orange
mit ↪ bei Ausweich).

App: hinter der Quell-Anzeige (Einstellungen, Default aus — Kopfzeile bleibt
fuer Mama unveraendert) ein Modell-Chip in der Kopfzeile; Tippen oeffnet die
Auswahl fuer diesen Chat inkl. "Zurueck". Laeuft ueber den vorhandenen
brain_request-Kanal, also keine neuen RVS-Typen.

Tests: 47/47 (12 neue fuer die Aufloesungsreihenfolge gegen agent.chat()),
tsc ohne Fehler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:39:30 +02:00
duffyduckandClaude Opus 5 d221c1a320 feat(brain): Sicherheitsfilter blockiert nicht mehr das ganze Projekt
Anthropics Filter ("safeguards flagged this message", Details: [cyber]) trifft
genau unsere Themen — Ports, Tunnel, Zugangsdaten. Bisher war danach der
Projekt-Chat tot, und zwar aus einem Grund, den man der Meldung nicht ansieht:

Der Filter meldet sich NICHT als HTTP-Fehler. Die CLI liefert ein voellig
normales Ergebnis mit is_error=true und dem Fehlertext im content — also dort,
wo sonst ARIAs Antwort steht. proxy_client.py warf das Flag weg, der Agent
konnte Fehler und Antwort nicht unterscheiden und schrieb den Text per
conversation.add("assistant", ...) in den Verlauf. Weil der Verlauf bei jedem
Turn mitgeht, scheiterte ab da JEDE weitere Frage an derselben Stelle.

Zwei Stufen dagegen (aria-brain/safeguard.py):

1. Modellwechsel. Der Filter haengt am Modell ("Opus 5's safeguards ..."),
   Anthropic raet selbst zu "change your model". Derselbe Turn wird automatisch
   mit dem Ausweich-Modell neu gefragt; laeuft der Rest des Turns (Tool-Schritte)
   gleich mit darauf weiter. Der ausloesende Turn wird vermerkt, damit die
   naechsten Turns nicht erst wieder gegen die Wand laufen. Der Vermerk
   verfaellt von selbst, sobald der Turn aus dem Rolling Window gerollt ist —
   nichts muss aufgeraeumt werden, und das Projekt faellt von allein aufs
   Hauptmodell zurueck.

2. Quarantaene. Blockt auch das Ausweich-Modell, liegt es am Verlauf selbst.
   Dann faellt der ausloesende Turn aus dem Prompt-Fenster. NICHT geloescht: er
   bleibt in conversation.jsonl, steht mit Text in der Diagnostic und ist per
   Klick zurueckholbar. Der rohe Fehlertext wird nie persistiert — ARIA sagt in
   eigenen Worten, was passiert ist.

Der Zustand liegt in /data/safeguard.json, bewusst nicht in conversation.jsonl:
ein Markieren dort erzwaenge ein Rewrite, und das schreibt nur das In-Memory-
Window zurueck — alles schon Destillierte waere weg.

Erkennung bewusst zweistufig: mit is_error genuegt ein Marker, ohne muss der
Text mit "API Error" beginnen. Sonst wuerde eine Antwort, in der ARIA ueber den
Filter *spricht*, einen Modellwechsel ausloesen.

Mitgenommen:
- Das Memory-Destillat schickt denselben Verlauf nochmal durch und wurde
  genauso blockiert — nur fiel es dort als "unparsbares JSON" auf und
  wiederholte sich bei jedem Lauf. Weicht jetzt ebenfalls aus.
- clean_poisoned_turns.py raeumt die Altlasten: Fehlertexte, die vor diesem Fix
  schon im Verlauf stehen. Neu auch in Projekten (dort sterben sie ja), mit dem
  ausloesenden User-Turn desselben Kontexts, Dry-Run per Default.
- Diagnostic: Ausweich-Modell einstellbar (runtime.json, ohne Neustart, weil
  safeguard.py erst im Ernstfall liest) und ein Panel, das zeigt was blockiert
  wurde und ob es NOCH wirkt.

Tests: 35/35 fuer die Rettungskette gegen den echten agent.chat(), 16/16 fuer
das Aufraeum-Script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 10:16:24 +02:00
duffyduckandClaude Opus 5 d53dd83df4 feat(diagnostic): "+ Projekt" direkt ueber dem Chat
Im Kontext-Streifen gab es keinen Weg, ein Projekt anzulegen — das ging nur
unten in den Einstellungen. Der Knopf steht bewusst AUSSERHALB des scrollenden
Streifens: bei mehreren Projekten waere er dort nach rechts rausgerutscht.

Anlegen zieht jetzt beide Projekt-Oberflaechen nach (Einstellungs-Liste UND
Streifen) und setzt den Fokus aufs neue Projekt. Vorher aktualisierte nur die
Liste, das neue Projekt blieb im Streifen bis zum 15s-Poll unsichtbar — und der
Fokus blieb im Hauptchat, obwohl create_project() serverseitig umschaltet. Man
legte also ein Projekt an und schrieb weiter in den Hauptchat.

Dazu ein Fehlerpfad: ein fehlgeschlagenes Anlegen (z.B. leerer Name, 400 vom
Brain) wurde stillschweigend verschluckt — das Modal schloss, als waere alles
gut. Jetzt kommt die Begruendung des Brains als Meldung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 10:16:01 +02:00
duffyduckandClaude Opus 5 58d60adbaf feat(diagnostic): Satelliten und Host-Agenten umbenennen
Beide hiessen bisher so, wie es in IHRER .env steht. Umbenennen hiess also: auf
den Rechner, Datei aendern, Dienst neu starten — beim Fire TV sogar neu
provisionieren. In der Oberflaeche gab es dafuer gar keinen Weg.

Jetzt ein ✎ pro Eintrag. Der Alias liegt zentral in
/shared/config/display_names.json ({"host": {...}, "satellite": {...}}) und
wirkt sofort fuer JEDEN schon ausgerollten Agenten, ohne ihn anzufassen.

Der entscheidende Teil ist die Rueckrichtung: die Bridge loest den Alias beim
ADRESSIEREN wieder auf (_resolve_host / _resolve_satellite). Ohne das haette man
etwas umbenennen koennen und es danach nicht mehr ansprechen — der Agent
vergleicht die Adresse gegen seine EIGENE Kennung und kennt den Alias nicht.
Angesprochen werden kann weiterhin alles: Alias, Eigenname oder technische ID.

Der Eigenname bleibt in der Liste klein daneben sichtbar, damit man den Bezug
zum Geraet nicht verliert. Leerer Name entfernt den Alias.

Diagnostic und Bridge teilen sich die Datei ueber /shared — kein neuer
Nachrichtentyp, keine Allow-List-Aenderung, eine Wahrheit.

Nebenbei behoben: _display_name_set legte fest "/shared/config" an, obwohl der
Dateipfad konfigurierbar ist. Damit scheiterte das Schreiben stillschweigend,
sobald der Pfad abwich. Verzeichnis wird jetzt aus dem Pfad abgeleitet.

17 Pruefungen: Aliasvergabe, Liste, Aufloesung in beide Richtungen,
Gross/Kleinschreibung, alter Name bleibt gueltig, anderer Agent unberuehrt,
beide Bereiche in einer Datei ohne sich zu stoeren, Entfernen, unbekanntes Ziel
wird nicht still umgebogen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 18:54:36 +02:00
duffyduckandClaude Opus 5 6404b99510 feat(satellite): der Satelliten-Rechner steht selbst mit in der Geraeteliste
Der Satellit laeuft auf einem ganz normalen Rechner — bei Stefan auf
duffy-desktop. Dort laufen typischerweise noch andere Dienste (FreeCAD-MCP,
Web-App, Dateiserver). Bisher war ausgerechnet dieser Rechner unsichtbar: man
findet sich nicht per mDNS/ARP selbst.

Er erscheint jetzt als normales Geraet — ansprechbar wie jedes andere, nur
zusaetzlich mit 🛰️ markiert und blau abgesetzt, damit klar ist, dass dort der
Satellit traegt. Abschaltbar ueber LIST_SELF=false, falls man den Traeger
bewusst heraushalten will.

Nebeneffekt, der ein echtes Problem loest: der eigene Rechner gilt damit als
"gefunden" und ist ohne Eintrag in TUNNEL_ALLOW tunnelbar. Genau der Fall, um
den es ging — der FreeCAD-MCP laeuft auf dem Satelliten-Host selbst.

Beim Zusammenfuehren bleibt die Markierung erhalten: findet mDNS denselben
Rechner nochmal, haette der Merge isSatellite sonst verschluckt. hostname kommt
aus demselben Grund mit in die erhaltenen Felder.

Dazu ein ✎-Knopf pro Geraet in der Diagnostic: Namen vergeben, damit ARIA
"duffy-desktop" ansprechen kann statt einer IP. Der Name haengt an der MAC und
ueberlebt einen DHCP-Wechsel.

8 Pruefungen: Selbst-Eintrag vollstaendig, Markierung ueberlebt den Merge,
mDNS-Infos bleiben erhalten, eigener Rechner ohne TUNNEL_ALLOW erlaubt, fremde
IP weiterhin blockiert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 18:49:49 +02:00
duffyduckandClaude Opus 5 e67659b78a feat(diagnostic): warnt, wenn der Proxy mit veralteten Patches laeuft
Der Proxy kopiert proxy-patches/*.js beim START ueber den npm-Code. Wer nach
einem git pull nur `restart` macht — oder neu startet, BEVOR der Pull durch ist
— laeuft still mit der alten Fassung weiter. Nichts deutet darauf hin: der
Container ist "Up", die Oberflaeche sieht normal aus, die Aenderung wirkt
einfach nicht.

Das hat heute zweimal Zeit gekostet: einmal wirkte ein Proxy-Fix nicht, einmal
blieb die Modell-Liste alt, obwohl der Code laengst gepullt war (Proxy
gestartet 08:51, Patches gepullt 09:28).

Die Einstellungen vergleichen jetzt die Zeitstempel der Quelldateien mit den
eingespielten und zeigen einen Hinweis samt fertigem Befehl — inklusive der
Angabe, welche Datei wann geaendert und wann eingespielt wurde. Toleranz 5s,
weil Quelle und Kopie beim Start kurz nacheinander entstehen. Ein Fehler beim
Pruefen loest bewusst KEINEN Alarm aus, sonst stuende dort eine Warnung, die
nichts ueber die Patches aussagt.

Dazu: der Datenschutz-Block sagt jetzt ausdruecklich, dass KEIN Neustart noetig
ist — die CLI liest ~/.claude/settings.json bei jedem Aufruf neu. Nur ein
gerade laufender Turn nutzt noch die alte Einstellung.

4 Pruefungen gegen den echten Container, in beide Richtungen: schweigt nach
frischem Start, erkennt eine veraltete Kopie samt Zeitstempeln, schweigt nach
Wiederherstellung.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 11:38:04 +02:00
duffyduckandClaude Opus 5 d5eea920a6 feat(diagnostic): Datenschutz-Schalter von Claude Code pruefen und setzen
Drei Kanaele, ueber die Claude Code zusaetzlich zur eigentlichen Anfrage Daten
verschickt — bisher nur per Hand in der docker-compose.yml abschaltbar, und
niemand konnte sehen, ob sie an sind:

  DISABLE_ERROR_REPORTING   Stacktraces an einen Fehler-Dienst. Bei Pro/Max ab
                            CLI 2.1.198 standardmaessig AN.
  DISABLE_TELEMETRY         Nutzungs-Metriken.
  DISABLE_FEEDBACK_COMMAND  /feedback sendet sonst die ganze Unterhaltung
                            inkl. Code — 5 Jahre Aufbewahrung.

Gesetzt wird in ~/.claude/settings.json unter "env". Die Datei ist in den
Proxy-Container gemountet, die Diagnostic erreicht sie ueber den vorhandenen
dockerExec — also kein Anfassen der docker-compose.yml und KEIN Neustart: die
CLI liest die Datei pro Aufruf.

Geprueft wird beides: was in settings.json steht UND was im Prozess wirklich
ankommt. Eine echte Container-Umgebungsvariable gewinnt gegen settings.json —
so ein Eintrag wird darum als "per docker-compose gesetzt" angezeigt und der
Haken gesperrt, statt eine Einstellung anzubieten, die nichts tut.

Geschrieben wird atomar (temp + mv) und nur der env-Block angefasst; bestehende
Einstellungen (tui, theme) bleiben. Sind alle drei abgewaehlt, verschwindet der
env-Block wieder ganz.

Der Hinweis im Panel sagt ausdruecklich, dass das NICHT die Trainings-
Einstellung ist — die steht im Anthropic-Konto und laesst sich hier nicht
umstellen. Link dorthin ist daneben.

12 Pruefungen gegen den echten Proxy-Container: lesen, setzen, Teilmengen,
JSON-Integritaet, Erhalt bestehender Werte, CLI laeuft damit, Abwaehlen raeumt
auf, Ausgangszustand wiederhergestellt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 11:21:47 +02:00
duffyduckandClaude Opus 5 752e2abc5f feat(models): Test-Knopf — zeigt, welches Modell wirklich geantwortet hat
Bisher liess sich nicht nachsehen, ob eine Modell-Einstellung ueberhaupt
greift. Der Proxy hat die Information sogar aktiv weggeworfen:
normalizeModelName() nahm den echten Namen aus modelUsage (z.B.
"claude-opus-5-5") und schrieb ihn auf "claude-opus-4" um. Das `model`-Feld
der Antwort log also — und damit war jede Ueberpruefung unmoeglich.

- normalizeModelName gibt den echten Namen durch. Im OpenAI-Protokoll soll
  `model` das Modell nennen, das geantwortet HAT; ein erfundener Name ist
  schlechter als keiner.
- Zusatzfelder aria_model / aria_error / aria_context_window / aria_max_output
  aus modelUsage.canonicalModel. Noetig, weil die CLI bei einem unbekannten
  Modell gar nicht bis zum Call kommt und ihre Begruendung einfach in den
  Antworttext legt — ohne Flag waere ein Fehlschlag nicht von einer Antwort
  zu unterscheiden.
- Knopf "🔬 Testen" neben Dropdown und Freitextfeld. Er schickt eine echte
  Mini-Anfrage durch den GANZEN Weg (Diagnostic → Proxy → extractModel →
  claude CLI → Anthropic).

Ausdruecklich NICHT gemacht: das Modell nach seiner eigenen Version fragen.
Darauf ist kein Verlass — Modelle kennen ihren Versionsstring oft nicht und
raten. Und den Dropdown-Wert zurueckzugeben waere sinnlos. Die Wahrheit kommt
aus modelUsage der CLI.

Vier unterscheidbare Ergebnisse:
  Tier-Alias      gruen  — zeigt die aufgeloeste Version ("opus" → Opus 5.5)
  exakte Version  gruen  — angefragt == geantwortet
  nicht erkannt   GELB   — der Proxy hat still "opus" eingesetzt; warnt
                           ausdruecklich davor, die ID so zu setzen
  ungueltig       ROT    — CLI-Begruendung im Klartext

Der gelbe Fall war wichtig: ein Name, der nicht wie ein Claude-Modell aussieht,
faellt auf "opus" zurueck und haette sonst als Erfolg gegolten — man setzt dann
eine ID, die nie benutzt wird, und merkt es nie.

Geprueft gegen ECHTE CLI-Ausgaben aus dem Proxy-Container (9 Faelle: Alias,
exakte Version, Tippfehler) plus 7 Faelle fuer die Anzeige-Logik. Nebenbefund:
`--model opus` loest derzeit auf claude-opus-5-5 auf.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 10:54:22 +02:00
duffyduckandClaude Opus 5 09d06011d5 fix(models): Modell-Liste kommt jetzt von Anthropic — und feste Versionen greifen wirklich
Zwei Fehler. Der zweite war der schlimmere.

1) Die Liste war handgepflegt und damit garantiert veraltet.
   Sie kannte "Opus (aktuell: Opus 5)" — waehrend es laengst Opus 5.5,
   Sonnet 5.5 und Fable 5.1 gab. Der Knopf "↻ Aktualisieren" las nur eine
   lokale Datei neu und aktualisierte damit gar nichts.

   Jetzt kommt die Liste aus Anthropics eigenem Modell-Katalog
   (downloads.claude.ai/model-catalog/v1/catalog.json, Surface 'cc') —
   dieselbe Quelle, aus der sich Claude Code selbst bedient. Oeffentlich,
   ohne API-Key (die Models-API braucht einen; mit dem Max-Abo gibt es keinen).
   6h-Cache plus Datei-Cache, der auch offline und bei abgelaufenem TTL
   einspringt: eine etwas alte echte Liste ist besser als keine.

   Die Tier-Aliase (opus/sonnet/haiku/fable) bleiben vorne und bleiben die
   Empfehlung — sie folgen automatisch der neuesten Version. Darunter die
   exakten Versionen, aeltere ausdruecklich als solche markiert.

2) Eine feste Version liess sich faktisch nicht waehlen.
   extractModel() hatte eine MODEL_MAP und fiel fuer alles Unbekannte STILL
   auf "opus" zurueck. Wer "claude-opus-5-5" setzte, bekam ohne jede Meldung
   das Tier-Default. Schlimmer noch: claude-opus-5 und claude-fable-5 standen
   selbst in der Map und wurden auf ihr Tier eingeschmolzen — eine bewusst
   gewaehlte aeltere Version wurde also durch die neueste ersetzt.

   Volle Modellnamen gehen jetzt unveraendert an die CLI. Die versteht sie
   ("--model: an alias for the latest model or a model's full name") und
   meldet sich selbst klar, wenn sie einen Namen nicht kennt — ehrlicher als
   ein stilles Downgrade. Nur echter Muell faellt noch auf "opus", und das
   wird geloggt.

Nachgewiesen gegen den LIVE-Katalog und die echte CLI im Proxy-Container:
20 Pruefungen gruen, u.a. dass alle 12 gelieferten exakten Versionen den Proxy
unveraendert passieren. `claude --print --model claude-opus-5-5` antwortet.
Stefans aktive Einstellung ist der Alias "opus" — am laufenden Betrieb aendert
sich dadurch nichts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 10:47:34 +02:00
duffyduckandClaude Opus 5 734868efab feat(diagnostic): Anhang-Limit einstellbar + Datum/Uhrzeit bei Gedanken
Zwei Dinge, die bisher nur im Code bzw. nur in der DB standen.

Anhang-Limit (Einstellungen → System & Wartung):
- Das Limit war eine Env-Variable mit 20 MB Default — zum Anheben musste man
  die .env editieren und das Brain neu starten. Jetzt steht es in runtime.json
  und das Brain liest es bei JEDEM Upload neu: Aenderung greift sofort.
- Reihenfolge: runtime.json > ENV > Default. Anders als beim OpenAI-Endpunkt
  gewinnt hier NICHT die .env — dort erzwingt ein Docker-Port-Mapping das,
  hier gibt es keinen solchen Zwang, und eine Einstellung die nichts tut waere
  schlimmer als keine.
- Default von 20 auf 64 MB. Genau so viel holt die App auch auf ausdruecklichen
  Tipp noch herunter (TAP_DL_MAX_BYTES); darueber warnt die UI, verbietet es
  aber nicht — der Anhang liegt dann sauber auf dem Server, ist mobil nur nicht
  mehr ladbar.
- Neuer Endpunkt GET /attachments/limit. Das fest eingetippte "max 20 MB pro
  Datei" im HTML ist weg — es stimmte nach jeder Aenderung nicht mehr.
- Die Fehlermeldung nennt jetzt MB statt Bytes und sagt, wo die Einstellung ist.

Datum/Uhrzeit bei Gedanken:
- created_at/updated_at lagen schon immer in der DB und wurden ausgeliefert —
  nur nie angezeigt. Jede Zeile zeigt jetzt "angelegt <Zeit>" und, falls
  abweichend, "geaendert <Zeit>" plus ein relatives "(vor 3 Std)". Damit sieht
  man auf den ersten Blick, was der letzte Eintrag war.
- Sortier-Dropdown: nach Typ gruppiert (wie bisher) oder nach Anlage/Aenderung
  auf- und absteigend. Bei Zeit-Sortierung wird die Liste flach dargestellt —
  man will sehen was zuletzt passiert ist, nicht in welche Schublade es gehoert.
- Zeitraum-Filter (🕒) mit von/bis, umschaltbar zwischen angelegt und geaendert,
  plus Schnellwahl Heute / 7 / 30 Tage. Gilt auch fuer Such-Treffer, damit
  "suche X, aber nur letzte Woche" geht. Zuklappen schaltet ihn aus, und das
  ✕-Zuruecksetzen raeumt ihn mit auf (sonst filtert er unsichtbar weiter).

Beides gegen den echten Code getestet: 7 Faelle fuers Limit (inkl. kaputter
runtime.json und einem 50-MB-PDF an beiden Grenzen), 10 fuer Sortierung und
Zeitraum.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 10:33:54 +02:00
duffyduckandClaude Opus 4.8 d6c7502810 feat(xtts): OpenAI-Endpunkt fuers lokale LLM + OpenHands-Profil
llama-swap ist bereits OpenAI-kompatibel, war aber nur im Compose-Netz erreichbar
(kein ports-Mapping). Jetzt nutzbar fuer OpenHands, Continue, Open WebUI & Co.

- compose: llama-swap veroeffentlicht 8080 als
  ${LLM_OPENAI_BIND:-127.0.0.1}:${LLM_OPENAI_PORT:-8081} — sicher per Default
  (nur localhost), fuer LAN bewusst BIND=0.0.0.0 setzen.
- llm-adapter: API-Key wird in JEDEN llama-server-Befehl der generierten
  llama-swap-Config eingehaengt (--api-key, shlex-gequotet). Quelle: .env
  (Vorrang) sonst /models/openai_key.json (0600). Neuer Handler
  llm_openai_config setzt ihn zur Laufzeit und lehnt bei .env-Vorrang ab.
  worker_hello meldet Port/Bind/keySet/envLocked — den Key NIE (Broadcast!).
- Diagnostic: pro LLM-Box Endpunkt-Zeile mit Base-URL, Key-Status und Eingabe.
  Bei .env-Vorrang ist das Feld schreibgeschuetzt (🔒). Warnung, wenn im LAN
  offen ohne Key. Der PORT wird nur ANGEZEIGT: er ist ein Docker-Port-Mapping
  und steht beim Container-Start fest — dafuer ist die .env zustaendig.
- rvs: llm_openai_config(_result) in ALLOWED_TYPES (sonst still verworfen).
- Neues Profil 'openhands' (COMPOSE_PROFILES=llm,openhands) mit Port/Bind/Modell
  aus der .env, lokales LLM vorbelegt. Ohne Profil aendert sich nichts.
- .env.example + README: alle Variablen, Sicherheitshinweise (offener Endpunkt,
  Docker-Socket bei OpenHands), curl-Test und wann der Key greift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 22:30:37 +02:00
duffyduckandClaude Opus 4.8 8f9e3e5c79 feat: Jellyfin-Integration — ARIA steuert die Wiedergabe ueber die API
Statt sich durch die Fire-TV-Oberflaeche zu klicken (fehleranfaellig: ARIA ist am
Titel vorbeigescrollt und auf Home gelandet) spricht ARIA den Jellyfin-Server
direkt an: suchen -> Sitzung des Abspielgeraets finden -> abspielen.

- Diagnostic (Einstellungen > Integrationen): Jellyfin-Abschnitt mit MEHREREN
  Servern (+-Button; eigener, vom Kumpel ...), einer davon Standard. Pro Server
  Name/URL/API-Key + Test-Knopf (prueft /System/Info, meldet Name und Version).
  Gespeichert in /shared/config/jellyfin.json mit Datei-Rechten 0600 (API-Keys).
- Brain: jellyfin_search / jellyfin_devices / jellyfin_play / jellyfin_control.
  Serverwahl per Name oder Standard. 'resume' ist echt implementiert (liest
  PlaybackPositionTicks und setzt startPositionTicks) statt nur zu existieren.
  Fehlertexte sind handlungsleitend: 401 -> API-Key pruefen; kein Geraet -> die
  Jellyfin-App muss offen sein, sonst erst host_app_launch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 03:23:30 +02:00
duffyduckandClaude Opus 4.8 27f9399eda feat(diagnostic): bereits vergebener Geraetename wird beim Ausrollen vorgeschlagen
Bisher stand im Namensfeld die technische Kennung aus der Netz-Erkennung
(F8FCE10B4E6C@AS-AFTKA[AirPlay]) — auch wenn das Geraet laengst 'Fire-TV
Schlafzimmer' heisst. Jetzt in dieser Reihenfolge:
  1. Name, den der Agent auf DIESEM Geraet traegt — Zuordnung ueber die IP, die
     der Agent neu in host_hello mitmeldet (localIp()); Server reicht sie durch.
  2. zuletzt hier eingegebener Name (localStorage je Satellit+IP).
  3. Name aus der Erkennung, aber nur wenn menschenlesbar — Seriennummern, IPs
     und Kennungen mit @/[]/: werden verworfen (Feld bleibt leer).
Android-Version 0.0.1.5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 02:49:38 +02:00
duffyduckandClaude Opus 4.8 44aef71813 fix: Leerzeichen im Geraetenamen + alte Agenten aus der Liste entfernbar
1) 'adb shell' haengt seine Argumente zu EINER Kommandozeile zusammen, die auf
   dem Geraet nochmal von der Shell zerlegt wird — '-e name Wohnzimmer Fire TV'
   kam als 'Wohnzimmer' an, der Rest fiel weg. Alle Werte werden jetzt mit
   shlex.quote gequotet.
2) Umbenennen erzeugt eine neue hostId, der alte Eintrag blieb fuer immer in der
   Diagnostic stehen (nach 5 min nur rot, nie weg). Neuer ✕-Button je Agent
   (host_forget) mit Rueckfrage; laeuft der Agent noch, meldet er sich von selbst
   wieder — das Entfernen stoppt ihn also nicht.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 02:07:27 +02:00
duffyduckandClaude Opus 4.8 27381e7038 feat(diagnostic): Geraetename beim Rollout am PC vergeben + 'Nur einrichten'
Fire TV meldet sich in der Netz-Erkennung oft nur mit der Seriennummer
(0d94400fa5b63301) — genau der Name, den man auf dem Fernseher nicht tippen will.

- Namensfeld im Rollout-Dialog (am PC getippt), wird beim Einrichten mitgegeben.
- Vorbelegung filtert technische Namen (Hex-Seriennummern, IPs) raus.
- Neuer Button 'Nur einrichten': setzt Zugang + Namen per adb.provision, OHNE die
  APK neu zu installieren — zum Umbenennen bereits ausgerollter Geraete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 02:01:55 +02:00
duffyduckandClaude Opus 4.8 eae036a9fc feat: Fern-Einrichtung des Agents per ADB (kein Abtippen am Fire TV)
Am Fire TV gibt es keine Kamera (kein QR) und Host/Token mit der Fernbedienung
einzugeben ist eine Qual. Der Satellit hat aber ohnehin schon eine ADB-Verbindung
— darueber bekommt der Agent seine Zugangsdaten direkt.

- Android: MainActivity.applyProvisioning() liest Intent-Extras (host/port/tls/
  token/name/control/reply_mode), speichert sie, startet den Dienst und zeigt
  'Von ARIA eingerichtet' (Transparenz). Auch via onNewIntent.
- Satellit: adb.provision (am start mit Extras) und adb.status (installiert?
  laeuft? welche Version?). adb.install richtet direkt mit ein, wenn rvs_host/
  rvs_token mitkommen -> ein Klick = installieren + einrichten + online.
- Diagnostic: Checkbox 'Gleich einrichten' (default an) + 'Status pruefen'-Button.
  Der RVS-Zugang wird SERVERSEITIG ergaenzt (params.provision) — das Token steht
  nie im Browser-Formular.
- Allowlists (Code + .env.example) und README ergaenzt, inkl. Sicherheitshinweis.
Android-Version 0.0.1.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 01:54:38 +02:00
duffyduckandClaude Opus 4.8 621b5525a8 feat(satellite): eigene MAC-Adresse melden + in der Diagnostic anzeigen
NET bekommt ein 'mac'-Feld (_own_mac): liest /sys/class/net des Interfaces, das
zur primaeren IP gehoert — wichtig, weil sonst die Docker-Bridge-MAC (02:42:...)
statt der echten Karte kaeme. Fallback uuid.getnode(). Wird ueber sat_hello.net
mitgeschickt (Server reicht net bereits durch) und in der Satelliten-Zeile hinter
der IP angezeigt; auch im Startup-Log.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 01:41:48 +02:00
duffyduckandClaude Opus 4.8 8301342728 feat(satellite): ADB-Rollout wartet auf die Geraete-Bestaetigung (ein Klick genuegt)
Bisher: 1. Klick -> 'unauthorized' (Fehler), am Fire TV bestaetigen, 2. Klick ->
klappt. Jetzt wartet der Satellit nach dem ersten connect bis zu ADB_AUTH_WAIT_SEC
(90s) auf die Autorisierung und installiert danach automatisch weiter — der
Dialog auf dem Fernseher erscheint ja erst DURCH das connect.

- _adb_wait_authorized(): pollt adb devices alle 2s und verbindet neu (nach dem
  Bestaetigen wechselt der Zustand oft erst mit frischem connect auf 'device').
- adb.install/adb.connect nutzen es; scheitert es doch, nennt die Meldung Wartezeit
  und Zustand statt nur 'unauthorized'.
- Brain-Timeout fuer adb.* auf 320s (Warten + Download + Installation).
- Diagnostic: Hinweis erscheint SOFORT beim Klick ('Jetzt auf den Bildschirm des
  Geraets schauen'), nicht erst als Fehler hinterher.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 01:34:18 +02:00
duffyduckandClaude Opus 4.8 47735642f2 feat(satellite): APK-Rollout per ADB — Fire TV & Android aus der Ferne bespielen
Der Satellit kann Android-Geraete im LAN erkennen und die Agent-APK ausrollen,
statt sie von Hand aufs Geraet zu kopieren.

- satellite.py: adb.devices/connect/install/shell. _apk_fetch laedt die APK per
  HTTP (gecached in /data/apk, sha256 optional) statt sie durchs RVS zu schicken —
  der RVS ist ein BROADCAST-Relay (jede base64-APK ginge an alle Clients, und das
  Satelliten-max_size liegt bei 8 MB). adb.install ist selbstheilend (connect ->
  install -r) und uebersetzt die typischen Fehler in klare Ansagen (unauthorized,
  Signatur-Mismatch, Speicher voll). Imports lokal in den Funktionen (Hausmuster).
- Discovery: mDNS-Typen _amzn-wplay/_adb-tls-connect/_androidtvremote2, _mdns_kind
  -> firetv/android-adb/androidtv, plus _enrich_adb (TCP-Probe 5555) -> adbCapable.
- Dockerfile: adb; compose: HOME=/data (ADB-Key persistent, sonst fragt das Geraet
  nach jedem Rebuild neu) + ANDROID_ADB_SERVER_PORT=5038 (Host-Kollision).
- .env.example: neue Aktionen + Warnung, dass die Allowlist den Code-Default
  ueberschreibt (sonst lehnt ein bestehender Satellit adb.* ab).
- Brain: adb.* in der satellite_command-Beschreibung; WICHTIG Timeout 200s fuer
  adb.*/ssh.exec — der Bridge-Default von 20s haette jede Installation abgewuergt.
- Diagnostic: sat_command (Browser->RVS) und sat_result (RVS->Browser) gab es
  bisher GAR NICHT; beide ergaenzt. 📦-Button je ADB-faehigem Geraet + Rollout-
  Modal mit Status/Log, ADB-Tag in der Geraeteliste.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-29 19:17:53 +02:00
duffyduckandClaude Opus 4.8 f4b7148cf9 feat(diagnostic): Agent-Historie pro Agent — Akkordeon je Nachricht
Jede Host-Aktion wird als Historie-Eintrag festgehalten und in der Diagnostic
pro User-Nachricht gruppiert aufklappbar dargestellt (mit Screenshot-Thumbnails).

- Brain: trace_id+msg pro chat(); _dispatch_host als Wrapper um _dispatch_host_inner
  emittiert je Aktion einen Eintrag an POST /internal/agent-history (Datei-Pfad aus
  Screenshot-Text erkannt).
- Bridge: /internal/agent-history persistiert nach /shared/config/agent_history/
  <hostId>.jsonl (Ringpuffer 200) + broadcastet agent_history; agent_history_query
  -> agent_history_list.
- RVS: agent_history/_query/_list in ALLOWED_TYPES (sonst still verworfen).
- Diagnostic-Server: relay browser<->RVS + /uploads/<file> Bild-Endpoint (nur
  /shared/uploads, kein Traversal).
- index.html: 'Historie'-Button je Host, Modal mit Akkordeon (Gruppe=Nachricht,
  aufklappbar, Screenshot-Thumbs), Live-Refresh bei agent_history.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-25 13:32:40 +02:00
duffyduckandClaude Opus 4.8 145c64e67f feat(diagnostic): RVS-Raum-Monitor + Server/GPU-Icon fuer die Compute-Flotte
Raum-Monitor (haette uns die Nacht erspart): der RVS-Log kuerzt Tokens auf 8
Zeichen -> zwei verschiedene Tokens mit gleichem Prefix ergeben zwei Raeume,
die im Log IDENTISCH aussehen (Prefix-Kollision). Jetzt zeigt die Diagnostic
(Satelliten-Tab, Panel 'RVS-Raeume 🚪') alle Raeume mit token8 + laengerem
Fingerprint (sha256) + Token-Laenge + Client-Zahl, ★ = eigener Raum. >1 Raum =
Warnung 'Token-Mismatch'. Keine vollen Tokens (nur Fingerprint).

- rvs: rooms_query -> direkt rooms_info antworten (wie update_check); Typen in
  ALLOWED_TYPES; sha256-Fingerprint via crypto.
- diagnostic: rooms_query durchreichen, rooms_info an Browser; Panel + Tabelle.

Dazu: Compute-Flotte-Ueberschrift bekommt statt 🖥️ ein Inline-SVG (Server mit
GPU-Karte, currentColor -> theme-aware).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-24 18:29:37 +02:00
duffyduckandClaude Opus 4.8 74fcf7fd03 feat(diagnostic): Host-Agenten in der Satelliten-Flotte anzeigen (Phase E)
Diagnostic-Server trackt host_hello/host_ping (hosts-Map), broadcastet
host_update und beantwortet die host_list-Action. UI: neues Panel
"Host-Agenten" im Satelliten-Tab — zeigt Name/OS/Caps/online + ob
CONTROL_ENABLED. Reine Sichtbarkeit; Steuerung laeuft ueber ARIA.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-24 16:12:50 +02:00
duffyduckandClaude Opus 4.8 a99ea32664 feat(satellite): ssh.exec — ARIA fuehrt Kommandos per SSH auf Geraeten aus
Neuer Credential-Typ 'ssh' (Benutzer + Passwort ODER privater Key, Port) und
Aktion ssh.exec (params: ip, cmd). paramiko-Client; grosse Ausgaben werden wie
bei http.get gefenstert (contains/offset/max_chars gemeinsam via _window_text),
Antwort mit exit_code + stdout + stderr. Auth kommt aus dem Credential-Store,
ARIA muss keine Passwoerter mitgeben.

- satellite: _do_ssh + _ssh_load_key (RSA/Ed25519/ECDSA/DSS aus String),
  ssh.exec in _control + Allowlist, 'ssh' in beide Cred-Typ-Listen; paramiko
  in requirements; .env.example ergaenzt.
- diagnostic: SSH-Sektion im Credentials-Modal (User/Port/Passwort/Key) +
  Save-Logik (User + Passwort|Key).
- brain: satellite_command-Tool um ssh.exec erweitert.

Laeuft ueber den bestehenden sat_command/sat_result-Pfad — keine RVS-Aenderung.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-24 16:00:54 +02:00
duffyduckandClaude Opus 4.8 bb7a19f818 fix(creds): HTTP-Basic-Benutzer optional (Password-only-Geraete)
Wie bei der FritzBox: manche Geraete nutzen HTTP-Basic-Auth nur mit Passwort.
Modal speichert HTTP-Creds jetzt bei User ODER Passwort; _do_http wendet die
Auth auch bei leerem Benutzer an. SNMP v1/v2c hat ohnehin nur die Community
(kein User); v3 braucht den securityName zwingend und bleibt Pflicht.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 17:45:39 +02:00
duffyduckandClaude Opus 4.8 6ffbc77387 fix(diagnostic): FritzBox-Benutzer optional — Password-only-Boxen speicherbar
Das Credentials-Modal speicherte FritzBox-Zugangsdaten nur, wenn das Benutzer-
Feld ausgefuellt war (if fu) — Username war damit faktisch Pflicht. FritzBoxen
ohne benannten Benutzer haben aber nur ein Passwort. Jetzt: gespeichert sobald
User ODER Passwort gesetzt ist; Placeholder kennzeichnet den User als optional.
Backend (_do_fritzbox) verlangte ohnehin nur das Passwort.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 17:44:34 +02:00