Auto refresh
- New refreshCodexAccount(index) calls https://auth.openai.com/oauth/token
with grant_type=refresh_token and persists rotated tokens back to
~/.codex-accounts/{N}/auth.json. JWT's subscription_active_until
reflects the latest plan state OpenAI hands back.
- startCodexAccountRefreshLoop() runs every 6h (first run delayed 60s
after boot to keep startup snappy). Hooked into main()/shutdown()
alongside the existing claude token refresh loop.
Manual controls (Settings → 계정 → Codex)
- "갱신" button per row: forces an immediate refresh for that account.
- "전체 갱신" button: refreshes all codex accounts in sequence.
- "전환" button: writes data/codex-rotation-state.json so the next codex
spawn picks the chosen account. Active account marked with a green-
bordered card and "사용중" badge.
Endpoints
- POST /api/settings/accounts/codex/{i}/refresh
- POST /api/settings/accounts/codex/refresh-all
- PUT /api/settings/accounts/codex/current { index }
- GET /api/settings/accounts now also returns codexCurrentIndex.
Why
JWTs cache subscription state at issue-time. When a Pro plan lapses or
a user upgrades/downgrades, the dashboard kept showing stale data until
the user logged in again. Periodic refresh + explicit "갱신" button
keeps the displayed state honest, and the manual switch unblocks the
user when rotation lands on a known-bad account.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Adds a disabled-by-default loopback web dashboard MVP with read-only control-plane views, prompt preview redaction, Vite React UI, and validation coverage.
- Failover is now global (account-level, not per-channel)
- Dashboard shows role model config (Owner/Reviewer/Arbiter + MoA refs)
- Dashboard shows failover status when active
- Auto-clear failover on successful Claude rotation
- Remove per-channel lease writes from failover path
SERVICE_AGENT_TYPE was always 'claude-code' in the unified service,
making it a misleading constant. Each group already has its own
agentType field.
- Removed SERVICE_AGENT_TYPE from config.ts
- Session functions now accept agentType parameter (default: 'claude-code')
- Task scheduler uses task-level agent_type for token rotation decisions
- All fallback defaults changed to 'claude-code' literal
- Logging uses 'unified' instead of the misleading type
When OAuth tokens rotate or refresh, all reviewer containers are
automatically removed. The next reviewer turn recreates them with
the latest token, preventing 401 auth failures.
Uses callback pattern to avoid circular dependencies:
- token-rotation.ts: onTokenRotated(cb)
- token-refresh.ts: onTokenRefreshed(cb)
- index.ts: registers recreateAllReviewerContainers as callback
In paired rooms, cron output was posted by the owner bot. Since the
owner can't respond to its own messages, the cron report just sat
there with no follow-up action.
Now cron output in paired rooms is posted via the reviewer bot. The
owner picks it up as a peer request, analyzes the report, and acts
on it (e.g., fixing Sentry errors). The normal paired review loop
then kicks in to verify the fix.
Proxy was binding to 127.0.0.1 which is unreachable from Docker
containers. Now uses PROXY_BIND_HOST (detects docker0 IP on Linux)
so containers can reach the proxy via host.docker.internal.
- Detect pnpm projects and mount global store read-only so hardlinks resolve
- npm/yarn/bun need no extra mounts (node_modules is self-contained)
- Pre-flight check: verify Docker running + image exists (cached after first call)
- Add activity-based idle timeout (reset on stdout/stderr like host runner)
- Clean up orphaned containers on shutdown (not just startup)
- Remove UNIFIED_MODE legacy: single service manages all 3 Discord bots
- Add OWNER_AGENT_TYPE / REVIEWER_AGENT_TYPE env vars for configurable agent selection
- Fix Discord channel routing: reviewer output goes through correct bot (discord/discord-review)
- Fix channel name assignment: explicit names prevent agentTypeFilter collision
- Remove silent output suppression system: harness-level protections replace prompt workarounds
- Add reviewer approval detection: DONE marker on first line stops ping-pong
- Include user's original message in reviewer prompt for context
- Fix round_trip_count auto-reset on new user message
- Fix session ID conflict: reviewer doesn't reuse owner's session
- Fix pending progress text flush in runner on close sentinel
- Promote buffered intermediate text to final result when result event has no text
- Remove legacy files: .env.codex.example, .env.codex-review.example, migrate-unify.cjs
- Update CLAUDE.md: server-side build deployment, unified architecture docs
- Add UNIFIED_MODE flag (default on, disable with UNIFIED_MODE=0)
- Register all 3 Discord bots in one process (claude, codex, review)
- Load all registered groups regardless of agent_type (codex/owner priority)
- Start credential proxy and container cleanup at unified startup
- shouldServiceProcessChat returns true in unified mode
- Add findChannelByName for role-based response routing
- Backward compatible: UNIFIED_MODE=0 restores per-service behavior
The previous regex used \w+ for descriptor tokens between the function
name and JSON body, which only matches ASCII word characters. Model
hallucinations often inject CJK/non-ASCII text (e.g. 彩神争霸) in this
position. Switch to (?:\s+[^\s{}]+)+ to match any whitespace-separated
non-brace tokens regardless of character set.
Also removes stale backward-compat re-exports from index.ts and updates
the test import for composeDashboardContent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restores token-refresh.ts that was deleted in 35356dd. Now works
with multi-account token rotation:
- Refreshes tokens from ~/.claude/.credentials.json (account 0)
and ~/.claude-accounts/{n}/.credentials.json (account 1+)
- Updates token-rotation memory and .env on refresh
- Syncs credentials to session directories
- 5-min check interval, refreshes 30 min before expiry
- forceRefreshToken() export for 401 recovery
- New codex-token-rotation module: rotates between multiple
~/.codex-accounts/{n}/auth.json on rate-limit
- Copies active account auth to session dir before each spawn
- Fix detectFallbackTrigger to match "usage limit" / "hit your limit"
- Fix streamed error detection: remove claude-only guard so codex
rate-limit errors are caught even when output.status is "success"
- Add rotation in both task-scheduler and message-agent-executor
- New token-rotation module: stores multiple tokens from
CLAUDE_CODE_OAUTH_TOKENS env var (comma-separated)
- On rate-limit, rotates to next healthy token before falling
back to Kimi provider
- Also fixes: intermediate text routes to progress message
when no subagents active (prevents message flooding)
Remove duplicate processGroupMessages, runAgent, startMessageLoop, and
recoverPendingMessages from index.ts. All message processing now flows
through createMessageRuntime() in message-runtime.ts, eliminating the
dual-path issue that caused the v1 follow-up turn reset bug.
index.ts reduced from ~2300 to ~1210 lines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>