From a45069af5e2871d82460d94f2e82587d7c491ee1 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Sun, 30 Aug 2026 17:28:46 +0200 Subject: [PATCH] =?UTF-8?q?feat(v5):=20Etappe=20W-1=20=E2=80=94=20Laufwerk?= =?UTF-8?q?:=20Wache,=20Typ,=20Auswerfen=20mit=20Nachsehen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kern/laufwerk in drei Schichten: codes.ts (Steuercodes HERGELEITET wie win_ioctl.py, gegen die Doku-Zahlen getestet), win32.ts (der einzige koffi-Ort im Kern, Muster aus beweise/laufwerk.js), disc.ts (Logik gegen die LaufwerkApi-Schnittstelle — classify mit den cdrom.py-Schwellen, Geraete-Info mit ready/empty/unknown + Klartext-Grund, Auswurf als entriegeln→auswerfen→NACHSEHEN mit injizierbarem Warten). Dazu wache.ts im 3-Sekunden-Takt (§ 5 Plan A): Uebergangslogik pur, gescheiterte Runde behaelt den Stand (R2) und meldet laut (R4). Fenster zeigt Laufwerke live (Modell, Typ, Groesse, Grund) mit Auswerfen-Knopf; Ereigniszeilen fuer Disc rein/raus und Fehler. Bündel-Falle gefunden und behoben: Ein woertliches require überlebt Rollup nicht — win32 wird per dynamischem import() als eigener Chunk gebaut; der Fehler war dank R4 im Fenster sichtbar statt still. Gemessen am echten BU40N (30.08.2026, RIPPY_MESSUNG=1): Laufwerk G: status=ready typ=bluray groesse=33759690752 modell=HL-DT-ST BD-RE BU40N 1.03 serial=0025114C0149 Der Auswurf-Beweis (messung.auswurf) folgt am Ende der Sitzung — der BU40N kann die Schublade nicht selbst einziehen. 52 Tests gruen (Steuercodes, classify, Auswurf-Ablauf, Geraete-Info, Wache, Smoke weiterhin gruen mit Laufwerks-Kachel im Bild). Co-Authored-By: Claude Fable 5 --- rippy-windows/src/fenster/App.tsx | 181 +++++++++--- rippy-windows/src/fenster/kernverbindung.ts | 82 ++++-- rippy-windows/src/gemeinsam/nachrichten.ts | 44 ++- rippy-windows/src/haupt/index.ts | 9 +- rippy-windows/src/kern/index.ts | 80 +++++- rippy-windows/src/kern/laufwerk/codes.ts | 94 ++++++ rippy-windows/src/kern/laufwerk/disc.ts | 304 ++++++++++++++++++++ rippy-windows/src/kern/laufwerk/wache.ts | 107 +++++++ rippy-windows/src/kern/laufwerk/win32.ts | 88 ++++++ rippy-windows/test/laufwerk.test.ts | 282 ++++++++++++++++++ rippy-windows/test/messung.auswurf.test.ts | 47 +++ rippy-windows/test/messung.laufwerk.test.ts | 42 +++ rippy-windows/test/wache.test.ts | 90 ++++++ 13 files changed, 1377 insertions(+), 73 deletions(-) create mode 100644 rippy-windows/src/kern/laufwerk/codes.ts create mode 100644 rippy-windows/src/kern/laufwerk/disc.ts create mode 100644 rippy-windows/src/kern/laufwerk/wache.ts create mode 100644 rippy-windows/src/kern/laufwerk/win32.ts create mode 100644 rippy-windows/test/laufwerk.test.ts create mode 100644 rippy-windows/test/messung.auswurf.test.ts create mode 100644 rippy-windows/test/messung.laufwerk.test.ts create mode 100644 rippy-windows/test/wache.test.ts diff --git a/rippy-windows/src/fenster/App.tsx b/rippy-windows/src/fenster/App.tsx index aa8f399..f736079 100644 --- a/rippy-windows/src/fenster/App.tsx +++ b/rippy-windows/src/fenster/App.tsx @@ -1,9 +1,9 @@ -// W-0-Statusbild: zeigt, dass die drei Prozesse stehen und miteinander -// reden. Die echte Oberfläche (Dashboard, Bibliothek, Einstellungen) ist -// Etappe W-5 — hier geht es nur darum, das Gerüst SICHTBAR zu beweisen. +// Statusbild W-0/W-1: die drei Prozesse plus die echten Laufwerke aus der +// Disc-Wache. Die große Oberfläche (Dashboard, Bibliothek, Einstellungen) +// ist Etappe W-5 — hier wird das Gerüst SICHTBAR bewiesen. import { useEffect, useState } from 'react' -import type { HauptStatus } from '../gemeinsam/nachrichten' -import { aufVerbindung, verbindungStarten, type Verbindung } from './kernverbindung' +import type { GeraeteInfo, HauptStatus } from '../gemeinsam/nachrichten' +import { aufVerbindung, auswerfen, verbindungStarten, type Verbindung } from './kernverbindung' function istHauptStatus(wert: unknown): wert is HauptStatus { return ( @@ -13,6 +13,18 @@ function istHauptStatus(wert: unknown): wert is HauptStatus { ) } +function gb(bytes: number): string { + return `${(bytes / 1e9).toFixed(2).replace('.', ',')} GB` +} + +const TYP_NAMEN: Record = { + cd: 'Audio-CD', + dvd: 'DVD', + bluray: 'Blu-ray', + uhd: '4K-UHD', + unknown: 'unbekannt', +} + interface KachelProps { titel: string zustand: 'ok' | 'fehler' | 'wartet' @@ -39,12 +51,52 @@ function Kachel({ titel, zustand, zeilen }: KachelProps) { ) } +function LaufwerkKachel({ geraet }: { geraet: GeraeteInfo }) { + const zustand = geraet.status === 'ready' ? 'ok' : geraet.status === 'empty' ? 'wartet' : 'fehler' + const punktFarbe = + zustand === 'ok' ? 'bg-emerald-400' : zustand === 'fehler' ? 'bg-red-400' : 'bg-slate-500' + return ( +
+
+
+ +

{geraet.name}

+
+ +
+
+

{geraet.modell.length > 0 ? geraet.modell : 'Modell unbekannt'}

+ {geraet.status === 'ready' && ( +

+ {TYP_NAMEN[geraet.typ]} + {geraet.groesseBytes > 0 ? ` · ${gb(geraet.groesseBytes)}` : ''} +

+ )} + {geraet.status === 'empty' &&

keine Disc eingelegt

} + {geraet.status === 'unknown' &&

{geraet.grund}

} + {geraet.status !== 'unknown' && geraet.grund.length > 0 && ( +

{geraet.grund}

+ )} +
+
+ ) +} + export default function App() { const [haupt, setHaupt] = useState(null) const [verbindung, setVerbindung] = useState({ verbunden: false, kern: null, pongLatenzMs: null, + laufwerke: [], + meldungen: [], }) useEffect(() => { @@ -63,52 +115,91 @@ export default function App() {

Rippy

- v{haupt?.version ?? '…'} · Etappe W-0 — Gerüst + v{haupt?.version ?? '…'} · Etappe W-1 — Laufwerk

- Drei Prozesse, eine Datenbank, eine Leine — das Fundament für Rippy v5. + Drei Prozesse, eine Datenbank, eine Leine — und die Disc-Wache läuft.

-
- - - - +
+
+

+ Laufwerke +

+ {verbindung.laufwerke.length === 0 ? ( +

+ {verbindung.verbunden ? 'Kein optisches Laufwerk gefunden.' : 'Warte auf den Kern …'} +

+ ) : ( +
+ {verbindung.laufwerke.map((geraet) => ( + + ))} +
+ )} +
+ +
+

+ Gerüst +

+
+ + + + +
+
+ + {verbindung.meldungen.length > 0 && ( +
+

+ Ereignisse +

+
+ {verbindung.meldungen.map((zeile, i) => ( +

+ {zeile} +

+ ))} +
+
+ )}