dshbase

插件目录 / Desktop / dsh-desktop-archive-manager

dsh-desktop-archive-manager

已验证 · 实测可装 baom1ng

✓ 持续维护 基于 1 个官方 DSH 包

查看 GitHub ↗ ← 返回插件目录

0Stars
0Forks
0未关闭 issue
JavaScript语言
2026-10-04最近推送
跨平台平台

功能简介

在 DeepSeek Harness 桌面端管理已归档会话:侧边栏「归档」面板浏览/恢复/批量删除,会话行菜单「永久删除」;主机端直接清理会话日志、投影缓存与归档标记,无需给 harness 打核心补丁。仅桌面端。

✅
我们的评价
可用 — 实测通过,早期项目

在 DeepSeek Harness 桌面端管理已归档会话:侧边栏「归档」面板浏览/恢复/批量删除,会话行菜单「永久删除」;主机端直接清理会话日志、投影缓存与归档标记,无需给 harness 打核心补丁。仅桌面端。 实测能干净安装、正常启动。早期项目,但功能可用。

「已验证」表示我们的自动化 CI 在干净 profile 里实际执行了 dsh plugin add 并启动成功——仅此而已。功能描述与版本兼容性均为作者声明。这不是安全审计,也不代表对第三方代码的背书。

README

dsh-desktop-archive-manager

English | 中文

dshbase verified

Manage the archived Sessions of DeepSeek Harness: browse them, restore them, and delete them permanently — the surface the harness itself does not ship. Written for the desktop app, and it works in any web-capable profile.

The harness archives Sessions but never deletes them. The shipped ui-workspace package states the limit outright:
"No Session deletion — sessions can be archived but never deleted."
This plugin fills that gap without patching the harness core — it works on a stock install.

Requirements: the DeepSeek Harness Desktop app (developed against 0.2.0-rc.2), or any Harness profile with a web UI. The bundle row carries
no disabled gate — it activates in every profile, and the web surface (host route plus browser half) simply stays quiet where no webserver runs.

How it differs from the existing session-archive-manager:
that plugin adds workspace.deleteSession by patching the harness core and therefore needs a source checkout or a forked build.
This one adds no core API: its host half removes the stored artifacts itself, so it installs into the shipped desktop app as-is.


1. Install and uninstall

From the app: Settings → Plugins → Local plugins

Install the companion dsh-local-plugin-source once and the local plugin
folder (%USERPROFILE%\.dsh\local-plugins) becomes an in-app source:

Button What it does
Install / Reinstall installs and enables the bundle (reinstall after editing local source)
Enable / Disable toggles the bundle layer, keeping dependencies and files
Remove runs pnpm remove through the profile's own Plugin Manager

From a package spec

The sidebar Plugins → Add plugin dialog accepts a package name, a git URL, a tarball, or a local absolute path:

dsh plugin add dsh-desktop-archive-manager                 # after publishing to npm
dsh plugin add github:<you>/dsh-desktop-archive-manager    # straight from GitHub
dsh plugin add C:\path\to\dsh-desktop-archive-manager      # local folder

Any of these goes through the profile's own installer: pnpm add <spec> → validate dsh.bundle.patch → append the package name to
dsh.profile.bundles in the profile's package.json → recompose and activate (no restart).

Uninstall

Remove the bundle from the Plugins page (or dsh plugin remove dsh-desktop-archive-manager): the bundle selection is dropped,
the Loader row is unloaded, and pnpm removes the package. The plugin keeps no global state, so nothing is left behind — except the
Sessions it deleted.

2. What you get in the UI

Seat Content
Sidebar panel icon (sidebar.panellist, order 30) an Archives icon that opens the manager
Main panel (main, key archive-manager) the archive list: filter, select all, batch restore / batch delete, per-row restore / delete, total size on disk
Session row "…" menu (sidebar.workspaces.session.menu.item, order 900) Delete permanently on an archived Session
Frame overlay (shell.overlay) deletion confirmation (must tick the acknowledgement) plus the result toast

Localized in English and Simplified Chinese (locale namespace archive-manager).

3. What a deletion actually removes

Per Session, the host half touches exactly three things:

  1. The Session log directory — <root>/<project directory>/<sessionId>/, including every stored format generation
    (session.v4.jsonl.zstd, .v3, .v2, …). The path comes from the persistence backend's own locate(); when a backend
    cannot answer, the plugin falls back to scanning <root>/*/<sessionId>/.
  2. The projection-cache record — that Session's row in the session_projcache domain, deleted through the domain API
    (ctx.storageDomain), never by writing the JSON file behind its back.
  3. The archive mark — removed from archivedSessionIds in workspace.json, which also refreshes the sidebar.

Nothing else is touched: project directories, other Sessions, attachments and workspace records stay as they are.

Safety gates

  • only Session ids that are currently archived are accepted — anything else is refused with archive-manager/not-archived;
  • a Session id must be one safe path segment (regex-checked, .. refused), so path traversal is impossible;
  • a Session with running work is refused (workspace/session-activity plus a live-Agent status check);
  • the API is one exact route with a same-origin check (Origin header + a custom request header); it never touches the /api trust boundary.

4. Sessions that are still live in memory

A Session may have been created or opened during the current run, so the process still holds it (Agent/Session in memory, write
handle claimed). Removing the files works, but the row cannot disappear yet — and unarchiving it could wake a Session with no log.

Session state Behaviour
Cold (untouched in this run) files removed → cache removed → archive mark dropped → the row leaves the sidebar immediately
Live (still held in memory) files removed → cache removed → archive mark kept (the archived gate keeps blocking new turns) → the row stays in the archive view marked "Deleted · cleans up after restart"

At every startup the plugin runs one prune: archive marks whose Session is neither stored on disk nor live in the process are dropped,
so whatever a live Session left behind disappears by itself on the next start.

5. Package layout

dsh-desktop-archive-manager/
├── package.json          # dsh.bundle.patch + dsh.client (both halves in one package)
├── cordis.patch.yml      # bundle patch: inserts the desktop-archive-manager row (no disabled gate)
├── lib/host.js           # host half: the Cordis plugin and POST /archive-manager/api
├── lib/client.js         # browser half: a prebuilt __ModuleLoader__ bundle
├── lib/core.js           # dependency-free deletion core (unit-tested)
├── test/*.test.mjs       # node --test suite (38 tests)
├── LICENSE
└── README.md / README.zh.md

The two declarations that make it a plugin:

"dsh": {
  "bundle": { "patch": "./cordis.patch.yml" },
  "client": { "platform": "web", "inject": [], "external": [] }
}
  • dsh.bundle.patch makes the package a bundle: the installer lists it in dsh.profile.bundles and inserts its rows.
  • dsh.client (with exports["./client"]) gives the same row a browser half: client-modules scans enabled Loader entries, finds
    the declaration on this package, and serves lib/client.js. Host and browser halves therefore come from one package and one version.

6. Host endpoint

One exact route: POST /archive-manager/api, JSON body, responses shaped { ok: true, value } or
{ ok: false, error: { code, message, details } }.

op Request Returns
list — every archived Session: id, creation time, working directory, owning workspace, log directory, file count, bytes, whether it is live, whether it needs a restart
plan sessionId checks and measures only, deletes nothing (the dialog uses it to show the paths that would go)
delete sessionId the deletion result (removed/bytes/files/projectionCache/live/pendingRestart/remaining)
deleteMany sessionIds[] per-item results plus the remaining archive set (one failure never stops the others)
prune — drops archive marks with no storage behind them
status — route, storage root, current archive set (self-check)

7. Notes for contributors

  • An inject face's hooks object is flattened by the renderer. inject: () => ({ hooks: { archives } }) reaches the component as
    the selector hook useArchives (see bindInjectSources in ui-renderer); the hooks key itself is dropped. Reading
    props.hooks.archives throws during render and the slot error boundary marks the entry abdicated — the seat then silently disappears.
    Name custom sources so they cannot shadow the owner's standard hooks (this plugin uses archiveWorkspaces / archiveSessions
    because seats like shell.overlay and main already carry useWorkspaces / useSessions).
  • The browser half is a prebuilt bundle with no bundler step at install time. It may only require modules from the platform seed table
    (react, react/jsx-runtime, react-dom, @deepseek-ai/cordis, @deepseek-ai/dsh-client-store, @deepseek-ai/dsh-client-ui-slots,
    @deepseek-ai/dsh-client-ui-primitives, @deepseek-ai/dsh-client-ui-dockkit).
  • The host half injects the web surface optionally (export const inject = [] plus ctx.inject([...], cb)), so the row still activates
    where there is no webserver instead of waiting forever.

8. Tests

node --test "test/*.test.mjs"

38 tests cover the deletion core (path traversal, only the target Session removed, sibling directories kept), the host half
(cold delete, live policy, the three prune judgements, request gates, partial batch failures) and the browser half
(slot registrations, host-call plumbing, failure and "pending restart" notices, restore) — including render tests that project
each registration through the renderer's real hook flattening before rendering the component, which is what caught the inject-face
contract bug described above.

9. Known limitations

  • A live Session's row waits for a restart. The harness exposes no public "release Agent/Session by id", and this plugin does not
    reach into another plugin's fibers; after a restart the process no longer holds it, the row goes away, and prune clears the mark.
  • Only the Session itself is deleted — subagent Sessions it spawned are separate Sessions and are left alone.
  • Content indexes are out of scope. This profile's Session search index is :memory: (openAt: never); a deployment with an
    on-disk index rebuilds it after a restart, and the plugin never touches it directly.
  • Deletion is irreversible. The UI therefore requires an explicit acknowledgement and lists every log directory in the dialog.

安装

🧩 让 Agent 自动装(推荐)

装一次目录插件,之后本站所有插件都能让 DeepSeek Harness 自动找、自动装:

dsh plugin add dshbase-catalog

然后对 agent 说「帮我装 dsh-desktop-archive-manager」,它会在目录里找到并自动安装。文档:dshbase-catalog · 已验证场景包。

该插件是 GitHub 源码(未发 npm)——直接从仓库装:

Web profile:

dsh plugin --profile web add github:baom1ng/dsh-desktop-archive-manager

Headless(CLI)profile:

dsh plugin --profile headless add github:baom1ng/dsh-desktop-archive-manager

实测报告

验证通过:从 GitHub 源码完成 L1 安装 + L2 加载 + L3 运行(dsh 0.1.0-rc.6)。

安全:尚未扫描——我们的每日静态扫描将很快覆盖它。

分享徽章

Desktop 里更多

浏览全部 7819 个插件 →