From a734bf1a472b19d63341769d26a66628575df7f4 Mon Sep 17 00:00:00 2001 From: soryu Date: Wed, 4 Feb 2026 01:07:14 +0000 Subject: Add chain checkpoint contracts --- .../frontend/src/components/chains/ChainEditor.tsx | 207 ++++++++-- makima/frontend/src/lib/api.ts | 44 ++- makima/frontend/tsconfig.tsbuildinfo | 2 +- .../20260204000000_checkpoint_validation.sql | 16 + makima/src/bin/makima.rs | 88 +++++ makima/src/daemon/api/chain.rs | 26 ++ makima/src/daemon/cli/mod.rs | 14 + makima/src/daemon/cli/supervisor.rs | 64 +++ makima/src/db/models.rs | 67 ++++ makima/src/db/repository.rs | 432 ++++++++++++++++++++- makima/src/server/handlers/chains.rs | 150 ++++++- makima/src/server/handlers/contracts.rs | 29 ++ 12 files changed, 1088 insertions(+), 51 deletions(-) create mode 100644 makima/migrations/20260204000000_checkpoint_validation.sql diff --git a/makima/frontend/src/components/chains/ChainEditor.tsx b/makima/frontend/src/components/chains/ChainEditor.tsx index 9028c3e..49e585c 100644 --- a/makima/frontend/src/components/chains/ChainEditor.tsx +++ b/makima/frontend/src/components/chains/ChainEditor.tsx @@ -54,6 +54,7 @@ export function ChainEditor({ const [isStarting, setIsStarting] = useState(false); const [isStopping, setIsStopping] = useState(false); const [error, setError] = useState(null); + const [withSupervisor, setWithSupervisor] = useState(false); // Load definitions when chain changes useEffect(() => { @@ -131,7 +132,22 @@ export function ChainEditor({ [onContractClick, showDefinitions] ); - const getStatusColor = (status: string) => { + const getStatusColor = (status: string, isCheckpoint = false) => { + // Checkpoint contracts use purple/violet colors + if (isCheckpoint) { + switch (status) { + case "active": + return { bg: "#a78bfa", border: "#8b5cf6", text: "#5b21b6" }; + case "completed": + return { bg: "#818cf8", border: "#6366f1", text: "#3730a3" }; + case "pending": + return { bg: "#c4b5fd", border: "#a78bfa", text: "#6d28d9" }; + case "failed": + return { bg: "#ef4444", border: "#dc2626", text: "#991b1b" }; + default: + return { bg: "#a78bfa", border: "#8b5cf6", text: "#5b21b6" }; + } + } switch (status) { case "active": return { bg: "#4ade80", border: "#22c55e", text: "#166534" }; @@ -158,14 +174,14 @@ export function ChainEditor({ setIsStarting(true); setError(null); try { - await startChain(chain.id); + await startChain(chain.id, { withSupervisor }); onRefresh(); } catch (err) { setError(err instanceof Error ? err.message : "Failed to start chain"); } finally { setIsStarting(false); } - }, [chain.id, onRefresh]); + }, [chain.id, onRefresh, withSupervisor]); const handleStopChain = useCallback(async () => { if (!confirm("Are you sure you want to stop this chain?")) return; @@ -245,13 +261,26 @@ export function ChainEditor({ {/* Chain control buttons */} {chain.status === "pending" && definitions.length > 0 && ( - + <> + + + )} {chain.status === "active" && (