From c732dd048128808cd9f67f6e1176a5b565df5678 Mon Sep 17 00:00:00 2001 From: soryu Date: Tue, 3 Feb 2026 23:49:08 +0000 Subject: Allow chain creation via web interface --- makima/frontend/src/lib/api.ts | 190 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 1 deletion(-) (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 bdaedf9..e5cf1d8 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -3008,7 +3008,7 @@ export async function listTaskPatches(taskId: string, contractId: string): Promi // ============================================================================= /** Chain status */ -export type ChainStatus = "active" | "completed" | "archived"; +export type ChainStatus = "pending" | "active" | "completed" | "archived"; /** Chain summary for list view */ export interface ChainSummary { @@ -3237,3 +3237,191 @@ export async function getChainEvents(chainId: string): Promise { } return res.json(); } + +// ============================================================================= +// Chain Contract Definitions +// ============================================================================= + +/** Task definition for chain contract definitions */ +export interface ChainTaskDefinition { + name: string; + plan: string; +} + +/** Deliverable definition for chain contract definitions (optional priority) */ +export interface ChainDeliverableDefinition { + id: string; + name: string; + priority?: string; +} + +/** Contract definition stored in chain (before actual contract is created) */ +export interface ChainContractDefinition { + id: string; + chainId: string; + name: string; + description: string | null; + contractType: string; + initialPhase: string | null; + dependsOnNames: string[]; + tasks: ChainTaskDefinition[] | null; + deliverables: ChainDeliverableDefinition[] | null; + editorX: number | null; + editorY: number | null; + orderIndex: number; + createdAt: string; +} + +/** Request to add a contract definition to a chain */ +export interface AddContractDefinitionRequest { + name: string; + description?: string; + contractType?: string; + initialPhase?: string; + dependsOn?: string[]; + tasks?: ChainTaskDefinition[]; + deliverables?: ChainDeliverableDefinition[]; + editorX?: number; + editorY?: number; + orderIndex?: number; +} + +/** Request to update a contract definition */ +export interface UpdateContractDefinitionRequest { + name?: string; + description?: string; + contractType?: string; + initialPhase?: string; + dependsOn?: string[]; + tasks?: ChainTaskDefinition[]; + deliverables?: ChainDeliverableDefinition[]; + editorX?: number; + editorY?: number; + orderIndex?: number; +} + +/** Response when starting a chain */ +export interface StartChainResponse { + chainId: string; + supervisorTaskId: string | null; + contractsCreated: string[]; + status: string; +} + +/** Node in definition graph (shows definitions + instantiation status) */ +export interface ChainDefinitionGraphNode { + id: string; + name: string; + contractType: string; + x: number; + y: number; + isInstantiated: boolean; + contractId: string | null; + contractStatus: string | null; +} + +/** Definition graph response */ +export interface ChainDefinitionGraphResponse { + chainId: string; + chainName: string; + chainStatus: string; + nodes: ChainDefinitionGraphNode[]; + edges: ChainGraphEdge[]; +} + +/** List contract definitions for a chain */ +export async function listChainDefinitions( + chainId: string +): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/definitions`); + if (!res.ok) { + throw new Error(`Failed to list chain definitions: ${res.statusText}`); + } + return res.json(); +} + +/** Create a contract definition for a chain */ +export async function createChainDefinition( + chainId: string, + req: AddContractDefinitionRequest +): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/definitions`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(req), + }); + if (!res.ok) { + throw new Error(`Failed to create chain definition: ${res.statusText}`); + } + return res.json(); +} + +/** Update a contract definition */ +export async function updateChainDefinition( + chainId: string, + definitionId: string, + req: UpdateContractDefinitionRequest +): Promise { + const res = await authFetch( + `${API_BASE}/api/v1/chains/${chainId}/definitions/${definitionId}`, + { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(req), + } + ); + if (!res.ok) { + throw new Error(`Failed to update chain definition: ${res.statusText}`); + } + return res.json(); +} + +/** Delete a contract definition */ +export async function deleteChainDefinition( + chainId: string, + definitionId: string +): Promise<{ deleted: boolean }> { + const res = await authFetch( + `${API_BASE}/api/v1/chains/${chainId}/definitions/${definitionId}`, + { method: "DELETE" } + ); + if (!res.ok) { + throw new Error(`Failed to delete chain definition: ${res.statusText}`); + } + return res.json(); +} + +/** Get definition graph for a chain */ +export async function getChainDefinitionGraph( + chainId: string +): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/definitions/graph`); + if (!res.ok) { + throw new Error(`Failed to get chain definition graph: ${res.statusText}`); + } + return res.json(); +} + +/** Start a chain (creates root contracts and spawns supervisor) */ +export async function startChain(chainId: string): Promise { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/start`, { + method: "POST", + }); + if (!res.ok) { + const error = await res.json().catch(() => ({ message: res.statusText })); + throw new Error(error.message || `Failed to start chain: ${res.statusText}`); + } + return res.json(); +} + +/** Stop a chain (kills supervisor, marks as archived) */ +export async function stopChain(chainId: string): Promise<{ stopped: boolean; status: string }> { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/stop`, { + method: "POST", + }); + if (!res.ok) { + const error = await res.json().catch(() => ({ message: res.statusText })); + throw new Error(error.message || `Failed to stop chain: ${res.statusText}`); + } + return res.json(); +} -- cgit v1.2.3