🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

额度用量统计 Yinxe/dshp

DeepSeek Harness
Yinxe11 天前有提交已提供中文文档扫描:含敏感能力

DeepSeek Harness(DSH)插件 monorepo(pnpm + TypeScript)

34.8/100
综合分
7
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/23 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查未通过:缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Yinxe/dshp
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · dev
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 11 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包deepseek-harness-plugins(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/27 11:46:33

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件写入剪贴板(不计风险)读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 86 处,展示前 72 条)
  • 发起网络请求
    archive/file-change-viewer/lib/client.js:755
    const response = await fetch(BASE, {
  • 发起网络请求
    archive/file-change-viewer/lib/client.js:829
    const response = await fetch(`${BASE2}/state`, { cache: "no-store" });
  • 发起网络请求
    archive/file-change-viewer/lib/client.js:833
    const response = await fetch(`${BASE2}/config`, {
  • 发起网络请求
    archive/file-change-viewer/lib/host.js:927
    const outcome = await approval.approver.request({
  • 读取本地文件
    archive/file-change-viewer/lib/host.js:1022
    if (same(await realpath(target))) return true;
  • 读取本地文件
    archive/file-change-viewer/lib/host.js:1028
    if (same(await realpath(ancestor))) return true;
  • 发起网络请求
    archive/mcp-manager/lib/client.js:36
    const r = await fetch(BASE + path, {
  • 发起网络请求
    archive/mcp-manager/lib/client.js:44
    const r = await fetch(`${BASE}/state`, { cache: "no-store" });
  • 读取密钥环境变量
    archive/mcp-manager/lib/host.js:6412
    if (node_process.env.LOG_TOKENS)
  • 读取本地文件
    archive/mcp-manager/lib/host.js:8389
    if (existsSync(candidate) && isProfileRoot(dir)) return info(candidate, "module-path");
  • 读取本地文件
    archive/mcp-manager/lib/host.js:8402
    return { path: abs, exists: existsSync(abs), source };
  • 读取本地文件
    archive/mcp-manager/lib/host.js:8406
    if (!existsSync(pkgPath)) return true;
  • 读取本地文件
    archive/mcp-manager/lib/host.js:8408
    const raw = JSON.parse(readFileSync(pkgPath, "utf8"));
  • 读取本地文件
    archive/mcp-manager/lib/host.js:8418
    if (!existsSync(profilesDir)) return null;
  • 读取本地文件
    archive/mcp-manager/lib/host.js:8421
    return readdirSync(profilesDir).map((x) => String(x));
  • 写入本地文件
    archive/mcp-manager/lib/host.js:8453
    await writeFile(tmp, text, "utf8");
  • 写入本地文件
    archive/mcp-manager/lib/host.js:8455
    await copyFile(path, path + ".bak");
  • 写入本地文件
    archive/mcp-manager/lib/host.js:8458
    await rename(tmp, path);
  • 发起网络请求
    archive/mcwiki-search/lib/client.js:109
    const r = await fetch(`${BASE}/state`, { cache: "no-store" });
  • 发起网络请求
    archive/mcwiki-search/lib/client.js:113
    const r = await fetch(`${BASE}/config`, {
  • 发起网络请求
    archive/mcwiki-search/lib/client.js:121
    const r = await fetch(`${BASE}/test`, {
  • 发起网络请求
    archive/mcwiki-search/lib/host.js:1296
    response = await fetch(url, {
  • 发起网络请求
    archive/skill-manager/lib/client.js:36
    const r = await fetch(BASE + path, {
  • 发起网络请求
    archive/skill-manager/lib/client.js:44
    const r = await fetch(`${BASE}/state`, { cache: "no-store" });
  • 发起网络请求
    archive/skill-manager/lib/client.js:48
    const r = await fetch(`${BASE}/read?root=${encodeURIComponent(rootId)}&name=${encodeURIComponent(name)}`, {
  • 发起网络请求
    archive/skill-manager/lib/client.js:54
    const r = await fetch(`${BASE}/config`, {
  • 写入剪贴板
    archive/skill-manager/lib/client.js:223
    navigator.clipboard.writeText(text).catch(() => legacyCopy(text));
  • 读取本地文件
    archive/skill-manager/lib/host.js:1193
    exists: existsSync(path)
  • 读取本地文件
    archive/skill-manager/lib/host.js:1210
    exists: existsSync(agentsSkills)
  • 读取本地文件
    archive/skill-manager/lib/host.js:1219
    exists: existsSync(dshSkills)
  • 写入本地文件
    archive/skill-manager/lib/host.js:1243
    await mkdir(root.path, { recursive: true });
  • 读取本地文件
    archive/skill-manager/lib/host.js:1247
    const entries = await readdir(path);
  • 读取本地文件
    archive/skill-manager/lib/host.js:1255
    const [realRoot, realEntry] = await Promise.all([realpath(rootPath), realpath(entryDir)]);
  • 读取本地文件
    archive/skill-manager/lib/host.js:1288
    return await stat(path);
  • 写入本地文件
    archive/skill-manager/lib/host.js:1452
    await writeFile(target, content, "utf8");
  • 写入本地文件
    archive/skill-manager/lib/host.js:1460
    await mkdir(dirTarget, { recursive: true });
  • 写入本地文件
    archive/skill-manager/lib/host.js:1461
    await writeFile(skillMd, content, "utf8");
  • 写入本地文件
    archive/skill-manager/lib/host.js:1477
    await writeFile(res.entry.entryPath, serializeFrontmatter(entries, body), "utf8");
  • 写入本地文件
    archive/skill-manager/lib/host.js:1493
    await writeFile(res.entry.entryPath, serializeFrontmatter(entries, res.body), "utf8");
  • 删除本地文件递归
    archive/skill-manager/lib/host.js:1500
    if (res.entry.kind === "bundle") await rm(target, { recursive: true, force: false });
  • 删除本地文件
    archive/skill-manager/lib/host.js:1501
    else await unlink(target);
  • 发起网络请求
    archive/token-meter/lib/client.js:190
    const r = await fetch(`${BASE}${path}`, {
  • 发起网络请求
    archive/token-meter/lib/client.js:198
    const r = await fetch(`${BASE}/state`, { cache: "no-store" });
  • 发起网络请求
    archive/token-meter/lib/client.js:208
    const r = await fetch(`${BASE}/stats`, { cache: "no-store" });
  • 写入剪贴板
    archive/token-meter/lib/client.js:663
    await nav.clipboard.write([new ClipboardItem({ "image/png": blob })]);
  • 发起网络请求
    archive/token-meter/lib/client.js:3288
    void fetch("/ext/dshp-token-meter/identity", { cache: "no-store" }).then((r) => r.json()).then((v) => {
  • 写入剪贴板
    archive/token-meter/lib/client.js:4465
    void nav.clipboard.writeText(text).then(
  • 发起网络请求
    archive/token-meter/lib/client.js:6411
    const r2 = await fetch(path, { cache: "no-store" });
  • 发起网络请求
    archive/token-meter/lib/client.js:6414
    const r = await fetch(path, {
  • 写入剪贴板
    archive/token-meter/lib/client.js:7962
    void navigator.clipboard.writeText("$DSH_HOME/sessions/");
  • 发起网络请求
    archive/token-meter/lib/host.js:1547
    async fetch(vendor, deps) {
  • 发起网络请求
    archive/token-meter/lib/host.js:2298
    async fetch(vendor, deps) {
  • 发起网络请求
    archive/token-meter/lib/host.js:2649
    async fetch(vendor, deps) {
  • 发起网络请求
    archive/token-meter/lib/host.js:2774
    async fetch(vendor) {
  • 发起网络请求
    archive/token-meter/lib/host.js:3226
    const data = await adapter.fetch(v, { resolveSecret, fetchImpl: fetch });
  • 读取本地文件
    archive/token-meter/lib/host.js:3970
    for (const entry of readdirSync(sessionsDir)) {
  • 读取本地文件
    archive/token-meter/lib/host.js:3974
    st = statSync(full);
  • 读取本地文件
    archive/token-meter/lib/host.js:3981
    sessDirs = readdirSync(full);
  • 读取本地文件
    archive/token-meter/lib/host.js:3988
    if (!statSync(dir).isDirectory()) continue;
  • 读取本地文件
    archive/token-meter/lib/host.js:3997
    const s = statSync(file);
  • 读取本地文件
    archive/token-meter/lib/host.js:4107
    for (const frame of zstdFrames(readFileSync(file))) {
  • 发起网络请求
    archive/web-style/lib/client.js:1866
    const response = await fetch(BASE + "/state", { cache: "no-store" });
  • 发起网络请求
    archive/web-style/lib/client.js:1872
    const response = await fetch(BASE + "/themes", { cache: "no-store" });
  • 发起网络请求
    archive/web-style/lib/client.js:1887
    const response = await fetch(BASE + "/theme", {
  • 发起网络请求
    archive/web-style/lib/client.js:1895
    const response = await fetch(BASE + "/config", {
  • 写入剪贴板
    archive/web-style/lib/client.js:1912
    const p = navigator.clipboard.writeText(text);
  • 发起网络请求
    archive/widget-kit/lib/client.js:1660
    const r = await fetch(`${BASE}/state`, { cache: "no-store" });
  • 发起网络请求
    archive/widget-kit/lib/client.js:1664
    const r = await fetch(`${BASE}/config`, {
  • 发起网络请求
    plugins/search-provider/lib/client.js:38
    const response = await fetch(ROUTE_BASE + path, { cache: "no-store", ...init });
  • 发起网络请求
    plugins/search-provider/lib/host.js:1027
    response = await fetch(url, {
  • 发起网络请求
    plugins/vision-bridge/lib/client.js:36
    const response = await fetch(BASE + path, { cache: "no-store", ...init });
  • 读取本地文件
    shared/tsup.preset.ts:119
    code: readFileSync(resolvePath(process.cwd(), assetId)),
扫描于 2026/11/2(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

4 张 · 点击查看大图

功能亮点

  • TypeScript编写

README

由 DeepSeek 最新模型翻译生成
deepseek-harness-plugins DeepSeek Harness(DSH)插件 Monorepo(pnpm workspaces + TypeScript ESM)。 当前维护 @dshp/vision-bridge 与 @dshp/search-provider。 2026-10-20 起其余插件已归档到 archive/,冻结在归档时的版本,不再适配新版 DSH,也不参与构建、测试与发布。 运行时零依赖 · 构建产物已提交:插件 dependencies 恒为 {},lib/host.js / lib/client.js 随仓库提交 —— clone 下来即可直接安装,无需先 build。
展开完整文档(README 剩余 1 节)
deepseek-harness-plugins

DeepSeek Harness(DSH)插件 Monorepo(pnpm workspaces + TypeScript ESM)。

当前维护 @dshp/vision-bridge 与 @dshp/search-provider。 2026-10-20 起其余插件已归档到 archive/,冻结在归档时的版本,不再适配新版 DSH,也不参与构建、测试与发布。

运行时零依赖 · 构建产物已提交:插件 dependencies 恒为 {},lib/host.js / lib/client.js 随仓库提交 —— clone 下来即可直接安装,无需先 build。

插件一览

维护中:

| 插件 | 一句话 | 文档 |
| @dshp/vision-bridge | 视觉桥接:让纯文本模型也能“看图”(vision_describe 工具 + 主/备模型自动降级) | README |
| @dshp/search-provider | AI 搜索中枢:用 Tavily / Exa / Firecrawl 接管 web_search(含两个免费后端) | README |

已归档(冻结,不再维护):

| 插件 | 版本 | 一句话 | 归档位置 |
| @dshp/token-meter | 0.15.0 | Token 额度 + 用量统计 + 在线时长(多供应商额度 + 会话日志聚合) | archive/token-meter |
| @dshp/file-change-viewer | 0.4.0 | edit / write 行的高亮差异视图 + patch 工具 | archive/file-change-viewer |
| @dshp/mcwiki-search | 1.6.0 | Minecraft Wiki 查询(搜索 / 引言 / 全文,清洗成 AI 可读文本) | archive/mcwiki-search |
| @dshp/web-style | 0.5.0 | Web 外观定制(8 套主题 + 背景效果 + 壁纸取色 + 全局圆角) | archive/web-style |
| @dshp/skill-manager | 0.4.0 | 技能管理(全局 + 工作区技能的新建 / 编辑 / 启停 / 复制移动 / 删除) | archive/skill-manager |
| @dshp/mcp-manager | 0.4.0 | MCP 服务器管理(patch 条目 CRUD + 探活,表单 / JSON 双模式) | archive/mcp-manager |
| @dshp/widget-kit | 0.13.0 | 小组件规范与宿主(托盘 + 卡片 + 小面板,不含业务) | archive/widget-kit |

归档件保留源码、文档与已提交的 lib/,可直接从 archive/<name> 本地安装;不参与 CI、不再发版,也不再适配新版 DSH。归档清单与冻结版本见 archive/README.md。

安装到 DSH

方式一(推荐):克隆仓库安装 —— 更新只需 git pull,旧版 DSH 可 checkout tag

git clone git@github.com:Yinxe/deepseek-harness-plugins.git
cd deepseek-harness-plugins
pnpm install
lib/ 已提交,clone 下来就能用;改了 src 才需要 pnpm build

安装维护中的插件
dsh plugin --profile web add ./plugins/vision-bridge

归档插件仍可本地安装(冻结版本,不再更新;见 archive/README.md)
dsh plugin --profile web add ./archive/token-meter

dsh web # 重启生效

- 更新:仓库内 git pull + dsh web(最快——lib 已提交,未改 src 无需 build);兼容旧版 DSH:按 compat.json 的 tag git checkout <tag> 后重跑上面的 add。
- 归档插件不随仓库更新:它们的源码与 lib/ 已冻结,装与不装都不影响 vision-bridge。

dsh plugin add 会把包写进 profile 的 dsh.profile.bundles —— 无需手动改配置文件。
各插件的详细安装说明、配置与常见问题见对应 README(上表)。

方式二:从 Release 安装(无需 clone;更新需手动重跑命令)

CI 把维护中的插件打包成 tgz 发布到 Releases,latest 滚动发布固定跟随 main 最新构建(持 Latest 徽标、始终置顶):

macOS / Linux
dsh --profile web add \
https://github.com/Yinxe/deepseek-harness-plugins/releases/download/latest/dshp-vision-bridge-latest.tgz

Windows PowerShell
dsh --profile web add
'https://github.com/Yinxe/deepseek-harness-plugins/releases/download/latest/dshp-vision-bridge-latest.tgz'

维护中插件的下载与安装命令见 Releases 各预发布说明;滚动更新 = 重跑同一条命令 + dsh web 重启(latest 资产随 main 每次构建滚动重建)。

两个 pnpm 语义坑,遇到别绕远路:

1. dsh plugin … update 对 tarball URL 直装无效——pnpm update 只重解析 semver 范围,URL 是精确 spec(且 lockfile 用 integrity 钉住首次内容),永远 "Already up to date"。滚动更新请重跑同一条 add 命令(或用下面的 Git tag 安装);
2. remove 后重装同一 URL 若报 ERR_PNPM_MISSING_TARBALL_INTEGRITY(lockfile 残留了无 integrity 的条目),删掉 profile 目录里的 pnpm-lock.yaml 再 add 即可(lockfile 是可再生的本机状态)。

历史版本(兼容旧版 DSH)

维护中的 vision-bridge 永远跟随最新 DSH。老版本 DSH 用户装静态历史版本:按 compat.json 记录的兼容 tag(「DSH 版本 → 推荐 tag」矩阵),到 Releases 找对应版本 Release(v tag 触发,静态存档、永不滚动),资产名 = dshp-<插件名>-<tag>.tgz(历史 tag 里仍含当时尚未归档的插件,checkout 后路径为 plugins/<name>):

以 v0.1.5-rc.1 为例
dsh --profile web add \
https://github.com/Yinxe/deepseek-harness-plugins/releases/download/v0.1.5-rc.1/dshp-vision-bridge-v0.1.5-rc.1.tgz

方式三:Git 依赖安装 —— 支持 update 一键(可解析较慢,列为备选)

仓库自带一个随 CI 滚动的 latest git tag(每次 main 构建通过门禁后重置到 main HEAD)。装它 = "永远最新",且 update 一键跟进——spec 永不改变,可变性由 git ref 承担,完全绕开 tarball URL 的语义坑:

安装(一次,此后 spec 永不改)
dsh plugin --profile web add \
"github:Yinxe/deepseek-harness-plugins#latest&path:plugins/vision-bridge"

之后每次更新就这一条:
dsh plugin --profile web update @dshp/<插件名>
dsh web # 重启生效

同一机制的两种变体(换选择器即可):

- #semver:^1.0.0&path:plugins/vision-bridge —— 跟发版 tag 走的受控升级:只在 push 了匹配范围的新 tag 后 update 才会动;预发布 tag 受 node-semver 元组规则限制,范围必须显式含预发布(如 ^0.1.5-rc.1 只匹配 0.1.5 系列);
- #main&path:plugins/vision-bridge —— 与 #latest 等价的分支滚动。

注意:

- latest tag 在门禁通过后才移动到 main HEAD,所以 update 拿到的永远是过了门禁的构建;
- 网络慢时,git 解析可能要 2–4 分钟;clone 一次后 pnpm 有本地缓存,重复 update 会快一些;
- 协议取决于你本机的 pnpm 版本,而不是 spec 本身:pnpm ≥ 11.21.0 的 github: 简写走 HTTPS,开箱即用;更早的版本(如 11.7.0)会解析成 git+ssh://git@github.com/…,需先配好 GitHub SSH key,否则报 Permission denied (publickey)。旧版又不想配 key 时,升级 pnpm,或让 Git 把 ssh 重写成 HTTPS(pnpm 只是 shell out 到 git,重写自动生效):

git config --global url."https://github.com/".insteadOf "git@github.com:"

- 对比:tarball URL 直装(…latest.tgz)的 spec 是精确 URL,update 永远 no-op——这正是 git 依赖方案存在的理由。

多插件统一更新:update 支持一条命令带多个包名(git 与 tarball 混装亦可):

dsh plugin --profile web update "@dshp/" # 或显式列出:update @dshp/a @dshp/b …

实测耗时(国内网络、SSH 热缓存):约 35 秒/插件、线性增长(3 个 ≈ 1 分 40 秒;首次冷安装更久,每个都要完整 clone)。插件多且网络差时更新会到分钟级——这是 git 解析的固有成本,根治要等 npm 发布渠道恢复(registry 元数据 + CDN tarball,秒级)。tarball 渠道的多插件重装同样支持一条命令带多个 URL,但在 HTTPS 不稳的网络下可能超时。

卸载

dsh plugin --profile web remove "@dshp/<插件名>"
dsh web # 重启生效

remove 直接转发 pnpm(参数 = 包名),并自动从 dsh.profile.bundles 撤下挂载;写入 profile 条目 config: 的配置按需手动清理。各插件的详细安装/更新/卸载说明见各自 README。

一键 AI 安装

把下面这段发给你的 DSH AI,让它代你装:

帮我从 monorepo Yinxe/deepseek-harness-plugins 安装插件(按需选择子目录):
1. git clone 仓库并 pnpm install
2. dsh plugin --profile web add ./plugins/vision-bridge
3. 重启 dsh web,确认无报错、设置页出现对应条目

发布与更新约定(CI 自动执行)

| 通道 | 触发 | 行为 |
| latest | 推送 main | 滚动重建到最新提交(正式渠道,持 Latest 徽标置顶),下载地址固定 |
| 版本 Release | 推送 v tag | 静态存档,永不随构建变化 |
| 自定义后缀 | 手动触发(限 main / tag) | 勾选 rolling = 预发布随滚动;不勾 = 静态正式版 |
| 仅门禁 | 推送其他分支 / PR | 不打包、不发布(分支上的构建产物没有意义) |

- 只有 main 与 v tag 能产出发布物:其他分支推送与 PR 只跑门禁;手动触发是唯一的人工发版口,也只在 main(或 v tag)上生效,在别的 ref 上跑只跑门禁并打一条 notice。要给人试新版,用 main 的 latest,或手动触发指定后缀。
- 滚动约定:所有预发布(以及 notes 首行带 标记的 release)都跟随 main——每次 main 推送成功后整体重建到最新提交;停止跟随 = 取消 Pre-release 勾选或删除标记行。latest 每次最后重建并授予 Latest 徽标,始终置顶 Releases 列表。
- 数量约束:除 latest 外同时最多允许 1 个滚动项;出现多个时 CI 立即报错终止(不动任何现有 Release),处理后再推送即可。
- Release 说明由 scripts/gen-release-notes.cjs 生成:逐插件列出包名、版本、双语描述、下载与安装命令。

结构

.
├── plugins/
│ ├── vision-bridge/ # @dshp/vision-bridge(视觉桥接,维护中) │ │ ├── src/host/ # Host TS:types/http/config/cache/vision/index │ │ ├── src/client/ # Client TS:types/styles/api/components/VisionSection/index │ │ ├── lib/ # 单文件构建产物(已提交,DSH git 安装必需) │ │ └── cordis.patch.yml # bundle 声明(id: dshp-vision-bridge) │ └── search-provider/ # @dshp/search-provider(AI 搜索,维护中) │ ├── src/host/ # Host TS:types/http/config/providers/index │ ├── src/client/ # Client TS:types/styles/api/components/SearchSection/index │ ├── lib/ # 单文件构建产物(已提交,DSH git 安装必需) │ └── cordis.patch.yml # bundle 声明(id: dshp-search-provider) ├── archive/ # 冻结的历史插件(源码 + lib + 文档,不参与构建 / 发布) │ ├── token-meter/ # @dshp/token-meter 0.15.0 │ ├── file-change-viewer/ # @dshp/file-change-viewer 0.4.0 │ ├── mcwiki-search/ # @dshp/mcwiki-search 1.6.0 │ ├── web-style/ # @dshp/web-style 0.5.0 │ ├── skill-manager/ # @dshp/skill-manager 0.4.0 │ ├── mcp-manager/ # @dshp/mcp-manager 0.4.0 │ ├── widget-kit/ # @dshp/widget-kit 0.13.0 │ └── README.md # 归档清单、冻结版本与安装说明 ├── AGENT.md # 开发规范·规则版(红线 + 指路) ├── docs/ # 规范细节(脚手架 / TS / package.json / 构建 / Cordis / settings / 路由 / Client / provider / 时区 / 安全 / 门禁 / 发布 / 文档 / 小组件)——旧 AGENT.md §1–§14 的完整下沉 ├── tsconfig.base.json # 共享 TS 配置(NodeNext + strict) ├── tsconfig.json # solution 引用(只含维护中的插件) ├── pnpm-workspace.yaml # packages: plugins/(archive 不在 workspace) ├── compat.json # DSH 版本兼容矩阵 └── .github/workflows/CICD.yml # 门禁 + 打包发布:main→latest 滚动发布,v* tag→版本 Release,其他分支仅门禁

每个插件内部一律是同一套布局:src/host/(Node 半)+ src/client/(浏览器 半)+ lib/(已提交的单文件产物)+ cordis.patch.yml + AGENT.md(本插件的局部规则与事实,指回根规范)。

设置键名约定(全仓统一,改名即 breaking)

每个插件只有一个配置键,四处同名,等于 dshp-<目录名>:

| 位置 | 值(以 vision-bridge 为例) |
| 配置命名空间(条目 Config + volatile / settings.update) | dshp-vision-bridge |
| 同源路由前缀 | /ext/dshp-vision-bridge/ |
| cordis.patch.yml 的 id | dshp-vision-bridge |
| 设置页 settings.section 的 id | dshp-vision-bridge |

插件只读自己的键,不做任何历史键兼容与迁移:不读 dshp-inx- 等旧命名空间、不读 storages/*.json、不读不改写 settings.yaml(旧配置一次性导入是平台的事;规范见 docs/settings.md)。升级时若键名有变,请按各插件 README 的更新日志手工把旧分节改名或重配;配置键改名属 breaking 变更。

环境

- Node >= 20(推荐 24,见 .nvmrc)
- pnpm 11.7.0(见 devEngines)
- 本沙箱全局 store 只读,pnpm-workspace.yaml 已设 storeDir: /tmp/pnpm-store(pnpm v11 必须写这里,.npmrc 会被忽略)

常用命令

pnpm install
pnpm check # 一条流程:build → typecheck → lint → format(提交前跑这个)
pnpm format # prettier 全仓写盘
pnpm format:check # CI 用,只检查不写
pnpm lint # oxlint 全仓(--deny-warnings,警告也算挂)
pnpm typecheck # pnpm -r typecheck
pnpm build # pnpm -r build
pnpm test # pnpm -r test

单个插件
pnpm --filter @dshp/vision-bridge build
pnpm --filter @dshp/vision-bridge typecheck

提交前跑 pnpm check(构建 → 类型检查 → 质量检查 → 格式化一步完成);CI 仍按严格检查序把关;改了 src/ 必须重新 build 并把 lib/ 一起提交。

加新插件

mkdir -p plugins/<name>/src

照抄 plugins/vision-bridge/{package.json,tsconfig.json},改 name/version/description

tsconfig.json 里 extends 保持 ../../tsconfig.base.json

根 tsconfig.json references 加一条 { "path": "./plugins/<name>" }

pnpm install

规范分三层:AGENT.md(红线规则版)→ docs/(主题细节,旧 §1–§14 全部下沉在此)→ 各插件 AGENT.md(局部规则与事实)。多服务商分层渲染、接管工具行渲染等专题见 docs/ 对应篇目。
预览分享卡片长什么样 ↓Yinxe/dshp
分享 · DeepSeek Harness Hub
Yinxe/dshp

DeepSeek Harness(DSH)插件 monorepo(pnpm + TypeScript)

回到顶部