🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

归档收藏增强 loyalchiiina/dsh-archive-favorites-forge

DeepSeek Harness
loyalchiiina24 天前有提交已提供中文文档扫描:含敏感能力

为对话补上收藏、复制路径与超时批量归档

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/10 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add loyalchiiina/dsh-archive-favorites-forge
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · chat
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 101 处,展示前 37 条)
  • 读取本地文件
    lib/index.js:127
    const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8'))
  • 读取本地文件
    lib/index.js:160
    const parsed = JSON.parse(readFileSync(statePath(), 'utf8'))
  • 写入本地文件
    lib/index.js:185
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/index.js:189
    writeFileSync(tmp, JSON.stringify(next, null, 2), 'utf8')
  • 写入本地文件
    lib/index.js:190
    renameSync(tmp, statePath())
  • 读取本地文件
    lib/index.js:237
    const parsed = JSON.parse(readFileSync(snapshotPolicyPath(), 'utf8'))
  • 写入本地文件
    lib/index.js:252
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/index.js:259
    writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf8')
  • 写入本地文件
    lib/index.js:260
    renameSync(tmp, snapshotPolicyPath())
  • 读取本地文件
    lib/index.js:286
    const parsed = JSON.parse(readFileSync(archiveDeletePolicyPath(), 'utf8'))
  • 读取本地文件
    lib/index.js:359
    const parsed = JSON.parse(readFileSync(archivePurgePolicyPath(), 'utf8'))
  • 读取本地文件
    lib/index.js:635
    if (existsSync(file)) {
  • 删除本地文件
    lib/index.js:636
    rmSync(file, { force: true })
  • 删除本地文件递归
    lib/index.js:1067
    await rm(sessionDir, { recursive: true, force: true })
  • 删除本地文件
    lib/index.js:1781
    if (existsSync(target)) rmSync(target, { force: true })
  • 删除本地文件
    lib/index.js:1840
    if (existsSync(target)) rmSync(target, { force: true })
  • 删除本地文件
    lib/index.js:1878
    if (!referenced.has(blobName)) rmSync(join(blobsDir, blobName), { force: true })
  • 删除本地文件递归
    lib/index.js:3293
    if (existsSync(legacy)) rmSync(legacy, { recursive: true, force: true })
  • 发起网络请求
    lib/client.js:99
    return fetch(ROUTE + route, init).then(function (res) {
  • 写入剪贴板
    lib/client.js:213
    return navigator.clipboard.writeText(text).then(function () { return true; }, function () { return legacyCopy(text); });
  • 发起网络请求
    lib/client.js:5161
    const resp = await fetch(path, {
  • 读取本地文件
    lib/ungrouped-guard.js:163
    names = readdirSync(dir)
  • 读取本地文件
    lib/ungrouped-guard.js:179
    buf = readFileSync(file)
  • 读取本地文件
    lib/ungrouped-guard.js:378
    const parsed = JSON.parse(readFileSync(env.workspaceFile, 'utf8'))
  • 读取本地文件
    lib/ungrouped-guard.js:448
    if (!existsSync(env.sessionsRoot)) {
  • 读取本地文件
    lib/ungrouped-guard.js:471
    level1 = await readdir(env.sessionsRoot, { withFileTypes: true })
  • 读取本地文件
    lib/ungrouped-guard.js:482
    inner = await readdir(projectDir, { withFileTypes: true })
  • 写入本地文件
    lib/ungrouped-guard.js:916
    await fsRename(file, target)
  • 写入本地文件
    lib/ungrouped-guard.js:1060
    await fsRename(dir, target)
  • 读取本地文件
    lib/snapshot-usage.js:180
    level1 = await readdir(root, { withFileTypes: true })
  • 读取本地文件
    lib/snapshot-usage.js:189
    inner = await readdir(top, { withFileTypes: true })
  • 读取本地文件
    lib/snapshot-usage.js:299
    blobNames = await readdir(blobsDir, { withFileTypes: true })
  • 读取本地文件
    lib/snapshot-usage.js:306
    const info = await stat(join(blobsDir, entry.name))
  • 读取本地文件
    lib/snapshot-usage.js:323
    const [buffer, info] = await Promise.all([readFile(manifestPath), stat(manifestPath)])
  • 读取本地文件
    lib/snapshot-usage.js:323
    const [buffer, info] = await Promise.all([readFile(manifestPath), stat(manifestPath)])
  • 写入本地文件
    lib/snapshot-usage.js:631
    mkdirSync(dirname(target), { recursive: true })
  • 写入本地文件
    lib/snapshot-usage.js:632
    renameSync(dir, target)
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 收藏对话
  • 复制ID与路径
  • 超时批量归档

为 DSH 对话增加收藏、复制 ID+路径、单会话删除、空闲批量归档和收藏筛选,这些都是在已发布归档功能上做的增量插槽扩展,不改动任何官方文件。

README

由 DeepSeek 最新模型翻译生成
dsh-archive-favorites-forge 给 DSH 的对话加上收藏、复制 ID+路径、单条删除、超时批量归档和收藏筛选 —— 全部挂在官方插槽上,不改官方一行代码。 Favorites, copy id+path, per-session delete, idle batch archive and a favourites filter for DeepSeek Harness — additive slot extensions over the shipped archive feature, editing no official file. 效果图 ① 对话菜单 —— 在官方「…」菜单里新增三行:收藏对话、复制 ID + 路径、带二次确认的永久删除: 对话菜单 ② 收藏筛选 —— 在官方「筛选会话」分组里新增两行,把侧栏收窄到「已归档的收藏」与「未归档的收藏」: 收藏筛选 ③ 设置页 —— 超时批量归档、带归档状态的收藏清单、以及批量删除归档中未收藏的对话: 设置页 一句话说明 DSH 自带的归档功能只有「归档 / 取消归档 / 筛选已归档」,没有收藏、没有单条删除、没有复制 ID 或路径、也没有按时间批量归档。这个插件把这些补上,而且一个字都不改官方文件。
展开完整文档(README 剩余 1 节)
dsh-archive-favorites-forge

给 DSH 的对话加上收藏、复制 ID+路径、单条删除、超时批量归档和收藏筛选 —— 全部挂在官方插槽上,不改官方一行代码。

Favorites, copy id+path, per-session delete, idle batch archive and a favourites
filter for DeepSeek Harness — additive slot extensions over the shipped archive feature, editing no official file.

效果图

① 对话菜单 —— 在官方「…」菜单里新增三行:收藏对话、复制 ID + 路径、带二次确认的永久删除:

对话菜单

② 收藏筛选 —— 在官方「筛选会话」分组里新增两行,把侧栏收窄到「已归档的收藏」与「未归档的收藏」:

收藏筛选

③ 设置页 —— 超时批量归档、带归档状态的收藏清单、以及批量删除归档中未收藏的对话:

设置页

一句话说明

DSH 自带的归档功能只有「归档 / 取消归档 / 筛选已归档」,没有收藏、没有单条删除、没有复制 ID 或路径、也没有按时间批量归档。这个插件把这些补上,而且一个字都不改官方文件。

功能总览

| | 中文 | 位置 |
| ① | 收藏对话:归档或未归档的都能收藏,星标即时生效 | 侧栏行「…」菜单 + 行内 ☆ |
| ② | 复制 ID + 路径:一键复制会话 ID 与转录文件绝对路径(两行) | 侧栏行「…」菜单 |
| ③ | 单条永久删除:任意非收藏对话可删,二次确认;删完侧栏立即移除该行 | 侧栏行「…」菜单 |
| ④ | 超时批量归档:把闲置超过 N 小时的未归档对话一次性归档,可一键撤回 | 设置 → 归档收藏 |
| ⑤ | 导出清单:制表符分隔的 txt,含对话名称 / 对话ID / 所属工作区 / 闲置时长 / 最后活动时间;可复制路径或直接打开所在文件夹 | 设置 → 归档收藏 |
| ⑥ | 收藏筛选:「仅显示收藏(已归档)」与「仅显示收藏(未归档)」 | 视图选项 → 筛选会话 |
| ⑦ | 批量删除:一键永久删除「已归档且未收藏」的对话 | 设置 → 归档收藏 |
| ⑧ | 删除护栏:收藏项拒删、越出会话根目录拒删、符号链接拒删、逐条报告、批量上限 | 自动生效 |

安装

dsh plugin --profile <profile> add dsh-archive-favorites-forge

装完必须完全退出 DSH 再打开。宿主半边(lib/index.js)在本代 harness 里没有热重载,客户端 bundle 也在 DSH 启动时就快照了 —— 所以刷新页面拿不到新版,必须重启。

工作原理

lib/index.js 宿主半边 —— 收藏存储、转录路径解析、JSON 路由、带护栏的删除、归档/取消归档 lib/client.js 客户端半边 —— 官方插槽注册 + 一条 DOM 规则

用到的官方插槽(全部来自官方客户端契约):

| 插槽 | 贡献内容 |
| sidebar.workspaces.session.menu.item | 3 行:收藏、复制 ID+路径、删除 |
| sidebar.workspaces.session.row.action | 1 个行内 ☆ 星标 |
| settings.section | 「归档收藏」设置页 |

所有贡献都通过 ctx.slots.inject 注册 —— 也就是「等宿主条目挂载后再注册」的官方契约。
所以插件从不假设侧栏已经起来,也从不持有宿主节点的引用。

唯一的例外是收藏筛选:官方那个「视图选项」菜单是写死的数组,既没有插槽也没有触发器 id,所以这一个控件只能走 DOM —— 做法是找到官方那条筛选行并克隆它。
定位只依赖 role / aria / data-row-key 这些稳定属性,绝不依赖 CSS 模块哈希 (那些类名每次构建都会重新哈希)。

为什么收藏存在文件里,不用 localStorage

渲染进程的 localStorage 是按 origin 隔离的:桌面端、手机端、远程浏览器是三个不同 origin,各自只会看到自己的星标。所以宿主半边把它们持久化到:

~/.dsh/data/dsh-archive-favorites-forge/favorites.json

这样换 profile、重装、两端之间都共享同一份收藏。

为什么删除放在宿主端并带护栏

本代 harness 没有官方的会话删除 RPC —— 官方 UI 从来不删会话。
所以「删除这条对话」在这里的物理含义是:删掉该会话自己那个产物目录(~/.dsh/sessions/ 下)。
这个操作不可逆,因此宿主端在动手前逐项拦:

1. 收藏的 id 直接拒删(在宿主端判定,不只是 UI 不显示);
2. 解析出来的路径越出 sessions 根目录的拒删;
3. 符号链接拒删;
4. sessions 根目录本身拒删;
5. 单次批量受 maxDeletePerCall 上限约束。

每个 id 单独回报结果,所以一条失败不会中断整批。
删除成功后宿主会发出 harness 自己的 api-session/removed 事件,所以侧栏那一行会立刻消失,而不是挂到下次刷新。

配置

| 键 | 默认 | 含义 |
| enabled | true | 宿主路由总开关 |
| maxDeletePerCall | 500 | 单次删除请求的硬上限 |

- id: dsh-archive-favorites-forge
config:
maxDeletePerCall: 200

注意事项与边界

- 会话 id 有两种拼写:session-<uuid>,但磁盘上的产物目录两种都有 (老机器升级后 <uuid> 与 session-<uuid> 并存)。插件所有比较都经过归一化,路径解析也两种都试,所以新老对话都能正确复制出路径。
- 已归档的对话打不开 —— 这是 DSH 官方行为,不是本插件造成的。想读就先取消归档。
- 删除是永久的,会连同转录一起删掉。不会碰你的项目工作目录。
- 空白会话永不作为候选。 「空白」= 从没发过消息的「新会话」占位槽。
它没有内容可归档,而且官方侧栏只显示当前那一个空白会话、其余全部隐藏 ——所以候选清单里出现它的话,你根本无法在界面上核对。
插件已把空白会话从超时归档候选和批量删除集合里都排除,导出时其余对话的命名也与侧栏用词一致(新会话 / 未命名)。
- 候选清单会与「侧栏真正列出的会话」求交集:已归档但侧栏不渲染(没有 cwd)的会话, 既不会被统计,也不会被操作。
- 插件会读 Workspace 注册表来判断会话归属哪个文件夹,但归档/取消归档只走注册表自己的 archiveSession / unarchiveSession 方法,绝不手写状态文件,也绝不改其他插件的内部实现。

开发

lib/index.js 宿主半边 lib/client.js 客户端半边(__ModuleLoader__ bundle) test/probe-client.mjs DOM stub + 宿主探针测试

跑测试:

node test/probe-client.mjs

这套探针不是走过场 —— 它反复抓出了「语法检查通过、人工读码也通过」的真 bug,包括:

- 项目目录名编码器把分隔符折叠成 C--Users(正确是 C-Users), 会让每一次「复制路径」都指向一个不存在的文件;
- 路径解析只试了裸 uuid 目录形式,对目录带 session- 前缀的那些会话静默失败;
- 隐藏规则没有等收藏集合加载完成就生效,可以把整个侧栏清空;
- 归档集合读取失败会连带整个收藏筛选静默失效,因为两个本该独立的闸门共用了同一个标志位。

它对着机器上真实的目录和真实的注册表断言,同时 DOM fixture 逐项照抄官方结构 (包括「选中标记是选中行上那个裸 」这一条)—— 上面每个 bug 都是这么暴露出来的。

许可

MIT。
预览分享卡片长什么样 ↓loyalchiiina/dsh-archive-favorites-forge
分享 · DeepSeek Harness Hub
loyalchiiina/dsh-archive-favorites-forge

为对话补上收藏、复制路径与超时批量归档

这是你的仓库?认领条目

回到顶部