Issue #1161. Sweeps 127 files to import from
src/config/config-loader-facade.ts instead of unified-config-loader or
utils/config-manager directly.
WRITE callers (32 files): replaced raw saveUnifiedConfig /
mutateUnifiedConfig / updateUnifiedConfig calls with the facade's
cache-coherent wrappers saveConfig / mutateConfig / updateConfig. This
fixes a latent stale-cache window where direct writes through the
underlying loader bypassed the facade's memoization.
READ callers (95 files): mechanical import-path migration only —
function names unchanged because the facade re-exports them. No
behavior change.
Also updated:
- tests/unit/utils/browser/browser-setup.test.ts (DI interface rename)
- src/management/checks/image-analysis-check.ts (dynamic import rename)
- src/web-server/health-service.ts (dynamic require rename)
- src/ccs.ts (path prefix fix from sweep script)
After sweep: zero raw write callers remain outside src/config/. Direct
imports of config-manager remain only for symbols not in the facade
(getConfigPath, getCcsDirSource, etc). Behavior unchanged; full suite
passes 1824/1824.
Out of scope: switching loadOrCreateUnifiedConfig() callers to
getCachedConfig() — needs per-callsite cache-safety analysis. Tracked
as follow-up.
Refs #1161
Each target adapter (claude, codex, droid) now emits dispatch on child
spawn and respond on child exit with latencyMs. instance-manager emits
lifecycle events for instance create / start / stop so multi-instance flows
are traceable per requestId.
Refs #1141, #1138
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.
- serialize deleteInstance with the same profile and plugin-layout locks as ensure
- lock non-account marketplace normalization paths and ignore .locks as an instance source
- detach verified shared symlinks when a profile is reopened as bare
- prune stale marketplace entries whose payload directories no longer exist
- add regressions for bare/non-bare transitions and stale registry recovery
- keep bare and non-bare marketplace normalization inside the plugin-layout lock
- warn when malformed registry sources are skipped during reconciliation
- add regression coverage for cross-instance refresh metadata and legacy layout upgrade
- Add --bare flag to `ccs auth create` to skip shared symlinks
(commands/, skills/, agents/, settings.json). Bare profiles are
clean instances without ClaudeKit or other global extensions.
`ccs sync` respects bare flag and skips re-linking.
- Add MCP server sync from global ~/.claude.json to instances.
Claude Code stores MCP config in ~/.claude.json (not settings.json),
which was invisible to CCS profiles using CLAUDE_CONFIG_DIR isolation.
Selective copy of mcpServers key only (not OAuth sessions/caches).
`ccs sync` refreshes MCP servers across all non-bare instances.
Closes#691Closes#692
- Extract shared _resolveCcsDir() to prevent getCcsDir/getCcsDirSource divergence
- Replace all hardcoded ~/.ccs/ and ~/.claude/ in recovery-manager.ts with
dynamic paths from instance properties (ccsDir, claudeDir, sharedDir, etc.)
- Add cloud sync detection for CCS_HOME env var (parity with CCS_DIR/--config-dir)
- Cache getSessionSecretPath() in local var in auth-middleware.ts
- Cache getCacheDir() in local var in disk-cache.ts ensureCacheDir()
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
- Update checkAuthCodePorts() to filter from CLIPROXY_PROFILES
- Update header comment to list all OAuth ports including Claude
- Addresses PR #384 review round 3