Detect system dark mode on Windows (registry AppsUseLightTheme) and
Linux (gsettings for GNOME, kreadconfig for KDE Plasma) to set native
window background color before webview renders, matching the existing
macOS behavior. Make should_use_dark_background() cross-platform and
apply background_color in all platform branches of
apply_platform_window_style.
Finder moves files to Trash (rename) instead of deleting them, which
may be reported as `Modify(Name)` rather than `Remove` by the file
watcher. This caused untracked files to lose their red color without
being removed from the tree. Fix by checking disk existence in the
event batch emitter and promoting the kind to "remove" when a changed
path no longer exists.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detect dark/light mode before React hydrates to eliminate the visible
white-to-dark flash when opening windows in dark mode.
Frontend:
- Inline script now reads next-themes localStorage key and applies
.dark class, colorScheme, and backgroundColor on <html> before first
paint
- Add CSS-only fallback via prefers-color-scheme media query in an
inline <style> tag that fires before any JS executes
macOS backend:
- Detect system dark mode via `defaults read -g AppleInterfaceStyle`
(cached with OnceLock) and set native window background color to
match dark theme in apply_platform_window_style
- Persist user appearance mode preference (dark/light/system) to DB
alongside zoom level so new windows use the correct background
- Add update_appearance_mode Tauri command; frontend syncs on mount,
on settings change, and on cross-window storage events
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the welcome window (or any startup window) always used the
default CURRENT_ZOOM of 100, ignoring the user's saved zoom preference
stored in frontend localStorage. Now update_traffic_light_position also
writes the zoom value to the app_metadata DB, and setup() reads it back
before creating any window.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the spinner-only UX with live log output during agent SDK
operations, matching the existing OpenCode plugin install experience.
Backend: emit structured events (started/log/completed/failed) via
EventEmitter during npm install and binary download. npm commands now
run with piped stdio for line-by-line streaming; binary downloads
report chunked progress every 1 MB.
Frontend: subscribe to `app://agent-install` events through a new
`useAgentInstallStream` hook and render a theme-aware log terminal
below the preflight checks panel.
Also fixes the install log container in both agent settings and the
OpenCode plugins modal: auto-scroll no longer shifts the outer page,
and colours now follow the active light/dark theme.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Set UTF-8 environment variables (PYTHONUTF8, PYTHONIOENCODING, LANG,
LC_ALL) on all child processes via process.rs helpers
- Configure PTY terminals per shell flavor: chcp 65001 for cmd.exe,
[Console]::OutputEncoding for PowerShell, LANG=C.UTF-8 for Git Bash
- Use /K and -NoExit for interactive shells to avoid nested processes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use Tauri's native `traffic_light_position()` builder method to position
macOS window controls instead of runtime objc2 calls. A global AtomicU32
tracks the current zoom level so newly created windows reflect the latest
zoom. The frontend syncs zoom changes to the backend via a new
`update_traffic_light_position` command.
- Add `traffic_light_position()` to `apply_platform_window_style` builder
- Add `CURRENT_ZOOM` atomic and `traffic_light_position()` helper
- Register `update_traffic_light_position` Tauri command
- Add `syncTrafficLightPosition` in appearance-provider to sync on zoom
change, mount, and cross-tab storage events
- Consolidate `ensure_windows_undecorated` calls into `post_window_setup`
- Remove dead `on_window_resized` no-op and its Resized event listener
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The naive // and /* check triggered on URLs like https://... inside
string values. Now we only reject the file as JSONC when serde_json
parsing fails AND comment-like sequences are found.
- install_missing_plugins now pins ALL @latest specs (not just newly installed)
- When nothing is missing but @latest exists, the pin-only path runs
- Modal button switches to 'Pin @latest Versions' when no missing plugins
- Added pinVersions i18n key for 10 languages
After a successful plugin install, read the actual installed version from
node_modules and replace @latest in opencode.json with the pinned version.
This prevents opencode from hitting the npm registry on every startup.
Also add a preflight warning when @latest specs are detected, guiding
the user to install via the plugin manager to auto-pin.
Add InstallOpencodePlugins variant to FixActionKind and wire
opencode_plugins::check_opencode_plugins into check_binary_environment
so preflight surfaces missing/installed plugin status for OpenCode agents.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add concurrency lock (PLUGIN_OP_LOCK), install/uninstall functions with
bun subprocess management, progress event streaming via EventEmitter, and
protected-package guard for @opencode-ai/* internals.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add check_opencode_plugins() to read ~/.config/opencode/opencode.json,
parse the plugin[] array, and cross-reference against
~/.cache/opencode/node_modules/ to report installed vs. missing plugins.
Also adds opencode_config_path, opencode_cache_dir, and
has_project_opencode_config helpers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Session-page connect never triggers download/install; returns
SdkNotInstalled immediately and prompts the user to install from
Agent Settings instead
- Binary agents now accept any cached version via
find_best_cached_binary_for_agent so stale caches still connect
- Bound Initialize handshake with a 60s timeout and convert it to
AcpError::InitializeTimeout via a sentinel in run_connection
- Spawn background task owns ConnectionManager map insertion and
removes the entry on exit through an RAII guard that survives
panics, preventing leaked stale entries
- AcpError gains SdkNotInstalled and InitializeTimeout variants plus
a stable code() identifier; AcpEvent::Error carries code so the
frontend can render localized messages by key
- Frontend preflight now runs for all connect sources; error event
handler switches on code to show translated text for
initialize_timeout, sdk_not_installed, platform_not_supported,
process_exited, spawn_failed and download_failed
- Remove ConnectionStatus::Downloading enum variant, all frontend
branches, and i18n strings; drop obsolete autoLinkFailedTitle,
autoLinkPreflightFailed, preflightCheckFailedDefault and
preflightFailedTitle keys across 10 locales
- Add backendErrors.* translations in 10 languages
- Diagnostic logging: always log agent stderr plus binary
path/size/args/env keys and Initialize timing; gate stdin/stdout
JSON-RPC tracing behind CODEG_ACP_DEBUG to avoid persisting user
content into OS log files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codex CLI also reads skills from ~/.agents/skills/, so include it
alongside ~/.codex/skills/ in the skill storage spec. The Codex dir
stays first so it remains the preferred write target for new links,
while lookup and unlink scan both locations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Change Codex skill storage to use only ~/.codex/skills/ instead of
~/.agents/skills/, and never disable the expert skills button so users
can always access the empty-state hint. Also fix stale expert list in
conversation window after linking in the separate settings window by
re-fetching on window focus.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expert skills in the chat session were derived by intersecting built-in
experts with ACP availableCommands, which caused Codex experts to never
appear since Codex does not advertise skills through ACP.
- Add `experts_list_for_agent` backend API that checks symlink status
across all global skill dirs for the given agent type
- Replace availableCommands-based expert filtering with symlink-based
query, making the settings page the single source of truth
- Use `$` prefix for Codex expert skills while keeping `/` for slash
commands and other agents' experts
- Disable the expert button when no experts are linked for the agent
- Invalidate per-agent expert cache after link/unlink in settings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When reopening a Gemini CLI history session, session/load fails with
"Authentication required" and the fallback session/new overwrites the
DB external_id with a new session ID that has no corresponding file,
causing all historical messages to disappear.
- Skip session/new when session/load returns "Authentication required"
- Add Gemini to the parser fallback so stale external_ids recover via
folder_path + started_at matching
- Guard externalIdSavedRef for existing conversations to prevent
session/new from overwriting the persisted external_id
- Only update conversation status on disconnect when user has sent a
message, avoiding spurious "completed" flips on pure history views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add --version flag to codeg-server binary and enhance both install.sh
and install.ps1 with version detection (skip if already up-to-date),
running process stop before upgrade, and post-upgrade restart guidance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Block deletion of a model provider when it is referenced by any agent,
returning an error that lists the agent names so the user knows what to unlink first
- When a provider's api_url or api_key is updated, automatically propagate
the new credentials to all dependent agents: updates env_json in the database
and patches on-disk config files (Claude Code settings.json, Gemini settings.json,
Codex auth.json + config.toml, OpenCode auth.json) using the same field names
and structure as the agent settings UI
- Fix error message display in provider dialogs for both Tauri and web transports,
which throw plain objects rather than Error instances
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Split env vars and config file persistence into separate save operations
- Add model_provider_id field to agent_setting for tracking selected provider
- Add "Model Provider" auth mode for Claude Code, Codex CLI, and Gemini CLI
- Add "Custom Endpoint" auth mode for Claude Code (previously only official subscription)
- Unify auth mode labels across all three agents (official subscription / custom endpoint / model provider)
- When model provider is selected, fill api_url and api_key into env and config automatically
- Resolve model provider credentials at ACP connect time as a backend fallback
- Clear provider deletion cascades to agent_setting.model_provider_id
- Claude Code writes API credentials to config.env (ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN)
- Codex: switching auth modes patches config.toml instead of clearing it
- Add i18n keys for new auth modes in all 10 supported languages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a new settings page for managing API model providers (name, API URL,
API key, applicable agent types). Includes database migration, SeaORM
entity, backend CRUD commands/handlers, frontend settings UI with agent
type filter, add/edit/delete dialogs, and i18n support for all 10 locales.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Code errors when setting config options to "auto". Strip "auto"
values from config options returned to frontend and skip set requests
with "auto" value for Claude Code agent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add split button with dropdown in commit dialog supporting both
"Commit" and "Commit and Push" actions
- Pass folderId through gitCommit/gitPush API calls so backend emits
events that the folder window can receive for toast notifications
- Update Tauri git_commit and git_push commands to accept folder_id
parameter with window label fallback for cross-window compatibility
- Wrap commit page with GitCredentialProvider for push authentication
- Keep commit window open when push fails so user can see the error
- Add i18n translations for all 10 locales
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move PTY spawn from context layer to view layer so event subscription
happens before spawn, preventing loss of initial terminal output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Generate QR code server-side when iLink API returns SPA page URL
(added qrcode + image crates for PNG generation)
- Strip bot_token from frontend response (new WeixinQrcodeStatusPublic type)
- Add request timeouts and shared HTTP client for QR code endpoints
- Fix TOCTOU race on reply_context double-lock (single lock scope)
- Extract do_send() helper to deduplicate sendmessage logic; resend now
checks ret field for context expiry instead of HTTP status only
- Cap pending_messages buffer at 50 to prevent unbounded memory growth
- Generate stable X-WECHAT-UIN per backend instance instead of per request
- Extract ILINK_CHANNEL_VERSION constant (was hardcoded in 4 places)
- Add 5-minute client-side QR expiry timeout in frontend dialog
- Track consecutive polling errors and show warning after 3 failures
- Stabilise onAuthSuccess/onClose callback refs to prevent polling restarts
- Replace dead i18n key weixinOpenQrcode with weixinPollError
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Filter messages by message_type=1 to skip bot echo and prevent loops
- Add voice message support (type=3) with voice-to-text extraction
- Check resend results and re-buffer failed messages to prevent loss
- Handle session expiry (ret=-14) with 30s pause in polling loop
- Use exponential backoff (5s–30s) for network errors instead of fixed 5s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Display specific file paths, commands, and patterns in tool call messages
instead of generic titles (e.g. ">> Read: src/main.rs")
- Show tool call details only on completion to ensure raw_input availability
- Enrich permission request messages with tool details from rawInput
- Localize stop_reason in turn_complete messages for all 10 languages
- Fix UTF-8 byte-slice panic in format_completion for multi-byte content
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>