- 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
Add maxLevel field to ThinkingSupport interface to cap reasoning
effort at model's maximum supported level. This fixes Issue #344
where gpt-5-mini fails with xhigh reasoning (only supports high).
- Add Codex provider to model catalog with gpt-5.2-codex and gpt-5-mini
- Add capLevelAtMax() and capEffortAtModelMax() for runtime capping
- Update UI presets with new Codex models and tier mappings
- 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.
- Fix connection tracking test: wait for 'close' event instead of only
checking socket.destroyed (more reliable in CI environments)
- Increase timeout from 500ms to 1000ms for CI latency
- Add proper socket cleanup after test
- Merge dev changes: add projectId parameter to registerAccount()
- Check isAccountPaused() before readAuthData() in fetchAccountQuota()
- Return "Account is paused" instead of confusing "Auth file not found"
- Improves UX by explaining why quota fetch fails for paused accounts
CLIProxyAPI's watcher uses filepath.Walk() which recursively scans
all subdirectories of auth/. Moving paused tokens to auth/paused/
subdirectory didn't hide them from CLIProxyAPI, causing token refresh
loops where paused tokens were immediately recreated.
Solution: Use auth-paused/ as a sibling directory instead of auth/paused/
subdirectory. This places paused tokens completely outside CLIProxyAPI's
scan path, preventing token discovery and refresh.
Path change:
- Before: ~/.ccs/cliproxy/auth/paused/
- After: ~/.ccs/cliproxy/auth-paused/
Address PR review feedback:
- Wrap fs.renameSync() in try-catch for pauseAccount/resumeAccount
- Wrap fs.mkdirSync() in try-catch for paused directory creation
- Add idempotent checks (skip if already paused/active)
- Rely on syncRegistryWithTokenFiles() for recovery on failure
Follows same error handling pattern as removeAccount().
- Validate empty string projectId with typeof check and trim()
- Include projectId in registerAccount return value
- Update projectId when changed (not just when missing)
- Add aria-hidden/aria-label for accessibility
- Add max-width + truncate for long projectId overflow
Previously, discoverExistingAccounts skipped existing token files
entirely, so accounts created before the projectId feature never
got their projectId populated from auth files.
Now when a token file is already registered, we still check if
projectId needs to be updated for agy accounts.
Display GCP project_id for Antigravity (agy) accounts in the Dashboard:
- Add projectId field to AccountInfo interface (account-manager.ts)
- Read project_id from auth files when discovering/registering accounts
- Pass projectId through token-manager when registering new accounts
- Add projectId to OAuthAccount type (api-client.ts)
- Add projectId to AccountRow type (auth-monitor/types.ts)
- Display project_id in account-item.tsx with FolderCode icon
- Show N/A warning with amber tooltip if project_id is missing
suggesting user remove and re-add account to fetch it
Note: project_id is read-only and respects privacy mode blur.
- 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.
Pausing an account now physically moves the token file to auth/paused/
subdirectory, preventing CLIProxyAPI from discovering and using it.
Resume moves the file back to auth/ directory.
Changes:
- Add getPausedDir() helper for paused tokens location
- Update pauseAccount() to move token to paused/ subdir
- Update resumeAccount() to move token back to auth/
- Update syncRegistryWithTokenFiles() to check both directories
- Update removeAccount() to clean up from both directories
- Update getAccountTokenPath() to return correct path based on state
Fixes#337
- Fix timeout test to use HTTPS server (tunnel uses https.request)
- Fix timeout event handling - call reject directly instead of relying on destroy error event
- Fix misleading comment in remote-token-uploader (Authorization header, not X-Management-Key)
- Remove unused imports in test files
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
- Fix race condition in start() using Promise instead of boolean flag
- Document that tunnel intentionally doesn't limit response sizes (streaming)
- Improve token upload failure visibility with actionable user message
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
* feat(cliproxy): add HTTPS tunnel for remote proxy mode
Claude Code doesn't support HTTPS in ANTHROPIC_BASE_URL directly (undici
limitation). This adds an HTTP→HTTPS tunnel proxy for remote CLIProxyAPI
connections.
Changes:
- Add HttpsTunnelProxy: local HTTP server tunneling to remote HTTPS
- Add CodexReasoningProxy HTTPS support and path prefix stripping
- Remote mode now uses root paths (/v1/messages) not provider-prefixed
- Add remote token uploader for syncing OAuth tokens to remote server
- Auto-upload tokens after OAuth auth when remote mode is enabled
Flow for remote HTTPS:
Claude CLI → CodexReasoningProxy → HttpsTunnel → Remote HTTPS
Built with [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
* fix: address PR review issues for HTTPS tunnel proxy
- Add connection tracking with activeConnections Set for proper cleanup
- Add port validation after start() to reject port 0
- Add Authorization header fallback injection in buildForwardHeaders()
- Handle client disconnect (premature close) and request errors
- Improve error handling in uploadTokenToRemoteAsync (log instead of silent catch)
- Add comprehensive tests for HttpsTunnelProxy (97% coverage)
- Add integration tests for remote-token-uploader
- Add stripPathPrefix unit tests for remote mode
Built with [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
* fix: bump Node.js engine requirement to >=18.0.0
FormData and Blob APIs used in remote-token-uploader require Node.js 18+.
Addresses coderabbit review comment about Node.js engine compatibility.
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
* fix: address remaining PR suggestions
- Add verbose parameter to registerAccountFromToken for proper propagation
- Improve stripPathPrefix with path normalization (double slashes, leading slash)
- Add edge case tests for path normalization
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
* fix: add timeout to flaky npm CLI tests
Tests 'handles empty arguments gracefully' and 'handles very long argument'
were missing timeout option in execSync, causing occasional timeouts when
bun test's 5000ms limit was reached before CLI completed.
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
* fix: address new PR review feedback
- Add path segment boundary check to prevent partial matches (/codex vs /codextra)
- Add hostname validation in HttpsTunnelProxy constructor
- Add race condition protection with 'starting' flag in start()
- Sanitize error messages (detailed only in verbose mode)
- Update comments for clarity (regex behavior)
- Add comprehensive tests for all edge cases
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
---------
Co-authored-by: OnSteroids <built@onsteroids.ai>
- Pass verbose flag through fetchQuotaWithDedup to fetchAccountQuota
- Change verbose logging from console.log to console.error (stderr)
- Keep quotaPercent optional (semantically correct for cases without quota)
- Change calculateAverageQuota() to return null instead of 100 when no model data
- Update callers to use null coalescing (?? 0) for health check thresholds
- Display "N/A (fetch unavailable)" for null quota values
- Add --verbose flag to quota-related functions for troubleshooting
- Add debug logging: token refresh status, API response, errors
Add backup management functionality to the persist command:
- List available backups with timestamps and dates
- Restore from most recent or specific backup
- Improved error handling for corrupted settings.json
- Updated CLAUDE.md to document the persist command and the exception to the non-invasive constraint
- 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
- Add showHelp() with usage, options, checks, examples, exit codes
- Update handleDoctorCommand to accept args array instead of boolean
- Update ccs.ts to pass restArgs to doctor command
- Add doctor to CLAUDE.md Help Location Reference table
Previously getReadyProfiles() scanned all *.settings.json files,
including orphan files (ghcp, kiro) not in config.yaml.
Now reads from config.yaml:
- profiles section (excluding 'default')
- cliproxy.providers section
Fixes doctor showing 11 profiles instead of configured 9.
Replace hardcoded ['glm', 'kimi'] list with DelegationValidator.getReadyProfiles()
to detect all configured *.settings.json profiles including mm, or1, g7, etc.
- Support --thinking=value in addition to --thinking value
- Warn when multiple --thinking flags detected (uses first)
- Document intentional negative number blocking
- GET /api/thinking returns current config
- PUT /api/thinking updates mode/override/tier_defaults
- validate override bounds and level names
Refs #307
- add getEffectiveThinkingValue() to resolve tier defaults
- append (budget) or (level) suffix to model ID
- validate thinking value against model capabilities
- respect mode: auto uses tier defaults, manual uses override
Refs #307
- add ThinkingConfig type with mode/override/tier_defaults
- add getThinkingConfig() and getEffectiveThinkingBudget() helpers
- support auto/off/manual modes with tier-based defaults
Refs #307