import { safeJson } from "@/features/agent/safe-json"; import type { GitAction, GitBranch, GitState, GitWorktree } from "@/features/agent/contracts"; import type { GitSummary, Project } from "@/features/agent/projects/types"; type DesktopBridge = { openDirectory?: () => Promise; listProjects?: () => Promise; removeProject?: (id: string) => Promise<{ ok: true }>; }; function getDesktopBridge(): DesktopBridge | null { if (typeof window === "undefined") return null; const candidate = (window as unknown as { localStudioDesktop?: Partial }) .localStudioDesktop; if (!candidate) return null; const hasBridgeMethod = typeof candidate.openDirectory === "function" || typeof candidate.listProjects === "function" || typeof candidate.removeProject === "function"; return hasBridgeMethod ? (candidate as DesktopBridge) : null; } export async function loadProjects(): Promise { const bridge = getDesktopBridge(); if (bridge?.listProjects) return bridge.listProjects(); const response = await fetch("/api/agent/projects", { cache: "no-store" }); const payload = (await response.json()) as { projects?: Project[]; error?: string }; if (!response.ok) throw new Error(payload.error || "Failed to load projects"); return payload.projects ?? []; } export type OpenProjectDirectoryResult = | { source: "desktop"; project: Project | null } | { source: "fallback" }; export async function openProjectDirectory(): Promise { const bridge = getDesktopBridge(); if (!bridge?.openDirectory) return { source: "fallback" }; return { source: "desktop", project: await bridge.openDirectory() }; } export async function addProjectFromPath(path: string): Promise { const response = await fetch("/api/agent/projects", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ path }), }); const payload = (await response.json()) as { project?: Project; error?: string }; if (!response.ok || !payload.project) { throw new Error(payload.error || "Failed to add project"); } return payload.project; } export async function removeProject(id: string): Promise { const bridge = getDesktopBridge(); if (bridge?.removeProject) { await bridge.removeProject(id); return; } const response = await fetch(`/api/agent/projects?id=${encodeURIComponent(id)}`, { method: "DELETE", }); if (!response.ok) { const payload = (await response.json().catch(() => ({}))) as { error?: string }; throw new Error(payload.error || "Failed to remove project"); } } export async function loadGitSummary(cwd: string): Promise { const response = await fetch(`/api/agent/git?cwd=${encodeURIComponent(cwd)}`, { cache: "no-store", }); const payload = await safeJson(response); return { isRepo: payload.isRepo === true, branch: payload.branch ?? null, additions: payload.additions ?? 0, deletions: payload.deletions ?? 0, statusCount: payload.status?.length ?? 0, }; } export async function initGit(cwd: string): Promise { const response = await fetch(`/api/agent/git?cwd=${encodeURIComponent(cwd)}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "init" }), }); if (!response.ok) { const payload = await safeJson<{ error?: string }>(response); throw new Error(payload.error || "Failed to initialize git repository"); } } export async function listBranches(cwd: string): Promise { const response = await fetch(`/api/agent/git/branches?cwd=${encodeURIComponent(cwd)}`, { cache: "no-store", }); const payload = await safeJson<{ branches?: GitBranch[]; error?: string }>(response); if (!response.ok) throw new Error(payload.error || "Failed to list branches"); return payload.branches ?? []; } export async function listWorktrees(cwd: string): Promise { const response = await fetch(`/api/agent/git/worktrees?cwd=${encodeURIComponent(cwd)}`, { cache: "no-store", }); const payload = await safeJson<{ worktrees?: GitWorktree[]; error?: string }>(response); if (!response.ok) throw new Error(payload.error || "Failed to list worktrees"); return payload.worktrees ?? []; } export async function runGitAction(cwd: string, action: GitAction): Promise { const response = await fetch(`/api/agent/git?cwd=${encodeURIComponent(cwd)}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(action), }); if (!response.ok) { const payload = await safeJson<{ error?: string }>(response); throw new Error(payload.error || "Git operation failed"); } } export async function switchBranch(cwd: string, branch: string): Promise { await runGitAction(cwd, { action: "switch_branch", branch }); } export async function createBranch(cwd: string, branch: string): Promise { await runGitAction(cwd, { action: "create_branch", branch }); } export async function addWorktree(cwd: string, branch: string, path: string): Promise { await runGitAction(cwd, { action: "add_worktree", branch, path }); } export async function removeWorktree(cwd: string, path: string): Promise { await runGitAction(cwd, { action: "remove_worktree", path }); }