/* Claude — the management page for the Claude Code install agents run on: the account * login (moved here from the old Claude Login page), plus the operator-managed skills, * MCP connectors, plugins, and permission overrides. Everything except the login is a * plain DB write that the control container applies at the NEXT launch of every agent — * skills sync to the workers' user-level ~/.claude/skills, connectors become each run's * --mcp-config file, and plugins/permissions fold into the generated settings.json. */ "use client"; import { useState } from "react"; import { useDashboard } from "@/components/store"; import type { ConnectorBody, ModelBody, PluginBody, SkillBody } from "@/components/store"; import { Badge, Button, Card, Input, Select, Tabs, Textarea, Toggle } from "@/components/ui"; import type { ClaudeConnector, ClaudeModel, ClaudePlugin, ClaudeSkill } from "@/lib/api"; import { ClaudeLoginPanel } from "@/components/sections/LoginSection"; /* KEY=VALUE-per-line <-> map helpers for connector env/headers. */ function parseKeyValues(text: string): Record { const out: Record = {}; for (const line of text.split("\n")) { const trimmed = line.trim(); if (!trimmed) continue; const eq = trimmed.indexOf("="); if (eq <= 0) continue; out[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim(); } return out; } function formatKeyValues(map: Record | null | undefined): string { return Object.entries(map ?? {}) .map(([k, v]) => `${k}=${v}`) .join("\n"); } function parseLines(text: string): string[] { return text .split("\n") .map((l) => l.trim()) .filter(Boolean); } /* ---- Skills ------------------------------------------------------------------------ */ const emptySkill = { name: "", description: "", content: "", enabled: true }; /* Install-from-prompt: paste the "install prompt" a marketplace page (SkillsMP etc.) * shows, and the worker runs it through a one-off headless claude, importing whatever * it fetches as managed skills. Headless = nobody to answer questions, so the run makes * the choices a human would be asked (scope, options) itself — always user scope, * sensible defaults — and reports them; the import lands below for review/editing. */ function InstallCard() { const s = useDashboard(); const [prompt, setPrompt] = useState(""); const run = async () => { const ok = await s.installClaudeSkill(prompt.trim()); if (ok) setPrompt(""); }; return (
Install from a marketplace prompt