feat: complete stage 1 infrastructure

This commit is contained in:
Jason
2025-10-16 10:00:22 +08:00
parent 95e2d84655
commit cc0b7053aa
31 changed files with 2350 additions and 9 deletions

6
src/lib/api/index.ts Normal file
View File

@@ -0,0 +1,6 @@
export type { AppType } from "./types";
export { providersApi } from "./providers";
export { settingsApi } from "./settings";
export { mcpApi } from "./mcp";
export { usageApi } from "./usage";
export { vscodeApi } from "./vscode";

69
src/lib/api/mcp.ts Normal file
View File

@@ -0,0 +1,69 @@
import { invoke } from "@tauri-apps/api/core";
import type {
McpConfigResponse,
McpServer,
McpServerSpec,
McpStatus,
} from "@/types";
import type { AppType } from "./types";
export const mcpApi = {
async getStatus(): Promise<McpStatus> {
return await invoke("get_claude_mcp_status");
},
async readConfig(): Promise<string | null> {
return await invoke("read_claude_mcp_config");
},
async upsertServer(
id: string,
spec: McpServerSpec | Record<string, any>
): Promise<boolean> {
return await invoke("upsert_claude_mcp_server", { id, spec });
},
async deleteServer(id: string): Promise<boolean> {
return await invoke("delete_claude_mcp_server", { id });
},
async validateCommand(cmd: string): Promise<boolean> {
return await invoke("validate_mcp_command", { cmd });
},
async getConfig(app: AppType = "claude"): Promise<McpConfigResponse> {
return await invoke("get_mcp_config", { app });
},
async upsertServerInConfig(
app: AppType,
id: string,
spec: McpServer,
options?: { syncOtherSide?: boolean }
): Promise<boolean> {
const payload = {
app,
id,
spec,
...(options?.syncOtherSide !== undefined
? { syncOtherSide: options.syncOtherSide }
: {}),
};
return await invoke("upsert_mcp_server_in_config", payload);
},
async deleteServerInConfig(
app: AppType,
id: string,
options?: { syncOtherSide?: boolean }
): Promise<boolean> {
const payload = {
app,
id,
...(options?.syncOtherSide !== undefined
? { syncOtherSide: options.syncOtherSide }
: {}),
};
return await invoke("delete_mcp_server_in_config", payload);
},
};

75
src/lib/api/providers.ts Normal file
View File

@@ -0,0 +1,75 @@
import { invoke } from "@tauri-apps/api/core";
import type { Provider } from "@/types";
import type { AppType } from "./types";
export interface ProviderSortUpdate {
id: string;
sortIndex: number;
}
export const providersApi = {
async getAll(appType: AppType): Promise<Record<string, Provider>> {
return await invoke("get_providers", { app_type: appType, app: appType });
},
async getCurrent(appType: AppType): Promise<string> {
return await invoke("get_current_provider", {
app_type: appType,
app: appType,
});
},
async add(provider: Provider, appType: AppType): Promise<boolean> {
return await invoke("add_provider", {
provider,
app_type: appType,
app: appType,
});
},
async update(provider: Provider, appType: AppType): Promise<boolean> {
return await invoke("update_provider", {
provider,
app_type: appType,
app: appType,
});
},
async delete(id: string, appType: AppType): Promise<boolean> {
return await invoke("delete_provider", {
id,
app_type: appType,
app: appType,
});
},
async switch(id: string, appType: AppType): Promise<boolean> {
return await invoke("switch_provider", {
id,
app_type: appType,
app: appType,
});
},
async importDefault(appType: AppType): Promise<boolean> {
return await invoke("import_default_config", {
app_type: appType,
app: appType,
});
},
async updateTrayMenu(): Promise<boolean> {
return await invoke("update_tray_menu");
},
async updateSortOrder(
updates: ProviderSortUpdate[],
appType: AppType
): Promise<boolean> {
return await invoke("update_providers_sort_order", {
updates,
app_type: appType,
app: appType,
});
},
};

52
src/lib/api/settings.ts Normal file
View File

@@ -0,0 +1,52 @@
import { invoke } from "@tauri-apps/api/core";
import type { Settings } from "@/types";
import type { AppType } from "./types";
export const settingsApi = {
async get(): Promise<Settings> {
return await invoke("get_settings");
},
async save(settings: Settings): Promise<boolean> {
return await invoke("save_settings", { settings });
},
async restart(): Promise<boolean> {
return await invoke("restart_app");
},
async checkUpdates(): Promise<void> {
await invoke("check_for_updates");
},
async isPortable(): Promise<boolean> {
return await invoke("is_portable_mode");
},
async getConfigDir(appType: AppType): Promise<string> {
return await invoke("get_config_dir", {
app_type: appType,
app: appType,
});
},
async openConfigFolder(appType: AppType): Promise<void> {
await invoke("open_config_folder", { app_type: appType, app: appType });
},
async selectConfigDirectory(defaultPath?: string): Promise<string | null> {
return await invoke("pick_directory", { default_path: defaultPath });
},
async getClaudeCodeConfigPath(): Promise<string> {
return await invoke("get_claude_code_config_path");
},
async getAppConfigPath(): Promise<string> {
return await invoke("get_app_config_path");
},
async openAppConfigFolder(): Promise<void> {
await invoke("open_app_config_folder");
},
};

1
src/lib/api/types.ts Normal file
View File

@@ -0,0 +1 @@
export type AppType = "claude" | "codex";

15
src/lib/api/usage.ts Normal file
View File

@@ -0,0 +1,15 @@
import { invoke } from "@tauri-apps/api/core";
import type { UsageResult } from "@/types";
import type { AppType } from "./types";
export const usageApi = {
async query(providerId: string, appType: AppType): Promise<UsageResult> {
return await invoke("query_provider_usage", {
provider_id: providerId,
providerId: providerId,
app_type: appType,
app: appType,
appType,
});
},
};

113
src/lib/api/vscode.ts Normal file
View File

@@ -0,0 +1,113 @@
import { invoke } from "@tauri-apps/api/core";
import type { CustomEndpoint } from "@/types";
import type { AppType } from "./types";
export interface EndpointLatencyResult {
url: string;
latency: number | null;
status?: number;
error?: string;
}
export const vscodeApi = {
async getLiveProviderSettings(appType: AppType) {
return await invoke("read_live_provider_settings", {
app_type: appType,
app: appType,
appType,
});
},
async testApiEndpoints(
urls: string[],
options?: { timeoutSecs?: number }
): Promise<EndpointLatencyResult[]> {
return await invoke("test_api_endpoints", {
urls,
timeout_secs: options?.timeoutSecs,
});
},
async getCustomEndpoints(
appType: AppType,
providerId: string
): Promise<CustomEndpoint[]> {
return await invoke("get_custom_endpoints", {
app_type: appType,
app: appType,
appType,
provider_id: providerId,
providerId,
});
},
async addCustomEndpoint(
appType: AppType,
providerId: string,
url: string
): Promise<void> {
await invoke("add_custom_endpoint", {
app_type: appType,
app: appType,
appType,
provider_id: providerId,
providerId,
url,
});
},
async removeCustomEndpoint(
appType: AppType,
providerId: string,
url: string
): Promise<void> {
await invoke("remove_custom_endpoint", {
app_type: appType,
app: appType,
appType,
provider_id: providerId,
providerId,
url,
});
},
async updateEndpointLastUsed(
appType: AppType,
providerId: string,
url: string
): Promise<void> {
await invoke("update_endpoint_last_used", {
app_type: appType,
app: appType,
appType,
provider_id: providerId,
providerId,
url,
});
},
async exportConfigToFile(filePath: string) {
return await invoke("export_config_to_file", {
file_path: filePath,
filePath,
});
},
async importConfigFromFile(filePath: string) {
return await invoke("import_config_from_file", {
file_path: filePath,
filePath,
});
},
async saveFileDialog(defaultName: string): Promise<string | null> {
return await invoke("save_file_dialog", {
default_name: defaultName,
defaultName,
});
},
async openFileDialog(): Promise<string | null> {
return await invoke("open_file_dialog");
},
};