DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Better Dsh Session Deletetool — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
B

better-dsh-session-deletetool

Better Dsh Session Deletetool

从 DSH 侧边栏删除对话,而不只是将其归档;在选择要一并删除的内容前,查看它所产生的完整家族——所有嵌套的子智能体会话和派生对话;从工作区搜索旁的垃圾桶图标一次删除多个对话,该图标与周围图标对齐,并在每种 dsh-claude-style 搜索样式下可见。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:Lzcdebear/better-dsh-session-deletetool#68e16871573be29b23cd6b598a7d006c1e6b13cb
README兼容性版本

说明

在会话菜单中真正删除对话;确认框会按层级显示整个家族(子智能体、派生对话及其下一层),删除前即可查看,并可勾选要连带删除的内容;工作区搜索图标左侧另有批量删除入口(兼容 dsh-claude-style 主题的搜索框三档样式,图标自动与相邻图标对齐)。

兼容性与来源证明

Better Dsh Session Deletetool 以 better-dsh-session-deletetool 发布,当前版本为 0.5.3。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/14

版本

0.5.3stable
2026/10/14
0.5.2stable
2026/10/14
0.4.1stable
2026/10/4
查看其余 1 个版本收起版本
0.4.0stable
2026/10/4

相关插件

正在加载相关插件…

最新版
0.5.3
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 27
周下载
0
最近提交
2026/10/14
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 productivity-workflow 分类下经过校验的插件。

Acp App@deepseek-ai/dsh-acp-appdsh ACP 配置文件包:基于 dsh-base 的仅限自动化的 JSON-RPC stdio 和进程生命周期管理Experimental Schedule Bundle@deepseek-ai/dsh-experimental-schedule-bundle为 Web 组合添加 Schedule、其任务页面和时间上下文的可选捆绑包Ab Ocrdsh-ab-ocr--- description: "外部 ocr 工具:逐页识别扫描的 PDF 或图像,仅在处理完最后一页后按顺序合并页面,并使用模型确定的标题级别保存为一个 Markdown 文档。" kind: "package-reference" ---Web All@linxin666/dsh-web-allDSH Web UI 全家桶聚合插件:一键安装全部功能插件(task-board / git-graph / pet / remote-web-ui / web-ui-settings / skin-center / community-plugins / compat shim)。compat 桥接层已并入本包(src/client),无需独立 compat npm 包。

README

better-dsh-session-deletetool

Delete a conversation from DeepSeek Harness — DSH ships archive only.

中文说明


Why this exists

DSH can only archive a conversation. Archiving hides the row from the sidebar and keeps every artifact: the log, the workspace account, the projection checkpoint all stay on disk, and the conversation can be restored at any time. The persistence seam has no deletion API at all — @deepseek-ai/dsh-session-persistence-jsonl states it plainly:

Nothing deletes session files — logs accumulate under root until removed externally; the seam has no deletion API.

So a long-lived profile accumulates conversations forever. This plugin adds the missing step: a Delete conversation row in each session's ⋯ menu that really removes the data — and the dialog it opens is also the one place that shows a conversation's whole family before you touch it.

What it deletes

For the chosen session, the Host half:

  1. removes the session's artifact directory — the current log, every retained historical format generation, and any session-local file in it (ctx.sessionPersistence.locate(header) gives the path);
  2. removes the descendants you selected — child sessions are sessions of their own with their own logs. DSH records every child in its parent's header (SessionHeader.parentSession), and writes that field for every relation it creates: the Subagent runtime sets it with origin: 'subagent', a fork sets it with isSeeded, and Agent Teams resolves its roster through the same field. The plugin walks that lineage breadth-first and unions it with the durable subagentCatalog projection (ctx.subagents.listDescendants), so a child whose own header no longer reads is still named. Descendants are deleted deepest first, gathered before anything is removed, and only the ticked ones go — up to 200 per request;
  3. drops the workspace account — the id leaves every Workspace record's sessionIds (Workspace.detachSession) and the registry-global archive and pin sets;
  4. drops the projection checkpoint — the session_projcache domain record and its <id>.json file;
  5. closes the shells the session owned — ctx.terminals are part of no admission family, and the service only reaps them when the Agent is released, which can be long after the log is gone;
  6. tells connected pages — one api-session/removed per removed id, the same event the shipped Session controller emits when a Session is disposed, so the rows leave the sidebar immediately.

Seeing the family, and choosing what goes with it

The sidebar lists a subagent session and a derived conversation as rows of their own, and nothing there says which conversation spawned them; DSH itself never draws that relation. This dialog is the one place it is drawn: the session's whole family as one tree, the branches below the branches included.

  • row 1 is this conversation, carrying the whole family's checkbox and named as the sidebar names it;
  • row 2 is one collapsible Subagents (n) branch holding the subagents this conversation spawned;
  • row 3 is one collapsible Forked conversations (n) branch, and each fork inside it keeps its own Subagents branch — so a fork of a fork is drawn inside its parent's block, one step further in, instead of being listed beside it. A subagent that spawned a conversation keeps that conversation inside the subagent's own block for the same reason;
  • every row has a checkbox, its name and the tail of its id, and is badged when it is open or has unfinished work. Names follow the sidebar's own rule — the durable title, else the final segment of the project directory, else the id — so nothing reads as untitled;
  • the nesting is the indentation alone, one step per level: a parent is followed immediately by the children it draws, so a level-3 row reads as hanging off the level-2 row above it rather than merely as "somewhere deeper".

A row's checkbox covers its own subtree: ticked when everything below it is ticked, mixed when only part of it is, and pressing it takes or clears that whole subtree. A block's checkbox covers the rows the block lists. The delete set is one set of ids, with no second "excluded rows" state beside it, so the picture and the footer's count cannot drift apart.

Leads that could not be read are reported above the list (a branch whose directory would not open, for example) instead of quietly costing rows: a missing row and a conversation that genuinely has no children used to look exactly alike.

Confirming posts exactly the ticked ids and the button states how many conversations will go. Unticked descendants survive as conversation roots. The selection is validated against the Host's own walk, so a request can only ever name Sessions in that lineage. A fork is a conversation in its own right, which is exactly why it is listed with a checkbox instead of being taken silently.

Deleting in bulk

A trash control sits in the workspace section header, immediately left of the search icon (it draws the deleting icon.svg glyph). It aligns itself with the icons around it — the header row's own 4px gaps, the same label-tertiary grey at rest — and it does not live inside the search slot, so it stays put under all three search styles of the dsh-claude-style theme (Nwflower): where that theme hides the shipped search icon, the control remains on its own. It opens one dialog over every conversation the Host knows:

  • Sectioned by Workspace, in the registry's own order, each headed by the Workspace title and its conversation count; conversations no Workspace owns land in a final Ungrouped section.
  • Each conversation is drawn as the same tree the single-session dialog draws: under a row come its collapsible Subagents (n) and Forked conversations (n) blocks, and a derived conversation carries its own level inside its own block, so the hierarchy is the indentation alone.
  • Names follow the sidebar's own rule: the durable title when the log carries one, else the final segment of the project directory (for example Project_lzc), else the id. A conversation that was never renamed therefore reads as its directory rather than as untitled.
  • Selection follows the subtree, and a child can be deleted on its own. Ticking a parent takes the ticked rows below it; ticking one subagent without its parent sends that subagent as a delete root of its own and leaves the parent alone. The footer button always states how many conversations the press will delete.

The dialog carries the same stop unfinished work first switch as the single-session one, on by default. Confirming runs the delete above once per ticked root; a root that fails is listed and the rest still go.

What blocks a delete, and what does not

Running work blocks it — being open does not. The gate is DSH's own archive admission, the workspace/session-activity waterfall: the Agent registry reports a running turn, the job registry reports background jobs, the Subagent runtime reports running descendants, Schedule reports active reminders. The question is asked once per Session in the delete set, because the admission answers per Session: a descendant's running turn or background job is not reported when only the target is asked. The dialog names what is still running — on each row and in the summary — and offers Stop and delete, which dispatches workspace/session-stop for every busy Session first, exactly what archiveSession(id, { stopActivity: true }) does.

A session the Host still holds open (ctx.sessions / ctx.agents) is deleted anyway. Measured on Windows: rm succeeds while the append handle is open, the directory entry disappears at once, and later appends land in the unlinked file instead of resurrecting it. An earlier version refused such sessions with "switch away first", which wrongly blocked conversations that were not on screen.

Known limits

  • Attachment blobs are not removed. Uploaded images and files live in ~/.dsh/attachments/v1/objects/<hash>, a content-addressed store shared by sessions, and the service has no reference counting, so those blobs stay.
  • The search index looks after itself. dsh-session-query-sqlite is a derived index that reconciles against persistence on every search, so a deleted source stops being returned from the next search on.
  • A held-open session may leave one inert cache record. If the Host still owns the session when it is deleted, its disposal can write one more projection checkpoint. That record is never read (no log means no session) — a few tens of KB of dead file.
  • Plugin code changes need a DSH restart. In a profile whose HMR does not watch module files, replacing the code of an installed bundle requires a restart. The client half only needs a page refresh.

Install

Everything below goes through DSH's own plugin manager, which accepts an install spec (@deepseek-ai/dsh-plugin-manager): a registry name, a git host shorthand, a repository URL, a tarball, or an absolute local path. The npm route also works with a plain npm install, into the profile directory. Pick whichever route your network allows.

1. From npm (published as better-dsh-session-deletetool)

The registry route, and the only one that does not need github.com:

npm install better-dsh-session-deletetool

DSH's own plugin manager takes the registry name directly, which is the better route inside the app: it records the dependency in the profile and reloads it.

  • In the app: Settings → Plugins → the install entry, paste better-dsh-session-deletetool.
  • Through an agent session: plugin_manager { action: "install_bundle", target: "better-dsh-session-deletetool" }.

Pin a version the way npm writes it: better-dsh-session-deletetool@0.4.0.

2. Straight from GitHub (needs github.com reachable)

Spec:

github:Lzcdebear/better-dsh-session-deletetool

or, equivalently:

https://github.com/Lzcdebear/better-dsh-session-deletetool

Give it to DSH:

  • In the app: Settings → Plugins → the install entry, paste the spec. (The Plugin Manager UI and the plugin_manager tool take exactly the same spec string.)
  • Through an agent session: ask the agent to install it — the tool call is plugin_manager with action: "install_bundle" and target: "github:Lzcdebear/better-dsh-session-deletetool".

Pin a ref with #: github:Lzcdebear/better-dsh-session-deletetool#v0.1.0.

If the connection check fails, DSH reports a bounded log path. On a network where github.com is not reachable, use route 1, 3 or 4 — or point git at your proxy first (git config --global http.proxy http://127.0.0.1:7890).

3. From a local copy (works offline)

Download the repository (ZIP or git clone), unpack it anywhere, then install the absolute directory:

plugin_manager { action: "install_bundle", target: "D:\\plugins\\better-dsh-session-deletetool" }

DSH records a link: dependency and reloads the profile. This is the route used to develop the plugin, and the one to use behind a restrictive network.

4. From the release tarball

https://github.com/Lzcdebear/better-dsh-session-deletetool/archive/refs/heads/main.tar.gz

Same install entry as route 2; useful when git is unavailable but HTTPS is not.

After installing

The Host half loads with the profile. The Client half appears after the page is refreshed. The row shows up in the session ⋯ menu as 删除会话 / Delete conversation.

To remove the plugin again, use the same manager: plugin_manager { action: "remove_bundle", target: "better-dsh-session-deletetool" } (the bundle key is the package name).

Usage

  1. Open the ⋯ menu on any session row and pick Delete conversation.
  2. The dialog asks the Host for the session's real state and states it: what will be deleted, whether the Harness still holds it open, and what is still running.
  3. It then draws the whole family as a tree to choose from: this conversation on its own row, then its Subagents (n) and Forked conversations (n) blocks, each derived conversation carrying its own level inside its block, and a checkbox on every row (title, id tail, state badge). Untick whatever you want to keep.
  4. Confirm. The button states how many conversations will go; if work is running it reads Stop and delete and stops that work first.
  5. The rows leave the sidebar at once, and the data is gone from disk.

For bulk: press the trash control in the workspace section header, left of the search icon, tick conversations in the Workspace-sectioned list (ticking a parent brings its children, a child can be ticked or unticked on its own), then confirm.

HTTP surface

The Client half reaches the Host over four same-origin exact routes on ctx.webServer. A build-free plain-JavaScript bundle cannot declare a typed ctx.remote namespace (that needs generated Typert descriptors), so this uses the same transport the community plugin dshmarket uses.

RouteMethodPurpose
/better-dsh-session-deletetool/inspect?sessionId=…GETstored / open / agent / running / activity / artifactDirectory / warnings (the leads that could not be read, so a missing branch is never mistaken for a childless one), and descendants = { count, subagents, derived, truncated, maxDeletable, items[] } where each item carries id, kind, depth, parentId, title, open, agent, running and its own activity
/better-dsh-session-deletetool/deletePOSTbody { sessionId, stop?, descendants? } — descendants omitted means the whole family, an empty array means the session alone; returns removed, descendants (each with its kind), kept, stoppedActivity, terminalsKilled, warnings, runtime, activity. A name outside the family is refused with 400 unknown-descendant before anything is removed
/better-dsh-session-deletetool/catalogGET{ ok, workspaces: [{ key, workspaceId, title, path, sessions[] }], totals }; each session row carries id, kind (root / subagent / derived), depth, parentId, hasChildren, family, subagents, derived, title, cwd, open, agent, running, activity. Section order is the registry's own Workspace order, and the section whose workspaceId is null is Ungrouped
/better-dsh-session-deletetool/delete-batchPOSTbody { roots: [{ sessionId, descendants? }], stop? }, each root running the single-session delete once; returns . A failing root is reported as one entry and the rest are still attempted. At most 200 roots per request

All four routes carry their own same-origin gate: Host must be loopback, sec-fetch-site must not be cross-site, and a present Origin must match Host. Another site's page cannot reach them.

Layout

FileRole
host.jsHost half: the four routes, artifact/accounting/cache removal, the subagent subtree, and the Workspace-sectioned catalog
client.jsClient half: the sidebar.workspaces.session.menu.item row (order 500), the bulk control, and the two shell.overlay dialogs
cordis.patch.ymlInserts the Host row into the profile's layer stack
test/host.test.mjsRoute tests over real temporary directories
icon.svgPlugin artwork (the bulk control draws deleting icon.svg)

Styles use only host theme tokens (--dsw-alias-*), so light and dark both read; the UI is localized (English / 简体中文) through the Client locale service.

Why the bulk entry is not a slot registration of its own: sidebar.workspaces is a single slot, so a second registrant would shadow the shipped session browser instead of sitting beside it. The Client half therefore registers in sidebar.footer.action (rendering nothing there) and mounts its control as the browser's own search slot's previous sibling — never inside the slot — taking over the margin-left:auto that pushes the cluster to the row's right edge and pinning the collapsed slot back to its 28px cell (the expanded search is exempt), then re-creating the control through one MutationObserver when React re-renders that header. Whatever a theme does to the slot itself leaves the control standing: dsh-claude-style visually hides the slot in two of its three search styles. That insertion carries no authority beyond opening the dialog; the two Host routes do the work. If a future harness renames that slot's CSS class, the control stops appearing and nothing else changes.

Development

node --test test/host.test.mjs

The tests drive the real apply() registration against fake Host services and real temporary directories: deletion, the running-work gate and its stop path, the subagent subtree, the inspect report, and the refusal paths (bad id, bad body, wrong method, cross-site origin).

License

MIT

Author

  • Bilibili: https://space.bilibili.com/220996778
{ ok, roots, removed[], failed[] }
failed