- 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
1987 lines
59 KiB
TypeScript
1987 lines
59 KiB
TypeScript
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 });
|
||
|