diff options
| author | soryu <soryu@soryu.co> | 2026-02-03 23:19:40 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-03 23:19:40 +0000 |
| commit | bfa3af9ef16fd5e255bdb606a99a5ebb535ba7cc (patch) | |
| tree | 53da855b4ca61a5c0856fc15112daa7a3748c637 /makima/frontend/src/lib/api.ts | |
| parent | 1ce281adb89683a5fccfd153706383b14b944f32 (diff) | |
| parent | dcbf8c834626870a43b633b099f409d69d4f9b87 (diff) | |
| download | soryu-bfa3af9ef16fd5e255bdb606a99a5ebb535ba7cc.tar.gz soryu-bfa3af9ef16fd5e255bdb606a99a5ebb535ba7cc.zip | |
fix: Resolve merge conflict in server/mod.rsmakima/discuss-contract-feature
Combine imports from both branches - include both chains and contract_discuss handlers.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/frontend/src/lib/api.ts')
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index f507c7a..bdaedf9 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -3002,3 +3002,238 @@ 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 (chain fields are flattened via serde(flatten)) */ +export interface ChainWithContracts extends 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<string, unknown> | 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<ChainListResponse> { + 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<ChainWithContracts> { + 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<Chain> { + 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<Chain> { + 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<ChainContractDetail[]> { + 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<ChainGraphResponse> { + 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<ChainEvent[]> { + 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(); +} |
