fox-desktop/docs/superpowers/specs/2026-05-11-fox-desktop-desi...

183 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Fox Desktop — Design Spec
**Datum:** 2026-05-11
**Status:** Genehmigt
## Überblick
Fox Desktop ist eine native Mac-App (Electron), die als dünne Hülle um die bestehende Laravel-HUD-App (`fox.pxo.at/hud`) fungiert. Electron fügt native Mac-Fähigkeiten hinzu, ohne das HUD neu zu schreiben.
## Architektur
```
Mac OS
├── Tray Icon (Menu Bar)
├── BrowserWindow (Overlay, fullscreen, always-on-top)
│ └── lädt https://fox.pxo.at/hud
│ └── preload.js injiziert window.foxBridge
├── Global Shortcut: Cmd+Shift+F
└── Python Subprocess: openwakeword ("hey_jarvis")
└── stdout "WAKE" → IPC → showHud()
```
Der Electron-Main-Process hat **keine** eigene WebSocket-Verbindung zu Reverb. Der WebSocket-Kanal gehört der HUD-Seite selbst. Electron ist reiner Plattform-Layer.
## Prinzipien
- **Pure Shell:** Electron kapselt, erweitert nicht die App-Logik
- **Bridge ist optional:** `window.foxBridge` wird nur in Electron injiziert; das HUD funktioniert im normalen Browser unverändert weiter
- **Kein Vite Build:** Es gibt kein eigenes Frontend — nur Electron-Module und Python-Script
- **Kein electron-builder** vorerst — erst nach stabilem Dev-Setup
## Dateien
| Datei | Aufgabe |
|---|---|
| `package.json` | Electron-App-Konfiguration, npm-Scripts |
| `electron/main.js` | App-Lifecycle, IPC-Handler, globaler Shortcut |
| `electron/hud.js` | BrowserWindow erstellen, show/hide mit Transition |
| `electron/tray.js` | Menu Bar Icon (Template Image) + Kontextmenü |
| `electron/wakeword.js` | Python-Subprocess starten, Auto-Restart bei Absturz |
| `electron/mac-agent.js` | AppleScript-Ausführung via osascript |
| `electron/preload.js` | `window.foxBridge` in HUD-Seite injizieren |
| `python/wakeword.py` | OpenWakeWord Loop, schreibt "WAKE" auf stdout |
| `assets/fox-tray.png` | 16×16 Menu Bar Icon (Template Image) |
## Datenflüsse
### HUD öffnen (Wakeword)
```
"hey jarvis" gesprochen
→ python/wakeword.py erkennt Wakeword
→ stdout: "WAKE\n"
→ electron/wakeword.js liest stdout
→ IPC intern → showHud()
→ BrowserWindow.show() + focus()
→ webContents.send('hud-show')
→ HUD CSS-Transition startet
```
### HUD öffnen (Tastaturkürzel / Tray)
```
Cmd+Shift+F gedrückt ODER Tray-Icon geklickt
→ main.js globalShortcut / tray.on('click')
→ showHud()
```
### Mac-Befehl aus HUD
```
HUD JavaScript: await window.foxBridge.macCommand('spotify_play')
→ preload.js: ipcRenderer.invoke('mac-command', 'spotify_play')
→ main.js IPC Handler
→ electron/mac-agent.js: executeMacCommand('spotify_play')
→ osascript: tell application "Spotify" to play
→ Rückgabewert { success: true, output: '' } → HUD
```
### HUD schließen
```
ESC im HUD ODER foxBridge.hideHud() ODER Tray-Menü "Verstecken"
→ ipcRenderer.send('hide-hud')
→ main.js → hideHud()
→ webContents.send('hud-hide') ← CSS-Transition startet
→ setTimeout 600ms → BrowserWindow.hide()
```
## BrowserWindow Konfiguration
```javascript
{
width: screenWidth,
height: screenHeight,
x: 0, y: 0,
frame: false,
transparent: true,
alwaysOnTop: true,
show: false,
skipTaskbar: true,
hasShadow: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
webSecurity: false, // Remote URL + preload injection
allowRunningInsecureContent: true,
}
}
```
`setAlwaysOnTop(true, 'screen-saver')` und `setVisibleOnAllWorkspaces(true)` nach dem Erstellen.
## window.foxBridge API
```javascript
window.foxBridge = {
sendMessage(text), // Text an Fox Laravel via IPC
hideHud(), // HUD verstecken
macCommand(cmd), // AppleScript-Befehl ausführen (async, gibt Result zurück)
onFoxAction(callback), // Fox-Aktionen empfangen
onHudShow(callback), // HUD-Show-Event
onHudHide(callback), // HUD-Hide-Event
onStartListening(callback), // Mikrofon-Start-Signal
onPlayAudio(callback), // Audio-URL zum Abspielen
}
```
## Mac-Agent Befehle
Vordefinierte Shortcuts (z.B. `spotify_play`, `mail_open`, `volume_up`) sowie generische Formen:
- `script:<applescript>` — direktes AppleScript
- `open:<url>` — URL im Standardbrowser öffnen
- `app:<name>` — Mac-App öffnen
- `save:<json>` — Datei auf Desktop schreiben
## Wakeword (OpenWakeWord)
- Python 3, `openwakeword`, `pyaudio`, `numpy`, `tflite-runtime`
- Eingebautes Modell: `hey_jarvis` (kein API-Key, kein Training nötig)
- Electron spawnt `python3 python/wakeword.py` als Child-Process
- Auto-Restart nach Absturz (2s Delay)
- Später: eigenes "hey fox" Modell trainierbar
## Laravel HUD — Anpassungsstellen
Diese 3 optionalen Punkte müssen in `fox-hud.blade.php` / HUD-JavaScript hinzugefügt werden:
1. **ESC schließt HUD:**
```javascript
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') window.foxBridge?.hideHud();
});
```
2. **Mac-Aktionen in `onAction()`:**
```javascript
if (payload.action === 'spotify_play') {
await window.foxBridge?.macCommand('spotify_play');
return;
}
// ... weitere Mac-Aktionen
```
3. **Nachricht senden (optional, wenn direkt ohne Livewire):**
```javascript
window.foxBridge?.sendMessage(text);
```
## Deployment
- Dev: `npm start` (Electron lädt fox.pxo.at/hud direkt)
- LaunchAgent `~/Library/LaunchAgents/at.pxo.fox.plist` für Auto-Start beim Login
- `electron-builder` für DMG-Build — später
## Abhängigkeiten
**npm:**
- `electron` ^28
- `axios` ^1.6 (für sendMessage POST)
**Python:**
- `openwakeword`
- `pyaudio`
- `numpy`
- `tflite-runtime`