From 6a34a6f3c423a7c57616762eb4cea2b7da52eaf3 Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Sun, 22 Feb 2026 14:39:14 +0000
Subject: feat: Add daemon page with download binary and Cloudflare Agent setup
 (#77)

* feat: soryu-co/soryu - makima: Create DaemonList and DaemonDetail page components

* feat: soryu-co/soryu - makima: Add daemon page routes, CSS styles, and navigation

* feat: soryu-co/soryu - makima: Create daemon page with download and monitoring

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* feat: soryu-co/soryu - makima: Integrate Cloudflare Agent setup into daemon page
---
 makima/frontend/src/routes/daemon.tsx | 746 ++++++++++++++++++++++++++++++++++
 1 file changed, 746 insertions(+)
 create mode 100644 makima/frontend/src/routes/daemon.tsx

(limited to 'makima/frontend/src/routes/daemon.tsx')

diff --git a/makima/frontend/src/routes/daemon.tsx b/makima/frontend/src/routes/daemon.tsx
new file mode 100644
index 0000000..66154ad
--- /dev/null
+++ b/makima/frontend/src/routes/daemon.tsx
@@ -0,0 +1,746 @@
+import { useState, useEffect, useCallback } from "react";
+import { useNavigate } from "react-router";
+import { Masthead } from "../components/Masthead";
+import { useAuth } from "../contexts/AuthContext";
+import {
+  listDaemons,
+  restartDaemon,
+  type Daemon,
+} from "../lib/api";
+
+// =============================================================================
+// Types
+// =============================================================================
+
+interface GitHubAsset {
+  name: string;
+  browser_download_url: string;
+  size: number;
+}
+
+interface GitHubRelease {
+  tag_name: string;
+  name: string;
+  published_at: string;
+  html_url: string;
+  assets: GitHubAsset[];
+}
+
+interface PlatformDownload {
+  label: string;
+  arch: string;
+  pattern: string;
+  asset: GitHubAsset | null;
+  recommended: boolean;
+}
+
+// =============================================================================
+// Helpers
+// =============================================================================
+
+function detectPlatform(): string {
+  const ua = navigator.userAgent.toLowerCase();
+  const platform = navigator.platform?.toLowerCase() || "";
+
+  if (platform.includes("mac") || ua.includes("macintosh")) {
+    // Check for Apple Silicon
+    // navigator.platform is "MacIntel" even on ARM for some browsers,
+    // but we can check userAgent for hints or default to arm64 for modern Macs
+    if (
+      ua.includes("arm") ||
+      ua.includes("aarch64") ||
+      // Chrome 93+ on ARM Macs reports this
+      (typeof navigator !== "undefined" &&
+        "userAgentData" in navigator &&
+        // @ts-expect-error -- userAgentData may not be typed
+        navigator.userAgentData?.platform === "macOS")
+    ) {
+      return "macos-arm64";
+    }
+    return "macos-arm64"; // Default to ARM64 for modern Macs
+  }
+
+  if (platform.includes("linux") || ua.includes("linux")) {
+    return "linux-x86_64";
+  }
+
+  return "linux-x86_64"; // fallback
+}
+
+function formatBytes(bytes: number): string {
+  if (bytes === 0) return "0 B";
+  const k = 1024;
+  const sizes = ["B", "KB", "MB", "GB"];
+  const i = Math.floor(Math.log(bytes) / Math.log(k));
+  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
+}
+
+function formatDate(dateStr: string): string {
+  return new Date(dateStr).toLocaleDateString("en-US", {
+    year: "numeric",
+    month: "short",
+    day: "numeric",
+  });
+}
+
+// =============================================================================
+// Sub-components
+// =============================================================================
+
+function SectionHeader({ children }: { children: React.ReactNode }) {
+  return (
+    <h2 className="text-[11px] font-mono uppercase tracking-wide text-[#8899aa] mb-3 pb-2 border-b border-[rgba(117,170,252,0.15)]">
+      {children}
+    </h2>
+  );
+}
+
+function ErrorAlert({ children }: { children: React.ReactNode }) {
+  return (
+    <div className="border border-red-700/50 bg-red-900/20 text-red-400 px-3 py-2 mb-4 font-mono text-xs">
+      {children}
+    </div>
+  );
+}
+
+function CodeBlock({ children }: { children: React.ReactNode }) {
+  return (
+    <code className="block bg-black/50 px-3 py-2 text-[11px] font-mono text-green-400 mb-2 overflow-x-auto">
+      {children}
+    </code>
+  );
+}
+
+function StepNumber({ n }: { n: number }) {
+  return (
+    <span className="inline-flex items-center justify-center w-5 h-5 border border-[rgba(117,170,252,0.35)] text-[10px] font-mono text-[#75aafc] mr-2 shrink-0">
+      {n}
+    </span>
+  );
+}
+
+// =============================================================================
+// Download Section
+// =============================================================================
+
+function DownloadSection() {
+  const [release, setRelease] = useState<GitHubRelease | null>(null);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState<string | null>(null);
+  const [userPlatform] = useState(detectPlatform);
+
+  useEffect(() => {
+    const fetchRelease = async () => {
+      try {
+        setLoading(true);
+        setError(null);
+        const res = await fetch(
+          "https://api.github.com/repos/soryu-co/makima/releases/latest"
+        );
+        if (!res.ok) {
+          throw new Error(`GitHub API returned ${res.status}`);
+        }
+        const data: GitHubRelease = await res.json();
+        setRelease(data);
+      } catch (err) {
+        setError(
+          err instanceof Error ? err.message : "Failed to fetch release info"
+        );
+      } finally {
+        setLoading(false);
+      }
+    };
+    fetchRelease();
+  }, []);
+
+  const platforms: PlatformDownload[] = [
+    {
+      label: "Linux x86_64",
+      arch: "linux-x86_64",
+      pattern: "linux-x86_64.tar.gz",
+      asset: null,
+      recommended: userPlatform === "linux-x86_64",
+    },
+    {
+      label: "macOS Intel (x86_64)",
+      arch: "macos-x86_64",
+      pattern: "macos-x86_64.tar.gz",
+      asset: null,
+      recommended: userPlatform === "macos-x86_64",
+    },
+    {
+      label: "macOS Apple Silicon (ARM64)",
+      arch: "macos-arm64",
+      pattern: "macos-arm64.tar.gz",
+      asset: null,
+      recommended: userPlatform === "macos-arm64",
+    },
+  ];
+
+  // Match assets to platforms
+  if (release) {
+    for (const p of platforms) {
+      p.asset =
+        release.assets.find((a) => a.name.includes(p.pattern)) || null;
+    }
+  }
+
+  // Sort recommended first
+  const sortedPlatforms = [...platforms].sort(
+    (a, b) => (b.recommended ? 1 : 0) - (a.recommended ? 1 : 0)
+  );
+
+  return (
+    <section className="border border-[rgba(117,170,252,0.25)] bg-[#0d1b2d] p-4">
+      <SectionHeader>Download Daemon</SectionHeader>
+
+      {loading && (
+        <p className="text-[#7788aa] font-mono text-xs">
+          Fetching latest release...
+        </p>
+      )}
+
+      {error && <ErrorAlert>Failed to load release: {error}</ErrorAlert>}
+
+      {release && (
+        <>
+          <div className="flex items-center justify-between mb-4">
+            <div className="flex items-center gap-3">
+              <span className="text-[#9bc3ff] font-mono text-sm">
+                {release.tag_name}
+              </span>
+              <span className="text-[#556677] font-mono text-[10px]">
+                {formatDate(release.published_at)}
+              </span>
+            </div>
+            <a
+              href="https://github.com/soryu-co/makima/releases"
+              target="_blank"
+              rel="noopener noreferrer"
+              className="text-[10px] font-mono text-[#75aafc] hover:text-[#9bc3ff] transition-colors"
+            >
+              All Releases &rarr;
+            </a>
+          </div>
+
+          <div className="space-y-2">
+            {sortedPlatforms.map((p) => (
+              <div
+                key={p.arch}
+                className={`border p-3 flex items-center justify-between ${
+                  p.recommended
+                    ? "border-[rgba(117,170,252,0.5)] bg-[#0a1628]"
+                    : "border-[rgba(117,170,252,0.15)] bg-[#0a1525]"
+                }`}
+              >
+                <div className="flex items-center gap-3">
+                  <span className="font-mono text-xs text-[#9bc3ff]">
+                    {p.label}
+                  </span>
+                  {p.recommended && (
+                    <span className="text-[9px] font-mono uppercase px-1.5 py-0.5 border border-[rgba(117,170,252,0.4)] text-[#75aafc] bg-[rgba(117,170,252,0.08)]">
+                      Detected
+                    </span>
+                  )}
+                  {p.asset && (
+                    <span className="text-[10px] font-mono text-[#556677]">
+                      {formatBytes(p.asset.size)}
+                    </span>
+                  )}
+                </div>
+                {p.asset ? (
+                  <a
+                    href={p.asset.browser_download_url}
+                    className={`text-[10px] font-mono uppercase px-3 py-1.5 border transition-colors ${
+                      p.recommended
+                        ? "text-[#9bc3ff] border-[rgba(117,170,252,0.5)] bg-[rgba(117,170,252,0.1)] hover:bg-[rgba(117,170,252,0.2)]"
+                        : "text-[#75aafc] border-[rgba(117,170,252,0.25)] hover:bg-[rgba(117,170,252,0.1)]"
+                    }`}
+                    download
+                  >
+                    Download
+                  </a>
+                ) : (
+                  <span className="text-[10px] font-mono text-[#556677]">
+                    Not available
+                  </span>
+                )}
+              </div>
+            ))}
+          </div>
+        </>
+      )}
+    </section>
+  );
+}
+
+// =============================================================================
+// Setup Instructions Section
+// =============================================================================
+
+function SetupSection() {
+  const [showConfig, setShowConfig] = useState(false);
+
+  return (
+    <section className="border border-[rgba(117,170,252,0.25)] bg-[#0d1b2d] p-4">
+      <SectionHeader>Setup Instructions</SectionHeader>
+      <div className="space-y-3">
+        <div className="flex items-start">
+          <StepNumber n={1} />
+          <div className="flex-1">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+              Download the binary for your platform above
+            </p>
+          </div>
+        </div>
+
+        <div className="flex items-start">
+          <StepNumber n={2} />
+          <div className="flex-1">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+              Extract the archive
+            </p>
+            <CodeBlock>tar xzf makima-*.tar.gz</CodeBlock>
+          </div>
+        </div>
+
+        <div className="flex items-start">
+          <StepNumber n={3} />
+          <div className="flex-1">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+              Move to PATH
+            </p>
+            <CodeBlock>sudo mv makima /usr/local/bin/</CodeBlock>
+          </div>
+        </div>
+
+        <div className="flex items-start">
+          <StepNumber n={4} />
+          <div className="flex-1">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+              Set your API key (
+              <a
+                href="/settings"
+                className="text-[#75aafc] hover:text-[#9bc3ff] transition-colors"
+              >
+                generate one in Settings
+              </a>
+              )
+            </p>
+            <CodeBlock>export MAKIMA_API_KEY="your-key"</CodeBlock>
+          </div>
+        </div>
+
+        <div className="flex items-start">
+          <StepNumber n={5} />
+          <div className="flex-1">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+              Set server URL
+            </p>
+            <CodeBlock>
+              export MAKIMA_DAEMON_SERVER_URL="ws://your-server:8080"
+            </CodeBlock>
+          </div>
+        </div>
+
+        <div className="flex items-start">
+          <StepNumber n={6} />
+          <div className="flex-1">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+              Run the daemon
+            </p>
+            <CodeBlock>makima daemon</CodeBlock>
+          </div>
+        </div>
+      </div>
+
+      {/* Config file alternative */}
+      <div className="mt-4 pt-3 border-t border-[rgba(117,170,252,0.1)]">
+        <button
+          onClick={() => setShowConfig(!showConfig)}
+          className="text-[10px] font-mono text-[#75aafc] hover:text-[#9bc3ff] transition-colors bg-transparent border-none cursor-pointer p-0"
+        >
+          {showConfig ? "- Hide" : "+"} Config file alternative
+        </button>
+        {showConfig && (
+          <div className="mt-3">
+            <p className="text-[#7788aa] font-mono text-[10px] mb-2">
+              Create <code className="text-green-400">makima-daemon.toml</code>{" "}
+              in the working directory:
+            </p>
+            <code className="block bg-black/50 px-3 py-2 text-[11px] font-mono text-green-400 whitespace-pre overflow-x-auto">
+              {`[daemon]
+api_key = "your-key"
+server_url = "ws://your-server:8080"
+max_concurrent_tasks = 4`}
+            </code>
+          </div>
+        )}
+      </div>
+    </section>
+  );
+}
+
+// =============================================================================
+// Cloudflare Edge Deployment Section
+// =============================================================================
+
+function CloudflareAgentSection() {
+  const [showSetup, setShowSetup] = useState(false);
+
+  const benefits = [
+    {
+      label: "Global edge presence",
+      desc: "Lower latency from 300+ Cloudflare locations worldwide",
+    },
+    {
+      label: "Auto-scaling & hibernation",
+      desc: "Cost-efficient — only runs when needed",
+    },
+    {
+      label: "WebSocket relay",
+      desc: "Coordinate remote daemon instances through persistent connections",
+    },
+    {
+      label: "Durable Objects",
+      desc: "Built on Cloudflare's stateful edge compute primitives",
+    },
+  ];
+
+  return (
+    <section className="border border-[rgba(117,170,252,0.25)] bg-[#0d1b2d] p-4">
+      <SectionHeader>Edge Deployment</SectionHeader>
+
+      <p className="text-[#7788aa] font-mono text-[10px] mb-4 leading-relaxed">
+        Deploy a lightweight Makima relay agent on Cloudflare's edge network for
+        global, low-latency daemon coordination. Ideal for distributed teams or
+        production deployments requiring high availability.
+      </p>
+
+      {/* Benefits */}
+      <div className="space-y-2 mb-4">
+        {benefits.map((b) => (
+          <div
+            key={b.label}
+            className="flex items-start gap-2 text-[10px] font-mono"
+          >
+            <span className="text-[#75aafc] mt-px shrink-0">&#x25B8;</span>
+            <div>
+              <span className="text-[#9bc3ff]">{b.label}</span>
+              <span className="text-[#556677] ml-1">— {b.desc}</span>
+            </div>
+          </div>
+        ))}
+      </div>
+
+      {/* Quick Setup */}
+      <div className="border-t border-[rgba(117,170,252,0.1)] pt-3">
+        <button
+          onClick={() => setShowSetup(!showSetup)}
+          className="text-[10px] font-mono text-[#75aafc] hover:text-[#9bc3ff] transition-colors bg-transparent border-none cursor-pointer p-0"
+        >
+          {showSetup ? "- Hide" : "+"} Quick setup
+        </button>
+        {showSetup && (
+          <div className="mt-3 space-y-3">
+            <div className="flex items-start">
+              <StepNumber n={1} />
+              <div className="flex-1">
+                <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+                  Navigate to the Cloudflare agent directory
+                </p>
+                <CodeBlock>cd makima/cloudflare-agent</CodeBlock>
+              </div>
+            </div>
+            <div className="flex items-start">
+              <StepNumber n={2} />
+              <div className="flex-1">
+                <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+                  Run the setup script
+                </p>
+                <CodeBlock>./setup.sh</CodeBlock>
+              </div>
+            </div>
+            <div className="flex items-start">
+              <StepNumber n={3} />
+              <div className="flex-1">
+                <p className="text-[#7788aa] font-mono text-[10px] mb-1">
+                  Deploy to Cloudflare
+                </p>
+                <CodeBlock>npx wrangler deploy</CodeBlock>
+              </div>
+            </div>
+          </div>
+        )}
+      </div>
+
+      {/* Link to repo */}
+      <div className="mt-4 pt-3 border-t border-[rgba(117,170,252,0.1)] flex items-center justify-between">
+        <span className="text-[10px] font-mono text-[#556677]">
+          Full documentation & source
+        </span>
+        <a
+          href="https://github.com/soryu-co/soryu/tree/master/makima/cloudflare-agent"
+          target="_blank"
+          rel="noopener noreferrer"
+          className="text-[10px] font-mono text-[#75aafc] hover:text-[#9bc3ff] transition-colors px-3 py-1.5 border border-[rgba(117,170,252,0.25)] hover:bg-[rgba(117,170,252,0.1)]"
+        >
+          View on GitHub &rarr;
+        </a>
+      </div>
+    </section>
+  );
+}
+
+// =============================================================================
+// Connected Daemons Section
+// =============================================================================
+
+function ConnectedDaemonsSection() {
+  const [daemons, setDaemons] = useState<Daemon[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState<string | null>(null);
+  const [restartingDaemonId, setRestartingDaemonId] = useState<string | null>(
+    null
+  );
+  const [restartConfirmDaemonId, setRestartConfirmDaemonId] = useState<
+    string | null
+  >(null);
+
+  const loadDaemons = useCallback(async () => {
+    try {
+      setError(null);
+      const response = await listDaemons();
+      setDaemons(response.daemons);
+    } catch (err) {
+      setError(
+        err instanceof Error ? err.message : "Failed to load daemons"
+      );
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    loadDaemons();
+  }, [loadDaemons]);
+
+  // Auto-refresh every 30 seconds
+  useEffect(() => {
+    const interval = setInterval(() => {
+      loadDaemons();
+    }, 30000);
+    return () => clearInterval(interval);
+  }, [loadDaemons]);
+
+  const handleRestartDaemon = async (id: string) => {
+    try {
+      setRestartingDaemonId(id);
+      setError(null);
+      await restartDaemon(id);
+      setRestartConfirmDaemonId(null);
+      // Daemon will restart, so refresh the list after a short delay
+      setTimeout(() => {
+        loadDaemons();
+      }, 2000);
+    } catch (err) {
+      setError(
+        err instanceof Error ? err.message : "Failed to restart daemon"
+      );
+    } finally {
+      setRestartingDaemonId(null);
+    }
+  };
+
+  return (
+    <section className="border border-[rgba(117,170,252,0.25)] bg-[#0d1b2d] p-4">
+      <div className="flex items-center justify-between mb-3 pb-2 border-b border-[rgba(117,170,252,0.15)]">
+        <div className="flex items-center gap-2">
+          <h2 className="text-[11px] font-mono uppercase tracking-wide text-[#8899aa]">
+            Connected Daemons
+          </h2>
+          {daemons.length > 0 && (
+            <span className="text-[10px] font-mono text-[#556677]">
+              ({daemons.filter((d) => d.status === "connected").length}{" "}
+              connected / {daemons.length} total)
+            </span>
+          )}
+        </div>
+        <button
+          onClick={loadDaemons}
+          disabled={loading}
+          className="text-[10px] font-mono text-[#75aafc] hover:text-[#9bc3ff] disabled:opacity-50 bg-transparent border-none cursor-pointer p-0"
+          title="Refresh"
+        >
+          {loading ? "..." : "\u21BB"}
+        </button>
+      </div>
+
+      {error && <ErrorAlert>{error}</ErrorAlert>}
+
+      {loading && daemons.length === 0 ? (
+        <p className="text-[#7788aa] font-mono text-xs">Loading...</p>
+      ) : daemons.length === 0 ? (
+        <div className="text-center py-6">
+          <p className="text-[#7788aa] font-mono text-xs mb-2">
+            No daemons connected
+          </p>
+          <p className="text-[#556677] font-mono text-[10px]">
+            Follow the setup instructions above to connect a daemon
+          </p>
+        </div>
+      ) : (
+        <div className="space-y-2">
+          {daemons.map((daemon) => (
+            <div
+              key={daemon.id}
+              className="border border-[rgba(117,170,252,0.15)] bg-[#0a1525] p-3"
+            >
+              <div className="flex items-center justify-between mb-2">
+                <span className="font-mono text-xs text-[#9bc3ff]">
+                  {daemon.hostname || "Unknown Host"}
+                </span>
+                <div className="flex items-center gap-2">
+                  <span
+                    className={`text-[10px] font-mono uppercase px-2 py-0.5 border ${
+                      daemon.status === "connected"
+                        ? "text-green-400 border-green-700/50 bg-green-900/20"
+                        : daemon.status === "unhealthy"
+                          ? "text-yellow-400 border-yellow-700/50 bg-yellow-900/20"
+                          : "text-[#8899aa] border-[rgba(117,170,252,0.25)]"
+                    }`}
+                  >
+                    {daemon.status}
+                  </span>
+                </div>
+              </div>
+              <div className="font-mono text-[10px] text-[#7788aa] space-y-1">
+                <div className="flex justify-between">
+                  <span>Tasks</span>
+                  <span className="text-[#9bc3ff]">
+                    {daemon.currentTaskCount} / {daemon.maxConcurrentTasks}
+                  </span>
+                </div>
+                <div className="flex justify-between">
+                  <span>Connected</span>
+                  <span className="text-[#75aafc]">
+                    {new Date(daemon.connectedAt).toLocaleString()}
+                  </span>
+                </div>
+                {daemon.machineId && (
+                  <div className="flex justify-between">
+                    <span>Machine</span>
+                    <span
+                      className="text-[#556677] truncate ml-2"
+                      title={daemon.machineId}
+                    >
+                      {daemon.machineId.substring(0, 16)}...
+                    </span>
+                  </div>
+                )}
+              </div>
+              {/* Restart Section */}
+              {daemon.status === "connected" && (
+                <div className="mt-3 pt-2 border-t border-[rgba(117,170,252,0.1)]">
+                  {restartConfirmDaemonId === daemon.id ? (
+                    <div className="flex items-center justify-between gap-2">
+                      <span className="text-[10px] font-mono text-yellow-400">
+                        Restart daemon? Running tasks will be interrupted.
+                      </span>
+                      <div className="flex gap-2">
+                        <button
+                          onClick={() => setRestartConfirmDaemonId(null)}
+                          className="text-[10px] font-mono text-[#7788aa] hover:text-[#9bc3ff] px-2 py-1 bg-transparent border-none cursor-pointer"
+                          disabled={restartingDaemonId === daemon.id}
+                        >
+                          Cancel
+                        </button>
+                        <button
+                          onClick={() => handleRestartDaemon(daemon.id)}
+                          disabled={restartingDaemonId === daemon.id}
+                          className="text-[10px] font-mono text-red-400 hover:text-red-300 px-2 py-1 border border-red-700/50 bg-red-900/20 disabled:opacity-50 cursor-pointer"
+                        >
+                          {restartingDaemonId === daemon.id
+                            ? "Restarting..."
+                            : "Confirm"}
+                        </button>
+                      </div>
+                    </div>
+                  ) : (
+                    <button
+                      onClick={() => setRestartConfirmDaemonId(daemon.id)}
+                      className="text-[10px] font-mono text-[#75aafc] hover:text-[#9bc3ff] bg-transparent border-none cursor-pointer p-0"
+                    >
+                      &#x27F3; Restart Daemon
+                    </button>
+                  )}
+                </div>
+              )}
+            </div>
+          ))}
+        </div>
+      )}
+    </section>
+  );
+}
+
+// =============================================================================
+// Main Page
+// =============================================================================
+
+export default function DaemonPage() {
+  const {
+    isAuthenticated,
+    isAuthConfigured,
+    isLoading: authLoading,
+  } = useAuth();
+  const navigate = useNavigate();
+
+  useEffect(() => {
+    if (!authLoading && isAuthConfigured && !isAuthenticated) {
+      navigate("/login");
+    }
+  }, [authLoading, isAuthConfigured, isAuthenticated, navigate]);
+
+  if (authLoading) {
+    return (
+      <div className="relative z-10 min-h-screen flex flex-col bg-[#0a1628]">
+        <Masthead showNav />
+        <main className="flex-1 flex items-center justify-center">
+          <p className="text-[#7788aa] font-mono text-sm">Loading...</p>
+        </main>
+      </div>
+    );
+  }
+
+  return (
+    <div className="relative z-10 min-h-screen flex flex-col bg-[#0a1628]">
+      <Masthead showNav />
+      <main className="flex-1 px-4 py-6 max-w-4xl mx-auto w-full">
+        {/* Page header */}
+        <div className="mb-6">
+          <h1 className="text-sm font-mono uppercase tracking-wide text-[#9bc3ff] mb-1">
+            Daemon Management
+          </h1>
+          <p className="text-[#556677] font-mono text-[10px]">
+            Download, configure, and monitor Makima daemons
+          </p>
+        </div>
+
+        <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
+          {/* Left Column: Downloads & Setup */}
+          <div className="space-y-6">
+            <DownloadSection />
+            <SetupSection />
+          </div>
+
+          {/* Right Column: Edge Deployment & Connected Daemons */}
+          <div className="space-y-6">
+            <ConnectedDaemonsSection />
+            <CloudflareAgentSection />
+          </div>
+        </div>
+      </main>
+    </div>
+  );
+}
-- 
cgit v1.2.3

