feat(v5): Etappe W-0 — das Geruest steht

Electron 44 + TypeScript, drei Prozesse (haupt / kern als utilityProcess /
fenster mit React), Nachrichten-Schema mit Pruef-Funktionen, node:sqlite
als einzige Datenbank-Stelle (kern/speicher/db.ts, § 6.7), Prozess-Leine
im Haupt (Job Object aus beweise/leine.js — Begruendung fuer den Ort im
Dateikopf), MessagePort direkt Fenster<->Kern, Einzelinstanz-Sperre,
Kern-Neustart-Wache, strikte CSP im gebauten Fenster.

Wächter-Tests nach § 4.3: koffi nur an zwei benannten Orten (R1), kein
leerer catch und kein catch-mit-Leerwert (R2/R4), kein HTTP-Server
(§ 4.1), node:sqlite nur in db.ts (§ 6.7). Dazu Datenbank- und
Schema-Tests: 18/18 gruen, Typpruefung in drei Kontexten.

Der W-0-Beweis (npm run smoke, echtes Programm):
SMOKE: OK — fenster=geladen kern=pid:13676,node:24.18.1 datenbank=ok
leine=gesetzt pong=ok version=5.0.0-w0

Nachgemessen ausserdem: taskkill /F auf den Haupt-Prozess (ohne /T,
der Absturz-Fall aus rc10) — der Kern stirbt mit.

Bau-Fallen dokumentiert (BAUEN.md): npm 11 blockt Electrons
Install-Skript (§ 3.5), plugin-react 6 verlangt Vite 8 (deshalb 5.2),
TypeScript bewusst auf 5.9.3 gepinnt statt tsgo 7.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-30 16:53:30 +02:00
co-authored by Claude Fable 5
parent 564bd17f84
commit c539e65cd2
27 changed files with 5207 additions and 0 deletions
@@ -0,0 +1,69 @@
// Das Nachrichten-Schema zwischen den drei Prozessen (KONZEPT-WINDOWS.md § 4.1).
// NUR Typen und Prüf-Funktionen — keine Logik, keine Abhängigkeiten, denn diese
// Datei läuft im Fenster UND im Kern.
//
// Wege:
// Kern → Haupt über process.parentPort (KernNachricht)
// Kern ↔ Fenster über einen direkten MessagePort (KernNachricht/FensterNachricht)
// Haupt → Fenster über IPC-Kanal 'haupt-status' (HauptStatus)
// Haupt → Kern über utilityProcess.postMessage (HauptNachricht)
/** Zustand der Datenbank, wie der Kern ihn beim Start gemessen hat. */
export type DbStatus = { ok: true; pfad: string } | { ok: false; fehler: string }
/** Nachrichten, die der Kern verschickt. */
export type KernNachricht =
| { art: 'kern-bereit'; pid: number; nodeVersion: string; datenbank: DbStatus }
| { art: 'pong'; zeit: number }
| { art: 'kern-fehler'; text: string }
/** Nachrichten, die das Fenster über den MessagePort an den Kern schickt. */
export type FensterNachricht = { art: 'ping'; zeit: number }
/** Nachrichten, die das Haupt an den Kern schickt (Port-Übergabe). */
export type HauptNachricht = { art: 'fenster-port' }
/** Zustand des Haupt-Prozesses fürs Fenster (Kanal 'haupt-status'). */
export interface HauptStatus {
version: string
/** Prozess-Leine (Job Object, § 3.3): gesetzt oder mit Fehlertext. */
leine: { ok: boolean; fehler?: string }
kern: { laeuft: boolean; pid?: number; neustarts: number }
}
function istObjekt(wert: unknown): wert is Record<string, unknown> {
return typeof wert === 'object' && wert !== null
}
export function istKernNachricht(wert: unknown): wert is KernNachricht {
if (!istObjekt(wert)) return false
switch (wert.art) {
case 'kern-bereit':
return (
typeof wert.pid === 'number' &&
typeof wert.nodeVersion === 'string' &&
istDbStatus(wert.datenbank)
)
case 'pong':
return typeof wert.zeit === 'number'
case 'kern-fehler':
return typeof wert.text === 'string'
default:
return false
}
}
export function istDbStatus(wert: unknown): wert is DbStatus {
if (!istObjekt(wert)) return false
if (wert.ok === true) return typeof wert.pfad === 'string'
if (wert.ok === false) return typeof wert.fehler === 'string'
return false
}
export function istFensterNachricht(wert: unknown): wert is FensterNachricht {
return istObjekt(wert) && wert.art === 'ping' && typeof wert.zeit === 'number'
}
export function istHauptNachricht(wert: unknown): wert is HauptNachricht {
return istObjekt(wert) && wert.art === 'fenster-port'
}