You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Broker data race fixed: onCommand/onConnect callback fields were read in Session goroutines without locks while being written by setters. Added callbackMu (RWMutex) with copy-then-call pattern.
Nested lock order eliminated: enqueueWithBytes/enqueueSnapshotEvent held outMu while calling SessionID()/AuthorityEpoch() which internally acquire sessionMu.RLock(). Moved reads before lock acquisition to remove the implicit outMu → sessionMu dependency.
Data integrity fixes
migrateMessageIDs: WriteString/Close errors were silently ignored — disk-full conditions would lose session data without any error. All write paths now check errors and clean up.
backfillIDs/backfillTimestamps: Same write-error ignoring pattern fixed with error checking + Sync().
8 session persistence sites: AppendMetaToDisk errors were silently swallowed (_ =) across sidebar preference, model selection, context window probe, binding state, and async usage recording. All now log via debug.Log.
Crash prevention
git commit nil panic: When injecting Co-Authored-By trailer, the shell command was rebuilt with cmd, _, _ = NewShellCommandContext(...) — ignoring the error. If rebuild failed, cmd was nil and subsequent cmd.Dir / configureCommandCancellation(cmd) would panic. Now returns a proper error Result.
Fixes and improvements
Performance
emitUsage/emitMetric Lock→RLock: High-frequency read-only callbacks used exclusive Lock(), causing unnecessary contention. Switched to RLock().
HandleInbound persistBinding merge: Each inbound IM message wrote binding state to disk twice (once for ChannelID, once for LastInboundMessageID). Merged into a single write.
CountTokens capability caching: context.WithTimeout was created on every Add() call even for providers (OpenAI/Gemini) that use pure local estimation. After first probe, local-estimation providers skip context creation entirely. Cache is reset on SetProvider.
User experience
Bilingual error messages: UserFacingError always returned Chinese text regardless of interface language. New UserFacingErrorLang(err, lang) provides English equivalents for all 12+ error categories (401/403/429/timeout/network/400/etc.). English TUI users no longer see Chinese errors.
Model switch feedback: Selecting a model from the panel silently closed it. Now shows a system message confirming the switch.
/help completeness: 15+ slash commands were missing from help output (/retry, /edit, /files, /chat, /nick, /tunnel, /rules, /allow, /inspector, /reflect, /impersonate, /stream, /stats, etc.). Both EN and ZH catalogs updated.
/retry hint in errors: Transient error messages (429/timeout/network) now suggest "Type /retry to resend".
Keyboard shortcut docs corrected: Ctrl+T was documented as "open tunnel" (actually config scope toggle), Ctrl+N/P descriptions were wrong, and Ctrl+G/Ctrl+\/Esc+Esc/Alt+Up-Down were missing. Both EN and ZH help texts corrected.
Reverted
Stream UI throttle (from auto-optimization round): Added 50ms time-based throttle to appendStreamChunk to reduce markdown re-renders. Reverted because it broke assistant message rendering — the existing three-layer cache (SetText dedup → streamRenderCache incremental blocks → CachedItem width cache) already handles this efficiently.