Spaces:
Sleeping
Sleeping
Commit History
-
feat: dashboard login gate for public deployments (#148)
icebear +1: icebear0828Unverified signature* feat: dashboard login gate for public deployments (#141) Cookie-based session auth when proxy_api_key is set and request is non-localhost. API routes (/v1/*) unaffected, Electron (localhost) auto-bypassed. - In-memory session store with TTL from session.ttl_minutes config - Dashboard auth middleware with path-based allowlist - Login/logout/status endpoints with per-IP brute-force protection - HTTPS auto-detection: Secure flag on cookie when X-Forwarded-Proto: https - Remote session cannot clear proxy_api_key (prevents disabling login gate) - Frontend LoginGate component with i18n (en/zh), conditional logout button * fix: dashboard login security hardening - Timing-safe password comparison (crypto.timingSafeEqual) - Rate limiter cleanup of expired entries to prevent memory leak - Extract shared parseSessionCookie to src/utils/parse-cookie.ts - Remove silent password.trim() that could cause subtle mismatches - Logout button visible on mobile (icon-only on small screens) - Fix fragi…91ee702 -
feat: usage stats page with time-series token tracking (#147)
icebear +1: icebear0828Unverified signature* feat: usage stats page with time-series token tracking - Background snapshot recording (piggybacks on quota refresh, ~5min interval) - UsageStatsStore: JSON persistence, 7-day retention, delta computation - GET /admin/usage-stats/summary — live cumulative totals - GET /admin/usage-stats/history — time-series deltas with hourly/daily granularity - Pure SVG line charts (input/output tokens + request count) - Granularity (hourly/daily) and range (24h/3d/7d) selectors - 13 backend tests (snapshot, delta, aggregation, retention, API routes) - i18n: en + zh * fix: usage stats review fixes — chart coords, refresh, cleanup --------- Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>df56b50 -
feat: account management page with batch operations (#146)
icebear +1: icebear0828Unverified signature* fix: treat unfetched plan types as possibly compatible in acquire() When model-fetcher fails to fetch models for a plan type (e.g. the selected free account had an expired token), _planModelMap only contains successfully fetched plans. acquire() then excludes all accounts whose planType is absent from the map — even though their compatibility is unknown, not negative. Add isPlanFetched() to model-store and use it in acquire() to distinguish "plan was fetched and model is absent" (exclude) from "plan was never fetched" (include as possibly compatible). This prevents false 503s when a plan's model fetch failed at startup. * feat: account management page with batch operations Add #/account-management page for bulk account management: - POST /auth/accounts/batch-delete and batch-status endpoints - Batch delete, set active, set disabled with confirmation - Status summary chips (clickable to filter) - Reuse AccountTable with optional proxy column - Import/export accessible from new pag…7516302 -
feat: detect banned accounts and show status in dashboard (#142)
icebear +1: icebear0828Unverified signature* feat: detect banned accounts and show status in dashboard When upstream returns non-Cloudflare 403, the account is now marked as "banned" instead of silently failing quota fetches with no UI feedback. - Add "banned" to AccountStatus type - usage-refresher: detect 403 ban during quota fetch, auto-recover on success - proxy-handler: detect 403 ban during requests, fallback to next account - Dashboard: rose-colored "Banned"/"已封禁" badge in card/table views - Status filter dropdown includes "Banned" option - acquire() naturally skips banned (status !== "active") * feat: handle 401 token invalidation with auto-retry Previously 401 "token has been invalidated" was passed through to the client without marking the account or trying alternatives. - proxy-handler: 401 → markStatus("expired") + try next account - usage-refresher: 401 → markStatus("expired") during quota fetch - Refresh scheduler will attempt token renewal for expired accounts --------- Co-authored-by: icebear0828 <icebear…ba262d0
-
refactor: decouple AccountPool, split codex-api and web.ts, fix CI (#113)
icebear +1: icebear0828Unverified signature* refactor: decouple AccountPool, split codex-api and web.ts, fix CI Phase 0 — CI fixes: - Fix TS2322: WS transport instructions type mismatch (Electron/Docker build) - Remove duplicate selectAll i18n keys (Vite warning) - Add rebase retry to sync-changelog.yml push step (race with bump-electron) Phase 1-5 — Architecture improvements: - Extract codex-types.ts: API type definitions separated from class - Extract rotation-strategy.ts: pure-function selection logic (10 tests) - Split web.ts (605 LOC) into routes/admin/ (health/update/connection/settings) - Extract account-persistence.ts: injectable fs persistence interface (8 tests) - Split codex-api.ts into codex-sse/usage/models modules (10 tests) All existing import paths preserved via re-exports. 902 tests pass (70 files), build clean. * fix: address PR #113 review issues before merge - Fix needsPersist regression: load() now returns { entries, needsPersist } and auto-persists when backfill is applied (restores original behavio…0c8b3c0 -
feat: add sticky rotation strategy (#107) (#110)
icebear +1: icebear0828Unverified signature* feat: add sticky rotation strategy with admin UI (#107) Keep using the same account until rate-limited or quota exhausted, instead of rotating across multiple accounts. - Add "sticky" to rotation_strategy config enum - Implement sticky sort in selectByStrategy() (last_used desc) - Add GET/POST /admin/rotation-settings endpoints - Add RotationSettings component (sticky vs rotation radio group) - Add i18n translations (en + zh) - 13 new tests (account-pool-sticky + rotation-settings routes) * refactor: extract ROTATION_STRATEGIES constant to eliminate hardcoded duplication Single source of truth for valid rotation strategies — route handler and Zod schema both reference the exported constant. --------- Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>d0eeb87
-
feat: add quota settings UI to dashboard (#101)
icebear +1: icebear0828* feat: add quota settings UI to dashboard (#92) Allow users to configure quota refresh interval, warning thresholds, and skip-exhausted toggle directly from the web dashboard instead of editing YAML manually. * docs: update CHANGELOG for quota settings UI --------- Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>07041c6 -
feat: auto-refresh quota with tiered warnings (#92) (#93)
icebear +1: icebear0828Unverified signatureBackground quota refresher fetches official usage every 5min (configurable), caches on AccountEntry for instant dashboard reads, and marks exhausted accounts as rate_limited. Tiered warning thresholds (default 80%/90%) trigger visual banners in the dashboard. Frontend auto-polls every 30s. Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>4f2665c
-
fix: server-side export filtering and JSON parse safety
icebear0828- Export endpoint supports ?ids= query param for selective export, preventing full token payload over the network - Import hook wraps JSON.parse in try-catch for invalid files - Add test for selective export filteringa8a2d95 -
feat: bulk account import/export with selective export (#82)
icebear0828- GET /auth/accounts/export — export all accounts (with tokens) for backup - POST /auth/accounts/import — bulk import from JSON with dedup detection - Dashboard: import/export buttons next to refresh, multi-file import - Selective export: checkbox on each account card, select all/deselect all - 9 unit tests for backend routes268c5a4
-
fix: add color-scheme declaration to prevent browser auto-darkening
icebear0828Browsers with Auto Dark Mode (Chrome/Safari on macOS dark) override CSS colors when color-scheme is not declared. Added color-scheme: light/dark to :root/.dark CSS, index.html meta tag, and JS toggle to explicitly control the color scheme per theme state.f3c6831 -
feat: model list auto-sync + theme contrast fix
icebear0828- Backend: auto-write merged catalog back to models.yaml after dynamic fetch - Frontend: poll /v1/models/catalog every 60s to pick up new models - Theme: light mode bg #f6f8f6 → #ffffff for clearer dark/light contrast - Remove unused legacy web/src/hooks/use-status.ts94a5578
-
feat: Docker image auto-publish to GHCR + Watchtower support
icebear0828- Add docker-publish.yml workflow: multi-arch (amd64/arm64) build on every push to master, published to ghcr.io/icebear0828/codex-proxy - Switch docker-compose.yml from local build to pre-built GHCR image - Add commented Watchtower service block for automatic updates - Simplify README Docker section: no git clone needed, just curl configs - Update dashboard Docker hint to mention Watchtower option - Add dockerAutoUpdateHint i18n key (en/zh)7ff102d -
fix: mode-specific update hints for Docker and Electron
icebear0828- apply-update 400 response now includes mode + hint per deploy type - Docker: docker compose pull && docker compose up -d (was --build) - Electron: prompt to use built-in auto-updater instead of GitHub link - Add electronUpdateHint i18n key (en/zh)009c43a -
feat: SSE update progress + reliable restart on Windows
icebear0828 +1: Claude Opus 4.6 (1M context)- apply-update returns SSE stream with step-by-step progress (pull → install → build → restart) - Frontend parses SSE, shows progress steps with checkmarks in modal - Restart helper writes temp .restart-helper.cjs file instead of -e inline script (fixes Windows command escaping issues) - RESTART_TIMEOUT increased from 30s to 120s - Frontend falls back to restart polling if connection drops mid-stream Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>236dd56 -
fix: dark mode not applying on initial load
icebear0828 +1: Claude Opus 4.6 (1M context)ThemeProvider only set the dark class on toggle, not on initialization. Users with system dark mode or saved "dark" preference would see light theme until they manually toggled. Now sync dark class to <html> before first render. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>b4b60dc
-
feat: display secondary rate limit window (weekly cap) in dashboard
icebear0828 +1: Claude Opus 4.6Add secondary_rate_limit to CodexQuota type and map secondary_window from Codex usage API. Dashboard now shows both primary (hourly) and secondary (weekly) quota bars with independent progress and reset times. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>2996fd8
-
feat: add Test Connection diagnostic button (#63)
icebear +2: icebear0828, Claude Opus 4.6Unverified signature* feat: add Test Connection diagnostic button (#61) Add a "Test Connection" button to the Dashboard that runs 4 sequential checks (Server, Accounts, Transport, Upstream) and displays pass/fail/skip results with latency — helps Electron users diagnose connectivity issues without access to console logs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use socket address for localhost check, static import for buildHeaders - Replace spoofable x-forwarded-for/x-real-ip with getConnInfo() socket address for /debug/fingerprint and /debug/diagnostics endpoints - Add ::ffff:127.0.0.1 match for IPv4-mapped IPv6 addresses - Change dynamic import() of buildHeaders to static import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>85a4cbd
-
fix: use catalog isDefault instead of hardcoded gpt-5.4 in dashboard
icebear0828 +1: Claude Opus 4.6The dashboard hardcoded gpt-5.4 as default/fallback model, but it was removed from the catalog. Now uses the catalog's isDefault flag to dynamically select the default model (gpt-5.2-codex). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>c231bc0
-
feat: editable proxy_api_key from Dashboard settings panel
icebear0828 +1: Claude Opus 4.6Add GET/POST /admin/settings endpoints to read/write proxy_api_key in config/default.yaml with hot-reload. Dashboard gets a collapsible Settings panel with masked input, save, and clear key functionality. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>69a8388 -
fix: Electron OAuth login + i18n layout shift + update modal (#53)
icebear +2: icebear0828, Claude Opus 4.6Unverified signature* fix: Electron OAuth login + i18n toggle layout shift + update modal 1. OAuth login fix for Electron: - Add focus/visibilitychange listeners to detect new accounts immediately when user switches back from system browser (bypasses Chromium throttling) - Track completed sessions server-side so code-relay returns success instead of "Invalid or expired session" after callback server handled it 2. i18n layout stability: - Push Star/Updates buttons from md to lg breakpoint to reduce crowding - Add inline-grid overlay to Star, Check for Updates, Proxy Settings buttons 3. Update modal: extract from Header into standalone UpdateModal component with auto-restart support (git mode spawns new process, frontend auto-refreshes) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add polling guard + fix Star button inline-grid reference width - Add re-entrancy guard to checkForNewAccount (both shared/ and web/) to prevent concurrent fetches from rapid focu…1b6fb15 -
feat: auto-release pipeline + multi-mode update system + commit hash display
icebear0828 +1: Claude Opus 4.6- sync-electron.yml: auto bump patch version + create tag after merge, concurrency group - release.yml: replace CHANGELOG extraction with GitHub auto-generated release notes - self-update.ts: support git/docker/electron deploy modes, GitHub Releases API, periodic checker - Header: show commit hash in status badge, expandable update panel with changelog - use-update-status: add applyUpdate, mode/commits/release fields Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>0c2aed2
-
feat: model name suffix system + service_tier + Docker persistence fix (#35)
icebear +2: icebear0828, Claude Opus 4.6Unverified signature* feat: model name suffix system + service_tier (fast mode) support Add a unified model name suffix convention so CLI tools (Claude Code, opencode, etc.) can control reasoning effort and speed mode purely through the model name — no extra API fields needed. Suffix parsing (`parseModelName`): - `-fast` / `-flex` → `service_tier` - `-minimal` / `-low` / `-medium` / `-high` / `-xhigh` → `reasoning_effort` - Known model IDs and aliases are never suffix-parsed - Priority: explicit API field > suffix > model default > config default Backend: - `parseModelName()` in model-store.ts (core suffix resolver) - `service_tier` field in Zod schema + CodexResponsesRequest interface - `default_service_tier` in config schema + default.yaml - All 3 translation layers (OpenAI/Anthropic/Gemini) use parseModelName() Dashboard: - Standard / Fast speed toggle in ApiConfig - AnthropicSetup shows compound model name with suffixes - CodeExamples builds compound model name, suppresses redundant params Exampl…5416ffb -
feat: proxy assignment management page with bulk operations (#34)
icebear +2: icebear0828, Claude Opus 4.6Unverified signature* feat: proxy assignment management page with bulk operations Add dedicated page (#/proxy-settings) for managing proxy assignments across hundreds of accounts with matrix-style dual-column layout: - Left sidebar: proxy group list with counts, search, click-to-filter - Right panel: paginated account table (50/page) with search, status filter, Shift+click range select, per-row proxy dropdown - Bulk actions: batch assign to proxy, round-robin even distribute, rule-based assignment modal - Import/export: download JSON assignments, upload with diff preview - Hash routing (zero-dependency), Header navigation links - Backend: 6 new bulk API endpoints + ProxyPool.bulkAssign() - i18n: 35 new translation keys (en + zh) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review issues in proxy assignment feature - Make accountPool required param (was optional but always passed) - Extract isValidProxyId() helper to eliminate duplicated validation - Add resp.ok checks…f878eff -
perf: instant proxy mode switching via optimistic UI update
icebear0828Replace slow accounts.refresh() (fetches quota from chatgpt.com per account) with local state patch for immediate UI response.2ee9797 -
fix: update checker shows correct status + version display + dark mode fixes
icebear0828- Fix 'Up to date' shown incorrectly when Codex version changed (add version_changed field) - Change update status text from <span> to clickable <button> - Add proxy version number next to 'Server Online' badge - Fix dark mode for ProxyPool form inputs and AccountCard proxy selector - Add fingerprintUpdating translation key (zh/en)3cf831b -
feat: proxy pool add form with separate protocol/host/port/auth fields
icebear0828 +1: Claude Opus 4.6Replace single URL input with structured fields (protocol dropdown, host, port, username, password) for easier configuration of authenticated proxies. Backend still accepts raw url for API compat. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>af3e19d -
fix: proxy pool review fixes — security, validation, robustness
icebear0828 +1: Claude Opus 4.6- Skip disabled proxies in healthCheckAll (avoid unnecessary network calls) - Validate proxy URL scheme (only http/https/socks5/socks5h allowed) - Deduplicate proxy URLs on add (return existing ID if URL already exists) - Mask proxy credentials server-side via getAllMasked() (remove client-side maskUrl) - Add try-catch to all use-proxies hook operations (prevent unhandled rejections) - Fix misleading route ordering comment in proxies.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>deae086 -
feat: add proxy pool for per-account proxy routing
icebear0828 +1: Claude Opus 4.6Add proxy pool system allowing different accounts to route through different upstream proxies for IP diversity and risk isolation. Backend: - ProxyPool manager with CRUD, assignment, round-robin, health checks - TlsTransport interface accepts per-request proxyUrl parameter - Both curl-cli and libcurl-ffi transports support per-request proxy - CodexApi forwards proxy through the request chain - REST API at /api/proxies for proxy + assignment management - Periodic health checks (default 5min) via api.ipify.org Frontend: - ProxyPool management section in dashboard - Per-account proxy selector dropdown in AccountCard - Four assignment modes: Global/Direct/Auto(Round-Robin)/Specific Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>4ebb914 -
feat: GitHub Star badge + check-for-updates in dashboard header
icebear0828 +1: Claude Opus 4.6- Header: ⭐ Star badge linking to GitHub repo (amber pill style) - Header: 🔄 Check for Updates button with status display - Checks both proxy self-update (git fetch/pull/build) and Codex fingerprint (appcast) - CLI: auto git pull + npm install + build, prompt restart - Docker: fingerprint auto-update, proxy shows manual rebuild hint - Electron: version display only, managed by desktop app - New endpoints: GET /admin/update-status, POST /admin/check-update - Footer: version info (proxy commit + Codex Desktop version) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>06a5304
-
fix: collapsible model dropdown, default to gpt-5.4, remove legacy gpt-5
icebear0828 +1: Claude Opus 4.6- Model selector now collapses after selection (click-outside close) - Default model changed from gpt-5.2-codex to gpt-5.4 - Removed deprecated gpt-5, gpt-5-codex, gpt-5-codex-mini Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>c52388f
-
feat: add gpt-5.4 + codex-spark support, matrix model selector, extended reasoning efforts
icebear0828 +1: Claude Opus 4.6- Add gpt-5.4 (4 efforts: minimal/low/medium/high) and gpt-5.3-codex-spark (minimal/low) to models.yaml - Update codex alias to gpt-5.4 - Generalize isCodexModelId → isCodexCompatibleId to match bare gpt-X.Y models - Add /v1/models/catalog endpoint returning full CodexModelInfo[] with reasoning efforts - Replace flat model dropdown with family × reasoning effort matrix selector in dashboard - Add reasoning_effort to code examples when non-default effort is selected - Bump client to v26.305.950 (build 863) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>7824fcd
-
refactor: extract startServer() + path abstraction for Electron reuse
icebear0828 +1: Claude Opus 4.6- Export startServer(options?) from src/index.ts so Electron can import it - Add src/paths.ts: centralized path getters (getConfigDir, getDataDir, etc.) with setPaths() hook for Electron to redirect to userData - Replace all process.cwd() calls with path getters across src/ - Extract shared/ from web/ (i18n, theme, hooks, utils) for desktop reuse - Add /desktop route in web.ts (serves desktop UI if built, no-op otherwise) CLI behavior is unchanged — all path getters default to process.cwd(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>4a940a5