Skip to content

dsh-pinned-sessions

Verified

dsh-pinned-sessions · v0.2.0 · MIT · Web UI

Keeps running, finished-but-unopened and currently open sessions at the top of the DSH Web sidebar workspace list.

Install

dsh plugin add dsh-pinned-sessions

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Tags

Creators

Readme

dsh-pinned-sessions(置顶会话)

反馈 / Feedback:遇到 bug 或有改进建议,请到 Issues 提;也可以直接发邮件到 [email protected]。

把你不该跟丢的会话固定在 DSH Web 侧栏工作区列表顶部,并且允许从任意会话/工作区自己的「...」菜单里全局置顶。

English | 中文

置顶区里有什么

顺序如下,位于区域标题下方、所有工作区分组上方:

侧栏
├─ 工作区              ← 区域标题(搜索 / 视图选项 / 添加工作区)
├─ 置顶                ← 本插件插入
│   ├─ 全局置顶 2       ← 从会话「...」菜单置顶的会话
│   │   ● 会话标题…            proj
│   ├─ 进行中 1         ← 由会话状态推导
│   │   ● 会话标题…            other
│   ├─ 待查看 1
│   ├─ 当前打开 1
│   └─ 置顶工作区       ← 从工作区「...」菜单置顶的工作区
│       ▸ proj  4
├─ 工作区分组一         ← 被置顶的工作区在这里消失
└─ 工作区分组二
  1. 全局置顶的会话:从会话「...」菜单置顶;同时仍保留在下方它自己的工作区分组里。

  2. 进行中 / 待查看 / 当前打开:由会话状态推导:

    分组 判据 圆点
    进行中 会话状态 running === true 蓝色呼吸点
    待查看 会话状态 completionUnread === true(跑完但你还没点开) 绿色点
    当前打开 会话被主视图持有(retainedBy.mainView > 0) 空心环

    一个会话只进其中一个分组(优先级如上)。被全局置顶的会话不再出现在这些分组里——它的状态由置顶行前面那个点表示。

  3. 全局置顶的工作区:从工作区「...」菜单置顶;在置顶区里渲染成可展开的分组,里面的会话可直接点开,而该工作区在下方列表里的原分组会被隐藏。

已归档会话、subagent 子会话不出现。组内按最近更新倒序;空的部分不显示;所有部分都为空时整段不渲染。点击行即打开该会话。

置顶区只在「按工作区分组 / 工作区树」模式下显示;侧栏收起成图标栏、切成「一张扁平列表」、或列表正在显示搜索结果时自动隐藏——而且它隐藏时不会隐藏下方任何东西。

置顶与取消置顶

  1. 会话「...」菜单里新增 全局置顶 / 取消全局置顶:这是 DSH 官方槽位 sidebar.workspaces.session.menu.item 里的真实菜单项,和自带的置顶、重命名、分叉、归档并列。
  2. 工作区「...」菜单里同样新增这一项。DSH 没有为工作区菜单声明槽位,所以这一项是插件门户注入进那个弹层的——靠打开行的 data-row-key="workspace:<key>" 定位。
  3. 置顶会话行与置顶工作区标题行悬停时右侧都有取消置顶的 ×;工作区那个是必需的,因为它原来的行在置顶期间被隐藏了。

置顶区插在列表自己的滚动容器最前面,所以置顶项很多时,它和工作区分组共用同一个滚动条,不会被自己裁掉。

开关

设置 → 通用 → 置顶会话区。偏好(开关、置顶的会话、置顶的工作区、哪些置顶工作区是折叠的)持久化在共享客户端 store,localStorage 键为 dsh.pinned-sessions.prefs.v1。

安装

npm:

dsh plugin add dsh-pinned-sessions

Release tarball:

dsh plugin add https://github.com/TianYa-DAO/dsh-pinned-sessions/releases/latest/download/dsh-pinned-sessions-0.2.0.tgz

桌面版可在「插件」页里安装。包内声明了 dsh.bundle,profile 会挂载它的 cordis.patch.yml 行,客户端注册表随之为浏览器提供 ./client.js。

实现要点

  1. 纯客户端插件:client.js 通过动态客户端模块协议(window.__ModuleLoader__.load)加载;overlay 行注册进增量槽 shell.overlay,由它承载下面两个 portal。
  2. 侧栏工作区区域(sidebar.workspaces)是 single 槽、区域内部没有可插入的插槽,因此本插件不改动也不替换自带浏览器:自己创建一个 host 元素,插到 div[data-slot="sidebar.workspaces"] 内列表自己的滚动容器(带浏览器 list 类、即 overflow-y: auto 的那个元素)最前面。插件卸载时 host 被移除。
  3. 位置与模式判定全部通过稳定的 DOM 事实完成:listArea 类名定位列表区;projectRow / searchResultRow 行类名区分工作区分组 / 扁平列表 / 搜索结果;根节点上的 rail 类名判定侧栏收起。MutationObserver 负责结构变化,1.5s 轮询兜底区域被整体替换的情况。
  4. 工作区菜单项被 portal 进打开菜单的弹层;弹层是 React portal 到 document.body 的,它属于哪一行由 data-row-key 加打开态类名确定。
  5. 数据来自客户端根标准 hook:useSessions / useSessionStatus / useWorkspaces;打开会话走 ctx.get("uiWorkspace").openSession(id)。
  6. 样式只用自己的 dshps-* 类,颜色全部取自 --dsw-alias-* 主题 token,跟随主题/皮肤。客户端半只依赖平台模块(react、react-dom、@deepseek-ai/dsh-client-store、@deepseek-ai/dsh-client-ui-primitives),所以本包没有任何安装期 npm 依赖。

自检

npm test

用桩化的动态模块协议加载 client.js,校验:工厂与导出形状、apply() 的三次注册(槽位 / id / order / 共享 store / inject face / 双语字典)、分区推导(优先级、归档与 subagent 过滤、空会话、显式置顶、置顶工作区)以及渲染树。

已知限制

  1. 依赖自带客户端的 DOM 与类名(listArea / projectRow / searchResultRow / rail / list)。DSH 若重构侧栏结构,需要同步更新 client.js 里的锚点选择器。
  2. 工作区「...」菜单项是注入的(DSH 没有该槽位);那个弹层的结构一变,就要同步更新 client.js 里的定位逻辑。
  3. 客户端包版本变化(如方法或 hook 改名)可能导致注册失败;client.js 对 uiWorkspace 缺失做了降级告警,不做静默失败。
  4. 实测环境为 DSH 0.2.0-rc.2。

许可

MIT