- enforce strict tool_result ordering and pairing against assistant tool_use ids
- reject tool_result image payloads that cannot map to OpenAI tool messages
- preserve raw tool schemas on the /v1/messages proxy path instead of silently tightening them
- forward Anthropic tool_choice semantics and cover adaptive routing plus upstream payload checks
- capture the resolved local cliproxy config/auth paths before regenerating
routing strategy config
- thread explicit override paths into regenerateConfig so scoped config writes
stay deterministic during the full test suite
- add regression coverage for explicit config path overrides
- skip managed Claude browser attach when the default CCS browser profile
directory has not been created yet
- keep explicit env override flows failing fast so real misconfiguration still
surfaces clearly
- add regression coverage for default and settings-profile launches
- derive repo imports from each test file via file URLs
- avoid hardcoded paths in the repo
- launch child scripts with the current runtime for consistent local and runner behavior
- isolate tokens and session-tracker tests in child processes
- make child scripts resolve repo modules from the test location
- avoid machine-specific paths in the repo
- skip CLIProxy auto-update checks on runtime bootstrap paths
- fail fast when local startup needs a missing binary instead of attempting installs
- add regression coverage for dashboard limited mode and startup test isolation
Claude Code's marketplace auto-update uses a three-step atomic rename:
clone to <name>.staging → rename old dir to <name>.bak → rename staging
to the final name. On Windows, EPERM errors can interrupt the rename-dance
and leave a <name>.staging directory permanently on disk.
CCS scanned physical directories to discover marketplaces, so a lingering
.staging directory was registered as a bare { installLocation } entry in
known_marketplaces.json. Claude Code's Zod schema requires each entry to
also have `source` and `lastUpdated` fields, so the corrupt entry caused
the /plugin command to throw a validation error.
Fix (two layers of defence):
- discoverMarketplaceEntries: skip any directory whose name starts with
'.' or ends with '.staging'. This filters all hidden dirs including
.staging and .bak left behind by interrupted rename operations.
- buildMarketplaceRegistryContent: invert the loop direction. Instead of
iterating discoveredEntries and adding to the registry (which could
introduce bare entries for disk-only directories with no registry
record), iterate the merged registry and only keep entries that also
exist on disk. Disk-only directories are now silently ignored.
Adds two regression tests: one for .staging pollution, one for orphan
registry entries whose physical directory has been removed.