Skip to content

Fit/merge forked#196

Closed
handy-sun wants to merge 119 commits into
SaladDay:mainfrom
handy-sun:fit/merge-forked
Closed

Fit/merge forked#196
handy-sun wants to merge 119 commits into
SaladDay:mainfrom
handy-sun:fit/merge-forked

Conversation

@handy-sun
Copy link
Copy Markdown

@handy-sun handy-sun commented May 21, 2026

Sorry, I accidentally clicked the wrong one,i donnot want to merge

handy-sun added 30 commits May 7, 2026 21:25
…ypes

- Add Hermes to AppType enum with additive mode support
- Wire Hermes through McpApps, SkillApps, CommonConfigSnippets, PromptRoot
- Add hermes field to VisibleApps (default: false)
- Add hermes_config_dir and current_provider_hermes to AppSettings
- Add get_hermes_override_dir() to settings module
- Add Hermes branch to sync_policy::should_sync_live()
- Add Hermes prompt file path (~/.hermes/AGENTS.md)
- Fix SkillApps initializers in skills DAO
- Add Hermes color theme (LightYellow/BrightYellow)
…CLI match arms

- Add Hermes branches to all match statements across 12 files
- services/provider: mod.rs, common_config.rs, live.rs, usage.rs
- services: prompt.rs, mcp.rs, config.rs
- cli/tui: helpers.rs
- deeplink, proxy, store
- LiveSnapshot enum adds Hermes variant with config field
- Additive-mode apps use unreachable!() for switch/delete paths
- Config read/write stubs marked TODO for Tier 2 hermes_config
…d service match arms

- cli/commands: config_common, mcp, provider_input, provider_inspect
- cli/tui: data, form (provider_json, provider_state, provider_state_loading, provider_templates), runtime_actions, theme
- services: skill, stream_check (provider_extract, service)
- All additive-mode paths use empty blocks or TODO stubs
- LiveSnapshot::Hermes variant added with config field
- Hermes skills dir: ~/.hermes/skills
- Hermes accent color: DRACULA_YELLOW
Remove fmt job from rust-ci.yml; add .githooks/pre-commit that runs rustfmt --check on staged .rs files. Set core.hooksPath to .githooks.
Port hermes_config.rs from desktop (config read/write, provider CRUD, MCP section, memory files)
Add Hermes MCP format conversion (stdio/HTTP <-> YAML) with merge-on-write
Wire provider services: refresh_from_live, read_app_config, live_write, validation
Wire usage extraction: api_key, base_url for Hermes providers
Wire stream check: model, base_url, auth extraction from Hermes config
Wire MCP services: sync_server, remove_server, import_from_hermes
…terals

test files create VisibleApps and SkillApps struct literals that now
require the hermes field after Tier 2 added it to the definitions;
also add Hermes variant to test-local AppType enums
- replace fmt-only check with clippy (ubuntu/macos/windows) + test (ubuntu/macos/windows)
- add Linux system deps for GTK/WebKit/Soup
- add frontend dist placeholder for Tauri build
- keep failover-e2e job with matching deps
- trigger on feat/** branches for early CI feedback
- config: save/restore settings for config_dir tests (fixes pollution
  from preceding env_overrides_settings)
- hermes_config: preserve old test_home_override in with_test_home,
  use global lock_test_home_and_settings() mutex
- cli/tui/app/tests: #[cfg(unix)] on symlink-based tests (Windows fix)
- codex_oauth: new lock_codex_oauth_test() mutex, flavor=current_thread
  for affected tests (replaces unreliable serial_test)
- streaming failover: flavor=current_thread + global mutex
- Add FIXME comments documenting env::set_var root cause (35 call sites)
- Add src-tauri/flake.nix with devShell providing cargo-zigbuild, zig,
  cmake, rustup, and cargo-watch
- Auto-installs rustup stable toolchain and cross-compilation targets
  (x86_64/aarch64-linux-gnu, aarch64-apple-darwin on macOS) in shellHook
- rust-toolchain.toml: channel 1.91.1 -> stable (aligned with flake shell)
- No container runtime needed: zig serves as C cross-compiler for
  rusqlite bundled SQLite and rquickjs QuickJS

Usage:
  cd src-tauri && nix develop
  cargo zigbuild --target x86_64-unknown-linux-gnu --release
  cargo zigbuild --target aarch64-unknown-linux-gnu --release
ConfigDirEnvGuard and TempHome now hold the test-home mutex internally
and call set_test_home_override, matching the TestHomeEnvGuard pattern
from services/proxy.rs. The 3 known-flaky tests (env::set_var races
across ~35 concurrent tests) are marked #[ignore] with instructions to
run single-threaded. 2 integration tests in import_export_sync.rs still
fail (pre-existing, root cause unrelated to this change).
import_openclaw_providers_from_live stores to state.db, not state.config.
Both integration tests incorrectly asserted against state.config, which
was never updated by the import. Switch to state.db.get_provider_by_id
and get_provider_ids to match the actual storage backend.
… CLI commands

- provider_state_loading: reuse openclaw form (same additive-mode fields)
- provider_templates: add PROVIDER_TEMPLATE_DEFS_HERMES with Custom preset
- provider_templates: implement preset application (identical to OpenClaw)
- provider_state: add Hermes provider fields (apiKey, baseUrl, user-agent, models)
- provider_state: exclude Hermes from common config (additive mode)
- provider_json: implement full JSON builder (identical to OpenClaw)
- data: add API URL extraction (baseUrl)
- provider_inspect: implement model fetch with bearer auth
- provider_input: implement display config (apiKey, baseUrl, models count)
- stream_check: remove TODO (codex_stream fallback is correct)
Schema and migration (v9->v10) already had the column; DAO layer was
hardcoding hermes: false. Now reads/writes enabled_hermes from DB in
get_all_installed_skills, get_installed_skill, save_skill, and
update_skill_apps.
Six locations had hardcoded app arrays missing Hermes:
- pickers.rs: MCP, visible apps, and skills app picker overlays
- store.rs: DB-to-config export and config-to-DB persist loops
- app_config.rs: prompt auto-import loop
- runtime_actions/mcp.rs: MCP sync toggle loop
- services/skill.rs: supported_skill_apps and skill removal loop
- app_type_for_picker_index: add index 5 => Hermes
- handle_visible_apps_picker_key: .min(4) -> .min(5) for 6 apps
- handle_mcp_apps_picker_key: .min(3) -> .min(4) for 5 apps
- handle_skills_apps_picker_key: .min(3) -> .min(4) for 5 apps
Extract MCP_PICKER_APPS, VISIBLE_PICKER_APPS, SKILLS_PICKER_APPS consts; handlers use .len()-1 and array indexing instead of magic numbers. Add Copy derive to AppType.
src-tauri/rust-toolchain.toml pins channel to stable (to stay aligned
with the nix devShell). dtolnay/rust-toolchain installs the matrix
target onto env.RUST_VERSION (1.91.1), but cargo invoked under
src-tauri/ auto-switches to the stable toolchain which does not inherit
that target. On macos-14 arm64 runners the darwin-x64 cross build then
fails with 'can't find crate for core'.

Add an explicit 'rustup target add' step running in src-tauri/ so the
target lands on the stable toolchain that cargo will actually use.
Guarded by use_cross != true to skip cross-docker builds.
- Switch from implicit host-target cargo build to explicit --target
- Add 3 targets: linux-x64-musl, linux-arm64-musl, macos-x64
- Use cross for musl/ARM64 targets (same as release)
- Add rustup target add step for rust-toolchain.toml mismatch
- Update artifact paths and cache keys per target
The function was defined but never called — prompt editing is fully
implemented via submit_prompt_edit / edit_prompt.
v5.5.0: Hermes Agent, prompt create/rename, failover controls,
Nix flake, Anthropic header stripping, live provider import

v5.5.1: minisign keypair replacement, CI cross-target fix
MCP table header, data rows, summary bar, and column widths all
rendered only 4 apps (Claude/Codex/Gemini/OpenCode). Add Hermes
as the 5th column with active/inactive markers and summary count.
handy-sun added 29 commits May 13, 2026 18:11
Bump the cc-switch-tui crate version from 0.1.1 to 0.1.2 and keep Cargo.lock aligned so the tagged release workflow can validate GITHUB_REF_NAME against Cargo metadata.

Refresh README badges and the fork-specific changelog with the OpenClaw MCP, local environment version display, skills visual selection, and agent import fixes shipped since v0.1.1.

Update the GitHub Release body product description to include Hermes alongside the other supported assistants.

Verified with: cargo fmt --check; cargo metadata --no-deps --format-version 1; cargo test --locked; git diff --check. crates.io returned 404 for cc-switch-tui/0.1.2 before tagging.
Implement a Codex-only provider catalog flow that keeps TUI-managed custom providers mirrored into the live ~/.codex/config.toml [model_providers.*] table.

Add import support for the Codex Providers page so pressing i reads all recognizable providers from the current live config, merges them by stable catalog key first, falls back to an exact name merge when the key is missing, and creates new saved providers for the remaining entries.

Keep current-provider semantics separate from catalog import. Importing live providers updates the saved provider set only and does not implicitly switch the active Codex provider.

Preserve existing compatibility guarantees around Codex common-config handling by making live catalog sync tolerant of broken legacy snapshots. Invalid saved provider TOML is skipped with a warning instead of aborting unrelated Codex operations such as switching providers or updating common snippets.

Also add TUI copy and regression coverage for the new Codex-only import affordance, stable-alias deduplication during import, and catalog synchronization back into live config.
- primary_codex_model_provider_id_with_table(): find the single
  provider key that owns a [model_providers.<key>] table
- rewrite_codex_config_model_provider_key(): rename a provider table
  key, rewrite profile references, and update root model_provider
When multiple custom providers share the 'custom' key in
[model_providers], the catalog sync would overwrite entries. Now:

- compact_codex_key_suffix / unique_codex_provider_key_for_conflict:
  generate unique keys from provider id/name
- rewrite_provider_codex_model_provider_key: rewrite a Provider's
  stored key + settings config
- repair_conflicting_custom_codex_provider_keys: detect and fix
  duplicate 'custom' keys before sync
- collect_codex_providers_for_live_sync: run repair then collect
- Both sync entry points now acquire write lock and run repair
  before catalog write
Set up two providers both using key 'custom', switch to the second,
and verify both get unique keys (codex_provider / uuid-derived) in
the stored data and live config.toml.
…tches

When the user temporarily disables an MCP server (or anything else) by
commenting out a whole subtable in `~/.codex/config.toml`, switching
providers used to silently drop those comment lines. From the user's
perspective, sections they had intentionally turned off would either
disappear or — worse — be perceived as reopened on the next switch.

Root cause: `write_codex_live` previously replaced the entire
config.toml from the stored snapshot, and the recently-added merge
helper rebuilt the document *from the snapshot* and then cloned the
live `[mcp_servers]` Item back in. In toml_edit's model, comment-only
lines that trail the last `[mcp_servers.x]` subtable (e.g. a disabled
`# [mcp_servers.disabled]` block) are attached to the **document-level
trailing decor**, not to any subtable's decor — so cloning the Item
left them behind.

Fix: invert the merge strategy. Edit the **live** document in place
and only overlay entries the snapshot explicitly provides:

- `[mcp_servers]` is never overwritten by the snapshot. The user's
  live content, including any commented-out subtables and loose
  comments around them, is preserved verbatim.
- Live entries the snapshot does not cover are removed, so the
  previous provider's `[projects]` / `[model_providers.OLD]` don't
  leak into the new live config (provider isolation).
- Root-level preference keys (`approval_mode`,
  `disable_response_storage`, `model_reasoning_effort`,
  `check_for_update_on_startup`) follow `preserve_user_preferences`:
    - true (provider switch with applyCommonConfig honored): live
      wins when present, falls back to snapshot otherwise so initial
      writes still seed merged common-snippet defaults.
    - false (common-snippet clear, or `applyCommonConfig=false` on
      the target provider): snapshot drives; live keys absent from
      the snapshot are removed so old snippet residue doesn't bleed.

In `write_codex_live`, `preserve_live_preferences` is now ANDed with
the effective `apply_common_config`. A provider that explicitly opts
out of the common snippet must also wipe any snippet preferences left
in the live config by a previous provider — otherwise the toggle has
no observable effect on existing keys.

Adds tests in `codex_config.rs` covering:

- commented-out `[mcp_servers.x]` blocks and inline comments survive
  a provider switch verbatim (the regression that motivated this fix);
- preferences seeded from snapshot when live is empty;
- `preserve=false` drops live preference keys missing from snapshot;
- existing user-preference and mcp preservation behavior.

Dev-only: adds `indoc = "2"` to dev-dependencies for readable TOML
fixtures in the new tests.
…ches

Add a test that covers comment patterns the user is likely to keep in
~/.codex/config.toml at the root level:

- a header comment attached as prefix decor to an existing key
  (`# pinned by me — do not change ...` above `model_provider`),
- a commented-out root key
  (`# disable_response_storage = true` between two live keys),
- a trailing footnote at EOF.

These all survive a provider switch because the new in-place merge
overwrites only the value side of existing live keys via toml_edit's
IndexMut, leaving the key's prefix decor intact; trailing decor is
document-level and untouched by entry replacement.

Updates the merge helper's docstring to spell out the exact set of
comment shapes that are preserved, so future readers don't need to
re-derive the toml_edit decor rules.

No behavior change.
…coped blacklist

The merge helper previously had a hardcoded PREFERENCE_KEYS list naming
the four preference keys it knew about. Everything not on that list was
treated as provider-scoped: if the snapshot didn't include the key, it
was wiped from the live config on a provider switch. That works for the
keys we currently track, but it bakes a maintenance burden into the
file: every time Codex adds a new root-level preference (e.g.
`sandbox_mode`, `verbose_logging`, …) we'd have to remember to extend
PREFERENCE_KEYS, otherwise the user's live setting would be silently
discarded on the next switch.

Flip the polarity: introduce a small PROVIDER_SCOPED_KEYS blacklist
naming the keys that **must** hard-sync with the active provider's
snapshot — `model_provider`, `model`, `model_providers`, `projects`.
Anything not in this list is user-owned and follows the existing
`preserve_user_preferences` rule (live wins on switch when present,
seeded from snapshot otherwise; cleared on snippet-driven writes).

Why this is the right default:

- A new Codex root preference is the much more common future change
  than a new provider-scoped table — and the cost of the wrong default
  is asymmetric: misclassifying a preference as provider-scoped loses
  user data on switch, while misclassifying a provider-scoped key as
  user-owned at worst leaks one inert value between providers (and a
  later writer of the same key overwrites it). User data > residue.
- The blacklist is short and grounded in observable behavior — these
  are the only keys whose value must change on every provider switch
  — so it's far easier to keep correct than an open-ended whitelist
  of "all the preferences we know about today."

No behavior change for the currently-tracked four preference keys; all
existing merge tests pass as-is. Adds `merge_keeps_unknown_root_keys_from_live_on_switch`
as a forward-compatibility regression guard simulating a future
unknown preference (`sandbox_mode`, `verbose_logging`).
Detect when Codex config.toml points at a provider that differs from cc-switch's stored current provider and surface that choice in the TUI.

Backfill the actual live provider snapshot before switching, write normal provider switches with the selected model_provider id, and preserve live user preferences/MCP edits instead of resyncing managed MCP over them.

Add startup, service, command, and TUI coverage for stale current-provider and live-edit preservation cases.
fix(codex): preserve live config and resolve current drift
Provider switching in the TUI was blocked whenever automatic failover was enabled for the app. That made a stale DB flag behave like an active failover lock even when the local proxy was stopped and no traffic was being routed through cc-switch.
Limit the provider switch guard to the actual runtime condition: automatic failover must be enabled and the local proxy must be routing the current app. When the proxy is inactive, users can switch providers normally even if the failover preference remains enabled.
Also align the provider list marker with the same active-proxy condition so an inactive proxy shows the current provider marker instead of queue membership.
Tests cover inactive-proxy provider switching and provider-list rendering while preserving the active-proxy failover guard.
Absorbed upstream commits:

- 5c6d373 Fix broken internal documentation links (SaladDay#167)

- d36070b (tui)refine footer shortcuts

- 371f422 (prompt)stabilize prompt list order

Recorded skipped upstream commits:

- 64cbca7 (docs) update RightCode rebate to 5%

- d3c240c feat: add CODEX_HOME support (SaladDay#179)
Absorbed upstream commit:

- 73b7c3c fix(webdav): avoid upload readback checks

Behavior changes:

- Remove the WebDAV check_connection probe write/read/delete round trip.

- Stop gating uploads on a post-PUT manifest GET readback.

- Keep manifest HEAD lookup as best-effort metadata only.

- Avoid cleanup of legacy V1 remote data after a plain upload.

Recorded but not absorbed in this high-risk pass:

- 8330715 Improve failover proxy UX: touches failover policy, proxy lifecycle, DB schema/DAO, provider routing, and TUI UX; conflicts with local failover guard behavior.

- 6ff4f88, 8afd907, d3810be, 3fa2723 prompt series: needs a separate prompt-service/form migration because current prompt service and TUI form structure diverge.

- 65c4dc7..d160b16 provider common config series: conflicts with local Hermes/OpenClaw provider common-config behavior and live-write boundaries.

- a1dd240 usage query configuration: large multi-service/TUI/provider-form feature, not suitable for the WebDAV fix batch.

Verification:

- cargo fmt --manifest-path src-tauri/Cargo.toml --check

- git diff --check --cached

- cargo test --manifest-path src-tauri/Cargo.toml --test webdav_sync_service
Reviewed but did not absorb upstream commits:

- 8330715

- 6ff4f88, 8afd907, d3810be, 3fa2723

- 65c4dc7, ee155e6, a5914cd, fa96c24, 8e311ee, d160b16

- a1dd240

Also records 73b7c3c as absorbed by local commit 20c949f.
Hermes provider switching writes the selected provider to the live custom_providers list before applying top-level model defaults. The write path sanitizes UI and DeepLink payloads from baseUrl/apiKey to Hermes' base_url/api_key schema, but apply_switch_defaults was still reading the original unsanitized settings_config and only looking for snake_case keys.

That meant switching providers could update model.provider and model.default while leaving model.base_url and model.api_key from the previously active provider. The runtime could then continue routing through the old endpoint or auth token even though the selected provider name and model changed.

Update apply_switch_defaults to accept both snake_case and camelCase credential keys, replace top-level model credentials from the selected provider, and clear stale credentials when the selected provider does not provide them. Model tuning fields such as context_length and max_tokens continue to survive provider switches.

Add focused Hermes config tests for camelCase credentials and stale credential clearing, and strengthen the ProviderService switch regression to exercise the real UI/DeepLink camelCase payload shape while asserting the live Hermes provider is persisted in canonical snake_case.

Verification: cargo fmt --manifest-path src-tauri/Cargo.toml --check; git diff --check; cargo test apply_switch_defaults --manifest-path src-tauri/Cargo.toml; cargo test hermes_switch_updates_live_model_provider_and_default --manifest-path src-tauri/Cargo.toml; cargo test hermes_config::tests --lib --manifest-path src-tauri/Cargo.toml
@handy-sun handy-sun closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant