A plugin that registered a settings namespace could not reach the browser configuration page: the api-proxy filtered every read and gated every write through two hardcoded namespace lists, and the plugin configuration section rendered an unordered list of cards carrying an opaque id rather than the namespace they edit. Both gates lived in this repository, so a user-authored plugin was configurable only by hand-editing settings.yaml. The proxy now serves whatever ctx.settings.describe() returns and adds no boundary of its own; a name no registration answers folds into the seam's own settings-rejected, and the settings-not-exposed code retires. The settings seam is untouched: which client may read a namespace, and which page renders it, are facts about consumers. settings.plugin.item becomes a keyed slot whose key is the namespace a card edits, following tool.call.toolview. The section reads describe once and dispatches the intersection of the slot ledger and the served set, so a namespace another surface owns renders nothing without declaring anything, and a card for an uncomposed plugin is never dispatched.
5.0 KiB
dsh-client-ui-plugin-config
English | 中文
插件设置分区:每个配置由用户拥有的 Host 插件占一张可展开卡片。卡片展示插件名称及其管辖范围;就地展开后是绑定到该插件 settings 命名空间的手写控件,每个字段标注用户是否覆盖过它,并提供重置回部署组装值的入口。
这里会出现什么
本分区读取 Host 服务了哪些 settings 命名空间,并为每个命名空间派发一个 slot 键,因此渲染出来的是两份账本的交集:存活 Host 插件注册的命名空间,以及注册在这些键上的卡片。被服务却无人认领的命名空间什么都不渲染——它归别的界面所有,或本部署没有为它提供浏览器半侧;而命名空间未被本部署服务的卡片根本不会被派发,因此未组装的插件不留任何痕迹,也不会挡住那行空态文案。卡片按自身注册的顺序出现,而非 Host 描述其命名空间的顺序——插件激活时序会让后者在不同次启动之间变化。空态文案要等 Host 的第一次答复,因此一次尚未答复的读取绝不会被读成"本部署没有可配置的插件"。
本包自带的卡片覆盖 shell 执行器(bash)、agent 循环的工具调用并行度(agent-loop)以及 DeepSeek 搜索提供方(web-search-deepseek)。
扩展点
本分区声明了根级 keyed slot settings.plugin.item,其键就是卡片所编辑的 settings 命名空间。带浏览器半侧的插件把自己的卡片注册在自己的命名空间上,并拥有它的全部——外观、控件与文案;本包不提供任何未被交给它的表单,也从不知道某个命名空间意味着什么。以命名空间为键,正是在本仓库之外分发的插件能出现在这里的原因:它在 Host 上注册命名空间、在浏览器里注册卡片,由本分区把两者配对。
写入
卡片暂存用户输入,只有用户保存时才写入。每个控件渲染的都是暂存文本,因此屏幕上所见即保存后所存;放弃修改丢弃这些草稿,持有未保存修改的卡片即使收起也会在标题上标明。重置暂存的是组装默认值而非立即写入;字段不接受的草稿会阻塞保存,而不是被丢弃。
保存时,每个暂存字段都通过客户端 settings scope 写入,该 scope 用读取时的命名空间 revision 为每次写入设栅,因此已与文档脱节的表单会被拒绝,而不是覆盖并发变更。某个值是否被接受只有 Host 说了算——schema 表达不了的约束归它的校验器所有——因此卡片在写入后回读分节,报告没有落盘的保存,并保留这些草稿供用户修改。
密钥也可能从别的表层写入——模型页寻址的是同一个引用——而那不改变任何 settings 分节,因此卡片会在转发来的 credentials/updated 事件报告它所关注的引用时重读。
字段是否被覆盖,取决于它是否出现在原始用户层中,而非取决于它的值;重置会清除该字段,使其重新继承组装层。secret 角色的字段绝不搭乘响应,因此密钥控件初始为空、只报告是否已配置,并经由 credentials 领域而非 settings 分节写入;空草稿不写入任何东西,保留已存密钥。
模型体验
无。该分区渲染浏览器配置 UI;它写入的值只通过拥有这些值的插件到达模型,而这些效应各由其拥有方的包记录。
KV Cache 影响
无;该包既不组装也不发送提供方请求。
已知限制与暂缓事项
- 只有宿主平面的插件会出现——由 agent preset 挂载的插件把配置内联在该 preset 的
agent.cordis.yml中,且根本无法注册 settings 命名空间(同一 preset 挂载第二个会话时会因重复注册而失败),因此本分区不会列出它。编辑那些值仍是 preset 编辑器的职责。 - 卡片仍然需要一份浏览器 bundle——浏览器半侧必须是按客户端模块系统的 lazy-CJS factory 格式构建的
dsh.client包,而产出它的clientBundle预设位于packages/client/tsdown.client.ts,并非已发布的包,因此本仓库之外的插件得自行复刻该构建。bundle 纯净度门禁同时禁止以值的形式导入本包的卡片外观与表单模型,所以这样的卡片要自行拥有暂存与 revision 设栅。 - 被服务的命名空间只在两种信号上重读——协议通告的是 settings 文档提交与连接重置,而非注册行为,因此在本分区读取之后才被其拥有方注册的命名空间,要等下一次文档提交或重连才会加入列表。
- shell 卡片跟随被组装的执行器——POSIX 与 PowerShell 两个执行器家族共用
bash命名空间,因为一个宿主只组装其中之一,所以被服务的 schema 随平台不同(PowerShell 多出pwshPath),尽管卡片在两者下编辑的都是同样两个字段;而两者都不组装的部署不会显示这张卡片。