summaryrefslogtreecommitdiff
path: root/makima/frontend/src/lib/api.ts
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-03 23:49:08 +0000
committersoryu <soryu@soryu.co>2026-02-03 23:49:19 +0000
commitc732dd048128808cd9f67f6e1176a5b565df5678 (patch)
tree6ebf359c9c3f2d8aca264c53da6367b7f0af5fc8 /makima/frontend/src/lib/api.ts
parent9ebc9724afcc0482a8e7cd2369c06208fedbcbd1 (diff)
downloadsoryu-c732dd048128808cd9f67f6e1176a5b565df5678.tar.gz
soryu-c732dd048128808cd9f67f6e1176a5b565df5678.zip
Allow chain creation via web interface
Diffstat (limited to 'makima/frontend/src/lib/api.ts')
-rw-r--r--makima/frontend/src/lib/api.ts190
1 files changed, 189 insertions, 1 deletions
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<ChainEvent[]> {
}
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<ChainContractDefinition[]> {
+ 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<ChainContractDefinition> {
+ 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<ChainContractDefinition> {
+ 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<ChainDefinitionGraphResponse> {
+ 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<StartChainResponse> {
+ 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();
+}