claude-keys-manager
Version:
Claude Code API Key manager with template and repository management tools
444 lines (395 loc) • 14.5 kB
JavaScript
const { program } = require('commander');
const inquirer = require('inquirer');
const chalk = require('chalk');
const ClaudeCodeManager = require('../index');
const KeyManager = require('../lib/keyManager');
const package = require('../package.json');
program
.name('claude-get')
.description('Claude Code Manager - 轻量级代码模板和项目管理工具')
.version(package.version);
program
.argument('[repository]', 'GitHub仓库URL或简化格式 (owner/repo)')
.option('-d, --dir <directory>', '目标目录')
.option('-i, --interactive', '交互式模式')
.description('下载GitHub仓库')
.action(async (repository, options) => {
try {
const manager = new ClaudeCodeManager();
// 交互式模式
if (options.interactive || !repository) {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'repository',
message: '请输入GitHub仓库URL或简化格式 (owner/repo):',
when: !repository,
validate: (input) => {
if (!input.trim()) {
return '仓库URL不能为空';
}
return true;
}
},
{
type: 'input',
name: 'targetDir',
message: '目标目录 (留空使用默认):',
when: !options.dir
}
]);
repository = repository || answers.repository;
options.dir = options.dir || answers.targetDir;
}
// 执行主要功能
await manager.run(repository, {
targetDir: options.dir
});
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
});
program
.command('template')
.description('模板管理')
.addCommand(
program.createCommand('create')
.argument('<name>', '模板名称')
.argument('<source>', '源目录路径')
.description('创建代码模板')
.action(async (name, source) => {
try {
const manager = new ClaudeCodeManager();
await manager.createTemplate(name, source);
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('use')
.argument('<name>', '模板名称')
.option('-d, --dir <directory>', '目标目录')
.description('使用代码模板')
.action(async (name, options) => {
try {
const manager = new ClaudeCodeManager();
await manager.useTemplate(name, options.dir);
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('list')
.description('列出所有模板')
.action(async () => {
try {
const manager = new ClaudeCodeManager();
const templates = await manager.listTemplates();
if (templates.length === 0) {
console.log(chalk.yellow('📝 暂无可用模板'));
console.log(chalk.gray('使用 claude-get template create <name> <source> 创建模板'));
return;
}
console.log(chalk.blue.bold('📝 可用模板:'));
templates.forEach(template => {
console.log(chalk.green(` • ${template.name}`));
console.log(chalk.gray(` 创建时间: ${new Date(template.created).toLocaleString()}`));
});
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
);
program
.command('quick')
.description('快速下载常用项目模板')
.action(async () => {
try {
const { template } = await inquirer.prompt([
{
type: 'list',
name: 'template',
message: '选择项目模板:',
choices: [
{ name: 'React App (Create React App)', value: 'facebook/create-react-app' },
{ name: 'Vue.js 3 (Vue CLI)', value: 'vuejs/vue-cli' },
{ name: 'Next.js Starter', value: 'vercel/next.js' },
{ name: 'Express.js Starter', value: 'expressjs/express' },
{ name: 'Node.js TypeScript Starter', value: 'microsoft/TypeScript-Node-Starter' },
{ name: 'Python Flask Starter', value: 'pallets/flask' },
{ name: 'Django Starter', value: 'django/django' },
{ name: '自定义输入', value: 'custom' }
]
}
]);
let repoUrl = template;
if (template === 'custom') {
const { customRepo } = await inquirer.prompt([
{
type: 'input',
name: 'customRepo',
message: '请输入GitHub仓库URL或简化格式:',
validate: (input) => input.trim() ? true : '仓库URL不能为空'
}
]);
repoUrl = customRepo;
}
const manager = new ClaudeCodeManager();
await manager.run(repoUrl);
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
});
program
.command('key')
.description('Claude Code API Key管理')
.addCommand(
program.createCommand('add')
.description('添加新的API Key')
.action(async () => {
try {
const keyManager = new KeyManager();
await keyManager.init();
const answers = await inquirer.prompt([
{
type: 'input',
name: 'name',
message: '请输入Key名称:',
validate: (input) => input.trim() ? true : 'Key名称不能为空'
},
{
type: 'password',
name: 'key',
message: '请输入API Key:',
validate: (input) => input.trim() ? true : 'API Key不能为空'
},
{
type: 'input',
name: 'description',
message: '描述 (可选):',
}
]);
await keyManager.addKey(answers);
console.log(chalk.green(`✅ Key "${answers.name}" 添加成功`));
// 询问是否立即验证
const { validate } = await inquirer.prompt([
{
type: 'confirm',
name: 'validate',
message: '是否立即验证此Key?',
default: true
}
]);
if (validate) {
const keys = keyManager.listKeys();
const newKey = keys.find(k => k.name === answers.name);
await keyManager.validateKey(newKey.id);
}
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('list')
.description('列出所有API Keys')
.action(async () => {
try {
const keyManager = new KeyManager();
await keyManager.init();
const keys = keyManager.listKeys();
const stats = keyManager.getKeyStats();
console.log(chalk.blue.bold('\n🔑 API Keys 管理'));
console.log(chalk.gray(`总计: ${stats.total} | 有效: ${stats.valid} | 无效: ${stats.invalid} | 未测试: ${stats.untested}`));
console.log(chalk.yellow(`当前使用: ${stats.currentKey}`));
console.log(chalk.gray(`总使用次数: ${stats.totalUsage}\n`));
if (keys.length === 0) {
console.log(chalk.yellow('📝 暂无API Keys'));
console.log(chalk.gray('使用 claude-get key add 添加新的Key'));
return;
}
keys.forEach(key => {
const status = key.isValid === true ? chalk.green('✅') :
key.isValid === false ? chalk.red('❌') : chalk.gray('❓');
const current = key.isCurrent ? chalk.yellow(' (当前)') : '';
console.log(`${status} ${chalk.cyan(key.name)}${current}`);
console.log(chalk.gray(` Key: ${key.key}`));
console.log(chalk.gray(` 描述: ${key.description || '无'}`));
console.log(chalk.gray(` 使用次数: ${key.usageCount} | 最后使用: ${key.lastUsed ? new Date(key.lastUsed).toLocaleString() : '从未使用'}`));
console.log('');
});
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('switch')
.description('切换当前使用的API Key')
.action(async () => {
try {
const keyManager = new KeyManager();
await keyManager.init();
const keys = keyManager.listKeys();
if (keys.length === 0) {
console.log(chalk.yellow('暂无可用的API Keys'));
return;
}
const { keyId } = await inquirer.prompt([
{
type: 'list',
name: 'keyId',
message: '选择要使用的API Key:',
choices: keys.map(key => ({
name: `${key.name} ${key.isCurrent ? '(当前)' : ''}`,
value: key.id
}))
}
]);
const switchedKey = await keyManager.switchKey(keyId);
console.log(chalk.green(`✅ 已切换到Key: ${switchedKey.name}`));
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('test')
.description('测试API Key功能')
.option('-k, --key <keyId>', '指定要测试的Key ID')
.option('-p, --prompt <prompt>', '自定义测试提示', 'Hello, Claude!')
.action(async (options) => {
try {
const keyManager = new KeyManager();
await keyManager.init();
let keyId = options.key;
if (!keyId) {
const keys = keyManager.listKeys();
if (keys.length === 0) {
console.log(chalk.yellow('暂无可用的API Keys'));
return;
}
const { selectedKeyId } = await inquirer.prompt([
{
type: 'list',
name: 'selectedKeyId',
message: '选择要测试的API Key:',
choices: keys.map(key => ({
name: `${key.name} ${key.isCurrent ? '(当前)' : ''}`,
value: key.id
}))
}
]);
keyId = selectedKeyId;
}
console.log(chalk.blue(`🧪 测试提示: "${options.prompt}"`));
const result = await keyManager.testKey(keyId, options.prompt);
console.log(chalk.green('\n✅ 测试结果:'));
console.log(chalk.cyan(`响应: ${result.response}`));
console.log(chalk.gray(`Token使用: ${result.usage.total_tokens} (输入: ${result.usage.prompt_tokens}, 输出: ${result.usage.completion_tokens})`));
console.log(chalk.gray(`时间: ${new Date(result.timestamp).toLocaleString()}`));
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('validate')
.description('验证API Key有效性')
.option('-a, --all', '验证所有Keys')
.action(async (options) => {
try {
const keyManager = new KeyManager();
await keyManager.init();
const keys = keyManager.listKeys();
if (keys.length === 0) {
console.log(chalk.yellow('暂无可用的API Keys'));
return;
}
if (options.all) {
console.log(chalk.blue('🔍 验证所有API Keys...'));
for (const key of keys) {
await keyManager.validateKey(key.id);
}
} else {
const { keyId } = await inquirer.prompt([
{
type: 'list',
name: 'keyId',
message: '选择要验证的API Key:',
choices: keys.map(key => ({
name: `${key.name} ${key.isCurrent ? '(当前)' : ''}`,
value: key.id
}))
}
]);
await keyManager.validateKey(keyId);
}
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
)
.addCommand(
program.createCommand('remove')
.description('删除API Key')
.action(async () => {
try {
const keyManager = new KeyManager();
await keyManager.init();
const keys = keyManager.listKeys();
if (keys.length === 0) {
console.log(chalk.yellow('暂无可用的API Keys'));
return;
}
const { keyId } = await inquirer.prompt([
{
type: 'list',
name: 'keyId',
message: '选择要删除的API Key:',
choices: keys.map(key => ({
name: `${key.name} ${key.isCurrent ? '(当前)' : ''}`,
value: key.id
}))
}
]);
const keyToRemove = keys.find(k => k.id === keyId);
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: `确认删除Key "${keyToRemove.name}"?`,
default: false
}
]);
if (confirm) {
await keyManager.removeKey(keyId);
console.log(chalk.green(`✅ Key "${keyToRemove.name}" 已删除`));
} else {
console.log(chalk.gray('操作已取消'));
}
} catch (error) {
console.error(chalk.red.bold(`❌ 错误: ${error.message}`));
process.exit(1);
}
})
);
// 解析命令行参数
program.parse();
// 如果没有提供命令,显示帮助
if (!process.argv.slice(2).length) {
program.outputHelp();
}