Commit Graph

17 Commits

Author SHA1 Message Date
Thefool 1c0ee0c58a feat(grokbuild): add first-class Grok Build support (#5453)
* feat(grokbuild): add backend integration

* feat(grokbuild): add provider and management UI

* test(grokbuild): cover configuration and integrations

* fix(grokbuild): address backend review feedback

* fix(grokbuild): complete UI review feedback

* feat(grokbuild): add CLI lifecycle management

* fix(grokbuild): align provider icon fallback

* test(grokbuild): cover provider icon persistence
2026-07-17 15:50:50 +08:00
Jason Young 7bb59fa5a6 fix(proxy): harden takeover-residue recovery across config-dir switches (#4076)
Changing app_config_dir relocates the SQLite database, so a restart
triggered while proxy takeover is active used to strand the live
configs: the new instance reads a fresh DB with no live backups, the
first-run import then persisted the PROXY_MANAGED placeholder as the
`default` provider, and the no-backup recovery path wrote that
placeholder right back to the live files — leaving Claude/Codex/Gemini
pointed at a dead local proxy with no automatic way out.

Three orthogonal fixes, defense in depth:

- restart_app now awaits cleanup_before_exit() before app.restart().
  Since #4069 the ExitRequested handler intentionally defers restart
  requests to Tauri's default re-exec without custom cleanup, which is
  correct for same-DB restarts but not for this command's dir-change
  use case: only the old instance holds the backups needed to restore
  the taken-over live files, so it must restore them while its event
  loop is still alive.
- import_default_config refuses to import a live config that is under
  proxy takeover (placeholder detected), instead of persisting it as
  the current provider.
- restore_live_from_ssot_for_app validates that the current provider's
  settings_config does not itself contain takeover placeholders before
  writing it back; polluted SSOT now falls through to the placeholder
  cleanup fallback.

Regression tests cover the import guard and the no-backup recovery
path (the latter fails before this change by writing PROXY_MANAGED
back to live).
2026-06-11 21:32:24 +08:00
Jason 60a9b330e5 Refactor Codex live-write routing and cover default auth overwrite
Collapse the two duplicated write_codex_live_atomic branches in
write_codex_live_for_provider into a single should_write_auth guard.
This is behavior-preserving: `if A {X} else if B {X} else {Y}` becomes
`if A || B {X} else {Y}`.

Adapt the Codex switch tests to the new opt-in default for
preserve_codex_official_auth_on_switch (flipped off in 3f59ab37):
add an enable_codex_official_auth_preservation() test helper for the
cases that assert the auth-preserving path, and tag the official login
provider with category="official" so it routes through the official
branch rather than relying on the global preservation flag.

Add a regression test locking the default (preservation off) behavior:
switching to a third-party provider rewrites auth.json with the new
API key and discards the existing ChatGPT OAuth login. This is the
dual of the existing preserve-and-backfill test, which only covered
the opt-in path.
2026-05-30 22:09:28 +08:00
Jason 95f2dd4126 feat(codex): preserve OAuth login state during third-party provider switching
Codex provider switches now only write config.toml for third-party providers,
injecting the API key as experimental_bearer_token. The user's auth.json
(ChatGPT OAuth tokens) is preserved. Official providers with login material
still write auth.json normally. Backfill restores bearer tokens into stored
provider auth.OPENAI_API_KEY to maintain canonical shape.
2026-05-25 22:20:34 +08:00
Dhruv_S b05be92aa1 Fix Codex startup live import duplication (#2590)
* Fix Codex startup live import duplication

* Fix: Prevent duplicate Codex default provider on restart & add startup import tests
2026-05-08 08:41:50 +08:00
Jason 81af0a57f9 feat: add Hermes Agent as 6th supported app type (Phase 1)
Register AppType::Hermes across the entire Rust backend:
- Add Hermes variant to AppType enum with additive mode and MCP support
- Add hermes field to McpApps, SkillApps, CommonConfigSnippets, and all
  per-app structs (McpRoot, PromptRoot, VisibleApps, AppSettings)
- Create minimal hermes_config.rs with get_hermes_dir() respecting
  settings override, matching the pattern of other app config modules
- Update all match arms in commands, services, deeplink, proxy, mcp,
  session_manager, and test files
- Extract shared build_additive_app_settings() to eliminate duplication
  between OpenClaw and Hermes deep link handling
- Combine identical OpenClaw/Hermes proxy match arms into unified arms
2026-04-21 11:57:06 +08:00
Jason 859f413756 revert: restore full config overwrite + Common Config Snippet (revert 992dda5c)
Revert the partial key-field merging refactoring introduced in 992dda5c,
along with two dependent commits (24fa8a18, 87604b18) that referenced
the now-removed ClaudeQuickToggles component.

The whitelist-based partial merge approach had critical issues:
- Non-whitelisted custom fields were lost during provider switching
- Backfill permanently stripped non-key fields from the database
- Whitelist required constant maintenance to track upstream changes

This restores the proven "full config overwrite + Common Config Snippet"
architecture where each provider stores its complete configuration and
shared settings are managed via a separate snippet mechanism.

Reverted commits:
- 24fa8a18: context-aware JSON editor hint + hide quick toggles
- 87604b18: hide ClaudeQuickToggles when creating
- 992dda5c: partial key-field merging refactoring

Restored:
- Full config snapshot write (write_live_snapshot) for Claude/Codex/Gemini
- Full config backfill (settings_config = live_config)
- Common Config Snippet UI and backend commands
- 6 frontend components/hooks for common config editing
- configApi barrel export and DB snippet methods

Removed:
- ClaudeQuickToggles component
- write_live_partial / backfill_key_fields / patch_claude_live
- All KEY_FIELDS constants
2026-02-27 23:12:34 +08:00
Jason Young 992dda5c5c refactor(provider): switch from full config overwrite to partial key-field merging (#1098)
* refactor(provider): switch from full config overwrite to partial key-field merging

Replace the provider switching mechanism for Claude/Codex/Gemini from
full settings_config overwrite to partial key-field replacement, preserving
user's non-provider settings (plugins, MCP, permissions, etc.) across switches.

- Add write_live_partial() with per-app implementations for Claude (JSON env
  merge), Codex (auth replace + TOML partial merge), and Gemini (env merge)
- Add backfill_key_fields() to extract only provider-specific fields when
  saving live config back to provider entries
- Update switch_normal, sync_current_to_live, add, update to use partial merge
- Remove common config snippet feature for Claude/Codex/Gemini (no longer
  needed with partial merging); preserve OMO common config
- Delete 6 frontend files (3 components + 3 hooks), clean up 11 modified files
- Remove backend extract_common_config_* methods, 3 Tauri commands,
  CommonConfigSnippets struct, and related migration code
- Update integration tests to validate key-field-only backfill behavior

* refactor(cleanup): remove dead code and redundant MCP sync after partial-merge refactor

- Remove ConfigService legacy full-overwrite sync methods (~150 lines)
- Remove redundant McpService::sync_all_enabled from switch_normal
- Switch proxy fallback recovery from write_live_snapshot to write_live_partial
- Remove dead ProviderService::write_gemini_live wrapper
- Update tests to reflect partial-merge behavior (MCP preserved, not re-synced)

* feat(claude): add Quick Toggles for common Claude Code preferences

Add checkbox toggles for hideAttribution, alwaysThinking, and
enableTeammates that write directly to the live settings file via
RFC 7396 JSON Merge Patch. Mirror changes to the form editor using
form.watch for reactive updates.

* fix(provider): add missing key fields to partial-merge constants

Add provider-specific fields verified against official docs to prevent
key residue or loss during provider switching:

- Claude: CLAUDE_CODE_SUBAGENT_MODEL (env), model (top-level)
- Codex: review_model, plan_mode_reasoning_effort
- Gemini: GOOGLE_API_KEY (official alternative to GEMINI_API_KEY)

* fix(provider): expand partial-merge key fields for Bedrock, Vertex, Foundry and behavior settings

Add missing env/top-level fields to CLAUDE_KEY_ENV_FIELDS and
CLAUDE_KEY_TOP_LEVEL so that provider switching correctly replaces
(and clears) credentials and flags for AWS Bedrock, Google Vertex AI,
Microsoft Foundry, and provider behavior overrides like max output
tokens and prompt caching.

* feat(provider): add auth field selector for Claude providers (AUTH_TOKEN / API_KEY)

Allow users to choose between ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY
when creating or editing custom Claude providers, persisted in meta.apiKeyField.

* refactor(preset): remove AiHubMix hardcoded API_KEY in favor of generic auth selector

AiHubMix was the only preset that hardcoded ANTHROPIC_API_KEY before the
generic auth field selector was introduced. Now that users can freely
choose between AUTH_TOKEN and API_KEY via the UI, remove the special-case
and default AiHubMix to the standard ANTHROPIC_AUTH_TOKEN.
2026-02-23 21:57:04 +08:00
Jason 7ea2c3452b feat(opencode): complete Phase 4 - MCP sync module
Add mcp/opencode.rs with format conversion between CC Switch and OpenCode:
- stdio ↔ local type conversion
- command+args ↔ command array format
- env ↔ environment field mapping
- sse/http ↔ remote type conversion

Public API:
- sync_enabled_to_opencode: Batch sync all enabled servers
- sync_single_server_to_opencode: Sync individual server
- remove_server_from_opencode: Remove from live config
- import_from_opencode: Import servers from OpenCode config

Also fix test files to include new opencode field in McpApps struct.
All 4 unit tests pass for format conversion.
2026-01-15 16:11:25 +08:00
YoVinchen 7db4b8d976 feat(skill): implement recursive scanning for skill repositories (#309)
Add recursive directory scanning to discover SKILL.md files in nested
directories. When a SKILL.md is found, treat sibling directories as
functional folders rather than separate skills.
2025-11-28 12:01:20 +08:00
Jason 2a842e3b33 fix(provider): add backfill and Gemini security flags to switch function
The switch function was missing two important features after the SQLite
migration:

1. Backfill mechanism: Before switching providers, read the current live
   config and save it back to the current provider. This preserves any
   manual edits users made to the live config file.

2. Gemini security flags: When switching to a Gemini provider, set the
   appropriate security.auth.selectedType:
   - PackyCode providers: "gemini-api-key"
   - Google OAuth providers: "oauth-personal"

Also update tests to:
- Use the new unified MCP structure (mcp.servers) instead of the legacy
  per-app structure (mcp.codex.servers)
- Expect backfill behavior (was incorrectly marked as "no backfill")
- Remove assertions for provider-specific file deletion (v3.7.0+ uses
  SSOT, no longer creates per-provider config files)
2025-11-25 11:16:50 +08:00
Jason 1c87c8d253 Merge feat/sqlite-migration: add database schema migration system
This merge brings the SQLite migration system from feat/sqlite-migration branch:

## New Features
- Schema version control with SCHEMA_VERSION constant
- Automatic migration of missing columns for providers table
- Dry-run validation mode for schema compatibility checks
- JSON→SQLite migration feature gate (CC_SWITCH_ENABLE_JSON_DB_MIGRATION)
- Settings reload mechanism after imports

## Test Updates
- Updated tests to use SQLite database instead of config.json
- Removed obsolete import_config_from_path tests (replaced by db.import_sql)
- Fixed MCP tests to use unified McpServer structure (v3.7.0+)
- Updated provider switch tests to reflect no-backfill behavior
- Adjusted error type matching for new error variants
2025-11-25 10:33:54 +08:00
Jason 67aa275599 test: migrate tests to SQLite database architecture
This commit refactors all tests to work with the new database-based
architecture, replacing the previous JSON config approach.

Key changes:
- Add Database export to lib.rs for test access
- Create test helper functions in support.rs:
  - create_test_state(): Creates empty test state with fresh DB
  - create_test_state_with_config(): Migrates JSON config to DB
- Fix environment isolation in provider_service tests:
  - provider_service_switch_missing_provider_returns_error
  - provider_service_switch_codex_missing_auth_returns_error
- Replace ignored export tests with working alternatives:
  - export_sql_writes_to_target_path (tests Database::export_sql)
  - export_sql_returns_error_for_invalid_path (tests error handling)
- Update error type matching to align with current implementation

All tests now:
- Use isolated test environments (test_mutex + reset_test_fs)
- Access data via Database API instead of RwLock<MultiAppConfig>
- Work with SQLite persistence layer
- Pass without environment pollution or race conditions

Fixes test compilation errors after database migration.
2025-11-24 12:24:41 +08:00
Jason 7b1a68ee4e refactor(backend): phase 5 - optimize concurrency with RwLock and async IO
Replace Mutex with RwLock for AppState.config to enable concurrent reads,
improving performance for tray menu building and query operations that
previously blocked each other unnecessarily.

Key changes:
- Migrate AppState.config from Mutex<MultiAppConfig> to RwLock<MultiAppConfig>
- Distinguish read-only operations (read()) from mutations (write()) across
  all command handlers and service layers
- Offload blocking file I/O in import/export commands to spawn_blocking threads,
  minimizing lock hold time and preventing main thread blocking
- Extract load_config_for_import() to separate I/O logic from state updates
- Update all integration tests to use RwLock semantics

Performance impact:
- Concurrent reads: Multiple threads can now query config simultaneously
  (tray menu, provider list, MCP config)
- Reduced contention: Write locks only acquired during actual mutations
- Non-blocking I/O: Config import/export no longer freezes UI thread

All existing tests pass with new locking semantics.
2025-10-28 12:23:44 +08:00
Jason 7e27f88154 refactor(backend): phase 4 - add test hooks and extend service layer
- Extract internal functions in commands/mcp.rs and commands/provider.rs
  to enable unit testing without Tauri context
- Add test hooks: set_mcp_enabled_test_hook, import_mcp_from_claude_test_hook,
  import_mcp_from_codex_test_hook, import_default_config_test_hook
- Migrate error types from String to AppError for precise error matching in tests
- Extend ProviderService with delete() method to unify Codex/Claude cleanup logic
- Add comprehensive test coverage:
  - tests/mcp_commands.rs: command-level tests for MCP operations
  - tests/provider_service.rs: service-level tests for switch/delete operations
- Run cargo fmt to fix formatting issues (EOF newlines)
- Update BACKEND_REFACTOR_PLAN.md to mark phase 3 complete
2025-10-28 11:58:57 +08:00
Jason c2e8855a0f refactor(backend): phase 4 - extract provider service layer
Architecture improvements:
- Extract ProviderService with switch/backfill/write methods
- Reduce command layer from 160 to 13 lines via delegation
- Separate business logic (services) from state management (commands)
- Introduce precise error handling with structured validation

Refactoring details:
- Split Codex/Claude switching into symmetric private methods
- Add multi-layer validation for Codex auth field (existence + type)
- Extract import_config_from_path for command and test reuse
- Expose export_config_to_file and ProviderService in public API

Test coverage:
- Add 10+ integration tests for Claude/Codex switching flows
- Cover import/export success and failure scenarios (JSON parse, missing file)
- Verify state consistency on error paths (current remains unchanged)
- Test snapshot backfill for both old and new providers after switching
2025-10-28 10:47:48 +08:00
Jason 8e980e6974 refactor(backend): phase 3 - unify error handling and fix backup timestamp bug
Key improvements:
- Extract switch_provider_internal() returning AppError for better testability
- Fix backup mtime inheritance: use read+write instead of fs::copy to ensure latest backup survives cleanup
- Add 15+ integration tests covering provider commands, atomic writes, and rollback scenarios
- Expose write_codex_live_atomic, AppState, and test hooks in public API
- Extract tests/support.rs with isolated HOME and mutex utilities

Test coverage:
- Provider switching with live config backfill and MCP sync
- Codex atomic write success and failure rollback
- Backup retention policy with proper mtime ordering
- Negative cases: missing auth field, invalid provider ID
2025-10-28 09:55:10 +08:00