import { useState, useEffect, useCallback } from "react";
import { useAuth } from "../contexts/AuthContext";
import { useNavigate } from "react-router";
import { Masthead } from "../components/Masthead";
import {
listDaemons,
restartDaemon,
listDaemonPlatforms,
API_BASE,
type Daemon,
type DaemonListResponse,
type DaemonPlatform,
type RestartDaemonResponse,
} from "../lib/api";
// =============================================================================
// Section Header Component
// =============================================================================
function SectionHeader({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
// =============================================================================
// Alert Component
// =============================================================================
function ErrorAlert({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
// =============================================================================
// Daemons Page
// =============================================================================
export default function DaemonsPage() {
const { isAuthenticated, isAuthConfigured } = useAuth();
const navigate = useNavigate();
// Daemon state
const [daemons, setDaemons] = useState([]);
const [daemonsLoading, setDaemonsLoading] = useState(true);
const [daemonsError, setDaemonsError] = useState(null);
const [restartingDaemonId, setRestartingDaemonId] = useState(null);
const [restartConfirmDaemonId, setRestartConfirmDaemonId] = useState(null);
// Platform availability state
const [platforms, setPlatforms] = useState([]);
const [platformsLoading, setPlatformsLoading] = useState(true);
// Redirect if not authenticated
useEffect(() => {
if (isAuthConfigured && !isAuthenticated) {
navigate("/login");
}
}, [isAuthConfigured, isAuthenticated, navigate]);
const loadDaemons = async () => {
try {
setDaemonsError(null);
const response: DaemonListResponse = await listDaemons();
setDaemons(response.daemons);
} catch (err) {
setDaemonsError(err instanceof Error ? err.message : "Failed to load daemons");
} finally {
setDaemonsLoading(false);
}
};
const handleRestartDaemon = async (id: string) => {
try {
setRestartingDaemonId(id);
setDaemonsError(null);
const _response: RestartDaemonResponse = await restartDaemon(id);
// Daemon will restart, so refresh the list after a short delay
setTimeout(() => {
loadDaemons();
}, 2000);
} catch (err) {
setDaemonsError(err instanceof Error ? err.message : "Failed to restart daemon");
} finally {
setRestartingDaemonId(null);
setRestartConfirmDaemonId(null);
}
};
// Friendly labels for platform identifiers
const platformLabels: Record = {
"linux-x86_64": "Linux (Intel/AMD)",
"linux-arm64": "Linux (ARM64)",
"macos-x86_64": "macOS (Intel)",
"macos-arm64": "macOS (Apple Silicon)",
};
const loadPlatforms = useCallback(async () => {
try {
setPlatformsLoading(true);
const response = await listDaemonPlatforms();
setPlatforms(response.platforms);
} catch {
// Fallback: show all platforms as unavailable if API endpoint is missing
setPlatforms([
{ platform: "linux-x86_64", available: false, downloadUrl: "/api/v1/daemon/download/linux-x86_64" },
{ platform: "linux-arm64", available: false, downloadUrl: "/api/v1/daemon/download/linux-arm64" },
{ platform: "macos-x86_64", available: false, downloadUrl: "/api/v1/daemon/download/macos-x86_64" },
{ platform: "macos-arm64", available: false, downloadUrl: "/api/v1/daemon/download/macos-arm64" },
]);
} finally {
setPlatformsLoading(false);
}
}, []);
// Initial load
useEffect(() => {
loadDaemons();
loadPlatforms();
}, []);
// Auto-refresh daemons every 30 seconds
useEffect(() => {
const interval = setInterval(() => {
loadDaemons();
}, 30000);
return () => clearInterval(interval);
}, []);
return (
{/* Page Header */}
Daemons
Daemons are worker processes that connect to Makima and execute tasks on your machines.
{/* Left Column */}
{/* Download Section */}
Download Daemon
Download the pre-compiled daemon binary for your platform. The daemon connects to the Makima server and executes tasks.
Quick Install
curl -fsSL https://raw.githubusercontent.com/soryu-co/soryu/master/install.sh | bash
{/* Daemon Setup */}
Daemon Setup
Set your API key as an environment variable:
export MAKIMA_API_KEY="your-key"
Then run: makima-daemon
{/* Kubernetes Section */}
Run in Kubernetes
Deploy daemons as containers in Kubernetes for scalable task execution.
Pull Container Image
docker pull ghcr.io/soryu-co/makima-daemon:latest
Environment Variables
MAKIMA_API_KEY="your-key"
MAKIMA_SERVER_URL="https://your-server"
GITHUB_TOKEN="ghp_..." # optional, for repo access
Kubernetes manifests available in the repository under k8s/daemon/
{/* Right Column */}
{/* Connected Daemons */}
Connected Daemons
{daemons.length > 0 && (
({daemons.filter(d => d.status === "connected").length} connected / {daemons.length} total)
)}
{daemonsError && {daemonsError}}
{daemonsLoading && daemons.length === 0 ? (
Loading...
) : daemons.length === 0 ? (
No daemons connected
Start a daemon to enable task execution
) : (
{daemons.map((daemon) => (
{daemon.hostname || "Unknown Host"}
{daemon.status}
Tasks
{daemon.currentTaskCount} / {daemon.maxConcurrentTasks}
Connected
{new Date(daemon.connectedAt).toLocaleString()}
{daemon.machineId && (
Machine
{daemon.machineId.substring(0, 16)}...
)}
{/* Restart Section */}
{daemon.status === "connected" && (
{restartConfirmDaemonId === daemon.id ? (
Restart daemon? Running tasks will be interrupted.
) : (
)}
)}
))}
)}
);
}