diff --git a/src/cliproxy/binary/types.ts b/src/cliproxy/binary/types.ts index 12eda079..c82a05cc 100644 --- a/src/cliproxy/binary/types.ts +++ b/src/cliproxy/binary/types.ts @@ -24,14 +24,30 @@ export const VERSION_CACHE_DURATION_MS = 60 * 60 * 1000; /** Version pin file name - stores user's explicit version choice */ export const VERSION_PIN_FILE = '.version-pin'; -/** GitHub API URL for latest release (CLIProxyAPIPlus fork with Kiro + Copilot support) */ +/** + * GitHub API URLs - backend-specific + * @deprecated Use getGitHubApiUrls(backend) instead + */ export const GITHUB_API_LATEST_RELEASE = 'https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases/latest'; - -/** GitHub API URL for all releases */ export const GITHUB_API_ALL_RELEASES = 'https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases'; +/** GitHub repos per backend */ +export const GITHUB_REPOS = { + original: 'router-for-me/CLIProxyAPI', + plus: 'router-for-me/CLIProxyAPIPlus', +} as const; + +/** Get GitHub API URLs for specific backend */ +export function getGitHubApiUrls(backend: 'original' | 'plus') { + const repo = GITHUB_REPOS[backend]; + return { + latestRelease: `https://api.github.com/repos/${repo}/releases/latest`, + allReleases: `https://api.github.com/repos/${repo}/releases`, + }; +} + /** Version list cache structure */ export interface VersionListCache { versions: string[]; diff --git a/src/cliproxy/binary/version-cache.ts b/src/cliproxy/binary/version-cache.ts index d7f11614..2527fd76 100644 --- a/src/cliproxy/binary/version-cache.ts +++ b/src/cliproxy/binary/version-cache.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCliproxyDir, getBinDir } from '../config-generator'; +import { getBinDir } from '../config-generator'; import { VersionCache, VERSION_CACHE_DURATION_MS, @@ -181,17 +181,19 @@ export function migrateVersionPin(backend: CLIProxyBackend): void { const VERSION_LIST_CACHE_FILE = '.version-list-cache.json'; /** - * Get path to version list cache file + * Get path to version list cache file (backend-specific) */ -export function getVersionListCachePath(): string { - return path.join(getCliproxyDir(), VERSION_LIST_CACHE_FILE); +export function getVersionListCachePath(backend: CLIProxyBackend = DEFAULT_BACKEND): string { + return path.join(getBinDir(), backend, VERSION_LIST_CACHE_FILE); } /** - * Read version list cache if still valid + * Read version list cache if still valid (backend-specific) */ -export function readVersionListCache(): VersionListCache | null { - const cachePath = getVersionListCachePath(); +export function readVersionListCache( + backend: CLIProxyBackend = DEFAULT_BACKEND +): VersionListCache | null { + const cachePath = getVersionListCachePath(backend); if (!fs.existsSync(cachePath)) { return null; } @@ -212,10 +214,13 @@ export function readVersionListCache(): VersionListCache | null { } /** - * Write version list to cache + * Write version list to cache (backend-specific) */ -export function writeVersionListCache(cache: VersionListCache): void { - const cachePath = getVersionListCachePath(); +export function writeVersionListCache( + cache: VersionListCache, + backend: CLIProxyBackend = DEFAULT_BACKEND +): void { + const cachePath = getVersionListCachePath(backend); try { fs.mkdirSync(path.dirname(cachePath), { recursive: true }); diff --git a/src/cliproxy/binary/version-checker.ts b/src/cliproxy/binary/version-checker.ts index 9a15faba..a76d4996 100644 --- a/src/cliproxy/binary/version-checker.ts +++ b/src/cliproxy/binary/version-checker.ts @@ -11,12 +11,7 @@ import { readVersionListCache, writeVersionListCache, } from './version-cache'; -import { - UpdateCheckResult, - GITHUB_API_LATEST_RELEASE, - GITHUB_API_ALL_RELEASES, - VersionListResult, -} from './types'; +import { UpdateCheckResult, VersionListResult, getGitHubApiUrls } from './types'; import { CLIPROXY_MAX_STABLE_VERSION, CLIPROXY_FAULTY_RANGE, @@ -61,9 +56,15 @@ export function isVersionFaulty(version: string): boolean { /** * Fetch latest version from GitHub API + * @param verbose Enable verbose logging + * @param backend Backend to fetch version for (uses correct GitHub repo) */ -export async function fetchLatestVersion(verbose = false): Promise { - const response = await fetchJson(GITHUB_API_LATEST_RELEASE, verbose); +export async function fetchLatestVersion( + verbose = false, + backend: CLIProxyBackend = DEFAULT_BACKEND +): Promise { + const urls = getGitHubApiUrls(backend); + const response = await fetchJson(urls.latestRelease, verbose); // Extract version from tag_name (format: "v6.5.27" or "6.5.27") const tagName = response.tag_name as string; @@ -102,8 +103,8 @@ export async function checkForUpdates( }; } - // Fetch from GitHub API - const latestVersion = await fetchLatestVersion(verbose); + // Fetch from GitHub API (backend-specific repo) + const latestVersion = await fetchLatestVersion(verbose, backend); const now = Date.now(); writeVersionCache(latestVersion, backend); @@ -119,10 +120,15 @@ export async function checkForUpdates( /** * Fetch all available versions from GitHub releases * Caches result for 1 hour to avoid rate limiting + * @param verbose Enable verbose logging + * @param backend Backend to fetch versions for (uses correct GitHub repo) */ -export async function fetchAllVersions(verbose = false): Promise { - // Try cache first - const cache = readVersionListCache(); +export async function fetchAllVersions( + verbose = false, + backend: CLIProxyBackend = DEFAULT_BACKEND +): Promise { + // Try cache first (backend-specific) + const cache = readVersionListCache(backend); if (cache) { if (verbose) { console.error(`[cliproxy] Using cached version list (${cache.versions.length} versions)`); @@ -130,8 +136,9 @@ export async function fetchAllVersions(verbose = false): Promise; @@ -154,6 +161,6 @@ export async function fetchAllVersions(verbose = false): Promise => { try { - const result = await fetchAllVersions(); - const currentVersion = getInstalledCliproxyVersion(); + const backend = getConfiguredBackend(); + const result = await fetchAllVersions(false, backend); + const currentVersion = getInstalledCliproxyVersion(backend); res.json({ ...result, diff --git a/ui/src/components/monitoring/proxy-status-widget.tsx b/ui/src/components/monitoring/proxy-status-widget.tsx index c6dd5dc2..423ad17e 100644 --- a/ui/src/components/monitoring/proxy-status-widget.tsx +++ b/ui/src/components/monitoring/proxy-status-widget.tsx @@ -289,7 +289,7 @@ export function ProxyStatusWidget() { {updateCheck?.backendLabel ?? 'CLIProxy'} - {/* Right side: icon buttons when running */} + {/* Right side: icon buttons */}
{isLoading ? ( @@ -310,16 +310,15 @@ export function ProxyStatusWidget() { isPending={stopProxy.isPending} variant="destructive-ghost" /> - setIsExpanded(!isExpanded)} - className={isExpanded ? 'bg-muted' : undefined} - /> - ) : ( - - )} + ) : null} + {/* Settings button always visible */} + setIsExpanded(!isExpanded)} + className={isExpanded ? 'bg-muted' : undefined} + />
@@ -376,82 +375,80 @@ export function ProxyStatusWidget() { )} - {/* Expanded section: Version Management */} - {isRunning && ( - - - {/* Section header */} -

Version Management

+ {/* Expanded section: Version Management (available even when not running) */} + + + {/* Section header */} +

Version Management

- {/* Version picker row */} -
- {/* Dropdown - full width, no truncation */} - + {/* Version picker row */} +
+ {/* Dropdown - full width, no truncation */} + - {/* Install button */} - -
- - {/* Stability warning for selected version */} - {selectedVersion && - versionsData?.maxStableVersion && - isNewerVersionClient(selectedVersion, versionsData.maxStableVersion) && ( -
- - Versions above {versionsData.maxStableVersion} have known issues -
+ {/* Install button */} + +
- {/* Sync time */} - {updateCheck?.checkedAt && ( -
- Last checked {formatTimeAgo(updateCheck.checkedAt)} + {/* Stability warning for selected version */} + {selectedVersion && + versionsData?.maxStableVersion && + isNewerVersionClient(selectedVersion, versionsData.maxStableVersion) && ( +
+ + Versions above {versionsData.maxStableVersion} have known issues
)} - - - )} + + {/* Sync time */} + {updateCheck?.checkedAt && ( +
+ Last checked {formatTimeAgo(updateCheck.checkedAt)} +
+ )} + + {/* Not running state */} {!isRunning && (