npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-ws-recency

v0.26.0

Published

Sidebar session management for DeepSeek Harness: workspace groups sorted by latest activity, stale history folded, a global pinned section, follow-up marks, session delete into a recoverable trash, archived sessions managed from that same trash panel, per

Readme

dsh-ws-recency

DSH 侧栏的七件事:工作区分组按最近活跃排序、过期历史自动折叠、运行中/未读/需跟进三色标记、所有置顶会话汇总到顶部一个区、删除会话到可恢复的回收站(归档会话也在同一个面板里管理)、按来源拆分、并将参数与结果分段的 token 消耗统计、把会话移动到另一个工作区,外加跨会话的内容搜索(点结果直接跳到说过那句话的那一轮)。单独装上就有效,不依赖其它插件。

一、分组排序

DSH 已经把组内会话按 updatedAt 倒序排好了(排序方式 = 最近更新),但分组自身用的是工作区注册表的顺序(创建工作区的先后),所以一个刚跑完一堆活的工程可能仍排在侧栏很下面。

做法:从 Client store 读每个工作区自己的会话,取组内最大的 updatedAt;空工作区回落到该工作区的 createdAt;把结果写成各分组元素的 flex order。不碰会话行、不碰原生置顶、不碰归档、不改 store。

二、历史折叠

会话超过 foldDays(默认 3 天)没有更新就折叠起来;整个工作区都过期时,它只剩一行工作区标题——需要翻历史时点开就行。

  • 每组一个控件:宿主的「展开其余 N 条会话」被隐藏,由插件的 展开历史 N / 收起历史 接管。N = 宿主还没渲染的行 + 已折叠的过期行;
    • 点「展开历史」→ 插件逐轮驱动宿主那个隐藏按钮(每轮它会多渲染 5 条,剩下 ≤5 条时一次全出),直到整组都渲染出来,同时展开过期行——一次点到全展开;
    • 点「收起历史」→ 重新折叠过期行(宿主已渲染的部分仍由插件按时间折叠,不会丢失);
  • 选中 / 运行中 / 等待处理 / 标记「需要跟进」 的会话永不折叠——标记就是为了提醒自己去看,收进历史等于白标(选中/运行中/等待处理的豁免可在设置里关掉,跟进标记的豁免始终生效);
  • 空白草稿行(新会话)不参与折叠判断;
  • 每 5 分钟自动重算一次,所以跨过 3 天边界的会话会自己折叠,不用刷新。

三、颜色与“需要跟进”

自动那部分只做能读准的:运行中(蓝)、完成未读(绿)。“看过但没决策”不猜——DSH 只有 completionUnread 一个布尔,点开就清零,猜不准反而制造噪音。

改成反向标记,由你自己打:

| 状态 | 颜色 | 怎么产生 | |---|---|---| | 运行中 | 蓝 | 宿主状态 | | 完成未读 | 绿 | 宿主状态 | | 需要跟进 | 琥珀 | 你在会话「…」菜单点「标记需要跟进」 |

  • 标记存在 Client store 的 followUps(随 dsh.ws-recency.prefs.v1 持久化),重启后还在;
  • 琥珀圆点渲染在宿主自己的 sidebar.session.row.leading 槽里,不往行里塞子元素——塞进去会让后面的行整体下移一格;点圆点即取消标记;
  • 标记只有你手动取消才会消失:运行中/完成未读期间它只是被更强的状态盖住显示,跑完、读完(没有新未读)之后琥珀自己回来;
  • 不受打开时长、会话是否继续对话影响——继续对话恰恰常常是还欠一次跟进的原因。

四、全局置顶区

DSH 原生的置顶只把会话顶到它所属工作区分组的第一行,分组本身仍在原位;一旦分组排在列表下面,置顶了也看不见。

本插件在所有工作区分组之上加一个「置顶」区,把宿主自己的置顶会话(workspaces.pinnedSessionIds)集中列出来:

  • 用的是宿主原生置顶集合,不是第二套置顶:会话「…」菜单里的置顶/取消置顶照旧;
  • 置顶区每行显示标题 + 所属工作区名,点行直接打开;hover 出现「取消置顶」;
  • 置顶期间它在原工作区分组里的那一行隐藏(不重复出现),取消置顶后原行回到原位;
  • 置顶行沿用同一套状态色(运行中蓝 / 完成未读绿 / 需要跟进琥珀),运行状态变化即时更新(0.25.1 修);
  • 工作区分组、组内顺序、折叠、颜色全部照旧;
  • 只在按工作区分组时出现;搜索、扁平视图、侧栏收起时自动隐藏。

五、归档与回收站

归档(宿主动作,本插件只接管管理界面)

归档仍然是宿主原生的:「…」菜单 →「归档会话」。归档只是 archivedSessionIds 里的一个标记:会话从所有分组里消失,但日志还在 sessions/ 里,原工作区的槽位也保留着(取消归档就回到原位)。宿主自己只有「视图选项 → 显示已归档 / 仅显示已归档」能看到它们,没有地方能取消归档或清掉它们。

所以本插件把归档会话也列进回收站面板(侧栏面板列表里的「回收站」,与「插件」「自动化任务」同一排):

  • 面板分两段:已删除的会话(插件的回收站条目)和已归档的会话(宿主的归档集合),都带条数;
  • 归档行显示标题(取投影缓存里的标题,没有就退回第一条 prompt,再没有就退回会话 id)、所属工作区、体积、最后活动时间、原始目录;空白草稿会标「空白草稿」;
  • 每行三个动作:
    • 取消归档:摘掉归档标记,会话回到原工作区的原位置;若它的槽位已经不在了(工作区被删过),会按 cwd 重新挂到同名工作区,挂不上会在提示里说明;
    • 移到回收站:走下面那套正常删除,日志改名搬进 .trash/ws-recency/,之后仍可恢复;
    • 彻底删除:先移进回收站再立即清空,和回收站的「彻底删除」是同一条路径(二次确认);
  • 宿主的归档集合变动会通过它的 workspace feed 推到浏览器,所以取消归档后侧栏会自己把行放回去,不用刷新界面。

删除(宿主没有的,本插件补上)

「…」菜单 →「删除会话(移入回收站)」:

  1. 先停掉它正在跑的工作;
  2. 摘掉归档标记与置顶;
  3. 从每个工作区的记账里 detach(按 workspace.json 的原始记录判断,避免过滤视图漏删);
  4. 删掉投影缓存记录;
  5. 把日志目录移动到 ~/.hypers-work/.trash/ws-recency/<sessionId>-<时间戳>/;
  6. 广播 api-session/removed,浏览器立即移除该行。

不是物理删除:目录只是被改名搬走。每个条目在 .trash/ws-recency/ 下带一份 .wsr-trash.json(会话 id、原 cwd、时间、来源),回收站面板会列出它们:

  • 「恢复」:按记录的 cwd 算回 sessions/<project>/<id>/,并重新挂到对应工作区;
  • 「彻底删除」:真正删掉这份日志(二次确认);
  • 每条记录是一张卡片:标题、来源(已删除 / 移动前的旧副本 / 已归档)、轮次、步骤、token 总量、日志大小、时间、原目录(归档的统计按日志大小缓存,第一次读完后不再重算); 已删除会话的标题与统计在删除时就写进 .wsr-trash.json,旧条目则在第一次打开面板时从日志里补算并缓存;
  • 恢复/扫描/移动之后宿主会广播 api-session/added;面板与「扫描并刷新」都能重载页面(不重启应用)让侧栏立刻看到改动;
  • 移动操作留下的旧副本会标成「移动时的旧副本」,只允许彻底删除;
  • 所有确认(删除、恢复、彻底删除、移动、取消归档)都是页面内弹层,不调用系统 confirm/alert:系统对话框在 Windows 上关掉后会让渲染进程丢掉键盘焦点,表现为输入框点不进去、切换会话也没用,只能切走再切回来(0.24.2 修)。

六、Token 消耗统计

会话下方统计条上的「用量分析」,或会话「…」菜单 →「Token 消耗统计」:

  • 真实账单(每步记录的 usage):步数、输入(未缓存)、缓存命中、输出、合计;
  • 消耗分布图(按内容估算):主 agent 自己(思考 / 回复 / 用户消息 / 系统提示)vs 每个工具,每个来源一条带颜色的横条,按占用长度直观对比;色相由工具身份决定(常用工具人工指定,其余按名字哈希,跨会话稳定),明艳度随占比排名递减;
  • 参数 / 结果两段:每个工具那条横条拆成「参数」(淡色,模型自己写的命令 / 文件内容)和「结果」(实色,环境返回的内容),一眼看出贵在输入还是贵在输出。图例在图右上角;
  • 「参数计入主 agent」开关(设置 → 通用):工具参数严格说是模型写的,不属于工具消耗。打开后每个工具只算返回结果,参数量并入主 agent——实测一个 pwsh 偏重的会话,pwsh 从 37.6% 掉到约 20%,主 agent 从 40.4% 升到约 58%。表格里「参数」列仍在,只是显示为淡色并计入主 agent 那一行;
  • 明细表:调用次数、参数估算、结果估算、合计、占比,按合计降序;
  • 三个 tab(0.25.0):摘要卡片常驻顶部,下面按「分布统计 / 放大归因 / 明细」分页,页面不再一长条。打开时记住上次停留的 tab;
  • 放大成本 / 账单归因(0.25.0):账单 = 每步上下文之和,所以一块内容的真实成本不是它出现时的 token 数,而是「token × 之后还会被重读多少步」。放大归因页给出:每步上下文曲线(面积≈账单)、账单构成(工具结果 / 工具参数 / 主 agent / 用户 / 系统)、以及按内容块排序的放大排行——进入第几步、原始 token、重读次数、放大后 token、占整场账单的百分比,以及「压到 20% 可省多少」。单次 9k 的 read 在 350 步的会话里会放大成 300 万 token(约 3% 账单),这样小数字才能读出结论。压缩之后旧内容不再重读,放大窗口会从压缩点截断。

口径说明:prompt 的 token 是「整段上下文每一步都计费」,没法精确归属到某一条消息,所以「主 agent / 工具」的拆分是按内容长度估算(中文≈1 token/字,英文≈4 字符/token),用来比较占比;总量是真的。放大排行里的块大小同样是估算,但账单总量、每步上下文、放大倍数的分母都来自真实 usage。思维链通常不回传给模型,因此不计入放大排行。数据从会话日志算,跨重启也能看。大会话第一次打开约 1–2 秒(29MB 日志实测 1.2 秒),10 秒内重复打开走缓存。

宿主半(index.js)把统计与删除的路由挂在 webServer 上;如果面板报“宿主半未加载”,说明应用还没重启加载新版本。0.10.1 起面板失败时会带上 HTTP 状态和 /ws-recency/health 的自检结果,便于定位。

七、移动到工作区

「…」菜单 →「移动到工作区…」,选目标工作区即可。

为什么核心做不到:会话属于哪个工作区由它创建时的 cwd 决定,工作区的 attach 会校验「header.cwd 必须等于工作区路径」,而 header 是日志里不可变的第一条记录——所以在核心层面没有任何"改工作区"的入口。

本插件怎么做(宿主侧,唯一的写操作):

  1. 停掉会话;
  2. 通过 persistence 读出全部事件;
  3. 把旧日志目录移进 .trash/ws-recency/<id>-move-<时间戳>(既是备份,也腾出这个 id);
  4. 用新 cwd、原 id 重建日志,再回放全部事件;
  5. 校验新 header 的 cwd;
  6. 把新 cwd 同步到工作区的 header 索引和这个会话的内存对象(否则宿主会用旧目录拒绝 attach),再 attach 到目标(失败就回滚原目录),最后按 workspace.json 的原始记录 detach 旧工作区——工作区自己的 sessionIds getter 会按 cwd 过滤,用它判断会漏掉要删的那一条,导致会话同时出现在两个分组;
  7. 删投影缓存,让它按新路径重建。

只移动会话:对话框里明确提示——它在旧工作区里创建/修改的文件不会跟着走,仍留在原目录(附件与 rewind 快照按会话 id 存,不受影响)。

风险与退路:这是插件里唯一改写会话存储的操作。备份会保留,回滚 = 把备份目录移回 sessions/<project>/<id>。

八、交接到新会话

长期会话的上下文迟早会满,被动压缩往往比"换个新会话、带上交接"更差。交接全程在对话里完成,不弹窗:

  1. 每轮回复底部的动作行(复制 / 点赞 / 分支那一排)或会话「…」菜单 → 交接到新会话:插件把交接指令直接交给宿主的 Session 控制器发送(sessions.using + session.prompt),不写输入框、不模拟按键;
  2. 当前会话的 AI 输出一个 ```handoff 代码块——只写文档路径和要点,不粘贴文档内容;
  3. 抓到代码块后,在该轮回复下方出现一张问询卡片,和工具向用户提问的形态一致:
    • 卡片样式沿用宿主问询卡:标题 + 编号选项 + 底部动作;确认,交接到新会话(默认选中):用宿主的 connectWorkspace 在当前工作区建一个空白会话并打开,再把「前言 + 正文」作为它的第一条消息发出去;
    • 不满意,重新生成一版:让当前会话按同样的要求再写一份;
    • 底部输入框:填写调整意见(例如"多写接口约束、少写历史"),提交后按这些要求重写;
    • 「查看内容」展开只读预览,「放弃交接」收起卡片。
  4. 交接内容另存一份到 ~/.hypers-work/.wsr/handoff/<sessionId>-<时间>.md。

细节想改不用在这里改——新会话里直接说更顺手。轮询最多 5 分钟自动收起。

交接块按 markdown 围栏解析:**只有独占一行的 才算结束**,正文里引用「handoff 块」不会把内容截半(0.23.2 修)。

交接块用 ~~~handoff 围栏(三个波浪线,CommonMark 与反引号等价,宿主自己的 markdown 解析器就用 ~{3,} 识别围栏,展示仍是代码块):正文里提到标记不会切断内容,写了一半的回复也不会被提前抓取;旧的 ```handoff 回复仍兼容。

发送走宿主 API(0.24.1 起):ctx.sessions.using(id, …) 保持会话可寻址,再调 session.prompt([{type:"text",…}], "queue");菜单项也能对不在前台的会话发起交接。只有在 Client 没有 sessions 服务时才退回旧路:写入当前会话的输入框、250ms 后按回车、必要时再补两次;目标会话不在屏幕上时不写错输入框,卡片会提示按回车。

卡片只在这一轮结束之后才出现(0.24.2 修):轮询会比对回复的日志序号与「本轮是否还在跑」,只认点击之后产生、且已经收尾的那条回复——之前它读的是「全日志最后一条非空回复」,只要新轮先落一条工具步骤,就会把上一轮里的旧交接块当成答案,交接刚开始还在处理就弹卡;卡片也只挂在产生它的那一轮下面,不再在每个旧轮下面重复出现。

九、会话内容搜索

会话一长,靠滚动是找不回来的。侧栏的放大镜打开搜索页,输词回车:

  • 搜的是对话正文:你的提问 + 助手的回复;不搜思维链、不搜工具参数和工具结果(那些会让命中被日志噪声淹没);
  • 多个词用空格分隔,要求同时出现在同一条消息里(AND);大小写不敏感,纯字面匹配,不支持正则;
  • 结果按新到旧排列,每条给出角色、会话标题、所属工作区、第几轮,以及带高亮的片段;
  • 点一条结果:打开那个会话 → 滚到对应那一轮 → 闪一下蓝色描边。老会话的历史是懒加载的,插件会自己往上翻直到那一轮出现,最多等 8 秒;
  • 第一次搜索要为每个会话建一次正文索引(存在 ~/.hypers-work/.wsr/search/<sessionId>.json,按日志大小 + revision 决定是否失效)。面板顶部会显示「还有 N 个会话正在建立索引」,每轮补一批、结果自动刷新,之后同一份日志不再重复解码。

设置

设置 → 通用:

  • 历史折叠天数:− / 数字输入 / +(1–90,默认 3),以及“选中 / 运行中 / 等待处理的会话不折叠”;
  • 颜色与跟进标记:颜色标记总开关;
  • 全局置顶区:显示开关;
  • 把工具参数计入主 agent:消耗分布里工具只算返回结果,参数量并入主 agent(默认关闭,即每个工具含参数)。

偏好持久化在 Client store 的 dsh.ws-recency.prefs.v1。

已知边界

  • 依赖宿主 DOM:分组容器带 _groupSection、分组头带 data-row-key="workspace:<id>"、行带 data-row-key="session:<id>"、溢出按钮类名含 sessionOverflowButton。宿主改结构就要跟着改。
  • 折叠只能作用于宿主已经渲染的行;更早的行仍在宿主自己的「展开其余」之后。
  • “未分组”桶永远排在真实工作区之后。
  • 只在按工作区分组(含工作区树顶层)时生效。
  • 可选互操作:如果你另外装着 dsh-plugin-busy-workspace,本插件会尊重它写在分组上的 data-busy-rank,把它的紧急度当主键、档位内部再按活跃度排。没装就是纯最近活跃排序——本插件不依赖它。
  • 搜索是字面匹配,不是全文检索:不支持正则、不排序相关性,结果只按时间倒序;正文外的内容(思维链、工具参数、工具结果、附件)不参与匹配。
  • 搜索索引是插件自己的缓存(~/.hypers-work/.wsr/search/),删掉只会让下一次搜索重新建;宿主自带的 SQLite 全文索引默认关闭,本插件没有去改那个开关。
  • 跳到某一轮靠宿主的 data-chat-turn 行和 [data-conversation-scroll] 滚动容器:宿主改这两个标识,跳转就会失效,搜索本身不受影响。

安装

npm(推荐,升级最简单):

dsh plugin --profile <profile> add dsh-ws-recency

或从 GitHub 直装:

dsh plugin --profile <profile> add github:chyxhtc/dsh-ws-recency

或固定版本的预构建包:

dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.26.0/dsh-ws-recency-0.26.0.tgz

装完把 dsh-ws-recency 加进 ~/.hypers-work/profiles/<profile>/package.json 的 dsh.profile.bundles,重启应用。

本地开发可以直接 link::

dsh plugin --profile desktop add "link:C:\Users\Konka\Hypers Work\workspace\dsh-ws-recency"

自检(桩 DOM / 桩 Host,全部离线跑):

node tests/selfcheck.cjs     # 排序、按天数折叠、分组控件、三色与跟进标记、交接块切分
node tests/stats.cjs         # token 估算、聚合、持久层读取
node tests/move.cjs          # 移动:成功、回滚、守卫
node tests/trash.cjs         # 回收站:列表、恢复、彻底删除、路径守卫
node tests/archive.cjs       # 归档:列表/标题、取消归档、彻底删除、路由分发
node tests/archive-page.cjs  # 回收站页面:两段列表、卡片动作带的 sessionId
node tests/handoff.cjs       # 交接:最新回复、markdown 存档、守卫