mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 08:44:41 +08:00
Merge branch 'main' into feat/smart-url-path-detection
# Conflicts: # src/App.tsx # src/hooks/useProviderActions.ts # src/i18n/locales/en.json # src/i18n/locales/ja.json # src/i18n/locales/zh.json
This commit is contained in:
@@ -7,7 +7,9 @@ export { skillsApi } from "./skills";
|
||||
export { usageApi } from "./usage";
|
||||
export { vscodeApi } from "./vscode";
|
||||
export { proxyApi } from "./proxy";
|
||||
export { openclawApi } from "./openclaw";
|
||||
export { sessionsApi } from "./sessions";
|
||||
export { workspaceApi } from "./workspace";
|
||||
export * as configApi from "./config";
|
||||
export type { ProviderSwitchEvent } from "./providers";
|
||||
export type { Prompt } from "./prompts";
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type {
|
||||
OpenClawDefaultModel,
|
||||
OpenClawModelCatalogEntry,
|
||||
OpenClawAgentsDefaults,
|
||||
OpenClawEnvConfig,
|
||||
OpenClawToolsConfig,
|
||||
} from "@/types";
|
||||
|
||||
/**
|
||||
* OpenClaw configuration API
|
||||
*
|
||||
* Manages ~/.openclaw/openclaw.json sections:
|
||||
* - agents.defaults (model, catalog)
|
||||
* - env (environment variables)
|
||||
* - tools (permissions)
|
||||
*/
|
||||
export const openclawApi = {
|
||||
// ============================================================
|
||||
// Agents Configuration
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get default model configuration (agents.defaults.model)
|
||||
*/
|
||||
async getDefaultModel(): Promise<OpenClawDefaultModel | null> {
|
||||
return await invoke("get_openclaw_default_model");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set default model configuration (agents.defaults.model)
|
||||
*/
|
||||
async setDefaultModel(model: OpenClawDefaultModel): Promise<void> {
|
||||
return await invoke("set_openclaw_default_model", { model });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get model catalog/allowlist (agents.defaults.models)
|
||||
*/
|
||||
async getModelCatalog(): Promise<Record<
|
||||
string,
|
||||
OpenClawModelCatalogEntry
|
||||
> | null> {
|
||||
return await invoke("get_openclaw_model_catalog");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set model catalog/allowlist (agents.defaults.models)
|
||||
*/
|
||||
async setModelCatalog(
|
||||
catalog: Record<string, OpenClawModelCatalogEntry>,
|
||||
): Promise<void> {
|
||||
return await invoke("set_openclaw_model_catalog", { catalog });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get full agents.defaults config (all fields)
|
||||
*/
|
||||
async getAgentsDefaults(): Promise<OpenClawAgentsDefaults | null> {
|
||||
return await invoke("get_openclaw_agents_defaults");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set full agents.defaults config (all fields)
|
||||
*/
|
||||
async setAgentsDefaults(defaults: OpenClawAgentsDefaults): Promise<void> {
|
||||
return await invoke("set_openclaw_agents_defaults", { defaults });
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// Env Configuration
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get env config (env section of openclaw.json)
|
||||
*/
|
||||
async getEnv(): Promise<OpenClawEnvConfig> {
|
||||
return await invoke("get_openclaw_env");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set env config (env section of openclaw.json)
|
||||
*/
|
||||
async setEnv(env: OpenClawEnvConfig): Promise<void> {
|
||||
return await invoke("set_openclaw_env", { env });
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// Tools Configuration
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get tools config (tools section of openclaw.json)
|
||||
*/
|
||||
async getTools(): Promise<OpenClawToolsConfig> {
|
||||
return await invoke("get_openclaw_tools");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set tools config (tools section of openclaw.json)
|
||||
*/
|
||||
async setTools(tools: OpenClawToolsConfig): Promise<void> {
|
||||
return await invoke("set_openclaw_tools", { tools });
|
||||
},
|
||||
};
|
||||
@@ -98,6 +98,14 @@ export const providersApi = {
|
||||
async getOpenCodeLiveProviderIds(): Promise<string[]> {
|
||||
return await invoke("get_opencode_live_provider_ids");
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 OpenClaw live 配置中的供应商 ID 列表
|
||||
* 用于前端判断供应商是否已添加到 openclaw.json
|
||||
*/
|
||||
async getOpenClawLiveProviderIds(): Promise<string[]> {
|
||||
return await invoke("get_openclaw_live_provider_ids");
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
||||
+47
-1
@@ -1,5 +1,5 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type { Settings } from "@/types";
|
||||
import type { Settings, WebDavSyncSettings, RemoteSnapshotInfo } from "@/types";
|
||||
import type { AppId } from "./types";
|
||||
|
||||
export interface ConfigTransferResult {
|
||||
@@ -9,6 +9,15 @@ export interface ConfigTransferResult {
|
||||
backupId?: string;
|
||||
}
|
||||
|
||||
export interface WebDavTestResult {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface WebDavSyncResult {
|
||||
status: string;
|
||||
}
|
||||
|
||||
export const settingsApi = {
|
||||
async get(): Promise<Settings> {
|
||||
return await invoke("get_settings");
|
||||
@@ -93,6 +102,42 @@ export const settingsApi = {
|
||||
return await invoke("import_config_from_file", { filePath });
|
||||
},
|
||||
|
||||
// ─── WebDAV v2 sync ───────────────────────────────────────
|
||||
|
||||
async webdavTestConnection(
|
||||
settings: WebDavSyncSettings,
|
||||
preserveEmptyPassword = true,
|
||||
): Promise<WebDavTestResult> {
|
||||
return await invoke("webdav_test_connection", {
|
||||
settings,
|
||||
preserveEmptyPassword,
|
||||
});
|
||||
},
|
||||
|
||||
async webdavSyncUpload(): Promise<WebDavSyncResult> {
|
||||
return await invoke("webdav_sync_upload");
|
||||
},
|
||||
|
||||
async webdavSyncDownload(): Promise<WebDavSyncResult> {
|
||||
return await invoke("webdav_sync_download");
|
||||
},
|
||||
|
||||
async webdavSyncSaveSettings(
|
||||
settings: WebDavSyncSettings,
|
||||
passwordTouched = false,
|
||||
): Promise<{ success: boolean }> {
|
||||
return await invoke("webdav_sync_save_settings", {
|
||||
settings,
|
||||
passwordTouched,
|
||||
});
|
||||
},
|
||||
|
||||
async webdavSyncFetchRemoteInfo(): Promise<
|
||||
RemoteSnapshotInfo | { empty: true }
|
||||
> {
|
||||
return await invoke("webdav_sync_fetch_remote_info");
|
||||
},
|
||||
|
||||
async syncCurrentProvidersLive(): Promise<void> {
|
||||
const result = (await invoke("sync_current_providers_live")) as {
|
||||
success?: boolean;
|
||||
@@ -155,6 +200,7 @@ export const settingsApi = {
|
||||
export interface RectifierConfig {
|
||||
enabled: boolean;
|
||||
requestThinkingSignature: boolean;
|
||||
requestThinkingBudget: boolean;
|
||||
}
|
||||
|
||||
export interface LogConfig {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
import type { AppId } from "@/lib/api/types";
|
||||
|
||||
// ========== 类型定义 ==========
|
||||
export type AppType = "claude" | "codex" | "gemini" | "opencode" | "openclaw";
|
||||
|
||||
/** Skill 应用启用状态 */
|
||||
export interface SkillApps {
|
||||
@@ -10,6 +10,7 @@ export interface SkillApps {
|
||||
codex: boolean;
|
||||
gemini: boolean;
|
||||
opencode: boolean;
|
||||
openclaw: boolean;
|
||||
}
|
||||
|
||||
/** 已安装的 Skill(v3.10.0+ 统一结构) */
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// 前端统一使用 AppId 作为应用标识(与后端命令参数 `app` 一致)
|
||||
export type AppId = "claude" | "codex" | "gemini" | "opencode";
|
||||
export type AppId = "claude" | "codex" | "gemini" | "opencode" | "openclaw";
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export const workspaceApi = {
|
||||
async readFile(filename: string): Promise<string | null> {
|
||||
return invoke<string | null>("read_workspace_file", { filename });
|
||||
},
|
||||
|
||||
async writeFile(filename: string, content: string): Promise<void> {
|
||||
return invoke<void>("write_workspace_file", { filename, content });
|
||||
},
|
||||
};
|
||||
@@ -5,6 +5,7 @@ import { providersApi, settingsApi, type AppId } from "@/lib/api";
|
||||
import type { Provider, Settings } from "@/types";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { generateUUID } from "@/utils/uuid";
|
||||
import { openclawKeys } from "@/hooks/useOpenClaw";
|
||||
|
||||
export const useAddProviderMutation = (appId: AppId) => {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -16,12 +17,12 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
) => {
|
||||
let id: string;
|
||||
|
||||
if (appId === "opencode") {
|
||||
if (appId === "opencode" || appId === "openclaw") {
|
||||
if (providerInput.category === "omo") {
|
||||
id = `omo-${generateUUID()}`;
|
||||
} else {
|
||||
if (!providerInput.providerKey) {
|
||||
throw new Error("Provider key is required for OpenCode");
|
||||
throw new Error(`Provider key is required for ${appId}`);
|
||||
}
|
||||
id = providerInput.providerKey;
|
||||
}
|
||||
@@ -29,8 +30,10 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
id = generateUUID();
|
||||
}
|
||||
|
||||
const { providerKey: _providerKey, ...rest } = providerInput;
|
||||
|
||||
const newProvider: Provider = {
|
||||
...providerInput,
|
||||
...rest,
|
||||
id,
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
@@ -174,6 +177,7 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
||||
|
||||
// OpenCode/OpenClaw: also invalidate live provider IDs cache to update button state
|
||||
if (appId === "opencode") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["opencodeLiveProviderIds"],
|
||||
@@ -182,6 +186,14 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
queryKey: ["omo", "current-provider-id"],
|
||||
});
|
||||
}
|
||||
if (appId === "openclaw") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: openclawKeys.liveProviderIds,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: openclawKeys.defaultModel,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
|
||||
@@ -4,8 +4,8 @@ export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
refetchOnWindowFocus: true,
|
||||
staleTime: 0,
|
||||
},
|
||||
mutations: {
|
||||
retry: false,
|
||||
|
||||
@@ -28,6 +28,27 @@ export const settingsSchema = z.object({
|
||||
|
||||
// Skill 同步设置
|
||||
skillSyncMethod: z.enum(["auto", "symlink", "copy"]).optional(),
|
||||
|
||||
// WebDAV v2 同步设置(通过专用命令保存,schema 仅用于读取)
|
||||
webdavSync: z
|
||||
.object({
|
||||
enabled: z.boolean().optional(),
|
||||
baseUrl: z.string().trim().optional().or(z.literal("")),
|
||||
username: z.string().trim().optional().or(z.literal("")),
|
||||
password: z.string().optional(),
|
||||
remoteRoot: z.string().trim().optional().or(z.literal("")),
|
||||
profile: z.string().trim().optional().or(z.literal("")),
|
||||
status: z
|
||||
.object({
|
||||
lastSyncAt: z.number().nullable().optional(),
|
||||
lastError: z.string().nullable().optional(),
|
||||
lastRemoteEtag: z.string().nullable().optional(),
|
||||
lastLocalManifestHash: z.string().nullable().optional(),
|
||||
lastRemoteManifestHash: z.string().nullable().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type SettingsFormData = z.infer<typeof settingsSchema>;
|
||||
|
||||
Reference in New Issue
Block a user