同步完整源码至远程:扁平化重构现状 + 未入库源文件

- 补入库:server/internal/db/dump.go、redis 分页/扫描预算测试、opsxdb-mcp main_test、
  packages/opsxdb-mcp package-lock、docs 审计与对比文档等 37 个新文件
- 含结构扁平化进行中的 80 处修改与 155 处旧结构删除(server/ src/ src-tauri/ 为当前有效源)
- 构建产物(bin/target/dist)与签名私钥仍按规则排除
This commit is contained in:
logan committed 2026-10-16 03:47:33 +08:00
1 parent 5c0be49217
commit 2c0bfafd8d
269 files changed
+10372 -16435

No files matched your search

+32 -84
View File
@@ -24,11 +24,9 @@ const CLIENT_TABS: Array<{ id: ClientTab; label: string }> = [
{ id: "claude-desktop", label: "Claude Desktop" },
];
function buildClientSnippet(tab: ClientTab, goBin: string, readOnly: boolean): { path: string; json: string } {
function buildClientSnippet(tab: ClientTab, goBin: string): { path: string; json: string } {
const env: Record<string, string> = {};
if (goBin) env.OPSXDB_MCP_BIN = goBin;
// 权限以 ~/.opsxdb/mcp.json 为准;客户端 env 不放宽。
void readOnly;
const npxServer = {
command: "npx",
@@ -88,6 +86,7 @@ function buildClientSnippet(tab: ClientTab, goBin: string, readOnly: boolean): {
function StatusBadge({ status }: { status: string }) {
const map: Record<string, { label: string; color: string; bg: string }> = {
checking: { label: "检测中", color: "var(--ops-muted)", bg: "var(--ops-surface-2)" },
ready: { label: "已就绪", color: "var(--ops-accent)", bg: "color-mix(in srgb, var(--ops-accent) 14%, transparent)" },
partial: { label: "部分就绪", color: "var(--ops-warning, #d97706)", bg: "color-mix(in srgb, #d97706 14%, transparent)" },
not_installed: { label: "未安装", color: "var(--ops-warning, #d97706)", bg: "color-mix(in srgb, #d97706 14%, transparent)" },
@@ -103,51 +102,16 @@ function StatusBadge({ status }: { status: string }) {
);
}
function Row({ label, children, hint }: { label: string; children: React.ReactNode; hint?: string }) {
return (
<div className="space-y-1">
<div className="flex items-center justify-between gap-3">
<span className="text-[12.5px]" style={{ color: "var(--ops-text)" }}>{label}</span>
{children}
</div>
{hint && <div className="text-[11px] leading-relaxed" style={{ color: "var(--ops-muted)" }}>{hint}</div>}
</div>
);
}
function Toggle({ checked, onChange, disabled }: { checked: boolean; onChange: (v: boolean) => void; disabled?: boolean }) {
return (
<button
type="button"
role="switch"
aria-checked={checked}
disabled={disabled}
className="rounded-full border transition disabled:opacity-50"
style={{
height: 18,
width: 36,
borderColor: "var(--ops-border)",
background: checked ? "var(--ops-accent)" : "var(--ops-surface-2)",
}}
onClick={() => onChange(!checked)}
>
<span
className="block rounded-full bg-white transition-all"
style={{ width: 12, height: 12, marginLeft: checked ? 20 : 3, boxShadow: "0 1px 2px rgba(0,0,0,.3)" }}
/>
</button>
);
}
/** 设置 → MCP:安装检测、只读/危险 SQL、白名单、多客户端配置片段 */
/** 设置 → MCP:权限状态、授权连接、客户端接入 */
export function McpSettings() {
const notify = useWorkspaceStore((s) => s.notify);
const connections = useWorkspaceStore((s) => s.connections);
const [install, setInstall] = useState<McpInstallInfo | null>(null);
const [policy, setPolicy] = useState<McpPolicy | null>(null);
const [policyPath, setPolicyPath] = useState("");
const [loading, setLoading] = useState(true);
const [installLoading, setInstallLoading] = useState(true);
const [installError, setInstallError] = useState("");
const [saving, setSaving] = useState(false);
const [error, setError] = useState("");
const [clientTab, setClientTab] = useState<ClientTab>("cursor");
@@ -160,12 +124,10 @@ export function McpSettings() {
let alive = true;
setLoading(true);
setError("");
Promise.all([getMcpInstall(), getMcpPolicy()])
.then(([inst, pol]) => {
getMcpPolicy()
.then((pol) => {
if (!alive) return;
setInstall(inst);
setPolicy(pol.policy);
setPolicyPath(pol.path || "");
})
.catch((e) => {
if (alive) setError(e instanceof Error ? e.message : String(e));
@@ -173,6 +135,12 @@ export function McpSettings() {
.finally(() => {
if (alive) setLoading(false);
});
setInstallLoading(true);
setInstallError("");
getMcpInstall()
.then((inst) => { if (alive) setInstall(inst); })
.catch((e) => { if (alive) setInstallError(e instanceof Error ? e.message : String(e)); })
.finally(() => { if (alive) setInstallLoading(false); });
return () => {
alive = false;
};
@@ -183,8 +151,8 @@ export function McpSettings() {
const allowed = new Set(policy?.allowed_connection_ids ?? []);
const snippet = useMemo(
() => buildClientSnippet(clientTab, install?.goBinaryPath || "", readOnly),
[clientTab, install?.goBinaryPath, readOnly],
() => buildClientSnippet(clientTab, install?.goBinaryPath || ""),
[clientTab, install?.goBinaryPath],
);
const persist = async (next: McpPolicy) => {
@@ -192,7 +160,6 @@ export function McpSettings() {
try {
const res = await saveMcpPolicy(next);
setPolicy(res.policy);
setPolicyPath(res.path || policyPath);
notify({ kind: "success", title: "MCP", message: "策略已保存", mode: "toast", durationMs: 1400 });
} catch (e) {
notify({ kind: "error", title: "MCP", message: e instanceof Error ? e.message : String(e), mode: "modal" });
@@ -220,7 +187,7 @@ export function McpSettings() {
void persist({ ...policy, allowed_connection_ids: Array.from(set) });
};
if (loading) return <p role="status" className="text-xs" style={{ color: "var(--ops-muted)" }}>正在检测 MCP 环境…</p>;
if (loading) return <p role="status" className="text-xs" style={{ color: "var(--ops-muted)" }}>正在读取 MCP 设置…</p>;
if (error) {
return (
<div role="alert" className="space-y-2 text-xs">
@@ -237,7 +204,7 @@ export function McpSettings() {
{/* Header */}
<div className="flex flex-wrap items-center gap-2">
<h3 className="text-[13px] font-semibold">MCP Server</h3>
<StatusBadge status={install?.status || "not_installed"} />
<StatusBadge status={installLoading && !install ? "checking" : install?.status || "not_installed"} />
<button
type="button"
className="ops-btn-ghost ml-auto inline-flex h-6 items-center gap-1 px-2 text-[11px]"
@@ -247,14 +214,15 @@ export function McpSettings() {
MCP 指南 <ExternalLink className="h-3 w-3" strokeWidth={1.5} />
</button>
</div>
{installError && <p role="alert" className="text-[11px]" style={{ color: "var(--ops-warning, #d97706)" }}>安装检测失败:{installError}。连接白名单与权限设置仍可使用。</p>}
{/* Version grid */}
<div className="grid grid-cols-2 gap-2">
{[
["当前版本", install?.currentVersion || (install?.goBinaryFound ? "native" : "未检测到全局安装")],
["当前版本", install?.currentVersion || (installLoading ? "检测中…" : install?.goBinaryFound ? "native" : "未检测到全局安装")],
["最新版本", install?.latestVersion ? `v${install.latestVersion}` : "—"],
["Node.js", install?.nodeVersion || "未检测到"],
["npm", install?.npmAvailable ? (install.npmVersion || "可用") : "不可用"],
["Node.js", install?.nodeVersion || (installLoading ? "检测中…" : "未检测到")],
["npm", install?.npmAvailable ? (install.npmVersion || "可用") : installLoading ? "检测中…" : "不可用"],
].map(([k, v]) => (
<div key={k} className="rounded-lg border px-2.5 py-2" style={{ borderColor: "var(--ops-border-soft)", background: "var(--ops-surface-2)" }}>
<div className="text-[10px] uppercase tracking-wide" style={{ color: "var(--ops-muted)" }}>{k}</div>
@@ -296,42 +264,22 @@ export function McpSettings() {
</p>
</div>
{/* Toggles */}
<div className="space-y-3 border-t pt-3" style={{ borderColor: "var(--ops-border-soft)" }}>
<Row
label="只读模式"
hint="开启后 MCP/Agent 仅允许查询与元数据读取(mcp.json mode=read_only)。关闭后变为 read_write,写操作仍须确认。"
>
<Toggle
checked={readOnly}
disabled={saving || !policy}
onChange={(v) => {
if (!policy) return;
void persist({ ...policy, mode: v ? "read_only" : "read_write", allow_dangerous: v ? false : policy.allow_dangerous });
}}
/>
</Row>
<Row
label="允许危险 SQL"
hint="开启后,在非只读模式下经确认可执行 DROP / TRUNCATE / ALTER / 无 WHERE 的 UPDATE·DELETE 等。默认关闭。"
>
<Toggle
checked={allowDangerous}
disabled={saving || !policy || readOnly}
onChange={(v) => {
if (!policy) return;
void persist({ ...policy, allow_dangerous: v });
}}
/>
</Row>
<div className="space-y-2 border-t pt-3" style={{ borderColor: "var(--ops-border-soft)" }}>
<div className="flex flex-wrap items-center gap-2 text-xs">
<span className="rounded-md px-2 py-1" style={{ background: "var(--ops-surface-2)" }}>{readOnly ? "只读模式" : "读写模式"}</span>
{!readOnly && allowDangerous && <span className="rounded-md px-2 py-1" style={{ background: "var(--ops-surface-2)" }}>允许危险 SQL</span>}
{(readOnly || !allowDangerous) && <button type="button" className="ops-btn-secondary" disabled={saving || !policy} onClick={() => {
if (policy) void persist({ ...policy, mode: "read_write", allow_dangerous: true });
}}>使用默认权限</button>}
</div>
<p className="text-[11px]" style={{ color: "var(--ops-muted)" }}>Agent 写入前确认具体命令、连接与数据库。</p>
</div>
{/* Whitelist */}
<div className="space-y-2 border-t pt-3" style={{ borderColor: "var(--ops-border-soft)" }}>
<div className="text-[12px] font-medium">连接白名单</div>
<p className="text-[11px] leading-relaxed" style={{ color: "var(--ops-muted)" }}>
空白名单时 MCP/Agent <strong>拒绝全部连接</strong>。勾选后写入 <code className="font-mono">~/.opsxdb/mcp.json</code>
{policyPath ? `(${policyPath})` : ""}。
仅可访问勾选的连接。
</p>
{connections.length === 0 ? (
<p className="text-[11px]" style={{ color: "var(--ops-muted)" }}>暂无已保存连接。请先在侧栏新建连接。</p>
@@ -388,7 +336,7 @@ export function McpSettings() {
</div>
<div className="flex flex-wrap gap-2 border-t pt-3" style={{ borderColor: "var(--ops-border-soft)" }}>
<button type="button" className="ops-btn-secondary inline-flex h-7 items-center gap-1 px-2.5 text-[11px]" onClick={reload} disabled={loading}>
<button type="button" className="ops-btn-secondary inline-flex h-7 items-center gap-1 px-2.5 text-[11px]" onClick={reload} disabled={loading || installLoading}>
<RefreshCw className="h-3 w-3" /> 重新检查
</button>
</div>