Commit Graph
537 Commits
Author SHA1 Message Date
kaitranntt 847aad00fe fix(websearch): add type guards and deduplication for global settings
- Add typeof check before .replace() to prevent crash on non-string commands
- Add isCcsWebSearchHook() and deduplicateCcsHooks() to hook-config.ts
- Fix ensureHookConfig() detection to verify path, not just matcher
- Prevent overwriting user's custom WebSearch hooks
2026-02-02 11:36:48 -05:00
kaitranntt d61c940a08 fix(websearch): normalize Windows path separators in hook detection
On Windows, path.join() produces backslash paths (C:\Users\.ccs\hooks\...)
but detection used forward slashes, causing:
- Failed hook detection on Windows
- Duplicate hooks added on every CCS invocation

Changes:
- Normalize path separators (\ -> /) before matching
- Add deduplicateCcsHooks() to auto-cleanup accumulated duplicates
- Fix affects hasCcsHook(), isCcsWebSearchHook(), removeHookConfig()
2026-02-02 11:18:20 -05:00
kaitranntt 7aaf568c3f fix(cliproxy): load WebSearch hooks via --settings flag
- Add --settings flag to Claude CLI spawn for CLIProxy profiles
- Use getProviderSettingsPath() for hardcoded profiles (agy, gemini, codex, qwen)
- Use cfg.customSettingsPath for CLIProxy variants (user-defined providers)
- Block user --settings flag to prevent duplicate flags
- Enables WebSearch hooks to load for all CLIProxy profiles

Closes #412
2026-02-01 02:47:15 -05:00
kaitranntt a8b054781f fix(sync): prevent duplicate backup folders on Windows
On Windows, symlinks often fail so copyFallback() copies directories instead.
Previously, subsequent `ccs sync` runs would see the copied folder, fail the
isOurSymlink() check, and create a new .backup-{date} folder every time.

This fix adds Windows copy detection in installItem() before calling backupItem().
When a valid CCS copy is detected, it refreshes the content instead of backing up.

Fixes #409
2026-01-30 09:17:55 -05:00
Kai (Tam Nhu) TranandGitHub 7be20765fe Merge pull request #407 from kaitranntt/feat/glmt-rate-limit-resilience
feat(glmt): add rate limit resilience with exponential backoff retry
2026-01-30 08:25:03 -05:00
kaitranntt 62ac3e2ae9 fix(glmt): extract Retry-After from HTTP headers and cap maxRetries
- Extract Retry-After from actual HTTP response headers instead of parsing error messages
- Cap GLMT_MAX_RETRIES at 10 to prevent misconfiguration
- Prefer header-based Retry-After over message parsing (fallback preserved)

Addresses PR review feedback.
2026-01-30 08:14:10 -05:00
kaitranntt 67a8e2cefc fix(glmt): add env var validation and max delay cap
- Validate GLMT_MAX_RETRIES and GLMT_RETRY_BASE_DELAY for NaN/negative
- Add 30s max delay cap to prevent excessively long waits

Addresses PR review feedback.
2026-01-30 08:05:38 -05:00
kaitranntt 3afdcea379 feat(glmt): add rate limit resilience with exponential backoff retry
Add retry logic and connection pooling to GLMT proxy for handling Z.AI
429 rate limit errors gracefully.

Changes:
- Add RetryConfig with env vars (GLMT_MAX_RETRIES, GLMT_RETRY_BASE_DELAY, GLMT_DISABLE_RETRY)
- Add exponential backoff with jitter and Retry-After header support
- Add forwardWithRetry() and forwardAndStreamWithRetry() wrappers
- Add HTTPS connection pooling via shared https.Agent
- Add comprehensive unit tests (19 tests covering all scenarios)

Fixes: #402
2026-01-30 07:53:04 -05:00
kaitranntt b39726fc07 fix(update): add line-buffering and unit tests for stderr filter
Address review feedback:
- Add line-buffering to handle chunk splitting edge case
- Add 14 unit tests for stderr filter logic
- Test chunk boundary handling, mixed output, edge cases

Handles case where "npm warn cleanup" could be split across chunks.
2026-01-30 07:43:38 -05:00
kaitranntt c9f8ed1a04 fix(update): filter npm cleanup warnings on Windows
Filter cosmetic EPERM warnings during update on Windows when npm fails
to unlink native module prebuilds (bcrypt.node) due to file locking by
antivirus/indexing services. Update still succeeds - warnings are noise.

Closes #405
2026-01-30 07:35:34 -05:00
kaitranntt 606bb72723 feat(cliproxy): add proactive token refresh for Gemini quota (match AGY pattern)
- Add proactive refresh: refresh token 5min before expiry (not just after)
- Add retry on 401: if API returns 401, refresh token and retry once
- Extract fetchWithAuthData helper to reduce code duplication
- Update UI to show better error messages (no more "via CLI" text)
- Falls back gracefully if proactive refresh fails but token not yet expired
2026-01-29 23:09:47 -05:00
kaitranntt 7947a7ac89 feat(cliproxy): add backend caching and reauth indicator for quota endpoints
- 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)
2026-01-29 23:01:45 -05:00
kaitranntt 2f5a50b801 feat(cliproxy): add Codex/Gemini quota API routes
- 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
2026-01-29 21:50:02 -05:00
kaitranntt 98b7f6f454 fix(cliproxy): address PR #399 review suggestions
- Move require('os') to top-level import
- Add debug logging for log dir creation failures
- Add hash collision detection and warning in ToolNameMapper
- Clarify proxy chain order comments in cliproxy-executor
2026-01-29 17:49:32 -05:00
kaitranntt d86c53146a refactor(cliproxy): address PR review suggestions
- Add hash collision risk note to sanitizer docs (6-char MD5 = ~16M combos)
- Fix VALID_CHARS_REGEX comment to include '/' character
- Use getCcsDir() instead of os.homedir() for log path (CLAUDE.md compliance)
- Add JSDoc for isRecord type guard helper
2026-01-29 17:28:45 -05:00
kaitranntt 4d292c62e4 fix(cliproxy): route proxy logs to file instead of stderr
- Add file-based logging to ~/.ccs/logs/tool-sanitization-proxy.log
- Console output only when CCS_DEBUG=1 (prevents polluting Claude CLI output)
- Fallback to temp directory if logs dir creation fails
- Respects CCS_HOME for test isolation
2026-01-29 17:21:06 -05:00
kaitranntt 63633507d2 feat(cliproxy): add ToolSanitizationProxy for Gemini 64-char limit
Fixes #219 - MCP tool names exceeding Gemini's 64-character limit
now get sanitized automatically.

- Add tool-name-sanitizer: dedupe segments + smart truncate with hash
- Add tool-name-mapper: bidirectional mapping for response restoration
- Add tool-sanitization-proxy: HTTP proxy layer for all CLIProxy providers
- Chain: Claude CLI → ToolSanitizationProxy → [CodexReasoningProxy] → CLIProxy
- Add unit tests for sanitizer and mapper modules
2026-01-29 16:04:17 -05:00
Kai (Tam Nhu) TranandGitHub c046d19687 Merge pull request #396 from kaitranntt/kai/fix/gemini-auth-token-mismatch
fix(cliproxy): read Gemini tokens from CLIProxy auth directory
2026-01-29 15:15:34 -05:00
kaitranntt cddf931fe6 refactor(cliproxy): address code review feedback for token handling
- Remove module-level mutable state (lastTokenSourcePath)
- Add GeminiCredsWithSource interface for explicit source path passing
- Add isValidCliproxyToken() for proper type validation
- Use explicit path comparison instead of .includes('.gemini') heuristic
- Add descriptive comment for directory scan error handling

Addresses review feedback from PR #396
2026-01-29 15:10:20 -05:00
kaitranntt ad8327d17e test(cliproxy): add unit tests for quota fetchers and auth utilities
Add comprehensive unit tests for:
- buildCodexQuotaWindows(): window parsing, clamping, reset time calculation
- buildGeminiCliBuckets(): bucket grouping, model series, token types
- resolveGeminiCliProjectId(): project ID extraction from account field
- sanitizeEmail(): email to filename conversion
- isTokenExpired(): token expiry validation

Also removes unused 'preferred' field from GEMINI_CLI_GROUPS (YAGNI)

39 new tests covering edge cases:
- Percentage clamping (0-100, 0-1)
- Missing/null fields
- camelCase/snake_case API responses
- Empty inputs
- Invalid date strings

Addresses code review feedback on PR #395
2026-01-29 15:01:26 -05:00
kaitranntt 9d96535d28 fix(cliproxy): read Gemini tokens from CLIProxy auth directory
Fixes token mismatch where Gemini auth succeeds but token immediately
expires. The issue was that isAuthenticated() checked CLIProxy auth dir
(~/.ccs/cliproxy/auth/) but ensureGeminiTokenValid() only read from
~/.gemini/oauth_creds.json.

Changes:
- Add readCliproxyGeminiCreds() to read from CLIProxy auth dir first
- Add mapCliproxyToGeminiCreds() to convert CLIProxyAPI format to internal
- Track token source path for correct write-back on refresh
- Add writeCliproxyGeminiCreds() to preserve email/project_id fields
- Fall back to ~/.gemini/oauth_creds.json for backward compatibility

Closes #368
2026-01-29 14:57:05 -05:00
kaitranntt 38ba6a9fea fix(cliproxy): resolve regex escape bug and complete DRY refactor
- Fix regex escape in auth-utils.ts: `\\.` not `\\\\.` (dot matcher)
- Refactor quota-fetcher.ts to import from auth-utils.ts (DRY)
- Remove unused UnifiedQuotaResult type (YAGNI)
- Add maintenance comment to Gemini model groups

Addresses code review feedback on PR #395
2026-01-29 14:55:07 -05:00
kaitranntt e31d00f0b9 refactor(cliproxy): extract shared auth utils and remove unused parameter
- Create auth-utils.ts with sanitizeEmail() and isTokenExpired()
- Remove duplicated functions from quota-fetcher-codex.ts
- Remove duplicated functions from quota-fetcher-gemini-cli.ts
- Remove unused _verbose parameter from displayAntigravityQuotaSection()
- Add descriptive comment to USER_AGENT constant

Addresses code review feedback on PR #395
2026-01-29 14:38:02 -05:00
kaitranntt 30e611fc28 feat(cliproxy): add multi-provider quota display for Codex and Gemini CLI
Add quota fetching for Codex (ChatGPT) and Gemini CLI providers with
unified CLI display. Extends `ccs cliproxy quota` with --provider flag.

New files:
- quota-types.ts: Shared type definitions for multi-provider quota
- quota-fetcher-codex.ts: Fetches from ChatGPT backend API
- quota-fetcher-gemini-cli.ts: Fetches from Google Cloud Code API

Features:
- Parallel quota fetching from all providers
- --provider flag to filter (agy|codex|gemini|all)
- Rate limit windows for Codex (primary/secondary/code review)
- Bucket grouping for Gemini CLI (Flash/Pro series)
- Reset time display with proper formatting

Edge case handling:
- 429 rate limit specific error messages
- Clamp percentages/fractions to valid ranges
- Null/negative reset time guards
- Empty --provider= value validation
2026-01-29 14:27:55 -05:00
kaitranntt d238a5d43a fix(cliproxy): update Claude model catalog to latest CLIProxy models
- Updated claude-opus-4-5-20250220 → claude-opus-4-5-20251101
- Updated claude-sonnet-4-5-20250514 → claude-sonnet-4-5-20250929
- Updated claude-haiku-4-5-20250514 → claude-haiku-4-5-20251001
- Updated default model to claude-sonnet-4-5-20250929
- Updated all preset mappings to use new model IDs

Closes #392
2026-01-29 00:37:31 -05:00
kaitranntt 4967693839 fix(cliproxy): address PR review feedback
- align tier fallback to 'unknown' instead of 'pro' in quota-manager

- update stale comment referencing old allowedTiers approach
2026-01-28 16:41:27 -05:00
kaitranntt de23029b57 fix(cliproxy): use paidTier for account tier detection instead of allowedTiers
- paidTier.id contains actual subscription: g1-ultra-tier or g1-pro-tier

- allowedTiers[isDefault] returns standard-tier for all accounts (not useful)

- mapTierString now correctly parses g1-ultra-tier and g1-pro-tier formats
2026-01-28 15:17:23 -05:00
kaitranntt aeb9abc998 feat(cliproxy): add granular account tier prioritization (ultra/pro/free)
- change AccountTier from binary (free/paid) to granular (ultra/pro/free/unknown)

- update mapTierString() to parse API tier strings correctly

- remove faulty inferTierFromModels() fallback - tier comes only from API

- update default tier_priority config to ['ultra', 'pro', 'free']

- update model catalog tier types and display logic

Closes #387
2026-01-28 15:11:00 -05:00
kaitranntt 6611142dcc test(cliproxy): add management-api-client unit tests
- Add 31 unit tests for fetchLocalSyncStatus, fetchProfiles, and performLocalSync
- Cover success, error, timeout, and network failure scenarios
- Remove unused --force flag from sync handler (YAGNI)
2026-01-28 14:12:42 -05:00
kaitranntt bbad73b554 fix(cliproxy): harden sync against edge cases
Backend:
- Handle config file deletion race condition with try-catch
- Add null check for empty config files in yaml.load()
- Limit profile names to 64 chars, require alphanumeric content
- Add 5s timeout for watcher close() to prevent hangs

Frontend:
- Add 30s fetch timeout with AbortController for sync requests
2026-01-28 13:58:16 -05:00
kaitranntt 4124780ce0 fix(cliproxy): improve sync robustness and consistency
- Add timeout warning in restartAutoSyncWatcher when sync exceeds 10s
- Improve YAML key detection with regex pattern for safer parsing
- Replace --force help with --verbose (no confirmation prompt exists)
- Add force flag parsing for future use
2026-01-28 13:49:46 -05:00
kaitranntt e80d2d2d05 fix(cliproxy): address sync review feedback
- Fix auto_sync JSDoc to say (default: true) matching actual default
- Add unlink event handler for profile deletion sync
- Add debug logging for sync failures in api-command
2026-01-28 13:44:00 -05:00
kaitranntt c3f85bc4a8 fix(cliproxy): correct sync terminology and add unit tests
- Fix "Remote" → "Local" in sync-dialog.tsx and CLI help text
- Add resetWatcherState() export for test cleanup
- Add unit tests for profile-mapper, local-config-sync, auto-sync-watcher
- Remove unused ModelAlias and AliasesResponse types from hooks
2026-01-28 13:26:40 -05:00
kaitranntt 68a63a7768 fix(cliproxy): preserve config comments during sync
- Use section-based replacement instead of full yaml.dump()
- Only update claude-api-key section, keep rest of file intact
- Preserves comments, formatting, and key ordering
2026-01-28 11:57:22 -05:00
kaitranntt 32dbd5e174 refactor(cliproxy): remove model alias functionality
- delete model-alias-config.ts and cliproxy-alias-handler.ts

- simplify sync to use ANTHROPIC_MODEL directly

- remove alias routes, hooks, and UI components
2026-01-28 11:57:22 -05:00
kaitranntt b2ba402d0f feat(cliproxy): auto-sync on profile create 2026-01-28 11:57:22 -05:00
kaitranntt 28b0e89b34 feat(cliproxy): enable auto_sync by default 2026-01-28 11:57:22 -05:00
kaitranntt 9924b2fb25 fix(cliproxy): address edge cases in sync module
- 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)
2026-01-28 11:57:22 -05:00
kaitranntt fc23afdfc7 feat(cliproxy): add auto_sync config option
- export sync module from cliproxy barrel
- add auto_sync field to CLIProxyConfig interface
2026-01-28 11:57:22 -05:00
kaitranntt 56500fee98 feat(cliproxy): add sync API routes
- 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
2026-01-28 11:57:22 -05:00
kaitranntt cb6c21216d feat(cliproxy): add sync and alias CLI commands
- add `ccs cliproxy sync` command for manual sync
- add `ccs cliproxy alias` command for model alias management
- support --dry-run and --verbose flags
- integrate with cliproxy subcommand router
2026-01-28 11:57:22 -05:00
kaitranntt 9de2682062 feat(cliproxy): add local config sync module
- add profile mapper to transform CCS profiles to ClaudeKey format
- add model alias configuration with defaults for glm/kimi/qwen
- add local config sync to write claude-api-key section
- add auto-sync watcher with debouncing for profile changes
- include null config handling and temp file cleanup
2026-01-28 11:57:22 -05:00
kaitranntt 4cc89eaf87 feat(cliproxy): add Management API client for CLIProxy
- add types for ClaudeKey, ClaudeModel, HealthStatus
- add HTTP client for Management API endpoints
- support GET/PUT/PATCH/DELETE operations
2026-01-28 11:57:22 -05:00
kaitranntt c713d48d08 refactor(oauth): derive auth-code providers from OAUTH_FLOW_TYPES (DRY)
- Update checkAuthCodePorts() to filter from CLIPROXY_PROFILES

- Update header comment to list all OAuth ports including Claude

- Addresses PR #384 review round 3
2026-01-27 22:25:31 -05:00
kaitranntt 9fd9395588 refactor(cliproxy): use CLIPROXY_PROFILES for provider arrays (DRY)
- Replace hardcoded arrays in token-manager.ts, token-expiry-checker.ts

- Replace hardcoded arrays in account-manager.ts, oauth-port-diagnostics.ts

- Addresses PR #384 code review feedback
2026-01-27 22:04:46 -05:00
kaitranntt 8017ce8f86 fix(cliproxy): use correct --claude-login flag for Claude OAuth
- CLIProxyAPI expects --claude-login, not --anthropic-login

- Fixes 'CLIProxy auth exited with code 2' error

Closes #382
2026-01-27 21:39:19 -05:00
kaitranntt 4a2abc74ca fix: add claude provider to statsProviderMap, UI types, and provider arrays
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
2026-01-27 21:02:34 -05:00
kaitranntt 9cd9c423e9 fix: replace hardcoded provider validation arrays with CLIPROXY_PROFILES import
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.
2026-01-27 20:50:24 -05:00
kaitranntt 2091a90b77 fix(cliproxy): address PR review feedback
- Remove claude from PLUS_ONLY_PROVIDERS (Claude works with normal CLIProxy too)
- Fix color inconsistency: use #D97757 to match SVG brand color
- Add iflow to checkAuthCodePorts (pre-existing issue, fixed opportunistically)
2026-01-27 20:24:01 -05:00
kaitranntt b385ab131d refactor(cliproxy): reorder providers - Antigravity first, then Claude 2026-01-27 20:17:10 -05:00