@wangxiaocuo/dsh-session-trash 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.en.md +22 -4
- package/README.md +22 -5
- package/client.js +465 -13
- package/lib/cleanup.js +15 -8
- package/lib/errors.js +13 -10
- package/lib/fsops.js +8 -6
- package/lib/http.js +27 -9
- package/lib/inventory.js +24 -0
- package/lib/members.js +70 -28
- package/lib/state.js +53 -11
- package/lib/store.js +27 -1
- package/lib/trash-service.js +44 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,36 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.6.6] - 2026-11-11
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- 回收站页支持按移入时间、标题、大小、到期时间排序,可勾选多个条目批量恢复(只含工作区仍存在的条目),并支持全选当前页。
|
|
12
|
+
- 含子会话的条目可以展开查看成员列表(父/子会话 ID 与大小)。
|
|
13
|
+
- 同源浏览器标签页通过 `BroadcastChannel` 实时同步回收站变更,不再需要切换焦点或手动刷新。
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- 类型收紧:`members.js` 的 `Member`/`TrashEntry` 与 `state.js` 的状态投影形状改为具体类型。
|
|
18
|
+
|
|
19
|
+
## [0.6.5] - 2026-11-11
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- 回收站页可以清理不含会话日志的空无主对象(`POST /orphans/forget`);可能含日志的无主对象继续保留,供人工处理。
|
|
24
|
+
- CI 增加 `lib/**` 覆盖率门槛(行 85 / 分支 70 / 函数 84)和 README 的 CI badge。
|
|
25
|
+
- 新增 tag 触发的 release workflow:typecheck、单测、smoke、真实 Host e2e 通过后 `npm publish --provenance` 并创建 GitHub Release;使用 npm Trusted Publishing,无需 `NPM_TOKEN`。
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `GET /state` 改为纯只读;页面打开时由客户端显式调用 `POST /sweep` 触发节流维护,读请求不再可能触发永久删除。
|
|
30
|
+
- 锁竞争:Host 在报 `LOCKED` 前短暂重试,客户端对 `LOCKED` 自动重试一次;`trash()` 的 lineage/preflight 移到锁外,缩短持锁时间。
|
|
31
|
+
- 收紧 `lib/errors.js` 和 `lib/fsops.js` 的类型(`any` 换成 `unknown` 与具体形状)。
|
|
32
|
+
|
|
33
|
+
### Tests
|
|
34
|
+
|
|
35
|
+
- 覆盖页面维护扫描(成功/节流/失败)、空无主对象清理、锁重试和客户端 LOCKED 重试。
|
|
36
|
+
|
|
7
37
|
## [0.6.4] - 2026-11-11
|
|
8
38
|
|
|
9
39
|
### Added
|
|
@@ -94,6 +124,8 @@
|
|
|
94
124
|
|
|
95
125
|
- 回收站工具栏的「永久删除全部」与二次确认;`missing` 记录只移出索引,不删除会话文件。
|
|
96
126
|
|
|
127
|
+
[0.6.6]: https://github.com/wangxiaocuo/dsh-session-trash/compare/v0.6.5...v0.6.6
|
|
128
|
+
[0.6.5]: https://github.com/wangxiaocuo/dsh-session-trash/compare/v0.6.4...v0.6.5
|
|
97
129
|
[0.6.4]: https://github.com/wangxiaocuo/dsh-session-trash/compare/v0.6.3...v0.6.4
|
|
98
130
|
[0.6.3]: https://github.com/wangxiaocuo/dsh-session-trash/compare/v0.6.2...v0.6.3
|
|
99
131
|
[0.6.2]: https://github.com/wangxiaocuo/dsh-session-trash/compare/v0.6.1...v0.6.2
|
package/README.en.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# dsh-session-trash
|
|
2
2
|
|
|
3
|
+
[](https://github.com/wangxiaocuo/dsh-session-trash/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
[简体中文](./README.md) | English
|
|
4
6
|
|
|
5
7
|
[GitHub](https://github.com/wangxiaocuo/dsh-session-trash) · [npm](https://www.npmjs.com/package/@wangxiaocuo/dsh-session-trash) · [Changelog](./CHANGELOG.md)
|
|
@@ -13,7 +15,9 @@ Status: feature complete. CI (GitHub Actions) runs the unit tests, the Host smok
|
|
|
13
15
|
- Right-click a session in the sidebar and choose "Move to trash". It is available for cold sessions with no running turn, job, subagent, or scheduled task; hidden subagent children move with their parent and are restored together.
|
|
14
16
|
- For sessions that are still open, still running work, or own visible child sessions, the menu keeps a labelled explanatory "Move to trash" item that states why the move is unavailable instead of hiding the entry entirely.
|
|
15
17
|
- After the move, the shared DSH Toast offers one action: Undo. Undo tries a normal restore first and falls back to an orphan restore when the original workspace is gone.
|
|
16
|
-
- The Trash page in Settings shows title, Session ID, original workspace, trashed date, remaining days, size, and status. The list supports search, filters, and paging at 50 rows per page.
|
|
18
|
+
- The Trash page in Settings shows title, Session ID, original workspace, trashed date, remaining days, size, and status. The list supports search, filters, sorting by trashed date/title/size/expiry, and paging at 50 rows per page.
|
|
19
|
+
- Entries with hidden sub-sessions show a count badge and can expand to list every member (parent/child session IDs and sizes); restore and permanent deletion still operate on the whole tree.
|
|
20
|
+
- Select multiple entries to restore them as a batch (only rows whose workspace still exists), including a select-all-page checkbox.
|
|
17
21
|
- Row actions include restore, restore as orphan, permanent deletion, removal from the index, copying the Session ID, and revealing the original workspace in Finder or Explorer.
|
|
18
22
|
- The toolbar's "Delete all permanently" empties the whole trash after one confirmation: it deletes every trashed session log and drops file-missing records from the index. Attachments, images, and search-index rows are not deleted.
|
|
19
23
|
- Cleanup keeps entries for 30 days by default and runs every 6 hours. It also runs shortly after activation and when the Trash page opens. Failed cleanup runs are retried with exponential backoff, and the page shows the failure.
|
|
@@ -113,13 +117,15 @@ All routes live under `/plugins/dsh-session-trash/api/` and are registered as ex
|
|
|
113
117
|
|
|
114
118
|
| Method | Path | Description |
|
|
115
119
|
|---|---|---|
|
|
116
|
-
| `GET` | `/state` | Config, index state, entries, stats, and cleanup diagnostics;
|
|
120
|
+
| `GET` | `/state` | Config, index state, entries, stats, and cleanup diagnostics (read-only; never sweeps) |
|
|
121
|
+
| `POST` | `/sweep` | No body; runs one throttled page-open maintenance sweep; whether expired entries are deleted depends on `enableAutoCleanup` |
|
|
117
122
|
| `POST` | `/preflight` | `{ sessionId }` returns `{ eligible: true, descendants }` or `{ eligible: false, code, message, details? }`; `descendants` is the number of hidden children that move along |
|
|
118
123
|
| `POST` | `/trash` | `{ sessionId }`; moves the whole session tree (parent plus hidden subagent children) and returns `{ ok, entry }` |
|
|
119
124
|
| `POST` | `/restore` | `{ sessionId, mode: 'normal' \| 'orphan' }` |
|
|
120
125
|
| `POST` | `/purge` | `{ sessionId }`; permanently deletes the session log |
|
|
121
126
|
| `POST` | `/purge-all` | No body; permanently deletes every entry in the trash, dropping `missing` index records only; returns `{ ok, purged, forgotten, failed }` |
|
|
122
127
|
| `POST` | `/forget` | `{ sessionId }`; removes only a `missing` index entry |
|
|
128
|
+
| `POST` | `/orphans/forget` | No body; removes empty unindexed object directories that hold no session log; returns `{ ok, removed }` |
|
|
123
129
|
| `POST` | `/reveal` | `{ sessionId }`; opens the original workspace |
|
|
124
130
|
| `POST` | `/cleanup` | No body; runs one cleanup sweep |
|
|
125
131
|
| `POST` | `/rebuild` | No body; rebuilds the index only in protection mode |
|
|
@@ -165,11 +171,13 @@ The index schema is v2; a v1 index is upgraded automatically on startup and pres
|
|
|
165
171
|
- Orphan restore never recreates the original workspace directory and never reattaches the session to a workspace.
|
|
166
172
|
- Archive and pin state survive trash and restore. The Trash page does not manage either set.
|
|
167
173
|
- Permanent deletion removes the session log only. Attachments, images, projection-cache rows, and search-index rows are not deleted.
|
|
174
|
+
- Unindexed objects (object directories whose `meta.json` is damaged or unreadable) are never deleted automatically; the page can only clean empty leftovers that hold no session log, and anything that may contain logs is left for manual inspection.
|
|
168
175
|
- `/state` returns all entry summaries in one response. Search, filtering, and paging happen in the Client.
|
|
169
|
-
-
|
|
176
|
+
- Same-origin tabs in the same browser sync index changes through `BroadcastChannel`; different browsers or machines still need a refresh.
|
|
177
|
+
- Batch restore only covers rows whose workspace still exists; entries with a missing workspace need an individual orphan restore.
|
|
170
178
|
- The desktop apps on Windows and Linux have not been verified manually; CI boots an npm-installed `dsh web` Host, so desktop-shell UI and desktop-only features (such as reveal in the file manager) are still verified on macOS only. On Windows, cases that rely on POSIX permission bits are skipped, and long paths over 260 characters / symlink copying depend on system configuration (the related tests skip themselves when unsupported).
|
|
171
179
|
- macOS path comparison is case-insensitive. On a case-sensitive APFS volume, paths that differ only by case are treated as the same location.
|
|
172
|
-
- Multiple DSH processes sharing one `DSH_HOME` serialize trash operations through `.lock`.
|
|
180
|
+
- Multiple DSH processes sharing one `DSH_HOME` serialize trash operations through `.lock`. The Host retries briefly before reporting `LOCKED`, and the Client retries once automatically; a process paused for more than 10 minutes can lose the lock to another process.
|
|
173
181
|
|
|
174
182
|
## Development
|
|
175
183
|
|
|
@@ -177,6 +185,7 @@ The index schema is v2; a v1 index is upgraded automatically on startup and pres
|
|
|
177
185
|
pnpm install
|
|
178
186
|
pnpm test # unit tests + real-DOM component tests (jsdom)
|
|
179
187
|
pnpm typecheck # tsc --checkJs (currently lib/ and index.js)
|
|
188
|
+
pnpm test:coverage # coverage (CI thresholds apply to lib/**)
|
|
180
189
|
pnpm test:smoke # Host smoke test (real Cordis, plain Node)
|
|
181
190
|
npm run test:e2e # real dsh web end-to-end (desktop app or npm-installed DSH)
|
|
182
191
|
```
|
|
@@ -189,11 +198,20 @@ What CI verifies:
|
|
|
189
198
|
|---|---|
|
|
190
199
|
| Unit tests, Host smoke test | CI: Ubuntu Node 20/22, Windows Node 22 |
|
|
191
200
|
| Package contents (`npm pack`) | CI: Ubuntu |
|
|
201
|
+
| Coverage thresholds (`lib/**`, lines 85 / branches 70 / functions 84) | CI: Ubuntu Node 22 |
|
|
192
202
|
| Real `dsh web` end to end (npm-installed DSH) | CI: Ubuntu, Windows (Node 22) |
|
|
193
203
|
| Real `dsh web` end to end (desktop app) | macOS + DSH 0.2.2-rc.1 (run manually) |
|
|
194
204
|
|
|
195
205
|
`npm run test:e2e` boots a real `dsh web` Host in a temporary `DSH_HOME` and runs the full flow. By default it discovers the desktop app in the platform's usual install locations (or uses `DSH_ELECTRON`); set `DSH_E2E_DSH_BIN` to the `lib/bin.js` of an npm-installed `@deepseek-ai/dsh` to boot the Host with plain Node instead - CI and Linux/Windows use that mode, with no desktop app required. When no Host is found it prints a skip message and exits 0. The cleanup-failure scenario that relies on POSIX permission bits is skipped on Windows. Set `DSH_E2E_KEEP=1` to keep the temporary home and logs.
|
|
196
206
|
|
|
207
|
+
### Releasing (maintainers)
|
|
208
|
+
|
|
209
|
+
1. Bump the version in `package.json` and update `CHANGELOG.md`, then commit and push.
|
|
210
|
+
2. Create and push a tag: `git tag -a vX.Y.Z -m "..." && git push origin vX.Y.Z`.
|
|
211
|
+
3. The tag runs [release.yml](.github/workflows/release.yml): typecheck, unit tests, smoke test, real-host e2e, then `npm publish --provenance` and a GitHub release.
|
|
212
|
+
|
|
213
|
+
Publishing uses npm Trusted Publishing (OIDC), so no `NPM_TOKEN` is required: add repository `wangxiaocuo/dsh-session-trash` and workflow `release.yml` under the package's Settings -> Publishing access -> Trusted publishers on npmjs.com. To use an automation token instead, uncomment the `NODE_AUTH_TOKEN` environment variable in release.yml and add the matching secret.
|
|
214
|
+
|
|
197
215
|
Project layout:
|
|
198
216
|
|
|
199
217
|
```text
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# dsh-session-trash
|
|
2
2
|
|
|
3
|
+
[](https://github.com/wangxiaocuo/dsh-session-trash/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
简体中文 | [English](./README.en.md)
|
|
4
6
|
|
|
5
7
|
[GitHub](https://github.com/wangxiaocuo/dsh-session-trash) · [npm](https://www.npmjs.com/package/@wangxiaocuo/dsh-session-trash) · [更新记录](./CHANGELOG.md)
|
|
@@ -13,8 +15,9 @@ DeepSeek Harness 的会话回收站插件。冷会话可以从侧边栏移出,
|
|
|
13
15
|
- 侧边栏右键会话,选择「移入回收站」。只有冷会话、没有运行中的 turn、job、subagent 或定时任务时才能移入;会话跑过的隐藏 subagent 子会话会随父会话一起移入、一起恢复。
|
|
14
16
|
- 对仍打开的会话、正在运行的会话或含可见子会话的会话,菜单保留一个带原因的「移入回收站」说明项:点开解释为什么暂时不能移入,而不是把菜单项直接隐藏。
|
|
15
17
|
- 移入后显示 DSH 共享 Toast,只有「撤销」一个动作。撤销先尝试正常恢复,原工作区不存在时改为孤儿恢复。
|
|
16
|
-
- 设置页「回收站」显示标题、Session ID
|
|
17
|
-
- 含子会话的条目显示「含 N
|
|
18
|
+
- 设置页「回收站」显示标题、Session ID、原工作区、移入时间、剩余天数、大小和状态。列表支持搜索、筛选、按移入时间/标题/大小/到期排序,每页 50 条。
|
|
19
|
+
- 含子会话的条目显示「含 N 个子会话」徽章,可展开查看每个成员(父/子会话 ID 与大小);恢复和永久删除按整棵树处理,不做部分恢复。
|
|
20
|
+
- 可勾选多个条目批量恢复(只对工作区仍存在的条目开放),也支持全选当前页。
|
|
18
21
|
- 行操作包括恢复、恢复为孤儿会话、永久删除、从索引移除、复制 Session ID,以及在 Finder 或资源管理器中显示原工作区。
|
|
19
22
|
- 工具栏「永久删除全部」在二次确认后清空回收站:删除所有已移入的会话日志,并把文件缺失的记录移出索引;附件、图片和搜索索引等衍生物不删除。
|
|
20
23
|
- 默认保留 30 天,每 6 小时扫描一次;插件激活后和打开回收站页面时也会检查。清理失败按指数退避重试,失败信息显示在页面上。
|
|
@@ -112,13 +115,15 @@ npm 安装的插件在「插件」页打开「会话回收站」的详情,展
|
|
|
112
115
|
|
|
113
116
|
| 方法 | 路径 | 说明 |
|
|
114
117
|
|---|---|---|
|
|
115
|
-
| `GET` | `/state` |
|
|
118
|
+
| `GET` | `/state` | 配置、索引状态、条目、统计和清理诊断(只读,不触发清理) |
|
|
119
|
+
| `POST` | `/sweep` | 无请求体,按节流执行一次页面维护扫描;回收站页面打开时调用,是否删除过期条目由 `enableAutoCleanup` 决定 |
|
|
116
120
|
| `POST` | `/preflight` | `{ sessionId }` 返回 `{ eligible: true, descendants }` 或 `{ eligible: false, code, message, details? }`;`descendants` 是一并移入的隐藏子会话数 |
|
|
117
121
|
| `POST` | `/trash` | `{ sessionId }`,移动整棵会话树(父会话 + 隐藏 subagent 子会话),返回 `{ ok, entry }` |
|
|
118
122
|
| `POST` | `/restore` | `{ sessionId, mode: 'normal' \| 'orphan' }` |
|
|
119
123
|
| `POST` | `/purge` | `{ sessionId }`,永久删除会话日志 |
|
|
120
124
|
| `POST` | `/purge-all` | 无请求体,永久删除回收站中的全部条目;`missing` 记录仅移除索引;返回 `{ ok, purged, forgotten, failed }` |
|
|
121
125
|
| `POST` | `/forget` | `{ sessionId }`,仅移除 `missing` 条目的索引记录 |
|
|
126
|
+
| `POST` | `/orphans/forget` | 无请求体,删除不含会话日志的空无主对象目录;返回 `{ ok, removed }` |
|
|
122
127
|
| `POST` | `/reveal` | `{ sessionId }`,打开原工作区 |
|
|
123
128
|
| `POST` | `/cleanup` | 无请求体,手动执行一次清理 |
|
|
124
129
|
| `POST` | `/rebuild` | 无请求体,仅在索引保护模式下重建 |
|
|
@@ -164,11 +169,13 @@ npm 安装的插件在「插件」页打开「会话回收站」的详情,展
|
|
|
164
169
|
- 孤儿恢复不会重建原工作区目录,也不会重新挂到工作区。
|
|
165
170
|
- 归档和置顶状态会跨回收、恢复保留,回收站页面不管理这两个集合。
|
|
166
171
|
- 永久删除只删除会话日志。附件、图片、投影缓存和搜索索引不会被删除。
|
|
172
|
+
- 无主对象(`meta.json` 损坏或无法识别的对象目录)不会自动删除;页面只能清理其中不含会话日志的空目录,可能含日志的需要人工处理。
|
|
167
173
|
- `/state` 一次返回全部条目摘要,页面在客户端搜索、筛选和分页。
|
|
168
|
-
-
|
|
174
|
+
- 同一浏览器的同源标签页通过 `BroadcastChannel` 实时同步索引变更;不同浏览器或不同设备之间仍需刷新页面。
|
|
175
|
+
- 批量恢复只包含工作区仍存在的条目;工作区缺失的条目需要逐条使用「恢复为孤儿会话」。
|
|
169
176
|
- Windows/Linux 的桌面版尚未手动验证;CI 用 npm 安装的 `dsh web` 覆盖真实 Host 行为,但桌面壳 UI 与桌面专属能力(例如「在文件管理器中显示」)仍只在 macOS 上验证。Windows 上依赖 POSIX 权限位的用例会跳过;超过 260 字符的长路径和符号链接复制受系统设置影响,对应用例在不支持时自动跳过。
|
|
170
177
|
- macOS 的路径比较按大小写不敏感处理。在大小写敏感的 APFS 卷上,仅大小写不同的两个路径会被视为同一位置。
|
|
171
|
-
- 多个 DSH 进程共享同一个 `DSH_HOME` 时,回收站操作通过 `.lock`
|
|
178
|
+
- 多个 DSH 进程共享同一个 `DSH_HOME` 时,回收站操作通过 `.lock` 串行;Host 在报 `LOCKED` 前会短暂重试,客户端也会自动重试一次;进程暂停超过 10 分钟后,锁可能被另一个进程接管。
|
|
172
179
|
|
|
173
180
|
## 开发
|
|
174
181
|
|
|
@@ -176,6 +183,7 @@ npm 安装的插件在「插件」页打开「会话回收站」的详情,展
|
|
|
176
183
|
pnpm install
|
|
177
184
|
pnpm test # 单元测试 + 真实 DOM 组件测试(jsdom)
|
|
178
185
|
pnpm typecheck # tsc --checkJs(当前覆盖 lib/ 和 index.js)
|
|
186
|
+
pnpm test:coverage # 覆盖率(CI 的门槛只作用于 lib/**)
|
|
179
187
|
pnpm test:smoke # Host 冒烟测试(真实 Cordis,普通 Node 即可)
|
|
180
188
|
npm run test:e2e # 真实 dsh web 端到端(桌面版或 npm 安装的 DSH)
|
|
181
189
|
```
|
|
@@ -188,11 +196,20 @@ Host 冒烟测试通过 `@deepseek-ai/cordis` 这个 devDependency 装配真实
|
|
|
188
196
|
|---|---|
|
|
189
197
|
| 单元测试、Host 冒烟测试 | CI:Ubuntu Node 20/22、Windows Node 22 |
|
|
190
198
|
| 打包内容(`npm pack`) | CI:Ubuntu |
|
|
199
|
+
| 覆盖率门槛(`lib/**`,行 85 / 分支 70 / 函数 84) | CI:Ubuntu Node 22 |
|
|
191
200
|
| 真实 `dsh web` 端到端(npm 安装的 DSH) | CI:Ubuntu、Windows(Node 22) |
|
|
192
201
|
| 真实 `dsh web` 端到端(桌面版) | macOS + DSH 0.2.2-rc.1(手动执行) |
|
|
193
202
|
|
|
194
203
|
`npm run test:e2e` 会启动真实 `dsh web` Host,在临时 `DSH_HOME` 中跑完整流程。默认按平台在常见安装位置查找桌面版(也可以用 `DSH_ELECTRON` 指定);设置 `DSH_E2E_DSH_BIN` 指向 npm 安装的 `@deepseek-ai/dsh` 的 `lib/bin.js` 时,改用普通 Node 启动 Host——CI 和 Linux/Windows 都走这条路径,不依赖桌面版。找不到 Host 时打印跳过信息并以 0 退出。依赖 POSIX 权限位的「清理失败」场景在 Windows 上会跳过。设置 `DSH_E2E_KEEP=1` 可以保留临时目录和日志。
|
|
195
204
|
|
|
205
|
+
### 发布(维护者)
|
|
206
|
+
|
|
207
|
+
1. 更新 `package.json` 版本和 `CHANGELOG.md`,提交并推送。
|
|
208
|
+
2. 打 tag 并推送:`git tag -a vX.Y.Z -m "..." && git push origin vX.Y.Z`。
|
|
209
|
+
3. tag 会触发 [release.yml](.github/workflows/release.yml):跑 typecheck、单测、smoke 和真实 Host e2e,然后 `npm publish --provenance` 并创建 GitHub Release。
|
|
210
|
+
|
|
211
|
+
发布使用 npm Trusted Publishing(OIDC),不需要 `NPM_TOKEN`:在 npmjs.com 的包设置 → Publishing access → Trusted publishers 里添加仓库 `wangxiaocuo/dsh-session-trash` 和 workflow `release.yml`。如果改用 automation token,取消 release.yml 里 `NODE_AUTH_TOKEN` 的注释并添加同名 secret。
|
|
212
|
+
|
|
196
213
|
项目结构:
|
|
197
214
|
|
|
198
215
|
```text
|