feat(win): hermes wsl installer hooks
This commit is contained in:
@@ -47,6 +47,13 @@ type ControlUiInfo = {
|
||||
port: number;
|
||||
};
|
||||
|
||||
type HermesStatus = {
|
||||
installState: string;
|
||||
runState: string;
|
||||
version?: string;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export function Settings() {
|
||||
const { t } = useTranslation('settings');
|
||||
const {
|
||||
@@ -98,6 +105,8 @@ export function Settings() {
|
||||
const [wsDiagnosticEnabled, setWsDiagnosticEnabled] = useState(false);
|
||||
const [showTelemetryViewer, setShowTelemetryViewer] = useState(false);
|
||||
const [telemetryEntries, setTelemetryEntries] = useState<UiTelemetryEntry[]>([]);
|
||||
const [hermesStatus, setHermesStatus] = useState<HermesStatus | null>(null);
|
||||
const [hermesBusy, setHermesBusy] = useState(false);
|
||||
|
||||
const isWindows = window.electron.platform === 'win32';
|
||||
const showCliTools = true;
|
||||
@@ -233,6 +242,51 @@ export function Settings() {
|
||||
}
|
||||
};
|
||||
|
||||
const refreshHermesStatus = async () => {
|
||||
try {
|
||||
const result = await hostApiFetch<{ success: boolean; status?: HermesStatus }>('/api/hermes/status');
|
||||
if (result.success && result.status) {
|
||||
setHermesStatus(result.status);
|
||||
}
|
||||
} catch {
|
||||
setHermesStatus({ installState: 'error', runState: 'stopped', error: 'Failed to query Hermes status' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleInstallHermes = async () => {
|
||||
setHermesBusy(true);
|
||||
try {
|
||||
const result = await hostApiFetch<{ success: boolean; stderr?: string }>('/api/hermes/install', { method: 'POST' });
|
||||
if (result.success) {
|
||||
toast.success('Hermes installed');
|
||||
} else {
|
||||
toast.error(result.stderr || 'Hermes install failed');
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(toUserMessage(error) || 'Hermes install failed');
|
||||
} finally {
|
||||
setHermesBusy(false);
|
||||
void refreshHermesStatus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleStartHermes = async () => {
|
||||
setHermesBusy(true);
|
||||
try {
|
||||
const result = await hostApiFetch<{ success: boolean; stderr?: string }>('/api/hermes/start', { method: 'POST' });
|
||||
if (result.success) {
|
||||
toast.success('Hermes started');
|
||||
} else {
|
||||
toast.error(result.stderr || 'Hermes start failed');
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(toUserMessage(error) || 'Hermes start failed');
|
||||
} finally {
|
||||
setHermesBusy(false);
|
||||
void refreshHermesStatus();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!showCliTools) return;
|
||||
let cancelled = false;
|
||||
@@ -262,6 +316,12 @@ export function Settings() {
|
||||
return () => { cancelled = true; };
|
||||
}, [devModeUnlocked, showCliTools]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isWindows) return;
|
||||
if (gatewayBackend !== 'hermes') return;
|
||||
void refreshHermesStatus();
|
||||
}, [gatewayBackend, isWindows]);
|
||||
|
||||
const handleCopyCliCommand = async () => {
|
||||
if (!openclawCliCommand) return;
|
||||
try {
|
||||
@@ -648,6 +708,56 @@ export function Settings() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isWindows && gatewayBackend === 'hermes' && (
|
||||
<div className="p-4 rounded-2xl bg-black/5 dark:bg-white/5 border border-black/5 dark:border-white/5 space-y-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<Label className="text-[14px] font-medium text-foreground">Hermes status</Label>
|
||||
<p className="text-[12px] text-muted-foreground mt-1">
|
||||
{hermesStatus
|
||||
? `${hermesStatus.installState} / ${hermesStatus.runState}${hermesStatus.version ? ` (${hermesStatus.version})` : ''}`
|
||||
: 'unknown'}
|
||||
</p>
|
||||
{hermesStatus?.error ? (
|
||||
<p className="text-[12px] text-red-600 dark:text-red-500 mt-1">
|
||||
{hermesStatus.error}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={refreshHermesStatus}
|
||||
disabled={hermesBusy}
|
||||
className="rounded-full h-8 px-4 border-black/10 dark:border-white/10 bg-transparent hover:bg-black/5 dark:hover:bg-white/5"
|
||||
>
|
||||
<RefreshCw className={`h-3.5 w-3.5 mr-1.5${hermesBusy ? ' animate-spin' : ''}`} />
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleInstallHermes}
|
||||
disabled={hermesBusy}
|
||||
className="rounded-full h-8 px-4 border-black/10 dark:border-white/10 bg-transparent hover:bg-black/5 dark:hover:bg-white/5"
|
||||
>
|
||||
Install Hermes
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleStartHermes}
|
||||
disabled={hermesBusy}
|
||||
className="rounded-full h-8 px-4 border-black/10 dark:border-white/10 bg-transparent hover:bg-black/5 dark:hover:bg-white/5"
|
||||
>
|
||||
Start Hermes
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user