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
+8 -7
View File
@@ -455,13 +455,14 @@ describe("useSettings hook", () => {
expect(settingsFormMock.syncLanguage).toHaveBeenCalledWith(
settingsFormMock.initialLanguage,
);
expect(directorySettingsMock.resetAllDirectories).toHaveBeenCalledWith(
"/server/claude",
undefined,
"/server/gemini",
"/server/opencode",
"/server/openclaw",
);
expect(directorySettingsMock.resetAllDirectories).toHaveBeenCalledWith({
claude: "/server/claude",
codex: undefined,
gemini: "/server/gemini",
opencode: "/server/opencode",
openclaw: "/server/openclaw",
hermes: undefined,
});
expect(metadataMock.setRequiresRestart).toHaveBeenCalledWith(false);
});