Verbinden-Tab: Hermes Desktop als Hauptweg, Legacy-Tools in den Ausklapper

Konsequenz aus dem Zed-Aus: Der Tab führte alle Anbindungen gleichrangig,
obwohl der rohe /v1-Zugang am PC kaum noch reale Nutzer hat. Neu:
- "Hermes Desktop anbinden" als prominente eigene Karte (Anleitung + Status).
- Kilo Code / Claude Code / Gedächtnis-MCP in den zugeklappten Ausklapper
  "Sonstige Tools (roher /v1-Zugang + Gedächtnis-MCP)" — alles weiter da,
  nur nicht mehr im Vordergrund. Drei-Leitungen-Hero bleibt.
- Header-Text entsprechend.
Browser-verifiziert gegen die Box (Karte, Ausklapper zu/auf, Leitungen grün);
tsc + Build grün, dist mit-committet, package-lock unangetastet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-09 11:26:43 +02:00
parent 3572667e08
commit 47ec64f61b
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
+2 -2
View File
@@ -7,8 +7,8 @@
<link rel="manifest" href="/manifest.webmanifest" /> <link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title> <title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-ByMZe5CM.js"></script> <script type="module" crossorigin src="/assets/index-BmqzJdEY.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DndftNG6.css"> <link rel="stylesheet" crossorigin href="/assets/index-CAFno6lH.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
+118 -70
View File
@@ -1,7 +1,7 @@
import { useState } from "react" import { useState } from "react"
import { import {
Check, Copy, Cpu, Brain, Globe, FolderOpen, Laptop, ArrowRight, Check, Copy, Cpu, Brain, Globe, FolderOpen, Laptop, ArrowRight,
Info, CircleCheck, CircleX, Loader2, Info, CircleCheck, CircleX, Loader2, ChevronDown, ChevronRight,
} from "lucide-react" } from "lucide-react"
import { useConnect, useConnectHealth } from "@/lib/queries" import { useConnect, useConnectHealth } from "@/lib/queries"
import type { ConnectTool, ConnectLine } from "@/lib/api" import type { ConnectTool, ConnectLine } from "@/lib/api"
@@ -75,8 +75,10 @@ function CodeWindow({
export function ConnectView() { export function ConnectView() {
const [host, setHost] = useState(localStorage.getItem("mc_host") || "192.168.178.151") const [host, setHost] = useState(localStorage.getItem("mc_host") || "192.168.178.151")
const [mcpPath, setMcpPath] = useState(localStorage.getItem("mc_mcp_path") || "") const [mcpPath, setMcpPath] = useState(localStorage.getItem("mc_mcp_path") || "")
const [active, setActive] = useState("hermes_desktop") // Legacy-Tools (roher /v1-Zugang) leben im Ausklapper — Hermes Desktop ist der Hauptweg.
const [copied, setCopied] = useState<"model" | "memory" | null>(null) const [active, setActive] = useState("kilo")
const [sonstigeOffen, setSonstigeOffen] = useState(false)
const [copied, setCopied] = useState<"desktop" | "model" | "memory" | null>(null)
const params = new URLSearchParams({ host }) const params = new URLSearchParams({ host })
if (mcpPath) params.set("mcp_path", mcpPath) if (mcpPath) params.set("mcp_path", mcpPath)
@@ -94,9 +96,10 @@ export function ConnectView() {
localStorage.setItem("mc_mcp_path", v) localStorage.setItem("mc_mcp_path", v)
} }
const desktop = data?.tools["hermes_desktop"]
const tool = data?.tools[active] 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 if (!snippet) return
await navigator.clipboard.writeText(snippet) await navigator.clipboard.writeText(snippet)
setCopied(which) setCopied(which)
@@ -111,8 +114,8 @@ export function ConnectView() {
Verbindung &amp; Integration Verbindung &amp; Integration
</h1> </h1>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Binde deinen lokalen Agenten an die Box an über <span className="text-foreground">drei getrennte Leitungen</span>: <span className="text-foreground">Hermes Desktop</span> ist die Tür zur Box einmal verbinden, fertig.
das Modell (Gateway), das geteilte Gedächtnis (MCP) und das Desktop-Gateway. Für Spezialfälle gibt es darunter die rohen Leitungen (Gateway&nbsp;/v1 + Gedächtnis-MCP) für sonstige Tools.
</p> </p>
</div> </div>
@@ -221,77 +224,122 @@ export function ConnectView() {
)} )}
{data && ( {data && (
<div className="grid gap-5 lg:grid-cols-2"> <div className="space-y-5">
{/* Leitung 1 — Modell anbinden */} {/* Hauptweg — Hermes Desktop anbinden */}
<div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-primary/70 bg-card/30 p-4"> {desktop && (
<div> <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 className="flex items-center gap-2 text-sm font-space font-bold text-foreground"> <div>
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-primary/15 text-primary text-[11px]">1</span> <div className="flex items-center gap-2 text-sm font-space font-bold text-foreground">
Modell anbinden <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> </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> </div>
)}
{/* Tool-Picker */} {/* Ausklapper — Legacy: roher /v1-Zugang + Gedächtnis-MCP für sonstige Tools */}
<div className="flex flex-wrap gap-1.5"> <div className="rounded-2xl border border-border/60 bg-card/30">
{Object.entries(data.tools).map(([key, t]) => ( <button
<button onClick={() => setSonstigeOffen((v) => !v)}
key={key} 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"
onClick={() => setActive(key)} >
className={cn( {sonstigeOffen ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
"rounded-lg px-3 py-1.5 text-[11px] font-semibold tracking-wide transition-all cursor-pointer", Sonstige Tools (roher /v1-Zugang + Gedächtnis-MCP)
active === key <span className="text-[10px] font-medium text-muted-foreground normal-case">Kilo Code · Claude Code · Eigenbau</span>
? "bg-primary text-primary-foreground shadow-md shadow-primary/10" </button>
: "border border-border/50 text-muted-foreground hover:text-foreground",
)}
>
{t.label}
</button>
))}
</div>
{tool && ( {sonstigeOffen && (
<> <div className="grid gap-5 lg:grid-cols-2 p-4 pt-0">
{tool.note && ( {/* Leitung 1 — Modell anbinden */}
<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"> <div className="space-y-3 rounded-2xl border border-border/60 border-t-2 border-t-primary/70 bg-card/30 p-4">
<Info className="h-4 w-4 text-primary shrink-0 mt-0.5" /> <div>
<span>{tool.note}</span> <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> </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 */} {/* Tool-Picker (ohne hermes_desktop — der hat oben seine eigene Karte) */}
<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 className="flex flex-wrap gap-1.5">
<div> {Object.entries(data.tools).filter(([key]) => key !== "hermes_desktop").map(([key, t]) => (
<div className="flex items-center gap-2 text-sm font-space font-bold text-foreground"> <button
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-violet-500/15 text-violet-300 text-[11px]">2</span> key={key}
Gedächtnis anbinden onClick={() => setActive(key)}
<span className="text-[10px] font-medium text-muted-foreground normal-case">optional</span> 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> </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>
</div> </div>
)} )}