- Language: Dart 3.10+
- TUI:
noctermv0.8.0 - Server:
dart:ioHttpServer - HTTP client:
dart:ioHttpClient - Compile:
dart compile exe-> single native binary - Distribution: npm tarball with Node.js launcher wrapper
commandcode-bridge/
├── bin/
│ ├── commandcode_bridge.dart # Dart entry point
│ └── commandcode-bridge.js # npm wrapper (spawns native binary)
├── lib/
│ ├── commandcode_bridge.dart # Barrel export
│ └── src/
│ ├── main.dart # CLI wiring (TUI / server / cost-sync modes)
│ ├── models/
│ │ ├── account.dart # Account + config store (port persist)
│ │ ├── models_db.dart # 52 bundled models + plan access metadata
│ │ └── version.dart # Bridge version constant
│ ├── services/
│ │ ├── api_client.dart # HTTP client for api.commandcode.ai (incl. /provider/v1/models)
│ │ ├── cost_sync.dart # Cost sync: detect agents, update configs
│ │ ├── log_store.dart # JSONL activity log (2000 entries max)
│ │ ├── pricing_db.dart # Hardcoded pricing table (52 models)
│ │ └── updater.dart # Self-update: API cache + download .tgz + npm install -g
│ ├── server/
│ │ ├── server_controller.dart # HTTP server, routing, shared endpoints
│ │ ├── openai_handler.dart # OpenAI-compatible proxy
│ │ └── anthropic_handler.dart # Anthropic-compatible proxy
│ └── tui/
│ └── app.dart # Nocterm TUI (10 panels + log sidebar)
├── scripts/
│ └── stage-npm-package.mjs # CI packaging helper
├── docs/
├── test/
├── AGENTS.md
├── CHANGELOG.md
├── build / run # Shell scripts
├── build.bat / run.bat # Windows batch scripts
├── LICENSE
├── package.json
└── pubspec.yaml
Client -> POST /v1/chat/completions -> Translate to CC wire format
| |
POST https://api.commandcode.ai/alpha/generate
| |
Translate NDJSON events back to target format
|
Client <- OpenAI SSE / Anthropic SSE
Client -> POST /v1/messages -> Same flow, Anthropic format
The cost-sync CLI command and TUI page 7 keep CLI agent cost tracking in
sync with Command Code pricing.
pricing_db.dartholds a hardcoded pricing table (52 models) matching the live bridge/v1/modelsAPIcost_sync.dartdetects installed CLI agents (OpenCode, Aider, Goose), reads each agent's configured models, and writes per-model cost fields (input, output, cache_read per 1M tokens)- Only providers that point at the bridge (localhost base URL) and are named "Command Code" are considered bridge providers; all are listed
- Pricing is validated against the live
/v1/modelsendpoint before syncing - OpenCode configs (JSONC) are parsed with comment and trailing-comma support
The bridge does not rely solely on its bundled registry. On every TUI refresh
([r], or once in the background when a page is opened) it calls the official
Command Code endpoint GET /provider/v1/models, caches the result in memory,
and merges it with the bundled ModelsDb models. This means newly released
models (for example Qwen/Qwen3.8-Max) are served by /v1/models and shown in
the TUI without needing a bridge release.
api_client.fetchModels()returns the live model list from the APIServerController.setLiveModelIds()updates the in-memory cache used by/v1/models- Unknown live models are still proxyable and appear with
owned_by: command-code - TUI page 5 groups models by plan access (Go/Pro/Max) using
PlanAccess, which mirrors the official CLI'sevaluateModelAccess: Go = open source + GPT-5.6 Luna / Grok 4.5, Pro blocks Fable/Opus + Fugu Ultra, and a credits override (purchased or free credits) grants access to everything - Model availability is classified dynamically via
ModelsDb.classify, mirroring the CLI (no hardcoded list):expired: free promotion ended by timestamp (ModelsDb.modelExpiryUtc, the same date-based checks the CLI ships, e.g.isLingFlashFreeEnded()), or bundled but dropped from the current Command Code catalog. Kept in the registry for history, grouped at the bottom of TUI page 5, excluded from/v1/modelsand TUI page 7 (Cost).isNew: present in the live API but absent from the bundled registry (newly released or renamed), shown in a "New / Coming soon" section above expired ones, excluded from cost display/sync.- comparison is case-insensitive and strips
-YYYYMMDDsuffixes (claude-haiku-4-5-20251001==claude-haiku-4-5)
Request translation:
- System messages extracted to
systemfield - Tool messages converted to
{role: "tool", content: [{type: "tool-result", ...}]} - Assistant tool_calls converted to
{type: "tool-call", ...}blocks - OpenAI params (model, stream, max_tokens, temperature) mapped to CC params
Response translation:
text-delta->data: {"choices":[{"delta":{"content":"..."}}]}reasoning-delta->data: {"choices":[{"delta":{"reasoning_content":"..."}}]}tool-call->data: {"choices":[{"delta":{"tool_calls":[...]}}]}finish-> final SSE chunk withfinish_reasonerror->data: {"error":{...}}
Request translation:
- System prompt extracted from top-level
systemfield (string or content blocks) - Anthropic content blocks (
text,tool_use,tool_result,image) converted to CC wire format - Anthropic tools (
input_schema) mapped to CC tools tool_choiceandthinkingsettings translated
Response translation:
message_start-> SSE event initiating the messagetext-delta->content_block_start(text)+content_block_delta(text_delta)+content_block_stopreasoning-delta->content_block_start(thinking)+content_block_stop(if available)tool-call->content_block_start(tool_use, input:{})+content_block_delta(input_json_delta)+content_block_stopfinish->message_delta(stop_reason)+message_stoperror-> SSE error event