einstellungen: Zeitfenster, Radar-Schalter, Telegram-Test, Software-Stand und Altreste

Einstellungen, die etwas einstellen (services/einstellungen.py, /api/einstellungen):
- Update-Zeitfenster: Wochentag und Uhrzeit des Update-Laufs als Drop-in
  mc2-autoupdate.timer.d/zeitfenster.conf. Gegen die Nachhol-Falle von
  Persistent=true (24.09.): Timer vor dem daemon-reload stoppen, Stempel auf
  jetzt, dann starten. Bei Fehler zurück auf das alte Drop-in. Während eines
  Update-Laufs abgelehnt.
- Neustart nur im eingestellten Fenster (deploy/wartungsfenster.sh, drei
  Stunden ab der vollen Stunde des Beginns; Standard So 04:00-06:59).
- Radar an/aus: disable --now bzw. enable + Stempel + start (kein Nachholen).
  deploy.sh respektiert den Schalter und startet den Radar-Timer nur mit
  Stempel; das Zeitfenster-Drop-in fasst er nie an.
- Wächter: schläft der Timer eines Timer-Dienstes, ist ein alter Fehlschlag
  kein Befund mehr (der Dienst selbst ist static und schläft nie).
- Telegram-Test je Instanz (/api/einstellungen/telegram-test und
  /api/homelab/einstellungen/telegram-test) über notify.sh -d; Ergebnis und
  Grund aus dem Melde-Log. notify.sh schreibt jetzt auch den Grund des
  gescheiterten Zweitwegs in den FALLBACK-Eintrag.
- Einstellungsdatei mc2-einstellungen.json im Datenordner.

Software-Stand: deploy.sh und homelab/ausrollen.sh schreiben nach dem
Umschalten mc2-stand.json (deploy/stand-schreiben.py); /api/instanz liefert
den Stand, die Einstellungen zeigen beide Instanzen und warnen bei Abweichung.
Ohne Datei aus git, sonst unbekannt.

Aufräumen: Altreste neben dem Betrieb aus einer festen, auf der Box geprüften
Liste (Größe, Hinweis, nur was da und nicht in Gebrauch ist). Löschen nur per
Kennung und Klick mit Rückfrage; Worktrees mit git worktree prune, Alt-Units
mit daemon-reload, /opt/llamacpp notfalls mit sudo -n.

Tests: pytest mit einem systemd-Abbild samt Nachhol-Regel, echtem notify.sh
(Ersatz-Hermes, Tmp-Zugang, lokale Bot-API), Shell-Funktionen des
Wartungsfensters und von deploy.sh; vitest für die Rückfragen der Schublade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-24 20:37:30 +02:00
co-authored by Claude Opus 5.5
parent 40d2840b16
commit 3d8df1c6fd
24 changed files with 2640 additions and 85 deletions
+61
View File
@@ -301,3 +301,64 @@ export const useHomelabHinweise = (aktiv: boolean) =>
enabled: aktiv,
refetchInterval: takt(60_000),
})
// --- Einstellungen, Software-Stand, Altreste (seit 24.09.2026) --------------------------------------------------
import type { Altrest, EinstellungenStand, InstanzMitStand, TelegramTest } from "./typen"
/** Update-Zeitfenster und Radar-Schalter der KI-Box, samt nächstem Lauf laut systemd. */
export const useEinstellungenStand = (aktiv: boolean) =>
useQuery({
queryKey: ["einstellungen"],
queryFn: () => api<EinstellungenStand>("/api/einstellungen"),
enabled: aktiv,
retry: false,
})
export const useUpdateFensterSetzen = () =>
useAktion(
(f: { tag: number; uhrzeit: string }) => post<AktionsErgebnis>("/api/einstellungen/update-fenster", f),
{ erfolg: (_, e) => (e as AktionsErgebnis).text ?? "Gespeichert.", neuLaden: ["einstellungen", "start"] },
)
export const useRadarSchalten = () =>
useAktion((an: boolean) => post<AktionsErgebnis>("/api/einstellungen/radar", { an }), {
erfolg: (_, e) => (e as AktionsErgebnis).text ?? "Geschaltet.",
neuLaden: ["einstellungen", "start", "radar"],
})
/** Testmeldung über den echten Meldeweg der KI-Box oder des Homelab-Teils (lib/instanz.ts findet die Instanz). */
export const useTelegramTest = () =>
useAktion(
(ziel: "box" | "homelab") =>
post<TelegramTest>(ziel === "homelab" ? "/api/homelab/einstellungen/telegram-test" : "/api/einstellungen/telegram-test"),
{ erfolg: (_, e) => e.text ?? "Die Testmeldung ist raus.", neuLaden: [] },
)
/** Software-Stand dieser Instanz und der anderen (über /api/partner/instanz). */
export const useSoftwareStand = (aktiv: boolean, mitPartner: boolean) =>
useQueries({
queries: [
{ queryKey: ["stand", "hier"], queryFn: () => api<InstanzMitStand>("/api/instanz"), enabled: aktiv },
{
queryKey: ["stand", "partner"],
queryFn: () => api<InstanzMitStand>("/api/partner/instanz"),
enabled: aktiv && mitPartner,
retry: false,
},
],
})
/** Altreste neben dem Betrieb (Test-Ordner, alte Umgebungen, Worktrees …) — nur, was noch da ist. */
export const useAltreste = () =>
useQuery({
queryKey: ["altreste"],
queryFn: () => api<{ altreste: Altrest[] }>("/api/aufraeumen/altreste"),
staleTime: 60_000,
})
export const useAltrestLoeschen = () =>
useAktion((a: Altrest) => post<AktionsErgebnis>("/api/aufraeumen/altreste/loeschen", { id: a.id }), {
erfolg: (_, e) => (e as AktionsErgebnis).text ?? "Gelöscht.",
neuLaden: ["altreste", "start"],
})
+71
View File
@@ -302,3 +302,74 @@ export interface HomelabLauf {
text: string | null
schritte: string[]
}
// --- Einstellungen, Software-Stand, Altreste (seit 24.09.2026) --------------------------------------------------
/** Welcher Stand einer Instanz seit wann live ist (services/software_stand.py). */
export interface SoftwareStand {
/** "deploy" = Stand-Datei des Deploys, "git" = aus dem Checkout gelesen (Entwicklung), sonst "unbekannt". */
quelle: "deploy" | "git" | "unbekannt"
commit: string | null
betreff: string | null
/** ISO-Zeit des Commits */
commit_datum: string | null
/** ISO-Zeit des Deploys, nur mit Stand-Datei */
deploy_zeit: string | null
}
/** GET /api/instanz bzw. /api/partner/instanz, seit 24.09.2026 mit dem Software-Stand. */
export interface InstanzMitStand extends Instanz {
stand?: SoftwareStand
}
/** Einstellungen der KI-Box samt dem, was systemd daraus gemacht hat (GET /api/einstellungen). */
export interface EinstellungenStand {
/** false, wo es kein systemd gibt (Entwicklung am PC): Dann lässt sich nichts schalten. */
schaltbar: boolean
update_fenster: {
/** 1 = Montag … 7 = Sonntag */
tag: number
/** "HH:MM" */
uhrzeit: string
tag_name: string
/** Wann die Box nach einem Update neu starten darf, z. B. „Sonntag 04:00–06:59“. */
neustart_fenster: string
timer_aktiv: boolean
naechster_lauf: string | null
/** false: Der Timer läuft noch nach einem anderen Plan als eingestellt. */
wirksam: boolean
}
radar: {
/** Was eingestellt ist. */
an: boolean
/** Was systemd sagt: „schlaeft“ = abgeschaltet und nicht im Autostart. */
zustand: "an" | "schlaeft" | "aus" | "unbekannt"
naechster_lauf: string | null
wirksam: boolean
}
}
/** Antwort des Telegram-Tests (POST /api/einstellungen/telegram-test bzw. /api/homelab/einstellungen/telegram-test). */
export interface TelegramTest extends AktionsErgebnis {
gesendet: boolean
/** Über Hermes oder direkt an die Telegram-Bot-API. */
weg: "hermes" | "direkt" | null
/** Warum nicht, aus dem Melde-Log. */
grund: string | null
instanz: string
/** ISO-Zeit des Tests */
zeit: string
kennung?: string
}
/** Ein Altrest neben dem Betrieb (GET /api/aufraeumen/altreste). */
export interface Altrest {
/** Kennung aus der festen Liste — gelöscht wird nur darüber, nie über einen Pfad. */
id: string
name: string
pfade: string[]
groesse_bytes: number
/** fertig lesbar, z. B. „7,7 GB“ */
groesse: string
hinweis: string
}