Skip to content

Commit b3d8900

Browse files
authored
Merge pull request #24 from 0xtbug/dev
feat(providers): introduce `PLUS_ONLY_PROVIDERS` constant to identify CLIPROXYAPI VERSION
2 parents e331f91 + 700f958 commit b3d8900

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

src/constants/providers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export type ProviderId = typeof PROVIDERS[number]['id'];
1313

1414
export const WEBUI_SUPPORTED: OAuthProvider[] = ['codex', 'anthropic', 'antigravity', 'gemini-cli', 'kiro'];
1515

16+
export const PLUS_ONLY_PROVIDERS: ProviderId[] = ['copilot', 'kiro'];
17+
1618
export const CALLBACK_PROVIDER_MAP: Partial<Record<OAuthProvider, string>> = {
1719
'gemini-cli': 'gemini'
1820
};

src/features/providers/ProvidersPage.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useTranslation } from 'react-i18next';
22
import { motion } from 'motion/react';
3-
import { PROVIDERS } from '@/constants';
3+
import { PROVIDERS, PLUS_ONLY_PROVIDERS } from '@/constants';
44
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/shared/components/ui/card';
55
import { Button } from '@/shared/components/ui/button';
66
import { Badge } from '@/shared/components/ui/badge';
@@ -20,6 +20,7 @@ import {
2020
Key,
2121
Download,
2222
Upload,
23+
Lock,
2324
} from 'lucide-react';
2425
import {
2526
Dialog,
@@ -50,6 +51,7 @@ export function ProvidersPage() {
5051
const { t } = useTranslation();
5152
const {
5253
isAuthenticated,
54+
isNonPlusServer,
5355
files,
5456
loadingFiles,
5557
filesError,
@@ -532,6 +534,12 @@ export function ProvidersPage() {
532534
{provider.requiresProjectId && (
533535
<Badge variant="outline" className="text-[10px] h-5">Project ID</Badge>
534536
)}
537+
{isNonPlusServer && PLUS_ONLY_PROVIDERS.includes(provider.id) && (
538+
<Badge variant="outline" className="text-[10px] h-5 border-amber-500/50 text-amber-500 flex items-center gap-1">
539+
<Lock className="h-3 w-3" />
540+
Plus
541+
</Badge>
542+
)}
535543
</div>
536544

537545
<div className="flex items-center gap-2">

src/features/providers/useProvidersPresenter.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,32 @@ import { useHeaderRefresh } from '@/shared/hooks';
77
import { AuthFile, type ProviderId } from '@/types';
88
import { openExternalUrl, isTauri } from '@/services/tauri';
99
import { toast } from 'sonner';
10+
import { PLUS_ONLY_PROVIDERS } from '@/constants';
11+
import { useCliProxyStore } from '@/features/settings/cliProxy.store';
12+
13+
export function detectIsPlusVersion(serverVersion: string | null | undefined): boolean | null {
14+
if (!serverVersion) return null;
15+
const cleaned = serverVersion.trim().replace(/^v/i, '');
16+
if (!cleaned) return null;
17+
return /-/.test(cleaned);
18+
}
19+
20+
export function checkIsNonPlusServer(): boolean {
21+
const { serverVersion } = useAuthStore.getState();
22+
const fromServerVersion = detectIsPlusVersion(serverVersion);
23+
if (fromServerVersion !== null) return !fromServerVersion;
24+
25+
const { currentInstalledVersion, cliProxyVersion, exePath } = useCliProxyStore.getState();
26+
const fromInstalledVersion = detectIsPlusVersion(currentInstalledVersion);
27+
if (fromInstalledVersion !== null) return !fromInstalledVersion;
28+
29+
if (cliProxyVersion === 'plus') return false;
30+
if (cliProxyVersion === 'standard') return true;
31+
32+
if (exePath && exePath.toLowerCase().includes('plus')) return false;
33+
34+
return false;
35+
}
1036

1137
export type ProviderStatus = 'idle' | 'waiting' | 'polling' | 'success' | 'error';
1238

@@ -276,6 +302,12 @@ export function useProvidersPresenter() {
276302
}, [stopPolling, loadFiles, updateProviderState, t]);
277303

278304
const startAuth = useCallback(async (providerId: ProviderId, options?: { projectId?: string }) => {
305+
// Block plus-only providers when using standard (non-plus) CLIProxyAPI
306+
if (PLUS_ONLY_PROVIDERS.includes(providerId) && checkIsNonPlusServer()) {
307+
toast.error(t('providers.plusOnly', 'This provider requires CLIProxyAPI Plus version'));
308+
return;
309+
}
310+
279311
stopPolling(providerId);
280312
updateProviderState(providerId, { status: 'waiting', error: undefined });
281313
setSelectedProvider(providerId);
@@ -319,7 +351,6 @@ export function useProvidersPresenter() {
319351
return;
320352
}
321353

322-
// Copilot uses device code flow via backend
323354
if (providerId === 'copilot') {
324355
try {
325356
const response = await oauthApi.startAuth('copilot');
@@ -561,8 +592,27 @@ export function useProvidersPresenter() {
561592
setIsPrivacyMode(prev => !prev);
562593
}, []);
563594

595+
// Auto-detect Plus version from multiple sources
596+
const { serverVersion } = useAuthStore();
597+
const { currentInstalledVersion, cliProxyVersion, exePath } = useCliProxyStore();
598+
const isNonPlusServer = useMemo(() => {
599+
// Check serverVersion (from API response headers)
600+
const fromServer = detectIsPlusVersion(serverVersion);
601+
if (fromServer !== null) return !fromServer;
602+
// Check currentInstalledVersion (from update check)
603+
const fromInstalled = detectIsPlusVersion(currentInstalledVersion);
604+
if (fromInstalled !== null) return !fromInstalled;
605+
// Check explicit cliProxyVersion
606+
if (cliProxyVersion === 'plus') return false;
607+
if (cliProxyVersion === 'standard') return true;
608+
// Check exe path
609+
if (exePath && exePath.toLowerCase().includes('plus')) return false;
610+
return false;
611+
}, [serverVersion, currentInstalledVersion, cliProxyVersion, exePath]);
612+
564613
return {
565614
isAuthenticated,
615+
isNonPlusServer,
566616

567617
// Connected accounts
568618
files,

0 commit comments

Comments
 (0)