From 8d8d4c248ad890413d5c4e7e72f9f2a16305f74f Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Fri, 19 Dec 2025 02:14:49 -0500 Subject: [PATCH] refactor: rename proxy to cliproxy_server and update API routes --- README.md | 79 +-------------------------- src/config/unified-config-loader.ts | 35 ++++++++---- src/config/unified-config-types.ts | 14 ++--- src/web-server/index.ts | 6 +- src/web-server/routes/proxy-routes.ts | 45 ++++++++------- ui/src/lib/api-client.ts | 20 +++---- ui/src/pages/settings.tsx | 66 ++++++++++++---------- 7 files changed, 104 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index edbc9374..0a6620c7 100644 --- a/README.md +++ b/README.md @@ -195,84 +195,6 @@ Without Developer Mode, CCS falls back to copying directories.
-## Remote Proxy - -Connect to a remote CLIProxyAPI server (Docker, Kubernetes, or another machine) instead of using the local binary. - -### Configuration - -Configure via dashboard (**Settings → Proxy** tab) or `~/.ccs/config.yaml`: - -```yaml -proxy: - remote: - enabled: true - host: "192.168.1.100" # Remote server hostname/IP - port: 8317 # Default CLIProxy port - protocol: http # http or https - auth-token: "" # Optional auth token - fallback: - enabled: true # Fallback to local if remote unreachable - auto-start: true # Auto-start local proxy on fallback - local: - port: 8317 - auto-start: true -``` - -### CLI Flags - -Override config for one-time use: - -| Flag | Description | -|------|-------------| -| `--proxy-host ` | Remote proxy hostname/IP | -| `--proxy-port ` | Proxy port (default: 8317) | -| `--proxy-protocol ` | Protocol: `http` or `https` | -| `--proxy-auth-token ` | Auth token for remote proxy | -| `--local-proxy` | Force local mode, ignore remote config | -| `--remote-only` | Fail if remote unreachable (no fallback) | - -```bash -# One-time remote connection -ccs gemini --proxy-host 192.168.1.100 --proxy-port 8317 - -# Force local mode -ccs gemini --local-proxy - -# Strict remote mode (no fallback) -ccs gemini --proxy-host remote.example.com --remote-only -``` - -### Environment Variables - -For CI/CD and automation: - -| Variable | Description | -|----------|-------------| -| `CCS_PROXY_HOST` | Remote proxy hostname | -| `CCS_PROXY_PORT` | Proxy port | -| `CCS_PROXY_PROTOCOL` | Protocol (`http`/`https`) | -| `CCS_PROXY_AUTH_TOKEN` | Auth token | -| `CCS_PROXY_FALLBACK_ENABLED` | Enable local fallback (`1`/`0`) | - -```bash -# Docker example -export CCS_PROXY_HOST="cliproxy-container" -export CCS_PROXY_PORT="8317" -ccs gemini "implement feature" -``` - -### Priority Resolution - -Configuration sources are merged with this priority (highest first): - -1. **CLI flags** — One-time overrides -2. **Environment variables** — CI/CD automation -3. **config.yaml** — Persistent settings -4. **Defaults** — Local mode, port 8317 - -
- ## WebSearch Third-party profiles (Gemini, Codex, GLM, etc.) cannot use Anthropic's native WebSearch. CCS automatically configures MCP-based web search as a fallback. @@ -321,6 +243,7 @@ See [docs/websearch.md](./docs/websearch.md) for detailed configuration and trou | OAuth Providers | [docs.ccs.kaitran.ca/providers/oauth-providers](https://docs.ccs.kaitran.ca/providers/oauth-providers) | | Multi-Account Claude | [docs.ccs.kaitran.ca/providers/claude-accounts](https://docs.ccs.kaitran.ca/providers/claude-accounts) | | API Profiles | [docs.ccs.kaitran.ca/providers/api-profiles](https://docs.ccs.kaitran.ca/providers/api-profiles) | +| Remote Proxy | [docs.ccs.kaitran.ca/features/remote-proxy](https://docs.ccs.kaitran.ca/features/remote-proxy) | | CLI Reference | [docs.ccs.kaitran.ca/reference/cli-commands](https://docs.ccs.kaitran.ca/reference/cli-commands) | | Architecture | [docs.ccs.kaitran.ca/reference/architecture](https://docs.ccs.kaitran.ca/reference/architecture) | | Troubleshooting | [docs.ccs.kaitran.ca/reference/troubleshooting](https://docs.ccs.kaitran.ca/reference/troubleshooting) | diff --git a/src/config/unified-config-loader.ts b/src/config/unified-config-loader.ts index 2450472a..98c72da1 100644 --- a/src/config/unified-config-loader.ts +++ b/src/config/unified-config-loader.ts @@ -16,7 +16,7 @@ import { UNIFIED_CONFIG_VERSION, DEFAULT_COPILOT_CONFIG, DEFAULT_GLOBAL_ENV, - DEFAULT_PROXY_CONFIG, + DEFAULT_CLIPROXY_SERVER_CONFIG, GlobalEnvConfig, } from './unified-config-types'; import { isUnifiedConfigEnabled } from './feature-flags'; @@ -178,22 +178,33 @@ function mergeWithDefaults(partial: Partial): UnifiedConfig { enabled: partial.global_env?.enabled ?? true, env: partial.global_env?.env ?? { ...DEFAULT_GLOBAL_ENV }, }, - // Proxy config - remote/local CLIProxyAPI settings - proxy: { + // CLIProxy server config - remote/local CLIProxyAPI settings + cliproxy_server: { remote: { - enabled: partial.proxy?.remote?.enabled ?? DEFAULT_PROXY_CONFIG.remote.enabled, - host: partial.proxy?.remote?.host ?? DEFAULT_PROXY_CONFIG.remote.host, - port: partial.proxy?.remote?.port ?? DEFAULT_PROXY_CONFIG.remote.port, - protocol: partial.proxy?.remote?.protocol ?? DEFAULT_PROXY_CONFIG.remote.protocol, - auth_token: partial.proxy?.remote?.auth_token ?? DEFAULT_PROXY_CONFIG.remote.auth_token, + enabled: + partial.cliproxy_server?.remote?.enabled ?? DEFAULT_CLIPROXY_SERVER_CONFIG.remote.enabled, + host: partial.cliproxy_server?.remote?.host ?? DEFAULT_CLIPROXY_SERVER_CONFIG.remote.host, + port: partial.cliproxy_server?.remote?.port ?? DEFAULT_CLIPROXY_SERVER_CONFIG.remote.port, + protocol: + partial.cliproxy_server?.remote?.protocol ?? + DEFAULT_CLIPROXY_SERVER_CONFIG.remote.protocol, + auth_token: + partial.cliproxy_server?.remote?.auth_token ?? + DEFAULT_CLIPROXY_SERVER_CONFIG.remote.auth_token, }, fallback: { - enabled: partial.proxy?.fallback?.enabled ?? DEFAULT_PROXY_CONFIG.fallback.enabled, - auto_start: partial.proxy?.fallback?.auto_start ?? DEFAULT_PROXY_CONFIG.fallback.auto_start, + enabled: + partial.cliproxy_server?.fallback?.enabled ?? + DEFAULT_CLIPROXY_SERVER_CONFIG.fallback.enabled, + auto_start: + partial.cliproxy_server?.fallback?.auto_start ?? + DEFAULT_CLIPROXY_SERVER_CONFIG.fallback.auto_start, }, local: { - port: partial.proxy?.local?.port ?? DEFAULT_PROXY_CONFIG.local.port, - auto_start: partial.proxy?.local?.auto_start ?? DEFAULT_PROXY_CONFIG.local.auto_start, + port: partial.cliproxy_server?.local?.port ?? DEFAULT_CLIPROXY_SERVER_CONFIG.local.port, + auto_start: + partial.cliproxy_server?.local?.auto_start ?? + DEFAULT_CLIPROXY_SERVER_CONFIG.local.auto_start, }, }, }; diff --git a/src/config/unified-config-types.ts b/src/config/unified-config-types.ts index b1bc4252..fcffd26d 100644 --- a/src/config/unified-config-types.ts +++ b/src/config/unified-config-types.ts @@ -224,10 +224,10 @@ export interface ProxyLocalConfig { } /** - * Proxy configuration section. + * CLIProxy server configuration section. * Controls whether CCS uses local or remote CLIProxyAPI instance. */ -export interface ProxyConfig { +export interface CliproxyServerConfig { /** Remote proxy settings */ remote: ProxyRemoteConfig; /** Fallback behavior when remote is unreachable */ @@ -311,8 +311,8 @@ export interface UnifiedConfig { global_env?: GlobalEnvConfig; /** Copilot API configuration (GitHub Copilot proxy) */ copilot?: CopilotConfig; - /** Proxy configuration for remote/local CLIProxyAPI */ - proxy?: ProxyConfig; + /** CLIProxy server configuration for remote/local mode */ + cliproxy_server?: CliproxyServerConfig; } /** @@ -343,10 +343,10 @@ export const DEFAULT_COPILOT_CONFIG: CopilotConfig = { }; /** - * Default proxy configuration. + * Default CLIProxy server configuration. * Local mode by default - remote must be explicitly enabled. */ -export const DEFAULT_PROXY_CONFIG: ProxyConfig = { +export const DEFAULT_CLIPROXY_SERVER_CONFIG: CliproxyServerConfig = { remote: { enabled: false, host: '', @@ -411,7 +411,7 @@ export function createEmptyUnifiedConfig(): UnifiedConfig { env: { ...DEFAULT_GLOBAL_ENV }, }, copilot: { ...DEFAULT_COPILOT_CONFIG }, - proxy: { ...DEFAULT_PROXY_CONFIG }, + cliproxy_server: { ...DEFAULT_CLIPROXY_SERVER_CONFIG }, }; } diff --git a/src/web-server/index.ts b/src/web-server/index.ts index 4464027e..a4de7f80 100644 --- a/src/web-server/index.ts +++ b/src/web-server/index.ts @@ -51,9 +51,9 @@ export async function startServer(options: ServerOptions): Promise { try { const config = await loadOrCreateUnifiedConfig(); - res.json(config.proxy || DEFAULT_PROXY_CONFIG); + res.json(config.cliproxy_server || DEFAULT_CLIPROXY_SERVER_CONFIG); } catch (error) { - console.error('[proxy-routes] Failed to load proxy config:', error); + console.error('[cliproxy-server-routes] Failed to load proxy config:', error); res.status(500).json({ error: 'Failed to load proxy config' }); } }); /** - * PUT /api/proxy - Update proxy configuration + * PUT /api/cliproxy-server - Update proxy configuration */ router.put('/', async (req: Request, res: Response) => { try { const config = await loadOrCreateUnifiedConfig(); - const updates = req.body as Partial; + const updates = req.body as Partial; // Deep merge with defaults and current config - config.proxy = { + config.cliproxy_server = { remote: { - ...DEFAULT_PROXY_CONFIG.remote, - ...config.proxy?.remote, + ...DEFAULT_CLIPROXY_SERVER_CONFIG.remote, + ...config.cliproxy_server?.remote, ...updates.remote, }, fallback: { - ...DEFAULT_PROXY_CONFIG.fallback, - ...config.proxy?.fallback, + ...DEFAULT_CLIPROXY_SERVER_CONFIG.fallback, + ...config.cliproxy_server?.fallback, ...updates.fallback, }, local: { - ...DEFAULT_PROXY_CONFIG.local, - ...config.proxy?.local, + ...DEFAULT_CLIPROXY_SERVER_CONFIG.local, + ...config.cliproxy_server?.local, ...updates.local, }, }; await saveUnifiedConfig(config); - res.json(config.proxy); + res.json(config.cliproxy_server); } catch (error) { - console.error('[proxy-routes] Failed to save proxy config:', error); + console.error('[cliproxy-server-routes] Failed to save proxy config:', error); res.status(500).json({ error: 'Failed to save proxy config' }); } }); /** - * POST /api/proxy/test - Test remote proxy connection + * POST /api/cliproxy-server/test - Test remote proxy connection */ router.post('/test', async (req: Request, res: Response) => { try { @@ -85,7 +88,7 @@ router.post('/test', async (req: Request, res: Response) => { res.json(status); } catch (error) { - console.error('[proxy-routes] Failed to test connection:', error); + console.error('[cliproxy-server-routes] Failed to test connection:', error); res.status(500).json({ error: 'Failed to test connection' }); } }); diff --git a/ui/src/lib/api-client.ts b/ui/src/lib/api-client.ts index 3bb1c87f..4e0f6d21 100644 --- a/ui/src/lib/api-client.ts +++ b/ui/src/lib/api-client.ts @@ -183,8 +183,8 @@ export interface ProxyLocalConfig { auto_start: boolean; } -/** Proxy configuration */ -export interface ProxyConfig { +/** CLIProxy server configuration */ +export interface CliproxyServerConfig { remote: ProxyRemoteConfig; fallback: ProxyFallbackConfig; local: ProxyLocalConfig; @@ -389,13 +389,13 @@ export const api = { method: 'DELETE', }), }, - /** Proxy configuration API */ - proxy: { - /** Get proxy configuration */ - get: () => request('/proxy'), - /** Update proxy configuration */ - update: (config: Partial) => - request('/proxy', { + /** CLIProxy server configuration API */ + cliproxyServer: { + /** Get cliproxy server configuration */ + get: () => request('/cliproxy-server'), + /** Update cliproxy server configuration */ + update: (config: Partial) => + request('/cliproxy-server', { method: 'PUT', body: JSON.stringify(config), }), @@ -407,7 +407,7 @@ export const api = { authToken?: string; allowSelfSigned?: boolean; }) => - request('/proxy/test', { + request('/cliproxy-server/test', { method: 'POST', body: JSON.stringify(params), }), diff --git a/ui/src/pages/settings.tsx b/ui/src/pages/settings.tsx index 6f143344..1fdb9138 100644 --- a/ui/src/pages/settings.tsx +++ b/ui/src/pages/settings.tsx @@ -43,7 +43,7 @@ import { } from 'lucide-react'; import { CodeEditor } from '@/components/code-editor'; import { api } from '@/lib/api-client'; -import type { ProxyConfig, RemoteProxyStatus } from '@/lib/api-client'; +import type { CliproxyServerConfig, RemoteProxyStatus } from '@/lib/api-client'; interface ProviderConfig { enabled?: boolean; @@ -117,7 +117,7 @@ export function SettingsPage() { const [newEnvKey, setNewEnvKey] = useState(''); const [newEnvValue, setNewEnvValue] = useState(''); // Proxy state - const [proxyConfig, setProxyConfig] = useState(null); + const [proxyConfig, setCliproxyServerConfig] = useState(null); const [proxyLoading, setProxyLoading] = useState(true); const [proxySaving, setProxySaving] = useState(false); const [proxyError, setProxyError] = useState(null); @@ -131,7 +131,7 @@ export function SettingsPage() { fetchStatus(); fetchRawConfig(); fetchGlobalEnvConfig(); - fetchProxyConfig(); + fetchCliproxyServerConfig(); }, []); // Sync local model inputs when config changes @@ -204,12 +204,12 @@ export function SettingsPage() { } }; - const fetchProxyConfig = async () => { + const fetchCliproxyServerConfig = async () => { try { setProxyLoading(true); setProxyError(null); - const data = await api.proxy.get(); - setProxyConfig(data); + const data = await api.cliproxyServer.get(); + setCliproxyServerConfig(data); } catch (err) { setProxyError((err as Error).message); } finally { @@ -426,7 +426,7 @@ export function SettingsPage() { }; // Proxy functions - const saveProxyConfig = async (updates: Partial) => { + const saveCliproxyServerConfig = async (updates: Partial) => { if (!proxyConfig) return; // Optimistic update @@ -435,15 +435,15 @@ export function SettingsPage() { fallback: { ...proxyConfig.fallback, ...updates.fallback }, local: { ...proxyConfig.local, ...updates.local }, }; - setProxyConfig(optimisticConfig); + setCliproxyServerConfig(optimisticConfig); setTestResult(null); // Clear previous test result on config change try { setProxySaving(true); setProxyError(null); - const data = await api.proxy.update(updates); - setProxyConfig(data); + const data = await api.cliproxyServer.update(updates); + setCliproxyServerConfig(data); setProxySuccess(true); setTimeout(() => setProxySuccess(false), 1500); // Silently refresh raw config @@ -452,7 +452,7 @@ export function SettingsPage() { .then((text) => text && setRawConfig(text)) .catch(() => {}); } catch (err) { - setProxyConfig(proxyConfig); + setCliproxyServerConfig(proxyConfig); setProxyError((err as Error).message); } finally { setProxySaving(false); @@ -473,7 +473,7 @@ export function SettingsPage() { setProxyError(null); setTestResult(null); - const result = await api.proxy.test({ + const result = await api.cliproxyServer.test({ host, port, protocol, @@ -586,9 +586,9 @@ export function SettingsPage() { success={proxySuccess} testResult={testResult} testing={testing} - saveProxyConfig={saveProxyConfig} + saveCliproxyServerConfig={saveCliproxyServerConfig} handleTestConnection={handleTestConnection} - fetchProxyConfig={fetchProxyConfig} + fetchCliproxyServerConfig={fetchCliproxyServerConfig} fetchRawConfig={fetchRawConfig} /> )} @@ -1284,16 +1284,16 @@ function GlobalEnvContent({ // Proxy Tab Content Component interface ProxyContentProps { - config: ProxyConfig | null; + config: CliproxyServerConfig | null; loading: boolean; saving: boolean; error: string | null; success: boolean; testResult: RemoteProxyStatus | null; testing: boolean; - saveProxyConfig: (updates: Partial) => void; + saveCliproxyServerConfig: (updates: Partial) => void; handleTestConnection: () => void; - fetchProxyConfig: () => void; + fetchCliproxyServerConfig: () => void; fetchRawConfig: () => void; } @@ -1305,9 +1305,9 @@ function ProxyContent({ success, testResult, testing, - saveProxyConfig, + saveCliproxyServerConfig, handleTestConnection, - fetchProxyConfig, + fetchCliproxyServerConfig, fetchRawConfig, }: ProxyContentProps) { // Memoized default config to avoid recreation @@ -1359,7 +1359,7 @@ function ProxyContent({ const saveHost = () => { const value = editedHost ?? displayHost; if (value !== config?.remote.host) { - saveProxyConfig({ remote: { ...remoteConfig, host: value } }); + saveCliproxyServerConfig({ remote: { ...remoteConfig, host: value } }); } setEditedHost(null); }; @@ -1367,7 +1367,7 @@ function ProxyContent({ const savePort = () => { const port = parseInt(editedPort ?? displayPort, 10); if (!isNaN(port) && port !== config?.remote.port) { - saveProxyConfig({ remote: { ...remoteConfig, port } }); + saveCliproxyServerConfig({ remote: { ...remoteConfig, port } }); } setEditedPort(null); }; @@ -1375,7 +1375,7 @@ function ProxyContent({ const saveAuthToken = () => { const value = editedAuthToken ?? displayAuthToken; if (value !== config?.remote.auth_token) { - saveProxyConfig({ remote: { ...remoteConfig, auth_token: value } }); + saveCliproxyServerConfig({ remote: { ...remoteConfig, auth_token: value } }); } setEditedAuthToken(null); }; @@ -1383,7 +1383,7 @@ function ProxyContent({ const saveLocalPort = () => { const port = parseInt(editedLocalPort ?? displayLocalPort, 10); if (!isNaN(port) && port !== config?.local.port) { - saveProxyConfig({ local: { ...localConfig, port } }); + saveCliproxyServerConfig({ local: { ...localConfig, port } }); } setEditedLocalPort(null); }; @@ -1426,7 +1426,9 @@ function ProxyContent({
{/* Local Mode Card */}