dsh-recall-plugin 2.6.1 → 2.6.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/CHANGELOG.md +7 -0
- package/README.en.md +2 -1
- package/README.md +2 -1
- package/lib/scripts.posix.js +1 -1
- package/lib/scripts.pwsh.js +31 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
本文件格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## [2.6.2] - 2026-11-03
|
|
6
|
+
|
|
7
|
+
### 修复
|
|
8
|
+
|
|
9
|
+
- **Windows 保留设备名不再反复触发快照跳过提示(issue #32)**:`nul`、`aux`、`con`、`prn`、`com1`…、`lpt1`… 及其扩展名和上标数字变体在 `git add` 前默认排除,覆盖任意子目录;规则仅适用于 Windows,不进入构建产物 root 判定,POSIX 合法同名文件不受影响。这些路径保持「不恢复、不删除」的既有回退语义。
|
|
10
|
+
- **0 字节 `nul` 等路径的失败提示不再静默丢失**:`SNAP_SKIP` 同时识别 Git 的 `unable to index file 'X'` 与 `unable to add 'X' to index`,PowerShell 与 bash 模板均已覆盖。
|
|
11
|
+
|
|
5
12
|
## [2.6.1] - 2026-10-31
|
|
6
13
|
|
|
7
14
|
### 新增
|
package/README.en.md
CHANGED
|
@@ -77,6 +77,7 @@ Boundaries accepted by design and edge cases not yet covered — worth checking
|
|
|
77
77
|
- Recall cannot be initiated while an agent is running in the target workspace (by design — stop the agent first).
|
|
78
78
|
- 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.
|
|
79
79
|
- Nested git repositories inside the workspace (subdirectories with their own `.git`) cannot be indexed: the snapshot proceeds for everything else (fail-open, with a notice listing the skipped paths), but their contents do not participate in recalls.
|
|
80
|
+
- Windows reserved device names (such as `nul`, `aux`, `con`, and `com1`, including extension forms) cannot be indexed by Git and are excluded from snapshots and recalls by default. These paths are left untouched and do not generate repeated skip notices. This exclusion applies only to Windows.
|
|
80
81
|
- **Directory reparse points** in the workspace (junctions / directory symlinks) are not snapshotted by default: the subtree they point at is not indexed, so its contents do not participate in recalls. This is required on Windows, where git for Windows treats a junction as an ordinary directory and a self-referencing one inflates the index up to Windows' 31-reparse-point path limit (a two-file workspace measured 64 index entries); on POSIX a symlink still enters the snapshot (git records it as a `120000` entry and never recurses). To deliberately snapshot a **benign** junction (pointing outside the workspace, non-self-referencing), append `!path/` (e.g. `!ext-link/`) in the exclusion settings — user rules take effect after machine-generated ones; **never do this for a self-referencing junction** (the explosion vector).
|
|
81
82
|
- Extreme cases like filenames containing newlines/TAB are beyond the diff list's parsing capability (negligible probability).
|
|
82
83
|
- **Interplay with dsh-routing-suite (progressive tool-disclosure router)**: if you also run its router-standard preset, a recall forks a new session via `sessions.fork`, which resets the router's stage to its default (the tool surface temporarily narrows). Symptoms, root cause and the fix are documented in [docs/routing-interplay.md](docs/routing-interplay.md) (Chinese).
|
|
@@ -201,7 +202,7 @@ The most common questions and their troubleshooting paths; for the full set of d
|
|
|
201
202
|
|
|
202
203
|
**No "↶ Recall" button next to a message?** Check in order of likelihood: (1) the DSH process wasn't restarted after installing — restart it and hard-refresh (Ctrl+Shift+R); (2) git CLI isn't on PATH — a notice shows at the top of the page; (3) the message predates the plugin — snapshots are only created when a message is sent; (4) snapshots are disabled for that workspace — it sits under a directory-form exclusion (e.g. opened inside `dist/`), exceeded the `maxWorkspaceBytes` / `scanBudgetMs` guardrails, or the pre-snapshot size scan itself failed (`git ls-files` error; the reason is in "Recent errors" and it retries after 10 minutes) — recent messages carry a recovery notice (raise the limit or extend the exclusion list and it recovers automatically).
|
|
203
204
|
|
|
204
|
-
**Some files weren't restored by a recall?** They weren't in the snapshot: larger than `maxFileBytes` (8MB by default), matched by the exclusion list, or inside a nested git repository / a win32 reparse point (see "Known Limitations"). The confirmation panel's file list before a recall is the exact rollback scope — trust it.
|
|
205
|
+
**Some files weren't restored by a recall?** They weren't in the snapshot: larger than `maxFileBytes` (8MB by default), matched by the exclusion list (including Windows reserved device names), or inside a nested git repository / a win32 reparse point (see "Known Limitations"). The confirmation panel's file list before a recall is the exact rollback scope — trust it.
|
|
205
206
|
|
|
206
207
|
**Snapshots eating too much disk?** Open "Settings → Plugin Config → Recall Plugin → Snapshot Manager" to see per-workspace usage, run "gc now", or delete by workspace / session / single snapshot; longer-term, lower `maxSnapshotsPerWorkspace`, set `retentionDays`, or add big directories to the exclusion list.
|
|
207
208
|
|
package/README.md
CHANGED
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
- 目标工作区的 agent 正在运行时无法发起撤回(防护设计,先停止 agent 再撤回)。
|
|
75
75
|
- 支持 Windows(PowerShell 5.1/7 + git CLI)与 Linux/macOS(bash + git CLI)。Windows 真机验证充分;Linux 已在 WSL2(Ubuntu 26.04,bash 5.3 + git 2.53)实测全流程(含中文路径、home 降级、会话清理、gc);macOS 侧脚本按 bash 3.2 兼容编写,尚未真机实测。
|
|
76
76
|
- 工作区内嵌套的其他 git 仓库(子目录自带 `.git`)无法索引:其余部分快照照常(fail-open,页面会提示跳过了哪些路径),但其内容不参与回退。
|
|
77
|
+
- Windows 保留设备名(如 `nul`、`aux`、`con`、`com1`,含扩展名形式)无法由 Git 索引,默认不参与快照与回退;这些路径保持原样,也不会反复产生跳过提示。此排除仅适用于 Windows。
|
|
77
78
|
- 工作区内的**目录重解析点**(junction / 目录符号链接)默认不参与快照:它们指向的子树不会被索引,因此那部分内容不参与回退。win32 上这是必需的——git for Windows 把 junction 当普通目录递归,自引用 junction 会让索引膨胀到 Windows 的 31 层重解析点上限(实测 2 个文件的工作区产出 64 条索引);POSIX 侧符号链接照常进快照(git 记成 `120000` 条目,不递归进目标)。确需把某个**良性** junction(指向工作区外、非自引用)纳入快照时,可在排除配置里追加 `!路径/`(如 `!ext-link/`)反选恢复——用户排除行在机器生成行之后生效;**切勿对自引用 junction 使用**(爆炸根因)。
|
|
78
79
|
- 文件名含换行/TAB 的极端情形超出 diff 清单的解析能力(概率可忽略)。
|
|
79
80
|
- **与 dsh-routing-suite(渐进式工具披露路由)的交互**:同时启用其 router-standard 预设时,撤回经 `sessions.fork` 出新会话会把路由阶段重置为默认(工具面临时收窄)。现象、成因与解决方案见 [docs/routing-interplay.md](docs/routing-interplay.md)。
|
|
@@ -199,7 +200,7 @@ peerDependencies 按 minor 版本线开窗,与 `dsh.compatibility.dshReleases`
|
|
|
199
200
|
|
|
200
201
|
**消息旁没有「↶ 撤回」按钮?** 按概率排查:① 装完没重启 DSH 进程——重启后硬刷新页面(Ctrl+Shift+R);② git CLI 不在 PATH——页面顶部会有安装提示;③ 该消息发送于插件启用之前——快照只在消息发送时创建,历史消息无快照;④ 该工作区被停用快照——工作区开在 `dist/`、`target/` 这类命中基础排除表目录形态的位置,或超出 `maxWorkspaceBytes` / `scanBudgetMs` 护栏,或快照前的范围统计本身失败(`git ls-files` 报错,原因见「最近错误」,10 分钟后自动重试);最近消息上会给出恢复提示(调大上限或补充排除表后自动恢复)。
|
|
201
202
|
|
|
202
|
-
**撤回后个别文件没有恢复?** 该文件不在快照里:超过 `maxFileBytes`(默认 8MB
|
|
203
|
+
**撤回后个别文件没有恢复?** 该文件不在快照里:超过 `maxFileBytes`(默认 8MB)、命中排除表(含 Windows 保留设备名),或位于嵌套 git 仓库 / win32 目录重解析点内(见「已知限制」)。撤回前确认面板的清单就是实际回退范围,以它为准。
|
|
203
204
|
|
|
204
205
|
**快照占用磁盘太多?** 打开「设置 → 插件配置 → 撤回插件 → 快照管理」查看各工作区占用,可「立即 gc」或按工作区 / 会话 / 单条分级删除;长期可压低 `maxSnapshotsPerWorkspace`、设置 `retentionDays`,或把大目录补进排除表。
|
|
205
206
|
|
package/lib/scripts.posix.js
CHANGED
|
@@ -246,7 +246,7 @@ function snapshotScript(root, store, gitExe, messageId, base) {
|
|
|
246
246
|
"addrc=0",
|
|
247
247
|
'add_log=$("$git" --git-dir="$g" --work-tree="$root" add -A --ignore-errors "${pa_args[@]}" 2>&1) || addrc=$?',
|
|
248
248
|
`if [ "$addrc" -ge 2 ]; then printf '%s\\n' "$add_log" >&2; exit "$addrc"; fi`,
|
|
249
|
-
`printf '%s\\n' "$add_log" | sed -n "s/^error: unable to index file '\\(.*\\)'$/\\1/p" | sort -u | while IFS= read -r sk; do`,
|
|
249
|
+
`printf '%s\\n' "$add_log" | sed -n -e "s/^error: unable to index file '\\(.*\\)'$/\\1/p" -e "s/^error: unable to add '\\(.*\\)' to index$/\\1/p" | sort -u | while IFS= read -r sk; do`,
|
|
250
250
|
// 循环体用 if/fi 而非 && 列表:&& 列表条件为假时整条管道退出码为 1,
|
|
251
251
|
// set -e 会把脚本杀掉(if 语句天然豁免)
|
|
252
252
|
` if [ -n "$sk" ]; then printf 'SNAP_SKIP %s\\n' "$sk"; fi`,
|
package/lib/scripts.pwsh.js
CHANGED
|
@@ -5,6 +5,32 @@ const UTF8_PRELUDE = "$OutputEncoding = [Text.UTF8Encoding]::new($false)\ntry {
|
|
|
5
5
|
const MAX_FILE_BYTES = 8388608;
|
|
6
6
|
const STALE_LOCK_MIN = 5;
|
|
7
7
|
const HEARTBEAT_TTL_S = 900;
|
|
8
|
+
const WIN_RESERVED_EXCLUDES = [
|
|
9
|
+
"nul",
|
|
10
|
+
"nul.*",
|
|
11
|
+
"aux",
|
|
12
|
+
"aux.*",
|
|
13
|
+
"con",
|
|
14
|
+
"con.*",
|
|
15
|
+
"prn",
|
|
16
|
+
"prn.*",
|
|
17
|
+
"com[1-9]",
|
|
18
|
+
"com[1-9].*",
|
|
19
|
+
"lpt[1-9]",
|
|
20
|
+
"lpt[1-9].*",
|
|
21
|
+
"com\xB9",
|
|
22
|
+
"com\xB9.*",
|
|
23
|
+
"com\xB2",
|
|
24
|
+
"com\xB2.*",
|
|
25
|
+
"com\xB3",
|
|
26
|
+
"com\xB3.*",
|
|
27
|
+
"lpt\xB9",
|
|
28
|
+
"lpt\xB9.*",
|
|
29
|
+
"lpt\xB2",
|
|
30
|
+
"lpt\xB2.*",
|
|
31
|
+
"lpt\xB3",
|
|
32
|
+
"lpt\xB3.*"
|
|
33
|
+
];
|
|
8
34
|
const FIDELITY_ATTRS = "* -text -filter -ident -export-ignore -export-subst -working-tree-encoding";
|
|
9
35
|
function stripBom(text) {
|
|
10
36
|
return text.replace(/^\uFEFF/, "");
|
|
@@ -180,7 +206,8 @@ function limitScanBlock(maxBytes, fileMaxBytes, budgetMs) {
|
|
|
180
206
|
].join("\n");
|
|
181
207
|
}
|
|
182
208
|
function excludeSyncBlock(excludeFile, base) {
|
|
183
|
-
const
|
|
209
|
+
const configuredBase = Array.isArray(base) && base.length ? base : [".git", "node_modules/", ".dsh-recall-snapshots/", "dsh-recall-snapshots/"];
|
|
210
|
+
const baseList = [...configuredBase, ...WIN_RESERVED_EXCLUDES].map(psq).join(",");
|
|
184
211
|
return [
|
|
185
212
|
"$exFile = " + psq(excludeFile),
|
|
186
213
|
"$userPats = @()",
|
|
@@ -317,14 +344,14 @@ function snapshotScript(root, store, gitExe, messageId, base) {
|
|
|
317
344
|
// native stderr 包装成 ErrorRecord,EAP=Stop 下直接抛 NativeCommandError,
|
|
318
345
|
// 而 PS 5.1 的 SilentlyContinue 会把合并流里的记录整个丢弃(实测 LOG
|
|
319
346
|
// 为空)——Continue 是两个版本下唯一都能拿到 stderr 文本的取值。捕获
|
|
320
|
-
// 后按 "unable to index file 'X'"
|
|
321
|
-
//
|
|
347
|
+
// 后按 "unable to index file 'X'" / "unable to add 'X' to index" 提取
|
|
348
|
+
// 被跳过的路径,以 SNAP_SKIP 行回传 JS 侧做用户可见提示。
|
|
322
349
|
"$ErrorActionPreference = 'Continue'",
|
|
323
350
|
'$addLog = (@(& $git --git-dir=$g --work-tree=$root add -A --ignore-errors @paArgs 2>&1) | ForEach-Object { [string]$_ }) -join "`n"',
|
|
324
351
|
"$addRc = $LASTEXITCODE",
|
|
325
352
|
"$ErrorActionPreference = 'Stop'",
|
|
326
353
|
'if ($addRc -ge 2) { throw ("git add fatal (exit " + $addRc + "): " + $addLog) }',
|
|
327
|
-
`foreach ($m in [regex]::Matches($addLog, "unable to index file '([^']+)'") ) { Write-Output ('SNAP_SKIP ' + $m.Groups[1].Value) }`,
|
|
354
|
+
`foreach ($m in [regex]::Matches($addLog, "unable to (?:index file|add) '([^']+)'") ) { Write-Output ('SNAP_SKIP ' + $m.Groups[1].Value) }`,
|
|
328
355
|
dropGitlinksBlock(),
|
|
329
356
|
// 兜底:旧 git 走裸 add 时大文件仍会被重新索引,这里按清单再清一次;
|
|
330
357
|
// pathspec 生效时它是空操作(清单条目本就不在 index)
|
package/package.json
CHANGED