cursor-guard 4.8.4 → 4.8.5

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/ROADMAP.md CHANGED
@@ -3,8 +3,8 @@
3
3
  > 本文档描述 cursor-guard 从 V2 到 V7 的长期演进方向。
4
4
  > 每一代向下兼容,低版本功能永远不废弃。
5
5
  >
6
- > **当前版本**:`V4.8.4`
7
- > **文档状态**:`V2` ~ `V4.8.4` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
6
+ > **当前版本**:`V4.8.5`
7
+ > **文档状态**:`V2` ~ `V4.8.5` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
8
8
 
9
9
  ## 阅读导航
10
10
 
@@ -734,6 +734,14 @@ V4 经过 4 轮系统性代码审查,修复了以下关键问题:
734
734
  }
735
735
  ```
736
736
 
737
+ ### V4.8.5:修复变更摘要中 protect 范围外文件误标为"删除"的 Bug ✅
738
+
739
+ | 修复 | 说明 |
740
+ |------|------|
741
+ | **diff-tree 结果过滤 protect 范围** | 当 `protect` 配置非空时,`diff-tree` 对比上一次备份和当前备份的 tree 差异后,额外过滤掉不在 `protect` 范围内的文件。之前这些文件会被误标为"删除"(实际只是不在保护范围内) |
742
+ | **根因** | 用户配置 `protect: ["src/**", "pom.xml"]` 后,`.cursor-guard.json`、`.gitignore`、`.cursor/mcp.json` 等文件不在保护范围内,当前 tree 不含这些文件。`diff-tree` 对比时将其报告为 `D`(删除),但代码只过滤了 `cfg.ignore` 未过滤 `cfg.protect` |
743
+ | **影响** | 变更摘要不再出现"幽灵删除",仅展示 protect 范围内文件的真实变更 |
744
+
737
745
  ### V4.8.4:已删除文件恢复命令自动指向父提交 ✅
738
746
 
739
747
  | 修复 | 说明 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-guard",
3
- "version": "4.8.4",
3
+ "version": "4.8.5",
4
4
  "description": "Protects code from accidental AI overwrite or deletion in Cursor IDE — mandatory pre-write snapshots, review-before-apply, local Git safety net, and deterministic recovery. | 保护代码免受 Cursor AI 代理意外覆写或删除——强制写前快照、预览再执行、本地 Git 安全网、确定性恢复。",
5
5
  "keywords": [
6
6
  "cursor",
@@ -156,6 +156,7 @@ function createGitSnapshot(projectDir, cfg, opts = {}) {
156
156
  : 'M';
157
157
  const fileName = filePart.split('\t').pop();
158
158
  if (matchesAny(cfg.ignore, fileName) || matchesAny(cfg.ignore, path.basename(fileName))) continue;
159
+ if (cfg.protect.length > 0 && !matchesAny(cfg.protect, fileName, { strict: true })) continue;
159
160
  groups[key].push(fileName);
160
161
  }
161
162
  changedCount = Object.values(groups).reduce((sum, arr) => sum + arr.length, 0);
@@ -199,7 +200,8 @@ function createGitSnapshot(projectDir, cfg, opts = {}) {
199
200
  const lsInitial = git(['ls-tree', '--name-only', '-r', newTree], { cwd, allowFail: true });
200
201
  if (lsInitial) {
201
202
  const files = lsInitial.split('\n').filter(Boolean)
202
- .filter(f => !matchesAny(cfg.ignore, f) && !matchesAny(cfg.ignore, path.basename(f)));
203
+ .filter(f => !matchesAny(cfg.ignore, f) && !matchesAny(cfg.ignore, path.basename(f)))
204
+ .filter(f => cfg.protect.length === 0 || matchesAny(cfg.protect, f, { strict: true }));
203
205
  changedCount = files.length;
204
206
  const sample = files.slice(0, 5).join(', ');
205
207
  incrementalSummary = `Added ${files.length}: ${sample}${files.length > 5 ? ', ...' : ''}`;
@@ -1 +1 @@
1
- {"version":"4.8.4"}
1
+ {"version":"4.8.5"}
@@ -156,6 +156,7 @@ function createGitSnapshot(projectDir, cfg, opts = {}) {
156
156
  : 'M';
157
157
  const fileName = filePart.split('\t').pop();
158
158
  if (matchesAny(cfg.ignore, fileName) || matchesAny(cfg.ignore, path.basename(fileName))) continue;
159
+ if (cfg.protect.length > 0 && !matchesAny(cfg.protect, fileName, { strict: true })) continue;
159
160
  groups[key].push(fileName);
160
161
  }
161
162
  changedCount = Object.values(groups).reduce((sum, arr) => sum + arr.length, 0);
@@ -199,7 +200,8 @@ function createGitSnapshot(projectDir, cfg, opts = {}) {
199
200
  const lsInitial = git(['ls-tree', '--name-only', '-r', newTree], { cwd, allowFail: true });
200
201
  if (lsInitial) {
201
202
  const files = lsInitial.split('\n').filter(Boolean)
202
- .filter(f => !matchesAny(cfg.ignore, f) && !matchesAny(cfg.ignore, path.basename(f)));
203
+ .filter(f => !matchesAny(cfg.ignore, f) && !matchesAny(cfg.ignore, path.basename(f)))
204
+ .filter(f => cfg.protect.length === 0 || matchesAny(cfg.protect, f, { strict: true }));
203
205
  changedCount = files.length;
204
206
  const sample = files.slice(0, 5).join(', ');
205
207
  incrementalSummary = `Added ${files.length}: ${sample}${files.length > 5 ? ', ...' : ''}`;
@@ -35568,7 +35568,7 @@ var require_package = __commonJS({
35568
35568
  "package.json"(exports2, module2) {
35569
35569
  module2.exports = {
35570
35570
  name: "cursor-guard",
35571
- version: "4.8.4",
35571
+ version: "4.8.5",
35572
35572
  description: "Protects code from accidental AI overwrite or deletion in Cursor IDE \u2014 mandatory pre-write snapshots, review-before-apply, local Git safety net, and deterministic recovery. | \u4FDD\u62A4\u4EE3\u7801\u514D\u53D7 Cursor AI \u4EE3\u7406\u610F\u5916\u8986\u5199\u6216\u5220\u9664\u2014\u2014\u5F3A\u5236\u5199\u524D\u5FEB\u7167\u3001\u9884\u89C8\u518D\u6267\u884C\u3001\u672C\u5730 Git \u5B89\u5168\u7F51\u3001\u786E\u5B9A\u6027\u6062\u590D\u3002",
35573
35573
  keywords: [
35574
35574
  "cursor",
@@ -36096,6 +36096,7 @@ var require_snapshot = __commonJS({
36096
36096
  const key = code.startsWith("R") ? "R" : code === "D" ? "D" : code === "A" ? "A" : "M";
36097
36097
  const fileName = filePart.split(" ").pop();
36098
36098
  if (matchesAny(cfg.ignore, fileName) || matchesAny(cfg.ignore, path2.basename(fileName))) continue;
36099
+ if (cfg.protect.length > 0 && !matchesAny(cfg.protect, fileName, { strict: true })) continue;
36099
36100
  groups[key].push(fileName);
36100
36101
  }
36101
36102
  changedCount = Object.values(groups).reduce((sum, arr) => sum + arr.length, 0);
@@ -36127,7 +36128,7 @@ var require_snapshot = __commonJS({
36127
36128
  } else {
36128
36129
  const lsInitial = git(["ls-tree", "--name-only", "-r", newTree], { cwd, allowFail: true });
36129
36130
  if (lsInitial) {
36130
- const files = lsInitial.split("\n").filter(Boolean).filter((f) => !matchesAny(cfg.ignore, f) && !matchesAny(cfg.ignore, path2.basename(f)));
36131
+ const files = lsInitial.split("\n").filter(Boolean).filter((f) => !matchesAny(cfg.ignore, f) && !matchesAny(cfg.ignore, path2.basename(f))).filter((f) => cfg.protect.length === 0 || matchesAny(cfg.protect, f, { strict: true }));
36131
36132
  changedCount = files.length;
36132
36133
  const sample = files.slice(0, 5).join(", ");
36133
36134
  incrementalSummary = `Added ${files.length}: ${sample}${files.length > 5 ? ", ..." : ""}`;
@@ -2,7 +2,7 @@
2
2
  "name": "cursor-guard-ide",
3
3
  "displayName": "Cursor Guard",
4
4
  "description": "AI code protection dashboard embedded in your IDE — real-time alerts, backup history, one-click snapshots",
5
- "version": "4.8.4",
5
+ "version": "4.8.5",
6
6
  "publisher": "zhangqiang8vipp",
7
7
  "license": "BUSL-1.1",
8
8
  "engines": {
@@ -3,8 +3,8 @@
3
3
  > 本文档描述 cursor-guard 从 V2 到 V7 的长期演进方向。
4
4
  > 每一代向下兼容,低版本功能永远不废弃。
5
5
  >
6
- > **当前版本**:`V4.8.4`
7
- > **文档状态**:`V2` ~ `V4.8.4` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
6
+ > **当前版本**:`V4.8.5`
7
+ > **文档状态**:`V2` ~ `V4.8.5` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
8
8
 
9
9
  ## 阅读导航
10
10
 
@@ -734,6 +734,14 @@ V4 经过 4 轮系统性代码审查,修复了以下关键问题:
734
734
  }
735
735
  ```
736
736
 
737
+ ### V4.8.5:修复变更摘要中 protect 范围外文件误标为"删除"的 Bug ✅
738
+
739
+ | 修复 | 说明 |
740
+ |------|------|
741
+ | **diff-tree 结果过滤 protect 范围** | 当 `protect` 配置非空时,`diff-tree` 对比上一次备份和当前备份的 tree 差异后,额外过滤掉不在 `protect` 范围内的文件。之前这些文件会被误标为"删除"(实际只是不在保护范围内) |
742
+ | **根因** | 用户配置 `protect: ["src/**", "pom.xml"]` 后,`.cursor-guard.json`、`.gitignore`、`.cursor/mcp.json` 等文件不在保护范围内,当前 tree 不含这些文件。`diff-tree` 对比时将其报告为 `D`(删除),但代码只过滤了 `cfg.ignore` 未过滤 `cfg.protect` |
743
+ | **影响** | 变更摘要不再出现"幽灵删除",仅展示 protect 范围内文件的真实变更 |
744
+
737
745
  ### V4.8.4:已删除文件恢复命令自动指向父提交 ✅
738
746
 
739
747
  | 修复 | 说明 |
@@ -2,7 +2,7 @@
2
2
  "name": "cursor-guard-ide",
3
3
  "displayName": "Cursor Guard",
4
4
  "description": "AI code protection dashboard embedded in your IDE — real-time alerts, backup history, one-click snapshots",
5
- "version": "4.8.4",
5
+ "version": "4.8.5",
6
6
  "publisher": "zhangqiang8vipp",
7
7
  "license": "BUSL-1.1",
8
8
  "engines": {