Skip to content

Commit 8ec4486

Browse files
Numman AliNumman Ali
authored andcommitted
fix: constrain provider list viewport
1 parent 4a9112b commit 8ec4486

6 files changed

Lines changed: 57 additions & 20 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ Want to use different models? CC-MIRROR supports multiple providers:
149149
| **Ollama** | Local + cloud models | Auth Token | Local-first + hybrid setups |
150150
| **GatewayZ** | Multi-provider gateway | Auth Token | Centralized routing |
151151
| **Vercel** | Multi-provider gateway | Auth Token | Vercel AI Gateway |
152-
| **NanoGPT** | Anthropic-compatible | Auth Token | Simple Anthropic compat |
152+
| **NanoGPT** | Claude Code endpoint | Auth Token | Simple endpoint setup |
153153

154154
```bash
155155
# Z.ai (GLM Coding Plan)
@@ -165,19 +165,19 @@ npx cc-mirror quick --provider openrouter --api-key "$OPENROUTER_API_KEY" \
165165
# Claude Code Router (local LLMs)
166166
npx cc-mirror quick --provider ccrouter
167167

168-
# Ollama (Anthropic-compatible)
168+
# Ollama
169169
npx cc-mirror quick --provider ollama --api-key "ollama" \
170170
--model-sonnet "qwen3-coder" --model-opus "qwen3-coder" --model-haiku "qwen3-coder"
171171

172-
# GatewayZ (Anthropic-compatible gateway)
172+
# GatewayZ
173173
npx cc-mirror quick --provider gatewayz --api-key "$GATEWAYZ_API_KEY" \
174174
--model-sonnet "claude-3-5-sonnet-20241022"
175175

176176
# Vercel AI Gateway
177177
npx cc-mirror quick --provider vercel --api-key "$VERCEL_AI_GATEWAY_KEY" \
178178
--model-sonnet "anthropic/claude-3-5-sonnet-20241022"
179179

180-
# NanoGPT (Anthropic-compatible)
180+
# NanoGPT
181181
npx cc-mirror quick --provider nanogpt --api-key "$NANOGPT_API_KEY"
182182
```
183183

src/cli/help.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ PROVIDERS
6161
ollama Local + cloud models via Ollama
6262
gatewayz GatewayZ AI Gateway
6363
vercel Vercel AI Gateway
64-
nanogpt NanoGPT Anthropic-compatible
64+
nanogpt NanoGPT
6565
6666
EXAMPLES
6767
npx cc-mirror quick --provider mirror --name mclaude

src/providers/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface ProviderTemplate {
2222
noPromptPack?: boolean;
2323
/** Require empty ANTHROPIC_API_KEY (for authToken providers like Vercel AI Gateway) */
2424
requiresEmptyApiKey?: boolean;
25-
/** Keep ANTHROPIC_API_KEY alongside auth token (e.g., Ollama Anthropic compatibility) */
25+
/** Keep ANTHROPIC_API_KEY alongside auth token (e.g., Ollama compatibility) */
2626
authTokenAlsoSetsApiKey?: boolean;
2727
}
2828

@@ -141,7 +141,7 @@ const PROVIDERS: Record<string, ProviderTemplate> = {
141141
gatewayz: {
142142
key: 'gatewayz',
143143
label: 'GatewayZ',
144-
description: 'GatewayZ AI Gateway (Anthropic-compatible)',
144+
description: 'GatewayZ AI Gateway',
145145
baseUrl: 'https://api.gatewayz.ai',
146146
env: {
147147
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
@@ -156,7 +156,7 @@ const PROVIDERS: Record<string, ProviderTemplate> = {
156156
vercel: {
157157
key: 'vercel',
158158
label: 'Vercel AI Gateway',
159-
description: 'Vercel AI Gateway (Anthropic-compatible)',
159+
description: 'Vercel AI Gateway',
160160
baseUrl: 'https://ai-gateway.vercel.sh',
161161
env: {
162162
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
@@ -172,7 +172,7 @@ const PROVIDERS: Record<string, ProviderTemplate> = {
172172
nanogpt: {
173173
key: 'nanogpt',
174174
label: 'NanoGPT',
175-
description: 'NanoGPT Anthropic-compatible endpoint',
175+
description: 'NanoGPT endpoint',
176176
baseUrl: 'https://nano-gpt.com/api',
177177
env: {
178178
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,

src/tui/components/ui/Menu.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,19 @@ interface ProviderCardProps {
110110
selected: boolean;
111111
disabled?: boolean;
112112
docsUrl?: string;
113+
showDetails?: boolean;
113114
}
114115

115116
/**
116117
* Provider selection card
117118
*/
118-
export const ProviderCard: React.FC<ProviderCardProps> = ({ provider, selected, disabled = false, docsUrl }) => (
119+
export const ProviderCard: React.FC<ProviderCardProps> = ({
120+
provider,
121+
selected,
122+
disabled = false,
123+
docsUrl,
124+
showDetails = true,
125+
}) => (
119126
<Box flexDirection="column" marginBottom={1}>
120127
<Box>
121128
<Text color={selected ? colors.gold : colors.textMuted}>{selected ? icons.pointer : icons.pointerEmpty} </Text>
@@ -133,14 +140,14 @@ export const ProviderCard: React.FC<ProviderCardProps> = ({ provider, selected,
133140
{provider.description}
134141
</Text>
135142
</Box>
136-
{provider.baseUrl && !disabled && (
143+
{showDetails && provider.baseUrl && !disabled && (
137144
<Box marginLeft={3}>
138145
<Text color={colors.primaryBright} dimColor>
139146
{provider.baseUrl}
140147
</Text>
141148
</Box>
142149
)}
143-
{!provider.baseUrl && docsUrl && !disabled && (
150+
{showDetails && !provider.baseUrl && docsUrl && !disabled && (
144151
<Box marginLeft={3}>
145152
<Text color={colors.primaryBright} dimColor>
146153
{docsUrl}

src/tui/content/providers.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export const PROVIDER_EDUCATION: Record<string, ProviderEducation> = {
141141
headline: 'GatewayZ — AI Gateway',
142142
tagline: 'One gateway, many providers',
143143
features: [
144-
'Anthropic-compatible endpoint',
144+
'Claude Code endpoint support',
145145
'Single API key for multiple providers',
146146
'Gateway-style routing',
147147
'Violet-themed interface',
@@ -154,13 +154,13 @@ export const PROVIDER_EDUCATION: Record<string, ProviderEducation> = {
154154
apiKey: 'https://gatewayz.ai',
155155
docs: 'https://docs.gatewayz.ai/docs/anthropic-compatibility',
156156
},
157-
setupNote: 'GatewayZ uses Anthropic-compatible endpoints. Configure model mapping for your preferred models.',
157+
setupNote: 'GatewayZ uses Claude Code endpoints. Configure model mapping for your preferred models.',
158158
},
159159
vercel: {
160160
headline: 'Vercel AI Gateway',
161161
tagline: 'Unified AI routing on Vercel',
162162
features: [
163-
'Anthropic-compatible endpoint',
163+
'Claude Code endpoint support',
164164
'Use provider/model identifiers',
165165
'Centralized usage + billing',
166166
'Monochrome + green accents',
@@ -176,10 +176,10 @@ export const PROVIDER_EDUCATION: Record<string, ProviderEducation> = {
176176
setupNote: 'Set ANTHROPIC_AUTH_TOKEN and keep ANTHROPIC_API_KEY empty.',
177177
},
178178
nanogpt: {
179-
headline: 'NanoGPT — Anthropic Compatible',
179+
headline: 'NanoGPT',
180180
tagline: 'Lean gateway, fast setup',
181-
features: ['Anthropic-compatible endpoint', 'Simple API key auth', 'Neon-themed interface'],
182-
bestFor: 'Simple Anthropic-compatible usage with minimal setup',
181+
features: ['Claude Code endpoint support', 'Simple API key auth', 'Neon-themed interface'],
182+
bestFor: 'Simple Claude Code usage with minimal setup',
183183
requiresMapping: false,
184184
hasPromptPack: false,
185185
setupLinks: {

src/tui/screens/ProviderSelectScreen.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface ProviderSelectScreenProps {
2525
export const ProviderSelectScreen: React.FC<ProviderSelectScreenProps> = ({ providers, onSelect }) => {
2626
const [selectedIndex, setSelectedIndex] = useState(0);
2727
const [showDetails, setShowDetails] = useState(false);
28+
const maxVisible = 6;
2829

2930
// Get current selected provider and its education
3031
const currentProvider = providers[selectedIndex];
@@ -60,6 +61,23 @@ export const ProviderSelectScreen: React.FC<ProviderSelectScreenProps> = ({ prov
6061
}
6162
});
6263

64+
const getVisibleRange = (total: number, selected: number) => {
65+
const half = Math.floor(maxVisible / 2);
66+
let start = Math.max(0, selected - half);
67+
const end = Math.min(total, start + maxVisible);
68+
if (end - start < maxVisible) {
69+
start = Math.max(0, end - maxVisible);
70+
}
71+
return { start, end };
72+
};
73+
74+
const { start, end } = getVisibleRange(providers.length, selectedIndex);
75+
const visibleProviders = providers.slice(start, end);
76+
const hasAbove = start > 0;
77+
const hasBelow = end < providers.length;
78+
const aboveCount = start;
79+
const belowCount = providers.length - end;
80+
6381
return (
6482
<ScreenLayout
6583
title="Select Provider"
@@ -77,19 +95,31 @@ export const ProviderSelectScreen: React.FC<ProviderSelectScreenProps> = ({ prov
7795
</Box>
7896

7997
<Box flexDirection="column" marginY={1}>
80-
{providers.map((provider, idx) => {
98+
{hasAbove && (
99+
<Text color={colors.textDim}>
100+
{icons.arrowUp} {aboveCount} more above
101+
</Text>
102+
)}
103+
{visibleProviders.map((provider, idx) => {
104+
const absoluteIndex = start + idx;
81105
const providerEducation = getProviderEducation(provider.key);
82106
const docsUrl = providerEducation?.setupLinks?.docs;
83107
return (
84108
<ProviderCard
85109
key={provider.key}
86110
provider={provider}
87-
selected={idx === selectedIndex && !provider.experimental}
111+
selected={absoluteIndex === selectedIndex && !provider.experimental}
88112
disabled={provider.experimental}
89113
docsUrl={docsUrl}
114+
showDetails={absoluteIndex === selectedIndex}
90115
/>
91116
);
92117
})}
118+
{hasBelow && (
119+
<Text color={colors.textDim}>
120+
{icons.arrowDown} {belowCount} more below
121+
</Text>
122+
)}
93123
</Box>
94124

95125
{/* Details panel - shows when ? is pressed */}

0 commit comments

Comments
 (0)