Add .agents/ to .gitignore and untrack skill files.master
| @@ -1,65 +0,0 @@ | |||
| --- | |||
| allowed-tools: mcp__plugin_chrome-devtools-mcp_chrome-devtools__* | |||
| description: 'Command: add-channel (imported from Claude Code)' | |||
| name: cmd-add-channel | |||
| --- | |||
| ## 添加渠道 | |||
| 通过 Chrome DevTools MCP 在指定环境中操作浏览器完成渠道添加。 | |||
| ### 参数 | |||
| 用户在 `$ARGUMENTS` 中传入 JSON 格式的渠道信息(字段均可选,缺失时会询问): | |||
| ``` | |||
| { | |||
| "base_url": "https://api.example.com", | |||
| "api_key": "sk-xxx", | |||
| "name": "渠道名称", | |||
| "type": "OpenAI", | |||
| "target": "http://localhost:23000", | |||
| "select_all_models": true | |||
| } | |||
| ``` | |||
| | 字段 | 说明 | 默认值 | | |||
| |------|------|--------| | |||
| | `target` | 目标环境地址 | 询问用户 | | |||
| | `base_url` | 渠道 API 地址 | 询问用户 | | |||
| | `api_key` | 渠道密钥 | 询问用户 | | |||
| | `name` | 渠道名称 | 自动从 base_url 提取域名 | | |||
| | `type` | 渠道类型 | `OpenAI` | | |||
| | `select_all_models` | 是否全选模型 | `true` | | |||
| 如果 `$ARGUMENTS` 不是 JSON,则按顺序解析为 `base_url` `api_key`,其余使用默认值。 | |||
| ### 操作流程 | |||
| 1. **导航到目标页面** — `navigate_page` 到 `{target}/console/channel` | |||
| 2. **检查登录状态** — `take_snapshot`,如果没有登录(看不到侧边栏菜单),提示用户先登录 | |||
| 3. **点击添加渠道** — 找到并点击"添加渠道"按钮 | |||
| 4. **填写表单** — 按 snap 快照中的元素 uid,依次 `fill`: | |||
| - 名称(名称输入框) | |||
| - 密钥(密钥输入框) | |||
| - API地址(API地址输入框) | |||
| 5. **获取并选择模型**: | |||
| - 点击"填入所有模型"按钮 | |||
| - 等待模型选择对话框出现 | |||
| - 如果 `select_all_models` 为 true,点击全选 checkbox,然后点击 confirm | |||
| 6. **提交** — 点击"提交"按钮 | |||
| 7. **验证** — `take_snapshot` 确认渠道列表中出现了新建的渠道 | |||
| ### 测试环境地址 | |||
| | 环境 | 地址 | 说明 | | |||
| |------|------|------| | |||
| | 国内测试 | http://localhost:23000 | WSL 本地 | | |||
| | 国外测试 | http://localhost:13000 | WSL 本地 | | |||
| | 生产环境 | https://api.example.com | 按实际填写 | | |||
| ### 要求 | |||
| - 每步操作后用 `take_snapshot` 验证页面状态 | |||
| - 如果某步操作失败(如获取模型列表超时),报告错误并询问用户是否继续 | |||
| - 完成后向用户总结创建结果(渠道名称、类型、模型数量、状态) | |||
| @@ -1,142 +0,0 @@ | |||
| --- | |||
| allowed-tools: Bash(wsl -- *) | |||
| description: 'Command: claude-stats (imported from Claude Code)' | |||
| name: cmd-claude-stats | |||
| --- | |||
| ## Claude 模型统计 | |||
| 查询 Claude 模型的**错误率**和**缓存率**,自动排除 `relay-pulse` 检测令牌。 | |||
| ### 参数 `$ARGUMENTS` | |||
| 根据 `$ARGUMENTS` 确定日期范围: | |||
| | 传入格式 | 含义 | | |||
| |---------|------| | |||
| | (空) | 今天 | | |||
| | `2026-05-09` | 指定某一天 | | |||
| | `2026-05-01 2026-05-09` | 指定日期范围(含首尾两天) | | |||
| | `7d` | 最近 7 天 | | |||
| ### 执行步骤 | |||
| **第一步:根据参数计算日期过滤条件** | |||
| - `created_at` 字段是秒级 Unix 时间戳(bigint),用 `UNIX_TIMESTAMP('YYYY-MM-DD')` 转换 | |||
| - 今天:`created_at >= UNIX_TIMESTAMP(CURDATE())` | |||
| - 某一天 `D`:`created_at >= UNIX_TIMESTAMP('D') AND created_at < UNIX_TIMESTAMP('D') + 86400` | |||
| - 范围 `D1` 到 `D2`:`created_at >= UNIX_TIMESTAMP('D1') AND created_at < UNIX_TIMESTAMP('D2') + 86400` | |||
| - 最近 N 天:`created_at >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL N-1 DAY))` | |||
| 将计算好的条件替换到下面 SQL 中的 `{DATE_FILTER}` 占位符。 | |||
| **第二步:上传 SQL 文件到服务器** | |||
| ```bash | |||
| wsl -- bash -c " | |||
| cat > /tmp/claude_stats_error.sql << 'ENDSQL' | |||
| SELECT | |||
| model_name, | |||
| SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) as success, | |||
| SUM(CASE WHEN type = 5 THEN 1 ELSE 0 END) as errors, | |||
| COUNT(*) as total, | |||
| ROUND(SUM(CASE WHEN type = 5 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as error_rate_pct | |||
| FROM logs | |||
| WHERE {DATE_FILTER} | |||
| AND model_name LIKE '%claude%' | |||
| AND type IN (2, 5) | |||
| AND token_name != 'relay-pulse' | |||
| GROUP BY model_name | |||
| ORDER BY total DESC; | |||
| ENDSQL | |||
| cat > /tmp/claude_stats_cache.sql << 'ENDSQL' | |||
| SELECT | |||
| model_name, | |||
| COUNT(*) as total_requests, | |||
| SUM(prompt_tokens) as prompt_tokens, | |||
| SUM(completion_tokens) as completion_tokens, | |||
| SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_tokens')), 0) AS UNSIGNED)) as cache_read_tokens, | |||
| SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_creation_tokens')), 0) AS UNSIGNED)) as cache_creation_tokens, | |||
| SUM(CASE WHEN CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_tokens')), 0) AS UNSIGNED) > 0 THEN 1 ELSE 0 END) as cache_hit_requests, | |||
| ROUND( | |||
| SUM(CASE WHEN CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_tokens')), 0) AS UNSIGNED) > 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), | |||
| 2 | |||
| ) as cache_hit_rate_pct, | |||
| ROUND( | |||
| (SUM(prompt_tokens) * 1.0 | |||
| + SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_tokens')), 0) AS UNSIGNED)) * 0.1 | |||
| + SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_creation_tokens')), 0) AS UNSIGNED)) * 1.25) | |||
| * 100.0 | |||
| / NULLIF( | |||
| SUM(prompt_tokens) | |||
| + SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_tokens')), 0) AS UNSIGNED)) | |||
| + SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_creation_tokens')), 0) AS UNSIGNED)), | |||
| 0), | |||
| 2 | |||
| ) as cost_pct_of_full, | |||
| ROUND( | |||
| SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_creation_tokens')), 0) AS UNSIGNED)) * 1.0 | |||
| / NULLIF(SUM(CAST(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(other, '$.cache_tokens')), 0) AS UNSIGNED)), 0), | |||
| 3 | |||
| ) as creation_to_read_ratio | |||
| FROM logs | |||
| WHERE {DATE_FILTER} | |||
| AND type = 2 | |||
| AND model_name LIKE '%claude%' | |||
| AND other IS NOT NULL | |||
| AND token_name != 'relay-pulse' | |||
| GROUP BY model_name | |||
| ORDER BY total_requests DESC; | |||
| ENDSQL | |||
| cat > /tmp/claude_stats_errcode.sql << 'ENDSQL' | |||
| SELECT | |||
| model_name, | |||
| CAST(JSON_UNQUOTE(JSON_EXTRACT(other, '$.status_code')) AS UNSIGNED) as status_code, | |||
| COUNT(*) as cnt, | |||
| ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY model_name), 1) as pct | |||
| FROM logs | |||
| WHERE {DATE_FILTER} | |||
| AND type = 5 | |||
| AND model_name LIKE '%claude%' | |||
| AND token_name != 'relay-pulse' | |||
| AND other IS NOT NULL | |||
| GROUP BY model_name, status_code | |||
| ORDER BY model_name, cnt DESC; | |||
| ENDSQL | |||
| scp /tmp/claude_stats_error.sql root@139.180.189.205:/tmp/claude_stats_error.sql | |||
| scp /tmp/claude_stats_cache.sql root@139.180.189.205:/tmp/claude_stats_cache.sql | |||
| scp /tmp/claude_stats_errcode.sql root@139.180.189.205:/tmp/claude_stats_errcode.sql | |||
| " | |||
| ``` | |||
| **第三步:执行查询并展示结果** | |||
| ```bash | |||
| wsl -- bash -c "ssh -o ConnectTimeout=20 -o ServerAliveInterval=10 root@139.180.189.205 'echo \"=== 错误率 ===\"; docker exec -i mysql mysql -uroot -pLanqi123456 new-api < /tmp/claude_stats_error.sql; echo; echo \"=== 缓存 ===\"; docker exec -i mysql mysql -uroot -pLanqi123456 new-api < /tmp/claude_stats_cache.sql; echo; echo \"=== 错误状态码分布 ===\"; docker exec -i mysql mysql -uroot -pLanqi123456 new-api < /tmp/claude_stats_errcode.sql' 2>&1 | grep -v 'Warning'" | |||
| ``` | |||
| ### 字段说明 | |||
| **错误率表:** | |||
| - `success` — 正常请求数(type=2) | |||
| - `errors` — 错误请求数(type=5) | |||
| - `error_rate_pct` — 错误率 % | |||
| **缓存率表:** | |||
| - `cache_hit_rate_pct` — **次数缓存率** = 有缓存命中的请求数 / 总请求数(最能反映缓存策略是否生效) | |||
| - `cost_pct_of_full` — **实际成本占比** = `(prompt × 1 + cache_read × 0.1 + cache_creation × 1.25) / (全量按原价计费)`,越低越省钱(Anthropic 标准定价:cache_read 是原价 10%,cache_creation 是原价 125%) | |||
| - `creation_to_read_ratio` — **缓存创建/读取比** = `cache_creation_tokens / cache_read_tokens`,比值高说明缓存频繁失效再重建,命中复用差 | |||
| **错误状态码分布表:** | |||
| - `status_code` — HTTP 状态码(504=上游超时,429=限流,400=请求参数错误) | |||
| - `cnt` — 该状态码的错误次数 | |||
| - `pct` — 占该模型全部错误的百分比 | |||
| ### 注意事项 | |||
| - 日期以 OV 服务器(UTC+0)的时区为准,北京时间当天 08:00 后才对应同一自然日 | |||
| - `relay-pulse` 是自动探活令牌,已从统计中排除 | |||
| @@ -1,209 +0,0 @@ | |||
| --- | |||
| allowed-tools: Bash(wsl -- *) | |||
| description: 'Command: debug-prod (imported from Claude Code)' | |||
| name: cmd-debug-prod | |||
| --- | |||
| ## 线上排查命令 | |||
| 用户要求排查线上问题。根据 `$ARGUMENTS` 确定目标服务器,然后根据问题类型选择合适的操作。 | |||
| ### 参数 | |||
| `$ARGUMENTS` 中可能传入: | |||
| - (空) — 默认排查国外服务器(OV,主节点) | |||
| - `cn` — 只排查国内服务器 | |||
| - `ov` — 只排查国外服务器 | |||
| - `all` — 排查两台服务器 | |||
| 如果用户没有明确指定,**默认排查 OV 服务器**(因为 MySQL 主库在 OV)。 | |||
| --- | |||
| ### 服务器配置 | |||
| | 节点 | SSH | docker-compose 目录 | new-api 容器名 | MySQL 容器名 | | |||
| |------|-----|---------------------|---------------|-------------| | |||
| | 🇨🇳 国内 CN | `root@123.57.74.135` | `/root/new-api/` | `cn-new-api` | `ov-mysql` | | |||
| | 🌏 国外 OV | `root@139.180.189.205` | `/root/new-api/new-api/` | `ov-new-api` | `mysql` | | |||
| **重要**:两台服务器的 MySQL 实际都在 OV(国外节点)。CN 的 SQL_DSN 指向 `ov-mysql:3306`。所以查数据库统一用 OV 的 MySQL 容器 `mysql`。 | |||
| MySQL 连接:`docker exec mysql mysql -uroot -pLanqi123456 new-api -e "SQL语句"` | |||
| --- | |||
| ### 所有命令执行方式 | |||
| **必须通过 WSL 执行**(SSH 密钥在 WSL 中): | |||
| ```bash | |||
| # 单条命令 | |||
| wsl -- bash -c "ssh root@HOST '命令'" | |||
| # 多条命令(引号嵌套复杂时用 heredoc) | |||
| wsl -- bash -c "ssh root@HOST 'cmd1 && cmd2 && cmd3'" | |||
| ``` | |||
| --- | |||
| ### 操作指南 | |||
| 根据用户描述的问题,选择合适的排查步骤。**不要一次性执行所有操作**,应该根据问题逐步排查。 | |||
| #### 1. 服务状态检查 | |||
| ```bash | |||
| # 查看所有容器状态 | |||
| wsl -- bash -c "ssh root@HOST 'cd COMPOSE_DIR && docker compose ps'" | |||
| # 健康检查 | |||
| wsl -- bash -c "ssh root@HOST 'curl -s http://localhost:3000/api/status'" | |||
| # 系统资源(CPU/内存/磁盘) | |||
| wsl -- bash -c "ssh root@HOST 'free -h && df -h / && docker stats --no-stream'" | |||
| ``` | |||
| #### 2. 应用日志 | |||
| ```bash | |||
| # 最近 N 行容器日志 | |||
| wsl -- bash -c "ssh root@HOST 'docker logs --tail 100 CONTAINER_NAME'" | |||
| # 实时跟踪日志(带超时,避免阻塞) | |||
| wsl -- bash -c "ssh root@HOST 'timeout 5 docker logs --tail 50 --since 5m CONTAINER_NAME'" | |||
| # 搜索特定关键词(如错误、某用户、某模型) | |||
| wsl -- bash -c "ssh root@HOST 'docker logs --tail 500 CONTAINER_NAME 2>&1 | grep -i KEYWORD'" | |||
| # 应用日志文件(oneapi-*.log) | |||
| wsl -- bash -c "ssh root@HOST 'ls -lt COMPOSE_DIR/logs/ | head -5'" | |||
| wsl -- bash -c "ssh root@HOST 'tail -100 COMPOSE_DIR/logs/oneapi-XXXX.log'" | |||
| ``` | |||
| #### 3. MySQL 查询 | |||
| **连接方式(在 OV 服务器上执行)**: | |||
| ```bash | |||
| wsl -- bash -c "ssh root@139.180.189.205 'docker exec mysql mysql -uroot -pLanqi123456 new-api -e \"SQL语句\"'" | |||
| ``` | |||
| 注意:SQL 语句中的双引号需要用 `\"` 转义。 | |||
| **常用查询模板**: | |||
| ```sql | |||
| SELECT id, username, email, role, status, quota, used_quota, \`group\`, aff_code FROM users WHERE username = 'XXX'; | |||
| SELECT id, created_at, type, model_name, quota, channel_id, content FROM logs WHERE user_id = XXX ORDER BY created_at DESC LIMIT 20; | |||
| SELECT id, created_at, type, content, model_name FROM logs WHERE created_at >= '2026-04-16 00:00:00' AND type = 2 ORDER BY created_at DESC LIMIT 50; | |||
| SELECT id, name, type, status, balance, used_quota, models, \`group\`, priority FROM channels WHERE status != 3; | |||
| SELECT id, created_at, model_name, quota, content FROM logs WHERE channel_id = XXX ORDER BY created_at DESC LIMIT 20; | |||
| SELECT id, name, \`key\`, status, remain_quota, used_quota, expired_time FROM tokens WHERE user_id = XXX; | |||
| SELECT id, user_id, amount, money, trade_no, status, created_at FROM topups ORDER BY created_at DESC LIMIT 20; | |||
| SELECT id, user_id, plan_id, status, amount, created_at FROM subscription_orders ORDER BY created_at DESC LIMIT 20; | |||
| SELECT * FROM pending_sync_records ORDER BY id DESC LIMIT 20; | |||
| SELECT * FROM quota_sync_logs ORDER BY id DESC LIMIT 20; | |||
| SELECT id, user_id, action, status, progress, fail_reason, created_at FROM midjourneys ORDER BY created_at DESC LIMIT 20; | |||
| SELECT \`key\`, value FROM options WHERE \`key\` IN ('ServerAddress', 'TopUpLink', 'QuotaForNewUser', 'QuotaForInviter', 'QuotaForInvitee'); | |||
| ``` | |||
| **日志类型 (type 字段)**: | |||
| - `1` — 消耗 (consume) | |||
| - `2` — 充值 (recharge/topup) | |||
| - `3` — 管理员操作 | |||
| - `4` — 系统 | |||
| #### 4. Relay 抓包日志(请求体/响应体完整记录) | |||
| 对开启了 `capture_relay` 的用户,系统会将完整的请求体和响应体写入容器内文件。适用于需要查看客户端实际发送的请求体内容的场景(如验证字段是否正确、排查请求格式问题)。 | |||
| **文件路径**(容器内):`/data/data/relay-capture/{YYYY-MM-DD}/{requestID}.log` | |||
| ```bash | |||
| # 列出某天的抓包文件(最新 20 个) | |||
| wsl -- bash -c 'ssh root@HOST "docker exec CONTAINER_NAME ls -lt /data/data/relay-capture/2026-05-14/ | head -20"' | |||
| # 查看特定请求的抓包内容(requestID 从日志错误行中获取) | |||
| wsl -- bash -c 'ssh root@HOST "docker exec CONTAINER_NAME cat /data/data/relay-capture/2026-05-14/REQUEST_ID.log"' | |||
| # 文件很大时,只看请求头 + 请求体前 2000 字节 | |||
| wsl -- bash -c 'ssh root@HOST "docker exec CONTAINER_NAME head -c 2000 /data/data/relay-capture/2026-05-14/REQUEST_ID.log"' | |||
| ``` | |||
| **抓包文件格式**: | |||
| ``` | |||
| === REQUEST 2026-05-14T09:09:51.80665026Z === | |||
| POST /v1/chat/completions | |||
| user_id: 44 | |||
| X-Forwarded-For: 184.73.225.134 | |||
| User-Agent: Cursor/1.0 | |||
| Content-Type: application/json | |||
| ... | |||
| {"stream":true,"model":"openai/gpt-5.4","messages":[...]} | |||
| === RESPONSE === | |||
| {"error":{"message":"field messages is required",...}} | |||
| === END duration_ms=6 === | |||
| ``` | |||
| **使用场景**: | |||
| - 客户端发送了错误格式的请求体(如用 `input` 代替 `messages`) | |||
| - 需要确认请求头、User-Agent、请求体字段 | |||
| - 排查特定 request ID 的完整请求/响应链路 | |||
| **注意**: | |||
| - 只有开启了 `capture_relay` 的用户才有抓包文件,未开启的用户查不到 | |||
| - 请求体可能很大(100KB+),建议先用 `head -c` 限制输出大小 | |||
| - 抓包文件名即 request ID,可从容器的 `[ERR]` 日志行中提取 | |||
| #### 5. 容器内操作 | |||
| ```bash | |||
| # 进入容器执行命令(如检查网络连通性) | |||
| wsl -- bash -c "ssh root@HOST 'docker exec CONTAINER_NAME wget -qO- http://localhost:3000/api/status'" | |||
| # 重启某个服务(谨慎操作,先确认用户意图) | |||
| wsl -- bash -c "ssh root@HOST 'cd COMPOSE_DIR && docker compose restart new-api'" | |||
| ``` | |||
| --- | |||
| ### 排查流程建议 | |||
| 1. **先问清楚问题**:什么现象?什么时候开始的?影响哪些用户? | |||
| 2. **服务状态** → 检查容器是否正常运行 | |||
| 3. **应用日志** → 搜索错误关键词、时间范围 | |||
| 4. **数据库查询** → 根据日志中的线索查相关数据 | |||
| 5. **Relay 抓包** → 如果日志中只有错误摘要但看不清请求体细节,检查用户是否开启了 `capture_relay`,若有则读取抓包文件查看完整请求/响应 | |||
| 6. **综合分析** → 给出问题原因和修复建议 | |||
| ### 注意事项 | |||
| - **不要执行任何写入操作**(INSERT/UPDATE/DELETE),除非用户明确要求 | |||
| - MySQL 查询要加 `LIMIT`,避免返回过多数据 | |||
| - 查询时间范围要合理,不要全表扫描 | |||
| - 如果发现需要重启服务,先告知用户再操作 | |||
| - 所有输出向用户展示时,用中文解释含义 | |||
| @@ -1,98 +0,0 @@ | |||
| --- | |||
| allowed-tools: Bash | |||
| description: 'Command: deploy-local (imported from Claude Code)' | |||
| name: cmd-deploy-local | |||
| --- | |||
| ## 启动本机开发环境 | |||
| 在 Windows 上直接运行 `go run main.go`,数据库使用 WSL 中的 MySQL 和 Redis。 | |||
| ### 环境信息 | |||
| | 项目 | 连接信息 | | |||
| |------|---------| | |||
| | MySQL | `localhost:33306` root/Lanqi123456 db:new-api | | |||
| | Redis | `localhost:36379` | | |||
| | 后端 | `localhost:3000` | | |||
| | 前端 | `localhost:5173`(dev server) | | |||
| | 管理员 | root / 12345678 | | |||
| ### 参数 | |||
| 用户可能在 `$ARGUMENTS` 中传入: | |||
| - (空) — 启动全部(MySQL/Redis + 前端 + 后端) | |||
| - `--backend-only` — 只启动后端(MySQL/Redis + 后端) | |||
| - `--frontend-only` — 只启动前端 dev server | |||
| - `--stop` — 停止所有服务(后端进程 + 前端进程) | |||
| ### 执行步骤 | |||
| **步骤 1:确保 WSL 中 MySQL 和 Redis 运行** | |||
| ```bash | |||
| wsl -- bash -c "cd /root/new-api-dev && docker compose up -d" | |||
| ``` | |||
| 等待 MySQL 就绪(最多 30 秒): | |||
| ```bash | |||
| until wsl -- bash -c "mysql -h 127.0.0.1 -P 3306 -u root -pLanqi123456 -e 'SELECT 1'" 2>/dev/null; do sleep 2; done | |||
| ``` | |||
| **步骤 2:杀掉旧进程(如果端口被占用)** | |||
| 检查并杀掉占用 3000 端口的进程: | |||
| ```bash | |||
| netstat -ano | grep ":3000 " | grep LISTENING | awk '{print $5}' | sort -u | while read pid; do taskkill //PID $pid //F 2>/dev/null; done | |||
| ``` | |||
| 检查并杀掉占用 5173 端口的进程(如果需要启动前端): | |||
| ```bash | |||
| netstat -ano | grep ":5173 " | grep LISTENING | awk '{print $5}' | sort -u | while read pid; do taskkill //PID $pid //F 2>/dev/null; done | |||
| ``` | |||
| **步骤 3:启动服务** | |||
| 前端(后台,仅在非 `--backend-only` 时): | |||
| ```bash | |||
| cd web && bun run dev | |||
| ``` | |||
| 后端(后台,仅在非 `--frontend-only` 时),带环境变量: | |||
| ```bash | |||
| export SQL_DSN="root:Lanqi123456@tcp(localhost:33306)/new-api" | |||
| export REDIS_CONN_STRING="redis://localhost:36379" | |||
| export SESSION_SECRET="dev-secret-do-not-use-in-prod" | |||
| export SESSION_NAME="session_dev" | |||
| export DEBUG=1 | |||
| export ERROR_LOG_ENABLED=true | |||
| export BATCH_UPDATE_ENABLED=true | |||
| export TZ=Asia/Shanghai | |||
| go run main.go | |||
| ``` | |||
| **步骤 4:等待就绪并验证** | |||
| 等待后端就绪: | |||
| ```bash | |||
| until curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/api/status | grep -q "200"; do sleep 2; done | |||
| ``` | |||
| **步骤 5:报告状态** | |||
| 向用户报告: | |||
| - 各服务状态(MySQL/Redis/后端/前端) | |||
| - 访问地址 | |||
| - 如果有服务启动失败,报告具体错误 | |||
| ### 停止服务(`--stop`) | |||
| 杀掉 3000 和 5173 端口上的进程即可。MySQL/Redis 容器保持运行(数据持久化)。 | |||
| ### 要求 | |||
| - 所有服务使用 `run_in_background` 启动 | |||
| - 等待后端就绪后再报告 | |||
| - 如果编译失败,报告具体错误 | |||
| - 启动完成后提示用户可以使用 `curl` 或浏览器访问 | |||
| @@ -1,44 +0,0 @@ | |||
| --- | |||
| allowed-tools: Bash(wsl -- *) | |||
| description: 'Command: deploy-wsl-test (imported from Claude Code)' | |||
| name: cmd-deploy-wsl-test | |||
| --- | |||
| ## 部署到测试环境 | |||
| 将镜像构建并部署到 WSL 本地的国内/国外测试节点。 | |||
| ### 测试环境信息 | |||
| | 项目 | 国内节点 | 国外节点 | | |||
| |------|---------|---------| | |||
| | 目录 | /root/new-api-cn | /root/new-api-ov | | |||
| | 端口 | 23000:3000 | 13000:3000 | | |||
| | MySQL | 23306 | 13306 | | |||
| | 容器名 | cn-new-api | ov-new-api | | |||
| | SESSION | session_m (Master) | session_slave (Slave) | | |||
| ### 参数 | |||
| 用户可能在 `$ARGUMENTS` 中传入: | |||
| - (空) — 构建镜像 + 推送 + 部署到两个测试节点 | |||
| - `cn` — 只部署到国内测试节点 | |||
| - `ov` — 只部署到国外测试节点 | |||
| - `--no-build` — 跳过构建推送,使用本地最新镜像 | |||
| - 可以组合,如 `--no-build cn` | |||
| ### 执行 | |||
| 使用以下命令在 WSL 中执行部署: | |||
| ```bash | |||
| wsl -- bash -c "cd /root && bash //mnt/d/code/new-api/scripts/deploy-test.sh $ARGUMENTS" | |||
| ``` | |||
| **注意**:路径必须使用 `//mnt/d/...`(双斜杠),否则 Git Bash 会将其转换为 Windows 路径导致 WSL 找不到脚本。 | |||
| ### 要求 | |||
| - 等待命令完成,实时向用户报告进度 | |||
| - 如果失败,报告具体错误信息 | |||
| - 完成后向用户总结部署结果(镜像 tag、各节点状态) | |||
| @@ -1,34 +0,0 @@ | |||
| --- | |||
| allowed-tools: Bash(wsl -- *) | |||
| description: 'Command: deploy (imported from Claude Code)' | |||
| name: cmd-deploy | |||
| --- | |||
| ## 部署命令 | |||
| 通过 WSL 执行 `scripts/deploy.sh` 完成自动部署。 | |||
| ### 参数 | |||
| 用户可能在 `$ARGUMENTS` 中传入: | |||
| - (空) — 构建镜像 + 推送 + 部署到两台服务器 | |||
| - `cn` — 只部署到国内服务器 (123.57.74.135) | |||
| - `ov` — 只部署到国外服务器 (139.180.189.205) | |||
| - `--no-build` — 跳过构建推送,使用本地最新镜像 | |||
| - 可以组合,如 `--no-build cn` | |||
| ### 执行 | |||
| 使用以下命令调用部署脚本: | |||
| ```bash | |||
| wsl -- bash -c "bash //mnt/d/code/new-api/scripts/deploy.sh $ARGUMENTS" | |||
| ``` | |||
| **注意**:路径必须使用 `//mnt/d/...`(双斜杠),否则 Git Bash 会将其转换为 Windows 路径导致 WSL 找不到脚本。 | |||
| ### 要求 | |||
| - 等待命令完成,实时向用户报告进度 | |||
| - 如果失败,报告具体错误信息 | |||
| - 完成后向用户总结部署结果(镜像 tag、各节点状态) | |||
| @@ -1,86 +0,0 @@ | |||
| --- | |||
| allowed-tools: >- | |||
| Bash(git add:*), Bash(git status:*), Bash(git diff:*), Bash(git log:*), | |||
| Bash(git commit:*), Bash(mkdir:*), Read, Write, Edit, Glob, Grep | |||
| description: 'Command: ob-commit (imported from Claude Code)' | |||
| name: cmd-ob-commit | |||
| --- | |||
| ## Context | |||
| - Current git status: !`git status` | |||
| - Current git diff (staged and unstaged changes): !`git diff HEAD` | |||
| - Current branch: !`git branch --show-current` | |||
| - Recent commits: !`git log --oneline -10` | |||
| ## Task | |||
| Based on the above changes, create a git commit AND write a development log to Obsidian. | |||
| ### Step 1: Create the commit | |||
| 1. Analyze the changes and draft a commit message following conventional commits format. | |||
| 2. Stage the relevant files and create the commit. | |||
| ### Step 2: Write Obsidian dev log (MANDATORY) | |||
| After the commit succeeds, you MUST write a development log. Follow these rules exactly: | |||
| **Directory**: `D:\markdown\workspace-lanqi\new-api\{YYYY-MM-DD}\` (create if not exists) | |||
| **File naming**: `{YYYY-MM-DD} {commit message short summary}.md` | |||
| - If multiple commits on the same day, append a brief distinguishing suffix | |||
| - Example: `2026-04-16 fix: 修复支付回调签名验证.md` | |||
| **Log template** — write in Chinese: | |||
| ```markdown | |||
| --- | |||
| created: YYYY-MM-DD | |||
| tags: | |||
| - dev-log | |||
| - new-api | |||
| branch: {branch name} | |||
| commit: {short hash} | |||
| --- | |||
| # {commit message} | |||
| > 分支:`{branch}` | Commit:`{short hash}` | 日期:YYYY-MM-DD | |||
| ## 变更概述 | |||
| {1-3 sentences summarizing purpose and impact} | |||
| ## 新增文件 | |||
| | 文件 | 说明 | | |||
| |------|------| | |||
| | `{path}` | {description} | | |||
| ## 修改文件 | |||
| | 文件 | 变更内容 | | |||
| |------|---------| | |||
| | `{path}` | {what changed and why} | | |||
| ## 关键代码变更 | |||
| {Detailed description of core logic changes, including function signature changes, new key functions, algorithm logic. Use code blocks for key snippets.} | |||
| ## 数据库变更 | |||
| {If table structure changed, list new tables, columns, indexes. Delete this section if none.} | |||
| ## 备注 | |||
| {Additional notes, design decisions, known issues. Delete this section if none.} | |||
| ``` | |||
| ### Rules | |||
| - Delete sections with no content (数据库变更, 备注) | |||
| - All log content in Chinese | |||
| - Frontmatter MUST include: `created`, `tags` (at least `dev-log` and `new-api`), `branch`, `commit` | |||
| - Include enough detail for someone unfamiliar with the change to understand it | |||
| - You MUST use multiple tools in a single response. Stage, commit, then write the log file. | |||
| @@ -1,103 +0,0 @@ | |||
| --- | |||
| allowed-tools: mcp__plugin_chrome-devtools-mcp_chrome-devtools__* | |||
| description: 'Command: set-channel-pricing (imported from Claude Code)' | |||
| name: cmd-set-channel-pricing | |||
| --- | |||
| ## 设置渠道定价 | |||
| 通过 Chrome DevTools MCP 在指定环境中操作浏览器,为模型配置渠道定价并设置默认通道。 | |||
| ### 参数 | |||
| 用户在 `$ARGUMENTS` 中传入 JSON 格式的参数(字段均可选,缺失时会询问): | |||
| ``` | |||
| { | |||
| "target": "http://localhost:23000", | |||
| "model_name": "deepseek-ai/DeepSeek-V3-0324", | |||
| "default_channel": "AtlasCloud", | |||
| "channels": { | |||
| "AtlasCloud": { "model_ratio": 1, "completion_ratio": 1 }, | |||
| "atlascloud": { "model_ratio": 1, "completion_ratio": 1 } | |||
| } | |||
| } | |||
| ``` | |||
| | 字段 | 说明 | 默认值 | | |||
| |------|------|--------| | |||
| | `target` | 目标环境地址 | 询问用户 | | |||
| | `model_name` | 要配置定价的模型名称 | 询问用户 | | |||
| | `default_channel` | 设为默认的渠道名称 | 不设置默认 | | |||
| | `channels` | 各渠道的定价配置 | 所有渠道统一设置 model_ratio=1, completion_ratio=1 | | |||
| 如果 `$ARGUMENTS` 不是 JSON,按顺序解析为 `model_name`,其余使用默认值。 | |||
| ### 操作流程 | |||
| 1. **导航到渠道定价页面** | |||
| - `navigate_page` 到 `{target}/console/setting?tab=ratio` | |||
| 2. **切换到渠道定价视图** | |||
| - `take_snapshot` 确认页面加载 | |||
| - 找到并点击"分组与模型定价设置"标签页(如果 URL 未直接跳转) | |||
| - 点击"可视化倍率设置"子标签 | |||
| - 点击"渠道定价"单选按钮 | |||
| 3. **搜索目标模型** | |||
| - 在搜索框中输入 `model_name` | |||
| - 等待列表过滤出目标模型 | |||
| 4. **展开模型行** | |||
| - 点击目标模型行的展开按钮(chevron_right) | |||
| 5. **为每个渠道设置定价** | |||
| - 对展开后每个未配置的渠道行,点击编辑按钮(edit icon) | |||
| - 在弹出的编辑对话框中: | |||
| - 确认模型名称正确 | |||
| - 选择计费类型(默认"按量计费") | |||
| - 填写模型倍率(`model_ratio`) | |||
| - 填写补全倍率(`completion_ratio`) | |||
| - 点击确认(confirm)保存 | |||
| - 如果渠道已有定价但需要修改,同样点击编辑按钮更新 | |||
| 6. **设置默认通道** | |||
| - 在展开的模型行中,找到 `default_channel` 对应的渠道 | |||
| - 点击该渠道行的星标按钮(star icon) | |||
| - 验证出现"已设为默认通道"提示和"默认"文字标签 | |||
| 7. **验证结果** | |||
| - `take_snapshot` 确认: | |||
| - 所有渠道都显示正确的倍率 | |||
| - 默认渠道旁显示黄色星标 + "默认"标签 | |||
| - 非默认渠道的星标为灰色 | |||
| - 向用户总结配置结果 | |||
| ### 关键 UI 元素识别 | |||
| | 元素 | 识别方式 | | |||
| |------|---------| | |||
| | 分组与模型定价设置 tab | 文本匹配 "分组与模型定价设置" | | |||
| | 可视化倍率设置 tab | 文本匹配 "可视化倍率设置" | | |||
| | 渠道定价 radio | 文本匹配 "渠道定价" | | |||
| | 模型行展开按钮 | 模型名称旁的 chevron_right 按钮 | | |||
| | 渠道编辑按钮 | 渠道行操作列的 edit 按钮 | | |||
| | 模型倍率输入框 | spinbutton,label 含 "模型倍率" | | |||
| | 补全倍率输入框 | spinbutton,label 含 "补全倍率" | | |||
| | 确认按钮 | 对话框底部的 confirm 按钮 | | |||
| | 默认星标按钮 | 渠道行"默认"列的 star 按钮 | | |||
| ### 测试环境地址 | |||
| | 环境 | 地址 | 说明 | | |||
| |------|------|------| | |||
| | 国内测试 | http://localhost:23000 | WSL 本地 | | |||
| | 国外测试 | http://localhost:13000 | WSL 本地 | | |||
| | 生产环境 | https://api.example.com | 按实际填写 | | |||
| ### 要求 | |||
| - 每步操作后用 `take_snapshot` 验证页面状态 | |||
| - 如果模型不存在于列表中,报告错误并询问用户是否需要先添加渠道 | |||
| - 如果渠道未在列表中显示(模型未关联到该渠道),提示用户该渠道不支持此模型 | |||
| - 完成后向用户总结配置结果(模型名称、各渠道倍率、默认通道) | |||
| @@ -23,6 +23,7 @@ plans | |||
| docs/plans/ | |||
| CLAUDE.md | |||
| .claude | |||
| .agents/ | |||
| .worktrees/ | |||
| logs/ | |||
| docs/superpowers | |||