mirror of
https://github.com/R0m1k3/EveFlow.git
synced 2026-10-15 11:17:17 +02:00
feat: serveur MCP, heures calmes, mode mission, widget glanceable, barge-in (v2.4.0) (#14)
Serveur MCP local - Endpoint /mcp (JSON-RPC 2.0, Streamable HTTP, réponses JSON) sur le serveur webhook : initialize, tools/list, tools/call, ping. Même secret que le webhook. 14 outils : capture_screen (image MCP), lock_session, open_app, open_url, media_key, clipboard_get/set, find_files, speak_text, notify_user, set_hud_state, get_app_status, get_conversation_history, show_message. Les outils UI transitent par IPC vers le renderer. - Les mêmes actions système sont proposées au modèle en chat completions. Notifications - Heures calmes (plage horaire, franchissement de minuit), mots prioritaires, échecs de crons toujours lus, résumé vocal des messages entrants (n premières phrases), thème nuit automatique, compteur de non-lus. Conversation - Mode mission : bouton dans la barre de commande, second modèle Hermes (hermes.missionModel) pour les tâches longues. - Barge-in : la parole de l'utilisateur coupe la voix ; seuil d'énergie et ratio relevés pendant la synthèse pour ignorer l'écho. Widget compact - Bandeau glanceable : état, dernière phrase, non-lus, indicateurs heures calmes et mission. Tests : 28 tests unitaires (heures calmes, priorité, résumé), e2e Electron sous Xvfb : MCP initialize/tools/list/tools/call (presse-papiers, capture en image, état et message via le renderer), bandeau compact, aucune erreur. Claude-Session: https://claude.ai/code/session_017Wn5VX9HNbJ7N54hR24u9Y Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
af8bdc5e9d
commit
6fc38d335b
24 files changed
+668
-31
No files matched your search
@@ -1,13 +1,37 @@
|
||||
import { Maximize2, X, Minus } from 'lucide-react';
|
||||
import { Maximize2, X, Minus, Moon, Crosshair } from 'lucide-react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { bridge } from '../../lib/bridge';
|
||||
import { useSettings } from '../../state/settings';
|
||||
import { useChat } from '../../state/chat';
|
||||
import { useVoice } from '../../state/voice';
|
||||
import { CoreStage } from '../hud/CoreStage';
|
||||
import { ChatPanel } from '../chat/ChatPanel';
|
||||
|
||||
const STATE_LABEL: Record<string, string> = {
|
||||
idle: 'veille',
|
||||
listening: 'écoute',
|
||||
thinking: 'réflexion',
|
||||
speaking: 'parle',
|
||||
alert: 'alerte',
|
||||
error: 'erreur',
|
||||
success: 'terminé'
|
||||
};
|
||||
|
||||
/** Compact mode: a glanceable strip (state, unread, last sentence) above the mini chat. */
|
||||
export function CompactWidget() {
|
||||
const assistantName = useSettings((s) => s.settings.assistantName);
|
||||
const compactOpacity = useSettings((s) => s.settings.ui.compactOpacity);
|
||||
const { hud, hudOverride, unread, missionMode, quiet, last } = useChat(
|
||||
useShallow((s) => {
|
||||
const lastAssistant = [...s.messages].reverse().find((m) => m.role === 'assistant' && m.content.trim());
|
||||
return { hud: s.hud, hudOverride: s.hudOverride, unread: s.unread, missionMode: s.missionMode, quiet: s.quiet, last: lastAssistant?.content ?? '' };
|
||||
})
|
||||
);
|
||||
const wake = useVoice((s) => s.wake);
|
||||
const api = bridge();
|
||||
const state = hudOverride ?? hud;
|
||||
const label = state === 'idle' && wake === 'spotting' ? 'à l’écoute du mot-clé' : STATE_LABEL[state] ?? state;
|
||||
const sentence = last.replace(/```[\s\S]*?```/g, ' ').replace(/[#*_>`|]/g, '').replace(/\s+/g, ' ').trim().slice(0, 140);
|
||||
return (
|
||||
<div className="compact-root" style={{ ['--compact-opacity' as string]: compactOpacity }}>
|
||||
<div className="compact-head">
|
||||
@@ -21,6 +45,15 @@ export function CompactWidget() {
|
||||
)}
|
||||
</div>
|
||||
<CoreStage compact />
|
||||
<div className="compact-glance" onClick={() => useChat.getState().markRead()} title={sentence}>
|
||||
<span className={`state${state === 'alert' || state === 'error' ? ' alert' : ''}`}>{label}</span>
|
||||
<span className="last">{sentence || 'Aucun message pour l’instant.'}</span>
|
||||
<span className="badges">
|
||||
{missionMode && <Crosshair size={12} className="mission" aria-label="mode mission" />}
|
||||
{quiet && <Moon size={12} aria-label="heures calmes" />}
|
||||
{unread > 0 && <span className="unread" aria-label={`${unread} non lus`}>{unread}</span>}
|
||||
</span>
|
||||
</div>
|
||||
<div className="compact-body">
|
||||
<ChatPanel compact />
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user