commit b8e0e99e5c3639d3c18704e1b82fda1efdbc6418 Author: musistudio Date: Sun Aug 3 08:18:08 2025 +0800 init diff --git a/.github/workflows/daily-build.yml b/.github/workflows/daily-build.yml new file mode 100644 index 0000000..c51f3bf --- /dev/null +++ b/.github/workflows/daily-build.yml @@ -0,0 +1,49 @@ +name: Daily Build and Upload to Cloudflare R2 + +on: + schedule: + # Runs at 2 AM UTC every day + - cron: '0 2 * * *' + workflow_dispatch: # Allows manual triggering + +jobs: + build-and-upload: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build providers.json + run: npm run build + + - name: Verify providers.json exists + run: | + if [ ! -f providers.json ]; then + echo "providers.json file not found!" + exit 1 + fi + echo "providers.json file size: $(wc -c < providers.json) bytes" + + - name: Upload to Cloudflare R2 + uses: cloudflare/wrangler-action@v3 + with: + apiToken: $\{{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: $\{{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: r2 object put providers.json --file providers.json --bucket $\{{ secrets.R2_BUCKET_NAME }} + + - name: Upload Success Notification + if: success() + run: echo "Successfully uploaded providers.json to Cloudflare R2" + + - name: Upload Failure Notification + if: failure() + run: echo "Failed to upload providers.json to Cloudflare R2" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc36e87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +providers.json +.env \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..171c1e3 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Claude Code Router Provider Registry + +This repository contains provider configurations for the Claude Code Router. + +## Submitting a New Provider + +To add a new provider to the registry: + +1. Create a new JSON file in the `providers` directory with your provider's configuration. The file should include: + - `name`: The provider's name + - `api_base_url`: The base URL for the provider's API + - `api_key`: The API key (keep empty) + - `models`: An array of supported model names + - `transformer`: Configuration for request/response transformation +2. Commit your changes with a descriptive message +3. Push your changes to your fork +4. Open a pull request to the main repository with a clear title and description diff --git a/package.json b/package.json new file mode 100644 index 0000000..8b3543d --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "claude-code-router-provider-registry", + "version": "1.0.0", + "description": "Provider registry for Claude Code Router", + "main": "index.js", + "scripts": { + "build": "node scripts/build.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "fs": "0.0.1-security", + "path": "0.12.7" + } +} \ No newline at end of file diff --git a/providers/dashscope.json b/providers/dashscope.json new file mode 100644 index 0000000..8066e7e --- /dev/null +++ b/providers/dashscope.json @@ -0,0 +1,19 @@ +{ + "name": "dashscope", + "api_base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions", + "api_key": "", + "models": ["qwen3-coder-plus"], + "transformer": { + "use": [ + [ + "maxtoken", + { + "max_tokens": 65536 + } + ] + ], + "qwen3-coder-plus": { + "use": ["enhancetool"] + } + } +} diff --git a/providers/deepseek.json b/providers/deepseek.json new file mode 100644 index 0000000..14627f5 --- /dev/null +++ b/providers/deepseek.json @@ -0,0 +1,12 @@ +{ + "name": "deepseek", + "api_base_url": "https://api.deepseek.com/chat/completions", + "api_key": "", + "models": ["deepseek-chat", "deepseek-reasoner"], + "transformer": { + "use": ["deepseek"], + "deepseek-chat": { + "use": ["tooluse"] + } + } +} diff --git a/providers/gemini.json b/providers/gemini.json new file mode 100644 index 0000000..84065ef --- /dev/null +++ b/providers/gemini.json @@ -0,0 +1,9 @@ +{ + "name": "gemini", + "api_base_url": "https://generativelanguage.googleapis.com/v1beta/models/", + "api_key": "", + "models": ["gemini-2.5-flash", "gemini-2.5-pro"], + "transformer": { + "use": ["gemini"] + } +} diff --git a/providers/modelscope.json b/providers/modelscope.json new file mode 100644 index 0000000..662e33b --- /dev/null +++ b/providers/modelscope.json @@ -0,0 +1,26 @@ +{ + "name": "modelscope", + "api_base_url": "https://api-inference.modelscope.cn/v1/chat/completions", + "api_key": "", + "models": [ + "Qwen/Qwen3-Coder-480B-A35B-Instruct", + "Qwen/Qwen3-235B-A22B-Thinking-2507", + "ZhipuAI/GLM-4.5" + ], + "transformer": { + "use": [ + [ + "maxtoken", + { + "max_tokens": 65536 + } + ] + ], + "Qwen/Qwen3-Coder-480B-A35B-Instruct": { + "use": ["enhancetool"] + }, + "Qwen/Qwen3-235B-A22B-Thinking-2507": { + "use": ["reasoning"] + } + } +} diff --git a/providers/openrouter.json b/providers/openrouter.json new file mode 100644 index 0000000..822f2fb --- /dev/null +++ b/providers/openrouter.json @@ -0,0 +1,14 @@ +{ + "name": "openrouter", + "api_base_url": "https://openrouter.ai/api/v1/chat/completions", + "api_key": "", + "models": [ + "google/gemini-2.5-pro-preview", + "anthropic/claude-sonnet-4", + "anthropic/claude-3.5-sonnet", + "anthropic/claude-3.7-sonnet:thinking" + ], + "transformer": { + "use": ["openrouter"] + } +} diff --git a/providers/siliconflow.json b/providers/siliconflow.json new file mode 100644 index 0000000..41d8cdd --- /dev/null +++ b/providers/siliconflow.json @@ -0,0 +1,16 @@ +{ + "name": "siliconflow", + "api_base_url": "https://api.siliconflow.cn/v1/chat/completions", + "api_key": "sk-xxx", + "models": ["moonshotai/Kimi-K2-Instruct"], + "transformer": { + "use": [ + [ + "maxtoken", + { + "max_tokens": 16384 + } + ] + ] + } +} diff --git a/providers/volcengine.json b/providers/volcengine.json new file mode 100644 index 0000000..8edb1d4 --- /dev/null +++ b/providers/volcengine.json @@ -0,0 +1,9 @@ +{ + "name": "volcengine", + "api_base_url": "https://ark.cn-beijing.volces.com/api/v3/chat/completions", + "api_key": "sk-xxx", + "models": ["deepseek-v3-250324", "deepseek-r1-250528"], + "transformer": { + "use": ["deepseek"] + } +} diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..e6e2ec1 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,55 @@ +const fs = require('fs'); +const path = require('path'); + +/** + * 合并目录中的所有JSON文件到一个大的JSON文件中 + * @param {string} inputDir 包含JSON文件的目录路径 + * @param {string} outputFile 输出的合并后JSON文件路径 + */ +async function mergeJsonFiles(inputDir, outputFile) { + try { + // 1. 读取目录中的所有文件 + const files = await fs.promises.readdir(inputDir); + + // 2. 过滤出JSON文件 + const jsonFiles = files.filter(file => file.endsWith('.json')); + + if (jsonFiles.length === 0) { + console.log('目录中没有找到JSON文件'); + return; + } + + // 3. 读取并解析所有JSON文件 + const jsonArray = []; + + for (const file of jsonFiles) { + const filePath = path.join(inputDir, file); + const fileContent = await fs.promises.readFile(filePath, 'utf8'); + + try { + const jsonData = JSON.parse(fileContent); + jsonArray.push(jsonData); + console.log(`成功加载: ${file}`); + } catch (err) { + console.error(`解析失败 ${file}: ${err.message}`); + } + } + + // 4. 将合并后的数组写入输出文件 + await fs.promises.writeFile( + outputFile, + JSON.stringify(jsonArray, null, 2), // 使用2空格缩进美化输出 + 'utf8' + ); + + console.log(`成功合并 ${jsonArray.length} 个JSON文件到 ${outputFile}`); + } catch (err) { + console.error('处理过程中出错:', err); + } +} + +// 使用示例 +const inputDirectory = './providers'; // 替换为你的JSON文件目录 +const outputFile = './providers.json'; // 替换为你想输出的文件路径 + +mergeJsonFiles(inputDirectory, outputFile); \ No newline at end of file