DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Aliboder /

Aliboder/dsh-folder-sidebar

Verified

Folder-style sidebar for DeepSeek Harness: workspaces read as folders, click one to enter its session list. DSH 文件夹侧栏。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@8833423f

dsh-folder-sidebar

把 DeepSeek Harness 侧栏的「工作区 / 会话」列表换成分文件夹的进入式导航:侧栏先只列工作区(文件夹),点进去才显示该工作区的会话列表,并有返回上一级。会话行首带状态位,文件夹图标本身就是工作区的状态位。

行为

  • 顶栏固定:两级完全相同(标题「工作区」+ 搜索 / 视图选项 / 添加工作区 按钮),位置和结构不变。
  • 搜索集成在顶栏(对齐官方):平时只有一个放大镜按钮;点击后输入框淡入并占据整个顶栏(标题淡出、其余按钮让位,约 150–180ms 过渡,尊重 prefers-reduced-motion),带 ✕ 关闭;Esc 也关闭。输入后列表切换为跨工作区的扁平结果,点击结果打开会话并自动收起搜索。隐藏层不参与 Tab 与无障碍树。
  • 视图选项(对齐官方:排序与显示筛选合并在同一个菜单里,不再分成两个按钮)。菜单分两段:
    1. 排序(标题会写明「排序 · 文件夹 / 会话」,因为两级各自独立):手动顺序 / 按名称 / 按最近活动,外加 正序 ↑ / 倒序 ↓;选中项带 ✓。
    2. 显示:隐藏已归档 / 全部会话 / 仅显示已归档。
    • 两级偏好互不影响,一起存在 localStorage 的 dsh.folder-sidebar.sort({ folders: {mode, dir}, sessions: {mode, dir} }),归档筛选存在 dsh.folder-sidebar.archived。
    • 选模式时会重置到该模式的自然方向:名称 = 正序,最近活动 = 倒序,手动顺序 = 正序;之后可以单独切方向。
    • 方向就是比较器的符号:名称 A→Z / Z→A;最近活动 最早→最新 / 最新→最早;手动顺序 = Host 顺序 / 它的逆序(倒序只影响显示,不改 Host 里存的顺序)。
    • 会话级里「手动顺序」与「按最近活动」等价(会话只有「按最近更新」这一种原生顺序),置顶会话在任何模式下都排最前。
    • 文件夹级只有在「手动顺序 + 正序」下才显示「上移 / 下移」,也只有这时能拖拽(其他情况顺序是派生的,手动移没有意义)。
    • 拖拽排序(对齐官方):文件夹行可直接拖动,落在目标行的上半/下半决定插到它前面还是后面,落点有品牌色指示线;松开即通过 Host 的 workspace 排序接口持久化。搜索中或排序模式非「手动 + 正序」时自动禁用。
  • 第一级:工作区文件夹列表。每行:文件夹图标(兼状态位)、名称、… 菜单、会话数、›。
  • 第二级:进入某个工作区。顶栏保持不变;顶栏下面多一条文件夹行:
    ‹  文件夹名                                      +
    
    点这一行任意位置 = 返回上一级(文件夹列表);点右侧 + = 在当前工作区新开会话(不触发返回)。下面才是该工作区的会话列表。
  • 默认停在当前会话所在的工作区;返回后停在文件夹列表,不会被自动拉回。
  • 搜索:标题匹配即时本地过滤;内容匹配 250 ms 防抖后走 Host 的会话检索,结果带所属工作区与命中片段,点击直接打开。
  • 长名称:放不下的标题在悬停该行时横向滚动(会话行、文件夹行、未分组、搜索结果、面包屑文件名都生效),滚到末尾再回滚;能放下的标题静止不动,prefers-reduced-motion 下不滚动。
  • 侧栏收起成窄栏时只渲染一个文件夹图标,点击展开。

状态位

会话行:最前面一个固定 12px 的状态位(无状态时留空,标题始终对齐)。

占位 含义 来源
转圈(spinner) 正在运行 useSessionStatus 的 running(含摘要的 running)
绿 ✓ 有未读的新完成(你当时没在看它);打开这个会话即清除 useSessionStatus 的 completionUnread
黄 ? 正在等你回答或审批(pendingInteraction) useSessionStatus
红 ! 最近一轮失败或中断(error / blocked / max-tokens / interrupted,及非用户原因的 aborted);下一次开跑才清除 Host 投影 failed / interrupted
空心灰点 你自己按停止(aborted by user) Host 投影 stopped
灰点(实心、淡) 已处理完(读过、没有新完成)、从未运行过 —

会话行与文件夹行共用同一套图形语言:等待是 ?、失败是 !、运行是转圈,完成是绿 ✓,停止与空闲用点——所以两级列表切换时视觉一致。

文件夹行:状态位固定在图标上,只有一个,不额外占位。

图标 含义
转圈(spinner,不是转动文件夹) 有会话正在运行
黄色 ? 有会话在等你回答/审批
红色 ! 有会话最近一轮失败或中断
绿色 ✓ 有会话最近一轮正常完成
空心灰文件夹 有会话被主动停止
普通文件夹 没有可显示的状态

一个文件夹里有多种状态时按优先级取一个:等待 > 运行 > 失败 > 未读完成 > 主动停止;同一优先级里取状态起始时间最早的那个(since 最早;投影缺失时退化为会话 updatedAt)。

悬浮卡:会话行悬停 350ms 列出该会话的全部状态(等待的具体类型、运行、失败、未读完成、停止,最后一行是相对时间);文件夹行悬停列出它包含的状态及各自会话数(如「运行中 ×2」)。悬浮卡不拦截指针,滚动即消失。

为什么完成用「未读」而不是「完成过」:内置 ui-session 的 completionUnread 才是官方的「已处理」判定——它只在看到某个会话从运行变为结束、且当时它不是当前会话时置位,并且每次开启/切到该会话就清除;这个事实只存在于浏览器,永不上报 Host。用它作绿 ✓,读完切走就不会再亮。

为什么红/黄/转圈不用这个:失败与等待是持久事实(turn/end 的 reason、pendingInteraction),与「你是否看过」无关;转圈就是当前 running。红色会在下一次开跑或正常完成时被覆盖,不会因为你看过而消失。

为什么状态要 Host 投影:会话摘要(SessionSummary)只有 running、updatedAt 等字段,没有「最近一轮结果」;唯一可靠来源是会话事件 turn/end 的 reason。插件因此在 Host 侧注册一个 session projection,把最近一轮折叠成 idle / running / completed / failed / interrupted / stopped 并带上状态起始时间 since(stateVersion = 3),Client 从 projectionsBySession[id].values['folder-sidebar/turn'] 读取——值在 Host 算好并增量推送,浏览器不自己翻事件。

与官方实现的对齐情况

官方侧栏由 ui-workspace 的 sessionStatuses() 推导状态、由 ui-primitives 的 StateDot 渲染:

状态 官方做法 本插件 是否对齐
运行中 running → ongoing,StateDot 渲染 14px SVG spinner 同源,转圈 ✅ 已对齐(尺寸也对齐)
等待 pendingInteraction(approval / plan-review / question)→ warning 黄点;优先级最高,运行中也会显示黄 同源,黄点,优先级已改为等待 > 运行 ✅ 已对齐
完成未读 completionUnread → done 绿点;打开该会话即清除 同源,绿 ✓ ✅ 已对齐
空闲 / 已读 idle 时侧栏不渲染点 渲染淡灰点 ⚠️ 有意偏离(按你的要求)
失败 / 中断 官方没有失败状态(StateDot 有 error 色,但侧栏从不使用) 红点,来自本插件 Host 投影 ➕ 本插件新增
主动停止 无对应概念 空心灰点 ➕ 本插件新增
文件夹聚合 官方不聚合(文档明说:折叠分组里等待的行不会点亮分组头) 文件夹图标即状态位,优先级 + 同级最旧 ➕ 本插件新增(按你的要求)
悬浮卡 悬浮卡里列出全部状态的文字标签 同左(含文件夹的状态计数) ✅ 已对齐
归档筛选 / 取消归档 / 撤销 视图选项三选一、归档行不可打开、提示可撤销、搜索结果可取消归档 同左(顶栏漏斗按钮) ✅ 已对齐
未分组 不属于任何工作区的会话进 Ungrouped 同左(列表末尾伪文件夹) ✅ 已对齐
subagent 会话隐藏 侧栏不显示 subagent 来源会话 同左 ✅ 已对齐
操作失败提示 通知通道(Toast / 对话框错误) 底部提示条 ✅ 已对齐
拖拽排序 拖拽重排 + 插入指示线 + 跨组落点 暂用菜单「上移 / 下移」 ⏳ 待做(下一批)

点/圈的几何在官方 StateDot 基础上整体放大一档以便阅读:18px 状态位、12px 点(内圈 60%)、15px 符号;转圈保持 14px(与官方 StateDot 一致)。

菜单(… 按钮或鼠标右键)

会话行:置顶 / 取消置顶、重命名(行内输入,Enter 提交、Esc 取消)、分叉、复制会话 ID、归档。 归档仍在运行的会话时,Host 会拒绝,行内改为「该会话仍在运行,停止并归档?」二次确认。

文件夹行:重命名工作区(行内输入)、在此新建会话、上移 / 下移、删除工作区(二次确认;只删注册,不动会话与文件)。顶部 + 是添加工作区(系统目录选择器)。

两处都支持鼠标右键在指针位置打开同一份菜单;菜单是固定定位浮层,不会被列表裁切,滚动或点击别处自动关闭,Esc 也能关。

会话没有「删除」能力:Host 只提供归档 / 取消归档,所以菜单里是「归档」。

「上移 / 下移」通过 Host 的 workspace 排序接口持久化,改动会同步到内置侧栏的顺序;它只在文件夹级「手动顺序 + 正序」时出现,按名称 / 按最近活动请用顶栏的排序菜单。

安装与生效

从 npm 安装(推荐):

npm install dsh-folder-sidebar
# 或在 DSH 的 Plugin Manager / plugin_manager 里指定 install_bundle 目标 dsh-folder-sidebar

从源码目录安装(本地链接,便于改代码):

  • plugin_manager 的 install_bundle 指向本目录。
  • Client 改动(client.js、locale):刷新页面。
  • Host 改动(index.js——状态色投影):需要完整重启 DSH。

仓库:https://github.com/Aliboder/dsh-folder-sidebar · 包:https://www.npmjs.com/package/dsh-folder-sidebar

归档与「未分组」(对齐官方)

  • 视图选项(顶栏漏斗按钮):隐藏已归档(默认)/ 全部会话 / 仅显示已归档;选择存在浏览器 localStorage(dsh.folder-sidebar.archived)。
  • 已归档会话以半透明行显示、点击不会打开(提示「已归档,取消归档后才能打开」);菜单改为「取消归档 / 重命名 / 分叉 / 复制 ID」;「仅显示已归档」时没有归档会话的文件夹会被隐藏。
  • 归档成功的提示条带撤销按钮,直接取消归档。
  • 未分组:不属于任何工作区(且非 subagent 来源)的会话出现在文件夹列表末尾的「未分组」里,可打开、可归档;它没有「新建会话」(没有工作区可归属)。
  • subagent 来源的会话始终隐藏,与官方侧栏一致。

图标

插件不 import 宿主包(规范也禁止),而是按 ui-primitives 的真实几何复刻:全部 16×16 网格、strokeWidth: 1(官方 Regular 权重)、currentColor。

用途 官方来源
文件夹 IconFolderCloseRegular
行尾进入箭头 IconTriangleRightFillRegular(官方行箭头)
返回 IconChevronLeftOutlineRegular
搜索 IconSearchOutlineRegular
关闭搜索 IconCloseFillRegular
更多 … IconEllipsisOutlineRegular
视图选项 IconSlidersTwoOutlineRegular
置顶 IconPinFillRegular
新建会话 IconNewChatOutlineRegular
添加工作区 IconProjectAddOutlineRegular
完成 IconCheckOutlineRegular(绿)
等待 IconQuestionOutlineRegular(黄)
失败/中断 IconWarningOutlineRegular(红)

失败提示

置顶 / 归档 / 取消归档 / 重命名 / 分叉 / 排序 / 删除工作区 / 添加工作区失败时,底部显示一条提示条(不再只写 console)。

已知限制

  • 没有「展开其余」水位线。
  • 搜索内容命中走 Host 索引;搜索期间列表被结果替代(Esc 清空恢复)。
  • 文件夹状态位只统计当前筛选下可见的会话。

工程结构

  • 纯逻辑(排序比较器、状态优先级、文件夹状态聚合、归档筛选、相对时间、路径 basename)集中放在 client.js 模块顶层,不依赖 React/DOM;文件末尾在 Node 环境(module.exports 存在且 window 缺失)把这份 API 导出,因此 test/logic.test.mjs 加载的是真正发布的那份源码,不是副本。
  • 每个文件夹的会话行用一次 useMemo 建索引(rowsIndex),列表渲染、状态位聚合、悬浮卡共用同一份,避免同一帧内重复过滤排序。
  • 新增测试:test/logic.test.mjs(排序 × 方向、置顶、状态优先级、文件夹聚合、持久化、时间格式化、路径解析)。

文件

package.json          # dsh.bundle.patch + dsh.client + zod 依赖
cordis.patch.yml      # 插入 folder-sidebar 行
index.js              # Host:sessionProjections 单元 folder-sidebar/turn
client.js             # 全部 UI:两级导航、菜单、搜索、状态色
locale/en.json        # 插件列表展示文案
locale/zh.json
icon.svg
test/smoke.test.mjs   # 清单与 id 一致性自检
test/projection.test.mjs # 投影状态机单测(不启动 DSH)

本地验证

node --check index.js && node --check client.js
node test/smoke.test.mjs
node test/projection.test.mjs
—/ 5

No ratings yet

Verified DSH bundle

Commit 8833423f8f70

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout