中文 | English
一个本地部署、完全兼容 OpenAI Chat Completions 与 Anthropic Messages 的 API 网关,为 Command Code AI(commandcode.ai)提供透明代理。任何 OpenAI 风格的客户端(Cursor、Continue、Aider、OpenWebUI、Hermes、你自己的代码)都能直接指向它,透明地使用 CommandCode 后端模型。
非官方社区工具。逆向自官方 CommandCode CLI wire 协议(
/alpha/generate),与 CommandCode 无任何关联。
除命令行外,代理自带一个中文 Web 仪表盘(默认 http://127.0.0.1:9090),用于查看状态、管理账号与查看用量。以下为实际界面截图(均已脱敏)。
Beyond the CLI, the proxy ships a built-in Chinese web dashboard (default http://127.0.0.1:9090) for status, accounts and usage. Real screenshots below, all scrubbed.
- 一屏掌握运行状态:引擎运行/停止、监听端口、运行时长、当前账号、绑定地址、API 鉴权开关、已注册账号数与可用模型数。
- 顶部可一键切换引擎、切换当前账号、调整额度轮换模式。
- 官方模型定价目录(上下文 / 输入 / 输出 / 缓存读 / 缓存写 / 能力 / Deal),实时从 commandcode.ai 刷新,也可手动“获取最新模型”。
- 支持关键词搜索、标签筛选(GO / FREE / DEAL / 视觉 / 推理)与排序(输入价、输出价、缓存读、上下文等),令牌数以 K/M 友好显示。
- 支持浏览器登录(OAuth)或粘贴 Key 登录;多账号管理,5 小时额度轮换调度(≥90% 自动切换)。
- 密钥在界面上一律脱敏显示(如
sk-demo-...cccc),可设为当前账号或移除——保证敏感信息不落屏。
- OpenAI
/v1/chat/completions— 流式 SSE + 非流式,工具调用(并行工具、流式tool_calls增量),视觉(image_urlbase64/data-URL),reasoning_effort映射,max_completion_tokens,透传上游totalUsage用量 - Anthropic
/v1/messages— 流式块生命周期(message_start→content_block_start/delta/stop→signature_delta→message_delta→message_stop),tool_use/tool_result往返,带签名兼容的 thinking 块,system 块数组 - 忠实还原 wire 翻译 — 经官方 CLI 源码逐行核对:原始 base64 图片块带
mediaType、tool_search→search_tools别名、按模型细分推理档位 snap、终止性错误不重试列表(model_not_in_plan、premium_credits_exhausted、insufficient credits) - 工具定义全量透传 —
convertTools不再截断为 15 个:DSH Desktop 等多工具 Agent 宿主下发的 30+ 个工具(read/write/pwsh/web_search 等)全部透传给上游,避免模型调用被丢弃的工具而被拒绝;tool_search→search_tools别名与name/description/input_schema映射逻辑不变 - 可靠性 — 429/5xx/网络错误指数退避重试,空闲流看门狗(不会无限挂起),客户端断开即取消,保证流干净收尾
- 多账号 — 仪表盘 OAuth 浏览器登录 + 手动输入 Key,5 小时额度轮换调度器(≥90% 自动切换)
- 安全默认 — 仅绑定
127.0.0.1(可用HOST显式开放局域网),可选PROXY_API_KEY共享密钥鉴权,XSS 加固仪表盘,CORS 仅对公共 API 表面开放;所有服务端上游请求经assertSafeUpstreamUrl校验(拒绝非 http(s) 协议、内嵌凭据、非commandcode.ai的任意 host,且默认拒绝环回/私有/保留地址——除非显式加入允许清单;非回环强制 https),打开浏览器改为无 shell 的spawn参数调用(杜绝命令注入) - 打包 — TypeScript 构建、esbuild 打包、
pkg生成单文件 Windows exe - 中文仪表盘 — 内置界面为中文,含官方模型定价目录(上下文/输入/输出/缓存读/缓存写/能力/Deal),实时从 commandcode.ai 刷新;模型目录支持搜索、GO/FREE/DEAL/视觉/推理标签筛选与排序,令牌数大数(K/M)友好显示
- 会话明细用量 — 面板的"用量与额度"标签页内置会话明细:逐会话记录 input/output token、耗时、成本、模型、状态,并给出按天趋势折线、模型分布饼图、今日/本周/本月成本卡片;持久化到本地
~/.commandcode/usage-history.jsonl,重启不丢 - 官方用量总览 — 对齐官方 usage 页面(commandcode.ai/:login/settings/usage)的数据源:Total Tokens(含输入/输出拆分)、Total Runs(成功/失败/成功率)、月度限额进度条来自上游
/alpha/usage/summary与/alpha/billing/credits(与页面/internal/*接口字段一致,但接受 CLI API Key);仪表盘新增GET /api/usage/overview聚合接口 - 结构化错误码 — 任何失败都返回稳定错误码 + 可执行提示(
RATE_LIMIT/MODEL_NOT_IN_PLAN/STREAM_IDLE_TIMEOUT等 17 个码),并按出口分别给出 OpenAI 的error.type/error.code与 Anthropic 的error.type;调用方可据此判断该等额度、换模型还是改配置,详见下节错误码表 - 套餐与计费周期 —
/api/usage/overview新增plan块:套餐名(Go / GOAT / Pro …)、官方额度与 5 小时/周上限、currentPeriodStart/End、cancelAtPeriodEnd、以及totalDays / daysElapsed / daysLeft / cyclePct周期进度;仪表盘"用量与额度"页新增计费周期卡片(订阅额度到期不结转,这里一眼可见还剩几天) - 模型按套餐可用性 — 保留上游定价页的全量档位映射(此前被压成一个
onGoPlan布尔),GET /v1/models每个模型带availability/available_on_plan/plan_tier;支持?plan=individual-go&available=1按档位过滤(不带参数时行为不变,向后兼容)。判定采用 fail-open:数据缺失时保留而非误杀
npm install
npm run dev # http://127.0.0.1:9090或生产模式:
npm run build && npm start或独立二进制:
npm run build:win # dist/commandcode-proxy-v4.exe —— 零依赖运行首次启动仪表盘会自动打开。可通过 浏览器登录(OAuth) 或粘贴 API Key 登录。密钥也会自动从 ~/.commandcode/auth.json 或 COMMANDCODE_API_KEY 加载。
# OpenAI 风格(示例用免费模型,任何套餐可直接跑通)
curl http://127.0.0.1:9090/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"meituan/LongCat-2.0:free","messages":[{"role":"user","content":"hi"}]}'
# Anthropic 风格
curl http://127.0.0.1:9090/v1/messages \
-H "Content-Type: application/json" \
-d '{"model":"meituan/LongCat-2.0:free","max_tokens":1024,"messages":[{"role":"user","content":"hi"}]}'模型名请以仪表盘"模型"页或
GET /v1/models返回的实时目录为准;免费/折扣模型标有 FREE / DEAL 标签。
客户端配置:OpenAI 风格设 base URL 为 http://127.0.0.1:9090/v1,Anthropic 风格设为 http://127.0.0.1:9090,密钥随意(若设置了 PROXY_API_KEY 则须一致)。
按套餐筛选可用模型(plan 可显式指定,也可省略而使用当前账号的套餐;不带 available 则为完整目录):
curl "http://127.0.0.1:9090/v1/models?plan=individual-go&available=1"任何失败都返回稳定错误码 + 可执行提示,调用方可据此判断该等待额度、换模型还是改配置。
OpenAI 出口(/v1/chat/completions):
{ "error": { "message": "Upstream error 429: insufficient credits", "type": "rate_limit_error",
"code": "RATE_LIMIT", "param": null, "hint": "The plan usage window (5-hour or weekly) is exhausted..." } }Anthropic 出口(/v1/messages):
{ "type": "error", "error": { "type": "rate_limit_error", "message": "...",
"code": "RATE_LIMIT", "hint": "..." } }code |
HTTP | 含义 |
|---|---|---|
MISSING_CREDENTIAL |
401 | 没有任何可用 Key(环境变量/auth.json/账号池皆空) |
INVALID_CREDENTIAL |
401 | Key 失效或被吊销 |
PROXY_AUTH_REQUIRED |
401 | 未携带匹配的 PROXY_API_KEY |
RATE_LIMIT |
429 | 5 小时/周额度耗尽,或余额不足 |
MODEL_NOT_IN_PLAN |
403 | 模型超出当前套餐档位 |
MODEL_NOT_FOUND |
404 | 模型 id 不存在(刷新目录后重试) |
UNSUPPORTED_OPTION / UNSUPPORTED_CONTENT |
400 | 请求形态或内容无法翻译到上游 wire |
REQUEST_TIMEOUT / STREAM_IDLE_TIMEOUT |
504 | 请求超时 / 流中途静默被看门狗中止 |
NETWORK_ERROR |
502 | 连不上上游 API |
SERVER_ERROR |
5xx | 上游 5xx(保留上游真实状态码) |
PROVIDER_PROTOCOL_ERROR |
502 | 上游返回体异常(缺 body 等) |
CATALOG_UNAVAILABLE |
503 | 模型目录不可用 |
GATEWAY_PAUSED |
503 | 引擎已在面板暂停 |
BLOCKED_HOST |
500 | 上游地址被 SSRF 防护拒绝 |
INTERNAL_ERROR |
500 | 网关内部异常 |
重试语义:408/409/425/429/500/502/503/504 按指数退避重试(上限 upstream.maxRetries);一旦命中终止性计费/套餐标记(model_not_in_plan、premium_credits_exhausted、insufficient credits)立即失败、绝不重试——重试只会白耗额度。重试耗尽后仍保留上游真实状态码与错误码,不会包装成"网络故障"。
流式请求在 HTTP 200 已发出后无法再改状态码,此时错误码会并入内容文本,形如
[Upstream Error: RATE_LIMIT: ...],便于客户端自愈。
| 环境变量 | 默认值 | 作用 |
|---|---|---|
PORT |
9090 |
监听端口 |
HOST |
127.0.0.1 |
绑定地址(0.0.0.0 暴露到局域网) |
PROXY_API_KEY |
未设置 | 要求 /v1/* 携带该密钥(Bearer 或 x-api-key) |
COMMANDCODE_API_KEY |
取自 auth.json | 上游密钥兜底;无命名账号时账号名显示为 CLI Key (尾4位 xxxx) / Env Key (尾4位 xxxx),启动后由 whoami 异步补全真实用户名 |
COMMANDCODE_API_BASE |
https://api.commandcode.ai |
上游服务地址 |
COMMANDCODE_UPSTREAM_ALLOWED_HOSTS |
未设置 | 追加允许的上游 host(逗号分隔,供自建网关/镜像);环回/私有/保留地址默认拒绝,仅在此显式加入才放行 |
COMMANDCODE_VERSION |
1.27.1 |
CLI 版本标识头 |
ROTATION_MODE |
manual |
auto-quota 启用 30 分钟额度检查 |
NO_OPEN_BROWSER |
未设置 | 设为 1 跳过仪表盘自动打开 |
MAX_BODY_MB |
64 |
入站 JSON 请求体上限(MB);视觉/多图 base64 负载超默认 1MB 会触发 413(FST_ERR_CTP_BODY_TOO_LARGE),范围 1..1024 |
持久化配置存于可执行文件旁的 config.json。
npm run typecheck # tsc --noEmit
npm test # vitest —— 单元 + 集成(mock 上游)
npm run build:exe # esbuild 打包
npm run build:win # Windows exe测试会拉起一个 mock CommandCode 上游,端到端跑通真实 HTTP 面:流式 chunk 形状、工具调用往返、推理档位 snap、Anthropic 块生命周期。
详见 HERMES_TEST_PROMPT.md 了解 agent 驱动的自测方案(让 LLM agent 穿过代理跑真实行为验证)。
src/
├── index.ts # 启动引导、额度轮换调度、可选鉴权钩子
├── types/index.ts # OpenAI / Anthropic / CC-wire 契约
├── adapters/commandcode/
│ ├── adapter.ts # 翻译引擎(两种协议 ↔ CC wire,含中文注释)
│ └── upstream.ts # HTTP 客户端:重试、空闲看门狗、中止
├── routes/
│ ├── chat.ts # POST /v1/chat/completions
│ ├── messages.ts # POST /v1/messages
│ ├── models.ts # GET /v1/models、refresh
│ └── dashboard.ts # 中文 SPA + 管理 API
└── utils/
├── config.ts # 账号、OAuth 流程、额度轮换
├── models.ts # 目录同步 + 模糊模型名解析
├── usage-store.ts # 会话明细持久化 + 聚合统计
└── logger.ts # 净化环形缓冲日志
代理对所有服务端上游请求做白名单校验,采用 fail-closed(不满足即拒绝),而非降级放行:
校验顺序为:仅允许 http(s) → 拒绝内嵌凭据 → 拒绝环回/私有/保留地址(除非显式允许)→ host 属于 commandcode.ai 及子域或显式允许清单 → 非回环强制 https,全满足才放行。
- 默认只允许
commandcode.ai及其子域;环回(localhost、127.x、::1)、私有(10.x、172.16-31.x、192.168.x)、保留/链路本地(169.254.x、IPv6 ULA/链路本地)及任意公网地址默认一律拒绝,除非运维显式加入允许清单。 - 环回/私有受控例外:本地 mock 上游、自建网关/镜像与开发测试需通过
COMMANDCODE_UPSTREAM_ALLOWED_HOSTS显式加入允许清单才放行。这是运维显式配置的受控例外,而非默认放行或客户端可控路径——上游地址只由COMMANDCODE_API_BASE等运维环境变量决定,不随客户端请求参数变化,因此不存在把客户端输入导向内网的 SSRF 路径。 - 配套校验:拒绝非
http(s)协议(防file:、gopher:协议混淆)、拒绝内嵌凭据(user:pass@host)、非回环 host 强制https(防降级明文;回环且显式放行时允许 http,供本地 mock)。
本项目通过观察官方 CLI 的网络行为来与私有 API 互通。上游协议变动时可能失效,使用可能受 CommandCode 服务条款约束。请用自己的账号与凭据使用。
本项目使用 MIT 许可证 发布,详见 LICENSE。
A local, fully-compatible OpenAI Chat Completions and Anthropic Messages API gateway for CommandCode AI. Point any OpenAI-style client (Cursor, Continue, Aider, OpenWebUI, Hermes, your own code) at it and use CommandCode backend models transparently.
Unofficial, community tool. Reverse-engineered from the official CommandCode CLI wire protocol (
/alpha/generate). Not affiliated with CommandCode.
The bilingual Screenshots section above shows the real dashboard UI (console overview, model catalog, accounts), all scrubbed.
- OpenAI
/v1/chat/completions— streaming SSE + non-streaming, tool calling (parallel tools, streamedtool_callsdeltas), vision (image_urlbase64/data-URL),reasoning_effortmapping,max_completion_tokens, usage passthrough from upstreamtotalUsage - Anthropic
/v1/messages— streaming block lifecycle (message_start→content_block_start/delta/stop→signature_delta→message_delta→message_stop),tool_use/tool_resultround-trip, thinking blocks with signature compatibility, system block arrays - Faithful wire translation verified against the original CLI source: raw-base64 image parts with
mediaType,tool_search→search_toolsaliasing, per-model effort tier snapping, terminal-error no-retry list (model_not_in_plan,premium_credits_exhausted,insufficient credits) - Full tool passthrough —
convertToolsno longer truncates to 15 tools: the 30+ tools issued by multi-tool agent hosts (DSH Desktop and similar, e.g. read/write/pwsh/web_search at the end of the list) are all forwarded to upstream, preventing the model from calling dropped tools and being rejected;tool_search→search_toolsaliasing andname/description/input_schemamapping are unchanged - Reliability — exponential-backoff retries on 429/5xx/network errors, idle-stream watchdog (no infinite hangs), client-disconnect cancellation, clean stream termination guaranteed
- Multi-account — dashboard OAuth browser login + manual key entry, 5-hour quota rotation scheduler (auto-switch ≥90%)
- Secure defaults — binds
127.0.0.1only (opt-in LAN viaHOST), optionalPROXY_API_KEYshared-secret auth, XSS-hardened dashboard, CORS limited to the public API surface; all server-side upstream requests are validated byassertSafeUpstreamUrl(rejects non-http(s)schemes, embedded credentials, and any host that is neithercommandcode.ainor explicitly allowlisted, and rejects loopback/private/reserved addresses by default; enforceshttpsfor non-loopback), and browser opening uses argument-arrayspawn(no shell injection) - Packaging — TypeScript build, esbuild bundle, single-file Windows exe via
pkg - Chinese dashboard — built-in Chinese UI with official model pricing catalog (context/input/output/cache read/cache write/caps/deals) refreshed live from commandcode.ai
- Per-session usage history — the dashboard's Usage tab includes a session detail view: records input/output tokens, latency, cost, model, and status per request, visualized with a daily trend line, model-distribution doughnut, and today/week/month cost cards; persisted to
~/.commandcode/usage-history.jsonl, survives restarts - Official usage overview — mirrors the data sources of the official usage page (
commandcode.ai/:login/settings/usage): Total Tokens (with input/output breakdown), Total Runs (completed/failed/success rate) and a monthly limit progress bar fetched from upstream/alpha/usage/summaryand/alpha/billing/credits(same fields as the page's/internal/*endpoints, but accepting CLI API keys); exposed via the newGET /api/usage/overviewdashboard endpoint - Structured error codes — every failure returns a stable code plus an actionable hint (17 codes such as
RATE_LIMIT,MODEL_NOT_IN_PLAN,STREAM_IDLE_TIMEOUT), surfaced as OpenAIerror.type/error.codeon one route and Anthropicerror.typeon the other, so callers can tell whether to wait for quota, switch models, or fix configuration — see the error table below - Subscription plan & billing cycle —
/api/usage/overviewnow includes aplanblock: plan name (Go / GOAT / Pro …), official credits and 5-hour/weekly caps,currentPeriodStart/End,cancelAtPeriodEnd, plustotalDays / daysElapsed / daysLeft / cyclePct. The dashboard's Usage tab gains a billing-cycle card, since subscription credits expire at renewal instead of rolling over - Per-plan model availability — the upstream pricing page's full per-plan availability map is now preserved (it used to be collapsed into a single
onGoPlanboolean). Each model inGET /v1/modelscarriesavailability,available_on_planandplan_tier, and you can filter with?plan=individual-go&available=1; without parameters the response is unchanged (backward compatible). Judgement fails open — missing data keeps a model rather than dropping it
npm install
npm run dev # http://127.0.0.1:9090or production:
npm run build && npm startor the standalone binary:
npm run build:win # dist/commandcode-proxy-v4.exe — runs with zero dependenciesOn first launch the dashboard opens automatically. Log in via Browser (OAuth) or paste an API key. Keys are also auto-loaded from ~/.commandcode/auth.json or COMMANDCODE_API_KEY.
Filter models by plan (plan may be given explicitly, or omitted to use the active account's plan; drop available for the full catalog):
curl "http://127.0.0.1:9090/v1/models?plan=individual-go&available=1"Every failure returns a stable code plus an actionable hint, so callers can tell whether to wait for quota, switch models, or fix configuration.
OpenAI route (/v1/chat/completions):
{ "error": { "message": "Upstream error 429: insufficient credits", "type": "rate_limit_error",
"code": "RATE_LIMIT", "param": null, "hint": "The plan usage window (5-hour or weekly) is exhausted..." } }Anthropic route (/v1/messages):
{ "type": "error", "error": { "type": "rate_limit_error", "message": "...",
"code": "RATE_LIMIT", "hint": "..." } }code |
HTTP | Meaning |
|---|---|---|
MISSING_CREDENTIAL |
401 | No usable key (env / auth.json / account pool all empty) |
INVALID_CREDENTIAL |
401 | Key expired or revoked |
PROXY_AUTH_REQUIRED |
401 | Missing or wrong PROXY_API_KEY |
RATE_LIMIT |
429 | 5-hour/weekly window exhausted, or out of credits |
MODEL_NOT_IN_PLAN |
403 | Model is above the current subscription tier |
MODEL_NOT_FOUND |
404 | Unknown model id (refresh the catalog and retry) |
UNSUPPORTED_OPTION / UNSUPPORTED_CONTENT |
400 | Request shape or content cannot be translated to the upstream wire |
REQUEST_TIMEOUT / STREAM_IDLE_TIMEOUT |
504 | Request timed out / stream went silent and was aborted |
NETWORK_ERROR |
502 | Cannot reach the upstream API |
SERVER_ERROR |
5xx | Upstream 5xx (the real upstream status is preserved) |
PROVIDER_PROTOCOL_ERROR |
502 | Malformed upstream response (e.g. missing body) |
CATALOG_UNAVAILABLE |
503 | Model catalog unavailable |
GATEWAY_PAUSED |
503 | Engine paused from the dashboard |
BLOCKED_HOST |
500 | Upstream URL rejected by the SSRF guard |
INTERNAL_ERROR |
500 | Unexpected proxy-side failure |
Retry semantics: 408/409/425/429/500/502/503/504 are retried with exponential backoff (capped by upstream.maxRetries); the terminal billing/plan markers (model_not_in_plan, premium_credits_exhausted, insufficient credits) fail fast and are never retried, because retrying only burns credits. Once retries are exhausted the real upstream status and code are preserved instead of being reported as a network failure.
For streaming requests, the HTTP status is already 200 by the time the failure happens, so the code is folded into the content text as
[Upstream Error: RATE_LIMIT: ...].
| Env var | Default | Purpose |
|---|---|---|
PORT |
9090 |
Listen port |
HOST |
127.0.0.1 |
Bind address (0.0.0.0 exposes to LAN) |
PROXY_API_KEY |
unset | Require this key on /v1/* (Bearer or x-api-key) |
COMMANDCODE_API_KEY |
from auth.json | Upstream key fallback; with no named account the name shows as CLI Key (last4 xxxx) / Env Key (last4 xxxx), enriched from whoami after boot |
COMMANDCODE_API_BASE |
https://api.commandcode.ai |
Upstream base |
COMMANDCODE_UPSTREAM_ALLOWED_HOSTS |
unset | Extra allowed upstream hosts (comma-separated, for self-hosted gateways/mirrors); loopback/private/reserved are rejected by default unless added here |
COMMANDCODE_VERSION |
1.27.1 |
CLI version header |
ROTATION_MODE |
manual |
auto-quota enables 30-min quota checks |
NO_OPEN_BROWSER |
unset | Set 1 to skip dashboard auto-open |
MAX_BODY_MB |
64 |
Max inbound JSON body size (MB); vision/multi-image base64 payloads exceed the 1MB default (413, FST_ERR_CTP_BODY_TOO_LARGE). Range 1..1024 |
Persistent config lives in config.json next to the executable.
npm run typecheck # tsc --noEmit
npm test # vitest — unit + integration (mock upstream)
npm run build:exe # esbuild bundle
npm run build:win # Windows exeDescribed in the bilingual Upstream URL safety section above.
All server-side upstream requests pass an allowlist check and fail closed (reject, never degrade):
- By default only
commandcode.aiand its subdomains are allowed; loopback (localhost,127.x,::1), private (10.x,172.16-31.x,192.168.x), reserved/link-local (169.254.x, IPv6 ULA/link-local), and arbitrary public hosts are rejected unless an operator adds them to the allowlist. - Controlled loopback/private exception: a local mock upstream, self-hosted gateway/mirror, and dev/testing must be explicitly added to
COMMANDCODE_UPSTREAM_ALLOWED_HOSTSto be reachable. This is an operator-configured exception, not a default-allowed or client-controlled path — the upstream URL is determined only by operator env vars such asCOMMANDCODE_API_BASE, never by client request parameters, so there is no SSRF vector that steers client input to an internal network. - Additional checks: reject non-
http(s)schemes (protocol smuggling likefile:,gopher:), reject embedded credentials (user:pass@host), and enforcehttpsfor non-loopback hosts (no plaintext downgrade; loopback with explicit allowlist may usehttpfor a local mock).
This project interoperates with a private API by observing the official CLI's network behavior. It may break when the upstream protocol changes, and usage may be subject to CommandCode's terms of service. Use with your own account and credentials.


