Commit Graph
443 Commits
Author SHA1 Message Date
kaitranntt ca490a9f4e fix(cliproxy): handle edge cases in thinking validation
- model-catalog: add null guard and trim for modelId lookup
- thinking-validator: add 100 char length limit, accept "8192.0" format
- cliproxy-executor: error on empty --thinking= value
- use-thinking-config: handle HTML error pages, return cleanup fn
2026-01-21 17:52:16 -05:00
kaitranntt 299d96c011 fix(api): add type guard for tier_defaults and extract tiers constant
- 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
2026-01-21 17:39:54 -05:00
kaitranntt 19b7a49eee feat(thinking): improve config validation and codex support
- Add shouldShowWarnings() helper for cleaner warning control
- Improve applyThinkingSuffix() regex for accurate suffix detection
- Fix provider_overrides validation for nested tier structure
- Add thinking section to YAML config export with documentation
- Update UI to clarify codex uses reasoning effort levels
- Remove unused setManualOverride hook
2026-01-21 17:25:33 -05:00
kaitranntt eec44d54e2 feat(cliproxy): add model-specific reasoning effort caps
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
2026-01-21 14:27:46 -05:00
kaitranntt 99d164901e Merge remote-tracking branch 'origin/dev' into feat/thinking-flag
Resolve merge conflicts keeping both features:
- thinking: extended thinking/reasoning budget control
- dashboard_auth: dashboard authentication
- backups: config backups section
2026-01-20 20:19:51 -05:00
kaitranntt a019ed2cf8 fix(cliproxy): address PR review issues for backend selection
- 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
2026-01-18 10:24:53 -05:00
kaitranntt 8ade4a6b26 feat(cliproxy): add backend selection for CLIProxyAPI vs CLIProxyAPIPlus
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.
2026-01-18 10:10:01 -05:00
kaitranntt 504b1b3974 fix: resolve CI test timing and merge conflict with dev
- 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()
2026-01-15 13:39:16 -05:00
Kai (Tam Nhu) TranandGitHub 126b244b36 Merge pull request #338 from kaitranntt/kai/fix/pause-account-cliproxy-usage
fix(cliproxy): move token files when pausing/resuming accounts
2026-01-15 13:06:50 -05:00
kaitranntt a931bc9745 fix(cliproxy): show clear message for paused accounts in Live Monitor
- 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
2026-01-15 12:57:37 -05:00
kaitranntt 4d31128b63 fix(cliproxy): use sibling auth-paused/ dir to prevent token refresh loops
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/
2026-01-15 12:41:44 -05:00
kaitranntt d87a653195 fix(cliproxy): add try-catch for file operations in pause/resume
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().
2026-01-15 11:50:35 -05:00
kaitranntt bc02ecc94c fix(dashboard): harden projectId handling with edge case fixes
- 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
2026-01-15 11:46:02 -05:00
kaitranntt 36367d49f0 fix(dashboard): update projectId for existing accounts during discovery
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.
2026-01-15 11:22:40 -05:00
kaitranntt ed2ce138e4 feat(dashboard): add project_id display for Antigravity 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.
2026-01-15 10:49:23 -05:00
kaitranntt 7b80dccdd3 fix(persist): add rate limiting, tests, and code quality improvements
- 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.
2026-01-14 17:59:15 -05:00
kaitranntt eee62a46a2 docs: update minimax preset references to 'mm'
Align README and CLI help with actual preset ID.
2026-01-14 17:43:52 -05:00
kaitranntt 623a3146d7 fix(dashboard): resolve 6 critical security and UX edge cases
- TOCTOU symlink attack: use file descriptor for atomic read in persist-routes
- Non-atomic mutex: add RestoreMutex class with Promise queue pattern
- Restore confirmation: add AlertDialog before destructive backup restore
- Sensitive data exposure: sanitize auth_token/management_key in debug console
- Chunk retry: add lazyWithRetry wrapper with exponential backoff (3 retries)
- URL tab case sensitivity: normalize tab param with toLowerCase()
2026-01-14 16:47:11 -05:00
kaitranntt 9d2442f9fa fix(cliproxy): move token files when pausing/resuming accounts
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
2026-01-14 16:01:56 -05:00
kaitranntt 2e45447bb7 fix(dashboard): resolve edge cases in backup restore and settings UI
Backend:
- Add atomic restore with mutex to prevent concurrent corruption
- Implement rollback on failure for backup restore
- Add symlink security validation

Frontend:
- Add 'backups' tab to URL validation in settings hook
- Add error boundary for lazy-loaded settings sections
- Clamp progress bar values to prevent visual bugs
- Add AbortController cleanup to prevent memory leaks
- Fix misleading debug mode description and add actual console logging
2026-01-14 15:42:12 -05:00
kaitranntt bd5e9d2b78 feat(dashboard): implement full parity UX improvements
- Remove 'agy' hardcode from quota hook (multi-provider support)
- Add quota N/A badge with AlertCircle icon for fetch failures
- Add new 'backups' tab to Settings page with Archive icon
- Create BackupsSection component with list/restore UI
- Add persist backend routes (GET /api/persist/backups, POST /api/persist/restore)
- Add debug mode toggle in Settings proxy section (localStorage persisted)

Closes documentation gap for persist command dashboard parity.
2026-01-14 13:52:54 -05:00
Sergey GaluzaandOnSteroids e055890e16 fix: address PR #4 review - HTTPS tests and timeout handling
- 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>
2026-01-14 18:06:58 +01:00
Sergey GaluzaandOnSteroids c3bfa34703 fix: address PR #4 review suggestions
- 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>
2026-01-14 18:06:58 +01:00
9e9cbd4858 feat(cliproxy): add HTTPS tunnel for remote proxy mode (#1)
* 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>
2026-01-14 18:05:49 +01:00
Kai (Tam Nhu) TranandGitHub cc83b596fb Merge pull request #331 from kaitranntt/fix/quota-fix
fix(cliproxy): return null for unknown quota, add verbose diagnostics
2026-01-14 11:38:31 -05:00
kaitranntt 04c9b087ca fix(cliproxy): address PR review feedback
- 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)
2026-01-14 10:49:47 -05:00
kaitranntt 1ac19415ce fix(cliproxy): return null for unknown quota, add verbose diagnostics
- 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
2026-01-14 10:19:27 -05:00
Kai (Tam Nhu) TranandGitHub 397331ec89 fix(persist): harden security and edge case handling (#328)
Security fixes:
- Add fs.chmodSync(backupPath, 0o600) after backup creation
- Add symlink detection (isSymlink helper) before all file operations
- Reject symlinks in write, backup, and restore operations

Edge case fixes:
- Handle empty settings.json (0 bytes) gracefully
- Validate parsed JSON is object type (not array/primitive)
- Validate backup JSON integrity before restore
- Show backup path guidance on write failure
- Validate existing env is object before spread

Maintenance:
- Add backup rotation (keep last 10, MAX_BACKUPS constant)
- Add cleanupOldBackups() function

Addresses security findings from PR #312 code review.
2026-01-14 10:06:44 -05:00
Leynier Gutiérrez Gonzálezandkaitranntt ef7e595b6f feat(persist): add --list-backups and --restore options for backup management
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
2026-01-14 09:27:48 -05:00
kaitranntt a3a167e62a fix(auth): add security hardening per code review
- Add timing-safe username comparison to prevent timing attacks
- Regenerate session on login to prevent session fixation
- Add warning log when session secret persistence fails
2026-01-13 16:23:10 -05:00
kaitranntt 39c1ee2ca0 feat(config): add ccs config auth CLI subcommand
Interactive CLI for managing dashboard authentication:
- ccs config auth setup: Interactive wizard with bcrypt password hashing
- ccs config auth show: Display current auth status and ENV overrides
- ccs config auth disable: Disable auth with confirmation

Follows modular facade pattern from auth-commands.ts.
Uses InteractivePrompt for masked password input.
Includes local documentation at docs/dashboard-auth-cli.md.

Related: #319
2026-01-13 15:13:10 -05:00
kaitranntt 37e3468d4d fix(auth): move redirect to useEffect and validate bcrypt hash format
- 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
2026-01-13 14:43:55 -05:00
kaitranntt 759d43c8f7 Merge remote-tracking branch 'origin/dev' into feat/login-auth 2026-01-13 14:31:01 -05:00
kaitranntt 464b410e8b feat(dashboard): add optional login authentication (#319)
Add session-based username/password auth for CCS dashboard:
- Backend: Express session middleware with bcrypt password verification
- Frontend: React AuthContext, login page, protected routes
- Config: dashboard_auth section in config.yaml + env var overrides
- Security: Rate limiting (5 attempts/15min), persistent session secret
- 16 unit tests for auth middleware

Auth disabled by default for backward compatibility.
2026-01-13 13:27:38 -05:00
kaitranntt 22c7d4a20d feat(doctor): add --help flag with comprehensive command documentation
- 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
2026-01-13 11:43:27 -05:00
kaitranntt 0075248273 fix(delegation): only check profiles defined in config.yaml
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.
2026-01-09 01:13:51 -05:00
kaitranntt f88ad8e781 fix(doctor): use dynamic profile discovery for delegation check
Replace hardcoded ['glm', 'kimi'] list with DelegationValidator.getReadyProfiles()
to detect all configured *.settings.json profiles including mm, or1, g7, etc.
2026-01-09 00:18:35 -05:00
kaitranntt 7c5f36580a docs(cli): add extended thinking section to help
- W3: explain thinking levels (off/auto/low/medium/high/xhigh)

- W3: document supported providers (agy, gemini)
2026-01-08 16:56:31 -05:00
kaitranntt ba19e1fcda fix(api): add optimistic locking for thinking config
- W4: return lastModified on GET /api/thinking

- W4: check mtime on PUT, return 409 on conflict
2026-01-08 16:55:45 -05:00
kaitranntt f7cc9f4653 fix(config): improve YAML error messages and thinking validation
- U3: show line/column/snippet for YAML syntax errors

- W2: warn when thinking: true used instead of object
2026-01-08 16:55:31 -05:00
kaitranntt d5652de634 fix(cliproxy): improve thinking flag validation and warnings
- U1: reject --thinking with no value (show usage hint)

- U2: warn when provider doesn't support thinking budget
2026-01-08 16:55:14 -05:00
kaitranntt 36bcc04133 fix(cliproxy): add case-insensitive model lookup
Normalize model IDs to lowercase for comparison in findModel()
2026-01-08 15:50:05 -05:00
kaitranntt 31b9520d54 fix(api): add override type and provider_overrides validation
- Reject objects/arrays for override field (only string/number)
- Validate provider_overrides keys and values against valid levels
2026-01-08 15:49:26 -05:00
kaitranntt 19e52399fe fix(config): add null guard and document nested paren limitation
- Add optional chaining for tier_defaults to prevent crash
- Document nested parenthesis matching limitation
2026-01-08 15:49:10 -05:00
kaitranntt 3060373797 fix(cli): add --thinking=value format and improve flag handling
- Support --thinking=value in addition to --thinking value
- Warn when multiple --thinking flags detected (uses first)
- Document intentional negative number blocking
2026-01-08 15:48:55 -05:00
kaitranntt 5f8d23c60b fix(cliproxy): add NaN/Infinity and empty string validation
- Add Number.isFinite() check to reject NaN/Infinity budgets
- Add explicit empty string handling before level validation
2026-01-08 15:48:39 -05:00
kaitranntt 9a2598fb61 feat(api): add /api/thinking endpoints for budget config
- GET /api/thinking returns current config

- PUT /api/thinking updates mode/override/tier_defaults

- validate override bounds and level names

Refs #307
2026-01-08 15:19:57 -05:00
kaitranntt 4d361b2ecf feat(cli): add --thinking flag for runtime budget override
- parse --thinking=value from CLI arguments

- pass thinking value to config generator

- update help command with --thinking documentation

Refs #307
2026-01-08 15:19:42 -05:00
kaitranntt 014b5e68b8 feat(cliproxy): inject thinking suffix into model config
- 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
2026-01-08 15:19:15 -05:00
kaitranntt 0c2fd9cf5f feat(config): add ThinkingConfig to unified config
- add ThinkingConfig type with mode/override/tier_defaults

- add getThinkingConfig() and getEffectiveThinkingBudget() helpers

- support auto/off/manual modes with tier-based defaults

Refs #307
2026-01-08 15:19:00 -05:00