- Add 30s timeout on proxy requests to prevent indefinite hangs
- Wrap resolveLocalCliproxyPort in try/catch with default port fallback
- Simplify buildProxyBody: remove fragile content-length check that
caused Bun to fall through to req.pipe() on consumed streams
- Replace proxyRes.pipe(res) with manual streaming for Bun compatibility
(pipe hangs after writeHead in Bun runtime)
- Replace deprecated req.on('aborted') with res.on('close') cleanup
(req.on('close') fires with req.destroyed=true in Bun after body
consumption, prematurely destroying the proxy connection)
- Explicitly end proxy request for bodyless methods (GET/HEAD/OPTIONS)
instead of piping an already-consumed express stream
- Add server.closeAllConnections() in test cleanup to prevent hangs
- Add GET passthrough and 502 unreachable test cases
- switch ccs-websearch MCP to stdio-first framing and keep legacy compatibility
- add cooldown persistence and bounded retries for provider failures
- surface cooldown status in readiness output and regression tests
Move reverse proxy under /api/cliproxy-local so it sits behind auth
middleware. Enforce localhost-only access when dashboard auth is disabled.
Resolve the target port from unified config instead of hardcoding 8317.
Re-serialize parsed JSON bodies before forwarding so writes still work
behind express.json(). Clean up proxy connections on client abort.
On the frontend, point the iframe and health check at the new same-origin
API path, probe the proxy directly, and tighten iframe origin/path
validation before sending the auto-login secret.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- keep Codex team and personal auth files as separate identities
- resolve quota and live monitor stats by token file-backed account id
- surface duplicate-aware account labels across the dashboard and variant UI
In Docker, the browser cannot directly reach the container-internal CLIProxy
port (8317). This adds a reverse proxy at /cliproxy-local/* that forwards
requests through the dashboard Express server to 127.0.0.1:8317 internally.
The control panel embed now uses same-origin API endpoints for health checks
and the proxy path for the management iframe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- prune stale generated Gemini preview clusters during config regeneration
- preserve manual preview overrides on built-in Gemini alias names
- add regression coverage for stale cluster cleanup and manual pins
- add guided editors for top-level settings, trust, profiles, providers, MCP, and features
- refresh raw snapshots after patch saves to avoid stale mtime conflicts
- block structured saves while raw TOML is dirty and add route plus hook coverage
- update CLI, API, route, and dashboard surfaces to recognize the Codex runtime target
- normalize persisted codex targets back to claude so runtime-only behavior stays truthful
- add regression coverage for help text, route parsing, and profile storage normalization
Refs #773
The auth check endpoint always returned authRequired=false when auth
was disabled, even for remote clients. This caused the UI to render
the dashboard directly, where all data API calls return 403 silently.
Now detects remote access via isLoopbackRemoteAddress and sets
effectiveAuthRequired=true, so the UI properly redirects to the login
page. Also fixes misleading catch handler comment in auth-context.
Users deploying via ccs docker up --host see "Docker stack is running"
but hit a broken dashboard because auth is required for remote API
access. Now prints a reminder with the exact command to configure auth.
Session registration in spawn handler can throw on lock contention or
disk errors — wrap in try-catch to prevent silent proxy-untracked state.
Narrow EBUSY catch to ETXTBSY only since EBUSY on non-Linux platforms
can mean mount point or directory in use, not running binary. Fix
misleading "skip" comment to say "abort".
In Docker, the dashboard tried to update the CLIProxy binary while
the bootstrap's instance was already executing it, causing ETXTBSY.
Now catches the error and throws a clear message instead of crashing.
Docker bootstrap spawns CLIProxy but never registered a session lock,
so the dashboard's fallback detection found nothing. Now registers on
spawn and unregisters on close.
Health check used OS-level port detection (lsof/ss) which is
unavailable in minimal Alpine containers. Switched to the unified
detectRunningProxy() which tries HTTP first, then session lock,
then port-process as fallback.
Remote compose commands placed env vars directly before a compound
if/then statement which is invalid bash syntax. Changed to export
statements chained with &&.
Added REMOTE_DOCKER_BUILD_TIMEOUT_MS (5min) for up and update
operations that involve npm install inside the container. Quick
queries (status, config, down) keep the default 30s timeout.
Closes#832
- fail enabled settings-profile create and launch flows when hook preparation is still unusable
- refresh stale shared hook binaries without rewriting unchanged installs or failing benign races
- add rollback and regression coverage for disabled, stale, invalid, copy, import, and launch paths
- verify the hook binary before migrating global WebSearch hook state
- centralize migration-marker helpers in hook-installer exports
- expand regression coverage for existing-hook, disabled, invalid-name, and failed-install paths
- ensure profile hook injection installs the transformer binary before writing the command
- keep migration marker cleanup in the installer to avoid a circular import
- add a regression test for isolated CCS_HOME settings profiles
- add default local and remote sync-command timeouts with clearer timeout diagnostics
- remove extra synchronous fs and process.exit patterns from docker assets/bootstrap helpers
- register the docker help handler in CLAUDE.md for the repo help-location reference