Commit Graph
1134 Commits
Author SHA1 Message Date
kaitrannttandShun Kakinoki 21e819b590 fix(cliproxy): improve skip-local-auth edge case handling
- Validate authToken with trim() to reject whitespace-only values
- Show broken model warning for both remote and local modes
- Add context-aware messaging for remote proxy users
- Add comprehensive test coverage for authToken edge cases:
  - Whitespace-only strings
  - Null values
  - Tabs/newlines
  - Tokens with leading/trailing whitespace

Co-authored-by: Shun Kakinoki <shunkakinoki@gmail.com>
2026-01-26 16:16:23 -05:00
kaitranntt 0216341b2c fix(websearch): stop polluting global ~/.claude/settings.json with hooks
Remove global hook registration from installWebSearchHook() - now only
copies hook file to ~/.ccs/hooks/. Hook registration handled by
ensureProfileHooks() which writes to per-profile settings.

Changes:
- hook-installer.ts: Remove ensureHookConfig() call
- ccs.ts: Remove redundant installWebSearchHook() call
- hook-config.ts: Add getClaudeSettingsPath() for test isolation
2026-01-26 14:51:51 -05:00
kaitranntt fb77d72a30 fix(cliproxy): pin version to 6.7.25, add disable-cooling
- Update fallbackVersion: 6.7.8 → 6.7.25 (original)
- Update fallbackVersion: 6.7.8-0 → 6.7.25-0 (plus)
- Add disable-cooling: true to generated config
- Bump CLIPROXY_CONFIG_VERSION to 5 for regeneration
2026-01-26 14:12:14 -05:00
Shun Kakinoki 1f5d11930e feat: skip local OAuth when using remote proxy with auth token
When --proxy-host and --proxy-auth-token are provided, the remote proxy
handles authentication via its own OAuth sessions. This change skips:

- Local OAuth check/trigger
- Preflight quota check (managed by remote server)
- Model configuration prompts (configured on remote server)
- Broken model warnings (model selection is remote)

This enables headless CI/CD usage without requiring pre-cached
CCS_SESSIONS when a remote proxy with auth token is available.
2026-01-26 16:25:24 +09:00
kaitranntt e98a92fded fix: address PR #373 review feedback
- postuninstall.js: add file logging for debugging on error
- profile-hook-injector.ts: use 'wx' flag for atomic marker creation
- profile-hook-injector.ts: include parse error message in debug log
- install-command.ts: use actual counts for consistent semantics
- Windows tests: align Section 7 with per-profile hook architecture
2026-01-25 22:02:25 -05:00
Kai (Tam Nhu) TranandGitHub 2f66f74ff9 Merge pull request #371 from kaitranntt/kai/fix/uninstall-hooks-cleanup
fix: uninstall hooks cleanup + test isolation
2026-01-25 21:53:00 -05:00
kaitranntt cd7a1121d4 fix: address PR review feedback
- ClaudeSymlinkManager.uninstall() now returns count for accurate reporting
- install-command.ts uses return value instead of always incrementing
- claude-dir-installer.ts uses getCcsHome() directly instead of string manipulation
- Add TODO comments to tests explaining --install is a no-op
2026-01-25 21:50:25 -05:00
kaitranntt 6a2c82917d fix(isolation): add getCcsDir/getCcsHome to more files
Fix test isolation in symlink managers and checkers to prevent tests
from touching user's real ~/.ccs/ and ~/.claude/ directories.

Files fixed:
- src/api/services/profile-writer.ts - use getCcsDir()
- src/management/checks/symlink-check.ts - use functions instead of
  module-level constants
- src/utils/claude-dir-installer.ts - use getCcsDir() for CCS paths
- src/utils/claude-symlink-manager.ts - use getCcsHome()/getCcsDir()
2026-01-25 21:42:17 -05:00
kaitranntt 9b61f5318e fix(isolation): use getCcsDir() for test isolation
Replace os.homedir() with getCcsDir() in 11 source files to ensure
tests don't touch the user's real ~/.ccs/ directory. The getCcsDir()
function from config-manager.ts respects CCS_HOME env var for
test isolation.

Files fixed:
- src/auth/profile-detector.ts
- src/auth/profile-registry.ts
- src/delegation/headless-executor.ts
- src/delegation/session-manager.ts
- src/glmt/glmt-transformer.ts
- src/management/checks/config-check.ts
- src/management/checks/profile-check.ts
- src/management/checks/system-check.ts
- src/management/instance-manager.ts
- src/management/shared-manager.ts
- src/utils/update-checker.ts
2026-01-25 21:38:27 -05:00
kaitranntt a8c46cc8ed fix(config): persist setup_completed flag to YAML file
Critical fix: setup_completed was set in memory but never written to disk.

- Add setup_completed to generateYamlWithComments() for YAML serialization
- Add setup_completed to mergeWithDefaults() to preserve during config merge

Without these changes, the flag was lost on save/reload, causing first-time
notice to reappear.

Addresses critical code review feedback on PR #372.
2026-01-25 21:33:29 -05:00
kaitranntt fca8dbd6cf feat(websearch): inject hooks on profile creation
Add hook injection at profile creation time (not just runtime):
- profile-writer.ts: inject on API profile create/update
- variant-settings.ts: inject on CLIProxy variant create

Hooks now present immediately after profile creation.
2026-01-25 21:31:20 -05:00
kaitranntt 596a9c6843 test(setup): add unit tests for setup_completed flag detection
- Add 3 test cases for setup_completed flag:
  - Detect flag when present and true
  - Treat missing flag as first-time eligible
  - Treat false flag as first-time eligible
- Update JSDoc to document detection priority order

Addresses code review feedback on PR #372.
2026-01-25 21:26:23 -05:00
kaitranntt 85e41a56e9 fix(setup): persist setup_completed flag to prevent repeated first-time notice
After running ccs setup with local proxy mode, the CLI was still showing
the first-time install notice because isFirstTimeInstall() only checked
for user-created content (profiles, accounts, variants, etc.). When user
chose "Local" mode and skipped API profiles, config had empty objects,
causing all checks to return false.

Added setup_completed flag to UnifiedConfig interface and set it to true
when setup wizard completes. isFirstTimeInstall() now checks this flag
first.
2026-01-25 21:21:02 -05:00
kaitranntt 21b18d0c4e refactor(websearch): address PR review recommendations
- Add comment in postuninstall.js explaining intentional os.homedir()
- Fix comment in install-command.ts (doesn't touch global settings.json)
- Consolidate duplicate getCcsHooksDir() - export from hook-config.ts
- Add debug logging to silent catch blocks in profile-hook-injector.ts
2026-01-25 21:13:55 -05:00
kaitranntt b33674b3b2 fix(websearch): use getCcsDir() for test isolation
Ensure all hook-related modules use getCcsDir() from environment.ts
for consistent test isolation. Prevents tests from touching the user's
real ~/.ccs/ directory during test runs.

Changes:
- hook-config.ts: Use getCcsDir() for hookConfigPath
- hook-installer.ts: Use getCcsDir() for HOOK_SOURCE_PATH
- profile-hook-injector.ts: Use getCcsDir() for hook sources
- CLAUDE.md: Add test isolation rules
2026-01-25 21:03:01 -05:00
kaitranntt ba1fb7eeb3 refactor(uninstall): stop modifying global settings.json
- remove removeHookConfig() call from uninstallWebSearchHook()

- add removeMigrationMarker() cleanup

- update postuninstall.js to only clean CCS files

- global ~/.claude/settings.json is never touched
2026-01-25 20:26:27 -05:00
kaitranntt 0099ab5a1c feat(cli): inject hooks into profile settings on launch
- call ensureProfileHooks() before CLIProxy execution

- call ensureProfileHooks() before Copilot execution

- call ensureProfileHooks() before Settings-based execution

- account-based profiles skip (use native WebSearch)
2026-01-25 20:25:01 -05:00
kaitranntt 242ab76453 feat(websearch): add per-profile hook injection module
- ensureProfileHooks() injects hooks into profile settings

- migrateGlobalHook() one-time migration from global settings

- removeMigrationMarker() cleanup for uninstall

- export from barrel files for module access
2026-01-25 20:24:47 -05:00
kaitranntt c44a5c221f feat(cli): implement --uninstall handler
- add handleUninstallCommand() with proper cleanup flow

- remove WebSearch hook (file + settings.json)

- remove symlinks from ~/.claude/

- display summary with removal count

- preserve ~/.ccs/ directory
2026-01-25 20:05:31 -05:00
kaitranntt fc4d987d20 feat(websearch): call removeHookConfig on uninstall
- uninstallWebSearchHook() now calls removeHookConfig()

- ensures settings.json cleanup when hook file is removed
2026-01-25 20:04:04 -05:00
kaitranntt 9159aa52cb feat(websearch): add removeHookConfig function
- add removeHookConfig() to remove CCS hook from settings.json

- only removes hooks matching CCS pattern (.ccs/hooks/websearch-transformer)

- preserves user-defined WebSearch hooks

- cleans up empty hooks object after removal

- export from barrel file

Closes #317
2026-01-25 20:03:52 -05:00
kaitranntt e3920e0776 fix(quota): return exhausted models with resetTime from API
- treat models with resetTime but null/missing remainingFraction as 0%
- matches CLIProxy Management Center behavior
- enables accurate Claude reset time display when quota exhausted
- mark primary models at 0% as exhausted for red styling
2026-01-25 17:34:30 -05:00
kaitranntt 27e8813cae fix(quota): fetch quota for paused accounts + simplify exhausted display
- Remove early return for paused accounts in quota fetcher
- Check both auth/ and auth-paused/ directories when reading auth data
- Allows users to see quota status of paused accounts to know when to unpause
- Remove "Exhausted" text in tooltip, just show 0% in red (saves width)
2026-01-25 17:12:45 -05:00
kaitranntt d1b579ad1b fix(api): add race condition prevention and input validation for account control
- add mutex pattern with providerLocks Map for solo mode

- convert soloAccount to async function

- extract VALID_PROVIDERS constant and isValidProvider helper (DRY)

- allow empty arrays in bulk endpoints (return early success)

- add accountIds string validation (non-empty strings only)
2026-01-24 12:22:49 -05:00
kaitranntt 2a0efbd954 fix(cliproxy): propagate backend parameter to version check functions
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.
2026-01-23 22:56:27 -05:00
kaitrannttandClaude bd343f3f02 fix(glmt): respect user-configured model instead of hardcoding glm-4.6
Root cause: execClaudeWithProxy() was ignoring ANTHROPIC_MODEL from
user settings and always using hardcoded 'glm-4.6'.

Changes:
- Read model from user's settings file in GLMT proxy flow
- Update default model to glm-4.7 in base configs (matches presets)
- Update fallback models in transformer/response-builder

Closes #358

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 17:08:08 -05:00
kaitranntt f0c845c32e fix(cliproxy): use backend-aware labels in error messages and API
- Use checkCliproxyUpdate() in checkLatestVersion() for correct repo
- Dynamic error messages based on backend in service-manager
- Dynamic error messages based on backend in cliproxy-executor
- Generic "CLIProxy" message in oauth-process (no backend context)
2026-01-23 15:37:40 -05:00
kaitranntt 2794a548a5 fix(cliproxy): complete backend switching with proper binary extraction
- Add backend field to BinaryManagerConfig type for installer context
- Thread backend parameter through tar/zip extractors to use correct names
- Delete existing binary before install to prevent mismatched binaries
- Track backend in session metadata for debugging/monitoring
- Validate and preserve backend field in config mergeWithDefaults
- Pass backend to registerSession for session tracking

The core issue was extractors calling getExecutableName() without the
backend parameter, causing it to default to 'plus' regardless of user
selection. This resulted in wrong binaries being extracted/renamed.
2026-01-23 15:17:32 -05:00
kaitranntt 0a1cbcc612 fix(cliproxy): use backend-specific GitHub repos for version fetching
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
2026-01-23 14:55:51 -05:00
kaitranntt a41fd2a093 fix(cliproxy): make version cache backend-specific for proper switching
- Add backend parameter to version cache functions (read/write/path)
- Store cache at bin/{backend}/.version-cache.json instead of shared location
- Pass backend through checkForUpdates() and BinaryManager
- Add refetchType: 'all' to force immediate query refetch on backend change
- Add cliproxy-server-config query invalidation for consistency
2026-01-23 14:40:40 -05:00
kaitranntt 88560c7119 fix(ui): sync backend state across all CLIProxy UI components
- 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.
2026-01-23 13:46:47 -05:00
kaitranntt dad4349994 fix(ui): display dynamic backend label in dashboard
- Add backend/backendLabel fields to CliproxyUpdateCheckResult
- Update proxy-status-widget to show backendLabel from API
- Update cliproxy page header to use backendLabel

Dashboard now shows "CLIProxy" or "CLIProxy Plus" based on configured
backend in config.yaml instead of hardcoded "CLIProxy Plus".
2026-01-23 13:25:24 -05:00
kaitranntt 388ab69a97 fix(cliproxy): complete backend param propagation per code review
- Add backend param to checkLatestVersion()
- Add backend param to isPinned(), getPinned(), clearPin() wrappers
- Use getBackendLabel() consistently in showStatus()

Addresses review feedback from PR #359.
2026-01-23 13:20:31 -05:00
kaitranntt 628148c359 fix(cliproxy): make backend switching work with version pins and status
- Add backend param to isCLIProxyInstalled(), getCLIProxyPath(),
  getInstalledCliproxyVersion(), installCliproxyVersion()
- Update getBinaryStatus() to pass backend to all helper functions
- Add getBackendLabel() helper for dynamic CLI messages
- Replace hardcoded "CLIProxy Plus" strings with dynamic labels
- Pass --backend flag through install/update command handlers
- Import CLIProxyBackend type from types.ts instead of redefining

Setting `cliproxy.backend: original` in config.yaml now correctly
uses the original backend for version pins and binary operations.
2026-01-23 10:52:01 -05:00
Kai (Tam Nhu) TranandGitHub 4dc6bbaf4c Merge pull request #354 from jellydn/feat/ollama-provider
feat: add Ollama provider support
2026-01-22 15:21:09 -05:00
kaitranntt 8e29c48c6d fix(presets): make requiresApiKey required boolean, add sentinel docs
- Change requiresApiKey from optional to required boolean in CLI
- Add requiresApiKey: true to all existing presets for consistency
- Document 'ollama' placeholder as sentinel value in code comment
- Add trailing newline to ollama.svg
2026-01-22 15:17:06 -05:00
kaitranntt 3ce698c5fe fix(ollama): align property naming and descriptions
- Change CLI noApiKey to requiresApiKey to match UI convention
- Set apiKey='ollama' instead of empty string for local Ollama
- Align ollama-cloud descriptions between CLI/UI
- Keep https://ollama.com endpoint for direct API access
2026-01-22 15:02:49 -05:00
kaitranntt 2b7d18c4c6 feat(ui): add Ollama provider presets to dashboard
- Add ollama (local) and ollama-cloud presets to UI provider-presets.ts
- Update profile-create-dialog to handle requiresApiKey: false
- Show "No API Key Required" info box for local Ollama
- Add --api-key ignored warning to CLI for local Ollama preset
- Add ollama-cloud to CLI help text preset list

Fixes edge cases identified in PR review:
- UI dashboard now has parity with CLI Ollama support
- Conditional API key validation in profile creation form
2026-01-22 14:09:59 -05:00
Huynh Duc DungandClaude dc6977d32e fix(api): skip API key prompt for local Ollama using noApiKey flag
Local Ollama doesn't require an API key, but the CLI was still
prompting for one. This adds a `noApiKey` flag to provider presets
to mark providers that don't need authentication.

- Add `noApiKey?: boolean` property to ProviderPreset interface
- Set `noApiKey: true` for local Ollama (no key needed)
- All other presets unchanged (default to requiring API key)
- Skip API key prompt and show info message when noApiKey is true

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 17:34:12 +08:00
Huynh Duc DungandClaude ef2c8bba12 fix(api): skip API key prompt for local Ollama preset
Local Ollama doesn't require an API key, but the CLI was still
prompting for one. This adds a `requiresApiKey` property to provider
presets to control whether the API key step is required.

- Add `requiresApiKey` property to ProviderPreset interface
- Set `requiresApiKey: false` for local Ollama (no key needed)
- Set `requiresApiKey: true` for OpenRouter and Ollama Cloud
- Skip API key prompt and show info message when not required

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 17:21:50 +08:00
Huynh Duc DungandClaude bd3be23355 feat: add Ollama provider support
Add support for Ollama as a provider in CCS, enabling users to use
local Ollama models (qwen3-coder, gpt-oss:20b, gpt-oss:120b) and
Ollama Cloud models (glm-4.7:cloud, qwen3-coder:480b).

Changes:
- Add base-ollama.settings.json for local Ollama (localhost:11434)
- Add base-ollama-cloud.settings.json for ollama.com cloud API
- Add 'ollama' and 'ollama-cloud' presets to provider-presets.ts
- Update help documentation in api-command.ts and help-command.ts

Usage:
  ccs api create --preset ollama          # Local Ollama
  ccs api create --preset ollama-cloud    # Ollama Cloud

Ref: https://github.com/kaitranntt/ccs/issues/353

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 16:59:23 +08:00
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