import type { AgentRuntime, CreateRepositoryInput, CreateSubagentInput, GithubAppConfig, InstallableRepo, Repository, } from "@vtit-agent-coding/shared"; import { getAuthToken, refreshAuthToken } from "./auth-client"; const API_BASE = "/api"; async function request(method: string, path: string, body?: unknown): Promise { const token = getAuthToken() ?? (await refreshAuthToken()); if (!token) throw new Error("NOT_AUTHENTICATED"); let res = await fetch(`${API_BASE}${path}`, { method, headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: body ? JSON.stringify(body) : undefined, }); if (res.status === 401) { const freshToken = await refreshAuthToken(); if (freshToken) { res = await fetch(`${API_BASE}${path}`, { method, headers: { "Content-Type": "application/json", Authorization: `Bearer ${freshToken}`, }, body: body ? JSON.stringify(body) : undefined, }); } } const data = (await res.json()) as any; if (!res.ok) { const err = new Error(data.error?.message || `HTTP ${res.status}`); (err as any).code = data.error?.code || "UNKNOWN"; (err as any).status = res.status; throw err; } return data as T; } export const api = { tasks: { list: (params?: Record) => { const qs = params ? `?${new URLSearchParams(params).toString()}` : ""; return request("GET", `/tasks${qs}`); }, get: (id: string) => request("GET", `/tasks/${id}`), session: (id: string) => request("GET", `/tasks/${id}/session`), sessionWs: (id: string) => request<{ url: string }>("GET", `/tasks/${id}/session/ws`), create: (input: Record) => request("POST", "/tasks", input), update: (id: string, body: Record) => request("PATCH", `/tasks/${id}`, body), delete: (id: string) => request("DELETE", `/tasks/${id}`), claim: (id: string) => request("POST", `/tasks/${id}/claim`), complete: (id: string) => request("POST", `/tasks/${id}/complete`), release: (id: string) => request("POST", `/tasks/${id}/release`), cancel: (id: string) => request("POST", `/tasks/${id}/cancel`), review: (id: string) => request("POST", `/tasks/${id}/review`), reject: (id: string) => request("POST", `/tasks/${id}/reject`), assign: (id: string, agentId: string) => request("POST", `/tasks/${id}/assign`, { agent_id: agentId }), addNote: (id: string, detail: string) => request("POST", `/tasks/${id}/notes`, { detail }), getNotes: (id: string, since?: string) => { const qs = since ? `?since=${encodeURIComponent(since)}` : ""; return request("GET", `/tasks/${id}/notes${qs}`); }, }, messages: { list: (taskId: string, since?: string) => { const qs = since ? `?since=${encodeURIComponent(since)}` : ""; return request("GET", `/tasks/${taskId}/messages${qs}`); }, create: (taskId: string, body: { sender_type: string; sender_id: string; content: string }) => request("POST", `/tasks/${taskId}/messages`, body), }, sessions: { list: (params?: { limit?: number; cursor?: string; state?: string; archived?: boolean; labelSelector?: string }) => { const query = new URLSearchParams(); if (params?.limit !== undefined) query.set("limit", String(params.limit)); if (params?.cursor) query.set("cursor", params.cursor); if (params?.state) query.set("state", params.state); if (params?.archived !== undefined) query.set("archived", String(params.archived)); if (params?.labelSelector) query.set("labelSelector", params.labelSelector); const qs = query.size > 0 ? `?${query.toString()}` : ""; return request<{ data: any[]; pagination: any }>("GET", `/sessions${qs}`); }, get: (id: string) => request("GET", `/sessions/${id}`), sessionWs: (id: string) => request<{ url: string }>("GET", `/sessions/${id}/ws`), }, agents: { list: (params?: Record) => { const qs = params ? `?${new URLSearchParams(params).toString()}` : ""; return request("GET", `/agents${qs}`); }, get: (id: string) => request("GET", `/agents/${id}`), create: (input: { name?: string; username: string; bio?: string; soul?: string; role?: string; handoff_to?: string[]; runtime: AgentRuntime; model?: string; skills?: string[]; }) => request("POST", "/agents", input), update: (id: string, body: Record) => request("PATCH", `/agents/${id}`, body), delete: (id: string) => request("DELETE", `/agents/${id}`), inbox: (agentId: string) => request<{ emails: any[] }>("GET", `/agents/${agentId}/inbox`), inboxEmail: (agentId: string, emailId: string) => request("GET", `/agents/${agentId}/inbox/${emailId}`), sessions: (agentId: string) => request("GET", `/agents/${agentId}/sessions`), }, machines: { list: () => request("GET", "/machines"), get: (id: string) => request("GET", `/machines/${id}`), createCloud: (input?: { name?: string }) => request("POST", "/machines/cloud", input ?? {}), delete: (id: string) => request("DELETE", `/machines/${id}`), }, ama: { provision: () => request<{ ok: boolean; project_id: string }>("POST", "/ama/provision"), }, subagents: { list: () => request("GET", "/subagents"), get: (id: string) => request("GET", `/subagents/${id}`), create: (input: CreateSubagentInput) => request("POST", "/subagents", input), update: (id: string, body: Partial) => request("PATCH", `/subagents/${id}`, body), delete: (id: string) => request("DELETE", `/subagents/${id}`), }, boards: { list: () => request("GET", "/boards"), get: (id: string) => request("GET", `/boards/${id}`), create: (input: { name: string; type: "dev" | "ops"; description?: string }) => request("POST", "/boards", input), update: (id: string, body: { name?: string; description?: string; visibility?: "private" | "public"; labels?: any[] }) => request("PATCH", `/boards/${id}`, body), createLabel: (id: string, body: { name: string; color: string; description?: string }) => request("POST", `/boards/${id}/labels`, body), updateLabel: (id: string, name: string, body: { name?: string; color?: string; description?: string }) => request("PATCH", `/boards/${id}/labels/${encodeURIComponent(name)}`, body), deleteLabel: (id: string, name: string) => request("DELETE", `/boards/${id}/labels/${encodeURIComponent(name)}`), maintainers: (id: string) => request("GET", `/boards/${id}/maintainers`), getMaintainer: (id: string, maintainerId: string) => request("GET", `/boards/${id}/maintainers/${maintainerId}`), maintainerVariables: (id: string, maintainerId: string) => request<{ data: { name: string }[]; credential_id: string | null; updated_at: string | null }>( "GET", `/boards/${id}/maintainers/${maintainerId}/variables`, ), updateMaintainerVariables: (id: string, maintainerId: string, body: { variables: Record }) => request<{ data: { name: string }[]; credential_id: string | null; updated_at: string | null }>( "PUT", `/boards/${id}/maintainers/${maintainerId}/variables`, body, ), maintainerRuns: (id: string, maintainerId: string, limit = 100) => request<{ data: any[]; pagination: any }>("GET", `/boards/${id}/maintainers/${maintainerId}/runs?limit=${limit}`), maintainerMemories: (id: string, maintainerId: string, limit = 100) => request<{ data: any[]; pagination: any }>("GET", `/boards/${id}/maintainers/${maintainerId}/memories?limit=${limit}`), createMaintainer: (id: string, body: Record) => request("POST", `/boards/${id}/maintainers`, body), updateMaintainer: (id: string, maintainerId: string, body: Record) => request("PATCH", `/boards/${id}/maintainers/${maintainerId}`, body), deleteMaintainer: (id: string, maintainerId: string) => request("DELETE", `/boards/${id}/maintainers/${maintainerId}`), delete: (id: string) => request("DELETE", `/boards/${id}`), }, share: { getBoard: (slug: string) => fetch(`/api/share/${slug}`).then((r) => { if (!r.ok) throw new Error("Board not found"); return r.json(); }) as Promise, }, repositories: { list: () => request("GET", "/repositories"), create: (input: CreateRepositoryInput) => request("POST", "/repositories", input), delete: (id: string) => request("DELETE", `/repositories/${id}`), }, githubApp: { config: () => request("GET", "/github-app/config"), installableRepos: () => request<{ installed: boolean; repositories: InstallableRepo[] }>("GET", "/github-app/repositories"), }, admin: { getStats: () => request("GET", "/admin/stats"), getMachines: () => request("GET", "/admin/machines"), }, projects: { list: () => request("GET", "/projects"), get: (id: string) => request("GET", `/projects/${id}`), getBoard: (projectId: string) => request("GET", `/projects/${projectId}/board`), getMasterPlan: (projectId: string) => request("GET", `/projects/${projectId}/master-plan`), }, skills: { list: () => request("GET", "/skills"), get: (id: string) => request("GET", `/skills/${encodeURIComponent(id)}`), create: (input: { id: string; name: string; description?: string; content: string }) => request("POST", "/skills", input), update: (id: string, body: { name: string; description?: string | null; content: string }) => request("PATCH", `/skills/${encodeURIComponent(id)}`, body), delete: (id: string) => request("DELETE", `/skills/${encodeURIComponent(id)}`), import: (ref: string) => request("POST", "/skills/import", { ref }), }, };