feat(settings): add Hermes config dir override with data-driven dispatch

Adds a dedicated Hermes row to the directory-override settings so users
can point CC Switch at alternate Hermes config locations (e.g. a second
profile directory for work/personal split). `get_config_dir` on the
Rust side already supports hermes; this just wires up the frontend row.

Wiring it through `useDirectorySettings` revealed a scaling problem:
every supported app required five parallel ternary chains across
`computeDefaultConfigDir`, `updateDirectory`, `browseDirectory`,
`resetDirectory`, and `updateDirectoryState`. Replaces those with two
lookup tables (`APP_DIRECTORY_META`, `DIRECTORY_KEY_TO_SETTINGS_FIELD`)
so adding the next app is two entries, not fifteen edit sites.

Drive-by cleanup from the same touch:
* `resetAllDirectories` takes a `ResolvedAppDirectoryOverrides` object
  instead of five positional optional strings.
* `setResolvedDirs` returns the same reference when the sanitized
  value is unchanged, so no-op edits don't cascade renders.

Also lands all i18n updates for this series (`hermesConfigDir` and
placeholder, Memory section's enable/disable/toggleFailed copy, and
the reworded `schemaMigratedV12` warning) in zh/en/ja together.
This commit is contained in:
Jason
2026-04-20 09:49:13 +08:00
parent 31fb998575
commit b8a3534cb5
9 changed files with 151 additions and 117 deletions
@@ -17,6 +17,7 @@ interface DirectorySettingsProps {
geminiDir?: string;
opencodeDir?: string;
openclawDir?: string;
hermesDir?: string;
onDirectoryChange: (app: AppId, value?: string) => void;
onBrowseDirectory: (app: AppId) => Promise<void>;
onResetDirectory: (app: AppId) => Promise<void>;
@@ -33,6 +34,7 @@ export function DirectorySettings({
geminiDir,
opencodeDir,
openclawDir,
hermesDir,
onDirectoryChange,
onBrowseDirectory,
onResetDirectory,
@@ -143,6 +145,17 @@ export function DirectorySettings({
onBrowse={() => onBrowseDirectory("openclaw")}
onReset={() => onResetDirectory("openclaw")}
/>
<DirectoryInput
label={t("settings.hermesConfigDir")}
description={undefined}
value={hermesDir}
resolvedValue={resolvedDirs.hermes}
placeholder={t("settings.browsePlaceholderHermes")}
onChange={(val) => onDirectoryChange("hermes", val)}
onBrowse={() => onBrowseDirectory("hermes")}
onReset={() => onResetDirectory("hermes")}
/>
</section>
</div>
);
+1
View File
@@ -317,6 +317,7 @@ export function SettingsPage({
geminiDir={settings.geminiConfigDir}
opencodeDir={settings.opencodeConfigDir}
openclawDir={settings.openclawConfigDir}
hermesDir={settings.hermesConfigDir}
onDirectoryChange={updateDirectory}
onBrowseDirectory={browseDirectory}
onResetDirectory={resetDirectory}