Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,16 @@ CC_API_KEY=
HOST=127.0.0.1
PORT=8787

# Upstream timeouts (milliseconds)
# Max wall-clock time for CC to return response headers + first byte.
# Bump this for slow reasoning models that take a while to start streaming.
# CC_UPSTREAM_TIMEOUT_MS=600000 # default: 10 minutes

# Max gap between consecutive data chunks during streaming. If CC opens the
# connection but stops sending data mid-response (stalled tool call, dropped
# TCP, etc.), the proxy aborts the stream and the client gets a clean
# error/finish instead of hanging forever. Set to 0 to disable.
# CC_IDLE_TIMEOUT_MS=120000 # default: 2 minutes

# Anthropic model mapping (optional — prefer --setup-claude-code)
# ANTHROPIC_DEFAULT_MODEL=deepseek/deepseek-v4-pro
16 changes: 0 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,3 @@ jobs:
- name: Build
run: pnpm build

docker:
runs-on: ubuntu-latest
needs: quality
if: github.ref == 'refs/heads/main' && github.event_name == 'push'

steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v6
with:
push: false
tags: commandcode-api-proxy:latest
20 changes: 0 additions & 20 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,26 +72,6 @@ tests/
└── e2e.test.ts # End-to-end integration tests
```

## Docker

```bash
# Build
docker build -t commandcode-api-proxy .

# Run with env var
docker run --rm -p 8787:8787 \
-e CC_API_KEY=user_xxx \
commandcode-api-proxy

# Or mount auth.json
docker run --rm -p 8787:8787 \
-v ~/.config/commandcode-api-proxy:/home/node/.config/commandcode-api-proxy:ro \
commandcode-api-proxy

# Using docker compose
docker compose up -d
```

## Tech stack

- **Runtime:** Node.js (zero runtime dependencies)
Expand Down
17 changes: 0 additions & 17 deletions Dockerfile

This file was deleted.

17 changes: 1 addition & 16 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build dev start test test-watch test-coverage fmt lint check clean docker-build docker-run docker-run-detached release help
.PHONY: build dev start test test-watch test-coverage fmt lint check clean release help

APP_NAME := commandcode-api-proxy
VERSION := $(shell node -p "require('./package.json').version")
Expand Down Expand Up @@ -32,21 +32,6 @@ clean: ## Clean build artifacts
rm -rf dist/
rm -rf coverage/

docker-build: ## Build Docker image
docker build -t $(APP_NAME):$(VERSION) .
docker tag $(APP_NAME):$(VERSION) $(APP_NAME):latest

docker-run: ## Run Docker container
docker run --rm -p 8787:8787 \
-e CC_API_KEY=$(or $(CC_API_KEY),) \
$(APP_NAME):latest

docker-run-detached: ## Run Docker container in background
docker run -d --name $(APP_NAME) \
-p 8787:8787 \
-e CC_API_KEY=$(or $(CC_API_KEY),) \
$(APP_NAME):latest

release: build test ## Build and test for release
@echo "Ready for release: pnpm publish"

Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,17 @@ commandcode-api-proxy auth logout

Equivalent env vars (lower priority than CLI flags):

| Env var | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `HOST` | Bind address |
| `PORT` | Port |
| `CC_API_KEY` | Command Code API key |
| `CC_API_BASE` | Upstream API base URL |
| `CC_CLI_VERSION` | CLI version sent upstream |
| `LOG_LEVEL` | Log level (`info`, `debug`, etc.) |
| `CORS_ORIGIN` | `Access-Control-Allow-Origin` value. `*` by default; empty string disables CORS. Restrict before exposing on a network. |
| Env var | Description |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `HOST` | Bind address |
| `PORT` | Port |
| `CC_API_KEY` | Command Code API key |
| `CC_API_BASE` | Upstream API base URL |
| `CC_CLI_VERSION` | CLI version sent upstream |
| `CC_UPSTREAM_TIMEOUT_MS` | Max ms for upstream to return response headers + first byte (default `600000` / 10 min). Bump for slow reasoning models |
| `CC_IDLE_TIMEOUT_MS` | Max ms between consecutive stream chunks (default `120000` / 2 min). `0` disables — detects stalled upstreams |
| `LOG_LEVEL` | Log level (`info`, `debug`, etc.) |
| `CORS_ORIGIN` | `Access-Control-Allow-Origin` value. `*` by default; empty string disables CORS. Restrict before exposing on a network. |

> **Security:** the proxy forwards your paid Command Code key upstream and
> accepts any auth token from clients (`proxy-managed`), so it is designed for
Expand Down
19 changes: 0 additions & 19 deletions docker-compose.yml

This file was deleted.

35 changes: 34 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export interface Config {
ccVersion: string;
logLevel: string;
corsOrigin: string;
/** Max wall-clock ms for upstream to send response headers + first byte. */
upstreamTimeoutMs: number;
/** Max ms between consecutive chunks during streaming. 0 = disabled. */
idleTimeoutMs: number;
}

/**
Expand Down Expand Up @@ -86,5 +90,34 @@ export function loadConfig(): Config {
// empty to disable) before exposing the proxy on a network.
const corsOrigin = process.env.CORS_ORIGIN ?? "*";

return { host, port, apiKey, ccApiBase, ccVersion, logLevel, corsOrigin };
// Upstream timeouts. The connection timeout covers the wall-clock time
// until the upstream returns response headers + first byte — bump it for
// slow reasoning models. The idle timeout catches stalled streams where
// the upstream opened the connection but stopped sending chunks
// mid-response (e.g. tool call hung on the upstream side). Set
// CC_IDLE_TIMEOUT_MS=0 to disable idle detection entirely.
const upstreamTimeoutMs = parsePositiveInt(
process.env.CC_UPSTREAM_TIMEOUT_MS,
600_000, // 10 minutes — covers high-effort reasoning models
);
const idleTimeoutMs = parsePositiveInt(process.env.CC_IDLE_TIMEOUT_MS, 120_000); // 2 minutes

return {
host,
port,
apiKey,
ccApiBase,
ccVersion,
logLevel,
corsOrigin,
upstreamTimeoutMs,
idleTimeoutMs,
};
}

function parsePositiveInt(raw: string | undefined, fallback: number): number {
if (raw == null || raw === "") return fallback;
const n = Number(raw);
if (!Number.isFinite(n) || n < 0) return fallback;
return Math.floor(n);
}
Loading
Loading