feat(api): add Anthropic direct API key support

Support native Anthropic API keys (sk-ant-...) via `ccs api create --preset anthropic`.
Profiles use ANTHROPIC_API_KEY env var without BASE_URL, letting Claude CLI
authenticate natively with x-api-key header instead of proxy Bearer token.

- Add anthropic preset to provider catalog
- Branch profile-writer env structure (native vs proxy)
- Add validateAnthropicKey() preflight with x-api-key header
- Auto-detect api.anthropic.com URL in interactive flow
- Fix hasApiKey/isConfigured to recognize ANTHROPIC_API_KEY
- Update delegation-validator for native mode profiles
- Add Droid target API key fallback (ANTHROPIC_API_KEY)

Closes #688

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
BbChip0103andClaude Opus 4.6 committed 2026-03-05 13:13:10 +09:00
1 parent 0c4d5244c8
commit fedb4d4cde
11 files changed
+301 -20

No files matched your search

+73
View File
@@ -166,3 +166,76 @@ export async function validateMiniMaxKey(
timeoutMs
);
}
/** Validate Anthropic direct API key using x-api-key header (not Bearer) */
export async function validateAnthropicKey(
apiKey: string,
timeoutMs = 2000
): Promise<ValidationResult> {
if (process.env.CCS_SKIP_PREFLIGHT === '1') {
return { valid: true };
}
if (!apiKey || DEFAULT_PLACEHOLDERS.includes(apiKey.toUpperCase())) {
return {
valid: false,
error: 'Anthropic API key not configured',
suggestion: 'Set ANTHROPIC_API_KEY in your profile settings.json',
};
}
return new Promise((resolve) => {
let resolved = false;
const safeResolve = (result: ValidationResult) => {
if (resolved) return;
resolved = true;
resolve(result);
};
const options: https.RequestOptions = {
hostname: 'api.anthropic.com',
port: 443,
path: '/v1/models',
method: 'GET',
headers: {
'x-api-key': apiKey,
'anthropic-version': '2023-06-01',
'User-Agent': 'CCS-Preflight/1.0',
},
};
const req = https.request(options, (res) => {
clearTimeout(timeoutId);
if (res.statusCode === 200) {
safeResolve({ valid: true });
} else if (res.statusCode === 401 || res.statusCode === 403) {
safeResolve({
valid: false,
error: 'Anthropic API key rejected',
suggestion:
'Your key may have expired. To fix:\n' +
' 1. Go to console.anthropic.com/settings/keys and regenerate your API key\n' +
' 2. Update ANTHROPIC_API_KEY in your profile settings.json\n' +
' 3. Or run: ccs api create --preset anthropic',
});
} else {
safeResolve({ valid: true });
}
res.resume();
});
req.on('error', () => {
clearTimeout(timeoutId);
safeResolve({ valid: true });
});
const timeoutId = setTimeout(() => {
req.destroy();
safeResolve({ valid: true });
}, timeoutMs);
req.end();
});
}
+4 -3
View File
@@ -69,16 +69,17 @@ export class DelegationValidator {
}
// Validate API key exists and is not default
const apiKey = settings.env?.ANTHROPIC_AUTH_TOKEN;
// Support both proxy mode (ANTHROPIC_AUTH_TOKEN) and native mode (ANTHROPIC_API_KEY)
const apiKey = settings.env?.ANTHROPIC_AUTH_TOKEN || settings.env?.ANTHROPIC_API_KEY;
if (!apiKey) {
return {
valid: false,
error: `API key not configured for ${profileName}`,
suggestion:
`Missing ANTHROPIC_AUTH_TOKEN in settings.\n\n` +
`Missing ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY in settings.\n\n` +
`Edit: ${settingsPath}\n` +
`Set: env.ANTHROPIC_AUTH_TOKEN to your API key`,
`Set: env.ANTHROPIC_AUTH_TOKEN (proxy) or env.ANTHROPIC_API_KEY (direct) to your API key`,
};
}