Commit Graph
182 Commits
Author SHA1 Message Date
Tam Nhu Tran 1d8d3d7671 chore: sync with dev after PR #527 merge 2026-02-12 11:01:10 +07:00
Tam Nhu Tran bfc9361701 fix(cursor): fix router fall-through, add daemon marker, use random test port
- Route all `ccs cursor *` to handleCursorCommand (no profile-switching)
- Add --ccs-daemon marker to spawned process for stable PID validation
- Use random port in lifecycle integration test to prevent CI conflicts
- Remove unnecessary .toFixed(1) on integer tokenAge
2026-02-12 08:37:01 +07:00
Tam Nhu Tran 760a5c3ca4 fix(cursor): harden stopDaemon PID validation, tighten regex, add lifecycle test
- Validate PID belongs to cursor daemon via /proc before signaling
- Tighten detectProvider regex to avoid over-matching o-prefixed models
- Add integration test for daemon start→health→stop lifecycle
- Add void cast on discarded handleHelp() return value
- Update model catalog date comment
2026-02-12 08:28:32 +07:00
Tam Nhu Tran 934238740e fix(cursor): export missing symbols, eliminate subcommand sync risk, improve tests
- Export detectProvider and formatModelName from barrel index
- Export CURSOR_SUBCOMMANDS from cursor-command.ts, import in ccs.ts
- Use getCcsDir() in tests instead of manual path construction
- Add handleCursorCommand routing test for unknown subcommand
2026-02-12 08:21:39 +07:00
Tam Nhu Tran cda037e7e5 fix(cursor): clean up PID file on startDaemon failure and improve daemon robustness
- Add removePidFile() in safeResolve on failure to prevent stale PIDs
- Only send SIGKILL in stopDaemon if SIGTERM wait loop exhausted
- Check isDaemonRunning before model fetch to avoid 5s timeout
- Add port validation unit tests for startDaemon
2026-02-12 08:11:41 +07:00
Tam Nhu Tran f9834c81c9 fix(cursor): add enabled field to tests, simplify cursor routing
- Add missing enabled field to CursorConfig in test assertions
- Consolidate duplicate dynamic import in ccs.ts cursor routing
2026-02-12 07:55:35 +07:00
Tam Nhu Tran ce1915366d fix(cursor): use stdio ignore, sequential polling, move CursorConfig to types
- Change spawn stdio from piped to 'ignore' preventing buffer deadlock
- Replace setInterval with sequential setTimeout polling
- Fix TOCTOU in SIGKILL escalation (send directly without probing)
- Move CursorConfig interface to types.ts
- Change detectProvider default from 'openai' to 'unknown'
- Remove redundant removePidFile() when PID is null
2026-02-12 07:51:22 +07:00
Tam Nhu Tran 7d4e6d6b65 fix(cursor): add resolve guard, port validation, and daemon tests
- Add double-resolve guard in startDaemon with safeResolve wrapper
- Add port validation (1-65535) before Node.js script interpolation
- Fix misleading comment in stopDaemon (no PID file handling)
- Add getDaemonStatus test for no daemon running case
- Add stopDaemon tests for graceful non-existent PID handling
2026-02-12 04:27:35 +07:00
Tam Nhu Tran b8aaa58d6e fix(cursor): address remaining PR #528 review feedback
- Add comment explaining whitelist merge pattern in PUT /settings
- Add comment for bare 'ccs cursor' fallthrough (differs from copilot)
- Add unit tests for cursor settings routes validation logic
  - Tests for null/non-object/array body rejection
  - Tests for port validation (integer, range 1-65535)
  - Tests for auto_start/ghost_mode boolean validation
  - Tests for whitelist merge (ignores unknown properties)
  - Tests for /settings/raw validation and file operations
  - Tests for mtime conflict detection

All web-server tests pass. Pre-existing test failures unrelated.
2026-02-12 04:17:34 +07:00
Tam Nhu Tran afb5e746b3 fix(cursor): address remaining PR #527 review feedback
- Add SIGKILL escalation in stopDaemon after SIGTERM timeout
- Document router difference between cursor/copilot help behavior
- Fix detectProvider to handle o1/o4 models via regex pattern
- Add fetchModelsFromDaemon fallback test for unreachable daemon
- Update CLAUDE.md help table with cursor command entry
2026-02-12 04:14:28 +07:00
Tam Nhu Tran 9f0ea25448 fix(cursor): address PR #527 review feedback
- Wire cursor command into main router (ccs.ts) following copilot pattern
- Centralize default port (4242) and model (gpt-4.1) as constants
- Remove duplicate types already in cursor-protobuf-schema from dev
- Handle daemon exit code 0 before health check succeeds
- Export PID helpers and model utils for testability
- Add unit tests for cursor-daemon (PID file ops, isDaemonRunning)
- Add unit tests for cursor-models (detectProvider, formatModelName, defaults)
2026-02-12 04:03:01 +07:00
Kai (Tam Nhu) TranandGitHub 5df2965642 Merge pull request #525 from kaitranntt/kai/feat/518-cursor-protobuf-executor
feat(cursor): add ConnectRPC protobuf encoder/decoder and HTTP/2 executor
2026-02-12 03:48:23 +07:00
Tam Nhu Tran c5e8241393 fix(cursor): address fourth-round review feedback for protobuf module 2026-02-12 03:27:58 +07:00
Kai (Tam Nhu) TranandGitHub cb981db356 Merge pull request #526 from kaitranntt/kai/feat/519-cursor-auth-module
feat(cursor): add credential detection, SQLite token extraction, and auth status
2026-02-12 03:16:47 +07:00
Tam Nhu Tran 66a93ee46f fix(cursor): address third-round review feedback for protobuf module
HIGH PRIORITY FIXES:
- Extract shared buffer parsing logic into parseProtobufFrames generator
  method (DRY violation fix) - both JSON and SSE transformers now use
  common frame parsing loop, eliminating ~60% code duplication
- Use COMPRESS_FLAG constants instead of hardcoded 0x01/0x02/0x03 in
  parseConnectRPCFrame for better maintainability

MEDIUM PRIORITY FIXES:
- Return empty buffer on gzip decompression failure (prevents silent
  data corruption) - ALREADY FIXED
- Add debug warning for unknown message roles in convertMessages
- Create GitHub issue #535 for FIELD namespace refactoring follow-up
- Add test coverage: transformProtobufToSSE, error paths, unknown roles

LOW PRIORITY FIXES:
- Rename checksum test to clarify timestamp granularity (~16 min)
- Fix debug log function name in SSE transformer - FIXED BY REFACTOR
- Add comment to TOOL_RESULT_RESULT field documenting future use

All tests pass (1593 pass, 0 fail)
All validation checks pass (typecheck + lint + format + tests)
2026-02-12 03:15:24 +07:00
Tam Nhu Tran a8a68c9599 fix(cursor): address third-round review feedback for auth module 2026-02-12 03:09:35 +07:00
Tam Nhu Tran 3e26dee013 feat(glm): update default model to GLM-5 and fix all GLM pricing
- Update default GLM model from glm-4.7 to glm-5 across configs, presets, help text, and fallbacks
- Add glm-5 pricing entry ($1.00/$3.20 per M tokens, OpenRouter verified)
- Fix incorrect glm-4.7 pricing: $0.60/$2.20 -> $0.40/$1.50 (OpenRouter verified)
- Fix incorrect glm-4.6 pricing: $0.60/$2.20 -> $0.35/$1.50 (OpenRouter verified)
- Fix incorrect glm-4.5 pricing: $0.60/$2.20 -> $0.35/$1.55 (OpenRouter verified)
- Keep all previous GLM model entries for backward compatibility

Closes #532
2026-02-12 01:43:59 +07:00
Tam Nhu Tran e177a4b097 fix(cursor): address second-round review feedback for protobuf module
HIGH Priority:
- Add comprehensive unit tests (27 tests covering encoder, decoder, translator, executor)
  * encodeVarint/decodeVarint round-trip (0, 1, 127, 128, 16383, 0xFFFFFFFF)
  * encodeField/decodeField round-trip (VARINT, LEN string, LEN binary)
  * wrapConnectRPCFrame/parseConnectRPCFrame (compressed/uncompressed)
  * buildCursorRequest message translation (system, user, assistant, tool)
  * generateChecksum header format validation
  * buildHeaders output validation
  * transformProtobufToJSON basic conversion
- Create GitHub issue #531 for true streaming implementation
- Update TODO comment to reference issue #531

MEDIUM Priority:
- Export CursorCredentials from cursor-protobuf-schema.ts
- Add JSDoc grouping comments to FIELD constant for clarity
- Make hardcoded values configurable (CURSOR_CLIENT_VERSION, CURSOR_USER_AGENT)
- Add debug logging to 9 silent catch blocks (respects CCS_DEBUG env var)
- Fix stream check: stream !== false → stream === true

Bug Fixes:
- Fix decodeVarint to return unsigned values (>>> 0)
- Fix test assertion for Response.text() async API
2026-02-12 01:26:47 +07:00
Tam Nhu Tran 84a256d0ac fix(cursor): address second-round review feedback for auth module
- Add comprehensive unit tests for cursor-auth.test.ts
  - validateToken: valid/invalid tokens, short tokens, UUID formats, empty strings
  - extractUserInfo: JWT parsing, email handling, non-JWT tokens, malformed base64
  - saveCredentials/loadCredentials: round-trip, invalid JSON/types, missing fields
  - checkAuthStatus: authenticated/not authenticated, expired tokens, JWT exp, invalid dates
  - deleteCredentials: delete existing/non-existent files, multiple deletes
  - All tests use CCS_HOME env var for isolation, real file I/O, no mocks

- Fix dead try-catch around new Date() in checkAuthStatus()
  - Replace try-catch with isNaN check (new Date('garbage') returns Invalid Date, not throw)
  - Properly handle Invalid Date by checking isNaN(getTime())

- Fix email populated with sub claim in extractUserInfo()
  - Change email: decoded.email || decoded.sub to email: decoded.email || undefined
  - Prevent non-email values (UUIDs) from populating email field

- Add type guards for JSON.parse result in extractUserInfo()
  - Cast to Record<string, unknown> and validate types
  - Use typeof checks for email, userId, exp fields
2026-02-12 01:23:29 +07:00
Tam Nhu Tran 7d049d8f1e fix(cliproxy): address all review feedback (Low + informational)
- Add sync constraint comment on process.exit handler (executor)
- Add TOCTOU race acceptability comment (account-safety)
- Mask email in handleQuotaExhaustion reason string
- Use realistic exhaustion_threshold (5) in test configs
2026-02-12 00:42:54 +07:00
Kai (Tam Nhu) TranandGitHub c6c94a0c1e feat(cliproxy): runtime quota monitoring during active sessions (#529)
* feat(cliproxy): add runtime quota monitoring during active sessions

Adds adaptive background quota polling to detect and respond to quota
exhaustion during active CLIProxy sessions. Prevents rate-limit-driven
account bans by auto-cooling exhausted accounts and switching defaults.

- Adaptive polling: 300s normal, 60s at 20% threshold, stops at 0%
- Stderr warnings at 20%, boxed exhaustion alerts at 0%
- Cooldown + default switch on exhaustion (existing patterns)
- Configurable via quota_management.runtime_monitor in config.yaml
- Timer.unref() prevents blocking process exit
- monitorStopped guard for in-flight poll safety

Closes #524

* fix: address code review feedback (attempt 1/5)

- M1: Round quotaPercent display with Math.round() to avoid ugly floats
- M2: Rename exhaust_threshold -> exhaustion_threshold for consistency
  with existing auto.exhaustion_threshold config field
- M3: Replace async not.toThrow() with direct await assertion pattern

* fix: address code review feedback (attempt 2/5)

- Remove .claude/agent-memory/ from tracking and add to .gitignore
- Unify cooldown_minutes default to 5 (was 10 in runtime_monitor, 5 in auto)
- Add threshold validation in startQuotaMonitor (warn > exhaustion)
- Document intentional post-switch monitoring gap in code comment
2026-02-11 22:50:50 +07:00
Kai (Tam Nhu) TranandGitHub e055dac199 feat(cliproxy): add account safety guards to prevent Google account bans (#516)
* feat(cliproxy): add account safety guards to prevent Google account bans

Implements cross-provider isolation to prevent Google from flagging
concurrent OAuth usage across different client IDs (ref: #509, #512).

Three pillars:
1. Auto-pause enforcement at session launch — conflicting accounts in
   other Google OAuth providers are paused so CLIProxyAPI can't use them,
   restored on session exit with crash recovery via auto-paused.json
2. Ban/disable detection — error responses matching Google ban patterns
   auto-pause the affected account to prevent further damage
3. Cross-provider conflict warnings during OAuth registration

Key design decisions:
- PID-based session tracking for crash recovery (dead PID = restore)
- Timestamp comparison prevents restoring ban-paused accounts on exit
- Schema validation on auto-paused.json prevents corrupted state
- Falls back to warn-only when another session is managing isolation

* fix(cliproxy): address code review feedback (attempt 1/5)

- Re-read auto-paused.json before write in enforceProviderIsolation to
  reduce concurrent write race window
- Use actual email from registry for display instead of raw accountId
- Export maskEmail for testability
- Add 27 unit tests covering ban detection, email masking,
  cross-provider duplicate detection, enforcement lifecycle,
  crash recovery, and timestamp-guarded restore

* fix(cliproxy): address remaining review feedback (attempt 2/5)

- Add handleBanDetection test verifying account pause on ban error
- Add warnCrossProviderDuplicates tests (true/false/non-Google)
- Document PID reuse limitation in isPidAlive JSDoc comment
2026-02-11 19:21:31 +07:00
Kai (Tam Nhu) TranandGitHub 4065399d8a fix(cliproxy): add fork:true for Claude model aliases in config generator (#523)
Config generator now outputs fork:true for Claude model alias entries,
ensuring both upstream (claude-*) and aliased (gemini-claude-*) model
names appear in /v1/models listings. Also preserves fork flag when
parsing user-added aliases during config regeneration.

Bumps config version to v7 to trigger regeneration on next ccs doctor.

Closes #522
2026-02-11 19:04:41 +07:00
Kai (Tam Nhu) TranandGitHub 19de42704f fix(hooks): isolate image type check before error-prone processing (#514)
* fix(hooks): isolate image type check before error-prone processing

Restructure processHook() into two phases so non-image Read calls
never see hook error messages. Phase 1 defensively checks tool name
and file extension, exiting 0 silently on any failure. Phase 2 only
runs for confirmed image/PDF files where errors are relevant.

Closes #511

* fix(hooks): sync image analyzer hook file on every profile launch

Add installImageAnalyzerHook() call to cliproxy executor, matching
the existing installWebSearchHook() pattern. This ensures the .cjs
file in ~/.ccs/hooks/ gets refreshed from the npm package on every
launch, so users receive hook updates after npm update.
2026-02-11 17:48:02 +07:00
Kai (Tam Nhu) TranandGitHub 6afbb72b47 fix(cliproxy): migrate deprecated gemini-claude-* model names to upstream claude-* names (#515)
* fix(cliproxy): migrate deprecated gemini-claude-* model names to upstream claude-* names

CLIProxyAPI registry no longer recognizes the gemini-claude-* prefix convention.
Model names in catalog, base config, and user settings are migrated to upstream
claude-* names. Auto-migration in env-builder rewrites existing user settings on
load and persists the change.

Closes #513

* fix: address code review feedback — sync UI layer and add migration tests

- Sync UI isNativeGeminiModel() with backend (remove gemini-claude- exclusion)
- Update UI model catalog agy entries from gemini-claude-* to claude-*
- Update CI/CD workflow and code-reviewer default model names
- Add unit tests for migrateDeprecatedModelNames() logic
2026-02-11 17:47:37 +07:00
Tam Nhu Tran 0483444864 fix: separate type-only exports and migrate test imports from dist/ to src/
Spinner interface re-exported as value in checks/index.ts caused Bun
runtime crash. Test files importing from dist/ failed without build step.
2026-02-11 14:05:33 +07:00
Kai (Tam Nhu) TranandGitHub 355a127910 Merge pull request #508 from kaitranntt/kai/feat/507-config-dir-override
feat(config): add CCS_DIR env var and --config-dir flag
2026-02-11 12:11:34 +07:00
Kai (Tam Nhu) TranandGitHub 7ec60a5be9 Merge pull request #505 from kaitranntt/kai/feat/503-ccs-env-command
feat(env): add ccs env command for third-party tool integration
2026-02-11 11:30:11 +07:00
Tam Nhu Tran d5abc7d691 fix(config): lazy-evaluate paths, fix TOCTOU, segment-boundary cloud detection
- Convert 4 module-level constants to lazy-evaluated functions to avoid
  import-time caching: openrouter-catalog, aggregator, disk-cache, auth-middleware
- Fix symlink-checks.ts to use ccsDir parameter instead of homedir/.ccs,
  remove unused homedir parameter from checkSettingsSymlinks()
- Replace TOCTOU existsSync+statSync with single statSync in try/catch
  for --config-dir validation in ccs.ts
- Switch detectCloudSyncPath from substring to path-segment-boundary matching
  to prevent false positives (e.g., megauser != MEGA, Dropbox-api != Dropbox)
- Add test for false-positive protection
2026-02-11 11:24:34 +07:00
Tam Nhu Tran 60d6bbd027 fix(config): migrate all hardcoded paths to getCcsDir() and improve validation
- Replace os.homedir() + '.ccs' with getCcsDir() across 14 instances in 13 files:
  version-command, model-config, openrouter-catalog, config-checks, disk-cache,
  aggregator, auth-middleware, shell-completion, shared-manager, recovery-manager,
  auto-repair, delegation-validator, claude-dir-installer, cliproxy executor
- Add isDirectory() validation for --config-dir argument in ccs.ts
- Make detectCloudSyncPath() case-insensitive for cloud provider matching
- Fix help-command.ts to use dynamic dirDisplay for all path references
- Add 5 new tests: setGlobalConfigDir precedence, relative path resolution,
  reset behavior, getCcsDirSource with --config-dir, case-insensitive detection
- Clean up unused os imports after migration
2026-02-11 11:15:08 +07:00
Tam Nhu Tran 7a0e6a4112 feat(config): add CCS_DIR env var and --config-dir flag for config directory override
Allow users to relocate the entire ~/.ccs/ directory via CCS_DIR env var
or --config-dir CLI flag. Precedence: --config-dir > CCS_DIR > CCS_HOME > default.
Includes cloud sync path detection warning and doctor diagnostics.

Closes #507
2026-02-11 10:55:00 +07:00
Tam Nhu Tran 6d9351dcbc fix(env): add missing CLIProxy profiles to bash completion and shell validation
- Add iflow, kiro, ghcp, claude to bash completion env block
- Add --shell flag validation matching --format pattern
- Add backtick injection test case
2026-02-11 10:50:55 +07:00
Tam Nhu Tran 3f5ecd4d69 fix(env): address P1-P3 review items from code review
- P1: Fix bash completion $cliproxy_profiles scoping — inline profiles
  in env block since variable is only defined at COMP_CWORD=1 scope
- P2: Detect account-based profiles and show specific error message
  instead of generic "not found"
- P2: Show `ccs migrate` hint when unified mode is disabled and settings
  profile resolution fails
- P2: transformToOpenAI omits empty entries at transform time instead of
  relying on output filter (removes fragile coupling)
- P3: Add zsh and auto to --shell completions across all 4 shells; map
  --shell zsh to bash in command handler since syntax is identical
- P3: Auto-detect PowerShell from SHELL containing pwsh on non-Windows
- Tests: 33 pass (+1 pwsh detection test, updated transform assertions)
2026-02-11 07:09:58 +07:00
Tam Nhu Tran d5c03d1f2d fix(env): fix fish escaping, profile parsing, and add OPENAI_MODEL mapping
- Fix P0: fish single-quote escaping uses '\'' (end-quote, literal, reopen)
  instead of \' which fish doesn't support inside single-quoted strings
- Fix P0: profile arg parsing now skips flag values via findProfile() so
  `ccs env --format openai gemini` correctly resolves to 'gemini'
- Add OPENAI_MODEL mapping from ANTHROPIC_MODEL in transformToOpenAI
- Add stderr warning when invalid env var keys are silently dropped
- Update --shell help text to mention zsh compatibility
- Add findProfile tests (6) and OPENAI_MODEL omission test
2026-02-11 06:52:21 +07:00
Tam Nhu Tran 44b3152d34 fix(env): address all PR review feedback
- Add settings profiles to zsh env completion (was proxy-only)
- Document intentional ANTHROPIC_MODEL omission in transformToOpenAI
- Use getCcsDir() in error hint instead of hardcoded ~/.ccs/
- Export parseFlag and add 5 unit tests for flag parsing
- Add fish and PowerShell single-quote escaping tests
2026-02-11 06:46:12 +07:00
Tam Nhu Tran a5dc15d174 fix(env): use single quotes to prevent shell injection via eval
Switch formatExportLine from double quotes to single quotes to prevent
shell metacharacter expansion ($(), backticks, etc.) when output is
consumed via eval. Also fix parseFlag to handle values containing =,
remove unused test imports, and add empty-output guard after format
transformation.
2026-02-11 06:26:52 +07:00
Tam Nhu Tran 2e85064b8a feat(env): add ccs env command for third-party tool integration
New `ccs env <profile>` command exports shell-evaluable environment
variables for OpenCode, Cursor, Continue, and other third-party tools.

Supports --format (openai|anthropic|raw) and --shell (auto|bash|fish|
powershell) flags. Auto-detects shell from $SHELL env var.

Closes #503
2026-02-11 02:38:29 +07:00
Tam Nhu Tran dc9b27623b test(utils): add unit tests for killWithEscalation
- Add 7 test cases covering SIGTERM/SIGKILL escalation, timer cleanup,
  default and custom grace periods, and already-exited process edge case
- Add timer.unref() to prevent keeping event loop alive during shutdown
- Add comment explaining 10s grace period in headless-executor timeout
2026-02-11 02:25:10 +07:00
kaitranntt 917f0bbef7 test(cliproxy): add edge case coverage for Gemini schema sanitizer
Add tests for: exclusiveMinimum/exclusiveMaximum/multipleOf stripping,
uniqueItems/contains/additionalItems stripping, writeOnly/definitions
stripping, example with array values, default with complex nested
objects, empty properties/anyOf edge cases.

Fix proxy log message to say "Gemini-unsupported" instead of
"non-standard".
2026-02-07 06:25:29 -05:00
kaitranntt 505d6d0f11 fix(cliproxy): strip Gemini-unsupported schema fields including "examples"
Replace permissive JSON Schema Draft-07 whitelist with strict
Gemini-compatible field set (22 fields). The "examples" field
in Claude Code tool schemas caused 400 errors from Gemini API.

Also strips other unsupported fields: $ref, $defs, oneOf, allOf,
additionalProperties, const, if/then/else, etc.

Safe change — sanitizer only runs for CLIProxy profiles (Gemini,
Codex, Antigravity), never for direct Anthropic API requests.

Closes #155
2026-02-07 06:17:26 -05:00
kaitranntt 152f5432ae refactor(cliproxy): deduplicate message_delta/message_stop in synthetic SSE response
Track hasReceivedMessageDelta and hasReceivedMessageStop in both
streaming paths (pipe-through and SSE-processing). Conditionally
omit these events from buildSyntheticErrorResponse() when upstream
already sent them, preventing protocol violations.

Closes #491
2026-02-07 04:24:54 -05:00
Kai (Tam Nhu) TranandGitHub 43cd19a52b fix(cliproxy): disable 1M extended context for opus 4.6 (256k limit) (#492)
* fix(cliproxy): disable 1M extended context for gemini-claude-opus-4-6-thinking

Antigravity backend only supports 256k context window for this model,
not 1M as previously declared. Set extendedContext: false with TODO
comment for easy re-enable when backend adds support.

Closes #490

* fix(cliproxy): strip [1m] suffix at runtime for models without extended context

Users with existing [1m] in saved agy.settings.json will now have it
automatically stripped at runtime when the model no longer supports
extended context. Prevents misleading context window claims.
2026-02-07 04:19:44 -05:00
Kai (Tam Nhu) TranandGitHub 545c8b9515 fix(cliproxy): guard against empty upstream SSE responses in agy profile (#489)
* fix(cliproxy): guard against empty upstream SSE responses in agy profile

When CLIProxyAPIPlus drops unsigned thinking blocks during sub-agent
execution, the response stream can contain no content_block_start or
message_delta events. This causes Claude Code CLI to crash with
"No assistant message found".

Add empty response detection in the tool sanitization proxy's streaming
handler. Both the pipe-through and SSE-processing paths now track
whether meaningful content was received. If upstream sent data but no
content blocks on a 200 OK, a synthetic minimal valid SSE response is
injected to prevent the client crash and surface a clear error message.

Closes #350

* fix(cliproxy): improve empty response detection and add tests

Address code review findings:
- Remove message_delta from content detection (lifecycle event, not
  content); only content_block_start indicates actual content
- Add try-catch in end handlers to handle client disconnects gracefully
- Add 3 integration tests: empty stream injection, normal stream
  passthrough, 4xx/5xx non-injection

* fix(cliproxy): avoid duplicate message_start in synthetic response

Track whether upstream already sent a message_start event. When
injecting the synthetic error response, omit message_start if upstream
already sent one, preventing duplicate events in the SSE stream.

Addresses PR review feedback from ccs-reviewer[bot].

* test(cliproxy): add SSE processing path and real failure mode tests

Address code review observations:
- Add test exercising SSE processing path (sanitized tool names) for
  empty response detection, ensuring both code paths are covered
- Add test mirroring real failure mode where upstream sends only
  message_start then ends abruptly (no message_delta/message_stop)
- Document duplicate message_start assumption with inline comment
2026-02-07 04:09:30 -05:00
Kai (Tam Nhu) TranGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
b454834175 feat(release): v7.38.0 - Extended Context, Qwen Models, Bug Fixes (#480)
* fix(version): show active config path instead of deprecated config.json

The version command was using deprecated getConfigPath() which always
returned config.json path. Now uses getActiveConfigPath() which shows
config.yaml in unified mode or config.json in legacy mode.

* chore(release): 7.37.1-dev.1 [skip ci]

* fix(ui): use native dynamic import to fix Node 24 ESM/CJS interop

TypeScript compiles import() to require() when targeting CommonJS,
which breaks ESM packages like ora on Node 24. Use new Function()
to create native dynamic import at runtime, bypassing TS transform.

Closes #472

* chore(release): 7.37.1-dev.2 [skip ci]

* fix(env): strip ANTHROPIC_* from account/default profiles

Account and default profiles inherit process.env which may contain
stale ANTHROPIC_BASE_URL from prior CLIProxy sessions. This causes
ConnectionRefused errors when Claude tries to hit an unavailable proxy.

Settings-based profiles already handle this by explicitly injecting
their own ANTHROPIC_* values. This fix applies the same protection
to account/default profiles by stripping ANTHROPIC_* before spawn.

Closes #474

* test(env): add unit tests for stripAnthropicEnv

Address code review feedback from PR #475. Tests cover:
- Removing all ANTHROPIC_* keys
- Preserving non-ANTHROPIC keys
- Empty object handling
- Undefined value preservation
- Case sensitivity (only uppercase ANTHROPIC_)
- All ANTHROPIC_ prefixed variants stripped

* chore(release): 7.37.1-dev.3 [skip ci]

* feat(cliproxy): add extended context support for 1M token window

Add --1m and --no-1m flags to enable/disable 1M token context window.
Uses Claude Code's [1m] suffix mechanism.

Behavior:
- Gemini models: auto-enabled by default
- Claude models: opt-in with --1m flag
- New extendedContext field in model catalog

Also adds Claude Opus 4.6 to model catalog with extended context support.

Closes #103

* feat(ui): add extended context toggle in dashboard model config

- Add ExtendedContextToggle component for 1M token context window
- Add Claude Opus 4.6 (claude-opus-4-6-20260203) to model catalogs
- Mark Gemini and Claude models with extendedContext: true
- Toggle only appears when selected model supports extended context
- Auto-enabled info for native Gemini, opt-in info for Claude

Part of extended context feature implementation for issue #103.

* fix: address code review findings and CI failure

- Fix CI error: add missing 'provider' prop to ModelConfigSection
- Fix case sensitivity in applyExtendedContextSuffix
- Fix whitespace handling in stripModelSuffixes
- Handle --1m=value and --no-1m=value CLI patterns
- Add warning when --1m used on unsupported model
- Sync agy catalog: add extendedContext to gemini-3-pro-preview
- Extract isNativeGeminiModel to shared utility (DRY)
- Add 21 unit tests for extended-context-config

* fix(catalog): rename claude-opus-4-6-20260203 to claude-opus-4-6

* fix(ui): wire extended context toggle through component tree

- Add extendedContextEnabled and toggleExtendedContext to useProviderEditor hook
- Store setting as CCS_EXTENDED_CONTEXT env var in provider settings
- Pass props through provider-editor → model-config-tab → model-config-section
- Update UseProviderEditorReturn type with new properties

* fix(ui): apply [1m] suffix directly to model strings in settings

- Toggle now applies/strips [1m] suffix to all ANTHROPIC_*MODEL env vars
- Extended context detected by checking if any model has [1m] suffix
- Remove legacy CCS_EXTENDED_CONTEXT flag approach
- Add suffix utilities: applyExtendedContextSuffix, stripExtendedContextSuffix
- Raw Configuration now shows actual model values with [1m] suffix

* fix(qwen): update model catalog with correct context windows and tier mappings

- Update context window specs from official Alibaba docs:
  - Qwen3 Coder Plus: 1M context (was 32K)
  - Qwen3 Max: 256K context (flagship)
  - Qwen3 Coder Flash: fast code generation
- Fix preset mappings for Claude tier equivalence:
  - Opus → qwen3-max (flagship 256K)
  - Sonnet → qwen3-coder-plus (balanced 1M)
  - Haiku → qwen3-coder-flash (fast)
- Update provider descriptions to reflect 256K-1M context range
- Add all 7 Qwen models from CLIProxyAPI: qwen3-coder-plus, qwen3-max,
  qwen3-max-preview, qwen3-235b, qwen3-vl-plus, qwen3-coder-flash, qwen3-32b

Closes #478

* fix(ui): only apply [1m] suffix to ANTHROPIC_MODEL, fix toggle refresh

- Only ANTHROPIC_MODEL gets [1m] suffix, not tier mappings
- Strip [1m] when looking up model in catalog to prevent toggle disappearing
- Fix odd page refresh when toggling extended context

* chore(release): 7.37.1-dev.4 [skip ci]

* fix(ui): remove duplicate import in use-provider-editor

* chore: address PR review feedback - sync comment and unused import

* chore(release): 7.37.1-dev.5 [skip ci]

* feat(cliproxy): add Opus 4.6 to Antigravity model catalog (#482)

* feat(cliproxy): add Opus 4.6 to Antigravity model catalog

- Add gemini-claude-opus-4-6-thinking as new default agy model
- Update preset mappings to route opus tier to Opus 4.6
- Bump CLIProxy fallback versions to v6.8.2
- Keep Opus 4.5 as previous flagship option

* fix(cliproxy): include oauth-model-alias in config generation

Root cause: CLIProxy config.yaml was missing Opus 4.6 alias because:
1. CLIProxyPlus startup migration is disabled (intentional)
2. CCS config generator never wrote oauth-model-alias section
3. Existing users with outdated aliases got 502 on Opus 4.6

Fix:
- Add DEFAULT_ANTIGRAVITY_ALIASES to config generator
- Generate oauth-model-alias section in config.yaml template
- Preserve claude-api-key and custom aliases during regeneration
- Bump config version to v6 to trigger auto-regeneration
- Update model catalog tests for new model count

* fix(cliproxy): preserve YAML indentation in extractYamlSection

- Replace .trim() with regex to strip only leading/trailing newlines,
  preserving 2-space indent on claude-api-key children
- Skip standalone comments at col 0 in section boundary detection
- Update stale test description (4 → 5 models)

* chore(release): 7.37.1-dev.6 [skip ci]

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-06 20:28:58 -05:00
kaitranntt 759f289119 fix(cliproxy): fix discoverExistingAccounts test failures
- Skip saving registry when no new accounts discovered (prevents empty
  accounts.json creation for invalid files)
- Skip merging empty provider sections to prevent empty provider entries
- Update test module cache clearing to include new modular submodules
  (accounts/registry, accounts/index) for proper test isolation
2026-02-05 15:09:47 -05:00
kaitranntt 61bc54af05 fix(shell): escape ! for cmd.exe delayed expansion
Adds defensive escaping for exclamation marks in case delayed
expansion is enabled in the user's cmd.exe environment.
2026-02-05 10:45:07 -05:00
kaitranntt 48aa3cca30 test(shell): add unit tests for escapeShellArg
- 11 tests covering Unix and Windows escaping behavior
- Tests for quotes, percent signs, carets, newlines, tabs
- Fixes comment inaccuracy (backslash → doubling)
2026-02-05 10:36:55 -05:00
Kai (Tam Nhu) TranandGitHub f8c179f6da fix(cliproxy): sanitize MCP tool input_schema to remove non-standard properties (#459)
Squash merge PR #459: MCP tool input_schema sanitization

Fixes #456 - Gemini/Vertex APIs reject non-standard JSON Schema properties from MCP tools

Changes:
- Add allowlist-based schema sanitizer for JSON Schema Draft-07 keywords
- Recursive sanitization with circular ref protection and depth limit
- Handle all schema containers: properties, items, additionalProperties, additionalItems, oneOf/anyOf/allOf, not, if/then/else, $defs, definitions, patternProperties, contains, propertyNames, dependencies
- 22 unit tests covering edge cases
- Integrates into ToolSanitizationProxy pipeline before tool name sanitization
2026-02-04 20:19:58 -05:00
kaitranntt 713ee93606 test(cliproxy): add comprehensive proxy support unit tests
Add 34 unit tests covering:
- getProxyUrl: env var precedence (lowercase > uppercase > all_proxy)
- shouldBypassProxy: wildcard, exact match, suffix patterns, case-insensitivity
- getHostname: URL parsing with error handling
- getProxyAgent: proxy creation, NO_PROXY bypass, error handling

Export internal functions via __testExports for testability.
2026-02-04 17:05:24 -05:00
kaitranntt aa83b4db4e test(glmt): increase timeout for retry-logic tests on CI
The GLMT retry logic tests use dynamic imports and GlmtProxy
instantiation which are slower on CI runners than locally.
Increase default timeout from 5s to 30s to prevent flaky failures.
2026-02-04 11:59:34 -05:00