From 96762a9f6ee096570b2fe6136a4431e6ce1d1a47 Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Thu, 18 Dec 2025 23:17:05 -0500 Subject: [PATCH] feat(ui): show CLIProxyAPI update availability in dashboard - Add GET /api/cliproxy/update-check endpoint - Export checkCliproxyUpdate() function from binary-manager - Add useCliproxyUpdateCheck hook with 1-hour cache - Update ProxyStatusWidget with amber "Update" badge when available - Highlight Restart button as "Update" with amber styling when update pending --- src/cliproxy/binary-manager.ts | 17 ++++++++++ src/web-server/routes.ts | 14 ++++++++ ui/src/components/proxy-status-widget.tsx | 41 +++++++++++++++++++---- ui/src/hooks/use-cliproxy.ts | 12 +++++++ ui/src/lib/api-client.ts | 9 +++++ 5 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/cliproxy/binary-manager.ts b/src/cliproxy/binary-manager.ts index db9e38bf..be2e533a 100644 --- a/src/cliproxy/binary-manager.ts +++ b/src/cliproxy/binary-manager.ts @@ -995,6 +995,23 @@ export async function fetchLatestCliproxyVersion(): Promise { return result.latestVersion; } +/** Update check result for API response */ +export interface CliproxyUpdateCheckResult { + hasUpdate: boolean; + currentVersion: string; + latestVersion: string; + fromCache: boolean; +} + +/** + * Check for CLIProxyAPI binary updates + * @returns Update check result with version info + */ +export async function checkCliproxyUpdate(): Promise { + const manager = new BinaryManager(); + return manager.checkForUpdates(); +} + /** * Get path to version pin file * @returns Absolute path to .version-pin file diff --git a/src/web-server/routes.ts b/src/web-server/routes.ts index 4f2797f7..6f68fc27 100644 --- a/src/web-server/routes.ts +++ b/src/web-server/routes.ts @@ -46,6 +46,7 @@ import type { CLIProxyProvider } from '../cliproxy/types'; import { getClaudeEnvVars } from '../cliproxy/config-generator'; import { getProxyStatus as getProxyProcessStatus, stopProxy } from '../cliproxy/session-tracker'; import { ensureCliproxyService } from '../cliproxy/service-manager'; +import { checkCliproxyUpdate } from '../cliproxy/binary-manager'; // Unified config imports import { hasUnifiedConfig, @@ -1402,6 +1403,19 @@ apiRoutes.post('/cliproxy/proxy-stop', (_req: Request, res: Response): void => { } }); +/** + * GET /api/cliproxy/update-check - Check for CLIProxyAPI binary updates + * Returns: { hasUpdate, currentVersion, latestVersion, fromCache } + */ +apiRoutes.get('/cliproxy/update-check', async (_req: Request, res: Response): Promise => { + try { + const result = await checkCliproxyUpdate(); + res.json(result); + } catch (error) { + res.status(500).json({ error: (error as Error).message }); + } +}); + /** * GET /api/cliproxy/models - Get available models from CLIProxyAPI * Returns: { models: CliproxyModel[], byCategory: Record, totalCount: number } diff --git a/ui/src/components/proxy-status-widget.tsx b/ui/src/components/proxy-status-widget.tsx index 946d1cff..161be85a 100644 --- a/ui/src/components/proxy-status-widget.tsx +++ b/ui/src/components/proxy-status-widget.tsx @@ -2,12 +2,18 @@ * Proxy Status Widget * * Displays CLIProxy process status with start/stop/restart controls. - * Shows: running state, port, session count, uptime. + * Shows: running state, port, session count, uptime, update availability. */ -import { Activity, Power, RefreshCw, Clock, Users, Square, RotateCw } from 'lucide-react'; +import { Activity, Power, RefreshCw, Clock, Users, Square, RotateCw, ArrowUp } from 'lucide-react'; import { Button } from '@/components/ui/button'; -import { useProxyStatus, useStartProxy, useStopProxy } from '@/hooks/use-cliproxy'; +import { Badge } from '@/components/ui/badge'; +import { + useProxyStatus, + useStartProxy, + useStopProxy, + useCliproxyUpdateCheck, +} from '@/hooks/use-cliproxy'; import { cn } from '@/lib/utils'; function formatUptime(startedAt?: string): string { @@ -27,11 +33,13 @@ function formatUptime(startedAt?: string): string { export function ProxyStatusWidget() { const { data: status, isLoading } = useProxyStatus(); + const { data: updateCheck } = useCliproxyUpdateCheck(); const startProxy = useStartProxy(); const stopProxy = useStopProxy(); const isRunning = status?.running ?? false; const isActioning = startProxy.isPending || stopProxy.isPending; + const hasUpdate = updateCheck?.hasUpdate ?? false; // Restart = stop then start const handleRestart = async () => { @@ -57,6 +65,16 @@ export function ProxyStatusWidget() { )} /> CLIProxy Service + {hasUpdate && ( + v${updateCheck?.latestVersion}`} + > + + Update + + )}
@@ -90,19 +108,28 @@ export function ProxyStatusWidget() { {/* Control buttons when running */}