From c8b169da8cb7eae0957e0ab5e7370b071093a224 Mon Sep 17 00:00:00 2001 From: soryu Date: Tue, 28 Apr 2026 00:18:40 +0100 Subject: feat: Document UI for directive orchestration with Lexical editor (#93) * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Save previous goal on update and include history in re-planning prompt * feat: soryu-co/soryu - makima: Install Lexical and create base document editor component * feat: soryu-co/soryu - makima: Create directive file system sidebar and document layout * feat: soryu-co/soryu - makima: Create custom Lexical step diagram block * feat: soryu-co/soryu - makima: Add context menu and goal auto-update integration * WIP: heartbeat checkpoint --- frontend/src/services/directiveApi.ts | 136 ++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 frontend/src/services/directiveApi.ts (limited to 'frontend/src/services') diff --git a/frontend/src/services/directiveApi.ts b/frontend/src/services/directiveApi.ts new file mode 100644 index 0000000..b82f594 --- /dev/null +++ b/frontend/src/services/directiveApi.ts @@ -0,0 +1,136 @@ +// API service for directive operations + +export interface DirectiveStepCounts { + pending: number + ready: number + running: number + completed: number + failed: number + skipped: number +} + +export interface DirectiveSummary { + id: string + title: string + goal: string + status: string + repositoryUrl: string + prUrl: string + prBranch: string + createdAt: string + updatedAt: string + goalUpdatedAt: string + stepCounts: DirectiveStepCounts + version?: number + pr_branch?: string | null +} + +export interface DirectiveStep { + id: string + directiveId: string + directive_id?: string + name: string + title?: string + description: string | null + taskPlan: string + dependsOn: string[] + status: string + taskId: string + contractId: string + orderIndex: number + sort_order?: number + completedAt: string +} + +export interface DirectiveWithSteps extends DirectiveSummary { + steps: DirectiveStep[] + reconcileMode: string +} + +// Alias for compatibility with context-menu branch types +export type Directive = DirectiveSummary + +async function apiFetch(path: string, options?: RequestInit): Promise { + const response = await fetch(path, { + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + }) + if (!response.ok) { + const body = await response.json().catch(() => ({ message: response.statusText })) + throw new Error(body.message ?? body.error ?? `API error ${response.status}: ${response.statusText}`) + } + return response +} + +export async function listDirectives(): Promise { + const response = await apiFetch('/api/v1/directives') + const data = await response.json() + return data.directives || [] +} + +export async function getDirective(id: string): Promise { + const response = await apiFetch(`/api/v1/directives/${id}`) + return response.json() +} + +export async function getDirectiveSteps(id: string): Promise { + const response = await apiFetch(`/api/v1/directives/${id}/steps`) + return response.json() +} + +export async function updateGoal(id: string, goal: string): Promise { + const response = await apiFetch(`/api/v1/directives/${id}/goal`, { + method: 'PUT', + body: JSON.stringify({ goal }), + }) + return response.json() +} + +export async function updateDirective( + id: string, + updates: { title?: string; goal?: string; version?: number }, +): Promise { + const response = await apiFetch(`/api/v1/directives/${id}`, { + method: 'PUT', + body: JSON.stringify(updates), + }) + return response.json() +} + +export async function cleanupDirective(id: string): Promise { + await apiFetch(`/api/v1/directives/${id}/cleanup`, { method: 'POST' }) +} + +export async function createPr(id: string): Promise<{ prUrl: string }> { + const response = await apiFetch(`/api/v1/directives/${id}/create-pr`, { method: 'POST' }) + return response.json() +} + +export async function pickUpOrders(id: string): Promise { + await apiFetch(`/api/v1/directives/${id}/pick-up-orders`, { method: 'POST' }) +} + +export async function startDirective(id: string): Promise { + const response = await apiFetch(`/api/v1/directives/${id}/start`, { method: 'POST' }) + return response.json() +} + +export async function pauseDirective(id: string): Promise { + const response = await apiFetch(`/api/v1/directives/${id}/pause`, { method: 'POST' }) + return response.json() +} + +export async function getUserSetting(key: string): Promise { + const response = await apiFetch(`/api/v1/settings/${key}`) + return response.json() +} + +export async function upsertUserSetting(key: string, value: any): Promise { + await apiFetch('/api/v1/settings', { + method: 'PUT', + body: JSON.stringify({ key, value }), + }) +} -- cgit v1.2.3