Merge pull request #1022 from kaitranntt/kai/fix/codex-free-account-badge

fix(accounts): refine codex plan badges
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-04-14 22:06:33 -04:00
commit 05e2aae7ac
14 files changed
+523 -133

No files matched your search

@@ -1,6 +1,9 @@
import type { CLIProxyProvider } from '../types';
const DUPLICATE_EMAIL_ACCOUNT_PROVIDERS = new Set<string>(['codex']);
const FREE_PLAN_PARTS = new Set(['free']);
const PERSONAL_PLAN_PARTS = new Set(['plus', 'pro']);
const BUSINESS_PLAN_PARTS = new Set(['team']);
// Keep variant parsing aligned with ui/src/lib/account-identity.ts. The UI copy is
// separate because the browser bundle cannot import this server module directly.
@@ -49,6 +52,20 @@ function formatVariantPart(value: string): string {
}
}
function formatWorkspaceLabel(parts: string[]): string | null {
const workspaceId = parts.find((part) => /^[a-f0-9]{8}$/i.test(part));
if (workspaceId) {
return `Workspace ${workspaceId.toLowerCase()}`;
}
return parts.map(formatVariantPart).filter(Boolean).join(' · ') || null;
}
function formatAudienceDetail(parts: string[]): string | null {
const label = parts.map(formatVariantPart).filter(Boolean).join(' · ');
return label || null;
}
export function supportsDuplicateEmailAccounts(provider: CLIProxyProvider | string): boolean {
return DUPLICATE_EMAIL_ACCOUNT_PROVIDERS.has(normalizeProvider(provider));
}
@@ -136,8 +153,16 @@ export function formatAccountVariantLabel(accountId: string, email?: string): st
}
const suffix = parts[parts.length - 1]?.toLowerCase();
if (suffix && ['team', 'free', 'plus', 'pro'].includes(suffix)) {
return [formatVariantPart(suffix), ...parts.slice(0, -1).map(formatVariantPart)]
if (suffix && BUSINESS_PLAN_PARTS.has(suffix)) {
return ['Business', formatWorkspaceLabel(parts.slice(0, -1))].filter(Boolean).join(' · ');
}
if (suffix && FREE_PLAN_PARTS.has(suffix)) {
return ['Free', formatAudienceDetail(parts.slice(0, -1))].filter(Boolean).join(' · ');
}
if (suffix && PERSONAL_PLAN_PARTS.has(suffix)) {
return ['Personal', formatVariantPart(suffix), formatAudienceDetail(parts.slice(0, -1))]
.filter(Boolean)
.join(' · ');
}
+2 -1
View File
@@ -624,11 +624,12 @@ export async function fetchCodexQuota(
// Extract plan type
const planTypeRaw = data.plan_type || data.planType;
let planType: 'free' | 'plus' | 'team' | null = null;
let planType: 'free' | 'plus' | 'pro' | 'team' | null = null;
if (planTypeRaw) {
const normalized = planTypeRaw.toLowerCase();
if (normalized === 'free') planType = 'free';
else if (normalized === 'plus') planType = 'plus';
else if (normalized === 'pro') planType = 'pro';
else if (normalized === 'team') planType = 'team';
}
+2 -2
View File
@@ -74,8 +74,8 @@ export interface CodexQuotaResult extends QuotaErrorMetadata {
windows: CodexQuotaWindow[];
/** Explicit core usage windows (5h + weekly) for easier reset display */
coreUsage?: CodexCoreUsageSummary;
/** Plan type: free, plus, team, or null if unknown */
planType: 'free' | 'plus' | 'team' | null;
/** Plan type: free, plus, pro, team, or null if unknown */
planType: 'free' | 'plus' | 'pro' | 'team' | null;
/** Timestamp of fetch */
lastUpdated: number;
/** Error message if fetch failed */