Previously, PUT /api/settings/:profile created a backup on every request
regardless of whether the content actually changed. This led to hundreds
of identical backup files accumulating in ~/.ccs/backups/.
Changes:
- Compare existing content with new content before creating backup
- Reuse computed newContent for atomic write (DRY)
- Make hook injection idempotent by checking content before write
Fixes#433
- Add in-memory quota cache with 2-minute TTL to reduce external API calls
- Add needsReauth flag to CodexQuotaResult and GeminiCliQuotaResult types
- Update quota routes to use caching (codex, gemini, and generic routes)
- Add "Reauth needed" indicator in account-item.tsx with CLI command hint
- Add "Reauth needed" indicator in account-card.tsx for flow visualization
- Cache successful results only (don't cache expired tokens needing reauth)
- add dedicated /quota/codex/:accountId and /quota/gemini/:accountId endpoints
- reorder routes to place specific before generic for correct Express matching
- fix Gemini auth file detection to support new naming format
- handle nested token structure in Gemini auth files
- delete model-alias-config.ts and cliproxy-alias-handler.ts
- simplify sync to use ANTHROPIC_MODEL directly
- remove alias routes, hooks, and UI components
- Reset isSyncing flag in stopAutoSyncWatcher (prevents stale state)
- Validate empty profile names in mapProfileToClaudeKey
- Add whitespace validation in API routes (POST/DELETE /aliases)
- Add Number.isInteger check for port validation
- Wrap response.json() in try-catch for React hooks (handles non-JSON 502)
- add /api/cliproxy/sync endpoints for local sync
- add /api/cliproxy/sync/aliases for model alias management
- add /api/cliproxy/sync/auto-sync for watcher toggle
- separate try-catch for config save vs watcher restart
Fixes remaining edge cases from #382:
- Add anthropic/claude mapping to statsProviderMap in cliproxy-auth-routes
- Add 'claude' case to provider-refreshers switch statement
- Add 'claude' to 4 UI type definitions in api-client.ts
- Add 'claude' to cliproxy-dialog providers array and options
- Add 'claude' to use-cliproxy-auth-flow VALID_PROVIDERS
- Fix wizard index.tsx type cast to include all 8 providers
Closes#382
Replace duplicate hardcoded provider validation arrays across three route files
with a single import from CLIPROXY_PROFILES constant. This DRY fix eliminates
code duplication and ensures provider validation is consistent across all routes.
Files updated:
- account-routes.ts
- cliproxy-auth-routes.ts
- cliproxy-stats-routes.ts
Reduces code by 21 lines while improving maintainability.
Root cause: fetchLatestCliproxyVersion() and checkCliproxyUpdate()
ignored the caller's backend selection, always re-computing from config.
This caused --update to report wrong version when config wasn't synced.
Changes:
- Add optional backend param to fetchLatestCliproxyVersion()
- Add optional backend param to checkCliproxyUpdate()
- Pass effectiveBackend in binary-service.ts calls
- Pass backend in cliproxy-stats-routes.ts web endpoints
Fixes inconsistent version reporting when switching between
CLIProxyAPI (original) and CLIProxyAPIPlus backends.
Root cause: fetchLatestVersion and fetchAllVersions were hardcoded to
CLIProxyAPIPlus repo, ignoring backend selection.
Changes:
- Add getGitHubApiUrls(backend) helper to types.ts
- Make fetchLatestVersion and fetchAllVersions backend-aware
- Make version list cache backend-specific (bin/{backend}/.version-list-cache.json)
- Update /api/cliproxy/versions route to use configured backend
- Allow version management even when proxy not running (ProxyStatusWidget)
- Show settings button in all states for easier access
- Add useUpdateBackend mutation hook that invalidates related queries
- Reduce update-check stale time from 1hr to 5min + enable refetchOnWindowFocus
- Settings proxy page now uses mutation hook for proper query invalidation
- Make all CLIProxy labels dynamic based on backendLabel from API:
- cliproxy-header.tsx: page title
- app-sidebar.tsx: nav item label
- cliproxy-stats-overview.tsx: both offline and running descriptions
- model-preferences-grid.tsx: card description
- settings proxy section: descriptions for local/remote modes
- Fix API route to use DEFAULT_BACKEND constant instead of hardcoded 'plus'
Ensures backend switching in Settings immediately reflects in all CLIProxy pages.
- Add defensive type guard in misc-routes.ts to prevent runtime crash
if malformed tier_defaults object is passed to PUT /api/thinking
- Extract VALID_THINKING_TIERS constant to thinking-validator.ts
to eliminate duplication across validation code
- Export constant from cliproxy barrel file
Addresses P2/P3 items from PR #351 review
- Remove duplicate CLIProxyBackend type from platform-detector.ts (import from types.ts)
- Add warning for invalid --backend CLI value (was silently ignored)
- Show toast notification when backend change blocked by running proxy
- Migrate from deprecated CLIPROXY_FALLBACK_VERSION to getFallbackVersion()
- Add comprehensive JSDoc for backend API endpoints
Add cliproxy.backend config field to choose between CLIProxyAPI (original)
and CLIProxyAPIPlus backends. Includes CLI --backend flag, Dashboard toggle,
and provider validation to block Kiro/ghcp on original backend.
- Add express-rate-limit to restore endpoint (5 req/min)
- Add JSDoc documentation to RestoreMutex class
- Extract magic numbers to named constants in BackupsSection
- Add unit tests for persist-routes.ts (23 tests)
- Add unit tests for BackupsSection component (28 tests)
Addresses PR #339 code review feedback.
- Fix React side effect: move navigate() to useEffect in LoginPage
- Remove misplaced express-rate-limit from ui/package.json
- Add bcrypt hash format validation before bcrypt.compare
- GET /api/thinking returns current config
- PUT /api/thinking updates mode/override/tier_defaults
- validate override bounds and level names
Refs #307
* feat(ci): add AI code review workflow with Claude via CLIProxyAPI
- Self-hosted runner calls CLIProxyAPI at localhost:8317
- Triggers on PR open/update and /review comment
- Uses gemini-claude-opus-4-5-thinking for deep reviews
- Posts summary + inline comments via gh CLI
- Handles self-PR fallback to COMMENT mode
* chore(release): 7.15.0-dev.1 [skip ci]
* refactor(ci): use GitHub App for reviewer identity + new review format
- Posts as ccs-agy-reviewer[bot] via GitHub App token
- New review format: structured markdown with verdict, summary, issues table
- Single PR comment instead of inline comments
- Concise, focused on PR changes only
* chore(release): 7.15.0-dev.2 [skip ci]
* refactor(ci): switch to Claude Code CLI for reviews
- Use claude -p instead of custom TypeScript script
- Auto-install if not present on runner
- CLIProxyAPI via env vars (ANTHROPIC_BASE_URL, ANTHROPIC_MODEL)
- Allowed tools: Read, Glob, Grep
- Max 3 turns for file exploration
* chore(release): 7.15.0-dev.3 [skip ci]
* chore(release): 7.15.0-dev.4 [skip ci]
* feat(ci): add workflow_dispatch for manual review trigger
* chore(release): 7.15.0-dev.5 [skip ci]
* refactor(cliproxy): add faulty version range infrastructure (#289)
* refactor(cliproxy): add faulty version range infrastructure
- Add CLIPROXY_FAULTY_RANGE constant for marking known buggy versions
- Add isVersionFaulty() helper to version-checker.ts
- Update lifecycle.ts to warn users on faulty versions with upgrade suggestion
- Update health checks to distinguish faulty vs experimental versions
- Update stats routes to include faultyRange in API response
- Skip faulty versions when calculating latestStable
Infrastructure ready for future version promotions. Currently:
- v80 and below: stable
- v81+: marked as faulty (context cancellation bugs)
* chore: trigger review
* chore: re-trigger review
* chore: test PR trigger
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- Trim nickname in API route for consistency with CLI
- Block URL-unsafe chars (%, /, &, ?, #) in nickname
- Block reserved patterns (kiro-N, ghcp-N) used by auto-discovery
- Add reload-merge pattern in discovery to reduce race condition
Kiro/GHCP OAuth tokens have empty email field, causing all accounts to
use accountId='default' and overwrite each other. This fix:
- Add PROVIDERS_WITHOUT_EMAIL constant for kiro/ghcp identification
- Require nickname for kiro/ghcp during registration (CLI + web UI)
- Use nickname as accountId instead of email for these providers
- Enforce nickname uniqueness to prevent collisions
- Update discoverExistingAccounts() to generate unique IDs (kiro-1, etc.)
Closes#258, #267
Implements comprehensive version management for CLIProxyAPI Plus:
Backend APIs:
- GET /versions: fetch available versions from GitHub releases
- POST /install: install specific version with force flag for unstable
- POST /restart: restart proxy without version change
Frontend:
- 4-button layout: Restart, Update/Downgrade, Stop, Settings gear
- Collapsible version picker with dropdown + manual input
- Confirmation dialog for unstable versions (>6.6.80)
- Progressive disclosure (version picker hidden by default)
Ref: plans/260105-1250-cliproxy-version-management/
Add version stability warnings to Dashboard API and UI:
- Extend /api/cliproxy/update-check with isStable, maxStableVersion, stabilityMessage
- Health check shows warning status for v81+ installations
- UI header displays version badge with amber warning for unstable
Closes: relates to #269
- Add CLIProxy accounts to GET /api/accounts (was only showing legacy/unified)
- Use unique ID for key to prevent collision between accounts with same nickname
- Skip accounts with missing identifier
- Route set-default to CLIProxy account manager for provider:id format
- Route delete to CLIProxy account manager for provider:id format
* fix(cliproxy): pass variant port to executor for isolation
Variants configured with dedicated ports (8318-8417) were not using
their assigned port. The executor always defaulted to 8317.
Changes:
- Add port field to ProfileDetectionResult interface
- Pass variant.port from profile-detector to ccs.ts
- Forward port to execClaudeWithCLIProxy options
- Update executor priority: CLI flags > variant port > config.yaml > default
Closes#228
* fix(cliproxy): propagate port in unified config and UI preset handlers
Edge case fixes identified in codebase review:
- Unified config variant detection: add settingsPath and port fields
- Provider editor: use variant port in handleApplyPreset/handleCustomPresetApply
- preset-utils: add optional port parameter to applyDefaultPreset()
* chore(release): 7.11.1-dev.1 [skip ci]
* fix(cliproxy): use correct default port (8317) for remote HTTP connections
Root cause: Inconsistent default port logic across code paths.
- Test Connection used 8317 (correct)
- Actual API calls used 80 (wrong)
Changes:
- Add centralized getRemoteDefaultPort() helper in config-generator.ts
- Fix proxy-target-resolver.ts to use shared helper
- Fix rewriteLocalhostUrls() and getRemoteEnvVars() in config-generator.ts
- Update remote-proxy-client.ts to use shared helper (DRY)
Fixes all 3 reported issues:
1. Port empty → now correctly uses :8317 instead of :80
2. BASEURL construction → now includes correct port
3. CLIProxy Plus auth → now fetches from remote on correct port
* chore(release): 7.11.1-dev.2 [skip ci]
* feat(delegation): add Claude Code CLI flag passthrough
Add explicit passthrough support for key Claude Code CLI flags:
- --max-turns: Limit agentic turns (prevents infinite loops)
- --fallback-model: Auto-fallback when model overloaded
- --agents: Dynamic subagent JSON injection
- --betas: Enable experimental features
Maintain extraArgs catch-all for future Claude Code flags.
Update help command with new "Delegation Flags" section.
Closes#89
* test(delegation): add comprehensive CLI flag passthrough tests
Add 45 test cases covering all edge cases for CLI flag passthrough:
- DelegationHandler: timeout/max-turns/fallback-model/agents/betas validation
- HeadlessExecutor: duplicate flag filtering, undefined vs truthy checks
* chore(release): 7.11.1-dev.3 [skip ci]
* fix(ui): enable cancel button during OAuth authentication
Resolves#234 - Cancel button was disabled during authentication flow,
preventing users from canceling the OAuth process.
Changes:
- Add auth-session-manager.ts for tracking active OAuth sessions
- Add POST /cliproxy/auth/:provider/cancel endpoint to abort sessions
- Kill spawned CLIProxy auth process when cancel is triggered
- Enable Cancel button in AddAccountDialog during authentication
- Add cancel support to QuickSetupWizard auth step
- Update useCancelAuth hook to call backend cancel endpoint
* chore(release): 7.11.1-dev.4 [skip ci]
* fix(prompt): add stdin.pause() to prevent process hang after password input
Fixes#236. The password() method called resume() on stdin but never
paused it in cleanup, keeping the event loop alive indefinitely.
* chore(release): 7.11.1-dev.5 [skip ci]
* feat(cliproxy): add --allow-self-signed flag for HTTPS connections (#227)
Previously, allowSelfSigned was hardcoded to true for all HTTPS protocol
connections, forcing use of the native https module which has issues with
Cloudflare-proxied connections causing timeouts.
This change:
- Adds --allow-self-signed CLI flag (default: false)
- Adds CCS_ALLOW_SELF_SIGNED environment variable
- Uses standard fetch API by default for HTTPS (works with valid certs)
- Only uses native https module when --allow-self-signed is specified
Usage:
- For production HTTPS proxies with valid certs: no flag needed
- For dev proxies with self-signed certs: use --allow-self-signed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* chore(release): 7.11.1-dev.6 [skip ci]
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Shun Kakinoki <39187513+shunkakinoki@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ui): validate BASE_URL and AUTH_TOKEN before save
- Add validation in use-provider-editor to block save when required
env vars (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN) are missing
- Show warning banner in raw editor when required fields are absent
- Always apply default preset on account add (not just first account)
This implements defense-in-depth: validation UI prevents confusion,
save-time validation prevents broken configs, auto-preset ensures
new providers start with working configuration.
Fixes#224
* fix: add validation to remaining settings routes and UI hooks
Backend:
- settings-routes.ts: Validate ANTHROPIC_BASE_URL and AUTH_TOKEN on PUT
- profile-routes.ts: Validate baseUrl/apiKey not empty on update
- variant-routes.ts: Require model field for variant creation
Frontend:
- use-profile-editor.ts: Add required field validation + error handling
- use-copilot-config-form.ts: Add required field validation + error handling
Both hooks now expose missingRequiredFields for UI warnings.
Ref #224
* feat(ux): auto-fill missing BASE_URL/AUTH_TOKEN from defaults at runtime
Instead of blocking saves when required env vars are missing, the system now:
- Runtime fills missing values from getClaudeEnvVars() defaults
- Backend returns warning in response (not 400 error)
- UI shows informational toast instead of blocking error
- Yellow warning banner still shown for user awareness
This provides better UX for CLIProxy users - saves always work, and
missing fields automatically use sensible defaults (local proxy URL
and global API key).
* fix(api): validate settings object before write to prevent undefined file content
Add validation to PUT /api/settings/:profile to return 400 if settings
object is undefined/null. Previously JSON.stringify(undefined) would
write literal "undefined" string to settings file.
* fix: add port validation and pre-save warning UI
- Add validatePort() helper (1-65535 range) to config-generator.ts
- Add missing field warning banner to copilot/config-form UI
- Add missing field warning banner to profiles/editor UI
- Wire missingRequiredFields prop through components
Quota fetcher:
- loadCodeAssist headers now match antigravity.go exactly
- fetchAvailableModels uses empty body {} and correct User-Agent
- Prevents accounts being flagged for anomalous requests
Error logs:
- Extract status code from end of log (RESPONSE section)
- Display full model names instead of abbreviated
- Show status badges (500/429/4xx) with color coding
- Add provider icons with white background
- Add quota-fetcher.ts for Google Cloud Code API integration
- Add REST endpoint GET /api/cliproxy/quota/:provider/:accountId
- Add useAccountQuota hook with React Query caching
- Display quota bar in AccountItem with per-model tooltip
- Create reusable Progress component
- Consolidate quota types in api-client.ts