dsh-recall-plugin 1.2.2 → 1.4.0

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 ADDED
@@ -0,0 +1,109 @@
1
+ # 更新日志
2
+
3
+ 本文件格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
4
+
5
+ ## [1.4.0] - 2026-08-17
6
+
7
+ ### 新增
8
+
9
+ - 官方插件配置机制:`cordis.patch.yml` 行声明默认值(`gcSnaps`/`gcHours`/`maxFileBytes`/`baseExcludes`),用户在 profile 的 `cordis.patch.yml` 按 `id: recall` 重述该行即可覆盖;`DSH_RECALL_GC_SNAPS/GC_HOURS` 环境变量保留为最高优先(向后兼容)。
10
+ - 回退前自动保存安全快照(`snap-pre-rollback-<时间戳>` tag,不进列表),误回退后可从该 tag 找回,堵住唯一的不可逆操作缺口;确认面板文案同步说明。
11
+ - 设置页「快照管理」卡片:快照列表(时间倒序,含工作区名/会话标题)、当前工作区磁盘占用、单条删除、「立即 gc」手动触发、最近错误展示(Host 侧失败原本只在宿主进程日志,页面不可见)。
12
+ - 快照列表跨工作区名称解析:`saveIndex` 条目持久化 `root`;store 目录新增 `root.txt` 元数据(旧 store 重新解析时自动补写);工作区 cwd 全集取「live 注册表 + `sessionQuery.listSessions` 冷元数据」并集(冷启动注册表为空也能解析)。
13
+ - 快照管理性能优化:新增双平台 `storesDumpScript` 一条 shell 批量 dump 全部 store 元数据(旧实现每目录 2-3 条 shell 串行,冷列表 20 秒级);列表 30 秒结果缓存(删除/新快照失效);冷会话标题两段式——列表首屏只查 live/缓存(同步瞬时),冷标题(整日志解压 10 秒级)由客户端异步 `titles` 端点补齐、行内先显示「…」。实测冷列表 20s+ → 2.3s、缓存命中 8ms、删除 20s+ → 4.4s。
14
+ - Host 新增 `manage`(list/usage/delete/gc)与 `status`(最近错误环形缓冲)端点;`preview`/`execute` 与快照/gc 共用同一条串行队列,消除 git index 锁并发竞态。
15
+ - 变更清单截断保护:超过 500 条时面板显示「仅显示前 N 条」,总数仍准确;请求体 1MB 上限(`BODY_TOO_LARGE`);启动时自检两套脚本模板的同名导出对齐。
16
+
17
+ ### 修复
18
+
19
+ - 索引载入失败(如 shell 未就绪)后该工作区本次进程内被永久标记「已载入」、撤回按钮消失直到重启——改为读取链路全部走通后才标记,失败自然重试。
20
+ - 快照列表「未知工作区」与同快照重复行:旧列表只查内存 `state.snapshots` 且去重 key 带 root——冷启动注册表为空时全部落空。修复后磁盘来源三层解析 root、去重只按消息 ID。
21
+ - 管理页删除误报「该快照不存在」:列表来自磁盘全量而删除只查内存——修复为「内存 → 条目 root → 磁盘 index 反查(`locateSnapshotOnDisk`)」解析链;兜底删除前先 `loadIndex` 补齐内存视图,防止 `saveIndex` 用残缺内存覆盖 index.json 抹掉同 store 其余快照;`purgeSession` 对未缓存 root 现场解析 store(原先直接跳过导致该 root 清理永远 miss)。
22
+ - 事件重放/重发产生重复 messageId 时 `git tag` 重名 fatal 导致整条快照失败——改 `tag -f`(同一条消息重快照取最新状态)。
23
+ - A→B→A 切换会话后 A 复用 B 的 init promise——init 缓存改 `Map<会话, Promise>`。
24
+
25
+ ### 变更
26
+
27
+ - 错误回包统一为 `{ok, code, message}`(业务失败与系统异常分离,文案与诊断解耦)。
28
+ - `saveIndex`/`writeExclude` 的 win32 base64 分块与 POSIX stdin 分叉合并为统一落盘原语 `writeTextViaShell`;脚本导出 `indexWriteCmd`/`excludeWriteCmd` 合并为 `fileWriteCmd`。
29
+ - `resolveHomeContainer` 改纯 JS 推导(容器 = home 目录父级),删除与 `homeDirScript` 重复的整条 `$h` shell 解析链(消除双链漂移风险)。
30
+ - `maintenance.js` 导出面收敛为 `maybeMaintain`/`runGc`;删除 `index.json` 的死字段 `count`;删除未使用的非 scoped `cordis` peerDependency。
31
+ - Host 端点分发重构为端点表 + 统一 try/catch;Client 侧 `kind` 语义(文案/徽章类名/汇总)合并为单表。
32
+
33
+ ### 兼容性
34
+
35
+ - 全部改动经冒烟实测:临时中文+空格工作区上跑通真实 git 链路(建仓/快照/tag -f 幂等/diff 三类变更检出/回退恢复与删除/分块索引读写/tag 清理/gc/磁盘统计),Windows PowerShell 5.1 与 pwsh 7 双解释器通过。
36
+ - 评估阶段曾将 win32 回退改为 bsdtar 优先,冒烟实测否决:GBK 代码页机器上 bsdtar 把 tar 流里的 UTF-8 文件名按 ANSI 解码(中文文件名解包成乱码新文件),已回滚为 zip + Expand-Archive 链路(中文路径实测正确,mtime 语义天然安全)。
37
+
38
+ ## [1.3.0] - 2026-08-17
39
+
40
+ ### 新增
41
+
42
+ - 设置页「撤回设置」标签(设置 → 插件):可视化编辑快照排除项——输入路径或模式回车即加、常用模式一键追加(`dist/`、`*.log`、`.env` 等)、放弃修改/保存与未保存状态提示,保存后下一次快照/预览/回退立即生效,无需重启。
43
+ - Host 端 `exclude-get` / `exclude-set` HTTP 端点:枚举并读写全部 exclude.txt(home 存储全局共享一份,降级工作区各自独立、分卡片展示);写入走 base64 分块(win32)/ stdin(POSIX),任意长度配置不受命令行上限约束;写入路径经服务端白名单校验(仅接受枚举结果中的路径)。
44
+ - 冷启动兜底:会话注册表未载入时按磁盘 home 容器目录枚举 exclude.txt(`resolveHomeContainer`),设置页不再误报「尚未创建快照存储」。
45
+
46
+ ### 兼容性
47
+
48
+ - 全部新增 shell 命令在 Windows PowerShell 5.1 与 WSL2 Ubuntu(bash)实测通过,覆盖中文/空格路径、CRLF、空文件、缺失文件等边界。
49
+
50
+ ## [1.2.2] - 2026-08-15
51
+
52
+ ### 修复
53
+
54
+ - 撤回出的新会话不再向标题追加递增数字:fork 不传 `increaseTitle`,原样继承原标题。
55
+
56
+ ### 文档
57
+
58
+ - 新增英文 README(README.en.md,与中文版互链)与 AGENTS.md 项目速览。
59
+
60
+ ## [1.2.1] - 2026-08-15
61
+
62
+ ### 修复
63
+
64
+ - 修正 package.json 仓库地址(仓库改名后同步);README 安装地址同步。
65
+
66
+ ## [1.2.0] - 2026-08-15
67
+
68
+ ### 新增
69
+
70
+ - Linux/macOS(bash)平台支持:与 Windows 版同名导出的脚本模板按 `process.platform` 单选;POSIX 侧 `DSH_HOME` 解析对齐执行器 env 洗刷语义(WSL2 实测)。
71
+ - 快照自动维护:定期 `git gc`(每 50 条快照或 24 小时先到先触发,`DSH_RECALL_GC_SNAPS` / `DSH_RECALL_GC_HOURS` 可调,`gc.stamp` 跨重启续存节流)。
72
+ - 会话删除联动清理:会话日志从磁盘消失后自动删除该会话全部快照 tag 并释放空间;归档不算删除,判断保守(冷会话不误清)。
73
+ - 用户自定义排除:home 下 `exclude.txt`(gitignore 语法)全局生效,下一次快照/回退即时应用。
74
+
75
+ ### 变更
76
+
77
+ - Host 代码模块化拆分(index / store / snapshots / maintenance / scripts.*),零顶层副作用,全部副作用经 `ctx.on` / `ctx.effect`。
78
+
79
+ ## [1.0.4] - 2026-08-15
80
+
81
+ ### 修复
82
+
83
+ - 非 UTF-8 代码页(GBK)输出乱码、UNC home、非 Windows 平台的通用性问题。
84
+
85
+ ## [1.0.3] - 2026-08-15
86
+
87
+ ### 修复
88
+
89
+ - 跨机器通用性:git 多候选安装位置探测、索引 base64 分块写入(突破命令行 32767 上限)、目录扫描容错(杀软锁定/异常 ACL)、路径尾分隔符归一、`DSH_HOME` 回退链。
90
+
91
+ ## [1.0.2] - 2026-08-15
92
+
93
+ ### 新增
94
+
95
+ - 未装 git / home 不可写时页面顶部一次性降级提示(gitMissing / homeFallback)。
96
+
97
+ ## [1.0.1] - 2026-08-15
98
+
99
+ ### 变更
100
+
101
+ - shell 以宿主身份(`danger-full-access`)执行:受限会话(workspace-write / read-only)也能在 home 建影子仓库、照常快照与回退。
102
+
103
+ ## [1.0.0] - 2026-08-15
104
+
105
+ ### 初始发布
106
+
107
+ - 消息撤回:影子 git 仓库快照(tag 即快照,项目目录零污染)+ 官方 `sessions.fork` 对话整段回退,原会话归档可找回。
108
+ - 确认面板先展示变更文件清单(修改/恢复/删除)再执行;`.git`、`node_modules` 自动排除;超过 100MB 的大文件跳过。
109
+ - key 冲突递减重试的 user 槽位注册,Windows PowerShell 5.1 / 7 双版本兼容。
package/README.en.md CHANGED
@@ -1,118 +1,124 @@
1
- # dsh-recall-plugin
2
-
3
- > Recall a message, and your project files go back with it.
4
-
5
- [简体中文](README.md) | English
6
-
7
- ![npm](https://img.shields.io/npm/v/dsh-recall-plugin?label=npm&color=cb3837)
8
- ![License](https://img.shields.io/badge/license-MIT-blue)
9
- ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-blue)
10
- ![DSH](https://img.shields.io/badge/DSH-0.1.0--rc-blue)
11
- ![Build](https://img.shields.io/badge/pure%20JS-zero%20build-green)
12
-
13
- ---
14
- **Under any message you've sent**, **click "↶ Recall"**, **and both your workspace files and the conversation history roll back to the moment right before that message was sent**.
15
-
16
- ## UI Preview
17
- - Recall button location
18
-
19
- ![Recall button appears on hover](docs/screenshots/recall-button.png)
20
-
21
- ---
22
- | Confirmation panel · file change list | |
23
- | --- | --- |
24
- | ![Confirmation panel · file change list](docs/screenshots/confirm-panel-1.png) | ![Confirmation panel](docs/screenshots/confirm-panel-2.png) |
25
-
26
- ## Highlights
27
-
28
- - **Files + conversation, rolled back together**: recalling isn't just about chat history — files the agent modified go back to their original state too.
29
- - **Never touches your project's own git**: snapshots live in an independent shadow git repository; your branches, staging area, and uncommitted changes are untouched. `.git` and `node_modules` are excluded automatically.
30
- - **Keeps your project directory clean**: snapshots always live under `$DSH_HOME`, nothing is ever dropped into your project — regardless of the session's sandbox permission (workspace-write / read-only sessions snapshot and recall as usual). Only when home itself is unwritable (e.g. pointed at a read-only drive) does it fall back to an in-project `.dsh-recall-snapshots` directory (the page shows a notice when degraded); once home is writable again, data migrates back and the fallback directory is cleaned up.
31
- - **Change your mind as many times as you like**: as long as the session still exists (including archived ones), snapshots are fully retained and never pruned. After one recall you can recall again to an even earlier point; files overwritten during a recall always remain recoverable. Once a session is permanently deleted, its snapshots are cleaned up accordingly (see below).
32
- - **See the list before you act**: clicking recall first shows the list of files that will change (modified / restored / deleted); nothing is overwritten until you confirm.
33
- - **Disk-friendly**: snapshots use git delta compression — incremental, not full-directory copies. Files larger than 100MB are skipped automatically.
34
- - **Automatic housekeeping**: periodic `git gc` packs loose objects (lossless not a single snapshot is lost); snapshots of deleted sessions are cleaned up automatically; build artifacts can be excluded globally via `exclude.txt` (see below).
35
-
36
- ## Known Limitations
37
-
38
- - Snapshots are created **when a message is sent**; messages from before the plugin was enabled have no snapshot and show no recall button.
39
- - The first user message of a session cannot roll back the conversation (files only), because fork requires an earlier turn boundary.
40
- - Supports Windows (PowerShell 5.1/7 + git CLI) and Linux/macOS (bash + git CLI). Windows is thoroughly verified on real machines; Linux has been fully tested on WSL2 (Ubuntu 26.04, bash 5.3 + git 2.53), including Chinese paths, home fallback, session cleanup, and gc; the macOS side is written to be bash 3.2 compatible but has not been tested on real hardware yet.
41
- - Nested git repositories inside the workspace (subdirectories with their own `.git`) are not snapshotted; their contents do not participate in recalls.
42
- - Extreme cases like filenames containing newlines/TAB are beyond the diff list's parsing capability (negligible probability).
43
-
44
- ## Installation
45
-
46
- Prerequisites: git CLI (without it the recall button won't appear and a notice shows at the top of the page DSH itself keeps running); PowerShell 5.1 / 7 on Windows, bash + git on Linux/macOS; DSH 0.1.0-rc.x (see `peerDependencies` for dependency versions).
47
-
48
- - Official DSH plugin command: install and auto-mount into the web profile
49
- ```powershell
50
- dsh plugin --profile web add dsh-recall-plugin
51
- ```
52
- - Or install directly from git (pure JS, no build step, no prepare/allowBuilds needed):
53
- ```powershell
54
- dsh plugin --profile web add github:limbo947/dsh-recall-plugin
55
- ```
56
- - Restart the DSH process (pick whichever matches how you start it)
57
- ```powershell
58
- dsh web # run in the foreground
59
- pm2 restart <your-dsh-name> # if managed by pm2
60
- ```
61
-
62
- **Verify**: after restarting, hard-refresh the page (Ctrl+Shift+R) and hover over any user message sent after the plugin was enabled — the "↶" appearing next to the copy button means it works. No button? Nine times out of ten the DSH process wasn't restarted, or git CLI isn't on PATH.
63
-
64
- **Uninstall**: `dsh plugin --profile web remove dsh-recall-plugin` (removes both the dependency and the mount layer). Snapshot data is kept under `dsh-recall-snapshots/` in home; delete that directory manually if you want it fully gone.
65
-
66
- ## Usage
67
-
68
- 1. Hover over any user message sent **after the plugin was enabled** — "↶ Recall" appears to the left of the copy button.
69
- 2. Click it → the confirmation panel shows the list of files that will change (modified / restored / deleted).
70
- 3. Click "Confirm rollback" files are restored to their state before that message was sent; the view switches to a new session (that message and everything after it is removed), while the original session is archived and can be recovered anytime.
71
-
72
- ## Snapshot Maintenance & Cleanup
73
-
74
- Snapshots are fully retained as long as "the session might still be recoverable"; on top of that, the plugin manages disk usage automatically — no manual housekeeping needed:
75
-
76
- - **Periodic gc**: every 50 snapshots or 24 hours since the last gc (whichever comes first), `git gc` runs in the background to pack loose objects. This is lossless every snapshot remains recallable. The throttle token lives in `gc.stamp` inside the shadow repository, so restarting DSH does not reset the cycle. Both thresholds can be overridden via environment variables (rarely needed): `DSH_RECALL_GC_SNAPS`, `DSH_RECALL_GC_HOURS`.
77
- - **Session-deletion cleanup**: once a session is permanently deleted (its log gone from disk), the next maintenance pass automatically removes all of its snapshots and frees the space. **Archiving is not deletion** — logs of sessions archived by the recall feature itself still exist, so their snapshots are kept and recoverable from the archive. The check is conservative: a session that is merely cold (not in memory) is never cleaned, and when the log's state cannot be verified, it is left alone.
78
- - **User-defined exclusions**: put one gitignore-style pattern per line in `dsh-recall-snapshots/exclude.txt` under home (i.e. `$DSH_HOME/dsh-recall-snapshots/exclude.txt`, or `~/.dsh/dsh-recall-snapshots/exclude.txt` when unset; UTF-8; lines starting with `#` are comments), for example:
79
-
80
- ```gitignore
81
- # keep build artifacts out of snapshots
82
- dist/
83
- build/
84
- *.log
85
- ```
86
-
87
- This applies to all projects and takes effect on the next snapshot/recall, no restart needed. New exclusions only affect future snapshots; **when recalling to an earlier snapshot, files that weren't excluded at that time are still restored** (returning to the state as it was — that's exactly what recall means). To fully purge a directory that already made it into snapshots, manually delete the corresponding hash directory under `dsh-recall-snapshots/` in home.
88
-
89
- ## How It Works
90
-
91
- When each user message is sent (before the agent touches any files), the workspace is snapshotted into an independent shadow git repository; on recall, files are restored via `git archive` and the conversation is rewound through DSH's official `sessions.fork` mechanism. Binary-safe, and your project's own git state is never touched.
92
-
93
- - Snapshot storage: `dsh-recall-snapshots/<SHA256(project absolute path)>/` under home, containing the shadow git repository (`git/`, tags named `snap-<messageID>`) and the index file `index.json` (message ID snapshot time / session). Scripts run via PowerShell on Windows and bash on Linux/macOS (forked automatically by the executor mounted on the `ctx.shell` platform layer).
94
- - To browse historical snapshots directly:
95
-
96
- ```powershell
97
- git --git-dir="<store>\git\.git" tag -l
98
- git --git-dir="<store>\git\.git" ls-tree -r --name-only snap-<messageID>
99
- ```
100
-
101
-
102
-
103
- ## Local Development (without publishing)
104
-
105
- ```powershell
106
- # Drop the package directory into the web profile's node_modules and register it in bundles
107
- $pkg = '<path-to-your-clone>\dsh-recall-plugin'
108
- $profile = "$env:USERPROFILE\.dsh\profiles\web"
109
- Copy-Item -Recurse -Force $pkg "$profile\node_modules\dsh-recall-plugin"
110
- # Manually edit $profile\package.json:
111
- # add "dsh-recall-plugin": "1.0.0" to dependencies
112
- # add "dsh-recall-plugin" to dsh.profile.bundles
113
- # then restart DSH and hard-refresh the page
114
- ```
115
-
116
- ## License
117
-
118
- MIT
1
+ # dsh-recall-plugin
2
+
3
+ > Recall a message, and your project files go back with it.
4
+
5
+ [简体中文](README.md) | English
6
+
7
+ ![npm](https://img.shields.io/npm/v/dsh-recall-plugin?label=npm&color=cb3837)
8
+ ![License](https://img.shields.io/badge/license-MIT-blue)
9
+ ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-blue)
10
+ ![DSH](https://img.shields.io/badge/DSH-0.1.0--rc-blue)
11
+ ![Build](https://img.shields.io/badge/pure%20JS-zero%20build-green)
12
+
13
+ ---
14
+ **Under any message you've sent**, **click "↶ Recall"**, **and both your workspace files and the conversation history roll back to the moment right before that message was sent**.
15
+
16
+ ## UI Preview
17
+ - Recall button location
18
+
19
+ ![Recall button appears on hover](docs/screenshots/recall-button.png)
20
+
21
+ ---
22
+ | Confirmation panel · file change list | |
23
+ | --- | --- |
24
+ | ![Confirmation panel · file change list](docs/screenshots/confirm-panel-1.png) | ![Confirmation panel](docs/screenshots/confirm-panel-2.png) |
25
+
26
+ - Settings page · quick exclusion editing (Settings → Plugins → Recall Settings)
27
+
28
+ | Settings | Settings |
29
+ | --- | --- |
30
+ | ![Settings·editing](docs/screenshots/settings-exclude-1.png) | ![Settings·saved](docs/screenshots/settings-exclude-2.png) |
31
+
32
+ ## Highlights
33
+
34
+ - **Files + conversation, rolled back together**: recalling isn't just about chat history files the agent modified go back to their original state too.
35
+ - **Never touches your project's own git**: snapshots live in an independent shadow git repository; your branches, staging area, and uncommitted changes are untouched. `.git` and `node_modules` are excluded automatically.
36
+ - **Keeps your project directory clean**: snapshots always live under `$DSH_HOME`, nothing is ever dropped into your project — regardless of the session's sandbox permission (workspace-write / read-only sessions snapshot and recall as usual). Only when home itself is unwritable (e.g. pointed at a read-only drive) does it fall back to an in-project `.dsh-recall-snapshots` directory (the page shows a notice when degraded); once home is writable again, data migrates back and the fallback directory is cleaned up.
37
+ - **Change your mind as many times as you like**: as long as the session still exists (including archived ones), snapshots are fully retained and never pruned. After one recall you can recall again to an even earlier point; files overwritten during a recall always remain recoverable. Once a session is permanently deleted, its snapshots are cleaned up accordingly (see below).
38
+ - **See the list before you act**: clicking recall first shows the list of files that will change (modified / restored / deleted); nothing is overwritten until you confirm.
39
+ - **Disk-friendly**: snapshots use git delta compression incremental, not full-directory copies. Files larger than 100MB are skipped automatically.
40
+ - **Automatic housekeeping**: periodic `git gc` packs loose objects (lossless not a single snapshot is lost); snapshots of deleted sessions are cleaned up automatically; build artifacts can be excluded globally via `exclude.txt` (see below).
41
+
42
+ ## Known Limitations
43
+
44
+ - Snapshots are created **when a message is sent**; messages from before the plugin was enabled have no snapshot and show no recall button.
45
+ - The first user message of a session cannot roll back the conversation (files only), because fork requires an earlier turn boundary.
46
+ - Supports Windows (PowerShell 5.1/7 + git CLI) and Linux/macOS (bash + git CLI). Windows is thoroughly verified on real machines; Linux has been fully tested on WSL2 (Ubuntu 26.04, bash 5.3 + git 2.53), including Chinese paths, home fallback, session cleanup, and gc; the macOS side is written to be bash 3.2 compatible but has not been tested on real hardware yet.
47
+ - Nested git repositories inside the workspace (subdirectories with their own `.git`) are not snapshotted; their contents do not participate in recalls.
48
+ - Extreme cases like filenames containing newlines/TAB are beyond the diff list's parsing capability (negligible probability).
49
+
50
+ ## Installation
51
+
52
+ Prerequisites: git CLI (without it the recall button won't appear and a notice shows at the top of the page — DSH itself keeps running); PowerShell 5.1 / 7 on Windows, bash + git on Linux/macOS; DSH 0.1.0-rc.x (see `peerDependencies` for dependency versions).
53
+
54
+ - Official DSH plugin command: install and auto-mount into the web profile
55
+ ```powershell
56
+ dsh plugin --profile web add dsh-recall-plugin
57
+ ```
58
+ - Or install directly from git (pure JS, no build step, no prepare/allowBuilds needed):
59
+ ```powershell
60
+ dsh plugin --profile web add github:limbo947/dsh-recall-plugin
61
+ ```
62
+ - Restart the DSH process (pick whichever matches how you start it)
63
+ ```powershell
64
+ dsh web # run in the foreground
65
+ pm2 restart <your-dsh-name> # if managed by pm2
66
+ ```
67
+
68
+ **Verify**: after restarting, hard-refresh the page (Ctrl+Shift+R) and hover over any user message sent after the plugin was enabled — the "↶" appearing next to the copy button means it works. No button? Nine times out of ten the DSH process wasn't restarted, or git CLI isn't on PATH.
69
+
70
+ **Uninstall**: `dsh plugin --profile web remove dsh-recall-plugin` (removes both the dependency and the mount layer). Snapshot data is kept under `dsh-recall-snapshots/` in home; delete that directory manually if you want it fully gone.
71
+
72
+ ## Usage
73
+
74
+ 1. Hover over any user message sent **after the plugin was enabled** " Recall" appears to the left of the copy button.
75
+ 2. Click it → the confirmation panel shows the list of files that will change (modified / restored / deleted).
76
+ 3. Click "Confirm rollback" files are restored to their state before that message was sent; the view switches to a new session (that message and everything after it is removed), while the original session is archived and can be recovered anytime.
77
+
78
+ ## Snapshot Maintenance & Cleanup
79
+
80
+ Snapshots are fully retained as long as "the session might still be recoverable"; on top of that, the plugin manages disk usage automatically — no manual housekeeping needed:
81
+
82
+ - **Periodic gc**: every 50 snapshots or 24 hours since the last gc (whichever comes first), `git gc` runs in the background to pack loose objects. This is lossless — every snapshot remains recallable. The throttle token lives in `gc.stamp` inside the shadow repository, so restarting DSH does not reset the cycle. Both thresholds can be overridden via environment variables (rarely needed): `DSH_RECALL_GC_SNAPS`, `DSH_RECALL_GC_HOURS`.
83
+ - **Session-deletion cleanup**: once a session is permanently deleted (its log gone from disk), the next maintenance pass automatically removes all of its snapshots and frees the space. **Archiving is not deletion** — logs of sessions archived by the recall feature itself still exist, so their snapshots are kept and recoverable from the archive. The check is conservative: a session that is merely cold (not in memory) is never cleaned, and when the log's state cannot be verified, it is left alone.
84
+ - **User-defined exclusions**: open "**Settings → Plugins → Recall Settings**" to edit snapshot exclusions visually — type a path or pattern and press Enter to add it, one-click append for common patterns (`dist/`, `*.log`, `.env`, …), and saved changes take effect on the very next snapshot/recall, no restart needed. Alternatively, edit `dsh-recall-snapshots/exclude.txt` under home directly (i.e. `$DSH_HOME/dsh-recall-snapshots/exclude.txt`, or `~/.dsh/dsh-recall-snapshots/exclude.txt` when unset; UTF-8; one gitignore-style pattern per line; lines starting with `#` are comments) — both paths edit the same configuration, for example:
85
+
86
+ ```gitignore
87
+ # keep build artifacts out of snapshots
88
+ dist/
89
+ build/
90
+ *.log
91
+ ```
92
+
93
+ This applies to all projects (when home is unwritable and a workspace falls back to in-project storage, it gets its own independent exclusion config, listed as a separate card in the settings tab). New exclusions only affect future snapshots; **when recalling to an earlier snapshot, files that weren't excluded at that time are still restored** (returning to the state as it was — that's exactly what recall means). To fully purge a directory that already made it into snapshots, manually delete the corresponding hash directory under `dsh-recall-snapshots/` in home. The settings tab requires DSH's built-in settings page (all 0.1.0-rc.x releases have it); on very old versions without the tab, editing the file directly is equivalent.
94
+
95
+ ## How It Works
96
+
97
+ When each user message is sent (before the agent touches any files), the workspace is snapshotted into an independent shadow git repository; on recall, files are restored via `git archive` and the conversation is rewound through DSH's official `sessions.fork` mechanism. Binary-safe, and your project's own git state is never touched.
98
+
99
+ - Snapshot storage: `dsh-recall-snapshots/<SHA256(project absolute path)>/` under home, containing the shadow git repository (`git/`, tags named `snap-<messageID>`) and the index file `index.json` (message ID → snapshot time / session). Scripts run via PowerShell on Windows and bash on Linux/macOS (forked automatically by the executor mounted on the `ctx.shell` platform layer).
100
+ - To browse historical snapshots directly:
101
+
102
+ ```powershell
103
+ git --git-dir="<store>\git\.git" tag -l
104
+ git --git-dir="<store>\git\.git" ls-tree -r --name-only snap-<messageID>
105
+ ```
106
+
107
+
108
+
109
+ ## Local Development (without publishing)
110
+
111
+ ```powershell
112
+ # Drop the package directory into the web profile's node_modules and register it in bundles
113
+ $pkg = '<path-to-your-clone>\dsh-recall-plugin'
114
+ $profile = "$env:USERPROFILE\.dsh\profiles\web"
115
+ Copy-Item -Recurse -Force $pkg "$profile\node_modules\dsh-recall-plugin"
116
+ # Manually edit $profile\package.json:
117
+ # add "dsh-recall-plugin": "1.0.0" to dependencies
118
+ # add "dsh-recall-plugin" to dsh.profile.bundles
119
+ # then restart DSH and hard-refresh the page
120
+ ```
121
+
122
+ ## License
123
+
124
+ MIT