dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
完全离线的内网即时通讯插件。给 DeepSeek Harness 左侧新增一个 「局域网聊天助手」 入口, 支持 单聊、群聊、文件传输,以及 按网段扫描发现同事。
不连任何外部服务:没有云端账号、没有中转服务器、没有 CDN 依赖。所有流量只在你自己的局域网里。
能力 · 说明 单聊 · 与任意一位同事一对一聊天,支持未读数、已读位置、在线状态 群聊 · 自建群、拉人入群、改名、退群、删除;群资料自动同步给成员 文件传输 · 拖拽或点选发送,单文件上限可配(默认 512MB);接收方按需下载(不占用对方磁盘两次) 网段扫描 · 填 192.168.1.0/24 即可并发探测,进度实时显示 自动发现 · 每 30 秒 UDP 广播一次,同网段的人无需手动添加就能互相看到 手动探测 · 知道对方 IP 时直接探测单个地址 访问码 · 可选。设置后只有知道访问码的人能与你通信 联系人备注 · 给同事起本地备注名(如「隔壁老王」),只改自己这边的显示,不通知对方 删除消息 · 单条删除或整个会话清空;只删本机记录,对方那份不受影响 删除群聊 · 群主删=解散(通知全员一起删),成员删=只删本机这份;都会清掉该群本地消息 文件上限 · 设置里可改单文件上限(64MB ~ 64GB),发送框提示实时跟随 离线可用 · 对端不在线时消息照常记录在本地,联网后手动重发即可
左侧会话列表 + 右侧聊天区,三个页签:
从 1.x 升级到 2.x 请看 CHANGELOG。 2.0.0 是破坏性安全版本,
协议不兼容,局域网内所有机器必须一起升级,否则互相连不上。
在 DSH Desktop 的插件市场里搜索 dsh-lan-chat,或者直接用命令:
dsh plugin --profile desktop add github:jasonchan2026/dsh-lan-chat装完重启 DSH Desktop,左侧就会出现「局域网聊天助手」。
已经 clone 到本地的话:
dsh plugin --profile desktop add link:$PWDdsh plugin add 会自动做两件事:把包写进 profile 的 dependencies, 并把包名追加进 dsh.profile.bundles(因为本包声明了 dsh.bundle)。
如果不用 dsh plugin add,手工接也只要改 profile 的 package.json 两处:
{
"dependencies": {
"dsh-lan-chat": "link:/path/to/dsh-lan-chat" // 或 github:<用户名>/dsh-lan-chat
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-lan-chat" // ← 追加这一项
]
}
}
}插件的 Loader 条目由包内自带的 cordis.patch.yml 提供,由 bundle 机制自动叠加:
- insert:
- id: lan-chat
name: dsh-lan-chat⚠️ 不要再往 profile 自己的 cordis.patch.yml 里写同样一条 —— DSH 会先叠所有bundle 的 patch,最后才叠 profile 的 patch,重复写会注册两次同一个条目。
0.2.1-rc.3 或更高所以在完全离线的机器上也能装(只要能把包拷过去)
插件在 cordis.patch.yml 里支持三个可选参数:
- insert:
- id: lan-chat
name: dsh-lan-chat
config:
port: 45871 # 局域网监听端口
nickname: 我的电脑 # 初始昵称
dataDir: /path/to/data # 数据目录参数 · 默认值 · 说明 port · 45871 · 局域网 TCP 端口。发现用的 UDP 端口是 port + 1 nickname · 主机名 · 首次启动写入,之后以界面设置为准 dataDir · $DSH_HOME/plugin-data/dsh-lan-chat · 消息、文件、身份、设置的存放位置
大部分设置直接在界面的「设置」里改,不需要编辑配置文件,包括:
界面设置项 · 说明 昵称 · 自己对外显示的名字,改完会自动推给在线联系人 访问码 · 留空表示不设;已设置时会显示「已设置」并提供「清除」勾选框 单文件上限 · 64MB ~ 64GB,默认 512MB;发送框右下角提示会跟着变 联系人备注 · 在「联系人」里点标签图标设置,只影响本机显示
文件总量配额(默认 2 GiB)通过 /lan-chat/settings 的 maxTotalBytes 调整,暂未做进界面。
插件在宿主进程里起一个独立的 HTTP + WebSocket 服务,监听 0.0.0.0:。 之所以不复用 DSH 自己的 web server,是因为它只监听回环地址,局域网里的其他机器根本连不上。
浏览器界面 ──同源 HTTP──> DSH web server ──> 插件宿主半侧 ──LAN──> 其他机器
│
SSE 实时推送HTTP 接口(/lan-chat/v1/...):
方法 · 路径 · 用途 GET · /info · 读取节点身份(扫描用,不鉴权) POST · /hello · 握手,校验访问码 POST · /send · 投递一条消息 POST · /sync · 拉取增量消息 POST · /group · 同步群资料 POST · /group-removed · 群主解散群时通知成员(2.2.0 新增) POST · /profile · 同步昵称 POST · /upload · 上传文件实体 GET · /file/:id · 下载文件实体 GET · /ws · WebSocket 实时通道
两条腿:
255.255.255.255 和各网段广播地址发一个 UDP 包(端口 port+1),收到的人回一条带自己身份的应答。
GET /info,700ms 超时。扫描上限 1024 个地址(/22 及更宽),避免误填 /8 把界面拖死。
发一条消息时:
messages/.jsonl(先写本地,保证不丢)POST /send收一条消息时:normalizeMessage 校验 → 幂等检查(同 id 跳过)→ 落盘 → 广播给界面和所有已连的 peer。
$DSH_HOME/plugin-data/dsh-lan-chat/
├── identity.json 本机身份(peerId + secret,首次启动生成)
├── state.json 设置、联系人、群、已读位置、文件索引
├── messages/
│ ├── dm%3AlcA%7ClcB.jsonl 单聊(每个会话一个追加日志)
│ └── grp%3Ag1.jsonl 群聊
└── files/
└── f<id> 文件实体消息用 JSONL 追加写,不重写整个文件;读取时只回看尾部 8MB,避免长年累积后打开变慢。
对方看不到我 / 我扫不到对方
192.168.1.x 和 192.168.2.x 通常不通)端口被占用
插件启动失败时界面顶部会显示红色提示,不影响其他功能。提示里会直接写出 占用者的 PID 和已运行时长:
界面会出现「强制释放」按钮,点一下就会结束它并重新监听,不用重启 DSH。 宿主只对确认过身份的残留进程动手,判据是「命令行是 DSH 宿主 + 父进程为 1 + 不是当前进程或其祖先」,三条缺一不可。
改 cordis.patch.yml 里的 port,或者关掉那个程序。
/listen/retry 只重试绑定、从不杀进程;/listen/release 才会结束残留宿主。
消息发不出去
看会话标题下面显示的是「在线」还是「离线」。离线时消息仍会记录在本地,等对方上线后可以重发。 文件也一样:接收方点下载时如果本地没有实体,会回源到发送方拉取。
能不能跨网段 / 跨 VLAN
不能自动发现,但如果路由可达,可以在「发现」页手动填对方 IP 探测,然后添加。
六套离线测试,不需要网络,也不需要 DSH 在跑:
node scripts/selftest.mjs # 协议层:WS 帧、文件、群、扫描、鉴权、昵称同步、持久化(34 项)
node scripts/hosttest.mjs # 宿主路由:全部 /lan-chat/* 接口 + 桌面端来源校验 + 端口重试与强制释放 + 删群(111 项)
node scripts/clienttest.mjs # 界面:真 React + jsdom 挂载并驱动交互(67 项)
node scripts/e2etest.mjs # 两台机器互联:发现→添加→单聊→群聊→文件→解散群(40 项)
node scripts/sectest.mjs # 安全回归:22 个渗透测试发现逐条验证 + 解散群越权(52 项)
node scripts/themetest.mjs # 主题配色:DSH token 存在性 + 明暗两套 WCAG 对比度(65 项)合计 302 项(不含需要额外开发依赖的 clienttest.mjs)。
themetest.mjs 是补上「深色主题下配色失效」这个缺陷后加的。它做两件事: 把插件引用的每个 --dsw-alias-* 变量拿去和 DSH 主题比对,名字写错立刻失败 (var() 写错不会报错,只会静默用兜底值,这类 bug 功能测试全绿也发现不了); 再用 DSH 真实的明 / 暗两套取值算 WCAG 对比度,挡住「能解析但看不清」。
clienttest.mjs 需要开发依赖 react / react-dom / jsdom(不进插件包):
pnpm add -D react react-dom jsdom也可以用 REACT_ROOT=/path/to/node_modules 指向已经装好它们的目录。