From 1b692b8cde4a888c8a35af69231f181b57bf5619 Mon Sep 17 00:00:00 2001 From: soryu Date: Fri, 6 Feb 2026 20:06:30 +0000 Subject: Fix: Cleanup old chain code --- makima/frontend/src/routes/directives.tsx | 1106 +---------------------------- 1 file changed, 18 insertions(+), 1088 deletions(-) (limited to 'makima/frontend/src/routes') diff --git a/makima/frontend/src/routes/directives.tsx b/makima/frontend/src/routes/directives.tsx index 35e5703..90f0854 100644 --- a/makima/frontend/src/routes/directives.tsx +++ b/makima/frontend/src/routes/directives.tsx @@ -1,31 +1,17 @@ -import { useState, useCallback, useEffect, useMemo } from "react"; +import { useState, useCallback, useEffect } from "react"; import { useParams, useNavigate } from "react-router"; -import { - ReactFlow, - Edge, - Controls, - Background, - Handle, - Position, - BackgroundVariant, - MarkerType, -} from "@xyflow/react"; -import "@xyflow/react/dist/style.css"; import { Masthead } from "../components/Masthead"; -import { useDirectives, useDirectiveEventSubscription } from "../hooks/useDirectives"; +import { useDirectives } from "../hooks/useDirectives"; +import { useDirectiveDetail } from "../hooks/useDirectiveDetail"; import { useAuth } from "../contexts/AuthContext"; import type { DirectiveSummary, - DirectiveWithProgress, - DirectiveGraphResponse, - DirectiveGraphNode, CreateDirectiveRequest, - RepositoryHistoryEntry, AutonomyLevel, - StepStatus, - ConfidenceLevel, } from "../lib/api"; -import { getRepositorySuggestions } from "../lib/api"; +import { DirectiveList } from "../components/directives/DirectiveList"; +import { DirectiveDetail } from "../components/directives/DirectiveDetail"; +import { CreateDirectiveModal } from "../components/directives/CreateDirectiveModal"; export default function DirectivesPage() { const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth(); @@ -67,33 +53,20 @@ function DirectivesPageContent() { error, createNewDirective, archiveExistingDirective, - getDirectiveById, - getGraph, - start, - pause, - resume, - stop, } = useDirectives(); - const [directiveDetail, setDirectiveDetail] = useState(null); - const [directiveGraph, setDirectiveGraph] = useState(null); - const [detailLoading, setDetailLoading] = useState(false); - const [isCreating, setIsCreating] = useState(false); + const { + directive: directiveDetail, + graph: directiveGraph, + loading: detailLoading, + refresh: refreshDetail, + start: handleStart, + pause: handlePause, + resume: handleResume, + stop: handleStop, + } = useDirectiveDetail(id); - // Load directive detail when ID changes - useEffect(() => { - if (id) { - setDetailLoading(true); - Promise.all([getDirectiveById(id), getGraph(id).catch(() => null)]).then(([directive, graph]) => { - setDirectiveDetail(directive); - setDirectiveGraph(graph); - setDetailLoading(false); - }); - } else { - setDirectiveDetail(null); - setDirectiveGraph(null); - } - }, [id, getDirectiveById, getGraph]); + const [isCreating, setIsCreating] = useState(false); const handleSelect = useCallback( (directiveId: string) => { @@ -147,45 +120,6 @@ function DirectivesPageContent() { [archiveExistingDirective, id, navigate] ); - const handleRefresh = useCallback(async () => { - if (id) { - const [directive, graph] = await Promise.all([ - getDirectiveById(id), - getGraph(id).catch(() => null), - ]); - setDirectiveDetail(directive); - setDirectiveGraph(graph); - } - }, [id, getDirectiveById, getGraph]); - - const handleStart = useCallback(async () => { - if (id) { - await start(id); - handleRefresh(); - } - }, [id, start, handleRefresh]); - - const handlePause = useCallback(async () => { - if (id) { - await pause(id); - handleRefresh(); - } - }, [id, pause, handleRefresh]); - - const handleResume = useCallback(async () => { - if (id) { - await resume(id); - handleRefresh(); - } - }, [id, resume, handleRefresh]); - - const handleStop = useCallback(async () => { - if (id) { - await stop(id); - handleRefresh(); - } - }, [id, stop, handleRefresh]); - return (
@@ -222,7 +156,7 @@ function DirectivesPageContent() { graph={directiveGraph} loading={detailLoading} onBack={handleBack} - onRefresh={handleRefresh} + onRefresh={refreshDetail} onStart={handleStart} onPause={handlePause} onResume={handleResume} @@ -248,1007 +182,3 @@ function DirectivesPageContent() {
); } - -// ============================================================================= -// Directive List Component -// ============================================================================= - -interface DirectiveListProps { - directives: DirectiveSummary[]; - loading: boolean; - onSelect: (id: string) => void; - onCreate: () => void; - selectedId?: string; - onArchive: (directive: DirectiveSummary) => void; -} - -function DirectiveList({ - directives, - loading, - onSelect, - onCreate, - selectedId, - onArchive, -}: DirectiveListProps) { - const [filter, setFilter] = useState<"all" | "active" | "completed" | "failed">("all"); - - const filteredDirectives = directives.filter((d) => { - if (filter === "all") return true; - if (filter === "active") return ["draft", "planning", "active", "paused"].includes(d.status); - if (filter === "completed") return d.status === "completed"; - if (filter === "failed") return d.status === "failed"; - return true; - }); - - return ( -
-
-

Directives

- -
- - {/* Filters */} -
- {(["all", "active", "completed", "failed"] as const).map((f) => ( - - ))} -
- - {/* List */} -
- {loading ? ( -
-

Loading...

-
- ) : filteredDirectives.length === 0 ? ( -
-

No directives found

-
- ) : ( - filteredDirectives.map((d) => ( - onSelect(d.id)} - onArchive={() => onArchive(d)} - /> - )) - )} -
-
- ); -} - -interface DirectiveListItemProps { - directive: DirectiveSummary; - selected: boolean; - onClick: () => void; - onArchive: () => void; -} - -function DirectiveListItem({ directive, selected, onClick, onArchive }: DirectiveListItemProps) { - const progress = directive.totalSteps > 0 - ? Math.round((directive.completedSteps / directive.totalSteps) * 100) - : 0; - - const statusColor = { - draft: "text-[#556677]", - planning: "text-yellow-400", - active: "text-green-400", - paused: "text-yellow-400", - completed: "text-[#75aafc]", - archived: "text-[#556677]", - failed: "text-red-400", - }[directive.status] || "text-[#556677]"; - - const confidenceColor = { - green: "bg-green-500", - yellow: "bg-yellow-500", - red: "bg-red-500", - }[directive.currentConfidence !== null && directive.currentConfidence >= 0.8 - ? "green" - : directive.currentConfidence !== null && directive.currentConfidence >= 0.5 - ? "yellow" - : "red"] || "bg-[#556677]"; - - return ( -
-
-
-
- {directive.title || directive.goal.slice(0, 50)} -
-
- - {directive.status} - - - {directive.completedSteps}/{directive.totalSteps} steps - -
-
-
- {directive.currentConfidence !== null && ( -
- )} - -
-
- - {/* Progress bar */} - {directive.totalSteps > 0 && ( -
-
-
- )} -
- ); -} - -// ============================================================================= -// Directive Detail Component -// ============================================================================= - -interface DirectiveDetailProps { - directive: DirectiveWithProgress; - graph: DirectiveGraphResponse | null; - loading: boolean; - onBack: () => void; - onRefresh: () => void; - onStart: () => void; - onPause: () => void; - onResume: () => void; - onStop: () => void; -} - -function DirectiveDetail({ - directive, - graph, - loading, - onBack, - onRefresh, - onStart, - onPause, - onResume, - onStop, -}: DirectiveDetailProps) { - const [activeTab, setActiveTab] = useState<"overview" | "chain" | "events" | "evaluations" | "approvals" | "verifiers">("overview"); - - if (loading) { - return ( -
-

Loading...

-
- ); - } - - const statusColor = { - draft: "text-[#556677] bg-[#556677]/10 border-[#556677]/30", - planning: "text-yellow-400 bg-yellow-400/10 border-yellow-400/30", - active: "text-green-400 bg-green-400/10 border-green-400/30", - paused: "text-yellow-400 bg-yellow-400/10 border-yellow-400/30", - completed: "text-[#75aafc] bg-[#75aafc]/10 border-[#75aafc]/30", - archived: "text-[#556677] bg-[#556677]/10 border-[#556677]/30", - failed: "text-red-400 bg-red-400/10 border-red-400/30", - }[directive.status] || "text-[#556677] bg-[#556677]/10 border-[#556677]/30"; - - return ( -
- {/* Header */} -
-
-
- -

- {directive.title || directive.goal.slice(0, 50)} -

- - {directive.status} - -
-
- {directive.status === "draft" && ( - - )} - {directive.status === "active" && ( - - )} - {directive.status === "paused" && ( - - )} - {["active", "paused"].includes(directive.status) && ( - - )} - -
-
-
- - {/* Tabs */} -
- {(["overview", "chain", "events", "evaluations", "approvals", "verifiers"] as const).map((tab) => ( - - ))} -
- - {/* Tab Content */} -
- {activeTab === "overview" && ( - - )} - {activeTab === "chain" && ( - - )} - {activeTab === "events" && ( - - )} - {activeTab === "evaluations" && ( - - )} - {activeTab === "approvals" && ( - - )} - {activeTab === "verifiers" && ( - - )} -
-
- ); -} - -// ============================================================================= -// Tab Components -// ============================================================================= - -function OverviewTab({ directive }: { directive: DirectiveWithProgress }) { - return ( -
- {/* Goal */} -
-

Goal

-

- {directive.goal} -

-
- - {/* Progress */} -
-

Progress

-
-
-
- {directive.chain?.completedSteps || 0} -
-
Completed Steps
-
-
-
- {directive.chain?.totalSteps || 0} -
-
Total Steps
-
-
-
- {directive.chain?.currentConfidence != null - ? `${Math.round((directive.chain?.currentConfidence ?? 0) * 100)}%` - : "-"} -
-
Confidence
-
-
-
- - {/* Configuration */} -
-

Configuration

-
-
- Autonomy Level - {directive.autonomyLevel} -
-
- Max Rework Cycles - {directive.maxReworkCycles} -
-
- Green Threshold - {directive.confidenceThresholdGreen} -
-
- Yellow Threshold - {directive.confidenceThresholdYellow} -
-
-
- - {/* Repository */} - {directive.repositoryUrl && ( -
-

Repository

-

{directive.repositoryUrl}

-
- )} -
- ); -} - -// Step status colors for both list and DAG views -const stepStatusStyles: Record = { - pending: { border: "#556677", bg: "#556677", text: "#556677" }, - ready: { border: "#3b82f6", bg: "#3b82f6", text: "#3b82f6" }, - running: { border: "#22c55e", bg: "#22c55e", text: "#22c55e" }, - evaluating: { border: "#eab308", bg: "#eab308", text: "#eab308" }, - passed: { border: "#75aafc", bg: "#75aafc", text: "#75aafc" }, - failed: { border: "#ef4444", bg: "#ef4444", text: "#ef4444" }, - rework: { border: "#f97316", bg: "#f97316", text: "#f97316" }, - skipped: { border: "#556677", bg: "#556677", text: "#556677" }, - blocked: { border: "#ef4444", bg: "#ef4444", text: "#ef4444" }, -}; - -// Confidence level colors -const confidenceColors: Record = { - green: "#22c55e", - yellow: "#eab308", - red: "#ef4444", -}; - -// Node dimensions -const NODE_WIDTH = 180; -const NODE_HEIGHT = 70; - -// Custom node component for steps -function StepNodeComponent({ data }: { data: DirectiveGraphNode & { selected?: boolean } }) { - const styles = stepStatusStyles[data.status] || stepStatusStyles.pending; - const isRunning = data.status === "running" || data.status === "evaluating"; - - return ( -
- - - {/* Status indicator bar */} -
- - {/* Content */} -
-
- {data.name} - {data.confidenceScore !== null && data.confidenceLevel && ( -
- )} -
-
- - {data.status} - - {data.stepType} -
-
- - -
- ); -} - -// Node types for React Flow -const nodeTypes = { - step: StepNodeComponent, -}; - -function ChainTab({ directive, graph }: { directive: DirectiveWithProgress; graph: DirectiveGraphResponse | null }) { - const [viewMode, setViewMode] = useState<"dag" | "list">("dag"); - - // Convert graph to React Flow nodes and edges - const { nodes, edges } = useMemo(() => { - if (!graph || !graph.nodes.length) { - // Fallback: generate positions from directive.steps - const stepNodes = directive.steps.map((step, index) => ({ - id: step.id, - type: "step" as const, - position: { - x: (index % 3) * 220 + 50, - y: Math.floor(index / 3) * 120 + 50, - }, - data: { - id: step.id, - name: step.name, - stepType: step.stepType, - status: step.status, - confidenceScore: step.confidenceScore, - confidenceLevel: step.confidenceLevel, - contractId: step.contractId, - editorX: null, - editorY: null, - }, - })); - - // Build edges from dependencies - const stepEdges: Edge[] = []; - directive.steps.forEach((step) => { - (step.dependsOn ?? []).forEach((depName) => { - const depStep = directive.steps.find((s) => s.name === depName); - if (depStep) { - stepEdges.push({ - id: `${depStep.id}-${step.id}`, - source: depStep.id, - target: step.id, - type: "smoothstep", - markerEnd: { type: MarkerType.ArrowClosed, color: "#556677" }, - style: { stroke: "#556677", strokeWidth: 2 }, - }); - } - }); - }); - - return { nodes: stepNodes, edges: stepEdges }; - } - - // Use graph data - const graphNodes = graph.nodes.map((node) => ({ - id: node.id, - type: "step" as const, - position: { - x: node.editorX ?? 50, - y: node.editorY ?? 50, - }, - data: { ...node }, - })); - - const graphEdges: Edge[] = graph.edges.map((edge) => ({ - id: `${edge.source}-${edge.target}`, - source: edge.source, - target: edge.target, - type: "smoothstep", - markerEnd: { type: MarkerType.ArrowClosed, color: "#556677" }, - style: { stroke: "#556677", strokeWidth: 2 }, - })); - - return { nodes: graphNodes, edges: graphEdges }; - }, [graph, directive.steps]); - - if (!directive.chain) { - return ( -
-

- No chain generated yet. Start the directive to generate a chain. -

-
- ); - } - - return ( -
- {/* Chain info header */} -
-
-
{directive.chain.name}
-
Generation {directive.chain.generation}
-
-
-
- {directive.chain.completedSteps}/{directive.chain.totalSteps} steps -
- {/* View toggle */} -
- - -
-
-
- - {viewMode === "dag" ? ( - /* DAG visualization */ -
- {directive.steps.length === 0 ? ( -
-

No steps in chain

-
- ) : ( - - - - - )} -
- ) : ( - /* List view */ -
-

Steps

- {directive.steps.length === 0 ? ( -

No steps in chain

- ) : ( - directive.steps.map((step) => { - const styles = stepStatusStyles[step.status] || stepStatusStyles.pending; - - return ( -
-
-
- {step.name} - - {step.status} - - {step.confidenceScore !== null && ( - - ({Math.round(step.confidenceScore * 100)}%) - - )} -
-
{step.stepType}
-
- {step.description && ( -

{step.description}

- )} - {step.dependsOn?.length > 0 && ( -
- Depends on: {step.dependsOn.join(", ")} -
- )} -
- ); - }) - )} -
- )} -
- ); -} - -function EventsTab({ directive }: { directive: DirectiveWithProgress }) { - // Subscribe to real-time events via SSE - const { events: streamEvents, isConnected, error: sseError } = useDirectiveEventSubscription(directive.id); - - // Combine initial events with streamed events (avoiding duplicates) - const allEvents = useMemo(() => { - const eventMap = new Map(); - // Add initial events first - directive.recentEvents.forEach((e) => eventMap.set(e.id, e)); - // Add streamed events (will override any duplicates) - streamEvents.forEach((e) => eventMap.set(e.id, e)); - // Sort by created_at descending (most recent first) - return Array.from(eventMap.values()).sort( - (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() - ); - }, [directive.recentEvents, streamEvents]); - - return ( -
- {/* Connection status */} -
-
- - {isConnected ? "● Live" : "○ Connecting..."} - - {sseError && {sseError}} -
- {allEvents.length} events -
- - {/* Event list */} - {allEvents.length === 0 ? ( -
-

No events yet

-
- ) : ( -
- {allEvents.map((event) => { - const severityColors: Record = { - info: "text-[#75aafc]", - warning: "text-yellow-400", - error: "text-red-400", - critical: "text-red-600", - }; - const severityColor = severityColors[event.severity] || "text-[#556677]"; - - return ( -
-
-
- {event.eventType} - {event.actorType} -
- - {new Date(event.createdAt).toLocaleString()} - -
- {event.eventData != null && ( -
-                    {JSON.stringify(event.eventData, null, 2)}
-                  
- )} -
- ); - })} -
- )} -
- ); -} - -function EvaluationsTab({ directive: _directive }: { directive: DirectiveWithProgress }) { - // TODO: Fetch evaluations separately - return ( -
-

- Evaluations will be shown here after steps are evaluated -

-
- ); -} - -function ApprovalsTab({ directive, onRefresh }: { directive: DirectiveWithProgress; onRefresh: () => void }) { - if (directive.pendingApprovals.length === 0) { - return ( -
-

No pending approvals

-
- ); - } - - const handleApprove = async (approvalId: string) => { - try { - const { approveDirectiveRequest } = await import("../lib/api"); - await approveDirectiveRequest(directive.id, approvalId); - onRefresh(); - } catch (err) { - console.error("Failed to approve:", err); - } - }; - - const handleDeny = async (approvalId: string) => { - try { - const { denyDirectiveRequest } = await import("../lib/api"); - await denyDirectiveRequest(directive.id, approvalId); - onRefresh(); - } catch (err) { - console.error("Failed to deny:", err); - } - }; - - return ( -
- {directive.pendingApprovals.map((approval) => { - const urgencyColor = { - low: "text-[#556677]", - normal: "text-[#75aafc]", - high: "text-yellow-400", - critical: "text-red-400", - }[approval.urgency] || "text-[#556677]"; - - return ( -
-
-
-
- {approval.approvalType} - - {approval.urgency} - -
-

{approval.description}

-
-
- - -
-
-
- ); - })} -
- ); -} - -function VerifiersTab({ directive: _directive }: { directive: DirectiveWithProgress }) { - // TODO: Fetch verifiers separately - return ( -
-

- Verifiers will be shown here. Use auto-detect to find available verifiers. -

-
- ); -} - -// ============================================================================= -// Create Directive Modal -// ============================================================================= - -interface CreateDirectiveModalProps { - onSubmit: (goal: string, repositoryUrl: string | undefined, autonomyLevel: AutonomyLevel) => void; - onCancel: () => void; -} - -function CreateDirectiveModal({ onSubmit, onCancel }: CreateDirectiveModalProps) { - const [goal, setGoal] = useState(""); - const [repositoryUrl, setRepositoryUrl] = useState(""); - const [autonomyLevel, setAutonomyLevel] = useState("guardrails"); - const [suggestions, setSuggestions] = useState([]); - const [showSuggestions, setShowSuggestions] = useState(false); - - // Load suggestions - useEffect(() => { - getRepositorySuggestions("remote", undefined, 5) - .then((res) => { - setSuggestions(res.entries); - }) - .catch(() => { - setSuggestions([]); - }); - }, []); - - const handleSubmit = () => { - if (goal.trim()) { - onSubmit(goal.trim(), repositoryUrl.trim() || undefined, autonomyLevel); - } - }; - - return ( -
-
-

- Create Directive -

- -
- {/* Goal */} -
- -