- P2: Edit dialog no longer seeds empty model string
Changed `variant.model || ''` to `variant.model ?? undefined`
Added payload filtering to exclude undefined/empty values before API call
Prevents unintended model overwrites when user only changes other fields
- P3: Composite --config guidance now uses variant name
Added profileName to ExecutorConfig interface
Error message now shows correct variant name instead of default tier provider
e.g., "ccs cliproxy edit my-mix" instead of "ccs cliproxy edit gemini"
- P1: Remove premature variant deletion in --force mode
Fix destructive overwrite path - old variant preserved if user
cancels auth or creation fails (createVariant handles overwrite)
- P2: Validate all composite tier providers at runtime
Backend gating now checks all providers in composite, not just
default tier. Prevents kiro/ghcp on non-default tiers bypassing
Plus backend requirement.
- P2: Preserve tier thinking when default tier is off
Early return skipped tier processing when default thinking was
"off". Now uses flag-based approach - only main model skipped,
tier loop continues with per-tier thinking config.
- Add requireAllTiers parameter to validateCompositeTiers (default false)
- POST/create passes true to enforce all 3 tiers required
- PUT/update passes false (default) to allow partial updates
- Guard against null tier values that would throw at runtime
- Add cursor section serialization after copilot, before global_env
- Fixes P1 data loss: cursor settings now persist to config.yaml
- Previously cursor was merged in memory but never written to disk
P1 (Critical): Remote composite execution now correctly uses remote endpoint
- Reorder condition to check useRemoteProxy before isComposite
- Composite variants now work with remote CLIProxy instances
P2a (Medium): Tier deep-merge preserves optional fields during updates
- Use spread merge instead of ?? to preserve fallback/thinking/account
P2b (Medium): API accepts partial tier updates in PUT endpoint
- Skip validation for tiers not present in request
- Aligns with updateCompositeVariant's merge behavior
- Validate fallback doesn't point to same provider+model (circular)
- Reject empty/whitespace model strings in composite tiers
- Add TODO comment for concurrent modification race condition
- Block variant deletion when CLIProxy has active sessions
- Use temp file + rename pattern for atomic settings writes
- Prevents partial writes on crash/interruption
- Continue to remaining providers on auth failure instead of throwing
- Aggregate failures and show summary of succeeded/failed providers
- Improves UX when one provider fails in composite variant
- Add optional chaining for tier access in env-resolver
- Throw error if default tier model missing in env-builder
- Add null checks for composite.tiers in profile-detector
- Allow partial composite updates in PUT endpoint (|| -> &&)
- Map service validation errors to 400 status, not 404
- Widen 4xx regex to cover full 400-499 range
- 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
- 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
- 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
- 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
- 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
- Change /start and /stop to /daemon/start and /daemon/stop matching copilot convention
- Add enabled field to CursorConfig for dashboard toggle parity
- Simplify getCursorConfig() to trust mergeWithDefaults()
- Handle bare 'ccs cursor' to show help instead of reserved-name error
- Thinking config: 24 tests for applyThinkingSuffix, detectTierFromModel,
getThinkingValueForTier, and applyThinkingConfig with compositeTierThinking
- Fallback: 42 tests for isProviderError, detectFailedTier, applyFallback,
and PROVIDER_ERROR_PATTERNS
- Variant service: 9 tests for updateCompositeVariant,
saveCompositeVariantUnified, and listVariantsFromConfig with composite types
MEDIUM fixes:
- Kill orphaned process when health check times out after 30s
- Prevents zombie processes from consuming resources
LOW fixes:
- Return exit code 1 for unknown cursor subcommands (was 0)
- Simplify exit handler dead code branch (else if code !== null → else)
- 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
- Extend create dialog with composite mode toggle and per-tier config tabs
- Add cliproxy-edit-dialog for modifying existing single and composite variants
- Add Edit action and composite type badge to variant table
- Extend API types with composite variant fields
- Update variant routes: GET (composite fields), POST (composite create), PUT (composite update)
- Add PROVIDER_ERROR_PATTERNS for HTTP 4xx/5xx, overloaded, quota, rate limit
- Add detectFailedTier() to identify which composite tier failed from stderr
- Add isProviderError() to distinguish provider failures from normal exits
- Add handleEdit() interactive wizard for modifying existing variants
- Add updateCompositeVariant() to variant-service for partial tier updates
- Route 'edit' subcommand in cliproxy index
- Update help text with edit command documentation
- Export updateCompositeVariant from services index
- 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.
- 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