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
Phase 07 of #1162. Splits tool-sanitization + codex-reasoning proxy spawn
out of the orchestrator:
- src/cliproxy/executor/proxy-chain-builder.ts (185 LOC):
buildProxyChain + ProxyChainContext / ProxyChainResult types.
DI escape hatch (_ToolSanitizationProxy / _CodexReasoningProxy) for
testability without refactoring the proxy classes (Bun module cache
blocks mock.module of already-loaded modules).
- 9 unit tests covering codex-only, tool-san only, both-together,
spawn failure swallowing, env propagation.
index.ts: 716 -> 665 LOC (-51). HTTPS tunnel kept inline because
tunnelPort is needed by image-analysis resolution before first-pass
buildClaudeEnvironment — folding it in would also require moving image
analysis. Two-pass buildClaudeEnvironment dance preserved exactly.
Behavior unchanged; full suite passes 1824/1824.
Refs #1162
Phase 06 of #1162. Splits the largest remaining concern out of the
orchestrator into a focused module:
- src/cliproxy/executor/auth-coordinator.ts (397 LOC):
handleLogout, handleImport, resolveSkipLocalAuth, runAntigravityGate,
ensureProviderAuthentication, runPreflightQuotaCheck,
runAccountSafetyGuards, ensureModelConfiguration,
ensureProviderSettingsFile. Preserves load-bearing ordering of
antigravity gate -> auth -> token refresh -> quota check.
- 36 unit tests covering --auth/--logout/--import early exit,
antigravity gate refusal/acceptance, OAuth trigger paths, composite
providers, remote-proxy skipLocalAuth.
index.ts: 895 -> 716 LOC (-179). Behavior unchanged; full suite passes
1824/1824. Module is 397 LOC (over the <200 ideal) — kept whole because
the auth ordering contract should not be split across files.
Refs #1162
Phases 04+05 of #1162. Splits two more concerns out of the orchestrator:
- src/cliproxy/executor/browser-launch-setup.ts (118 LOC):
resolveBrowserLaunchFlags + resolveBrowserRuntime. Encapsulates browser
flag resolution, attach config, blocked-override warning, and runtime
setup including MCP sync.
- src/cliproxy/executor/account-resolution.ts (197 LOC):
resolveRuntimeQuotaMonitorProviders, resolveAccounts (--accounts /
--use / --nickname / OAuth ban-risk warn / default touch),
applyAccountSafetyGuards, touchDefaultAccount.
- New tests: 184 + 430 LOC covering both modules.
index.ts: 1045 -> 895 LOC (-150). resolveRuntimeQuotaMonitorProviders
re-exported from index.ts for __testExports backwards compat. Behavior
unchanged; full suite passes 1824/1824.
Refs #1162
Phase 03 of #1162. Splits proxy + binary resolution out of the orchestrator
into a focused module:
- src/cliproxy/executor/proxy-resolver.ts (196 LOC):
ResolvedProxy + ResolveExecutorProxyContext interfaces, resolveExecutorProxy
function. Encapsulates proxy config resolution, port mutation, remote
reachability check, fallback prompt, local backend selection, and
binary acquisition.
- src/cliproxy/executor/__tests__/proxy-resolver.test.ts: 10 unit tests
covering local/remote/fallback paths.
index.ts: 1168 -> 1045 LOC (-123). Removes 9 now-unused imports. Browser
flag handling intentionally left in index.ts for Phase 04. Behavior
unchanged; full suite passes 1824/1824.
Refs #1162
Phases 01+02 of #1162. Splits executor flag parsing/validation out of the
1428-LOC orchestrator into a focused module:
New files:
- src/cliproxy/executor/arg-parser.ts (~500 LOC):
readOptionValue, hasGitLabTokenLoginFlag, getGitLabTokenLoginFlagName,
CCS_FLAGS + filterCcsFlags, ParsedExecutorFlags + parseExecutorFlags,
validateFlagCombinations (process.exit semantics preserved for parity).
- src/cliproxy/executor/__tests__/arg-parser.test.ts: 45 unit tests.
- src/cliproxy/executor/__tests__/index-characterization.test.ts:
TDD baseline (16 pass + 7 skipped scenarios at the spawn/dynamic-import
boundary; mock simplification deferred to a follow-up phase).
index.ts: 1428 -> 1175 LOC (-253). Re-exports preserved at module bottom
for backwards compatibility. Behavior unchanged; full test suite passes
(1824/1824).
Refs #1162
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
- Stop cleanup interval when all auth sessions are removed (unregister,
cancel, cancelAll) so the Node event loop isn't held alive.
- getActiveSessionForProvider now returns the most recent session by
startedAt instead of the first map entry.
- HTTPS tunnel includes port in Host header when non-443.
forceValidChars() now ensures leading char is letter or underscore
(catches dot, hyphen, colon, slash — not just digits). registerTools()
always registers in mapping so collisions are detected regardless of
tool registration order.
sanitizeToolName() fallback now forces valid characters (replaces
unsupported chars with underscores, ensures leading letter/underscore)
instead of only truncating. registerTools() disambiguates colliding
sanitized names with numeric suffixes so restoreToolUse() always maps
back to the correct original.
- base-config-loader.ts moved from src/cliproxy/ to src/cliproxy/config/,
so __dirname relative path needs one more .. to reach config/ dir
- Update mock.module paths for proxy-detector and routing-strategy
in non-colocated test files
- Add src/**/__tests__/** to tsconfig.json exclude list
- Add ignores pattern for __tests__ in eslint.config.mjs
- Fix ui/src/lib/api-client.ts import path for provider-entitlement-types
- Remove stale build artifacts from ui/src/lib/ and tests/mocks/
The Codex wham/usage API moved GPT-5.3 Codex Spark quota out of
code_review_rate_limit (now null) into a new additional_rate_limits[]
array. Parse the new field and surface it as Spark windows in the quota
view. Adds explicit category/cadence/featureLabel metadata on
CodexQuotaWindow so display logic does not depend on label sniffing.
The legacy label-sniffing path is preserved as a fallback so cached
windows from older versions still render correctly.
Anthropic OAuth usage returns utilization as a percent (0-100) while the
older policy-limits restrictions payload returns a 0-1 ratio. The shared
heuristic "value <= 1 means ratio" misinterpreted percent values like
1.0, rendering 1% Sonnet usage as 100% used. Pass the unit explicitly
from each payload branch so the same boundary value is interpreted
correctly in either format.
Bun's `mock.module()` is process-wide and is NOT undone by `mock.restore()`.
Two test files used module-level mocks that leaked across test runs,
silently breaking unrelated suites that imported the mocked modules
transitively:
- tests/unit/cliproxy/version-checker-stale-cache.test.ts mocked
binary/version-checker, contaminating cliproxy-stats-routes-install
and cliproxy-stats-routes-model-update suites that import a route
module which transitively imports version-checker.
- tests/unit/cliproxy/service-manager-startup.test.ts mocked 8 modules
at top level (binary-manager, stats-fetcher, etc.), contaminating any
later file that imports them.
CI happens to be green because file ordering on the GitHub runner places
victim files BEFORE contaminators in `bun test`. On Linux locally the
order is reversed, producing 6 reproducible test failures on every
`bun run test:fast` run. A change in OS, bun version, or new test files
that import the mocked modules could silently flip the CI runner's
order and surface these failures unexpectedly.
Replaced module-level mocks with explicit dependency-injection seams in
production code, following the existing pattern in version-checker.ts
and version-cache.ts (`fetchJsonFn?`, `fetchLatestVersionFn?`):
- src/cliproxy/types.ts: `BinaryManagerConfig.checkForUpdatesFn` (optional)
- src/cliproxy/binary/lifecycle.ts: route through new fn with default
- src/cliproxy/service-manager.ts: `ensureCliproxyService(deps?)` with
optional `ensureBinaryFn`, `detectRunningProxyFn`,
`configNeedsRegenerationFn`, `withStartupLockFn`
All deps fields are optional with real-implementation defaults, so
production callers are unchanged. Tests now inject deterministic stubs
through call-site parameters instead of module-level mocks.
Verified locally: \`bun run validate\` is now 2540 pass / 0 fail
(previously 2534 pass / 6 fail at the same upstream/main HEAD).
Built [OnSteroids](https://onsteroids.ai)
Add ANTHROPIC_EXTRA_MODELS env var to allow each API profile to
configure additional models alongside the primary ANTHROPIC_MODEL.
These are synced to CLIProxy config.yaml during ccs cliproxy sync.
- profile-mapper.ts: parse ANTHROPIC_EXTRA_MODELS on sync
- profile-writer.ts: write extra models to settings.json
- shared.ts + create-command.ts: --extra-models CLI flag
- profile-routes.ts + route-helpers.ts: REST API support
- profile-dialog.tsx + api-client.ts: frontend input
Anthropic exposes `max` as a distinct adaptive-thinking effort above
`xhigh` on Opus 4.7. Previously the validator aliased user input `max`
down to `xhigh`, so users couldn't reach the real top-tier effort
through CCS.
Extend the validator:
- Add `max` to VALID_THINKING_LEVELS and THINKING_LEVEL_RANK (rank 6,
above xhigh)
- Add `max` to THINKING_LEVEL_BUDGETS (65536, CCS-internal numeric
mapping for closest-level lookups)
- Widen ThinkingSupport.maxLevel union to include 'max'
The existing `max: 'xhigh'` alias in findClosestLevel is kept as a
graceful fallback for models whose levels list does not include `max`
(e.g. Codex `gpt-5.4`), because exact-match on validLevels takes
priority — so Opus 4.7 returns `max` directly while Codex still maps
`max` -> `xhigh`.
Update the claude.claude-opus-4-7 catalog entry to expose
`['low', 'medium', 'high', 'xhigh', 'max']` with `maxLevel: 'max'`.
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>
Per Anthropic docs, Claude Opus 4.7 only supports adaptive thinking;
manual `thinking.type: "enabled"` with `budget_tokens` is rejected
with HTTP 400.
Switch the claude provider's `claude-opus-4-7` entry from
`type: 'budget'` to `type: 'levels'` with the effort tiers exposed
by the API: `low | medium | high | xhigh`. The proxy is expected to
translate these into `thinking.type: "adaptive"` with the effort
parameter.
Opus 4.6 and Sonnet 4.6 keep `type: 'budget'` for now since the
deprecated mode is still functional on those models.
Built [OnSteroids](https://onsteroids.ai)
Co-Authored-By: OnSteroids <built@onsteroids.ai>