diff --git a/plugins/canvas/registry/build.mjs b/plugins/canvas/registry/build.mjs index 66c0a27..29be68e 100644 --- a/plugins/canvas/registry/build.mjs +++ b/plugins/canvas/registry/build.mjs @@ -3,7 +3,7 @@ // CI(publish-plugins.yml)把 dist/ 强推到 plugins-dist 分支,前端经 jsDelivr 远程拉取。 // 本地自测:`npm install && npm run build`,再把 VITE_PLUGIN_REGISTRY_URL 指向本地 dist。 import { build } from "esbuild"; -import { mkdir, rm, writeFile } from "node:fs/promises"; +import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -11,15 +11,24 @@ const root = dirname(fileURLToPath(import.meta.url)); const outDir = join(root, "dist"); const nodeModules = join(root, "node_modules"); -// 官方插件元数据(单一真源:清单从这里生成)。新增官方插件在此登记即可。 +// 官方插件登记表:新增官方插件在此登记即可。 +// 版本不在这里写死 —— 从各插件的 package.json 读取(单一真源), +// 与插件 src 里 definePlugin({version}) 保持一致,避免清单与产物版本脱节。 const OFFICIAL = [ - { id: "markdown", dir: "markdown", name: "Markdown 节点", version: "1.0.0", description: "在画布中编辑与渲染 Markdown", icon: "📝" }, - { id: "svg", dir: "svg", name: "SVG 节点", version: "1.0.0", description: "编辑与渲染 SVG,可接收上游文本节点的 SVG 源码", icon: "🔷" }, - { id: "html", dir: "html", name: "HTML 节点", version: "1.0.0", description: "沙箱 iframe 渲染 HTML,支持 {{input}} 注入上游文本", icon: "🌐" }, - { id: "panorama", dir: "panorama", name: "3D 全景节点", version: "1.0.0", description: "查看 360° 等距柱状全景图,可从上游图片节点取图", icon: "🧭" }, - { id: "sticky-note", dir: "sticky-note", name: "便利贴节点", version: "1.0.0", description: "可换色、可编辑、可衍生文本节点的便利贴", icon: "📌" }, + { id: "markdown", dir: "markdown", name: "Markdown 节点", description: "在画布中编辑与渲染 Markdown", icon: "📝" }, + { id: "svg", dir: "svg", name: "SVG 节点", description: "编辑与渲染 SVG,可接收上游文本节点的 SVG 源码", icon: "🔷" }, + { id: "html", dir: "html", name: "HTML 节点", description: "沙箱 iframe 渲染 HTML,支持 {{input}} 注入上游文本", icon: "🌐" }, + { id: "panorama", dir: "panorama", name: "3D 全景节点", description: "查看 360° 等距柱状全景图,可从上游图片节点取图", icon: "🧭" }, + { id: "sticky-note", dir: "sticky-note", name: "便利贴节点", description: "可换色、可编辑、可衍生文本节点的便利贴", icon: "📌" }, ]; +// 读取插件 package.json 的 version 作为清单版本的唯一来源 +async function readPluginVersion(dir) { + const pkg = JSON.parse(await readFile(join(root, "..", dir, "package.json"), "utf8")); + if (!pkg.version) throw new Error(`插件 ${dir} 的 package.json 缺少 version`); + return pkg.version; +} + await rm(outDir, { recursive: true, force: true }); await mkdir(outDir, { recursive: true }); @@ -45,14 +54,16 @@ for (const plugin of OFFICIAL) { const manifest = { // 清单结构版本;entry 为相对本清单的 bundle 文件名,由前端解析成绝对 URL version: 1, - plugins: OFFICIAL.map((plugin) => ({ - id: plugin.id, - name: plugin.name, - version: plugin.version, - description: plugin.description, - icon: plugin.icon, - entry: `${plugin.id}.js`, - })), + plugins: await Promise.all( + OFFICIAL.map(async (plugin) => ({ + id: plugin.id, + name: plugin.name, + version: await readPluginVersion(plugin.dir), + description: plugin.description, + icon: plugin.icon, + entry: `${plugin.id}.js`, + })), + ), }; await writeFile(join(outDir, "official-plugins.json"), JSON.stringify(manifest, null, 4) + "\n"); console.log(`wrote official-plugins.json (${OFFICIAL.length} plugins) → dist/`); diff --git a/web/src/components/canvas/canvas-plugin-manager-modal.tsx b/web/src/components/canvas/canvas-plugin-manager-modal.tsx index 8ebcdd3..979de8f 100644 --- a/web/src/components/canvas/canvas-plugin-manager-modal.tsx +++ b/web/src/components/canvas/canvas-plugin-manager-modal.tsx @@ -4,7 +4,7 @@ import { AlertTriangle, Download, Puzzle, RefreshCw, Trash2 } from "lucide-react import { canvasThemes } from "@/lib/canvas-theme"; import { installPluginFromUrl, setPluginEnabled, uninstallPlugin, updatePlugin } from "@/lib/canvas/plugin-loader"; -import { fetchOfficialPlugins, type OfficialPluginEntry } from "@/lib/canvas/plugin-registry"; +import { fetchOfficialPlugins, hasUpgrade, type OfficialPluginEntry } from "@/lib/canvas/plugin-registry"; import { useThemeStore } from "@/stores/use-theme-store"; import { usePluginStore, type InstalledPlugin } from "@/stores/canvas/use-plugin-store"; @@ -81,12 +81,20 @@ export function CanvasPluginManagerModal({ open, onClose }: { open: boolean; onC }; // 已安装插件的操作区:启用开关 +(非本地)更新/卸载 - const installedControls = (record: InstalledPlugin) => ( + // upgradable=true 时(远程有更高版本),更新按钮高亮为主色以提示升级 + const installedControls = (record: InstalledPlugin, upgradable = false) => ( <> runOnPlugin(record, () => setPluginEnabled(record, checked), checked ? "已启用" : "已禁用")} /> {!record.local && ( <> -