- 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>
Major reliability improvements to the message processing pipeline:
- Add messages.seq monotonic cursor replacing timestamp-based cursors,
preventing message loss from timestamp collisions with LIMIT queries
- Add work_items table separating agent production from delivery,
enabling delivery retry without re-running the agent
- Propagate Discord send failures instead of silently swallowing them
- Add Claude 429 → Kimi K2.5 automatic provider fallback with cooldown
- Fix follow-up turn state reset in live index.ts path (not just
message-runtime.ts) to prevent final output from being lost
- Add restart context tracking for graceful restart announcements
- Lazy migration from timestamp cursors to seq cursors for existing data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two bugs fixed:
1. agent-runner error path race condition: when agent process exited
with error, the promise resolved immediately without waiting for
outputChain, allowing a late wrappedOnOutput to re-persist a stale
session ID after clearSession had already run.
2. follow-up turn state not resetting: when a follow-up IPC message
joined an active run, turn-level flags (finalOutputSentToUser,
sawNonProgressOutput) from the first turn prevented the last
progress from being promoted to a final message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add MEMENTO_MCP_SSE_URL/ACCESS_KEY/REMOTE_PATH to readEnvFile
- Merge .env vars into cleanEnv for runner process inheritance
- Claude Code runner: add memento-mcp via mcp-remote in mcpServers
- Codex runner: inject memento-mcp section into config.toml
- Various improvements: CI watch, task scheduler, DB, IPC auth
Phase 0-2 of data unification:
- Enable WAL mode + busy_timeout for safe concurrent access
- router_state: keys prefixed with SERVICE_ID (lazy migration)
- sessions: composite PK (group_folder, agent_type)
- registered_groups: filtered by SERVICE_AGENT_TYPE on load
- Logger: service name tag for unified log streams
All changes are backward-compatible with the current split setup.
Actual directory merge (Phase 3-4) is a separate step.
Delete token-refresh.ts and credentials.json sync. Auth is now
via CLAUDE_CODE_OAUTH_TOKEN in .env (1-year setup-token).
No more auto-refresh loop or credentials.json dependency.
- Add purgeChannel() to Channel interface and DiscordChannel
- Uses bulkDelete for recent messages, individual delete for old ones
- Called once at startup before creating fresh dashboard messages
- Remove "📊 Usage 보고" title line
- Use os.uptime() instead of process.uptime() for actual server uptime
- Handle null limitName in Codex rate limits (fallback to limitId or 'Codex')
- Fix Codex usage parsing: extract from rateLimitsByLimitId object
- Fix formatResetKST to handle unix timestamps (number type)
- Remove seconds from update timestamp display
- Fetch Claude Code usage via OAuth API (five_hour/seven_day)
- Fetch Codex usage via app-server JSON-RPC (rateLimits/read)
- System resources: CPU%, memory, disk in GB with emoji thresholds
- Show actual Discord channel names (#name) instead of DB-stored names
- Guard against overlapping usage updates (async API calls)
- Add getChannelMeta to Discord channel (batch guild fetch)
- Status dashboard groups by Discord category, sorts by position
- Add live usage dashboard (CPU, memory, disk, uptime) with message edit
- Fix 4 failing discord.test.ts tests (sendMessage format, image fetch mock)
Dedicated Discord channel shows per-group agent status with live
elapsed time. Single message is edited every 10s instead of spamming.
- GroupQueue tracks startedAt timestamps and exposes getStatuses()
- Channel interface gets editMessage/sendAndTrack for message editing
- STATUS_CHANNEL_ID env var to configure the dashboard channel
- Shows processing/idle/waiting/inactive per registered group
- Remove commands/ sync from agent-runner (skills/ is SSOT for both agents)
- Remove ~/.codex/skills/ as source (use ~/.claude/skills/ only)
- Codex uses $skill prefix, Claude Code uses /skill — both read from skills/
- Minor formatting fixes in config.ts, group-queue.test.ts, index.ts
- Rewrite codex-runner to use `codex app-server` JSON-RPC instead of
`codex exec`. Supports streaming (item/agentMessage/delta), session
persistence (thread/start, thread/resume), and mid-turn message
injection (turn/steer with IPC polling during execution).
- Fix token refresh not syncing to per-group session directories,
causing 401 errors on running agents.
- Fix typing indicator staying on when codex returns null result
by always clearing typing on any streaming callback.
- Update README and CLAUDE.md to reflect dual-service architecture,
host process mode, and codex app-server integration.
- Add token-refresh module that auto-renews Claude OAuth tokens 30min before expiry
- Fix Codex session loss on service restart by resuming previous sessions
- Inject nanoclaw MCP server into Codex config.toml for send_message/schedule_task
- Sanitize ANTHROPIC_API_KEY and CLAUDE_CODE_OAUTH_TOKEN from Codex subprocess env
- Make STORE_DIR, DATA_DIR, GROUPS_DIR configurable via env vars
(NANOCLAW_STORE_DIR, NANOCLAW_DATA_DIR, NANOCLAW_GROUPS_DIR)
for running two instances from one codebase
- Remove broken 'both' agent type sequential loop from processGroupMessages
- Delete dead code: container-runtime, mount-security, credential-proxy,
Dockerfiles, and related config constants (~1,085 lines removed)
- Add codex instance launchd plist template