From cf0a25af1d2834bfe6c5ea892ce5769936e5a673 Mon Sep 17 00:00:00 2001 From: soryu Date: Tue, 3 Feb 2026 22:01:29 +0000 Subject: Add makima chain mechanism --- makima/frontend/src/lib/api.ts | 236 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) (limited to 'makima/frontend/src/lib/api.ts') diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index f148d76..445537c 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -2948,3 +2948,239 @@ export async function listTaskPatches(taskId: string, contractId: string): Promi } return res.json(); } + +// ============================================================================= +// Chain Types and API +// ============================================================================= + +/** Chain status */ +export type ChainStatus = "active" | "completed" | "archived"; + +/** Chain summary for list view */ +export interface ChainSummary { + id: string; + name: string; + description: string | null; + status: ChainStatus; + contractCount: number; + completedContractCount: number; + loopEnabled: boolean; + loopCurrentIteration: number | null; + loopMaxIterations: number | null; + createdAt: string; + updatedAt: string; +} + +/** Full chain with contracts */ +export interface Chain { + id: string; + ownerId: string; + name: string; + description: string | null; + status: ChainStatus; + loopEnabled: boolean; + loopMaxIterations: number | null; + loopCurrentIteration: number | null; + loopProgressCheck: string | null; + repositoryUrl: string | null; + localPath: string | null; + version: number; + createdAt: string; + updatedAt: string; +} + +/** Contract detail within a chain */ +export interface ChainContractDetail { + id: string; + chainId: string; + contractId: string; + contractName: string; + contractStatus: string; + contractPhase: string; + dependsOn: string[]; + orderIndex: number; + editorX: number | null; + editorY: number | null; + createdAt: string; +} + +/** Chain with contracts */ +export interface ChainWithContracts { + chain: Chain; + contracts: ChainContractDetail[]; +} + +/** Node in chain graph visualization */ +export interface ChainGraphNode { + id: string; + contractId: string; + name: string; + status: string; + phase: string; + x: number; + y: number; +} + +/** Edge in chain graph */ +export interface ChainGraphEdge { + from: string; + to: string; +} + +/** Chain graph response */ +export interface ChainGraphResponse { + chainId: string; + chainName: string; + chainStatus: string; + nodes: ChainGraphNode[]; + edges: ChainGraphEdge[]; +} + +/** Chain event */ +export interface ChainEvent { + id: string; + chainId: string; + eventType: string; + contractId: string | null; + eventData: Record | null; + createdAt: string; +} + +/** Chain list response */ +export interface ChainListResponse { + chains: ChainSummary[]; + total: number; +} + +/** Create chain request */ +export interface CreateChainRequest { + name: string; + description?: string; + repositoryUrl?: string; + localPath?: string; + loopEnabled?: boolean; + loopMaxIterations?: number; + loopProgressCheck?: string; + contracts?: CreateChainContractRequest[]; +} + +/** Create chain contract request */ +export interface CreateChainContractRequest { + name: string; + description?: string; + contractType?: string; + initialPhase?: string; + phases?: string[]; + dependsOn?: string[]; + tasks?: { name: string; plan: string }[]; + deliverables?: { id: string; name: string; priority?: string }[]; + editorX?: number; + editorY?: number; +} + +/** Update chain request */ +export interface UpdateChainRequest { + name?: string; + description?: string; + status?: ChainStatus; + loopEnabled?: boolean; + loopMaxIterations?: number; + loopProgressCheck?: string; + version?: number; +} + +/** List chains */ +export async function listChains( + status?: ChainStatus, + limit = 50, + offset = 0 +): Promise { + const params = new URLSearchParams(); + if (status) params.set("status", status); + params.set("limit", String(limit)); + params.set("offset", String(offset)); + + const res = await authFetch(`${API_BASE}/api/v1/chains?${params}`); + if (!res.ok) { + throw new Error(`Failed to list chains: ${res.statusText}`); + } + return res.json(); +} + +/** Get chain by ID */ +export async function getChain(chainId: string): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}`); + if (!res.ok) { + throw new Error(`Failed to get chain: ${res.statusText}`); + } + return res.json(); +} + +/** Create a new chain */ +export async function createChain(req: CreateChainRequest): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains`, { + method: "POST", + body: JSON.stringify(req), + }); + if (!res.ok) { + const errorText = await res.text(); + throw new Error(`Failed to create chain: ${errorText || res.statusText}`); + } + return res.json(); +} + +/** Update a chain */ +export async function updateChain( + chainId: string, + req: UpdateChainRequest +): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}`, { + method: "PUT", + body: JSON.stringify(req), + }); + if (!res.ok) { + const errorText = await res.text(); + throw new Error(`Failed to update chain: ${errorText || res.statusText}`); + } + return res.json(); +} + +/** Archive a chain */ +export async function archiveChain(chainId: string): Promise<{ archived: boolean }> { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}`, { + method: "DELETE", + }); + if (!res.ok) { + throw new Error(`Failed to archive chain: ${res.statusText}`); + } + return res.json(); +} + +/** Get chain contracts */ +export async function getChainContracts( + chainId: string +): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/contracts`); + if (!res.ok) { + throw new Error(`Failed to get chain contracts: ${res.statusText}`); + } + return res.json(); +} + +/** Get chain graph for visualization */ +export async function getChainGraph(chainId: string): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/graph`); + if (!res.ok) { + throw new Error(`Failed to get chain graph: ${res.statusText}`); + } + return res.json(); +} + +/** Get chain events */ +export async function getChainEvents(chainId: string): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/events`); + if (!res.ok) { + throw new Error(`Failed to get chain events: ${res.statusText}`); + } + return res.json(); +} -- cgit v1.2.3