在标题栏用浏览器式标签切换和管理多条会话
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/6 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add miao-ge/dsh-project-tabs该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · browser
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 29 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 标题栏项目标签切换
- 会话状态徽标
- 拖动排序标签
DSH 插件:窗口标题栏里的浏览器式项目标签页——每个会话一个标签,带运行中 / 已完成 / 等待批准徽标,可拖动排序,重启后自动恢复。
README
由 DeepSeek 最新模型翻译生成dsh-project-tabs
给 DSH 桌面端加一排浏览器式项目标签:Windows 原生标题栏里「应用 / 编辑」菜单右侧那块空白,变成一条标签栏。
┌──────────────────────────────────────────────────────────────────────┐
│ 应用 编辑 │ alpha beta × gamma × │ - □ × │ ← 标签栏 ├───────────────┴──────────────────────────────────────────────────────┤ │ 工作区 │ 会话正文(原版界面) │ │ ▸ alpha │ │ │ ▾ beta │ │ └───────────────────┴──────────────────────────────────────────────────┘
安装
用 dsh 自带的插件安装器(推荐):
dsh plugin --profile desktop add dsh-project-tabs
桌面端也可以直接在界面里装:左侧栏「插件」→「添加插件」→ 填包名 → 安装 → 立即启用。
展开完整文档(README 剩余 1 节)
dsh-project-tabs
给 DSH 桌面端加一排浏览器式项目标签:Windows 原生标题栏里「应用 / 编辑」菜单右侧那块空白,变成一条标签栏。
┌──────────────────────────────────────────────────────────────────────┐
│ 应用 编辑 │ alpha beta × gamma × │ - □ × │ ← 标签栏 ├───────────────┴──────────────────────────────────────────────────────┤ │ 工作区 │ 会话正文(原版界面) │ │ ▸ alpha │ │ │ ▾ beta │ │ └───────────────────┴──────────────────────────────────────────────────┘
安装
用 dsh 自带的插件安装器(推荐):
dsh plugin --profile desktop add dsh-project-tabs
桌面端也可以直接在界面里装:左侧栏「插件」→「添加插件」→ 填包名 → 安装 → 立即启用。
从源码装(开发用): 克隆本仓库然后
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\install.ps1
默认装进 desktop profile(-Profile web|both 可选,-Uninstall 卸载,幂等可重跑)。
客户端半边改完硬刷新页面即可,宿主半边改完要重启桌面端。
一个标签是什么
一个标签 = 一条会话(session)。标签上只显示工作区(项目)标题;左边的状态点告诉你它现在在干什么:
| 状态点 | 标签配色 | 含义 |
| 转圈 | 品牌蓝底(选中时) | 正在跑 |
| 黄点 | 黄底 | 在等你审批 / 回答 |
| 对勾 | 绿底 + 加粗 | 已经跑完,你还没看过 |
| 灰点 | 中性 | 空闲 |
界面其余部分完全是原版:左侧工作区列表、右侧面板、会话正文、输入框都不变。
标签只决定「中间那一栏显示哪条会话」。
用法
| 操作 | 结果 |
| 点标签 | 切到那条会话 |
| 点标签上的 × / 中键点标签 | 关掉这个标签(不动会话、不动工作区) |
| 拖标签 | 调整顺序 |
| 右键标签 | 关闭 / 关闭其他 / 关闭右侧 / 复制项目路径 |
| 点 +(紧跟在最后一个标签后面) | 选一个已有项目,或「选择目录…」挑一个新目录 → 在新标签里打开 |
| 在左侧工作区行上右键 | 「在新标签中打开」(由 dsh-sidebar-context-menu 提供这一项) |
侧边栏点会话时会怎样:如果那条会话已经有标签,就跳过去;否则在当前标签里打开 (不会越点标签越多)。所以标签数量和你的项目数是同一个量级。
为什么切标签不像「在重新加载」
一开始确实像:0.2.0 里 mainView 只保留一条会话,切走的会话会被 release 掉本地 generation —— 它的 SessionBinding、已加载的历史窗口、实时 tail 全部销毁。
再切回去是冷开(openState: 'loading'),界面上就是「重新加载了会话内容」。
所以本插件对每一个后台标签都额外持一个
sessions.retain(id, { source: 'projectTabs' }):历史窗口和 tail 一直活着,切回去时
ConversationMainPanel 直接是 active 相位 —— 不闪、不等,落点就是你上次读的那条消息。
在跑的标签优先保留,最多同时保 MAX_WARM_TABS = 10 个(每个保活标签 = 一条实时事件流)。
滚动位置本身由平台记着:dsh-client-ui-chat 的 chatScrollPositions 以 sessionId 为键存 { anchorKey, anchorTop, scrollTop },切走时保存、切回时锚回那条消息(dsh-client-ui-chat/lib/client.js:12327 / 4313 / 4656 / 4964)。
还差什么(诚实说明):这是「从热数据里重新渲染一遍」,不是「页面一直挂在那儿」。
所以 React 组件局部状态仍会复位 —— 最明显的是你展开的工具卡片 / 思考块会收起。
要连这个都保住,就得把每个标签的会话同时挂载,而 0.2.0 不允许复用官方的 main.conversation / conversation.header(renderSlot 有所有权校验),必须自己重新渲染正文并放弃官方标题栏(面包屑、标题动作、右侧面板开关、View 标签页),代价明显。
真要做到「浏览器那样的独立页面」,只有 iframe 一条路,而桌面壳不允许(preload 不在子框架运行)。详见文末「已知限制」。
标签列表持久化在 localStorage(dsh.project.tabs.v1),重启桌面端会恢复。
非 Windows / 浏览器里怎么办
插件会检测 html[data-windows-titlebar]:
- 有(Windows 桌面):贴进那 40px 标题栏,避开原生菜单和窗口按钮,不动页面布局。
- 没有(macOS 桌面 / 浏览器):降级成中栏顶部的一条 36px 标签栏,同时给中栏加 padding-top 把内容推下去;卸载时撤销。
和另一个插件的关系
本插件对外提供一个客户端服务 projectTabs(另有一份 window.__DSH_PROJECT_TABS__ 兜底),让 dsh-sidebar-context-menu 的右键菜单能加「在新标签中打开」:
js
const tabs = ctx.get('projectTabs') ?? globalThis.__DSH_PROJECT_TABS__;
const sessionId = await tabs.openWorkspaceInTab(workspaceId); // 连接工作区 + 开标签 + 切过去
tabs.openSessionInTab(sessionId); // 直接给某条会话开标签
tabs.listTabs(); // [{ id, sessionId }]
没装那个插件时,本插件完全独立工作。
实现要点(改代码前先读)
- 挂载点:shell.overlay 是唯一一个「root 作用域 + list + replaceRisk:none」的全窗口浮层插槽。Windows 下 frame 有 padding-top: var(--dsh-windows-titlebar-height),而绝对定位的包含块是 padding box,所以 top:0 正好落在那 40px 里。
- 别抢地盘:原生菜单宿主是 [data-windows-menu](桌面 preload 用 shadow DOM 画的, left: var(--dsh-windows-menu-start,48px)),运行时量它的 rect;右上角窗口按钮用
env(titlebar-area-*) 探针量。原生菜单宽度会随界面语言变,所以挂了 ResizeObserver。
- 切标签 = ctx.uiWorkspace.openSession(sessionId):0.2.0 里「当前显示的会话」就是 retainedBy.mainView > 0 的那一条,openSession 同步换掉这个引用。
- 不依赖构建:bundle 是 classic script,只调 window.__ModuleLoader__.load。
require() 用的是平台静态模块表(react、react/jsx-runtime、react-dom/client、
client-store、ui-slots、ui-primitives、ui-dockkit),所以不需要打包器。
- 宿主半边 lib/index.js 是故意空的:它存在的唯一意义是让 @deepseek-ai/dsh-client-modules 能从 Loader 条目里扫描到本包的 dsh.client 声明,这样 lib/client.js 才会作为 /plugins/dsh-project-tabs/client.js 提供给页面。
测试 powershell
node scripts\smoke-test.mjs
离线跑,不需要浏览器 / 联网 / 安装 React:自带一个迷你 hook 运行时,把 react/jsx-runtime 的产物当普通对象树来断言。覆盖模块加载、清单要求、 apply 接线、标签 store 的全部动作、组件渲染与回调,以及几处副作用(标题栏几何 / 降级布局 / 后台保活 / 跟随侧边栏 / 清理消失的会话)。
已知限制
- 左侧工作区列表是全局共享的(它本来就是全局列表,内容在每个标签下都一样)。
- 展开/收起的工具卡片在切换标签后会复位 —— 这是「重新渲染」而不是「一直挂着」的唯一可见代价,也是下面那条路要解决的问题。
- 右侧面板跟着当前会话走。
- 打开 + 菜单时会列出全部工作区;工作区特别多时列表会很长(会按视口夹取)。
- data-windows-titlebar 与原生菜单都是桌面端的实现细节;如果 DSH 改了标题栏结构,标签栏会退回「中栏顶部」那种降级布局(不会报错)。
为什么不做成「真·多页面」(iframe / 同时挂载)
用户最初想要的是「每个标签就是一份完整独立的页面」。桌面端做不到插件级实现,原因:
1. 桌面壳不允许在子框架里启动客户端:主窗口 webPreferences 没有开 nodeIntegrationInSubFrames(lib/main.js:11099-11107),所以 iframe 里没有 preload,拿不到 dsh-desktop:boot 的注入,那份 DSH 根本起不来。window.open 也被 setWindowOpenHandler 直接 deny(:11109-11112),插件开不了新窗口。
唯一的绕法是让 iframe 走宿主的 SPA 回退去拿带注入的 index,再靠 webServer.tapIndex 塞一个 __DSH_TRANSPORT__.streamBaseUrl(否则 WebSocket 连不上,见 dsh-api-gateway/lib/client.js:730)—— 这依赖若干未公开行为,DSH 一升级就可能坏,而且每个标签是一整份客户端(内存按标签数线性增长)。
2. 同时挂载多条会话技术上可行(ui-subagent 的侧边栏聊天就是这么做的:
sessions.retain(source:'sidebarChat') + SessionProvider +
renderFactorySlot('conversation.content', { variant: 'embedded' })),
但不能复用官方的主会话外壳:main.conversation / conversation.header / conversation.session.header 都是 single/有所有权校验的槽,第三方只能重新渲染正文,于是会丢掉官方标题栏(面包屑、标题动作、右侧面板开关、View 标签页)和宽度拖拽条。
这和「和原版界面完全一样」是矛盾的。
当前方案选了「官方外壳 + 热数据重渲染」,在保真度和成本之间取平衡。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
miao-ge/dsh-project-tabs
在标题栏用浏览器式标签切换和管理多条会话
相关插件 · 浏览器
智能体插件框架deepseek-ai/deepseek-harness
DeepSeek Harnessdsh是由 DeepSeek AI 开发的开源 agent harness智能体框架。
★ 270,422已汉化DSH
71.9
多设备 Agent 看板YaoApp/yao
✨ 所有 Agent 和工作区集中管理,覆盖你的每一台设备。任务看板追踪进度,桌面端、移动端、浏览器、API…
★ 8,147已汉化DSH
71.2
可扩展侧边栏工作台omdsh-dev/DSH-better-sidebar
DSH 的双工作台:原生右侧栏 + 自绘底部面板,并把 ctx.betterSidebar 服务开放给所有插件
★ 4,761已汉化DSH
71.1
浏览器自动化桥Tencent/BrowserSkill
你的 Agent。你的浏览器。连接,就能协作。
★ 9,967已汉化DSH
71
AI 小说创作工作台EthanYoQ/AI-Novel-Writer
AI 小说作家 / AI Novel Writer
★ 1,591已汉化DSH
70.7
智能体浏览器引擎platonai/Browser4
DeepSeek Harness 集成
★ 1,175已汉化DSH
70.4
这是你的仓库?认领条目