# Phase 0:基础设施骨架 ## 目标 建好管道,不改现有功能。验证编译通过 + API 可调用。 **不包含**:无 UI 变化、无真实插件注册、无设置面板。 --- ## 文件清单与实施顺序 ### Step 1:核心接口定义 **新建** `internal/plugin/plugin.go` 内容:PluginID、PluginSource、PluginMetadata、PluginCapability、Plugin 接口、TabProvider、FilePreviewHandler、PreviewInfo、TabDef、CoreServices 接口定义。 依赖:无 --- ### Step 2:适配器(避免方法泄漏) **新建** `internal/plugin/adapter.go` 内容:`adapter` 结构体实现 `CoreServices` 接口的 6 个方法。构造函数 `NewAdapter(app *App) CoreServices`。 关键设计:不在 App 上直接实现 CoreServices(会导致 6 个内部方法被 Wails v3 自动暴露为前端 API),而是通过独立 adapter 封装。 依赖:Step 1 --- ### Step 3:Tab 注册表 **新建** `internal/plugin/tab_registry.go` 内容: - `TabRegistry` struct(mu + entries map) - Register(冲突检测)、GetByTabKey、GetAllDefinitions(按 Order 排序)、GetAllProviders、Count 依赖:Step 1 --- ### Step 4:预览注册表 **新建** `internal/plugin/preview_registry.go` 内容: - `PreviewRegistry` struct(mu + handlers 切片,按 priority 降序) - Register(自动排序)、Resolve(遍历匹配第一个 canHandle)、GetAllHandlers、Count 依赖:Step 1 --- ### Step 5:PluginManager **新建** `internal/plugin/manager.go` 内容: - `Manager` struct(plugins map + core + tabReg + previewReg + ctx + initialized) - NewManager、Register(自动分发到子注册表 + 回滚)、InitAll、StartByTabKey - GetPluginInfos、ResolvePreview(附加 PluginID 到响应)、GetTabDefinitions、Shutdown 依赖:Step 1 ~ 4 全部 --- ### Step 6:前端类型定义 **新建** `frontend/src/plugin/types.ts` 内容:PluginCapability enum、PluginMetadata、TabPluginDefinition、FilePreviewHandlerDefinition、RenderConfig 接口。 依赖:无 --- ### Step 7:前端注册中心 **新建** `frontend/src/plugin/registry.ts` 内容: - Vue reactive state(tabPlugins Map + previewHandlers 数组) - Tab API:registerTabPlugin / getTabComponent / getAllTabDefinitions / hasTabPlugin - Preview API:registerPreviewHandler(按 priority 插入)/ resolvePreviewHandler / getAllPreviewHandlers - 调试工具:getRegistryStats 依赖:Step 6 --- ### Step 8:集成到 App **修改** `app.go` 改动点: 1. **新增字段**:`pluginMgr *plugin.Manager`(在 `mu` 字段之后) 2. **ServiceStartup 中**(步骤 4 之后):初始化 pluginMgr ```go fmt.Println("[启动] 初始化插件管理器...") a.pluginMgr = plugin.NewManager(plugin.NewAdapter(a)) ``` 3. **ServiceShutdown 末尾**:关闭 pluginMgr ```go if a.pluginMgr != nil { a.pluginMgr.Shutdown() } ``` 4. **新增绑定方法**(Wails v3 自动暴露前端): - `GetPluginInfos() ([]map[string]interface{}, error)` — 返回空数组或插件列表 - `ResolvePreview(req ResolvePreviewRequest) (map[string]interface{}, error)` — 解析文件预览处理器 - `ResolvePreviewRequest{Filename string}` 请求结构体 依赖:Step 5 --- ## 验证方案 ### 编译验证 ```bash go build ./internal/plugin/ go build . cd frontend && npx vue-tsc --noEmit ``` ### 运行时验证 | # | 操作 | 预期结果 | |---|------|---------| | V1 | 运行应用 | 日志出现 `[启动] 初始化插件管理器...` | | V2 | 关闭应用 | 日志出现 `[插件管理器] 已关闭` | | V3 | DevTools: `GetPluginInfos()` | 返回 `{success:true, data:[]}` | | V4 | DevTools: `ResolvePreview({filename:'test'})` | 返回 `{success:false, message:"no preview handler..."}` | | V5 | 前端 import registry | 无 TS 错误 | ### 边界情况 | 场景 | 预期行为 | |------|---------| | pluginMgr 为 nil 调用 GetPluginInfos | 返回空数组,不 panic | | pluginMgr 为 nil 调用 ResolvePreview | 返回 success:false,不 panic | | TabRegistry.Register 同一 TabKey 两次 | 返回冲突错误 | | PreviewRegistry.Resolve 无匹配文件 | 返回 nil, "" | | Manager.Shutdown 无插件注册 | 正常返回 nil |