diff --git a/src/renderer/components/SettingsPanel.tsx b/src/renderer/components/SettingsPanel.tsx
index 931ecba..2f84dfc 100644
--- a/src/renderer/components/SettingsPanel.tsx
+++ b/src/renderer/components/SettingsPanel.tsx
@@ -1,5 +1,5 @@
-import { useState, type ReactNode } from 'react';
-import { ChevronLeft, ChevronRight, Code, Cpu, FolderOpen, Palette, Plus, Server, TriangleAlert, Workflow, Wrench } from 'lucide-react';
+import { useEffect, useState, type ReactNode } from 'react';
+import { ChevronLeft, ChevronRight, Code, Cpu, FolderOpen, Palette, Plus, RefreshCw, Server, TriangleAlert, Workflow, Wrench } from 'lucide-react';
import { CopilotStatusCard } from '@renderer/components/CopilotStatusCard';
import { PatternEditor } from '@renderer/components/PatternEditor';
@@ -11,6 +11,7 @@ import type { DiscoveredMcpServer, DiscoveredToolingState } from '@shared/domain
import { listAcceptedDiscoveredMcpServers, listPendingDiscoveredMcpServers } from '@shared/domain/discoveredTooling';
import type { ModelDefinition } from '@shared/domain/models';
import type { PatternDefinition } from '@shared/domain/pattern';
+import type { UpdateStatus, UpdateStatusState } from '@shared/contracts/ipc';
import {
normalizeLspProfileDefinition,
normalizeMcpServerDefinition,
@@ -817,6 +818,30 @@ function TroubleshootingSection({
}) {
const [isResetting, setIsResetting] = useState(false);
const [confirmingReset, setConfirmingReset] = useState(false);
+ const [updateStatus, setUpdateStatus] = useState
({ state: 'idle' });
+ const [isCheckingManually, setIsCheckingManually] = useState(false);
+
+ useEffect(() => {
+ const unsubscribe = window.aryxApi.onUpdateStatus((status) => {
+ setUpdateStatus(status);
+ if (status.state !== 'checking') setIsCheckingManually(false);
+ });
+ return unsubscribe;
+ }, []);
+
+ async function handleCheckForUpdates() {
+ setIsCheckingManually(true);
+ try {
+ const status = await window.aryxApi.checkForUpdates();
+ setUpdateStatus(status);
+ } finally {
+ setIsCheckingManually(false);
+ }
+ }
+
+ async function handleInstallUpdate() {
+ await window.aryxApi.installUpdate();
+ }
async function handleReset() {
setIsResetting(true);
@@ -828,64 +853,148 @@ function TroubleshootingSection({
}
}
+ const isChecking = isCheckingManually || updateStatus.state === 'checking';
+
+ function getUpdateLabel(): string {
+ switch (updateStatus.state) {
+ case 'checking':
+ return 'Checking for updates…';
+ case 'available':
+ return `Update available: v${updateStatus.version ?? 'unknown'}`;
+ case 'downloading':
+ return `Downloading update${updateStatus.downloadProgress ? ` (${Math.round(updateStatus.downloadProgress.percent)}%)` : '…'}`;
+ case 'downloaded':
+ return `Update ready: v${updateStatus.version ?? 'unknown'}`;
+ case 'error':
+ return 'Update check failed';
+ default:
+ return 'Check for updates';
+ }
+ }
+
+ function getUpdateDescription(): string {
+ switch (updateStatus.state) {
+ case 'checking':
+ return 'Contacting the update server…';
+ case 'available':
+ case 'downloading':
+ return 'A new version is being downloaded and will be installed automatically.';
+ case 'downloaded':
+ return 'Restart Aryx to apply the update.';
+ case 'error':
+ return updateStatus.error ?? 'Could not reach the update server. Try again later.';
+ default:
+ return 'Manually check whether a newer version of Aryx is available.';
+ }
+ }
+
return (
-
-
-
-
-
}
- label="Open App Data Folder"
- onClick={onOpenAppDataFolder}
+
+
+
-
-
-
-
-
-
Reset Local Workspace
-
- Restore Aryx to its initial state. This permanently removes all sessions, custom patterns,
- MCP server definitions, LSP profiles, and scratchpad contents. Your GitHub Copilot sign-in
- is not affected.
-
-
- {!confirmingReset ? (
-
- ) : (
-
-
-
+
+ {/* Check for updates */}
+ {updateStatus.state === 'downloaded' ? (
+
+ ) : (
+
+ )}
+
+
}
+ label="Open App Data Folder"
+ onClick={onOpenAppDataFolder}
+ />
+
+
+
+
+
+
+
Reset Local Workspace
+
+ Restore Aryx to its initial state. This permanently removes all sessions, custom patterns,
+ MCP server definitions, LSP profiles, and scratchpad contents. Your GitHub Copilot sign-in
+ is not affected.
+
+
+ {!confirmingReset ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+ {/* Attribution footer */}
+
+
Built with
+
+
by Dávid Kaya
+
);
}