docs: README 指向外部插件指南与 AGENTS.md,设计文档补 v0.12.0 扩展记录
- README/README_EN:服务化小节与特性清单同时链接 AGENTS.md 与 docs/external-plugin-guide.md;安装示例版本 0.10.3 → 0.11.0(npm 最新已发布版) - docs/plans/2026-08-11-service-registry-design.md:追加 §18 v0.12.0 基座化扩展记录(类型导出/零 Node 依赖/新方法/新字段/设置 seam/load signal/测试) - docs/plans/2026-08-11-declarative-sidebar-settings-design.md:追加 §8 设置 seam 开放记录(pluginSettings 持久化/pluginToggles/render/SettingsBody) - docs/external-plugin-guide.md:修正纯度门交叉引用(§9 → §10)
This commit is contained in:
@@ -32,7 +32,7 @@ better-sidebar 从 v0.4.0 起把自己改造成一个**注册表服务**:
|
||||
import type {} from 'dsh-better-sidebar' // 触发 declare module 'cordis' 类型合并
|
||||
```
|
||||
|
||||
这个 **type-only import** 在编译时被擦除,不产生任何运行时依赖,也不会触发构建纯度门(见 §9)。
|
||||
这个 **type-only import** 在编译时被擦除,不产生任何运行时依赖,也不会触发构建纯度门(见 §10)。
|
||||
|
||||
### 2.2 package.json 声明
|
||||
|
||||
|
||||
@@ -135,3 +135,14 @@ isViewerEnabled(id: string): boolean
|
||||
4. **清单排序**:tabs 按 `hidden` 置后 + `order` 升序(editor/diff 殿后);viewers 按 priority 降序(code 兜底最后)。
|
||||
5. **开关改为卡片点击(v0.4.1 追加)**:清单项与嵌套相关设置、`openByDefault` 全部从"复选框行"改为**可点击卡片**——`<button aria-pressed>`,整卡即开关,视觉状态即状态(启用 = 品牌描边 + 交互选中填充 + `IconCheckOutline16` 勾选徽标;禁用 = 中性 hairline + 文字降级)。嵌套相关设置渲染为更小的缩进卡片;宽度输入保持原生设置行(它是数值不是开关)。设置导航齿轮图标为宿主 shell 硬编码(`navIcon` 按 section id 映射,无插件注入点),用户选择不改宿主,保持现状。
|
||||
6. **小卡片响应式网格 + 二级设置弹窗(v0.4.1 再追加)**:清单项改为**小卡片**,置于 `repeat(auto-fill, minmax(148px, 1fr))` 响应式网格(一行自适应多个,随宽度换行);卡片结构 = 顶行(图标 + 标题省略 + **勾选徽标钉在最右端**)+ 类型/扩展名描述行(省略号截断,`title` 属性给出完整值)。声明了 `settings.toggles` 的卡片右下角渲染**齿轮角标按钮**(`IconSettingsOutline16`,仅父级启用时显示),点击打开**原生 `Modal` 弹窗**,内含 DSH 原生设置行(标题/描述 + 品牌强调原生复选框 + hairline 分隔,末行去分隔线)——二级设置不再内嵌于网格。实现细节:Modal 采用条件挂载(`settingsFor !== null && <Modal open …>`),因为 Modal 原语无条件调用 hooks,常闭挂载在测试的 dual-react(react 18.2 server / 18.3 bundled)分裂环境下会崩;弹窗行体抽成 `FeatureSettingsRows` 供 renderToString 直测。
|
||||
|
||||
---
|
||||
|
||||
## 8. v0.12.0 设置 seam 开放记录(2026-08-14,feat/plugin-api-v012)
|
||||
|
||||
设计正文「key 必须是宿主 PrefsSchema 的字段」的限制在 v0.12.0 被打开(纯增量,`toggles` 的宿主 key 语义不变):
|
||||
|
||||
- **持久化**:`SidebarPrefs` 增加 `pluginSettings: Record<string, Record<string, unknown>>`(开放嵌套 map,schema `z.dict(z.dict(z.any())).default({})`,按 descriptor id 分桶)——外部插件的自有设置不再需要宿主 schema 字段、不再被 settings seam 丢弃。`parsePrefs` 增加 `pluginSettingsMapOf` 校验(非对象整体回退 `{}`)。
|
||||
- **声明**:`SidebarSettingsDeclaration` 增加 `pluginToggles`(声明式行,控件同 toggles 的 switch/text/number,值须 JSON 可序列化)与 `render?: (props: SidebarSettingsRenderProps) => ReactNode`(自定义面板:store/service/prefs/pluginSettings/updatePluginSetting/close;抛错被吞并显示内联错误)。
|
||||
- **渲染**:齿轮弹窗体抽为 `SettingsBody`(`render` 存在时优先,否则 toggles 行 + pluginToggles 行,后者把 pluginSettings 投影到 prefs 面复用 `FeatureSettingsRows`);`settingsFor` 状态从 `TabDescriptor | null` 扩为 `TabDescriptor | FileViewerDescriptor | null`——viewer 卡片 v0.12.0 起同样有齿轮设置弹窗(§4.6 原仅 tab)。
|
||||
- **向后兼容**:旧设置文档无 `pluginSettings` 字段 → schema default `{}`;`toggles` 行为与 v0.11.0 完全一致。
|
||||
|
||||
@@ -414,3 +414,19 @@ export function apply(ctx: Context): void {
|
||||
### 17.10 测试
|
||||
|
||||
新增 `tests/builtins.spec.ts`(内置注册清单)、`tests/orphaned-tab.spec.tsx`(sanitize 保留未注册类型 + 占位渲染)、`tests/editor-load.spec.ts`(策略分发纯函数);`tests/browser-globals.ts` 为拉入 xterm/CodeMirror 的 spec 提供模块求值期浏览器全局 mock。`matchFileViewer` 相关断言按 17.3 语义重写。
|
||||
|
||||
---
|
||||
|
||||
## 18. v0.12.0 基座化扩展记录(2026-08-14,feat/plugin-api-v012)
|
||||
|
||||
§5 的服务接口在 v0.12.0 做了**纯增量**扩展(无任何签名删除 / 语义变更,向上兼容),全部记录于此,文档以本节为准:
|
||||
|
||||
- **类型导出补齐**:`./client/service` 入口 re-export 公共状态词汇——`SidebarTab` / `SidebarState` / `SidebarStore` / `SidebarSnapshot` / `SidebarDiffRef` / `TabType` / `SessionScope` / `SidebarPrefs` / `OpenTabSeed` / `SidebarSettingsRenderProps`。此前消费者无法命名这些类型(TS2459),只能靠推断。
|
||||
- **client 声明图零 Node 依赖**:`context-types.ts` 的 `SidebarWebRoute` / `SidebarWebUpgradeRoute` 改用结构镜像类型(`SidebarHttpRequest` / `SidebarHttpResponse` / `SidebarUpgradeSocket` / `SidebarUpgradeHead`),宿主在 ws 边界显式转型(`src/index.ts` 两处)。外部消费插件无需 `@types/node`、`skipLibCheck: false` 也能编译(`scripts/check-consumer-types.sh` 双层校验守护)。
|
||||
- **新服务方法**:`version` / `features`(单调能力清单,只增不删);`getSnapshot` / `subscribeState`(状态订阅,委托 store);`updateTab(tabId, patch)`(title/path/meta);`activateTab(tabId)`(跨树激活,tab 栏点击路径);`openFile(scope, path, title?)`(editor 打开,id 按路径派生与内置拦截一致);`openTab(seed, scope?)`(定向到指定 session:`SidebarStore.reduceFor` 加载/变更/持久化目标 session 而不切换 snapshot,UI 不扰动;scope 指向当前 session 时走原 reduce 路径保证 notify)。
|
||||
- **新 descriptor 字段**:`badge`(tab 角标:number 计数 99+ 封顶 / string 文本 / null 不显示,每次 tab 栏渲染调用,抛错吞掉);`onOpen` / `onActivate` / `onClose`(生命周期回调,service 路径派发——dedupe/id 安全网聚焦触发 onActivate 而非 onOpen;内置 diff 拆分与 agent 终端 reconcile 直接改 state 不触发,但只作用于内置类型;回调抛错只 console.error);`SidebarTab.meta`(JSON 可序列化自定义状态,`sanitizeNode` 宽松保留,跨刷新原样恢复)。
|
||||
- **设置 seam 开放**:`PrefsSchema` 增加 `pluginSettings: z.dict(z.dict(z.any())).default({})` 开放嵌套 map;`settings.pluginToggles`(插件自有声明式行)与 `settings.render`(自定义面板,props 见 §5)替代「自定义 key 被 seam 丢弃」的限制;viewer 卡片 v0.12.0 起同样有齿轮设置弹窗。
|
||||
- **`FileViewerDescriptor.load` 第三参 `signal?: AbortSignal`**:EditorHost 在卸载/重匹配时 abort(忽略 signal 的 load 照常工作)。
|
||||
- 测试:`tests/consumer-types.ts`(消费面编译门)、`tests/api-surface.spec.ts`(client 图零 node 依赖守护 + 能力常量)、`tests/service.spec.ts` 新增生命周期 / 定向打开 / updateTab / activateTab / openFile / meta 持久化用例、`tests/unit.spec.ts` 新增 `reduceFor` 与 sanitize meta 用例。
|
||||
|
||||
实现偏差:§5.1 的 `openTab(seed)` 单参签名保留为 `openTab(seed, scope?)` 的可选参数(非破坏);`SidebarSnapshot` 类型 re-export 自 `./client/service` 而非新建独立文件。
|
||||
|
||||
Reference in New Issue
Block a user