feat(*): 插件中心与模型协议 - 完善声明式协议运行时并增加功能开放控制

This commit is contained in:
ddCat
2026-08-23 23:19:27 +08:00
parent 7cc6021f6e
commit 919037e5d9
106 changed files with 8817 additions and 500 deletions

View File

@@ -0,0 +1,92 @@
import { Modal, Upload } from "antd";
import { CloudUpload, FileText, ShieldCheck } from "lucide-react";
import type { RegisteredPlugin } from "@/lib/plugins/plugin-types";
import pluginDevelopmentGuideMarkdown from "./plugin-development-guide.md?raw";
import { getPluginDocumentation } from "./plugin-documentation";
import { PluginMarkdown } from "./plugin-markdown";
type UploadPluginModalProps = {
open: boolean;
onClose: () => void;
onUpload: (file: File) => void;
};
export function UploadPluginModal({ open, onClose, onUpload }: UploadPluginModalProps) {
return (
<Modal
className="workspace-modal workspace-modal-wide plugin-upload-modal"
title="上传插件"
open={open}
centered
footer={null}
destroyOnHidden
onCancel={onClose}
styles={{ body: { maxHeight: "min(82vh, 900px)", overflowY: "auto", overscrollBehavior: "contain" } }}
>
<div className="plugin-upload-layout">
<section className="plugin-upload-guide">
<PluginMarkdown source={pluginDevelopmentGuideMarkdown} />
</section>
<aside className="plugin-upload-panel">
<div className="plugin-upload-panel-heading">
<span className="plugin-upload-panel-icon"><CloudUpload className="size-5" /></span>
<div>
<h2>安装插件包</h2>
<p>选择符合清单规范的 JSON 文件,安装后会立即进入插件中心。</p>
</div>
</div>
<Upload.Dragger
className="plugin-upload-dropzone"
accept=".json,application/json"
maxCount={1}
showUploadList={false}
beforeUpload={(file) => {
onUpload(file);
return false;
}}
>
<CloudUpload className="plugin-upload-dropzone-icon" />
<p className="ant-upload-text">点击选择插件文件</p>
<p className="ant-upload-hint">仅支持 JSON 清单,大小不超过 512 KiB</p>
</Upload.Dragger>
<div className="plugin-upload-notice">
<ShieldCheck className="size-4" />
<span>上传前请确认插件来源可信。协议插件不会在浏览器执行任意脚本,密钥也不会从清单读取。</span>
</div>
</aside>
</div>
</Modal>
);
}
type PluginDetailsModalProps = {
plugin?: RegisteredPlugin;
restoreFocus: boolean;
onClose: () => void;
};
export function PluginDetailsModal({ plugin, restoreFocus, onClose }: PluginDetailsModalProps) {
return (
<Modal
className="workspace-modal workspace-modal-wide plugin-details-modal"
title={plugin ? (
<div className="plugin-details-title">
<FileText className="size-4" />
<span>{plugin.manifest.name}</span>
<span className="plugin-version">v{plugin.manifest.version}</span>
</div>
) : null}
open={Boolean(plugin)}
centered
footer={null}
destroyOnHidden
focusTriggerAfterClose={restoreFocus}
onCancel={onClose}
styles={{ body: { maxHeight: "min(78vh, 820px)", overflowY: "auto", overscrollBehavior: "contain" } }}
>
{plugin ? <PluginMarkdown className="plugin-details-document" source={getPluginDocumentation(plugin.manifest)} /> : null}
</Modal>
);
}