dsh-recall-plugin 1.2.0 → 1.2.2
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/README.en.md +118 -0
- package/README.md +3 -1
- package/lib/client.js +5 -1
- package/package.json +3 -2
package/README.en.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# dsh-recall-plugin
|
|
2
|
+
|
|
3
|
+
> Recall a message, and your project files go back with it.
|
|
4
|
+
|
|
5
|
+
[简体中文](README.md) | English
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
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
|
+

|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
| Confirmation panel · file change list | |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
|  |  |
|
|
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
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> 撤回一条消息,项目文件也一起回去。
|
|
4
4
|
|
|
5
|
+
简体中文 | [English](README.en.md)
|
|
6
|
+
|
|
5
7
|

|
|
6
8
|

|
|
7
9
|

|
|
@@ -50,7 +52,7 @@ dsh plugin --profile web add dsh-recall-plugin
|
|
|
50
52
|
```
|
|
51
53
|
- 也可从 git 直接安装(纯 JS 无构建,免 prepare/allowBuilds):
|
|
52
54
|
```powershell
|
|
53
|
-
dsh plugin --profile web add github:limbo947/
|
|
55
|
+
dsh plugin --profile web add github:limbo947/dsh-recall-plugin
|
|
54
56
|
```
|
|
55
57
|
- 重启 DSH 进程(按你的启动方式,任选其一)
|
|
56
58
|
```powershell
|
package/lib/client.js
CHANGED
|
@@ -368,7 +368,11 @@ window.__ModuleLoader__.load({
|
|
|
368
368
|
let chatError = ''
|
|
369
369
|
if (cutSeq !== null && sessionsSvc && typeof sessionsSvc.fork === 'function') {
|
|
370
370
|
try {
|
|
371
|
-
|
|
371
|
+
// 撤回语义是「回退」而非「复制」:新会话顶替原会话(原会话已
|
|
372
|
+
// 归档),必须原样继承标题。increaseTitle 是官方侧栏「复制会话」
|
|
373
|
+
// 用来区分新旧会话的,会把标题改成「xxx 2」且多次撤回时数字
|
|
374
|
+
// 不断递增,与「同一会话回退」的用户观感相悖,故不传。
|
|
375
|
+
const childId = await sessionsSvc.fork({ sessionId, atSeq: cutSeq })
|
|
372
376
|
if (childId) {
|
|
373
377
|
if (typeof sessionsSvc.open === 'function') sessionsSvc.open(childId)
|
|
374
378
|
chatReverted = true
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-recall-plugin",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "DSH 消息撤回插件:在用户消息气泡旁加「撤回」按钮,把项目文件(独立影子 git 仓库快照)与对话历史(官方 fork)一并回退到该消息发送之前。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/limbo947/
|
|
8
|
+
"url": "git+https://github.com/limbo947/dsh-recall-plugin.git"
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"lib",
|
|
21
21
|
"cordis.patch.yml",
|
|
22
22
|
"README.md",
|
|
23
|
+
"README.en.md",
|
|
23
24
|
"LICENSE"
|
|
24
25
|
],
|
|
25
26
|
"engines": {
|