diff options
| author | soryu <soryu@soryu.co> | 2026-02-21 23:20:17 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-21 23:20:17 +0000 |
| commit | a6f86ceed54a6b667f875af0b4051211d1ac4ce0 (patch) | |
| tree | 644e0bac90c1945120df27dea36d18c81f4470e9 | |
| parent | 5ce185afb43a1b8d5f17ba644de010716e9e922c (diff) | |
| parent | 1c0ef9118dc89dfe510c28f88c5fbd4f7c358b97 (diff) | |
| download | soryu-makima/directive-soryu-co-soryu---makima-19fd3e1d-v1771715990.tar.gz soryu-makima/directive-soryu-co-soryu---makima-19fd3e1d-v1771715990.zip | |
Merge remote-tracking branch 'origin/makima/soryu-co-soryu---makima--integrate-daemon-platform-c4832ab8' into makima/directive-soryu-co-soryu---makima-19fd3e1d-v1771715990makima/directive-soryu-co-soryu---makima-19fd3e1d-v1771715990
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 36 | ||||
| -rw-r--r-- | makima/frontend/src/routes/daemons.tsx | 87 |
2 files changed, 98 insertions, 25 deletions
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index 43eaa05..458b69d 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -1222,6 +1222,42 @@ export async function restartDaemon(id: string): Promise<RestartDaemonResponse> } // ============================================================================= +// Daemon Platform Download +// ============================================================================= + +/** A daemon platform with its availability and download URL */ +export interface DaemonPlatform { + platform: string; + available: boolean; + downloadUrl: string; +} + +/** Response from the list daemon platforms endpoint */ +export interface DaemonPlatformsResponse { + platforms: DaemonPlatform[]; +} + +/** + * List available daemon platforms and their download status. + * This is an unauthenticated endpoint. + */ +export async function listDaemonPlatforms(): Promise<DaemonPlatformsResponse> { + const res = await fetch(`${API_BASE}/api/v1/daemon/download/platforms`); + if (!res.ok) { + throw new Error(`Failed to list daemon platforms: ${res.statusText}`); + } + return res.json(); +} + +/** + * Get the full download URL for a daemon binary. + * Returns the absolute URL including API_BASE for cross-origin usage. + */ +export function getDaemonDownloadUrl(platform: string): string { + return `${API_BASE}/api/v1/daemon/download/${platform}`; +} + +// ============================================================================= // Mesh Chat Types for Task Orchestration // ============================================================================= diff --git a/makima/frontend/src/routes/daemons.tsx b/makima/frontend/src/routes/daemons.tsx index 5f078f8..f551543 100644 --- a/makima/frontend/src/routes/daemons.tsx +++ b/makima/frontend/src/routes/daemons.tsx @@ -1,12 +1,15 @@ -import { useState, useEffect } from "react"; +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"; @@ -49,6 +52,10 @@ export default function DaemonsPage() { const [restartingDaemonId, setRestartingDaemonId] = useState<string | null>(null); const [restartConfirmDaemonId, setRestartConfirmDaemonId] = useState<string | null>(null); + // Platform availability state + const [platforms, setPlatforms] = useState<DaemonPlatform[]>([]); + const [platformsLoading, setPlatformsLoading] = useState(true); + // Redirect if not authenticated useEffect(() => { if (isAuthConfigured && !isAuthenticated) { @@ -85,9 +92,36 @@ export default function DaemonsPage() { } }; + // Friendly labels for platform identifiers + const platformLabels: Record<string, string> = { + "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 @@ -123,30 +157,33 @@ export default function DaemonsPage() { </p> <div className="grid grid-cols-2 gap-2 mb-4"> - <a - href="/api/v1/daemon/download/linux-x86_64" - className="flex items-center justify-center gap-2 px-3 py-2 border border-[rgba(117,170,252,0.25)] bg-[#0a1525] text-[#75aafc] hover:text-[#9bc3ff] hover:border-[#3f6fb3] transition-colors font-mono text-[10px] uppercase tracking-wide" - > - <span>Linux x86_64</span> - </a> - <a - href="/api/v1/daemon/download/linux-arm64" - className="flex items-center justify-center gap-2 px-3 py-2 border border-[rgba(117,170,252,0.25)] bg-[#0a1525] text-[#75aafc] hover:text-[#9bc3ff] hover:border-[#3f6fb3] transition-colors font-mono text-[10px] uppercase tracking-wide" - > - <span>Linux ARM64</span> - </a> - <a - href="/api/v1/daemon/download/macos-x86_64" - className="flex items-center justify-center gap-2 px-3 py-2 border border-[rgba(117,170,252,0.25)] bg-[#0a1525] text-[#75aafc] hover:text-[#9bc3ff] hover:border-[#3f6fb3] transition-colors font-mono text-[10px] uppercase tracking-wide" - > - <span>macOS Intel</span> - </a> - <a - href="/api/v1/daemon/download/macos-arm64" - className="flex items-center justify-center gap-2 px-3 py-2 border border-[rgba(117,170,252,0.25)] bg-[#0a1525] text-[#75aafc] hover:text-[#9bc3ff] hover:border-[#3f6fb3] transition-colors font-mono text-[10px] uppercase tracking-wide" - > - <span>macOS Apple Silicon</span> - </a> + {platformsLoading ? ( + <p className="col-span-2 text-[#7788aa] font-mono text-[10px]">Loading platforms...</p> + ) : ( + platforms.map((p) => ( + <a + key={p.platform} + href={p.available ? `${API_BASE}${p.downloadUrl}` : undefined} + download={p.available ? true : undefined} + className={`flex flex-col items-center justify-center gap-1 p-3 border border-[rgba(117,170,252,0.25)] bg-[#0a1525] font-mono text-xs text-[#9bc3ff] transition-colors ${ + p.available + ? "hover:bg-[#0d1f3a] cursor-pointer" + : "opacity-50 pointer-events-none" + }`} + > + <span className="text-[10px] uppercase tracking-wide"> + {platformLabels[p.platform] || p.platform} + </span> + <span + className={`text-[10px] ${ + p.available ? "text-green-400" : "text-[#556677]" + }`} + > + {p.available ? "Available" : "Not bundled"} + </span> + </a> + )) + )} </div> <div className="border-t border-[rgba(117,170,252,0.15)] pt-3"> |
