import { Fragment, useEffect, useState } from 'react'; import { useShallow } from 'zustand/react/shallow'; import { AlertTriangle, Wrench, CalendarClock, Sparkles, Layers, History, Play, Pause, Trash2, Pencil, Plus, Save, X, RefreshCw, CheckCircle2, XCircle, Loader2, Bot, Cpu, GitBranch, Webhook, FolderOpen } from 'lucide-react'; import { formatDateTime, formatTime, previewText } from '../../lib/text'; import { bridge } from '../../lib/bridge'; import { jobSchedule, jobOutput } from '../../services/hermes/client'; import type { HermesJob, HermesJobDraft } from '../../services/hermes/types'; import { useChat } from '../../state/chat'; import { jobStatus, useHermes } from '../../state/hermes'; import { useSettings } from '../../state/settings'; type Tab = 'activity' | 'jobs' | 'skills' | 'sessions' | 'link'; const emptyDraft = (): HermesJobDraft => ({ name: '', schedule: 'every 1h', prompt: '', deliver: 'local' }); function ActivityTab() { const activity = useChat((s) => s.activity); const items = [...activity].reverse(); if (items.length === 0) return
Aucune activité outil pour l’instant.
; return (
{items.map((a) => (
{a.status === 'running' ? : a.status === 'done' ? : }
{a.kind === 'subagent' ? <> : null}{a.name}
{a.detail &&
{previewText(a.detail, 220)}
} {a.output &&
{previewText(a.output, 220)}
}
{formatTime(a.startedAt)}{a.endedAt ? ` · ${((a.endedAt - a.startedAt) / 1000).toFixed(1)}s` : ''}
))}
); } function JobsTab() { const jobs = useHermes((s) => s.jobs); const jobsError = useHermes((s) => s.jobsError); const busy = useHermes((s) => s.busy); const lastSyncAt = useHermes((s) => s.lastSyncAt); const refreshJobs = useHermes((s) => s.refreshJobs); const createJob = useHermes((s) => s.createJob); const updateJob = useHermes((s) => s.updateJob); const jobAction = useHermes((s) => s.jobAction); const setError = useChat((s) => s.setError); const [draft, setDraft] = useState(emptyDraft); const [editing, setEditing] = useState(null); const [showEditor, setShowEditor] = useState(false); const run = async (task: Promise) => { try { await task; } catch (err) { setError(`Cron Hermes : ${(err as Error).message}`); } }; const startEdit = (job: HermesJob) => { setEditing(job.id); setDraft({ name: job.name ?? job.id, schedule: jobSchedule(job), prompt: job.prompt ?? '', deliver: job.deliver ?? 'local' }); setShowEditor(true); }; const save = async () => { if (editing) await run(updateJob(editing, draft)); else await run(createJob(draft)); setEditing(null); setDraft(emptyDraft()); setShowEditor(false); }; const valid = draft.name.trim() && draft.schedule.trim() && draft.prompt.trim(); return (
{lastSyncAt ? `sync ${formatTime(lastSyncAt)}` : 'non synchronisé'}
{showEditor && (
setDraft({ ...draft, name: e.target.value })} /> setDraft({ ...draft, schedule: e.target.value })} />