mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
fix(cliproxy): infer emails from alternate token prefixes
This commit is contained in:
@@ -280,6 +280,40 @@ describe('account registry integrity', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('strips alternate token file prefixes when inferring missing emails', async () => {
|
||||
const cases = [
|
||||
{ provider: 'gemini', tokenFile: 'google-user@example.com.json', type: 'gemini' },
|
||||
{ provider: 'codex', tokenFile: 'openai-user@example.com.json', type: 'codex' },
|
||||
{ provider: 'agy', tokenFile: 'antigravity-user@example.com.json', type: 'antigravity' },
|
||||
{
|
||||
provider: 'ghcp',
|
||||
tokenFile: 'github-copilot-user@example.com.json',
|
||||
type: 'github-copilot',
|
||||
},
|
||||
] as const;
|
||||
|
||||
for (const testCase of cases) {
|
||||
await withIsolatedHome(async (homeDir) => {
|
||||
const authDir = path.join(homeDir, '.ccs', 'cliproxy', 'auth');
|
||||
fs.mkdirSync(authDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(authDir, testCase.tokenFile),
|
||||
JSON.stringify({ type: testCase.type }),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
const { discoverExistingAccounts, loadAccountsRegistry } = await loadRegistryModule();
|
||||
discoverExistingAccounts();
|
||||
const registry = loadAccountsRegistry();
|
||||
const providerAccounts = registry.providers[testCase.provider];
|
||||
|
||||
expect(Object.keys(providerAccounts?.accounts ?? {})).toEqual(['user@example.com']);
|
||||
expect(providerAccounts?.accounts['user@example.com']?.email).toBe('user@example.com');
|
||||
expect(providerAccounts?.accounts['user@example.com']?.tokenFile).toBe(testCase.tokenFile);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('preserves the corrupted registry backup when recovery cannot rewrite accounts.json', async () => {
|
||||
await withIsolatedHome(async (homeDir) => {
|
||||
const authDir = path.join(homeDir, '.ccs', 'cliproxy', 'auth');
|
||||
|
||||
@@ -7,6 +7,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as lockfile from 'proper-lockfile';
|
||||
import { CLIProxyProvider } from '../types';
|
||||
import { PROVIDER_CAPABILITIES } from '../provider-capabilities';
|
||||
import { PROVIDER_TYPE_VALUES } from '../auth/auth-types';
|
||||
import { getAuthDir, getCliproxyDir } from '../config/config-generator';
|
||||
import { AccountsRegistry, AccountInfo, PROVIDERS_WITHOUT_EMAIL } from './types';
|
||||
@@ -61,15 +62,21 @@ function resolveProviderFromTokenType(typeValue: string): CLIProxyProvider | und
|
||||
|
||||
const EMAIL_FILE_NAME_PATTERN = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
|
||||
|
||||
function stripTokenFileProviderPrefix(baseName: string, provider: CLIProxyProvider): string {
|
||||
const knownPrefixes = [...PROVIDER_CAPABILITIES[provider].authFilePrefixes, `${provider}-`].sort(
|
||||
(a, b) => b.length - a.length
|
||||
);
|
||||
const prefix = knownPrefixes.find((knownPrefix) => baseName.startsWith(knownPrefix));
|
||||
|
||||
return prefix ? baseName.slice(prefix.length) : baseName;
|
||||
}
|
||||
|
||||
function inferEmailFromTokenFileName(
|
||||
tokenFile: string,
|
||||
provider: CLIProxyProvider
|
||||
): string | undefined {
|
||||
const baseName = tokenFile.replace(/\.json$/i, '');
|
||||
const providerPrefix = `${provider}-`;
|
||||
const candidate = baseName.startsWith(providerPrefix)
|
||||
? baseName.slice(providerPrefix.length)
|
||||
: baseName;
|
||||
const candidate = stripTokenFileProviderPrefix(baseName, provider);
|
||||
|
||||
if (PROVIDERS_WITHOUT_EMAIL.includes(provider)) {
|
||||
const scopedCandidate = candidate.slice(candidate.indexOf('-') + 1);
|
||||
|
||||
@@ -483,9 +483,8 @@ export async function reconcileExhaustedRotationAccounts(
|
||||
return [];
|
||||
}
|
||||
|
||||
const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } = await import(
|
||||
'../accounts/account-safety'
|
||||
);
|
||||
const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } =
|
||||
await import('../accounts/account-safety');
|
||||
restoreExpiredQuotaPauses();
|
||||
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
@@ -593,9 +592,8 @@ export async function preflightCheck(provider: CLIProxyProvider): Promise<Prefli
|
||||
return { proceed: true, accountId: defaultAccount?.id || '' };
|
||||
}
|
||||
|
||||
const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } = await import(
|
||||
'../accounts/account-safety'
|
||||
);
|
||||
const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } =
|
||||
await import('../accounts/account-safety');
|
||||
restoreExpiredQuotaPauses();
|
||||
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
|
||||
@@ -112,9 +112,8 @@ export async function runImageAnalysisCheck(results: HealthCheck): Promise<void>
|
||||
* Fix image analysis configuration issues
|
||||
*/
|
||||
export async function fixImageAnalysisConfig(): Promise<boolean> {
|
||||
const { updateConfig, loadOrCreateUnifiedConfig } = await import(
|
||||
'../../config/config-loader-facade'
|
||||
);
|
||||
const { updateConfig, loadOrCreateUnifiedConfig } =
|
||||
await import('../../config/config-loader-facade');
|
||||
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
let fixed = false;
|
||||
|
||||
Reference in New Issue
Block a user