- Empty model validation: check `model.trim()` before using
- 10MB boundary: use `>=` instead of `>` for consistent messaging
- Timeout clamping: ensure timeout is between 1-600 seconds
- Response stream error: add error handler for network failures
- Empty response validation: check before JSON.parse to prevent crashes
On Windows, bun's global binary symlink may not update properly when
reinstalling the same package. Pre-remove the existing installation
to ensure a clean update, mirroring the dev-install.sh behavior.
Closes#435
Changes ImageAnalysisConfig from providers array to provider_models
mapping for granular vision model control per CLIProxy provider.
Breaking change: config.yaml image_analysis section now uses
provider_models instead of providers/model fields.
Provider-to-model mappings:
- agy → gemini-2.5-flash
- gemini → gemini-2.5-flash
- codex → gpt-5.1-codex-mini
- kiro → kiro-claude-haiku-4-5
- ghcp → claude-haiku-4.5
- claude → claude-haiku-4-5-20251001
Hook checks CCS_CURRENT_PROVIDER against provider_models and skips
if no vision model configured for that provider.
Match websearch transformer format:
- Header: [Image Analysis via CLIProxy]
- Metadata: File name, size in KB, model used
- Separator lines for better readability
- Footer instruction for Claude
Intercept Read tool calls for image/PDF files and route through CLIProxy
with gemini-2.5-flash for vision analysis. Returns text descriptions
instead of blocking, enabling Claude to "see" images via proxy.
Key changes:
- Add image-analyzer-transformer.cjs hook script
- Add ImageAnalysisConfig type and loader
- Add hook installer and profile injector
- Add prompt templates for analysis customization
- Add e2e test suite (excluded from normal CI runs)
- Configure test:e2e script for manual testing
Environment variables:
- CCS_IMAGE_ANALYSIS_ENABLED: Enable/disable (default: 1)
- CCS_IMAGE_ANALYSIS_MODEL: Vision model (default: gemini-2.5-flash)
- CCS_IMAGE_ANALYSIS_TIMEOUT: Timeout in seconds (default: 60)
- CCS_CLIPROXY_API_KEY: API key for CLIProxy auth
- CCS_CLIPROXY_PORT: CLIProxy port (default: 8317)
Closes#426
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
- Read ANTHROPIC_MODEL from profile settings instead of hardcoding
- Display model name in full uppercase (GLM-4.7, not Glm-4.7)
- Add null/undefined guard to getModelDisplayName
- Remove hardcoded GLM-4.6/GLM-4.6 (Thinking) display names
Closes#431
Match WebSearch hook pattern:
- ENABLED by default for settings/cliproxy profiles
- DISABLED for native Claude accounts (account/default)
- User can override via config: hooks.block_image_read.enabled: false
This ensures CCS CLI users get context protection out-of-the-box
while native Claude subscription users are unaffected.
Add PreToolUse hook that intercepts Read tool calls on image files
(.png, .jpg, .webp, etc.) and blocks them with helpful message.
This prevents context exhaustion when image generation skills
produce multiple files and the agent tries to read them (each
image can consume 100K+ tokens).
Configuration:
- Enable via config.yaml: hooks.block_image_read.enabled: true
- Or env var: CCS_BLOCK_IMAGE_READ=1
Hook integration:
- lib/hooks/block-image-read.cjs - the hook script
- src/utils/hooks/image-read-block-hook-env.ts - config loader
- Integrated into all spawn locations (ccs.ts, shell-executor,
cliproxy-executor)
Closes#426
Add 17 tests for isCcsWebSearchHook and deduplicateCcsHooks functions
covering Unix/Windows paths, edge cases, and duplicate cleanup.
Also add invariant comment in hook-config.ts.
Addresses code review feedback from PR #424.
Instead of showing "Quota access forbidden" generic error, now shows:
- Antigravity: "403 Forbidden - No Gemini Code Assist access"
- Codex: "403 Forbidden - No quota API access"
Keeps success=false with isForbidden flag so UI can show distinct
"403" badge (similar to Antigravity-Manager) rather than conflating
with 0% exhausted state.
403 ≠ 0% exhausted - they are semantically different:
- 403: Account lacks API access entirely
- 0%: Account has access but quota is used up (shows reset time)
- Create hook-utils.ts with isCcsWebSearchHook() and deduplicateCcsHooks()
- Update profile-hook-injector.ts and hook-config.ts to use shared module
- Combine double writeFileSync into single write in ensureHookConfig()
Addresses code review feedback on PR #420
- 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
- 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
Updated default Claude model IDs from outdated v4 (May 2025) to
current v4.5 versions matching model-catalog.ts:
- ANTHROPIC_MODEL: claude-sonnet-4-5-20250929
- ANTHROPIC_DEFAULT_OPUS_MODEL: claude-opus-4-5-20251101
- ANTHROPIC_DEFAULT_SONNET_MODEL: claude-sonnet-4-5-20250929
- ANTHROPIC_DEFAULT_HAIKU_MODEL: claude-haiku-4-5-20251001
Fixes "unknown provider for model" 400 errors when users add
Claude accounts and switch to Haiku tier.
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