export type TestStatus = "pass" | "fail"; export interface TestCasePayload { name: string; status: TestStatus; details?: string | null; } export interface RecordTestsPayload { story_id: string; unit: TestCasePayload[]; integration: TestCasePayload[]; } export interface AcceptanceRequest { story_id: string; } export interface TestRunSummaryResponse { total: number; passed: number; failed: number; } export interface CoverageReportResponse { current_percent: number; threshold_percent: number; baseline_percent?: number | null; } export interface AcceptanceResponse { can_accept: boolean; reasons: string[]; warning?: string | null; summary: TestRunSummaryResponse; missing_categories: string[]; coverage_report?: CoverageReportResponse | null; } export interface ReviewStory { story_id: string; can_accept: boolean; reasons: string[]; warning?: string | null; summary: TestRunSummaryResponse; missing_categories: string[]; coverage_report?: CoverageReportResponse | null; } export interface RecordCoveragePayload { story_id: string; current_percent: number; threshold_percent?: number | null; } export interface CollectCoverageRequest { story_id: string; threshold_percent?: number | null; } export interface ReviewListResponse { stories: ReviewStory[]; } export interface StoryTodosResponse { story_id: string; story_name: string | null; todos: string[]; } export interface TodoListResponse { stories: StoryTodosResponse[]; } export interface UpcomingStory { story_id: string; name: string | null; } export interface UpcomingStoriesResponse { stories: UpcomingStory[]; } const DEFAULT_API_BASE = "/api"; function buildApiUrl(path: string, baseUrl = DEFAULT_API_BASE): string { return `${baseUrl}${path}`; } async function requestJson( path: string, options: RequestInit = {}, baseUrl = DEFAULT_API_BASE, ): Promise { const res = await fetch(buildApiUrl(path, baseUrl), { headers: { "Content-Type": "application/json", ...(options.headers ?? {}), }, ...options, }); if (!res.ok) { const text = await res.text(); throw new Error(text || `Request failed (${res.status})`); } return res.json() as Promise; } export const workflowApi = { collectCoverage(payload: CollectCoverageRequest, baseUrl?: string) { return requestJson( "/workflow/coverage/collect", { method: "POST", body: JSON.stringify(payload) }, baseUrl, ); }, recordCoverage(payload: RecordCoveragePayload, baseUrl?: string) { return requestJson( "/workflow/coverage/record", { method: "POST", body: JSON.stringify(payload) }, baseUrl, ); }, recordTests(payload: RecordTestsPayload, baseUrl?: string) { return requestJson( "/workflow/tests/record", { method: "POST", body: JSON.stringify(payload) }, baseUrl, ); }, getAcceptance(payload: AcceptanceRequest, baseUrl?: string) { return requestJson( "/workflow/acceptance", { method: "POST", body: JSON.stringify(payload) }, baseUrl, ); }, getReviewQueue(baseUrl?: string) { return requestJson("/workflow/review", {}, baseUrl); }, getReviewQueueAll(baseUrl?: string) { return requestJson("/workflow/review/all", {}, baseUrl); }, getUpcomingStories(baseUrl?: string) { return requestJson( "/workflow/upcoming", {}, baseUrl, ); }, ensureAcceptance(payload: AcceptanceRequest, baseUrl?: string) { return requestJson( "/workflow/acceptance/ensure", { method: "POST", body: JSON.stringify(payload) }, baseUrl, ); }, getStoryTodos(baseUrl?: string) { return requestJson("/workflow/todos", {}, baseUrl); }, };