mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-30 02:14:43 +08:00
feat(omo): integrate Oh My OpenCode profile management (#972)
* feat(omo): integrate Oh My OpenCode profile management into Provider system Adds full-stack OMO support: backend config read/write/import, OMO-specific provider CRUD with exclusive switching, frontend profile editor with agent/category/model configuration, global config management, and i18n support. * feat(omo): add model/variant dropdowns from enabled providers Replace model text inputs with Select dropdowns sourced from enabled OpenCode providers, add thinking-level variant selection, and prevent auto-enabling newly added OMO providers. * fix(omo): use standard provider action styles for OMO switch button * fix(omo): replace hardcoded isZh strings with proper i18n t() calls
This commit is contained in:
+28
-14
@@ -17,13 +17,15 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
let id: string;
|
||||
|
||||
if (appId === "opencode") {
|
||||
// OpenCode: use user-provided providerKey as ID
|
||||
if (!providerInput.providerKey) {
|
||||
throw new Error("Provider key is required for OpenCode");
|
||||
if (providerInput.category === "omo") {
|
||||
id = `omo-${generateUUID()}`;
|
||||
} else {
|
||||
if (!providerInput.providerKey) {
|
||||
throw new Error("Provider key is required for OpenCode");
|
||||
}
|
||||
id = providerInput.providerKey;
|
||||
}
|
||||
id = providerInput.providerKey;
|
||||
} else {
|
||||
// Other apps: use random UUID
|
||||
id = generateUUID();
|
||||
}
|
||||
|
||||
@@ -32,7 +34,6 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
id,
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
// Remove providerKey from the provider object before saving
|
||||
delete (newProvider as any).providerKey;
|
||||
|
||||
await providersApi.add(newProvider, appId);
|
||||
@@ -41,7 +42,15 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
||||
|
||||
// 更新托盘菜单(失败不影响主操作)
|
||||
if (appId === "opencode") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["omo", "current-provider-id"],
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["omo", "provider-count"],
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
} catch (trayError) {
|
||||
@@ -115,7 +124,15 @@ export const useDeleteProviderMutation = (appId: AppId) => {
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
||||
|
||||
// 更新托盘菜单(失败不影响主操作)
|
||||
if (appId === "opencode") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["omo", "current-provider-id"],
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["omo", "provider-count"],
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
} catch (trayError) {
|
||||
@@ -157,14 +174,15 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
||||
|
||||
// OpenCode: also invalidate live provider IDs cache to update button state
|
||||
if (appId === "opencode") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["opencodeLiveProviderIds"],
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["omo", "current-provider-id"],
|
||||
});
|
||||
}
|
||||
|
||||
// 更新托盘菜单(失败不影响主操作)
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
} catch (trayError) {
|
||||
@@ -173,14 +191,10 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
trayError,
|
||||
);
|
||||
}
|
||||
|
||||
// Note: Success toast is handled by useProviderActions.switchProvider
|
||||
// to allow customization based on provider properties (e.g., apiFormat)
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
const detail = extractErrorMessage(error) || t("common.unknown");
|
||||
|
||||
// 标题与详情分离,便于扫描 + 一键复制
|
||||
toast.error(
|
||||
t("notifications.switchFailedTitle", { defaultValue: "切换失败" }),
|
||||
{
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { omoApi } from "@/lib/api/omo";
|
||||
import * as configApi from "@/lib/api/config";
|
||||
import type { OmoGlobalConfig } from "@/types/omo";
|
||||
|
||||
export const omoKeys = {
|
||||
all: ["omo"] as const,
|
||||
globalConfig: () => [...omoKeys.all, "global-config"] as const,
|
||||
currentProviderId: () => [...omoKeys.all, "current-provider-id"] as const,
|
||||
providerCount: () => [...omoKeys.all, "provider-count"] as const,
|
||||
};
|
||||
|
||||
function invalidateOmoQueries(queryClient: ReturnType<typeof useQueryClient>) {
|
||||
queryClient.invalidateQueries({ queryKey: omoKeys.globalConfig() });
|
||||
queryClient.invalidateQueries({ queryKey: ["providers"] });
|
||||
queryClient.invalidateQueries({ queryKey: omoKeys.currentProviderId() });
|
||||
queryClient.invalidateQueries({ queryKey: omoKeys.providerCount() });
|
||||
}
|
||||
|
||||
export function useOmoGlobalConfig(enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: omoKeys.globalConfig(),
|
||||
enabled,
|
||||
queryFn: async (): Promise<OmoGlobalConfig> => {
|
||||
const raw = await configApi.getCommonConfigSnippet("omo");
|
||||
if (!raw) {
|
||||
return {
|
||||
id: "global",
|
||||
disabledAgents: [],
|
||||
disabledMcps: [],
|
||||
disabledHooks: [],
|
||||
disabledSkills: [],
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
try {
|
||||
return JSON.parse(raw) as OmoGlobalConfig;
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[omo] invalid global config json, fallback to defaults",
|
||||
error,
|
||||
);
|
||||
return {
|
||||
id: "global",
|
||||
disabledAgents: [],
|
||||
disabledMcps: [],
|
||||
disabledHooks: [],
|
||||
disabledSkills: [],
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useCurrentOmoProviderId(enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: omoKeys.currentProviderId(),
|
||||
queryFn: omoApi.getCurrentOmoProviderId,
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
|
||||
export function useOmoProviderCount(enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: omoKeys.providerCount(),
|
||||
queryFn: omoApi.getOmoProviderCount,
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
|
||||
export function useSaveOmoGlobalConfig() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (input: OmoGlobalConfig) => {
|
||||
const jsonStr = JSON.stringify(input);
|
||||
await configApi.setCommonConfigSnippet("omo", jsonStr);
|
||||
},
|
||||
onSuccess: () => invalidateOmoQueries(queryClient),
|
||||
});
|
||||
}
|
||||
|
||||
export function useReadOmoLocalFile() {
|
||||
return useMutation({
|
||||
mutationFn: () => omoApi.readLocalFile(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useDisableCurrentOmo() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: () => omoApi.disableCurrentOmo(),
|
||||
onSuccess: () => invalidateOmoQueries(queryClient),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user