feat: add Hermes frontend types, API layer, and hooks (Phase 7)

- Add "hermes" to AppId union type and all exhaustive Record<AppId>
- Add HermesModelConfig, HermesAgentConfig, HermesEnvConfig types
- Add hermes field to VisibleApps, McpApps, ProxyTakeoverStatus
- Create src/lib/api/hermes.ts with Tauri invoke wrappers
- Create src/hooks/useHermes.ts with 5 query + 3 mutation hooks
- Register hermes in APP_IDS, APP_ICON_MAP (violet color scheme)
- Split MCP_SKILLS_APP_IDS into MCP_APP_IDS (includes hermes) and
  SKILLS_APP_IDS (excludes hermes, since Hermes has no Skills support)
- Wire hermes additive-mode into App.tsx (remove/duplicate handlers),
  ProviderList.tsx (live provider ID query + In Config badge),
  mutations.ts (cache invalidation on switch/add/delete)
- Add Hermes checkbox to McpFormModal
- Add basic hermes i18n keys (en/zh/ja)
This commit is contained in:
Jason
2026-04-15 17:41:33 +08:00
parent 576ff53a75
commit a0b585992a
23 changed files with 467 additions and 33 deletions
+17 -6
View File
@@ -31,7 +31,7 @@ import type { AppId } from "@/lib/api/types";
import { ConfirmDialog } from "@/components/ConfirmDialog";
import { settingsApi, skillsApi } from "@/lib/api";
import { toast } from "sonner";
import { MCP_SKILLS_APP_IDS } from "@/config/appConfig";
import { SKILLS_APP_IDS } from "@/config/appConfig";
import { AppCountBar } from "@/components/common/AppCountBar";
import { AppToggleGroup } from "@/components/common/AppToggleGroup";
import { ListItemRow } from "@/components/common/ListItemRow";
@@ -113,10 +113,17 @@ const UnifiedSkillsPanel = React.forwardRef<
}, [skillUpdates]);
const enabledCounts = useMemo(() => {
const counts = { claude: 0, codex: 0, gemini: 0, opencode: 0, openclaw: 0 };
const counts = {
claude: 0,
codex: 0,
gemini: 0,
opencode: 0,
openclaw: 0,
hermes: 0,
};
if (!skills) return counts;
skills.forEach((skill) => {
for (const app of MCP_SKILLS_APP_IDS) {
for (const app of SKILLS_APP_IDS) {
if (skill.apps[app]) counts[app]++;
}
});
@@ -342,7 +349,7 @@ const UnifiedSkillsPanel = React.forwardRef<
<AppCountBar
totalLabel={t("skills.installed", { count: skills?.length || 0 })}
counts={enabledCounts}
appIds={MCP_SKILLS_APP_IDS}
appIds={SKILLS_APP_IDS}
/>
<div className="flex items-center gap-1.5">
<div
@@ -546,7 +553,7 @@ const InstalledSkillListItem: React.FC<InstalledSkillListItemProps> = ({
<AppToggleGroup
apps={skill.apps}
onToggle={(app, enabled) => onToggleApp(skill.id, app, enabled)}
appIds={MCP_SKILLS_APP_IDS}
appIds={SKILLS_APP_IDS}
/>
<div
@@ -736,6 +743,7 @@ const ImportSkillsDialog: React.FC<ImportSkillsDialogProps> = ({
gemini: skill.foundIn.includes("gemini"),
opencode: skill.foundIn.includes("opencode"),
openclaw: false,
hermes: skill.foundIn.includes("hermes"),
},
]),
),
@@ -761,6 +769,7 @@ const ImportSkillsDialog: React.FC<ImportSkillsDialogProps> = ({
gemini: false,
opencode: false,
openclaw: false,
hermes: false,
},
})),
);
@@ -803,6 +812,7 @@ const ImportSkillsDialog: React.FC<ImportSkillsDialogProps> = ({
gemini: false,
opencode: false,
openclaw: false,
hermes: false,
}
}
onToggle={(app, enabled) => {
@@ -815,12 +825,13 @@ const ImportSkillsDialog: React.FC<ImportSkillsDialogProps> = ({
gemini: false,
opencode: false,
openclaw: false,
hermes: false,
}),
[app]: enabled,
},
}));
}}
appIds={MCP_SKILLS_APP_IDS}
appIds={SKILLS_APP_IDS}
/>
</div>
<div