"use client"; import { useState, useCallback, useMemo } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { Check, Copy, Terminal, Loader2 } from "lucide-react"; import { Button } from "@multica/ui/components/ui/button"; import { Card, CardContent } from "@multica/ui/components/ui/card"; import { useWSEvent } from "@multica/core/realtime"; import { api } from "@multica/core/api"; import { ProviderLogo } from "../runtimes/components/provider-logo"; import { runtimeListOptions, runtimeKeys, } from "@multica/core/runtimes/queries"; const CLOUD_HOST = "multica.ai"; const INSTALL_STEP = { label: "Install the Multica CLI", cmd: "curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash", }; function isCloudEnvironment(): boolean { if (typeof window === "undefined") return true; return window.location.hostname.endsWith(CLOUD_HOST); } function buildSetupCommand(): string { if (isCloudEnvironment()) return "multica setup"; const appUrl = typeof window !== "undefined" ? window.location.origin : ""; const apiBaseUrl = api.getBaseUrl?.() ?? ""; const serverUrl = apiBaseUrl || appUrl; if (!serverUrl || serverUrl === "http://localhost:8080") { // Default self-host — no flags needed return "multica setup self-host"; } const parts = ["multica setup self-host"]; parts.push(`--server-url ${serverUrl}`); if (appUrl && appUrl !== serverUrl) { parts.push(`--app-url ${appUrl}`); } return parts.join(" "); } function CopyButton({ text }: { text: string }) { const [copied, setCopied] = useState(false); const handleCopy = () => { navigator.clipboard.writeText(text); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return ( ); } export function StepRuntime({ wsId, onNext, }: { wsId: string; onNext: () => void; }) { const qc = useQueryClient(); const setupSteps = useMemo( () => [ INSTALL_STEP, { label: "Set up and start the daemon", cmd: buildSetupCommand() }, ], [], ); const { data: runtimes = [] } = useQuery(runtimeListOptions(wsId)); const handleDaemonEvent = useCallback(() => { qc.invalidateQueries({ queryKey: runtimeKeys.all(wsId) }); }, [qc, wsId]); useWSEvent("daemon:register", handleDaemonEvent); const hasRuntimes = runtimes.length > 0; return (
Install the CLI and run the setup command below to connect your machine. The daemon auto-detects agent CLIs (Claude Code, Codex, etc.) on your PATH.
{i + 1}. {step.label}
{step.cmd}
The setup command handles authentication, configuration, and daemon startup — all in one step.