DSH plugin 界面开发:设置卡片怎么注册、Host 半与浏览器半怎么配合、client 打包怎么写

简介: DeepSeek Harness(DSH)插件界面开发:一个包里写 Host 半(用 settings.installSection 注册命名空间)与浏览器半(向 settings.plugin.item 槽注册卡片),用 ctx.settingsScope 读写,并按 dsh.client 打包 ./client。

DeepSeek Harness(DSH)插件界面开发:一个包里写 Host 半(用 settings.installSection 注册命名空间)与浏览器半(向 settings.plugin.item 槽注册卡片),用 ctx.settingsScope 读写,并按 dsh.client 打包 ./client。

本文转自 DSH Plugin Hub 插件市场


DSH plugin 的界面开发不是「写个前端页面」,而是在同一个包里写两半代码:Host 半用 ctx.settings.installSection() 注册一个设置命名空间,浏览器半向 settings.plugin.item 槽注册一张卡片;两半靠同一个命名空间自动配对,无需改动宿主仓库。 无论叫 DSH插件 还是 DeepSeek插件,界面开发的这套两半结构完全一致。

DSH plugin 界面开发的两半结构:一个包,两个入口

设置页由 Host 半与浏览器半组成,缺一半卡片不会出现。 官方 Cookbook 的原话是:Host 服务每个已注册的设置命名空间,「Plugins」区按卡片编辑的命名空间给它们配对,两半都在一个包里——Host 半在 src/,浏览器半在 src/client/,通过 exports['./client'] 导出并用 dsh.client 声明(来源)。

my-plugin/
├── src/index.ts          # Host 半:注册命名空间
├── src/client/index.tsx  # 浏览器半:注册卡片
└── package.json          # exports['./client'] + dsh.client

配对键只有一个:命名空间。 建议把它写成常量(如 MY_PLUGIN_NS = 'my-plugin'),两半引用同一个常量,避免拼写漂移导致「卡片没出现」。

DSH plugin 的 Host 半:注册设置命名空间

已有 cordis.yml 条目的插件走 ctx.settings.installSection(),它会把条目分层放在用户文档之下,并且在没有设置提供方挂载时依然工作。 官方给出的宿主半写法如下:

import type {
    Context } from '@deepseek-ai/cordis'
import type {
   } from '@deepseek-ai/dsh-settings'
import z from '@deepseek-ai/schemastery'

export const MY_PLUGIN_NS = 'my-plugin'

export interface Config {
   
  endpoint?: string
  retries?: number
}

export const Config: z<Config> = z.object({
   
  endpoint: z.string(),
  retries: z.number().step(1).min(0).default(3),
})

export function apply(ctx: Context, config: Config) {
   
  let source = () => config
  ctx.inject(['settings'], (settingsCtx) => {
   
    settingsCtx.settings.installSection(ctx, MY_PLUGIN_NS, Config, config, {
   
      // schema 表达不了的约束:拒绝这次写入,而不是留到下次使用才报错。
      validate: value => void assertReachable(value.endpoint),
      setSource: (current) => {
    source = current },
      onChange: () => {
    rebuildFromSettings(source()) },
    })
  })
}

两个容易忽略的声明:给字段加 role('secret') 会让它的值不出现在任何响应里(卡片要么把它写进 update/mutate 载荷,要么通过 credentials 域引用凭据);applies: 'restart' 告诉配置界面「拥有者要到下次启动才真正生效这次变更」。

DSH plugin 的浏览器半:把卡片挂进槽位

卡片注册进 settings.plugin.item 槽,key 必须与 Host 半的命名空间一致。 官方示例:

import type {
    Context as ClientContext } from '@deepseek-ai/cordis'
// 仅类型导入:该槽位的声明。跨插件协作一律走 cordis 服务,
// 值导入会被 client 的 bundle-purity 关卡拦下。
import type {
   } from '@deepseek-ai/dsh-client-ui-settings-plugins/client'

export const inject = ['slots', 'locale', 'connection', 'remote', 'settingsScope']

export function apply(ctx: ClientContext): void {
   
  const card = new MyPluginCardController(ctx.settingsScope.bind({
    namespace: MY_PLUGIN_NS }))
  ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({
   
    name: 'settings.plugin.item',
    key: MY_PLUGIN_NS,
    locale: 'settings.myPlugin',
    inject: () => card.inject(),
  }, MyPluginCard))
}

卡片拥有自己内部的一切:外观、控件、文案。注意上面那行 import type {}——跨插件只能用类型导入,值导入会被 bundle-purity 关卡拒绝。

DSH plugin 配置读写语义:value / base / user 三层

作用域快照携带表单需要的三层信息,判断「是否被覆盖」看的是键的存在性而不是值。(来源)

层 含义 用途
value 解析后的生效值 表单回显
base 组合层 展示「默认来自哪里」
user 原始用户层 键存在 = 该字段被用户覆盖

写操作用 scope.set(field, value) 存单个字段,scope.unset(field) 把它清回组合层。每次写入都用读到的 revision 做栅栏——这能避免两个设置面板同时修改时互相覆盖。

DSH plugin 界面显示规则与打包要求

显示规则很直接:Host 服务该键且卡片注册了该键才渲染;Host 没服务就整张卡片不出现;Host 服务了但没有卡片认领,则什么都不渲染——这正是 ui-theme、permission、llm-* 这些命名空间不出现在该标签页的原因。卡片顺序等于注册顺序,带 key 的条目不能自己声明 order。

打包三条硬要求(来源):

  1. package.json 用 exports['./client'] 暴露浏览器半,并声明 dsh.client(含 platform 与它依赖的 client 包);
  2. bundle 必须是加载器期望的 lazy-CJS 工厂产物——仓库外没有公开 preset,需要自行复现同样的输出格式;
  3. 不能跨插件值导入:卡片要自带外观与暂存模型,自己拥有暂存与 revision 栅栏。

只要 cordis.yml 挂上这个插件,它就出现在页面上,无需重建 Web 应用——因为客户端模块系统是扫描已启用条目、按 dsh.client 服务构建产物的。

DSH plugin 界面开发自检与下一步

发布前过一遍:

  1. 命名空间常量是否两半共用;
  2. Host 半是否处理了 validate(schema 表达不了的约束)、setSource、onChange;
  3. 敏感字段是否加了 role('secret'),需要在下次启动才生效的是否标了 applies: 'restart';
  4. 卡片是否只用类型导入跨插件;
  5. exports['./client'] 与 dsh.client 是否齐备,bundle 是否为 lazy-CJS 工厂产物。

工具调用的卡片呈现是另一条线(presentCall / presentResult,且必须是纯函数),见 怎么写工具插件。界面之外的配置声明见 插件配置怎么用;打包与发布见 打包成 bundle 与 发布到插件中心。


常见问题

DSH plugin 界面开发为什么一定要写两半代码?

DSH plugin 的设置页由 Host 半与浏览器半共同构成:Host 半注册命名空间并决定服务哪些配置键,浏览器半注册卡片并决定怎么渲染。两半靠命名空间自动配对——「Plugins」区按卡片编辑的命名空间给它们配对,所以你只要在一个包的 src/ 与 src/client/ 里各写一半即可,无需改动宿主仓库(来源:官方 Cookbook「添加设置卡片」)。

DSH plugin 的 Host 半怎么注册设置命名空间?

DSH plugin 的 Host 半用 ctx.settings.installSection() 注册设置命名空间:传入插件上下文、命名空间常量、Config schema、当前配置与 { validate, setSource, onChange }。判断标准是「这个插件是否已有 cordis.yml 条目」——已有条目的消费方走 installSection 更稳,它会把条目分层放在用户文档之下,并且在没有设置提供方挂载时依然工作(来源:官方 Cookbook「添加设置卡片」)。

DSH plugin 的浏览器半怎么把卡片挂到设置页?

DSH plugin 的浏览器半把卡片注册进 settings.plugin.item 槽:用 ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({ name, key, locale, inject }, Card)),其中 key 必须是 Host 半注册的同一个命名空间。卡片内部通过 ctx.settingsScope.bind({ namespace }) 拿到作用域来读写配置(来源:官方 Cookbook「添加设置卡片」)。

ctx.settingsScope 的快照里 value、base、user 分别是什么?

DSH plugin 设置卡片的作用域快照携带表单需要的三层信息:value 是解析后的生效值、base 是组合层、user 是原始用户层。判断某个字段是否被用户覆盖,看的是 user 里那个键的存在性而不是它的值;scope.set(field, value) 写入单个字段,scope.unset(field) 把它清回组合层(来源:官方 Cookbook「添加设置卡片」)。

DSH plugin 发布浏览器半时对打包有什么硬要求?

DSH plugin 发布浏览器半时对打包有三条硬要求:① package.json 用 exports['./client'] 暴露浏览器半并声明 dsh.client;② bundle 必须是加载器期望的 lazy-CJS 工厂产物;③ 不能跨插件做值导入——client 的 bundle-purity 关卡会拒绝跨插件的 value import,所以卡片要自带自己的外观与暂存模型。仓库内用共享 preset 的 clientBundle(),仓库外需自行复现同样的输出格式(来源:官方 Cookbook「添加设置卡片」)。


本文转自 DSH Plugin Hub 插件市场,版权归属 DSH Plugin Hub 插件市场。

分类:插件开发

原文地址:https://dsh-plugin.org/zh/tutorials/develop-plugin-ui

首页:DSH Plugin Hub

相关文章
|
12天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
7928 15
|
10天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1739 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
11天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
1736 11
|
9天前
|
人工智能 编解码 并行计算
MiniMax-H3 一键整合包技术文档:8G 显存运行 AI 漫剧制作 —— 角色替换 / 动作迁移 / 文图生视频部署与调参指南
MiniMax H3 是 MiniMax 开源的全模态视频生成模型,支持文/图/音/视多条件输入,输出最高2K、15秒带双声道音频视频。本文档详述其Int8量化版在8GB显存下的本地一键部署、三段式工作流(EDIT/REPLACE/CONTINUE)、参数调优及常见问题排查。(239字)
|
24天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3789 10
|
19天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1995 1