Vai al contenuto principale
P

dsh-chat-embed

poluce/dsh-chat-embed

A multi-tab AI chat panel for the desktop app: seven services (DeepSeek, 豆包, ChatGPT, MiniMax, Kimi, Gemini, Grok) each run in their own webview and login partition, and the chat can live in the left navigation panel or in a right sidebar tab — whichever one you open owns it. Desktop app only; logins last until the app restarts unless you apply the optional manual patch (tools/shell-patch) to the desktop app's resources/app.asar, and restore-shell-patch.cmd reverts it.

Installazione

dsh plugin --profile web add github:poluce/dsh-chat-embed

README

dsh-chat-embed icon

dsh-chat-embed

在 DeepSeek Harness(dsh)桌面版里开一个多标签 AI 聊天面板。

左侧导航有「聊天」入口,点开后中央主面板就是聊天页:顶部一排标签 —— DeepSeek、豆包、ChatGPT、MiniMax、Kimi、Gemini、Grok —— 每个标签是一个真实的桌面 webview,各自独立登录;切标签不重载页面。同一个聊天页也能放到右栏(会话头「⧉」按钮 / 右栏启动器),两处互斥,哪边点哪边接管。

左栏「聊天」入口,中央主面板里是 DeepSeek 聊天页


项目名称与组成

名称说明
dsh-chat-embed本插件的包名,也是 dsh 插件管理器里的条目名
index.jsHost 半侧(Node):当前是空壳,只为满足 bundle 的 loader 行;后续若需 Host 配置从这扩展
client.jsClient 半侧(浏览器):多标签、租约握手、内联席位、全部 UI。手写产物,无构建
locale/{en,zh}.json插件管理器里显示的标题与简介
cordis.patch.yml组合补丁:向 profile 插入 id: chat-embed 的 loader 行
scripts/verify-bundle.mjs门禁:语法 / 清单 / loader 契约 / 服务注册表 / 显示资源
test/纯 Node 契约测试(伪造 DOM + 伪造桌面桥),57 项
docs/architecture.md内嵌契约、席位架构、壳补丁、升级复验清单(接到项目先读这份)
tools/shell-patch/可选的桌面壳补丁:持久分区(跨重启免登录)+ 关闭磁盘缓存
清理聊天缓存.cmd / restore-shell-patch.cmd缓存回收 / 还原原版壳

没有第三方运行时依赖:client.js 直接由 dsh 的模块加载器执行,React 用壳共享的那一份。

文档入口

想了解读哪里
怎么装、怎么用本文件(README)
为什么这样实现、内嵌契约、升级外壳时的复验清单docs/architecture.md
壳补丁(持久分区 / 关缓存)与回滚tools/shell-patch/ + restore-shell-patch.cmd
门禁与测试覆盖了什么scripts/verify-bundle.mjs、test/client.test.mjs

软件定位与功能

定位:给 dsh 桌面版补上一个"多服务 AI 聊天"的常驻界面。不代理请求、不保存聊天内容,只是把各站点装进独立登录态的桌面 webview。

能力说明
左栏「聊天」→ 中央主面板直接是聊天页顶部多标签切换,每个服务独立 webview、独立分区
右栏聊天 tab(keepMounted)+ 会话头「⧉」切标签不卸载,页面状态保留
哪边点哪边接管左栏入口 / 右栏 tab 谁被点开谁承载;互斥,切换重建一次并回到上次会话
7 个内置服务DeepSeek、豆包、ChatGPT、MiniMax、Kimi、Gemini、Grok;改 PROVIDERS 一行即可扩展
标签常驻切标签只切 data-active(display:none),草稿与滚动位置保留
失败隔离单个标签失败不影响其它;「重新加载」只换该标签的租约
拖动排序按住标签横向拖动(>6px 才算拖动),顺序写 localStorage;溢出时滚轮横向滚动
⚙ 设置逐个启用/禁用服务,至少保留一个,状态持久化
诊断(⚙ 菜单)URL / 分区 / 阶段 / 右栏注册 / 席位 / 自检,一键复制
调试日志(⚙ 菜单)默认关闭;开启后控制台输出插件事件,菜单里可「复制日志」
原生布局跟随聊天页放在席位布局盒里,宽高由 CSS 决定;拖分隔条零 JS、零重渲染
Google 登录死路 / 非桌面环境自动退回入口并给出说明卡片;Web GUI 下显示说明 + 外开链接

截图

左栏:中央面板多标签右栏:聊天 tab
ChatGPT 标签右栏标签里的 DeepSeek
Gemini 标签右栏标签里的 Gemini

快速开始

环境要求

项要求
桌面端@deepseek-ai/dsh-desktop 0.2.2-rc.1(实测;Windows 10/11)
Node.js>= 22(仅开发/测试需要,插件运行时不依赖 Node)
浏览器/壳Electron(webviewTag 开启)—— Web GUI 只能用降级卡片

安装(5 行)

仅桌面版可用(需要 Electron 的 <webview> 和 window.dshDesktop.browser)。 当前实测版本:@deepseek-ai/dsh-desktop 0.2.2-rc.1;包声明了 engines.dsh,版本不符时插件管理器会拒绝安装。

方式一:npm(已发布 0.5.4)

// 在 dsh 会话里交给插件管理器执行
plugin_manager { "action": "install_bundle", "target": "dsh-chat-embed" }
// 然后刷新页面;左侧栏出现气泡图标即安装成功
# 命令行等价写法
dsh plugin --profile desktop add dsh-chat-embed

方式二:git 仓库或本地 tarball

# 从 Releases 下载 dsh-chat-embed-<版本>.tgz 后:
dsh plugin --profile desktop add .\dsh-chat-embed-0.5.0.tgz

# 或直接从公开仓库安装
dsh plugin --profile desktop add git+https://github.com/poluce/dsh-chat-embed.git

方式三:在本仓库开发(link 方式,改完即生效)

dsh plugin --profile desktop add link:<本仓库克隆路径>

卸载:dsh plugin --profile desktop remove dsh-chat-embed(或 plugin_manager { "action": "remove_bundle", "target": "dsh-chat-embed" })。

启动与打开

  1. 打开 dsh 桌面版,左侧栏点「聊天」图标 → 中央主面板加载聊天页;
  2. 或在任意会话的标题栏点「⧉」→ 右栏打开聊天 tab;
  3. 标签切换 / 拖动排序 / 右上角工具行(重新加载、外开、设置)即可使用;诊断与调试日志在「⚙」菜单里。

简要使用说明

场景操作
打开聊天左栏「聊天」图标(中央)或会话头「⧉」/ 右栏启动器(右栏)
切换服务点标签;标签会记住上次激活项(localStorage)
拖动排序按住标签横向拖到目标位置松手;溢出时用滚轮横向滚动
隐藏某个服务工具行「⚙」→ 关闭对应开关(至少保留一个)
页面卡住/白屏工具行「重新加载」(换新租约)或「外开」到系统浏览器
排查问题工具行「⚙」→「标签页诊断…」→ 看地址 / 分区 / 状态 / 席位 / 自检,点「复制诊断信息」发给维护者
打开调试日志工具行「⚙」→「调试日志」开关(默认关闭);开启后控制台输出插件事件,「复制日志」导出最近 200 条
查看跨重启登录工具行「⚙」→「跨重启保持登录」一行显示 已开启(persist: 分区)/ 未开启(内存分区)/ 尚未检测;未开启时可点「复制补丁说明」
换到另一处显示直接点另一处的入口(左栏图标或右栏 tab),聊天会接管过去并回到上次会话

登录:每个服务在自己的 webview 里用站点自己的方式登录(验证码/扫码/邮箱)。登录态在同一次运行内有效;跨重启需要打桌面壳补丁(见 已知限制)。


配置

增删服务

服务清单只有一处:client.js 的 PROVIDERS。追加一条即可:

{ id: 'gemini', label: 'Gemini', url: 'https://gemini.google.com/',
  origin: 'https://gemini.google.com', workspace: 'dsh-chat-embed:gemini:v1' },
字段作用约束
id标签 id,也参与分区命名小写、唯一
label标签文字非空
url首次打开导航到哪里https://
origin站点基址(诊断/策略用)url 的前缀
workspace壳的存储身份 = 分区键唯一;发布后不可改(改了就退出登录)

改完执行 npm run check → 重装插件 → 刷新页面。门禁会校验 https、workspace 唯一、无未声明站点。

运行时开关

  • ⚙ 设置的启用状态存在 localStorage['dsh-chat-embed:enabled'];
  • 标签顺序存在 localStorage['dsh-chat-embed:tab-order'];
  • 上次激活标签存在 localStorage['dsh-chat-embed:active-tab'];
  • 调试日志开关存在 localStorage['dsh-chat-embed:log'](1 开 / 0 关,默认关);
  • 最近一次检测到的持久化状态存在 localStorage['dsh-chat-embed:persist'],重启后无需等 guest 挂载即可显示。

桌面壳补丁(可选,跨重启免登录)

node tools/shell-patch/patch-asar.cjs build                      # 自动探测安装目录并生成 app.asar.new
node tools/shell-patch/patch-asar.cjs build --resources "D:\DeepSeek Harness\resources"
node tools/shell-patch/patch-asar.cjs --help                     # 查看参数
# 关闭 DSH 后由 watchdog 自动替换,或手动替换 resources\app.asar

通过 npm 安装时脚本位于 <profile>/node_modules/<包名>/tools/shell-patch/;也可以在「⚙ → 跨重启保持登录」里点「复制补丁说明」拿到步骤。

补丁做两件事:persist: 固定分区(登录落盘)+ cache:false(不落 Chromium 缓存)。 没有补丁也能用,只是每次重启要重新登录。细节与风险见 已知限制。

界面语言

面板文案跟随 DSH 的语言设置(设置 → 通用设置 → 语言:中文 / English 等):插件注册 zh / en 两套词典,通过 DSH 的 locale 服务解析当前语言,切换后立即生效,不需要刷新或重启(监听 locale/change 事件重渲染)。

  • 当前语言没有对应翻译时(例如日语、西班牙语),回落到中文;
  • 诊断卡片里的席位、状态、最近事件、自检读数也随语言切换;
  • 插件管理器里的标题与描述(locale/en.json、locale/zh.json)同样是 DSH 系统界面的一部分,跟随系统语言。

目录结构

dsh-chat-embed/
├── package.json               # 包名/版本、dsh.bundle.patch、dsh.client、exports/files
├── cordis.patch.yml           # 组合补丁:插入 id=chat-embed 的 loader 行
├── index.js                   # Host 半侧(空壳,扩展点)
├── client.js                  # Client 半侧(约 3545 行,手写产物)
├── locale/{en,zh}.json        # 插件管理器显示用 meta
├── icon.svg                   # 插件图标(插件管理器显示)
├── assets/
│   ├── icon-180.png           # 商店卡片图标(180×180 位图)
│   └── screenshots/           # 商店截图(6 张,1600×1027)
├── screenshots.json           # 商店截图清单(插件市场读取)
├── scripts/
│   ├── verify-bundle.mjs      # 门禁脚本
│   └── pack-dist.mjs          # 产出 dist/*.tgz(维护者)
├── test/
│   ├── fake-env.mjs           # 伪造 DOM / 伪造桌面桥
│   └── client.test.mjs        # 62 项契约测试
├── docs/
│   ├── architecture.md        # 架构与内嵌契约(先读这份)
│   └── publishing.md          # 维护者:发版、分发与列表投稿
├── tools/shell-patch/         # 随 npm 包发布
│   ├── patch-asar.cjs         # 壳补丁(持久分区 + 关缓存)
│   ├── watchdog.ps1           # 退出时替换 asar
│   └── clean-cache.ps1        # 只删缓存、保留登录
├── 清理聊天缓存.cmd
├── restore-shell-patch.cmd
├── LICENSE (MIT)
└── README.md

工作原理(简要)

  1. 五处 slot:main(中央聊天页)、sidebar.panellist(左栏图标)、sidebar.right.pane.tab(右栏 tab body)、sidebar.right.pane.tab.title(右栏 chip 标题)、conversation.session.header.utilities(会话头「⧉」)。
  2. 租约握手:点标签 → window.dshDesktop.browser.acquire(workspace) → 拿到一次性 lease 与 partition → 建 <webview src="about:blank#<lease>" partition="<partition>" useragent="<归一化 UA>">。三个属性必须完全一致,否则壳在 will-attach-webview 拒绝。
  3. 导航:只能从 guest 文档内部导航(executeJavaScript('location.href = …')),loadURL() / 改 src 无效。
  4. 内联席位:聊天页渲染在席位布局盒里(width/height:100%),拖分隔条由浏览器布局,零 JS 测量;切标签只切 display:none,元素不移动。
  5. 席位接管:席位挂载即认领 guest;另一席位若仍挂载则显示移交卡片。宿主变化时丢弃旧 guest 并重建(Electron 无法搬移 webview),再用 startUrlFor() 回到上次会话地址。
  6. 隔离:每服务一个 workspace、一个分区、一个 guest、一条租约;一个标签失败不影响其它。

想看证据、契约细节与升级检查清单:docs/architecture.md。


开发

# 获取最新代码(当前仓库未配置远程地址,按你实际的 remote 替换)
git clone <repo-url> dsh-chat-embed
cd dsh-chat-embed

# 无需安装依赖;直接跑门禁与测试
npm run check     # 语法 + 清单 + 显示资源 + 服务注册表 + 62 项测试
npm test          # 只跑测试

没有构建步骤:client.js 就是最终产物。改完后重装一次让浏览器拿到新 generation:

plugin_manager { "action": "remove_bundle",  "target": "dsh-chat-embed" }
plugin_manager { "action": "install_bundle", "target": "<本仓库克隆路径>" }

提交前约定:门禁必须绿;代码注释/提交信息英文,文档中文;同时改 package.json 的 version 与 client.js 的 BUILD。

发布与分发

维护者发版、打包、GitHub Release、npm 发布与插件列表投稿:见 docs/publishing.md。


已知限制

  1. 跨重启登录需要壳补丁:壳默认给内存分区(dsh-sidebar-browser-<uuid>,无 persist:,每次启动随机),登录态不落盘。tools/shell-patch/ 可修;客户端升级会覆盖 app.asar,需要重打。
  2. 左右互斥:右栏聊天依赖会话视图;中央打开聊天面板时右栏不可用。同一时刻只有一处显示聊天页,切换会重建一次(自动回到上次会话,不用重新登录)。
  3. 中心面板会被切走:选另一个主面板时中央聊天页随 DOM 卸载,回来要重建;右栏 tab 带 keepMounted,切标签/切会话不卸载。
  4. 内存:每点亮一个标签 = 一个渲染进程;7 个全开会明显吃内存。
  5. Google / Apple 登录无法在内嵌面板完成:GSI 依赖 window.opener 交回凭据,面板无弹窗上下文;插件识别死路后自动退回入口并提示用邮箱登录。
  6. 人机校验:ChatGPT 首次打开可能要求过一次。
  7. 仅 Electron:无 Tauri / 第三方壳适配;Web GUI 降级为说明卡片。
  8. 聊天页宽度依赖席位布局盒(.dce-inline 100%);若 dsh 改掉主面板 / tab body 结构需复核。

常见问题

现象处理
侧栏没有「聊天」图标插件未启用 / 未加载:看 设置 → 插件,或重装一次
左栏入口打开是空白/卡片确认右栏聊天是否开着(互斥);看「⚙ → 标签页诊断… → 席位 / 自检」一行
标签变红(data-failed)该标签租约或导航失败:点它看状态行 detail,再「重新加载」
显示「已连接」但页面空白网络或站点风控;「重新加载」或「外开」
出现「使用环境异常」UA 归一化失效(壳升级后 UA 结构变了),查 normalizedUserAgent
重启后要重新登录未打壳补丁,或补丁被客户端升级覆盖:重跑 patch-asar.cjs build
磁盘占用变大执行 清理聊天缓存.cmd(只删缓存,保留登录);或确认补丁含 cache:false
标签文字/顺序要改只改 PROVIDERS,npm run check + 重装

版本历史

版本变化
0.5.4语言切换即时生效:翻译器改为 locale 绑定的单一来源,监听 locale/change 重渲染(不再依赖未注入的 props.t);补语言切换测试
0.5.3修复 locale 探针(t 作用域错误)并补测试;诊断读数在测试环境下的 <html lang> 兼容
0.5.2面板文案跟随 DSH 语言设置(中文 / English 即时切换,缺翻译回落中文);诊断读数一并本地化;新增 locale 探针
0.5.1面板文案固定中文(不再随界面语言显示英文);诊断读数的席位/状态/事件也改为中文;「复制补丁说明」改中文,并写明执行目录与替换步骤
0.5.0可发布化:engines.dsh、publishConfig、files 纳入 tools/、壳补丁脚本自动探测安装路径、README 增加三条安装路径与发布清单
0.4.28–0.4.31调试日志:默认关闭,⚙ 菜单一键开关,环形缓冲 + 诊断卡片复制;新增 log 探针;工具行精简为「重新加载 / 外开 / 设置」
0.4.32–0.4.33设置里显示「跨重启保持登录」状态(按 persist: 分区判定并记忆);未开启时提供「复制打补丁命令」
0.4.27文档重写并与实现对齐(README / architecture / 注释);新增 layout 诊断探针
0.4.25删除旧的浮层/测量实现(client.js 3947 → 3243 行),行为不变
0.4.15–0.4.22诊断探针(dom / prefer / openRight)、preferSeat 席位偏好、"哪边点哪边接管"
0.4.13左栏入口直接挂载聊天页(不再渲染入口页)
0.4.0内联宿主:聊天页渲染在席位布局盒里,几何交给 CSS
0.3.0多标签、每服务独立分区与租约、拖动排序、⚙ 设置、ⓘ 诊断

完整改动见 git log。


路线图

  1. 多壳适配:Tauri / window.__DSH_CHAT_EMBED__ 自定义原生视窗协议。
  2. 标签管理:可关闭标签(释放租约)、可配置服务列表(走 Host Config)。
  3. 内存策略:LRU 回收久未使用的标签,切回时重建。

反馈与贡献

  • Bug / 功能请求:在仓库 issue 里描述现象 + 「⚙ → 标签页诊断… → 复制诊断信息」得到的报告(含 build、地址、分区、席位、自检),能大幅缩短定位时间。
  • 补丁:改 client.js(或 index.js / tools)→ npm run check 全绿 → 提交 PR。提交信息英文、文档中文。
  • 本地开发:无需依赖安装,见 开发。
  • 联系方式:fishsummer@126.com。⚠️ 当前仓库未配置远程地址,issue/PR 入口需在配置 remote 后补充。
  • 目前没有邮件列表 / 聊天群组 / 官方网站;相关通知以仓库提交记录与邮件为准。

作者

poluce — fishsummer@126.com(维护者,GitHub 账号同 poluce;完整提交历史见 git log)。


许可证与法律声明

  • 许可证:MIT。Copyright (c) 2026 dsh-chat-embed contributors。
  • 无隶属:与 DeepSeek、字节跳动(豆包)、OpenAI(ChatGPT)、MiniMax、月之暗面(Kimi)、Google(Gemini)、X(Grok)均无关联,相关商标归各自所有。
  • 使用风险:插件只是把各站点装进桌面 webview,登录的是你的真实账号,请遵守各站点的服务条款与当地法律;因使用第三方服务产生的账号、数据、风控问题由使用者自行承担。
  • 免责:软件按"现状"提供,不附带任何明示或暗示担保;作者不对因使用本软件造成的任何损失负责。

Plugin correlati