DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

yankess233 /

yankess233/rea-switch

Verified

A security-hardened local DSH composer chip that toggles REA MCP tools, masks inherited schemas, shadows prompt sections, and reports token cost.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@17cf8c48

REA Switch

DSH Node License Tests

在 DSH 输入框左侧放一个紧凑的 REA 开关:一键开关 REA MCP 工具面,关闭时立即拦截执行、从 live agent 的 schema 中移除继承工具、shadow 对应 MCP 提示词,并在 chip 上显示被隐藏工具的数量与 token 估算。

项目 值
插件包 @local/rea-switch
版本 1.3.0
宿主 DSH 0.2.2-rc.1(engines.dsh:>=0.2.1-rc.5 <0.3.0-0)
Node >=24.9.0
默认 MCP server rea
许可证 MIT

为什么

REA 这类逆向工程 MCP server 往往一次暴露几百个工具。它们的 JSON Schema 会随每次模型请求一起发送,占用可观的上下文与 token 预算;而在不调试二进制的普通对话里,这些工具通常用不上。

REA Switch 把“这次对话是否需要 REA”变成一个可见、可点击的本机偏好:

  • 不需要时一键关闭,下一次工具调用立即生效,不用重启 DSH;
  • 关闭后同时处理执行层、工具列表和提示词三层,减少模型看到无关工具与说明的机会;
  • chip 直接显示关闭后隐藏了多少工具、约省下多少 token;
  • 状态保存在本机文件,重启后延续上次选择;
  • 状态文件损坏、不可读、版本不符等异常按关闭处理;首次运行(文件不存在)默认开启,保留原首启体验。

功能

  • 输入框 chip:注册在 conversation.input.left,位于权限/计划 chip 旁边;点击切换,支持键盘焦点与 aria-pressed。
  • 执行层 guard:关闭时,全局 tools.guard 拦截 mcp__<server>__*,以及 list_mcp_resources、list_mcp_resource_templates、read_mcp_resource 中指向该 server 的调用;参数缺失或指向不明时保守拦截。
  • 按 agent mask:通过 tools.restrict({ deny }) 从每个 live agent 的可见 schema 中移除继承的 REA 工具。
  • 提示词 shadow:注册空的 mcp:<server> section 遮蔽 server 描述;重写 mcp-resource-servers 列表并保留其他 server;追加一条关闭提示。
  • 真实状态:agent 自己 scope 注册的工具落在 host mask 的覆盖范围之外,插件用 tools.definitions(agent)(不可用时回退 schemas(agent))检测并把 mode 标为 partial,不会谎报“全部隐藏”。
  • token 估算:toolBytes 是当前 REA schema 投影的 JSON UTF-8 字节数,approxTokens = round(bytes / 4);4 字节/token 只是近似。统计只覆盖全局注册表投影,agent scope 的 REA 工具不计入 toolBytes,但仍计入 visible。
  • 持久化:默认 <DSH_HOME>/rea-switch.state.json,原子写入;损坏、不可读、未知版本、符号链接、特殊文件或超大文件一律按关闭处理。
  • 本机控制接口:仅 loopback 绑定时注册,JSON-only、同源校验、Host allowlist、Host 端口一致性、代理头拒绝、1024 字节请求体上限。
  • 中英双语:中文为主,英文界面按页面/浏览器语言回退。

快速开始

前置条件

  • DSH 0.2.2-rc.1(桌面版或本机 Web GUI);
  • Node.js >=24.9.0;
  • 一个可用的 REA MCP server,默认注册名为 rea(自定义名称见配置);
  • 插件源码位于 <WORKSPACE>/plugins/rea-switch。

方式一:link 安装(开发工作区)

在 DSH profile 的 package.json 中加入本地依赖,路径替换为实际工作区:

{
  "dependencies": {
    "@local/rea-switch": "link:<WORKSPACE>/plugins/rea-switch"
  }
}

然后在 profile 目录执行:

pnpm install

路径包含空格或中文时,link: 仍然可用;工作区移动或重命名后需要重新安装。

方式二:tarball 安装

cd <WORKSPACE>/plugins/rea-switch
pnpm pack

把生成的 tarball 放进 profile 依赖:

{
  "dependencies": {
    "@local/rea-switch": "file:C:/path/to/local-rea-switch-1.3.0.tgz"
  }
}
pnpm install

tarball 包含运行时文件与 README、LICENSE、CHANGELOG、SECURITY、ARCHITECTURE;测试与 .gitignore 留在仓库中。

包标记 private: true 是本地插件的有意设置,用来避免误发布到 npm。要正式发布时,先改成公开包名(例如 rea-switch)并移除 private 字段,再核对 files 与 exports。

启用插件

插件通过 cordis.patch.yml 插入:

- insert:
    - id: rea-switch
      name: '@local/rea-switch'

需要自定义 server 名称或状态文件路径时:

- insert:
    - id: rea-switch
      name: '@local/rea-switch'
      config:
        serverName: rea
        stateFile: C:/path/to/rea-switch.state.json

重新加载

保存配置后重新加载 DSH profile,或重启 DSH,然后刷新 Web 页面。chip 出现在已有会话的输入框左侧;新会话的 Hero 空态可能暂时没有 chip,进入一则已有对话即可看到。

验证控制接口(端口替换为当前 DSH Web 端口):

curl.exe -s http://127.0.0.1:<PORT>/dsh-local/rea-switch/state

使用

点击 chip 即切换。开启时 chip 显示绿点与“开”,关闭时显示空心点与“关”,并给出隐藏工具数量。

chip 状态 data-state 含义 典型文案
读取中 loading 首次 GET /state 尚未返回;保持中性色,不沿用上次的绿色 正在读取 REA 开关状态
已开启 on enabled: true REA 工具已开启,点击关闭 · 每次请求约 +19.4 万 tokens
已关闭 off 关闭且 mask 正常(mode: restrict) REA 工具已关闭,点击开启 · 已隐藏 207 个工具,约 19.4 万 tokens
离线 off 关闭、有 live agent,但注册表里没有 REA 工具(mode: offline) REA 未连接或无可用工具
部分隐藏 off + data-degraded=true mode: partial 或 guard,或注册表漂移(drift: true);执行层仍拦截 REA 已关闭,但部分工具仍可见,执行层已拦截
不可用 error 控制路由未注册、网络失败或响应异常;点击重试 REA 开关不可用,点击重试

切换期间 chip 进入 busy/pending:按钮禁用,pending 时圆点脉冲;关闭完成前不显示“全部隐藏”的终态文案。

mode 的完整语义:

mode 条件 含义
idle 开启,或没有 live agent 没有需要展示的关闭态 mask
offline 关闭、有 agent、注册表没有 REA 工具且 visible 为 0 REA server 未连接或未注册工具
restrict 关闭,所有 live agent 都安装了 mask 工具面已隐藏
partial 关闭,部分工具仍可见,或 settle() 发现注册表漂移 执行层仍拦截,但列表未完全清空
guard 关闭,没有任何 agent 成功安装 mask 只剩全局 guard 在执行层拦截

partial 和 guard 都是真实状态,不代表开关失效:执行层的 guard 与 mask 相互独立,guard 每次调用都读取当前开关值。

安全模型

[!WARNING] REA Switch 是本机偏好开关,不是访问控制,也不是权限边界。 关闭它只改变模型看到的工具面与提示词,并拦截经过 DSH 工具调度器的调用;它不停止 MCP server 进程,也不阻止本机其他进程直接访问该 server。

  • MCP 进程仍在运行:关闭开关不会卸载 server,也不会撤销其凭据或网络访问。
  • 旁路始终存在:带 pwsh、PTC 或 shell 的 preset 可以直接调用 rea-agents、MCP JSON-RPC 或其他本地接口;需要硬隔离时,应在 preset、OS 账户、网络或 MCP 配置层限制。
  • 本机进程边界:控制路由没有 API 凭据。同一台机器上的任意进程都可以请求 loopback 端口;这是本机偏好接口的设计边界。
  • 多进程不实时同步:同一进程内多个页面通过 BroadcastChannel 与焦点事件刷新;不同 DSH 进程只保证状态文件每次是完整 JSON,最后写入者胜。
  • 反向代理:把 DSH Web 暴露到非 loopback 地址时,必须在代理层拦截 /dsh-local/rea-switch,并启用认证。插件在非 loopback 绑定下不注册该路由,还会拒绝带 forwarded、via、x-forwarded-*、x-real-ip 的请求;会剥离这些头的代理仍必须自行拦截该路径。这属于纵深防御,不是远程部署的访问控制方案。
  • 无 secret:状态文件只保存 { version, enabled },不保存 token、cookie 或 server 凭据。

控制路由的防护:

  • 仅在 webServer.host 明确为 loopback 时注册:127.0.0.0/8、::1、IPv4-mapped ::ffff:127.*、localhost;缺失、空白或解析失败的 bind 值按非 loopback 处理,路由不注册。
  • 每个请求的 Host authority 必须是 loopback,且其端口必须与当前 webServer.port 一致(端口可读时);Origin 存在时必须与 Host 一致;Sec-Fetch-Site 只接受 same-origin 或 none。这可以挡住 DNS rebinding 与跨站表单。
  • 带 forwarded、via、x-forwarded-for、x-forwarded-host、x-forwarded-proto、x-real-ip 任一请求头的访问按代理流量处理,返回 403;这能挡住把 loopback 端口转成远程入口的常见代理配置。
  • POST /set 只接受 application/json,请求体上限 1024 字节;不返回 CORS 头;响应带 x-content-type-options: nosniff;500 只返回通用错误文本。
  • 访问日志只记录 method、action、status,不记录请求体。
  • 状态文件要求 version: 1,对符号链接、特殊文件与超过 64 KiB 的文件按关闭处理;写入使用不可预测名字的 wx 临时文件、0600 权限与 rename。

更完整的威胁模型、部署检查清单与已知边界见 SECURITY.md。

工作原理

flowchart LR
  Chip["composer chip<br/>conversation.input.left"] -->|"GET /state"| Route["loopback HTTP route<br/>/dsh-local/rea-switch"]
  Chip -->|"POST /set {enabled}"| Route
  Route --> State["内存 flag +<br/>rea-switch.state.json"]
  State --> Guard["全局 tools.guard<br/>拦截 mcp__server__* 与 3 个资源工具"]
  State --> Mask["每个 live agent<br/>tools.restrict({ deny })"]
  State --> Prompt["prompt shadow<br/>mcp:server / mcp-resource-servers<br/>+ 关闭提示"]
  Guard --> Model["下一次模型工具调用"]
  Mask --> Model
  Prompt --> Model

三层职责:

  1. Guard(权威、即时):注册一次,读取 state.enabled;关闭时拦截目标工具。即使 mask 尚未安装、安装失败或注册表正在变化,执行层仍然拦截。
  2. Mask(按 agent、尽力):对每个 live agent 调用 tools.restrict({ deny }),从继承工具中移除 REA 名称;tools.view(agent).restrictableNames 预过滤不可 mask 的名称,失败时从错误信息解析未知名称并保留部分 mask。
  3. Prompt(按 agent、尽力):空 mcp:<server> 覆盖 server 描述;mcp-resource-servers 现算列表并剔除目标 server;追加 rea-switch:disabled:<server> 提示。systemPrompt 或 mcpResources 取不到时只损失对应提示,guard 与 mask 继续工作。

一次关闭会启动一个 arming pass:每个 live agent 在独立 macrotask 中处理,避免一次性发布大量 tools/change 造成长任务;pass 结束后 settle() 再读一次注册表,发现漂移则指数退避重试,最多 5 次。

HTTP API

控制路由前缀:/dsh-local/rea-switch。只在 loopback 绑定时存在。

方法 路径 请求体 成功 主要错误
GET / HEAD /state 无 200 + snapshot JSON 403 跨站;405 方法错误;路由未注册时由宿主返回 404
POST /set {"enabled": true|false} 200 + 新 snapshot 400 JSON/字段错误;403 跨站;405 方法错误;413 超过 1024 字节;415 非 JSON;500 内部错误

约束:

  • Host 必须是 loopback authority,端口与当前 webServer.port 一致(端口可读时);Origin 若存在必须与之同源;Sec-Fetch-Site 只接受 same-origin / none。
  • 带 forwarded、via、x-forwarded-for、x-forwarded-host、x-forwarded-proto、x-real-ip 的请求返回 403;代理需要自行拦截该路径。
  • POST 的 Content-Type 必须以 application/json 开头;body 必须是对象,且 enabled 必须是布尔值,"true"、1 等一律 400。
  • 响应统一 application/json; charset=utf-8、cache-control: no-store、x-content-type-options: nosniff;不发送 CORS 头。
  • state 的 HEAD 与 GET 状态码、头一致,不返回 body。

GET /state 示例(数值随实际 REA 工具集变化):

{
  "enabled": false,
  "prefix": "mcp__rea__",
  "server": "rea",
  "tools": 207,
  "toolBytes": 775022,
  "approxTokens": 193756,
  "agents": 2,
  "visible": 0,
  "mode": "restrict",
  "drift": false,
  "pending": false,
  "persisted": true,
  "note": ""
}

字段说明:

字段 类型 含义
enabled boolean 当前开关值
prefix string mcp__<serverName>__
server string 当前 server 名
tools number 注册表中匹配前缀的工具数
toolBytes number 匹配工具 schema 投影的 JSON UTF-8 字节数
approxTokens number round(toolBytes / 4),近似值
agents number 已 attach 的 live agent 数
visible number 各 agent 仍可见的 REA 工具数之和
mode string idle / offline / restrict / partial / guard
drift boolean 最近一次 settle() 是否发现注册表与 mask 不一致
pending boolean arming pass 是否仍在运行或排队
persisted boolean 最近一次写入是否成功
note string 状态文件异常或不可写时的说明

写入示例:

curl.exe -X POST http://127.0.0.1:<PORT>/dsh-local/rea-switch/set `
  -H "content-type: application/json" `
  --data "{\"enabled\":false}"

非浏览器客户端可以省略 Origin,但 Host 仍必须是 loopback authority 且端口与监听端口一致;带 Host: evil.example 的请求即使 Origin 与 Host 相同也会返回 403,带 x-forwarded-* / forwarded / via 的请求同样按代理流量拒绝。

状态文件

默认路径:

<DSH_HOME>/rea-switch.state.json

DSH_HOME 解析规则与宿主一致:非空的 $DSH_HOME 优先(纯空白视为未设置),否则回退 ~/.dsh,最终归一化为绝对路径;支持 ~、~/、~\ 前缀。

默认是跨 profile 的全局开关:所有 profile 共享同一文件,最后写入者胜。需要按 profile 隔离时,用 config.stateFile 钉住路径:

- insert:
    - id: rea-switch
      name: '@local/rea-switch'
      config:
        stateFile: C:/path/to/profiles/desktop/rea-switch.state.json

文件格式:

{
  "version": 1,
  "enabled": true
}

读取语义:

情况 结果
文件不存在 首次运行,enabled: true
正常 JSON,enabled 为布尔值且 version 为 1 使用该值
JSON 损坏、不可读、enabled 非布尔值 enabled: false + note
version 缺失或不是 1 enabled: false + note
符号链接、目录、FIFO 等非普通文件 enabled: false + note
文件大于 64 KiB enabled: false + note

写入语义:

  • 使用 <file>.<pid>.<random>.tmp,以 wx 排他创建,0600 权限,写完后 rename 原子替换;
  • 目录按需递归创建;
  • 写入失败时返回 persisted: false,本次运行保留内存中的选择,并在 chip 的 title 中显示提示;
  • 状态文件只保存开关值,不保存任何凭据。

配置

apply(ctx, config) 读取两个可选字段:

字段 类型 默认值 说明
serverName string rea 同时决定工具前缀、guard 目标、prompt section 名、资源匹配与 chip 标签;须匹配 ^[A-Za-z0-9_-]{1,32}$
stateFile string <DSH_HOME>/rea-switch.state.json 钉住状态文件路径;支持 ~ 前缀

serverName 区分大小写,并与 MCP 工具前缀完全匹配。名称不符合 ^[A-Za-z0-9_-]{1,32}$ 时,插件记录 invalid serverName 警告并回退到 rea,避免 guard/mask 因错误前缀漏掉工具。cordis.patch.yml 不传 config 时使用 rea 与全局状态文件。

兼容性与已知限制

  • 宿主:在 DSH 0.2.2-rc.1 上验证;engines.dsh 允许 >=0.2.1-rc.5 <0.3.0-0。更老的宿主可能没有 tools.definitions(agent)、tools.view() 或 tools.schemas(),此时插件会降级并记录 warn。
  • Node:>=24.9.0。
  • serverName 白名单:名称须匹配 ^[A-Za-z0-9_-]{1,32}$;非法名称回退 rea 并记录警告。回退可以保证 guard/mask 仍覆盖默认前缀,但自定义 server 的工具不会被切换。
  • 仅本机 Web:非 loopback 绑定不注册控制路由;chip 仍会渲染,但请求得到 404 后进入 error 态。
  • 新会话 Hero 空态:可能没有输入框工具行,先进入已有会话再切换。
  • agent-owned 工具:per-agent/scoped 注册的 REA 工具不在 restrict() 的能力范围内,会保持可见并把 mode 置为 partial;执行层仍由 guard 拦截。它们计入 visible,但 toolBytes/approxTokens 只统计全局注册表投影,不包含这些工具。
  • prompt shadow 冲突:per-agent MCP server 可能已经拥有同名 mcp:<server> section;此时该 scope 的 prompt shadow 可能注册失败并记录 warn,notice 也可能缺失,执行层 guard 仍会拦截。
  • mask 漂移:注册表在 pass 期间变化时可能短暂出现 partial;settle() 会退避重试,tools/change 也会在 400 ms 防抖后重新 arm;mcpResources 延迟激活时,下一次 pass 会补注册资源列表 shadow。
  • token 估算:toolBytes 是精确的 schema JSON 字节数,approxTokens 按 4 字节/token 粗估;不同模型、语言与 JSON 结构下真实比例会变化。
  • 多进程:同源多页面通过 BroadcastChannel、focus、visibilitychange 刷新;跨进程依赖下一次 GET /state,没有实时订阅。
  • 极端并发下的旧快照:焦点/可见性触发的 GET 可能在一次切换 POST 之后返回旧值,chip 会在下一次刷新或 watch 时纠正;服务端状态以最终响应为准。
  • 资源列表内部结构:mcpResources.layers.merge(scope, pick) 是宿主内部契约;结构变化时资源列表 shadow 可能降级,但工具 guard 与 mask 不受影响。
  • 反向代理:远程部署必须在代理层拦截控制路由;插件会拒绝常见代理头与端口不匹配的请求,但会剥离这些头的代理仍须自行拦截该路径。
  • 路径移动:link: 依赖指向绝对路径,工作区移动后需要重新安装。
  • 开关不是权限边界:见安全模型。

项目结构

plugins/rea-switch/
├── index.js              # host half:状态、guard、mask、prompt、HTTP 路由
├── client.js             # client half:chip、样式、i18n、状态同步
├── cordis.patch.yml      # 插件插入声明
├── locale/
│   ├── zh.json           # 插件管理器元数据(中文)
│   └── en.json           # 插件管理器元数据(英文)
├── icon.svg              # 插件图标
├── test/
│   └── host.test.mjs     # 37 个 node:test 用例(host + client 渲染)
├── README.md
├── CHANGELOG.md
├── SECURITY.md
├── ARCHITECTURE.md
├── LICENSE
├── .gitignore
└── .gitattributes

npm tarball 包含 index.js、client.js、cordis.patch.yml、locale/*.json、icon.svg、README.md、LICENSE、CHANGELOG.md、SECURITY.md、ARCHITECTURE.md;test/ 与 .gitignore 留在仓库。

开发与测试

cd plugins/rea-switch
node --test

当前结果:37 个用例,36 通过,1 跳过(Windows 符号链接用例)。

  • 跳过的是 S3: a symlinked state file is refused before it is read:Windows 上创建符号链接需要管理员权限或开发者模式,测试环境缺少该权限时会 t.skip。这是环境相关跳过,不是失败。
  • 在允许创建符号链接的 Linux/macOS/Windows 环境会执行完整 37 项。
  • 新增 S5(非法 serverName 回退 rea)与 S6(mcpResources 延迟激活后补 prompt shadow);两者都覆盖本版本的行为边界。
  • 测试使用 Node 内置 node:test 与 assert/strict,无外部依赖;每个用例使用临时 DSH_HOME 或显式 stateFile,不会读写真实 profile。
  • index.js 的 __test 导出只用于测试确定性辅助函数,不属于运行时 API。
  • 打包检查:
npm pack --dry-run

涉及 host 契约的改动请同时更新 ARCHITECTURE.md 的 API 契约与测试映射。

故障排查

现象 排查
输入框没有 chip 确认插件已加载、cordis.patch.yml 已插入、profile 依赖已安装;新会话 Hero 空态先进入已有会话
chip 显示“开关不可用” 控制路由未注册或返回 404。检查 webServer.host 是否为 loopback;非 loopback 部署不会注册路由
浏览器请求返回 403 Host 不是 loopback、端口与 webServer.port 不一致、带代理头,或 Origin 与 Host 不一致;通过 127.0.0.1 / localhost 直连,并检查代理是否改写 Host 或添加 x-forwarded-*
POST /set 返回 415 Content-Type 必须是 application/json
POST /set 返回 413 请求体超过 1024 字节;只发送 {"enabled":true} 或 {"enabled":false}
POST /set 返回 400 enabled 必须是布尔值;检查是否发送了字符串或数字
关闭后仍有 REA 工具出现在列表 查看 mode 与 visible。partial 通常来自 agent-owned 工具、mask 失败或注册表漂移;执行层 guard 仍会拦截
状态重启后丢失 检查 persisted、note 与状态文件权限;确认 DSH_HOME 与 stateFile 指向预期位置,文件带 version: 1;版本缺失也会按关闭处理
切换后另一个窗口未变化 同源页面依赖 BroadcastChannel/焦点事件;跨 DSH 进程需等待下一次 GET /state
切换后工具前缀不匹配 检查 config.serverName 是否与 MCP server 注册名一致、大小写正确,并匹配 ^[A-Za-z0-9_-]{1,32}$;非法名称会回退 rea 并在日志中警告
升级后路由异常 重新加载 profile;热重载时旧 prefix 可能短暂占用路径,插件会在 150 ms 后重试一次注册

需要更多诊断信息时,查看 DSH 日志中的 rea-switch: 前缀:注册失败、prompt 服务缺失、mask 失败都会带 agent id 或原因记录,但不会记录请求体。

贡献

  1. 先读 ARCHITECTURE.md 的 invariants 与 API 契约,避免破坏 guard 的即时性。
  2. 行为改动附带 node:test 用例;涉及安全边界时同时更新 SECURITY.md。
  3. 文档使用占位路径(<WORKSPACE>、C:/path/to/...、~/.dsh/...),不要提交个人绝对路径、live 端口或本机状态文件。
  4. 提交前运行 node --test 与 npm pack --dry-run。
  5. 安全问题按 SECURITY.md 的渠道报告,不在公开 issue 中贴利用细节。

许可证

MIT © 2026 REA Switch contributors

English summary

REA Switch is a local DSH plugin that adds a compact chip to conversation.input.left. Clicking it toggles the REA MCP toolset for the current host:

  • a global tools.guard denies mcp__<server>__* and the three MCP resource tools aimed at that server on the next call;
  • every live agent gets a tools.restrict({ deny }) mask, an empty mcp:<server> prompt shadow, a filtered mcp-resource-servers list, and a short disabled notice;
  • the chip reports the number of hidden tools and an approximate token cost based on the JSON schema size (bytes / 4).

Modes idle, offline, restrict, partial, and guard describe how far the mask got; partial and guard still enforce through the guard. This is a local preference switch, not an access-control or permission boundary: the MCP process keeps running, local processes can call the loopback route, and shell/PTC tools can reach the server directly. The control route is registered only for an explicit loopback bind; requests need a loopback Host on the live listener port, no proxy headers, and a same-origin Origin/Sec-Fetch-Site. Bind DSH to loopback and block /dsh-local/rea-switch at any reverse proxy.

Install with a link: or packed tarball dependency, insert the plugin through cordis.patch.yml, reload the profile, and refresh the Web UI. Requires DSH 0.2.2-rc.1 (engine range >=0.2.1-rc.5 <0.3.0-0) and Node >=24.9.0. The package keeps private: true intentionally; rename it and remove that field before publishing to npm. Tests: cd plugins/rea-switch && node --test — 37 cases, 36 pass, 1 environment-dependent Windows symlink skip. Licensed MIT.

—/ 5

No ratings yet

Verified DSH bundle

Commit 17cf8c48f2d4

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout