dsh-worksop-plus
v0.1.9
Published
DSH web plugin: enhanced workspace panel — pin, groups, hide, filter and bulk actions for the session sidebar
Readme
dsh-worksop-plus
DSH Web GUI 左侧「工作区」面板的增强版本:置顶、自定义分组、隐藏、筛选、批量整理。
系统面板本身只能按「工作区」或「扁平列表」两种方式浏览,工作区一多就没法组织。这个插件接管整块区域,把组织方式变成你自己定义的:置顶区永远在最上面,命名分组可以折叠、排序、着色,暂时不关心的项目可以隐藏而不是删除。
能力
- 置顶:★ 置顶的工作区进入独立置顶区,可折叠;置顶顺序 = 最近置顶优先。
- 自定义分组:新建 / 重命名 / 删除 / 上移下移 / 8 色标记;工作区可移入分组,也可不分组。
- 四个桶都能折叠:置顶 / 各分组 / 未分组 / 已隐藏 都可点标题折叠,折叠状态持久化在 settings(跨浏览器一致);折叠只影响显示,成员归属与计数不变。
- 折叠组压成 chip:折叠的任何一个桶(含未分组、已隐藏),而是 26px 的 chip 式小标题(品牌色 6% 底 + 22% 描边 + 全圆角,与展开卡同一套配方);分组顺序不变,展开的那个仍然是完整 caption + 内容。
- 分组筛选(定宽 chip 行):顶部固定
全部 / ★置顶 / 分组 ▾ / +—— 分组数量再多,这一行也不增长;所有分组连同「未分组」收进下拉菜单,每项带计数与勾选,激活后该 chip 显示所属分组名并高亮。 - 隐藏:不想看见的项目隐藏即可(不动 Host 注册、不删目录),需要时可临时展开「已隐藏」。
- 筛选与排序:本地搜索匹配工作区名、路径与会话标题;排序支持 宿主顺序 / 最近活动 / 名称 / 手动顺序(拖拽写入)。
- 一键回退:面板「排序」菜单里选「使用系统面板」,或在侧栏底部点「工作区增强」开关,立刻回到系统面板(系统注册从未被移除,切换是瞬时的)。
- 状态一眼可见:工作区行、分组/分区标题都带状态点——琥珀=等你确认(授权 / 计划 / 回答,优先于运行中)、蓝色=运行中、绿色=有未查看的完成,同类多于一个时带数字;折叠起来的项目和分区同样显示,不用展开就知道哪块等你。会话行用系统同源的
StateDot;待处理状态读槽位标准 prop——DSH ≥ 0.1.6 的useSessionStatus(Map<SessionId, SessionStatus>,请求在pendingInteraction里),更早版本回退到useSessionPendingInteraction(Map<SessionId, interaction>),两种快照都直接支持。 - 会话操作:展开工作区即可看会话与运行状态点;点击打开、右键或行内 ⋯ 归档、重命名、fork。每个工作区默认显示 5 条会话,超过则给「还有 n 条 / 收起会话」。
- 会话级拖拽排序:会话行可拖动重排(同工作区内,宿主持久化走
insertSessionBefore,带插入指示线);跨工作区拖动会被拒绝而不是报错(宿主只支持在既有账目内移动)。 - 扁平列表视图:排序菜单里可切「按工作区分组 / 扁平列表」——后者把所有会话按时间/名称平铺,每行尾部标出所属项目,chips 相应收敛成一个计数。
- 活跃定时任务:会话带
schedule投影时行内显示时钟图标。 - 应用内目录浏览器:
+打开面板自带的目录浏览(面包屑 + 子目录列表 + 新建文件夹 + 隐藏项淡显),在远端浏览器/无 GUI 宿主上也能用;对话框里另有「系统选择器」回到宿主原生选择器。 - 多选整理:排序菜单开「多选整理」后点行勾选,顶部一栏批量 置顶 / 取消置顶 / 移入分组 / 隐藏 / 全选。
- 拖拽:把工作区行拖到分组标题即移入该组;拖到同一分区内的另一行按落点上下重排(2px 品牌色插入指示线),并自动切到「手动顺序」——每个分区各自记住自己的顺序(新成员按宿主顺序追加在尾部);拖分组标题重排分组。
- 宿主内容搜索:搜索框输入并发调用宿主
sessions.search(250ms 防抖 +AbortController取消),本地标题/路径没命中但正文命中的会话进「内容匹配」分区,带所属工作区名与命中片段,结果过多时给出收窄提示;搜索期间被过滤空的分区自动收起。 - 子代理 lineage:运行中的子代理按
parentId汇总到父会话,父行显示↳n角标(悬停说明「n 个子代理运行中」);子代理不再作为顶层行出现。 - 右键即菜单:工作区行与会话行都支持右键。菜单用产品原语
Menu(portal+getAnchorRect,右键喂合成 rect)渲染,键盘导航/定位/次级菜单交给产品组件;seed 模块缺失时回退到内置 popup。 - 分组 emoji:分组编辑对话框里从 16 个 emoji 预设挑一个(或清空),与 8 色标记并存。
- 导入 / 导出:排序菜单里导出配置(先试剪贴板,失败则弹文本框),导入则粘贴 JSON 覆盖当前组织方式。
- 置顶同步到系统顺序:一次调用
insertBefore把置顶项写进宿主工作区顺序,TUI 与其他前端也能看到。
视觉
面板的视觉语言吸纳自本仓库的 Material You 皮肤(dsh-skin-material-you):皮肤的 sidebar.css 本来就在打磨这块面板,但它选择器打的是系统面板的 DOM,插件接管后就不再命中,所以这里把同一套配方落进插件自己的类名:
- 展开的工作区是一张 tonal 卡片(品牌色 6% 底 + 22% 描边 + 16px 圆角),折叠的则是平铺行、靠留白分界(皮肤原始注释里明确否掉了分隔线和堆叠卡片);
- 会话行缩进在所属工作区下,并用 2px 引导线挂在 caret 列上;选中会话是品牌色 10% 的 tonal pill,引导线同步高亮;
- 会话数跟在项目名后作
(n)(无底色的 tertiary 小字,名字过长时随省略号一起收在名字后面),时间是固定 46px 右对齐的 tabular 列,右栏不会随数字跳动; - 悬停是 5–6% 的中性态层;行内操作按钮走绝对定位悬浮栏,不占用布局宽度,工作区名因此能多显示约 50px;
- M3 token 一律
var(--m3-*, fallback)读取,颜色全用--dsw-alias-*,因此装了皮肤更一致、不装也成立,明暗主题自适应。 - 图标用产品自己的图标组件(
@deepseek-ai/dsh-client-ui-primitives,浏览器 seed 模块,运行时require):文件夹开/合、箭头、搜索、更多、勾选、删除、排序全部与系统面板同源;只有「置顶星标」因官方图标集没有对应形状而内置,并带同风格的兜底。
实现要点
- 浏览器半注册
sidebar.workspaces槽位,priority: -1覆盖系统面板(系统注册仍在 ledger 上,本插件被停用或关闭开关后系统面板立即回来)。同一半还注册sidebar.footer.action的常驻开关,保证面板关掉后仍能打开。 - Host 半只做一件事:注册
worksop-plussettings 命名空间。数据落在~/.dsh/settings.yaml的worksop-plus:段,经ctx.settingsScope在浏览器与服务端双向同步(官方 settings 通道,无需自建 HTTP 路由),浏览器再叠一层 localStorage 缓存保证首屏不闪烁。 - 不写 Host 注册表:
@deepseek-ai/dsh-workspace的记录 schema 会剥离未知字段,且其 storage domain 只能开一次,所以置顶/分组这类视图偏好属于 settings,而不是 registry。 - 只存储稳定的
workspaceId(uuid),不存路径或标题:工作区改名、改路径都自动跟随;已被删除的工作区会在下次读取时惰性清理。
安装
dsh plugin --profile web add dsh-worksop-plus # 发布版
# 开发期可直接 link 本地目录
dsh plugin --profile web add link:/path/to/melon/packages/worksop-plus装好后刷新页面即可;lib/ 由 pnpm --filter dsh-worksop-plus build 产出。
开发
pnpm --filter dsh-worksop-plus build # esbuild 打包浏览器半 + 拷贝 host 半
pnpm --filter dsh-worksop-plus test # bun test:视图派生纯函数单测
pnpm --filter dsh-worksop-plus smoke # 真实驱动 lib/ 产物
node packages/worksop-plus/scripts/preview.mjs # 离线视觉预览(打开 lib/preview.html)scripts/preview.mjs 把构建产物里的真实组件静态渲染成一张对照页(四列:基线 / 拖拽高亮 / 多选整理 / 分组编辑),不需要起 dsh、不需要登录。它按 hook 序号注入组件状态(第 8 个 useState 是批量模式、第 5 个是对话框……),所以条件渲染的分支也能静态看到;改样式或改交互时先看它再交付。
src/derive.js是全部视图规则(置顶/分组/隐藏/筛选/排序/时间)的纯函数实现,单测覆盖它。src/client.js只负责 React 渲染、槽位注册与 settings 读写;src/host.js只有 schema 与命名空间注册。
