@wjj-8283/dsh-temp-workspace

sessiontested: passnpmMIT

Temporary workspace for DSH web — one click creates a throwaway workspace whose conversations are deleted at the next restart (immediately or after a delay, optionally behind a confirm dialog). Pin a temp workspace to keep it: its files move into the folder you pick, its title becomes that folder's

下载量 / Downloads
1,077
依赖体积 / node_modules
0.21 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @wjj-8283/dsh-temp-workspace

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

@wjj-8283/dsh-temp-workspace

一个 DSH web 客户端插件,提供 临时工作区(临时工作区) 功能。

点击侧边栏「添加工作区」(+)右侧的小沙漏图标,即可创建一个一次性工作区并打开一个全新的对话。下次 Harness 重启时,这个插件会删除该工作区下的全部对话以及工作区本身——临时工作区不留任何痕迹。

它是什么

  • 宿主半边(lib/index.js)—— 一个 Cordis 插件,注入

webServer / workspaceRegistry / sessionPersistence(可信授权列表改为

按需读取 web app 的 webStartup 服务,不作为硬依赖),注册受浏览器信任围墙保护的

/temp-workspace/api 路由,并在启动时驱动清理逻辑。

  • 浏览器半边(src/client.js → lib/client.js)—— 在侧边栏「+ 添加工作区」

按钮旁注入一个小图标;点击后调用宿主路由,并在新建的工作区里打开一个新对话。

它还注册了一个 设置 → 临时工作区 独立页面,并在设置开启时于启动阶段弹确认对话框。

安装方式

从 npm 安装(预构建,推荐)

该包已发布到 npm,lib/ 为预构建产物,安装无需构建、可跳过 pnpm 的 allowBuilds 授权——一条命令搞定:

dsh plugin --profile web add @wjj-8283/dsh-temp-workspace

dsh plugin … add 会把该 spec 转发给 profile 目录里的 pnpm,并代为合并 dsh.profile.bundles。因为清单声明了 dsh.bundle.patch,包会自动加入 Loader 层栈,下次启动 dsh web 时宿主把它组合为 Loader 条目、注册 /temp-workspace/api 路由,客户端插件(含设置页面)进入 __DSH_BOOT__。

从 GitHub 安装

直接从 GitHub 安装,使用 dsh plugin 转发器(在 profile 目录里 pnpm clone + add,并自动合并 bundle 层):

# 启动某个 profile,例如 web 应用
dsh plugin --profile web add github:wjj-8283/dsh-temp-workspace

因为清单声明了 dsh.bundle.patch,add 会把该包自动追加到 dsh.profile.bundles,下次启动 dsh web 时宿主就把它组合为 Loader 条目、注册 /temp-workspace/api 路由,客户端插件(含设置页面)进入 __DSH_BOOT__。

若想自己驱动 pnpm,可在 profile 目录里执行同一 spec:

cd "$DSH_HOME/profiles/web"
pnpm add github:wjj-8283/dsh-temp-workspace

要固定到某个分支/标签/提交,按 pnpm 的 git ref 语法追加:

dsh plugin --profile web add github:wjj-8283/dsh-temp-workspace#<ref>
构建后的客户端 bundle(lib/client.js)已提交在仓库里,所以 git 安装不需要构建步骤。要改它,克隆仓库后用 node build.mjs --watch(见[开发循环](#开发循环)),或改为从本地 checkout 安装(见[接入 profile](#接入-profile))。

设置 → 临时工作区

插件在 设置导航 里注册了自己的独立页面(settings.section 插槽,id 为

dsh-temp-workspace),页面里是下面三个设置项。取值存放在 profile patch 中 Loader 条目

dsh-temp-workspace 的 config 里(dsh 0.1.7 起旧的 settings.plugin.item 卡片插槽与

~/.dsh/settings.yaml 均已移除):

设置 · 取值 · 默认 · 含义

deleteMode · immediate / delayed · immediate · 下次启动时何时删除临时工作区

deleteDelay · 秒 · 3600 · delayed 模式下删除前的宽限期

confirmBeforeDelete · 开 / 关 · 开 · 删除前是否先询问用户

  • confirmBeforeDelete 开:宿主启动时绝不自动删除,而是挂起这些工作区,

浏览器弹出确认对话框,提供两个选项:

  • 删除 —— 清空被挂起的工作区(会话 + 注册 + 目录)。
  • 临时保留 —— 本次不动它们,但仍然是临时:它们还在标记里,会在之后的

启动时再次(按设置)被确认/清理。

  • 未作答时工作区原样保留到下次启动。

永久保留不在启动确认弹窗里——它有自己的按钮。侧边栏里每个临时工作区行

(标题「临时工作区」)在其「+」(New Session) 旁边有一个图钉按钮。点击后选取一个

目标文件夹(系统目录选择器:桌面端有 __DSH_DIRECTORY_PICKER__ 桥时直接用它,否则

dsh 0.2.x 走 uiWorkspace.pickDirectory(),0.1.x 走 ctx.workspaces.pickDirectory())。临时工作区的文件会

直接移进该文件夹(不会额外创建「临时工作区」子文件夹),该文件夹本身成为永久工作区,

并用其文件夹名作为工作区标题。同时迁移对话:把每个会话日志头行的 cwd 改写为该

文件夹路径,并把日志目录移到新 cwd 的 projectKey 槽位。迁移进行期间会显示一个

「正在迁移工作区…」提示(没有进度条,只提醒不要中途退出 Harness;10 秒后会给出关闭入口)。

成功后弹出的对话框只说明如何手动重启——没有「立即重启」按钮,因为桌面端无法重启自己的

宿主进程:

  • Web 版:在终端里退出 dsh 进程,然后重新打开;
  • 桌面版:彻底退出桌面端再重新打开
  • Windows:右键托盘区的 DSH 图标 → 退出;
  • macOS:直接按 Command+Q,或右键 Dock 栏里的图标 → 退出。
  • confirmBeforeDelete 关:自动删除——启动时立即执行,或在 deleteMode = 'delayed'

时等待 deleteDelay 秒后执行。

清理是如何工作的

DSH 没有公开的「删除会话日志」API——持久化层是 append-only。所以临时工作区的删除分为四步:

0. 先拆在线会话 —— 如果宿主进程里还活着该工作区的会话(确认弹窗、延迟自动删除、或只刷新了页面而宿主并未真正重启时,删除都会在仍持有这些会话的宿主里运行),会尽力拆除它们:

先取消 agent 并等它回到空闲(whenIdle,镜像 agent loop 自身的销毁顺序),再先把待写内容落盘

(sessions.flush),最后从会话存储中摘除该条目(发出 session/disposed,客户端立即关闭该对话)。

先 flush 再摘除对多会话工作区至关重要:摘除会触发 session/disposed,持久化协调器随之做一次

"退休刷新"(retire → flush → initFor),若会话还有未落盘的写入,这次刷新会在目录被删除后把日志

重新物化出来——那些会话就会变成不可读取的 Ungrouped 残留。先 flush 后,退休刷新无内容可写,日志

只会被删除一次。

0b. 归档冷会话 —— 本轮宿主里从未被打开(未 attach)的会话只有磁盘日志,删日志后浏览器收不到

session-removed 事件,会在侧边栏残留成不可读取的 Ungrouped 条目。archiveColdSessions 在删日志

之前把它们逐一归档(workspaceRegistry.archiveSession):归档集变化会推送

host/archived-sessions-changed,侧边栏(分组、扁平列表、搜索)都会过滤归档 id,残留条目立即消失。

归档留下的 archived-id 记录由启动清扫回收。

1. 再删会话 —— 工作区所属的每个会话(其头行 cwd 等于工作区路径)通过

ctx.sessionPersistence.locate 定位,并用 fs.rm 删除其磁盘目录。

2. 删注册 —— ctx.workspaceRegistry.delete(id) 删除工作区记录(本身不动日志/目录)。

3. 删目录 —— 删除临时目录(位于 <dsh-home>/temp-workspaces/<uuid>)。

插件用 <dsh-home>/temp-workspaces/state.json 记录临时工作区(持久化标记

{ workspaceId, path, createdAt })。删除由该标记里的 path 驱动,所以重启前已通过

UI 删除注册记录的临时工作区仍会清理残留目录(修复了「残留文件夹」bug)——目录以

标记路径(而非注册记录)为准。

零残留:删除时还会清理会话的投影缓存行(session_projcache 域,位于

~/.dsh/storages/session_projcache.json)与旧布局遗留的 per-session 缓存文件。

启动时还有一次孤儿残留清扫(pruneOrphanTempResidue):凡 cwd 位于临时根目录下、

且不再被标记引用的投影缓存行,连同其 archived-id 记录与遗留缓存文件一并删除。这些行

永远不会把幽灵对话显示出来(身份校验后读不到),但"不留痕迹"就是不留痕迹;用户对真实

会话的主动归档不会被触碰。

目录结构

temp-workspace-plugin/
  package.json       name, dsh.bundle.patch + dsh.client, exports
  cordis.patch.yml   把该插件插入为宿主 Loader 条目
  lib/index.js       节点半边 —— /temp-workspace/api 路由 + 设置 + 启动清理
  src/client.js      浏览器半边源码(图标 + 设置页面 + 确认弹窗)
  lib/client.js      构建后的浏览器半边(生成文件,勿改)
  build.mjs          把 src/client.js 包装 -> lib/client.js(HMR watch)

开发循环

node build.mjs --watch

lib/client.js 是 client-modules 提供、dsh-client-hmr 轮询的唯一文件;编辑

src/client.js 会热更新界面(无需刷新页面)。宿主半边改动(lib/index.js)需要重启

dsh web。

接入 profile

# 本地 checkout / clone(任意绝对或相对路径)
dsh plugin --profile web add /path/to/dsh-temp-workspace

这会把它加入 dsh.profile.bundles。下次启动 dsh web 时宿主组合该行、

注册 /temp-workspace/api 路由,客户端插件(含设置页面)进入 __DSH_BOOT__,并运行启动清理/确认流程。

API(/temp-workspace/api/<method>)

读取用 GET,变更用 POST。

方法 · 返回 · 说明

POST create · { workspace, created: true } · mkdir + workspaceRegistry.create + 标记

GET list · { entries } · 当前标记为临时的 [{ workspaceId, path, createdAt }]

POST delete · { ok: true } · 立即删除一个临时工作区(会话 + 注册 + 目录)

GET/POST config · { ok, value } · 读取设置,或 POST {…} 写入补丁

POST configReset · { ok, value } · 恢复所有设置为默认

GET pending · { ok, value } · 被挂起的工作区 + confirmBeforeDelete + deleteAt

POST confirm · `{

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::3,最后更新 2026-10-25

Links

GitHub · Homepage · npm

Same category