Auftragsbuch: 'wartung/verbinden-desktop-fokus' angenommen (Ein-Klick-Gate)

This commit is contained in:
Auftragsbuch
2026-07-09 11:27:30 +02:00
6 changed files with 294 additions and 246 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+16 -16
View File
@@ -1,16 +1,16 @@
<!doctype html>
<html lang="de" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0d1117" />
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-ByMZe5CM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DndftNG6.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
<!doctype html>
<html lang="de" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0d1117" />
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-BmqzJdEY.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CAFno6lH.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
+118 -70
View File
@@ -1,7 +1,7 @@
import { useState } from "react"
import {
Check, Copy, Cpu, Brain, Globe, FolderOpen, Laptop, ArrowRight,
Info, CircleCheck, CircleX, Loader2,
Info, CircleCheck, CircleX, Loader2, ChevronDown, ChevronRight,
} from "lucide-react"
import { useConnect, useConnectHealth } from "@/lib/queries"
import type { ConnectTool, ConnectLine } from "@/lib/api"
@@ -75,8 +75,10 @@ function CodeWindow({
export function ConnectView() {
const [host, setHost] = useState(localStorage.getItem("mc_host") || "192.168.178.151")
const [mcpPath, setMcpPath] = useState(localStorage.getItem("mc_mcp_path") || "")
const [active, setActive] = useState("hermes_desktop")
const [copied, setCopied] = useState<"model" | "memory" | null>(null)
// Legacy-Tools (roher /v1-Zugang) leben im Ausklapper — Hermes Desktop ist der Hauptweg.
const [active, setActive] = useState("kilo")
const [sonstigeOffen, setSonstigeOffen] = useState(false)
const [copied, setCopied] = useState<"desktop" | "model" | "memory" | null>(null)
const params = new URLSearchParams({ host })
if (mcpPath) params.set("mcp_path", mcpPath)
@@ -94,9 +96,10 @@ export function ConnectView() {
localStorage.setItem("mc_mcp_path", v)
}
const desktop = data?.tools["hermes_desktop"]
const tool = data?.tools[active]
async function copy(which: "model" | "memory", snippet?: string) {
async function copy(which: "desktop" | "model" | "memory", snippet?: string) {
if (!snippet) return
await navigator.clipboard.writeText(snippet)
setCopied(which)
@@ -111,8 +114,8 @@ export function ConnectView() {
Verbindung &amp; Integration
</h1>
<p className="text-sm text-muted-foreground">
Binde deinen lokalen Agenten an die Box an über <span className="text-foreground">drei getrennte Leitungen</span>:
das Modell (Gateway), das geteilte Gedächtnis (MCP) und das Desktop-Gateway.
<span className="text-foreground">Hermes Desktop</span> ist die Tür zur Box einmal verbinden, fertig.
Für Spezialfälle gibt es darunter die rohen Leitungen (Gateway&nbsp;/v1 + Gedächtnis-MCP) für sonstige Tools.
</p>
</div>
@@ -221,77 +224,122 @@ export function ConnectView() {
)}
{data && (
<div className="grid gap-5 lg:grid-cols-2">
{/* Leitung 1 — Modell anbinden */}
<div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-primary/70 bg-card/30 p-4">
<div>
<div className="flex items-center gap-2 text-sm font-space font-bold text-foreground">
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-primary/15 text-primary text-[11px]">1</span>
Modell anbinden
<div className="space-y-5">
{/* Hauptweg — Hermes Desktop anbinden */}
{desktop && (
<div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-emerald-500/70 bg-card/30 p-4">
<div>
<div className="flex items-center gap-2 text-sm font-space font-bold text-foreground">
<Laptop className="h-4 w-4 text-emerald-400" />
Hermes Desktop anbinden
<span className="text-[10px] font-medium text-emerald-400/90 normal-case">der Hauptweg</span>
</div>
<p className="text-[11px] text-muted-foreground mt-0.5">
Die Desktop-App dockt remote an die Box an volle Agent-Oberfläche, Projekte, Review, Gedächtnis inklusive.
</p>
</div>
<p className="text-[11px] text-muted-foreground mt-0.5">Wähle dein Tool das Snippet zeigt auf den Gateway.</p>
{desktop.note && (
<div className="flex items-start gap-2.5 p-3 rounded-xl bg-emerald-500/5 border border-emerald-500/20 text-[11px] text-muted-foreground leading-relaxed">
<Info className="h-4 w-4 text-emerald-400 shrink-0 mt-0.5" />
<span>{desktop.note}</span>
</div>
)}
<CodeWindow
tool={desktop}
fileName={FILE_NAMES["hermes_desktop"]}
accent="teal"
copied={copied === "desktop"}
onCopy={() => copy("desktop", desktop.snippet)}
/>
</div>
)}
{/* Tool-Picker */}
<div className="flex flex-wrap gap-1.5">
{Object.entries(data.tools).map(([key, t]) => (
<button
key={key}
onClick={() => setActive(key)}
className={cn(
"rounded-lg px-3 py-1.5 text-[11px] font-semibold tracking-wide transition-all cursor-pointer",
active === key
? "bg-primary text-primary-foreground shadow-md shadow-primary/10"
: "border border-border/50 text-muted-foreground hover:text-foreground",
)}
>
{t.label}
</button>
))}
</div>
{/* Ausklapper — Legacy: roher /v1-Zugang + Gedächtnis-MCP für sonstige Tools */}
<div className="rounded-2xl border border-border/60 bg-card/30">
<button
onClick={() => setSonstigeOffen((v) => !v)}
className="flex w-full items-center gap-2 p-4 text-sm font-space font-bold text-foreground cursor-pointer hover:text-primary transition-colors"
>
{sonstigeOffen ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
Sonstige Tools (roher /v1-Zugang + Gedächtnis-MCP)
<span className="text-[10px] font-medium text-muted-foreground normal-case">Kilo Code · Claude Code · Eigenbau</span>
</button>
{tool && (
<>
{tool.note && (
<div className="flex items-start gap-2.5 p-3 rounded-xl bg-primary/5 border border-primary/20 text-[11px] text-muted-foreground leading-relaxed">
<Info className="h-4 w-4 text-primary shrink-0 mt-0.5" />
<span>{tool.note}</span>
{sonstigeOffen && (
<div className="grid gap-5 lg:grid-cols-2 p-4 pt-0">
{/* Leitung 1 — Modell anbinden */}
<div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-primary/70 bg-card/30 p-4">
<div>
<div className="flex items-center gap-2 text-sm font-space font-bold text-foreground">
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-primary/15 text-primary text-[11px]">1</span>
Modell anbinden
</div>
<p className="text-[11px] text-muted-foreground mt-0.5">Wähle dein Tool das Snippet zeigt auf den Gateway.</p>
</div>
)}
<CodeWindow
tool={tool}
fileName={FILE_NAMES[active] || "config.json"}
accent="teal"
copied={copied === "model"}
onCopy={() => copy("model", tool.snippet)}
/>
</>
)}
</div>
{/* Leitung 2 — Gedächtnis anbinden */}
<div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-violet-500/70 bg-card/30 p-4">
<div>
<div className="flex items-center gap-2 text-sm font-space font-bold text-foreground">
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-violet-500/15 text-violet-300 text-[11px]">2</span>
Gedächtnis anbinden
<span className="text-[10px] font-medium text-muted-foreground normal-case">optional</span>
{/* Tool-Picker (ohne hermes_desktop — der hat oben seine eigene Karte) */}
<div className="flex flex-wrap gap-1.5">
{Object.entries(data.tools).filter(([key]) => key !== "hermes_desktop").map(([key, t]) => (
<button
key={key}
onClick={() => setActive(key)}
className={cn(
"rounded-lg px-3 py-1.5 text-[11px] font-semibold tracking-wide transition-all cursor-pointer",
active === key
? "bg-primary text-primary-foreground shadow-md shadow-primary/10"
: "border border-border/50 text-muted-foreground hover:text-foreground",
)}
>
{t.label}
</button>
))}
</div>
{tool && (
<>
{tool.note && (
<div className="flex items-start gap-2.5 p-3 rounded-xl bg-primary/5 border border-primary/20 text-[11px] text-muted-foreground leading-relaxed">
<Info className="h-4 w-4 text-primary shrink-0 mt-0.5" />
<span>{tool.note}</span>
</div>
)}
<CodeWindow
tool={tool}
fileName={FILE_NAMES[active] || "config.json"}
accent="teal"
copied={copied === "model"}
onCopy={() => copy("model", tool.snippet)}
/>
</>
)}
</div>
{/* Leitung 2 — Gedächtnis anbinden */}
<div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-violet-500/70 bg-card/30 p-4">
<div>
<div className="flex items-center gap-2 text-sm font-space font-bold text-foreground">
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-violet-500/15 text-violet-300 text-[11px]">2</span>
Gedächtnis anbinden
<span className="text-[10px] font-medium text-muted-foreground normal-case">optional</span>
</div>
<p className="text-[11px] text-muted-foreground mt-0.5">Ein MCP-Block gilt zusätzlich für <em>jedes</em> Tool aus Schritt 1.</p>
</div>
<div className="flex items-start gap-2.5 p-3 rounded-xl bg-violet-500/5 border border-violet-500/20 text-[11px] text-muted-foreground leading-relaxed">
<Info className="h-4 w-4 text-violet-400 shrink-0 mt-0.5" />
<span>{data.memory.note}</span>
</div>
<CodeWindow
tool={data.memory}
fileName="mcp.json"
accent="violet"
copied={copied === "memory"}
onCopy={() => copy("memory", data.memory.snippet)}
/>
</div>
</div>
<p className="text-[11px] text-muted-foreground mt-0.5">Ein MCP-Block gilt zusätzlich für <em>jedes</em> Tool aus Schritt 1.</p>
</div>
<div className="flex items-start gap-2.5 p-3 rounded-xl bg-violet-500/5 border border-violet-500/20 text-[11px] text-muted-foreground leading-relaxed">
<Info className="h-4 w-4 text-violet-400 shrink-0 mt-0.5" />
<span>{data.memory.note}</span>
</div>
<CodeWindow
tool={data.memory}
fileName="mcp.json"
accent="violet"
copied={copied === "memory"}
onCopy={() => copy("memory", data.memory.snippet)}
/>
)}
</div>
</div>
)}