The auth commands barrel re-exported 4 interface-only symbols (AuthCommandArgs,
ProfileOutput, ListOutput, CommandContext) via a value 'export {}', which bun's
per-file transpile cannot resolve at runtime (the tsc dist elides them, so users
were unaffected). Split them into 'export type {}' so 'bun run dev' / source runs
work.
exitWithError() already prints '[X] <msg>', so the preceding console.log(fail())
calls double-printed every auth error. Remove the redundant logs and fold richer
hints (e.g. --force) into the single exitWithError message. Also make
'auth default' accept a profile registered only in legacy profiles.json under
unified mode.
Epic P4. Migrates plain throw new Error to the typed-error classes in the four
locked subdomains, and makes the taxonomy erasable-syntax-compatible so it can
be adopted across UI-reachable code.
Migration (cliproxy/auth, web-server/routes, auth):
- 21 of 23 throws in the locked subdomains now use typed subclasses
(ProfileError, AuthError, ConfigError, ValidationError, ProviderError).
- Typed adoption in locked subdomains: 0/23 -> 21/23 (91.3%), > 40% target.
- Overall typed adoption: 0.9% -> 8.6%.
- Messages preserved exactly (message-based tests stable). Exit codes now
differentiate via handleError (ProfileError=7, AuthError=4, ConfigError=2,
ProviderError=6). ccs doctor 0/1 contract untouched (outside scope).
Erasable-syntax fix (unblocks the migration in the UI build graph):
- exit-codes.ts: enum ExitCode -> const object + union type (value and type
usage both preserved; no Object.values(ExitCode) consumers).
- error-types.ts: constructor parameter properties -> explicit readonly field
declarations + body assignment.
- The web UI build enforces erasableSyntaxOnly (ui/tsconfig.app.json) and
reaches src/errors via the @shared -> src/auth graph; pre-erasable
error-types blocked the build once profile-registry adopted typed errors.
Compat audit: docs/reports/typed-error-exit-code-compat-audit.md (Q1 resolved:
migrate freely; only documented contract is ccs doctor, which is untouched).
Behavior-lock: src/errors/__tests__/typed-error-migration-exit-codes.test.ts
(taxonomy -> exit-code mapping, instanceof chains, context fields).
validate + validate:ci-parity green (incl. UI build).
- create-command: show the pool onboarding hint only after profile
creation fully succeeds; the pre-create placement burned the
once-per-install dismissal when creation failed or rolled back
- remote env (claude): skip the read-level stale-pin filter once the
migration marker exists - a post-migration pin is user-intentional
(e.g. an explicit --config pick equal to a historical default)
- unified-config loader: document that loadOrCreateUnifiedConfig never
writes to disk, so read paths on legacy installs stay side-effect free
- ccs doctor, native account launch, and ccs auth create now surface a
one-line pool suggestion when >=2 native Claude profiles exist and no
pool is enabled; shared once-per-install dismissal; TTY-gated; hint
failures can never break a launch (guarded, single config read)
- credential import from native profiles evaluated and REJECTED:
refresh tokens are client_id-bound and not replayable cross-client;
pool setup requires fresh OAuth per account (verdict report in plan)
Part of #1464 account pools (phase 5).
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
Emit auth-stage events around OAuth round-trips and profile lookups so auth
flows are traceable end-to-end. Doctor command emits dispatch stages around
each health-check phase for clearer diagnostic logs.
Refs #1141, #1138
Use ComSpec-aware shell selection for escaped wrapper launches.
Apply it to the remaining Windows Claude launch paths.
Rewrite the Codex exec regression test to use scoped spies so the full suite stays isolated.
- extract account resume lane guidance into a dedicated auth helper
- swallow diagnostic failures so account launches still reach execClaude
- add focused tests for the warning success and failure paths
- add runtime-aware resume lane diagnostics and auth backup flows
- warn when account resume uses a different plain ccs continuity lane
- surface lane mismatch guidance in the accounts dashboard, docs, and tests
- 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
- 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
- Fix X-Forwarded-For header spoofing in requireSensitiveLocalAccess (use socket-level address only)
- Add model ID length validation (max 256 chars) in PUT /models/:provider
- Add provider name validation (alphanumeric, max 64 chars) to prevent path traversal
- Add stale entry eviction for unbounded quotaRateLimits Map (>1000 entries)
- Fix concurrent refresh race in usage aggregator (wait for in-flight before forced refresh)
- Sanitize internal URLs/paths from OAuth failure diagnostics
- Add ValidationError class for denylist violations (distinct from system errors)
- Make CLIProxy sync interval configurable via CCS_CLIPROXY_SYNC_INTERVAL env var
- Improve legacy continuity config error logging (unconditional warn)
- Add CACHE_VERSION history comments
- prevent km continuity mappings from affecting kimi cliproxy executions
- apply canonical alias fallback only for settings profile lookups
- add regression test for cross-type alias isolation
- resolve mappings with alias/canonical profile candidates
- fail open when source account initialization errors
- remove metadata touch side effects from inheritance preflight
- add 'kimi' to CLIProxyProvider union type
- register Kimi capabilities (device_code flow, moonshot alias)
- add OAuth config, auth prefixes, type values, channel maps
- add CLIProxy-delegated token refresh for Kimi
- add Kimi model catalog (k2.5, k2-thinking, k2)
- switch base-kimi.settings.json to CLIProxy mode (127.0.0.1:8317)
- update comments removing kimi from settings-based profile mentions
Closes#574
- 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