import type { Task, TaskDetail, TaskAttachment, TaskCreateInput, AgentLogEntry, Column, MergeResult, Settings } from "@kb/core"; async function api(path: string, opts: RequestInit = {}): Promise { const res = await fetch(`/api${path}`, { headers: { "Content-Type": "application/json" }, ...opts, }); const data = await res.json(); if (!res.ok) throw new Error((data as { error?: string }).error || "Request failed"); return data as T; } export function fetchTasks(): Promise { return api("/tasks"); } export async function fetchTaskDetail(id: string): Promise { const maxAttempts = 2; // 1 initial + 1 retry for (let attempt = 1; attempt <= maxAttempts; attempt++) { const res = await fetch(`/api/tasks/${id}`, { headers: { "Content-Type": "application/json" }, }); const data = await res.json(); if (res.ok) return data as TaskDetail; if (attempt === maxAttempts) { throw new Error((data as { error?: string }).error || "Request failed"); } } // unreachable throw new Error("Request failed"); } export function createTask(input: TaskCreateInput): Promise { return api("/tasks", { method: "POST", body: JSON.stringify(input), }); } export function updateTask(id: string, updates: { title?: string; description?: string; prompt?: string; dependencies?: string[] }): Promise { return api(`/tasks/${id}`, { method: "PATCH", body: JSON.stringify(updates), }); } export function moveTask(id: string, column: Column): Promise { return api(`/tasks/${id}/move`, { method: "POST", body: JSON.stringify({ column }), }); } export function deleteTask(id: string): Promise { return api(`/tasks/${id}`, { method: "DELETE" }); } export function mergeTask(id: string): Promise { return api(`/tasks/${id}/merge`, { method: "POST" }); } export function retryTask(id: string): Promise { return api(`/tasks/${id}/retry`, { method: "POST" }); } export function duplicateTask(id: string): Promise { return api(`/tasks/${id}/duplicate`, { method: "POST" }); } export function pauseTask(id: string): Promise { return api(`/tasks/${id}/pause`, { method: "POST" }); } export function unpauseTask(id: string): Promise { return api(`/tasks/${id}/unpause`, { method: "POST" }); } export function fetchConfig(): Promise<{ maxConcurrent: number }> { return api<{ maxConcurrent: number }>("/config"); } export function fetchSettings(): Promise { return api("/settings"); } export function updateSettings(settings: Partial): Promise { return api("/settings", { method: "PUT", body: JSON.stringify(settings), }); } export async function uploadAttachment(id: string, file: File): Promise { const formData = new FormData(); formData.append("file", file); const res = await fetch(`/api/tasks/${id}/attachments`, { method: "POST", body: formData, }); const data = await res.json(); if (!res.ok) throw new Error((data as { error?: string }).error || "Upload failed"); return data as TaskAttachment; } export async function deleteAttachment(id: string, filename: string): Promise { return api(`/tasks/${id}/attachments/${filename}`, { method: "DELETE" }); } export function fetchAgentLogs(taskId: string): Promise { return api(`/tasks/${taskId}/logs`); } export function addSteeringComment(id: string, text: string): Promise { return api(`/tasks/${id}/steer`, { method: "POST", body: JSON.stringify({ text }), }); } // --- Models API --- /** Available AI model info returned by the models endpoint */ export interface ModelInfo { provider: string; id: string; name: string; reasoning: boolean; contextWindow: number; } /** Fetch available AI models from the model registry */ export function fetchModels(): Promise { return api("/models"); } // --- Auth API --- /** OAuth provider with current authentication status */ export interface AuthProvider { id: string; name: string; authenticated: boolean; } /** Fetch authentication status for all OAuth providers */ export function fetchAuthStatus(): Promise<{ providers: AuthProvider[] }> { return api<{ providers: AuthProvider[] }>("/auth/status"); } /** Initiate OAuth login for a provider. Returns the auth URL to open in a new tab. */ export function loginProvider(provider: string): Promise<{ url: string; instructions?: string }> { return api<{ url: string; instructions?: string }>("/auth/login", { method: "POST", body: JSON.stringify({ provider }), }); } /** Logout from a provider, removing stored credentials. */ export function logoutProvider(provider: string): Promise<{ success: boolean }> { return api<{ success: boolean }>("/auth/logout", { method: "POST", body: JSON.stringify({ provider }), }); } // --- GitHub Import API --- /** GitHub issue returned by the fetch endpoint */ export interface GitHubIssue { number: number; title: string; body: string | null; html_url: string; labels: Array<{ name: string }>; } /** Fetch open GitHub issues from a repository */ export function apiFetchGitHubIssues( owner: string, repo: string, limit?: number, labels?: string[] ): Promise { return api("/github/issues/fetch", { method: "POST", body: JSON.stringify({ owner, repo, limit, labels }), }); } /** Import a specific GitHub issue as a kb task */ export function apiImportGitHubIssue(owner: string, repo: string, issueNumber: number): Promise { return api("/github/issues/import", { method: "POST", body: JSON.stringify({ owner, repo, issueNumber }), }); } // --- Git Remote Detection API --- /** Git remote info returned by the remotes endpoint */ export interface GitRemote { name: string; owner: string; repo: string; url: string; } /** Fetch GitHub remotes from the current git repository */ export function fetchGitRemotes(): Promise { return api("/git/remotes"); } // --- PR Management API --- /** PR info returned by PR endpoints */ export interface PrInfo { url: string; number: number; status: "open" | "closed" | "merged"; title: string; headBranch: string; baseBranch: string; commentCount: number; lastCommentAt?: string; lastCheckedAt?: string; } /** Create a GitHub PR for a task */ export function createPr( id: string, params: { title: string; body?: string; base?: string } ): Promise { return api(`/tasks/${id}/pr/create`, { method: "POST", body: JSON.stringify(params), }); } /** Fetch cached PR status for a task */ export function fetchPrStatus(id: string): Promise<{ prInfo: PrInfo; stale: boolean }> { return api<{ prInfo: PrInfo; stale: boolean }>(`/tasks/${id}/pr/status`); } /** Force refresh PR status from GitHub */ export function refreshPrStatus(id: string): Promise { return api(`/tasks/${id}/pr/refresh`, { method: "POST", }); }