dev-manager-tauri/src/lib/commands.ts
lanrtop a5cb30734d
All checks were successful
Push & PR Check / check (push) Successful in 50s
Push & PR Check / check (pull_request) Successful in 50s
feat(flywheel): 返工热区 UI + get_high_risk_scopes 命令,阶段三收官
- risk.rs 新增 Tauri command get_high_risk_scopes(薄包装)+ lib.rs 注册
- commands.ts 封装 HighRiskScope 类型与调用(R01)
- FlywheelPanel 新增「返工热区」块:跨项目返工率降序,
  分级配色与 classify_risk 阈值一致(≥35% 红 / ≥15% 琥珀)
- 蓝图:P3-A~E 五卡全部 done,附 L 级复盘笔记,模块 progress 98

Rules-Applied: R01,R13
2026-07-04 14:22:52 +09:00

1987 lines
59 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { invoke } from "@tauri-apps/api/core";
export interface Project {
/** workspace.id也是旧 projects.id */
id: string;
/** profile.id跨空间共享的项目档案 */
profile_id?: string;
/** 同 id前端可用于语义区分 */
workspace_id?: string;
/** 关联的 git_repos.id */
repo_id?: string;
name: string;
description?: string;
type?: string;
// ── profile 级(项目档案,跨空间共享)────────────────────────
status?: string;
priority?: string;
tech_stack?: string;
tags?: string;
repo_url?: string;
upstream_url?: string;
default_branch?: string;
staging_url?: string;
prod_url?: string;
server_note?: string;
// ── workspace 级(每空间独立)───────────────────────────────
space_id?: string;
wsl_path?: string;
win_path?: string;
platform?: "windows" | "wsl";
recent_focus?: string;
startup_commands?: string;
last_push_at?: string;
updated_at?: string;
}
export interface ProjectDetail extends Project {
recent_activities: ActivityLog[];
}
export interface ActivityLog {
id: number;
project_id: string;
summary: string;
created_at?: string;
}
export interface ProductGroup {
id: string;
name: string;
description?: string;
space_id?: string;
sort_order: number;
}
export interface ProjectGroupMap {
project_id: string;
group_id: string;
role?: string;
}
export interface EditorCandidate {
name: string;
cmd: string;
path: string | null;
found: boolean;
}
// ── Projects ──────────────────────────────────────────────────────────────────
export const getProjects = (status?: string, spaceId?: string) =>
invoke<Project[]>("get_projects", { status, spaceId });
export const getProject = (id: string) =>
invoke<ProjectDetail>("get_project", { id });
export const createProject = (input: Omit<Project, "updated_at" | "workspace_id">) =>
invoke<void>("create_project", { input });
export const updateProject = (id: string, input: Partial<Omit<Project, "id" | "updated_at">>) =>
invoke<void>("update_project", { id, input });
export const updateProjectTags = (id: string, tags: string) =>
invoke<void>("update_project_tags", { id, tags });
export const deleteProject = (id: string, deleteLocal?: boolean) =>
invoke<void>("delete_project", { id, deleteLocal });
export interface SubFolder { name: string; path: string }
export const scanSubfolders = (dir: string) =>
invoke<SubFolder[]>("scan_subfolders", { dir });
export interface BatchProjectInput {
id: string; name: string;
win_path?: string; wsl_path?: string;
status: string; priority: string;
space_id?: string; platform?: string;
}
export const batchCreateProjects = (items: BatchProjectInput[]) =>
invoke<string[]>("batch_create_projects", { items });
// ── Activity ──────────────────────────────────────────────────────────────────
export const getActivity = (projectId: string, limit?: number) =>
invoke<ActivityLog[]>("get_activity", { projectId, limit });
export const addActivity = (projectId: string, summary: string) =>
invoke<void>("add_activity", { projectId, summary });
// ── Groups ────────────────────────────────────────────────────────────────────
export const getGroups = (spaceId?: string) => invoke<ProductGroup[]>("get_groups", { spaceId });
export const createGroup = (input: { id?: string; name: string; description?: string; space_id?: string }) =>
invoke<void>("create_group", { input });
export const updateGroup = (id: string, input: { name: string; description?: string }) =>
invoke<void>("update_group", { id, input });
export const deleteGroup = (id: string) => invoke<void>("delete_group", { id });
/** 按 ids 数组顺序批量写入 sort_order */
export const reorderGroups = (ids: string[]) => invoke<void>("reorder_groups", { ids });
export const getGroupMaps = () => invoke<ProjectGroupMap[]>("get_group_maps");
export const addGroupMember = (projectId: string, groupId: string, role?: string) =>
invoke<string | null>("add_group_member", { projectId, groupId, role });
export const removeGroupMember = (projectId: string, groupId: string) =>
invoke<void>("remove_group_member", { projectId, groupId });
// ── Settings ──────────────────────────────────────────────────────────────────
export const getSettings = (spaceId?: string) =>
invoke<Record<string, string>>("get_settings", { spaceId });
export const updateSettings = (settings: Record<string, string>, spaceId?: string) =>
invoke<void>("update_settings", { settings, spaceId });
export const detectEditors = () => invoke<EditorCandidate[]>("detect_editors");
export const searchEditorPath = (cmd: string) =>
invoke<string | null>("search_editor_path", { cmd });
export interface McpHealthResult {
ok: boolean;
port: number;
latency_ms?: number;
error?: string;
}
export const checkMcpHealth = () => invoke<McpHealthResult>("check_mcp_health");
export interface HealthItem {
id: string;
name: string;
status: "ok" | "warn" | "error" | "skip";
detail?: string;
}
export interface DormantProject {
id: string;
name: string;
days_since_push: number;
}
export interface OrphanedProject {
id: string;
name: string;
}
export interface QualityMetrics {
dormant_projects: DormantProject[];
orphaned_projects: OrphanedProject[];
groups_with_inject_warn: string[];
projects_without_path: number;
}
export interface HealthReport {
checked_at: string;
items: HealthItem[];
quality: QualityMetrics;
}
export const runHealthCheck = () => invoke<HealthReport>("run_health_check");
// ── Project Tools ─────────────────────────────────────────────────────────────
export interface ProjectTool {
id: string;
project_id: string;
name: string;
icon: string;
exe_path: string;
args: string | null;
sort_order: number;
}
export interface ProjectToolInput {
name: string;
icon: string;
exe_path: string;
args?: string;
sort_order?: number;
}
export const getProjectTools = (projectId: string) =>
invoke<ProjectTool[]>("get_project_tools", { projectId });
export const addProjectTool = (projectId: string, input: ProjectToolInput) =>
invoke<string>("add_project_tool", { projectId, input });
export const updateProjectTool = (id: string, input: ProjectToolInput) =>
invoke<void>("update_project_tool", { id, input });
export const removeProjectTool = (id: string) =>
invoke<void>("remove_project_tool", { id });
export const launchTool = (exePath: string, args?: string) =>
invoke<void>("launch_tool", { exePath, args });
// ── Global Quick Launch ───────────────────────────────────────────────────────
export const getGlobalTools = () =>
invoke<ProjectTool[]>("get_global_tools");
export const addGlobalTool = (input: ProjectToolInput) =>
invoke<string>("add_global_tool", { input });
export const updateGlobalTool = (id: string, input: ProjectToolInput) =>
invoke<void>("update_global_tool", { id, input });
export const removeGlobalTool = (id: string) =>
invoke<void>("remove_global_tool", { id });
// ── Dev Tools ─────────────────────────────────────────────────────────────────
export interface ScannedTool {
id: string;
name: string;
category: string;
cmd: string;
path: string | null;
version: string | null;
found: boolean;
}
export type DevEnv = "windows" | "wsl";
export interface DevToolRecord {
id: string;
name: string;
category: string;
cmd: string | null;
path: string | null;
version: string | null;
note: string | null;
env: DevEnv;
space_id?: string | null;
}
export interface SaveDevToolInput {
id: string;
name: string;
category: string;
cmd?: string;
path?: string;
version?: string;
note?: string;
env?: DevEnv;
space_id?: string;
}
export const scanDevTools = () =>
invoke<ScannedTool[]>("scan_dev_tools");
export const scanWslDevTools = () =>
invoke<ScannedTool[]>("scan_wsl_dev_tools");
export const getDevTools = (env: DevEnv, spaceId?: string) =>
invoke<DevToolRecord[]>("get_dev_tools", { env, spaceId });
export const saveDevTools = (tools: SaveDevToolInput[]) =>
invoke<void>("save_dev_tools", { tools });
export const deleteDevTool = (id: string) =>
invoke<void>("delete_dev_tool", { id });
export const upsertDevTool = (tool: SaveDevToolInput) =>
invoke<void>("upsert_dev_tool", { tool });
// ── Project Env Scan ──────────────────────────────────────────────────────────
export interface EnvToolItem {
id: string;
project_id: string;
layer: number;
name: string;
source?: string;
version?: string;
note?: string;
}
export interface SaveEnvToolInput {
id: string;
layer: number;
name: string;
source?: string;
version?: string;
note?: string;
}
export const scanProjectEnv = (projectId: string, env: 'win' | 'wsl') =>
invoke<EnvToolItem[]>('scan_project_env', { projectId, env });
export const getProjectEnvTools = (projectId: string) =>
invoke<EnvToolItem[]>('get_project_env_tools', { projectId });
export const saveProjectEnvTools = (projectId: string, items: SaveEnvToolInput[]) =>
invoke<void>('save_project_env_tools', { projectId, items });
// ── Shell ─────────────────────────────────────────────────────────────────────
export const openEditor = (projectId: string, env: "wsl" | "win", editorPath: string) =>
invoke<string>("open_editor", { projectId, env, editorPath });
export const openTerminal = (projectId: string, env: "wsl" | "win") =>
invoke<string>("open_terminal", { projectId, env });
// ── Spaces ────────────────────────────────────────────────────────────────────
export interface Space {
id: string;
name: string;
is_current: boolean;
created_at?: string;
}
export interface DeployCommand {
id: string;
project_id: string;
name: string;
command: string;
run_in: "windows" | "wsl";
}
export const getSpaces = () =>
invoke<Space[]>("get_spaces");
export const createSpace = (name: string) =>
invoke<Space>("create_space", { name });
export const updateSpace = (id: string, name: string) =>
invoke<void>("update_space", { id, name });
export const deleteSpace = (id: string) =>
invoke<void>("delete_space", { id });
export const setCurrentSpace = (id: string) =>
invoke<void>("set_current_space", { id });
export const getDeployCommands = (projectId: string) =>
invoke<DeployCommand[]>("get_deploy_commands", { projectId });
export const addDeployCommand = (
projectId: string,
name: string,
command: string,
runIn: "windows" | "wsl"
) => invoke<DeployCommand>("add_deploy_command", { projectId, name, command, runIn });
export const removeDeployCommand = (id: string) =>
invoke<void>("remove_deploy_command", { id });
export const executeDeploy = (command: string, runIn: "windows" | "wsl", cwd?: string) =>
invoke<string>("execute_deploy", { command, runIn, cwd });
// ── Git 操作 ──────────────────────────────────────────────────────────────────
export interface GitStatus {
branch: string;
ahead: number;
behind: number;
has_changes: boolean;
last_commit_msg?: string;
last_commit_time?: string;
}
export const gitClone = (repoUrl: string, localPath: string, upstreamUrl?: string) =>
invoke<void>("git_clone", { repoUrl, localPath, upstreamUrl });
export const gitStatus = (localPath: string) =>
invoke<GitStatus>("git_status", { localPath });
export const gitFetch = (localPath: string) =>
invoke<void>("git_fetch", { localPath });
export const gitPull = (localPath: string) =>
invoke<string>("git_pull", { localPath });
export const gitPush = (localPath: string) =>
invoke<string>("git_push", { localPath });
export const gitHeadCommit = (localPath: string) =>
invoke<string | null>("git_head_commit", { localPath });
export const gitUpstreamBehind = (localPath: string, defaultBranch: string) =>
invoke<number>("git_upstream_behind", { localPath, defaultBranch });
export const gitCreateBranch = (localPath: string, branchName: string) =>
invoke<void>("git_create_branch", { localPath, branchName });
export const gitListBranches = (localPath: string) =>
invoke<string[]>("git_list_branches", { localPath });
export const gitCheckoutBranch = (localPath: string, branchName: string) =>
invoke<void>("git_checkout_branch", { localPath, branchName });
// ── WSL 代理同步 ──────────────────────────────────────────────────────────────
export const getWslIp = () => invoke<string>("get_wsl_ip");
/** 读取 v2rayN 代理端口,写入 WSL /etc/profile.d/v2rayn-proxy.sh */
export const syncWslProxy = (dbPath?: string) =>
invoke<string>("sync_wsl_proxy", { dbPath });
export interface WslProxyStatus {
configured: boolean;
port?: number;
/** /etc/environment 中记录的 IP 与当前网关不一致Windows 重启后常见) */
stale?: boolean;
configured_ip?: string;
current_ip?: string;
/** /etc/bash.bashrc 中的 source 行是否存在(非登录 shell 代理是否生效) */
bashrc_ok?: boolean;
}
export const getWslProxyStatus = () => invoke<WslProxyStatus>("get_wsl_proxy_status");
export const clearWslProxy = () => invoke<void>("clear_wsl_proxy");
export const testWslProxyIp = () => invoke<string>("test_wsl_proxy_ip");
export const testWinProxyIp = () => invoke<string>("test_win_proxy_ip");
export interface ActiveV2raynNode {
index_id: string;
remarks: string;
address: string;
port: number;
config_type: number;
share_link: string;
}
export const getActiveV2raynNode = (dbPath?: string) =>
invoke<ActiveV2raynNode>("get_active_v2rayn_node", { dbPath });
// ── v2rayN 节点导入 ───────────────────────────────────────────────────────────
export interface V2raynNode {
index_id: string;
config_type: number; // 1=VMess 3=SS 5=VLESS 6=Trojan 7=Hysteria2
remarks: string;
address: string;
port: number;
id?: string; // UUID
security?: string;
network?: string;
stream_security?: string;
flow?: string;
sni?: string;
fingerprint?: string;
public_key?: string;
short_id?: string;
spider_x?: string;
request_host?: string;
path?: string;
alter_id?: number;
}
export const CONFIG_TYPE_LABEL: Record<number, string> = {
1: "VMess",
3: "Shadowsocks",
4: "Socks",
5: "VLESS",
6: "Trojan",
7: "Hysteria2",
};
export const scanV2raynNodes = (dbPath?: string) =>
invoke<V2raynNode[]>("scan_v2rayn_nodes", { dbPath });
export const detectV2raynDbPath = () =>
invoke<string | null>("detect_v2rayn_db_path");
// ── Git Repos Registry仓库注册表──────────────────────────────────────────
export interface GitRepo {
id: string;
repo_url: string;
name: string;
description?: string;
default_branch?: string;
upstream_url?: string;
staging_url?: string;
prod_url?: string;
server_note?: string;
status?: string;
priority?: string;
tech_stack?: string;
last_synced_at?: string;
created_at?: string;
}
export interface ImportGitRepoInput {
id: string;
repo_url: string;
name: string;
description?: string;
default_branch?: string;
upstream_url?: string;
tech_stack?: string;
}
export interface UpdateGitRepoDeployInput {
staging_url?: string;
prod_url?: string;
server_note?: string;
upstream_url?: string;
tech_stack?: string;
status?: string;
priority?: string;
}
export interface MountRepoInput {
workspace_id: string;
repo_id: string;
space_id?: string;
win_path?: string;
wsl_path?: string;
platform?: string;
}
export const getGitRepos = () =>
invoke<GitRepo[]>("get_git_repos");
export const importGitRepos = (repos: ImportGitRepoInput[]) =>
invoke<string[]>("import_git_repos", { repos });
export const updateGitRepoDeploy = (id: string, input: UpdateGitRepoDeployInput) =>
invoke<void>("update_git_repo_deploy", { id, input });
export const mountRepo = (input: MountRepoInput) =>
invoke<void>("mount_repo", { input });
export const deleteGitRepo = (id: string) =>
invoke<void>("delete_git_repo", { id });
// ── 本地 Git 工具(扫描 / init / remote / WSL 路径)───────────────────────────
export interface ChangedFile {
status: string; // "M" | "A" | "D" | "?" | "R"
path: string;
}
export interface GitRemoteInfo {
name: string;
url: string;
}
export interface GitScanResult {
has_git: boolean;
has_commits: boolean;
branch: string;
has_changes: boolean;
changed_files: ChangedFile[];
remotes: GitRemoteInfo[];
has_gitignore: boolean;
suspicious_files: string[];
suggested_templates: string[];
}
export const scanLocalGit = (path: string) =>
invoke<GitScanResult>("scan_local_git", { path });
export const gitInitAndCommit = (path: string, message: string) =>
invoke<void>("git_init_and_commit", { path, message });
export const gitRemoteSet = (path: string, url: string) =>
invoke<void>("git_remote_set", { path, url });
/** 将 Linux WSL 路径转换为 Windows UNC 路径(\\wsl.localhost\distro\... */
export const resolveWslPath = (path: string) =>
invoke<string>("resolve_wsl_path", { path });
/** 列出已安装的 WSL 发行版 */
export const getWslDistros = () =>
invoke<string[]>("get_wsl_distros");
// ── 项目模板 ──────────────────────────────────────────────────────────────────
export interface TemplateFile {
id: string;
template_id: string;
path: string;
content: string;
}
export interface TemplateVariant {
label: string;
description: string;
initCommands: string;
}
export interface ProjectTemplate {
id: string;
name: string;
description?: string;
platform: string; // "win" | "wsl" | "both"
techStack?: string;
initCommands?: string;
isBuiltin: boolean;
createdAt?: string;
files: TemplateFile[];
/** JSON 字符串,解析后为 TemplateVariant[],存在时显示下拉选择 */
variants?: string;
}
export interface SaveTemplateInput {
id?: string;
name: string;
description?: string;
platform: string;
techStack?: string;
initCommands?: string;
files: { path: string; content: string }[];
}
export interface CreateProjectResult {
projectId: string;
logs: string[];
}
export const listTemplates = () =>
invoke<ProjectTemplate[]>("list_templates");
export const getTemplate = (id: string) =>
invoke<ProjectTemplate>("get_template", { id });
export const saveTemplate = (input: SaveTemplateInput) =>
invoke<string>("save_template", { input });
export const deleteTemplate = (id: string) =>
invoke<void>("delete_template", { id });
export const createProjectFromTemplate = (
templateId: string,
parentPath: string,
projectName: string,
platform: string,
spaceId?: string,
variantInitCommands?: string,
) =>
invoke<CreateProjectResult>("create_project_from_template", {
templateId,
parentPath,
projectName,
platform,
spaceId,
variantInitCommands,
});
export const registerAndLinkRepo = (
projectId: string,
repoUrl: string,
name: string,
description?: string,
defaultBranch?: string,
) => invoke<void>("register_and_link_repo", { projectId, repoUrl, name, description, defaultBranch });
// ── 项目标签 ──────────────────────────────────────────────────────────────────
export interface ProjectTag {
id: string;
name: string;
color: string;
}
export interface ProfileTagMap {
profile_id: string;
tag_id: string;
}
export const getTags = () => invoke<ProjectTag[]>("get_tags");
export const createTag = (name: string, color: string) => invoke<string>("create_tag", { name, color });
export const updateTag = (id: string, name: string, color: string) => invoke<void>("update_tag", { id, name, color });
export const deleteTag = (id: string) => invoke<void>("delete_tag", { id });
export const getProjectTags = (workspaceId: string) => invoke<ProjectTag[]>("get_project_tags", { workspaceId });
export const setProjectTags = (workspaceId: string, tagIds: string[]) => invoke<void>("set_project_tags", { workspaceId, tagIds });
export const getAllProjectTagMaps = () => invoke<ProfileTagMap[]>("get_all_project_tag_maps");
// ── CI/CD 配置 ────────────────────────────────────────────────────────────────
export interface CicdConfig {
id: string;
project_id: string;
/** 'web_ssh' | 'tauri_oss' */
config_type: string;
trigger_branch: string;
build_command?: string;
node_version?: string;
// web_ssh 专属
server_host?: string;
server_user?: string;
deploy_path?: string;
start_command?: string;
// tauri_oss 专属
oss_endpoint?: string;
created_at?: string;
}
export interface WorkflowResult {
content: string;
path: string;
secrets: string[];
}
export const getCicdConfig = (projectId: string) =>
invoke<CicdConfig | null>("get_cicd_config", { projectId });
export const saveCicdConfig = (input: CicdConfig) =>
invoke<CicdConfig>("save_cicd_config", { input });
/** 生成 workflow 文件写入磁盘projectPath 必须是 Windows 可访问路径 */
export const generateWorkflow = (projectId: string, projectPath: string) =>
invoke<WorkflowResult>("generate_workflow", { projectId, projectPath });
/** 根据节点数据构造 share link前端完成避免 Rust 侧 URL 编码依赖) */
export function buildShareLink(node: V2raynNode): string {
const remarks = encodeURIComponent(node.remarks);
if (node.config_type === 5) {
// VLESS
const uuid = node.id ?? "";
const params = new URLSearchParams();
params.set("encryption", "none");
params.set("security", node.stream_security ?? "none");
if (node.network) params.set("type", node.network);
if (node.stream_security === "reality" || node.stream_security === "tls") {
if (node.sni) params.set("sni", node.sni);
if (node.fingerprint) params.set("fp", node.fingerprint);
}
if (node.stream_security === "reality") {
if (node.public_key) params.set("pbk", node.public_key);
if (node.short_id) params.set("sid", node.short_id);
if (node.spider_x) params.set("spx", node.spider_x);
}
if (node.flow) params.set("flow", node.flow);
if (node.request_host) params.set("host", node.request_host);
if (node.path) params.set("path", node.path);
return `vless://${uuid}@${node.address}:${node.port}?${params.toString()}#${remarks}`;
}
if (node.config_type === 6) {
// Trojan
const params = new URLSearchParams();
params.set("security", node.stream_security ?? "tls");
if (node.sni) params.set("sni", node.sni);
if (node.fingerprint) params.set("fp", node.fingerprint);
if (node.network) params.set("type", node.network);
return `trojan://${node.id ?? ""}@${node.address}:${node.port}?${params.toString()}#${remarks}`;
}
if (node.config_type === 1) {
// VMess — base64 JSON 格式
const obj = {
v: "2", ps: node.remarks, add: node.address, port: String(node.port),
id: node.id ?? "", aid: String(node.alter_id ?? 0),
scy: node.security ?? "auto", net: node.network ?? "tcp",
type: "none", host: node.request_host ?? "", path: node.path ?? "",
tls: node.stream_security ?? "", sni: node.sni ?? "", fp: node.fingerprint ?? "",
};
return `vmess://${btoa(JSON.stringify(obj))}`;
}
return "";
}
// ── Blueprint ──────────────────────────────────────────────────────────────
export interface BlueprintTask {
title: string;
status: string;
complexity?: string;
files?: string;
depends?: string;
acceptance?: string;
notes?: string;
blocked_reason?: string;
locked?: boolean;
}
export interface BlueprintModule {
id: string;
name: string;
area: string;
status: string;
progress: number;
position: number[];
description?: string;
decisions: string[];
tasks: BlueprintTask[];
}
export interface BlueprintEdge {
from: string;
to: string;
edge_type: string;
}
export interface BlueprintArea {
id: string;
name: string;
color?: string;
}
export interface BlueprintStats {
total_modules: number;
done: number;
in_progress: number;
planned: number;
concept: number;
blocked: number;
total_tasks: number;
tasks_done: number;
tasks_blocked: number;
tasks_locked: number;
dispatchable: number;
}
export interface BlueprintData {
manifest: {
version: number;
name: string;
description?: string;
updated?: string;
/** 当前迭代号,默认 1重构已完成模块时递增 */
iteration?: number;
areas: BlueprintArea[];
modules: BlueprintModule[];
edges: BlueprintEdge[];
};
stats: BlueprintStats;
}
export const getBlueprint = (projectPath: string) =>
invoke<BlueprintData | null>("get_blueprint", { projectPath });
export const generateBlueprintPrompt = (projectPath: string, promptType: "init" | "sync") =>
invoke<string>("generate_blueprint_prompt", { projectPath, promptType });
export interface BlueprintStatus {
status: "none" | "rules_outdated" | "content_stale" | "synced";
conventions_version?: string;
claude_md_managed: boolean;
claude_md_version?: string;
manifest_updated?: string;
master_version: string;
}
export interface SyncResult {
success: boolean;
conventions_written: boolean;
claude_md_action: string;
agents_md_action: string;
message: string;
}
export const getBlueprintStatus = (projectPath: string) =>
invoke<BlueprintStatus>("get_blueprint_status", { projectPath });
export const syncBlueprintRules = (projectPath: string) =>
invoke<SyncResult>("sync_blueprint_rules", { projectPath });
export interface UserConventionsStatus {
source: "builtin" | "user";
version: string;
content: string;
builtin_version: string;
outdated_from_builtin: boolean;
}
export interface SaveConventionsResult {
version: string;
synced_count: number;
}
export const getUserConventionsStatus = () =>
invoke<UserConventionsStatus>("get_user_conventions_status");
export const saveUserConventions = (content: string) =>
invoke<SaveConventionsResult>("save_user_conventions", { content });
export const resetConventionsToBuiltin = () =>
invoke<SaveConventionsResult>("reset_conventions_to_builtin");
export interface FlywheelCohort {
conventions_version: string;
project_count: number;
/** 可派发率dispatched(可派发数) / total tasks最新快照均值 */
dispatchable_rate: number;
/** 任务完成率done / total tasks最新快照均值反映整体进度 */
completion_rate: number;
/** 飞轮持续率30天内有快照的项目比例 */
continuity_rate: number;
/** 阻塞密度blocked / total tasks最新快照均值 */
blocked_density: number;
}
export interface BlockedReasonCount {
reason: string;
count: number;
}
export interface StalledProject {
name: string;
/** UTC 日期字符串 "YYYY-MM-DD",未知时为 "unknown" */
last_active: string;
}
export interface IterationJump {
project: string;
from_iteration: number;
to_iteration: number;
/** 跳变前最后一条快照的任务完成率 */
rate_before: number;
/** 跳变后第一条快照的任务完成率 */
rate_after: number;
}
export interface ProjectNoteEntry {
project_name: string;
content: string;
created_at: string;
}
export interface ExecutionQuality {
complexity_dist: Record<string, number>;
total_rework_count: number;
avg_rounds_m: number | null;
}
export interface FlywheelStats {
cohorts: FlywheelCohort[];
top_blocked_reasons: BlockedReasonCount[];
/** 飞轮停转项目60天无快照 */
stalled_projects: StalledProject[];
/** AI文档休眠项目90天无快照 */
ai_doc_stale_projects: StalledProject[];
/** 迭代跳变记录iteration 递增,说明发生了主动重构) */
iteration_jumps: IterationJump[];
/** 停滞模块in_progress 但无可推进任务,格式 "project/module_id" */
stalled_modules: string[];
total_projects_scanned: number;
projects_with_data: number;
/** 跨项目复盘笔记(最近 50 条) */
project_notes: ProjectNoteEntry[];
/** 跨项目执行质量指标(阶段二扩展) */
execution_quality: ExecutionQuality;
}
export const getFlywheelStats = (projectPaths: string[]) =>
invoke<FlywheelStats>("get_flywheel_stats", { projectPaths });
export const generateMuhePrompt = (stats: FlywheelStats) =>
invoke<string>("generate_muhe_prompt", { stats });
export interface ArchiveResult {
archived_files: string[];
archive_dir: string;
}
export const archiveProjectDocs = (projectPath: string) =>
invoke<ArchiveResult>("archive_project_docs", { projectPath });
// ── Canvas State ───────────────────────────────────────────────────────────────
export const getCanvasState = (groupId: string) =>
invoke<string | null>("get_canvas_state", { groupId });
export const saveCanvasState = (groupId: string, data: string) =>
invoke<void>("save_canvas_state", { groupId, data });
// ── Mentor ────────────────────────────────────────────────────────────────────
export interface ProjectHealth {
path_valid: boolean;
has_git: boolean;
last_commit?: string;
tech_stack?: string;
}
export interface BlueprintSummary {
module_count: number;
done_count: number;
in_progress: number;
planned: number;
total_tasks: number;
done_tasks: number;
dispatchable: number;
}
export interface RuntimeLogEntry {
ts: string;
category: string;
level: string;
message: string;
}
export interface ReviewCoverage {
completed_ml_tasks: number;
note_count: number;
}
export interface MentorContext {
project_id: string;
project_name: string;
health: ProjectHealth;
blueprint_summary?: BlueprintSummary;
recent_errors: RuntimeLogEntry[];
review_coverage?: ReviewCoverage;
mentor_markdown: string;
}
export const getMentorContext = (projectId: string) =>
invoke<MentorContext>("get_mentor_context", { projectId });
export const getGroupMentorReport = (groupId: string) =>
invoke<string>("get_group_mentor_report", { groupId });
export interface StartupAlert {
project_name: string;
alert_type: string;
detail: string;
}
export const getStartupAlerts = () =>
invoke<StartupAlert[]>("get_startup_alerts");
export interface ProjectNote {
id: number;
project_id: string;
source: string;
content: string;
created_at: string;
}
export const getProjectNotes = (projectId: string) =>
invoke<ProjectNote[]>("get_project_notes", { projectId });
export const addProjectNote = (projectId: string, content: string, source: string = "manual") =>
invoke<void>("add_project_note", { projectId, content, source });
// ── 用户项目个人备忘 ──────────────────────────────────────────────────────────
export interface UserTodo {
id: number;
project_id: string;
content: string;
done: boolean;
sort_order: number;
created_at: string;
}
export const getUserTodos = (projectId: string) =>
invoke<UserTodo[]>("get_user_todos", { projectId });
export const addUserTodo = (projectId: string, content: string) =>
invoke<UserTodo>("add_user_todo", { projectId, content });
export const toggleUserTodo = (id: number) =>
invoke<void>("toggle_user_todo", { id });
export const deleteUserTodo = (id: number) =>
invoke<void>("delete_user_todo", { id });
// ── Servers ──────────────────────────────────────────────────────────────────
export interface QuickLink {
label: string;
url: string;
}
export interface Server {
id: string;
name: string;
server_host: string;
server_port?: string;
username?: string;
password?: string;
ssh_key_path?: string;
quick_links?: string; // JSON string of QuickLink[]
notes?: string;
created_at?: string;
updated_at?: string;
}
export interface SaveServerInput {
name: string;
server_host: string;
server_port?: string;
username?: string;
password?: string;
ssh_key_path?: string;
quick_links?: string;
notes?: string;
}
export interface ProjectServerLink {
project_id: string;
server_id: string;
role?: string;
deploy_type?: "bare" | "docker";
deploy_path?: string;
container_name?: string;
start_command?: string;
notes?: string;
server_name?: string;
server_host?: string;
server_port?: string;
username?: string;
password?: string;
ssh_key_path?: string;
quick_links?: string;
}
export interface LinkServerInput {
role?: string;
deploy_type?: string;
deploy_path?: string;
container_name?: string;
start_command?: string;
notes?: string;
}
export const getServers = () =>
invoke<Server[]>("get_servers");
export const addServer = (input: SaveServerInput) =>
invoke<Server>("add_server", { input });
export const editServer = (id: string, input: SaveServerInput) =>
invoke<Server>("edit_server", { id, input });
export const deleteServer = (id: string) =>
invoke<void>("delete_server", { id });
export const linkServer = (projectId: string, serverId: string, input: LinkServerInput) =>
invoke<void>("link_server", { projectId, serverId, input });
export const unlinkServer = (projectId: string, serverId: string) =>
invoke<void>("unlink_server", { projectId, serverId });
export const getProjectServerLinks = (projectId: string) =>
invoke<ProjectServerLink[]>("get_project_server_links", { projectId });
export const getServerProjectLinks = (serverId: string) =>
invoke<ProjectServerLink[]>("get_server_project_links", { serverId });
// ── Server Service Configs服务连接配置─────────────────────────────────────
export interface ServiceConfigEntry {
key: string;
value: string;
/** 密码/密钥等敏感值,独立隐藏和复制 */
secretValue?: string;
}
export interface ServiceConfig {
id: string;
server_id: string;
name: string;
category?: string;
scope?: "system" | "docker";
config_data: string; // JSON of ServiceConfigEntry[]
sort_order?: number;
created_at?: string;
updated_at?: string;
}
export interface SaveServiceConfigInput {
name: string;
category?: string;
scope?: string;
config_data: string;
sort_order?: number;
}
export const getServiceConfigs = (serverId: string, scope?: string) =>
invoke<ServiceConfig[]>("get_service_configs", { serverId, scope });
export const addServiceConfig = (serverId: string, input: SaveServiceConfigInput) =>
invoke<ServiceConfig>("add_service_config", { serverId, input });
export const editServiceConfig = (id: string, input: SaveServiceConfigInput) =>
invoke<ServiceConfig>("edit_service_config", { id, input });
export const deleteServiceConfig = (id: string) =>
invoke<void>("delete_service_config", { id });
// ── Host Apps宿主机部署应用────────────────────────────────────────────────
export interface HostApp {
id: string;
server_id: string;
name: string;
deploy_type: string;
service_name?: string;
binary_path?: string;
config_path?: string;
log_path?: string;
port?: string;
start_cmd?: string;
stop_cmd?: string;
restart_cmd?: string;
status_cmd?: string;
notes?: string;
sort_order?: number;
created_at?: string;
updated_at?: string;
}
export interface SaveHostAppInput {
name: string;
deploy_type: string;
service_name?: string;
binary_path?: string;
config_path?: string;
log_path?: string;
port?: string;
start_cmd?: string;
stop_cmd?: string;
restart_cmd?: string;
status_cmd?: string;
notes?: string;
sort_order?: number;
}
export const getHostApps = (serverId: string) =>
invoke<HostApp[]>("get_host_apps", { serverId });
export const addHostApp = (serverId: string, input: SaveHostAppInput) =>
invoke<HostApp>("add_host_app", { serverId, input });
export const editHostApp = (id: string, input: SaveHostAppInput) =>
invoke<HostApp>("edit_host_app", { id, input });
export const deleteHostApp = (id: string) =>
invoke<void>("delete_host_app", { id });
// ── API Keys ─────────────────────────────────────────────────────────────────
export interface ApiKey {
id: string;
name: string;
provider: string;
api_key: string;
base_url?: string;
model?: string;
notes?: string;
created_at?: string;
updated_at?: string;
}
export interface SaveApiKeyInput {
name: string;
provider: string;
api_key: string;
base_url?: string;
model?: string;
notes?: string;
}
export const getApiKeys = () =>
invoke<ApiKey[]>("get_api_keys");
export const addApiKey = (input: SaveApiKeyInput) =>
invoke<ApiKey>("add_api_key", { input });
export const editApiKey = (id: string, input: SaveApiKeyInput) =>
invoke<ApiKey>("edit_api_key", { id, input });
export const deleteApiKey = (id: string) =>
invoke<void>("delete_api_key", { id });
// ── SSH Config & VS Code Remote ──────────────────────────────────────────────
export interface SshConfigStatus {
config_path: string;
file_exists: boolean;
has_devmanager_block: boolean;
}
export interface VscodeStatus {
installed: boolean;
path?: string;
remote_ssh_hint: string;
}
export const syncSshConfig = () =>
invoke<string>("sync_ssh_config");
export const getSshConfigStatus = () =>
invoke<SshConfigStatus>("get_ssh_config_status");
export const checkVscodeStatus = () =>
invoke<VscodeStatus>("check_vscode_status");
export const openVscodeRemote = (serverId: string, remotePath?: string) =>
invoke<string>("open_vscode_remote", { serverId, remotePath });
export const openServerTerminal = (serverId: string) =>
invoke<string>("open_server_terminal", { serverId });
export interface SshConfigEntry {
host_alias: string;
hostname?: string;
port?: string;
user?: string;
identity_file?: string;
}
export const parseSshConfigEntries = () =>
invoke<SshConfigEntry[]>("parse_ssh_config_entries");
export const importSshConfigEntries = (entries: SshConfigEntry[]) =>
invoke<number>("import_ssh_config_entries", { entries });
// ── Server Software & Mirrors ────────────────────────────────────────────────
export interface GithubMirror {
id: string;
name: string;
url_prefix: string;
is_builtin: boolean;
sort_order: number;
}
export interface ServerNetworkConfig {
server_id: string;
github_mirror_id?: string;
last_tested?: string;
test_results?: string;
}
export interface MirrorTestResult {
mirror_id: string;
reachable: boolean;
latency_ms?: number;
error?: string;
}
export interface ServerSoftware {
id: string;
name: string;
description?: string;
category?: string;
install_type: "package" | "github";
install_cmd?: string;
github_url?: string;
remote_path?: string;
post_cmd?: string;
is_builtin: boolean;
sort_order: number;
created_at?: string;
}
export interface SaveSoftwareInput {
name: string;
description?: string;
category?: string;
install_type: string;
install_cmd?: string;
github_url?: string;
remote_path?: string;
post_cmd?: string;
}
export interface SaveMirrorInput {
name: string;
url_prefix: string;
}
export interface SoftwareCategory {
id: string;
name: string;
color: string;
sort_order: number;
}
export interface SaveCategoryInput {
name: string;
color?: string;
}
export const getSoftwareCategories = () =>
invoke<SoftwareCategory[]>("get_software_categories");
export const addSoftwareCategory = (input: SaveCategoryInput) =>
invoke<SoftwareCategory>("add_software_category", { input });
export const updateSoftwareCategory = (id: string, input: SaveCategoryInput) =>
invoke<void>("update_software_category", { id, input });
export const deleteSoftwareCategory = (id: string) =>
invoke<void>("delete_software_category", { id });
export const getGithubMirrors = () =>
invoke<GithubMirror[]>("get_github_mirrors");
export const addGithubMirror = (input: SaveMirrorInput) =>
invoke<GithubMirror>("add_github_mirror", { input });
export const deleteGithubMirror = (id: string) =>
invoke<void>("delete_github_mirror", { id });
export const testMirrorLocal = (mirrorId: string) =>
invoke<MirrorTestResult>("test_mirror_local", { mirrorId });
export const getServerNetworkConfig = (serverId: string) =>
invoke<ServerNetworkConfig | null>("get_server_network_config", { serverId });
export const setServerMirror = (serverId: string, mirrorId?: string) =>
invoke<void>("set_server_mirror", { serverId, mirrorId });
export const getServerSoftwareList = () =>
invoke<ServerSoftware[]>("get_server_software_list");
export const addServerSoftware = (input: SaveSoftwareInput) =>
invoke<ServerSoftware>("add_server_software", { input });
export const updateServerSoftware = (id: string, input: SaveSoftwareInput) =>
invoke<void>("update_server_software", { id, input });
export const deleteServerSoftware = (id: string) =>
invoke<void>("delete_server_software", { id });
export const generateInstallCommand = (softwareId: string, serverId: string) =>
invoke<string[]>("generate_install_command", { softwareId, serverId });
// ── Blueprint Buff ────────────────────────────────────────────────────────────
export interface BuffStatus {
project_path: string;
project_id: string;
applied_at: string;
last_sync_at?: string;
last_commit?: string;
status: string;
}
export const applyBlueprintBuff = (projectPath: string, projectId: string) =>
invoke<BuffStatus>("apply_blueprint_buff", { projectPath, projectId });
export const removeBlueprintBuff = (projectPath: string) =>
invoke<void>("remove_blueprint_buff", { projectPath });
export const getBuffStatus = (projectPath: string) =>
invoke<BuffStatus | null>("get_buff_status", { projectPath });
export const listBuffedProjects = () =>
invoke<BuffStatus[]>("list_buffed_projects");
// ── Onboarding Pack接入包──────────────────────────────────────────────────
export interface TemplateResult {
name: string;
action: "written" | "updated" | "appended" | "skipped" | "failed";
detail: string;
}
export interface HookActivation {
status: "activated" | "missing_binary" | "failed";
detail: string;
}
export interface OnboardingReport {
templates: TemplateResult[];
hook: HookActivation;
buff: BuffStatus;
}
export const applyOnboardingPack = (projectPath: string, projectId: string) =>
invoke<OnboardingReport>("apply_onboarding_pack", { projectPath, projectId });
// ── Agent Infrastructure ──────────────────────────────────────────────────────
export interface DetectedContract {
label: string;
paths: string[];
doc: string;
confidence: 'high' | 'medium' | 'low';
}
export interface AgentInfraStack {
detected_contracts: DetectedContract[];
meta_rules_present: boolean;
context_yaml_exists: boolean;
}
export const scanAgentInfraStack = (projectPath: string) =>
invoke<AgentInfraStack>('scan_agent_infra_stack', { projectPath });
export interface ContractInput {
label: string;
paths: string[];
doc: string;
}
export interface FileResult {
path: string;
action: 'written' | 'updated' | 'skipped' | 'failed';
detail: string;
}
export interface GenerateReport {
files: FileResult[];
}
export const generateAgentInfraFiles = (projectPath: string, contracts: ContractInput[]) =>
invoke<GenerateReport>('generate_agent_infra_files', { projectPath, contracts });
export interface FreshnessDetail {
contract_path: string;
contract_ts: number | null;
yaml_ts: number | null;
gap_days: number | null;
level: 'green' | 'yellow' | 'red';
}
export interface FreshnessResult {
level: 'green' | 'yellow' | 'red';
details: FreshnessDetail[];
checked_at: string;
}
export interface CachedFreshness {
score: 'green' | 'yellow' | 'red';
details: string; // JSON string
checked_at: string;
}
export const scanDocFreshness = (projectPath: string, projectId: string) =>
invoke<FreshnessResult>('scan_doc_freshness', { projectPath, projectId });
export const getDocFreshnessCache = (projectId: string) =>
invoke<CachedFreshness | null>('get_doc_freshness_cache', { projectId });
export interface AgentHealthIssue {
level: 'error' | 'warn';
title: string;
fix: string;
}
export interface AgentHealthReport {
overall: 'green' | 'yellow' | 'red';
issues: AgentHealthIssue[];
fix_prompt: string;
checked_at: string;
}
export const getAgentHealth = (projectPath: string, projectId: string) =>
invoke<AgentHealthReport>('get_agent_health', { projectPath, projectId });
export interface CommitStats {
total: number;
conventional: number;
rework: number;
}
export const getCommitStats = (projectId: string) =>
invoke<CommitStats>("get_commit_stats", { projectId });
export interface IngestResult {
imported: number;
skipped: number;
}
export const ingestFullGitHistory = (projectId: string, projectPath: string) =>
invoke<IngestResult>("ingest_full_git_history", { projectId, projectPath });
export interface ScopeActivity {
scope: string;
commit_count: number;
rework_count: number;
}
export interface ProjectCommitHealth {
project_id: string;
total_commits: number;
conventional_commits: number;
conventional_rate: number;
rework_commits: number;
rework_rate: number;
top_scopes: ScopeActivity[];
}
export const getProjectCommitHealth = (projectIds: string[]) =>
invoke<ProjectCommitHealth[]>("get_project_commit_health", { projectIds });
export interface CommitHealthWithName extends ProjectCommitHealth {
project_name: string;
}
export const getAllCommitHealth = () =>
invoke<CommitHealthWithName[]>("get_all_commit_health");
// 飞轮阶段三:跨项目返工热区(样本 ≥minCommits 且有非 CI 返工的 scope按返工率降序
export interface HighRiskScope {
project_name: string;
scope: string;
commits: number;
rework: number;
rework_rate: number;
}
export const getHighRiskScopes = (minCommits?: number, limit?: number) =>
invoke<HighRiskScope[]>("get_high_risk_scopes", { minCommits, limit });
// ── Gitea Integration ────────────────────────────────────────────────────────
export interface GiteaInstance {
id: string;
name: string;
url: string;
access_token: string;
is_default: boolean;
created_at?: string;
}
export interface SaveGiteaInstanceInput {
name: string;
url: string;
access_token: string;
is_default?: boolean;
}
export interface GiteaUser {
login: string;
full_name: string;
email: string;
}
export interface GiteaLinkedRepo {
id: string;
instance_id: string;
instance_name: string;
instance_url: string;
project_id: string;
gitea_owner: string;
gitea_repo_name: string;
clone_url?: string;
has_webhook: boolean;
webhook_id?: number;
linked_at?: string;
}
export const giteaSaveInstance = (input: SaveGiteaInstanceInput) =>
invoke<GiteaInstance>("gitea_save_instance", { input });
export const giteaListInstances = () =>
invoke<GiteaInstance[]>("gitea_list_instances");
export const giteaDeleteInstance = (id: string) =>
invoke<void>("gitea_delete_instance", { id });
export const giteaUpdateInstance = (
id: string,
fields: { name?: string; url?: string; access_token?: string; is_default?: boolean }
// Tauri 命令参数按 camelCase 匹配 Rust snake_case直接展开 snake_case 字段会被静默丢弃
) => invoke<GiteaInstance>("gitea_update_instance", {
id,
name: fields.name,
url: fields.url,
accessToken: fields.access_token,
isDefault: fields.is_default,
});
export const giteaTestConnection = (instanceId: string) =>
invoke<GiteaUser>("gitea_test_connection", { instanceId });
export const giteaListLinkedRepos = () =>
invoke<GiteaLinkedRepo[]>("gitea_list_linked_repos");
/** 后端 GiteaRepo 结构(单项目绑定详情,与 GiteaLinkedRepo 列表视图字段不同) */
export interface GiteaRepoLink {
id: string;
instance_id: string;
project_id: string;
gitea_owner: string;
gitea_repo_name: string;
clone_url?: string;
webhook_secret?: string;
webhook_id?: number;
linked_at?: string;
}
export const giteaGetRepoLink = (projectId: string) =>
invoke<GiteaRepoLink | null>("gitea_get_repo_link", { projectId });
export const giteaCreateRepo = (
instanceId: string,
projectId: string,
repoName: string,
description?: string,
privateRepo?: boolean
) => invoke<GiteaRepoLink>("gitea_create_repo", { instanceId, projectId, repoName, description, private: privateRepo });
export const giteaMigrateRepo = (
instanceId: string,
projectId: string,
cloneAddr: string,
repoName: string,
authToken?: string,
privateRepo?: boolean
) => invoke<GiteaRepoLink>("gitea_migrate_repo", { instanceId, projectId, cloneAddr, repoName, authToken, private: privateRepo });
export const giteaLinkRepo = (
instanceId: string,
projectId: string,
owner: string,
repoName: string
) => invoke<GiteaRepoLink>("gitea_link_repo", { instanceId, projectId, owner, repoName });
export const giteaSetupWebhook = (projectId: string, callbackBase: string) =>
invoke<GiteaRepoLink>("gitea_setup_webhook", { projectId, callbackBase });
export const giteaUnlinkRepo = (projectId: string) =>
invoke<void>("gitea_unlink_repo", { projectId });
/** 手动触发一次远端轮询采集(后台每 10 分钟自动跑一次) */
export const giteaPollNow = () =>
invoke<{ polled: number; ingested: number }>("gitea_poll_now");
// ── Beast Global Status (read-only) ───────────────────────────────────────────
export interface BeastGlobalStatus {
/** Beast 是否已安装 */
installed: boolean;
/** 当前是否处于狂暴模式 */
active: boolean;
/** ~/.claude/CLAUDE.md 是否含 Beast 注入的 bash 规则 */
has_bash_rules: boolean;
}
export const getBeastGlobalStatus = () =>
invoke<BeastGlobalStatus>("get_beast_global_status");
// ── Source Library (源码库) ──────────────────────────────────────────────────
export interface SourceCategory {
id: string;
name: string;
icon: string;
color: string;
sort_order: number;
}
export interface SourceProject {
id: string;
name: string;
description?: string;
category_id?: string;
language?: string;
tags?: string;
repo_url?: string;
introduction?: string;
readme?: string;
notes?: string;
created_at?: string;
updated_at?: string;
category_name?: string;
version_count?: number;
}
export interface SourceVersion {
id: string;
project_id: string;
version: string;
file_path: string;
archive_path?: string;
file_size: number;
is_primary: boolean;
dir_tree?: string;
notes?: string;
imported_at?: string;
}
export interface DirEntry {
name: string;
type: "dir" | "file";
children_count?: number;
}
// categories
export const getSourceCategories = () =>
invoke<SourceCategory[]>("get_source_categories");
export const createSourceCategory = (name: string, icon?: string, color?: string) =>
invoke<SourceCategory>("create_source_category", { name, icon, color });
export const updateSourceCategory = (id: string, name: string, icon: string, color: string) =>
invoke<void>("update_source_category", { id, name, icon, color });
export const deleteSourceCategory = (id: string) =>
invoke<void>("delete_source_category", { id });
// projects
export const getSourceProjects = (categoryId?: string, search?: string) =>
invoke<SourceProject[]>("get_source_projects", { categoryId, search });
export const createSourceProject = (
name: string,
description?: string,
categoryId?: string,
language?: string,
repoUrl?: string,
introduction?: string,
) => invoke<SourceProject>("create_source_project", { name, description, categoryId, language, repoUrl, introduction });
export const updateSourceProject = (
id: string,
name: string,
description?: string,
categoryId?: string,
language?: string,
repoUrl?: string,
introduction?: string,
notes?: string,
) => invoke<void>("update_source_project", { id, name, description, categoryId, language, repoUrl, introduction, notes });
export const deleteSourceProject = (id: string) =>
invoke<void>("delete_source_project", { id });
// versions
export const getSourceVersions = (projectId: string) =>
invoke<SourceVersion[]>("get_source_versions", { projectId });
export const addSourceVersion = (projectId: string, projectName: string, version: string, filePath: string) =>
invoke<SourceVersion>("add_source_version", { projectId, projectName, version, filePath });
export const setPrimaryVersion = (versionId: string, projectId: string) =>
invoke<void>("set_primary_version", { versionId, projectId });
export const deleteSourceVersion = (versionId: string) =>
invoke<void>("delete_source_version", { versionId });
export const updateVersionNotes = (versionId: string, notes: string) =>
invoke<void>("update_version_notes", { versionId, notes });
export const scanSourceDirTree = (path: string) =>
invoke<DirEntry[]>("scan_source_dir_tree", { path });
export const revealSourceInExplorer = (path: string) =>
invoke<void>("reveal_source_in_explorer", { path });
export const copySourceTo = (source: string, destDir: string) =>
invoke<string>("copy_source_to", { source, destDir });
// ── Cloud Products ────────────────────────────────────────────────────────────
export interface CloudProduct {
id: string;
vendor: string; // aliyun | tencent | custom
product_type: string; // ecs/cvm/rds/tdsql/oss/cos/cdn/domain/redis/clb/custom
name: string;
region?: string;
instance_id?: string;
endpoint?: string;
expire_at?: string;
status: string; // active | expired | stopped
config_data: string; // JSON string
notes?: string;
sort_order: number;
created_at?: string;
updated_at?: string;
}
export interface SaveCloudProductInput {
vendor: string;
product_type: string;
name: string;
region?: string;
instance_id?: string;
endpoint?: string;
expire_at?: string;
status: string;
config_data?: string;
notes?: string;
sort_order?: number;
}
export const getCloudProducts = () =>
invoke<CloudProduct[]>("get_cloud_products");
export const addCloudProduct = (input: SaveCloudProductInput) =>
invoke<CloudProduct>("add_cloud_product", { input });
export const editCloudProduct = (id: string, input: SaveCloudProductInput) =>
invoke<CloudProduct>("edit_cloud_product", { id, input });
export const deleteCloudProduct = (id: string) =>
invoke<void>("delete_cloud_product", { id });
// ── Cloud DB Databases ────────────────────────────────────────────────────────
export interface CloudDatabase {
id: string;
product_id: string;
name: string;
db_driver: string; // postgresql | mysql | redis | mongodb | custom
username?: string;
password?: string;
charset?: string;
notes?: string;
sort_order: number;
created_at?: string;
updated_at?: string;
}
export interface SaveCloudDatabaseInput {
product_id: string;
name: string;
db_driver: string;
username?: string;
password?: string;
charset?: string;
notes?: string;
sort_order?: number;
}
export const getCloudDatabases = (productId: string) =>
invoke<CloudDatabase[]>("get_cloud_databases", { productId });
export const addCloudDatabase = (input: SaveCloudDatabaseInput) =>
invoke<CloudDatabase>("add_cloud_database", { input });
export const editCloudDatabase = (id: string, input: SaveCloudDatabaseInput) =>
invoke<CloudDatabase>("edit_cloud_database", { id, input });
export const deleteCloudDatabase = (id: string) =>
invoke<void>("delete_cloud_database", { id });
// ── Docker Apps ──────────────────────────────────────────────────────────────
export interface DockerApp {
id: string;
product_id: string;
name: string;
access_url?: string;
username?: string;
password?: string;
notes?: string;
sort_order: number;
created_at?: string;
updated_at?: string;
}
export interface SaveDockerAppInput {
product_id: string;
name: string;
access_url?: string;
username?: string;
password?: string;
notes?: string;
sort_order?: number;
}
export const getDockerApps = (productId: string) =>
invoke<DockerApp[]>("get_docker_apps", { productId });
export const addDockerApp = (input: SaveDockerAppInput) =>
invoke<DockerApp>("add_docker_app", { input });
export const editDockerApp = (id: string, input: SaveDockerAppInput) =>
invoke<DockerApp>("edit_docker_app", { id, input });
export const deleteDockerApp = (id: string) =>
invoke<void>("delete_docker_app", { id });