cursor-guard 1.0.1 → 1.2.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/README.md CHANGED
@@ -1,30 +1,31 @@
1
1
  # Cursor Guard
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/cursor-guard)](https://www.npmjs.com/package/cursor-guard)
4
+ [![license](https://img.shields.io/github/license/zhangqiang8vipp/cursor-guard)](LICENSE)
5
+
3
6
  Protects your code from accidental AI overwrite or deletion in [Cursor](https://cursor.com).
4
7
 
5
- 保护你的代码免受 [Cursor](https://cursor.com) AI 代理意外覆写或删除。
8
+ **[中文文档](README.zh-CN.md)**
6
9
 
7
10
  ---
8
11
 
9
- ## What It Does / 功能介绍
12
+ ## What It Does
10
13
 
11
14
  When Cursor's AI agent edits your files, there's a risk of accidental overwrites, deletions, or loss of work. **Cursor Guard** enforces a safety protocol:
12
15
 
13
- Cursor AI 代理编辑你的文件时,可能会意外覆盖、删除或丢失代码。**Cursor Guard** 强制执行一套安全协议:
14
-
15
- - **Mandatory pre-write snapshots / 强制写前快照** Git commit or shadow copy before any destructive operation / 在任何破坏性操作前自动 Git 提交或影子拷贝
16
- - **Read before Write / 先读后写** The agent must read a file before overwriting it / 代理必须先读取文件内容,才能覆写
17
- - **Review before apply / 预览再执行** Diff previews and explicit confirmation for dangerous ops / 危险操作前展示 diff 预览并要求确认
18
- - **Deterministic recovery / 确定性恢复** Clear priority-ordered recovery paths (Git shadow copies → conversation context → editor history) / 按优先级的恢复路径(Git 影子拷贝 → 对话上下文 → 编辑器历史)
19
- - **Configurable scope / 可配置保护范围** Protect only what matters via `.cursor-guard.json` / 通过配置文件只保护你关心的文件
20
- - **Secrets filtering / 敏感文件过滤** — Sensitive files (`.env`, keys, certificates) are auto-excluded from backups / `.env`、密钥、证书等敏感文件自动排除
21
- - **Auto-backup script / 自动备份脚本** — A PowerShell watcher that periodically snapshots to a dedicated Git branch without disturbing your working tree / 定期快照到独立 Git 分支,不干扰工作区
16
+ - **Mandatory pre-write snapshots** Git commit or shadow copy before any destructive operation
17
+ - **Read before Write** — The agent must read a file before overwriting it
18
+ - **Review before apply**Diff previews and explicit confirmation for dangerous ops
19
+ - **Deterministic recovery** Clear priority-ordered recovery paths (Git shadow copies conversation context editor history)
20
+ - **Configurable scope**Protect only what matters via `.cursor-guard.json`
21
+ - **Secrets filtering**Sensitive files (`.env`, keys, certificates) are auto-excluded from backups
22
+ - **Auto-backup script** A PowerShell watcher that periodically snapshots to a dedicated Git branch without disturbing your working tree
22
23
 
23
24
  ---
24
25
 
25
- ## Installation / 安装
26
+ ## Installation
26
27
 
27
- ### Method 1: npm install / 方式一:npm 安装
28
+ ### Method 1: npm
28
29
 
29
30
  ```bash
30
31
  npm install cursor-guard
@@ -32,106 +33,98 @@ npm install cursor-guard
32
33
 
33
34
  After installation, copy the skill files to your Cursor skills directory:
34
35
 
35
- 安装后,将技能文件复制到 Cursor 技能目录:
36
-
37
36
  **Windows (PowerShell):**
38
37
 
39
38
  ```powershell
40
- # Global installation (all projects) / 全局安装(所有项目生效)
39
+ # Global (all projects)
41
40
  Copy-Item -Recurse node_modules/cursor-guard "$env:USERPROFILE/.cursor/skills/cursor-guard"
42
41
 
43
- # Per-project installation / 项目级安装(仅当前项目生效)
42
+ # Per-project (current project only)
44
43
  Copy-Item -Recurse node_modules/cursor-guard .cursor/skills/cursor-guard
45
44
  ```
46
45
 
47
46
  **macOS / Linux:**
48
47
 
49
48
  ```bash
50
- # Global installation / 全局安装
49
+ # Global
51
50
  cp -r node_modules/cursor-guard ~/.cursor/skills/cursor-guard
52
51
 
53
- # Per-project installation / 项目级安装
52
+ # Per-project
54
53
  cp -r node_modules/cursor-guard .cursor/skills/cursor-guard
55
54
  ```
56
55
 
57
56
  After copying, you can remove the npm dependency if you don't need it in `node_modules`:
58
57
 
59
- 复制完成后,如果不需要保留在 `node_modules` 中,可以卸载:
60
-
61
58
  ```bash
62
59
  npm uninstall cursor-guard
63
60
  ```
64
61
 
65
- ### Method 2: Git clone / 方式二:Git 克隆
62
+ ### Method 2: Git clone
66
63
 
67
64
  ```bash
68
- # Global installation / 全局安装
65
+ # Global
69
66
  git clone https://github.com/zhangqiang8vipp/cursor-guard.git ~/.cursor/skills/cursor-guard
70
67
 
71
- # Per-project installation / 项目级安装
68
+ # Per-project
72
69
  git clone https://github.com/zhangqiang8vipp/cursor-guard.git .cursor/skills/cursor-guard
73
70
  ```
74
71
 
75
- ### Method 3: Manual download / 方式三:手动下载
72
+ ### Method 3: Manual download
76
73
 
77
74
  Download from [GitHub Releases](https://github.com/zhangqiang8vipp/cursor-guard/releases) and extract to:
78
75
 
79
- 从 [GitHub Releases](https://github.com/zhangqiang8vipp/cursor-guard/releases) 下载并解压到:
80
-
81
76
  ```
82
- ~/.cursor/skills/cursor-guard/ # Global / 全局
83
- <project-root>/.cursor/skills/cursor-guard/ # Per-project / 项目级
77
+ ~/.cursor/skills/cursor-guard/ # Global
78
+ <project-root>/.cursor/skills/cursor-guard/ # Per-project
84
79
  ```
85
80
 
86
- ### Verify Installation / 验证安装
81
+ ### Verify Installation
87
82
 
88
- After installation, your directory structure should look like this / 安装后目录结构应如下所示:
83
+ After installation, your directory structure should look like this:
89
84
 
90
85
  ```
91
86
  .cursor/skills/cursor-guard/
92
- ├── SKILL.md # AI agent instructions / AI 代理指令
87
+ ├── SKILL.md # AI agent instructions
93
88
  ├── README.md
94
89
  ├── LICENSE
95
90
  └── references/
96
- ├── auto-backup.ps1 # Auto-backup script / 自动备份脚本
97
- ├── recovery.md # Recovery commands / 恢复命令
98
- ├── cursor-guard.example.json # Example config / 示例配置
99
- └── cursor-guard.schema.json # Config schema / 配置 Schema
91
+ ├── auto-backup.ps1 # Auto-backup script
92
+ ├── recovery.md # Recovery commands
93
+ ├── cursor-guard.example.json # Example config
94
+ └── cursor-guard.schema.json # Config schema
100
95
  ```
101
96
 
102
- The skill activates automatically when the AI agent detects risky operations (file edits, deletes, renames) or when you mention recovery-related terms.
103
-
104
- 技能会在 AI 代理检测到高风险操作(文件编辑、删除、重命名)或你提到恢复相关词汇时自动激活。无需其他设置,安装即生效。
97
+ The skill activates automatically when the AI agent detects risky operations or when you mention recovery-related terms. No extra setup needed.
105
98
 
106
99
  ---
107
100
 
108
- ## Quick Start / 快速上手
101
+ ## Quick Start
109
102
 
110
- 1. **Install the skill** using any method above / 用以上任意方式安装技能
103
+ 1. **Install the skill** using any method above
111
104
 
112
- 2. **Open Cursor** and start an Agent conversation / 打开 Cursor,开始一个 Agent 对话
105
+ 2. **Open Cursor** and start an Agent conversation
113
106
 
114
- 3. **The skill works automatically** — when the AI agent tries to edit files, it will: / 技能自动生效——当 AI 代理尝试编辑文件时,会自动:
115
- - Create a Git snapshot before writing / 写入前创建 Git 快照
116
- - Read files before overwriting / 覆写前先读取文件
117
- - Show diff previews for dangerous operations / 危险操作前展示 diff 预览
118
- - Report a status block after each protected operation / 每次受保护操作后报告状态
107
+ 3. **The skill works automatically** — when the AI agent tries to edit files, it will:
108
+ - Create a Git snapshot before writing
109
+ - Read files before overwriting
110
+ - Show diff previews for dangerous operations
111
+ - Report a status block after each protected operation
119
112
 
120
- 4. **(Optional) Add project config** to customize protection scope / (可选)添加项目配置自定义保护范围:
113
+ 4. **(Optional) Add project config** to customize protection scope:
121
114
 
122
115
  ```bash
123
116
  cp .cursor/skills/cursor-guard/references/cursor-guard.example.json .cursor-guard.json
124
117
  ```
125
118
 
126
- 5. **(Optional) Run auto-backup** in a separate terminal / (可选)在独立终端运行自动备份:
119
+ 5. **(Optional) Run auto-backup** in a separate terminal:
127
120
 
128
121
  ```powershell
129
122
  .\auto-backup.ps1 -Path "D:\MyProject"
130
123
  ```
131
124
 
132
- ### Project Configuration / 项目配置
125
+ ### Project Configuration
133
126
 
134
- Edit `.cursor-guard.json` to define which files to protect / 编辑 `.cursor-guard.json` 定义保护哪些文件:
127
+ Edit `.cursor-guard.json` to define which files to protect:
135
128
 
136
129
  ```json
137
130
  {
@@ -145,74 +138,100 @@ Edit `.cursor-guard.json` to define which files to protect / 编辑 `.cursor-gua
145
138
 
146
139
  ---
147
140
 
148
- ## Auto-Backup Script / 自动备份脚本
141
+ ## Auto-Backup Script
149
142
 
150
143
  Run in a separate terminal while working in Cursor:
151
144
 
152
- 在使用 Cursor 时,在**单独的终端窗口**中运行:
153
-
154
145
  ```powershell
155
146
  .\auto-backup.ps1 -Path "D:\MyProject"
156
147
 
157
- # Custom interval (default 60s) / 自定义间隔(默认 60 秒):
148
+ # Custom interval (default 60s):
158
149
  .\auto-backup.ps1 -Path "D:\MyProject" -IntervalSeconds 30
159
150
  ```
160
151
 
161
152
  The script uses Git plumbing commands to snapshot to `cursor-guard/auto-backup` branch — it never switches branches or touches your working index.
162
153
 
163
- 脚本使用 Git 底层命令快照到 `cursor-guard/auto-backup` 分支——不会切换分支,也不会影响你的工作索引。
164
-
165
- > **Note / 注意**: Run this script in a separate PowerShell window, NOT inside Cursor's integrated terminal. Cursor's terminal may interfere with Git plumbing commands.
166
- >
167
- > 请在独立的 PowerShell 窗口中运行此脚本,不要在 Cursor 的集成终端中运行,因为 Cursor 终端可能干扰 Git 底层命令。
154
+ > **Note**: Run this script in a separate PowerShell window, NOT inside Cursor's integrated terminal. Cursor's terminal may interfere with Git plumbing commands.
168
155
 
169
156
  ---
170
157
 
171
- ## Recovery / 恢复
158
+ ## Recovery
159
+
160
+ If something goes wrong, just tell the AI agent in natural language:
172
161
 
173
- If something goes wrong, recovery follows this priority:
162
+ ### By time
174
163
 
175
- 出问题时,按以下优先级恢复:
164
+ > "restore to 5 minutes ago"
165
+ > "go back to yesterday's version"
166
+ > "restore to 3pm today"
167
+
168
+ ### By version
169
+
170
+ > "undo the last change"
171
+ > "go back 3 versions"
172
+ > "restore to the previous version"
173
+
174
+ ### By file
175
+
176
+ > "restore src/app.py to 10 minutes ago"
177
+ > "restore src/app.py to the previous version"
178
+
179
+ The agent will automatically search Git history and auto-backup snapshots, show you matching versions to choose from, and restore after your confirmation.
180
+
181
+ ### Recovery priority
176
182
 
177
183
  1. **Git** — `git restore`, `git reset`, `git reflog`
178
- 2. **Shadow copies / 影子拷贝** `.cursor-guard-backup/<timestamp>/`
179
- 3. **Conversation context / 对话上下文** Original file content captured by agent Read calls / 代理 Read 调用捕获的原始内容
180
- 4. **Editor history / 编辑器历史** VS Code/Cursor Timeline (auxiliary / 辅助)
184
+ 2. **Auto-backup branch**`cursor-guard/auto-backup`
185
+ 3. **Shadow copies**`.cursor-guard-backup/<timestamp>/`
186
+ 4. **Conversation context** Original file content captured by agent Read calls
187
+ 5. **Editor history** — VS Code/Cursor Timeline (auxiliary)
181
188
 
182
- See [references/recovery.md](references/recovery.md) for detailed commands / 详细命令见恢复文档。
189
+ See [references/recovery.md](references/recovery.md) for detailed commands.
183
190
 
184
191
  ---
185
192
 
186
- ## Trigger Keywords / 触发关键词
193
+ ## Trigger Keywords
187
194
 
188
- The skill activates on these signals / 技能在以下信号时激活:
195
+ The skill activates on these signals:
189
196
 
190
- - File edits, deletes, renames by the AI agent / AI 代理的文件编辑、删除、重命名
191
- - Recovery requests / 恢复请求:"回滚"、"误删"、"丢版本"、"rollback""undo""recover"
192
- - History issues / 历史问题:checkpoints missing、Timeline not working、save failures
197
+ - File edits, deletes, renames by the AI agent
198
+ - Recovery requests: "rollback", "undo", "recover", "restore"
199
+ - Time-based recovery: "restore to N minutes ago", "go back to yesterday"
200
+ - Version-based recovery: "previous version", "go back N versions"
201
+ - History issues: checkpoints missing, Timeline not working, save failures
193
202
 
194
203
  ---
195
204
 
196
- ## Files / 文件说明
205
+ ## Files
197
206
 
198
- | File / 文件 | Purpose / 用途 |
207
+ | File | Purpose |
199
208
  |------|---------|
200
- | `SKILL.md` | Main skill instructions for the AI agent / AI 代理的主要技能指令 |
201
- | `references/auto-backup.ps1` | PowerShell auto-backup watcher script / PowerShell 自动备份监控脚本 |
202
- | `references/recovery.md` | Recovery command templates / 恢复命令模板 |
203
- | `references/cursor-guard.example.json` | Example project configuration / 示例项目配置 |
204
- | `references/cursor-guard.schema.json` | JSON Schema for config validation / 配置文件的 JSON Schema |
209
+ | `SKILL.md` | Main skill instructions for the AI agent |
210
+ | `references/auto-backup.ps1` | PowerShell auto-backup watcher script |
211
+ | `references/recovery.md` | Recovery command templates |
212
+ | `references/cursor-guard.example.json` | Example project configuration |
213
+ | `references/cursor-guard.schema.json` | JSON Schema for config validation |
205
214
 
206
215
  ---
207
216
 
208
- ## Requirements / 环境要求
217
+ ## Known Limitations
218
+
219
+ - **Binary files**: Git diffs and snapshots work on text files. Binary files (images, compiled assets) are stored but cannot be meaningfully diffed or partially restored.
220
+ - **Untracked files**: Files never committed to Git cannot be recovered from Git history. Shadow copy (`backup_strategy: "shadow"` or `"both"`) is the only safety net for untracked files.
221
+ - **Concurrent agents**: If multiple AI agent threads write to the same file simultaneously, snapshots cannot prevent race conditions. Avoid parallel edits to the same file.
222
+ - **External tools modifying the index**: Tools that alter Git's index (e.g. other Git GUIs, IDE Git integrations) while `auto-backup.ps1` is running may conflict. The script uses a temporary index to minimize this, but edge cases exist.
223
+ - **Git worktree**: The auto-backup script supports worktree layouts (`git rev-parse --git-dir`), but has not been tested with all exotic setups (e.g. `--separate-git-dir`).
224
+ - **Cursor terminal interference**: Cursor's integrated terminal injects `--trailer` flags into `git commit` commands, which breaks plumbing commands like `commit-tree`. Always run `auto-backup.ps1` in a **separate PowerShell window**.
225
+ - **Large repos**: For very large repositories, `git add -A` in the backup loop may be slow. Use `protect` patterns in `.cursor-guard.json` to narrow scope.
226
+
227
+ ## Requirements
209
228
 
210
- - **Git** — for primary backup strategy / 主要备份策略
211
- - **PowerShell 5.1+** — for auto-backup script (Windows built-in) / 自动备份脚本(Windows 自带)
212
- - **Cursor IDE** — with Agent mode enabled / 需启用 Agent 模式
229
+ - **Git** — for primary backup strategy
230
+ - **PowerShell 5.1+** — for auto-backup script (Windows built-in)
231
+ - **Cursor IDE** — with Agent mode enabled
213
232
 
214
233
  ---
215
234
 
216
- ## License / 许可证
235
+ ## License
217
236
 
218
237
  MIT
@@ -0,0 +1,237 @@
1
+ # Cursor Guard
2
+
3
+ [![npm version](https://img.shields.io/npm/v/cursor-guard)](https://www.npmjs.com/package/cursor-guard)
4
+ [![license](https://img.shields.io/github/license/zhangqiang8vipp/cursor-guard)](LICENSE)
5
+
6
+ 保护你的代码免受 [Cursor](https://cursor.com) AI 代理意外覆写或删除。
7
+
8
+ **[English](README.md)**
9
+
10
+ ---
11
+
12
+ ## 功能介绍
13
+
14
+ 当 Cursor 的 AI 代理编辑你的文件时,可能会意外覆盖、删除或丢失代码。**Cursor Guard** 强制执行一套安全协议:
15
+
16
+ - **强制写前快照** — 在任何破坏性操作前自动 Git 提交或影子拷贝
17
+ - **先读后写** — 代理必须先读取文件内容,才能覆写
18
+ - **预览再执行** — 危险操作前展示 diff 预览并要求确认
19
+ - **确定性恢复** — 按优先级的恢复路径(Git → 影子拷贝 → 对话上下文 → 编辑器历史)
20
+ - **可配置保护范围** — 通过 `.cursor-guard.json` 配置文件只保护你关心的文件
21
+ - **敏感文件过滤** — `.env`、密钥、证书等敏感文件自动排除备份
22
+ - **自动备份脚本** — 定期快照到独立 Git 分支,不干扰工作区
23
+
24
+ ---
25
+
26
+ ## 安装
27
+
28
+ ### 方式一:npm 安装
29
+
30
+ ```bash
31
+ npm install cursor-guard
32
+ ```
33
+
34
+ 安装后,将技能文件复制到 Cursor 技能目录:
35
+
36
+ **Windows (PowerShell):**
37
+
38
+ ```powershell
39
+ # 全局安装(所有项目生效)
40
+ Copy-Item -Recurse node_modules/cursor-guard "$env:USERPROFILE/.cursor/skills/cursor-guard"
41
+
42
+ # 项目级安装(仅当前项目生效)
43
+ Copy-Item -Recurse node_modules/cursor-guard .cursor/skills/cursor-guard
44
+ ```
45
+
46
+ **macOS / Linux:**
47
+
48
+ ```bash
49
+ # 全局安装
50
+ cp -r node_modules/cursor-guard ~/.cursor/skills/cursor-guard
51
+
52
+ # 项目级安装
53
+ cp -r node_modules/cursor-guard .cursor/skills/cursor-guard
54
+ ```
55
+
56
+ 复制完成后,如果不需要保留在 `node_modules` 中,可以卸载:
57
+
58
+ ```bash
59
+ npm uninstall cursor-guard
60
+ ```
61
+
62
+ ### 方式二:Git 克隆
63
+
64
+ ```bash
65
+ # 全局安装
66
+ git clone https://github.com/zhangqiang8vipp/cursor-guard.git ~/.cursor/skills/cursor-guard
67
+
68
+ # 项目级安装
69
+ git clone https://github.com/zhangqiang8vipp/cursor-guard.git .cursor/skills/cursor-guard
70
+ ```
71
+
72
+ ### 方式三:手动下载
73
+
74
+ 从 [GitHub Releases](https://github.com/zhangqiang8vipp/cursor-guard/releases) 下载并解压到:
75
+
76
+ ```
77
+ ~/.cursor/skills/cursor-guard/ # 全局
78
+ <项目根目录>/.cursor/skills/cursor-guard/ # 项目级
79
+ ```
80
+
81
+ ### 验证安装
82
+
83
+ 安装后目录结构应如下所示:
84
+
85
+ ```
86
+ .cursor/skills/cursor-guard/
87
+ ├── SKILL.md # AI 代理指令
88
+ ├── README.md
89
+ ├── LICENSE
90
+ └── references/
91
+ ├── auto-backup.ps1 # 自动备份脚本
92
+ ├── recovery.md # 恢复命令模板
93
+ ├── cursor-guard.example.json # 示例配置
94
+ └── cursor-guard.schema.json # 配置 Schema
95
+ ```
96
+
97
+ 技能会在 AI 代理检测到高风险操作(文件编辑、删除、重命名)或你提到恢复相关词汇时自动激活。无需其他设置,安装即生效。
98
+
99
+ ---
100
+
101
+ ## 快速上手
102
+
103
+ 1. **安装技能** — 用以上任意方式安装
104
+
105
+ 2. **打开 Cursor** — 开始一个 Agent 对话
106
+
107
+ 3. **技能自动生效** — 当 AI 代理尝试编辑文件时,会自动:
108
+ - 写入前创建 Git 快照
109
+ - 覆写前先读取文件
110
+ - 危险操作前展示 diff 预览
111
+ - 每次受保护操作后报告状态
112
+
113
+ 4. **(可选)添加项目配置** — 自定义保护范围:
114
+
115
+ ```bash
116
+ cp .cursor/skills/cursor-guard/references/cursor-guard.example.json .cursor-guard.json
117
+ ```
118
+
119
+ 5. **(可选)运行自动备份** — 在独立终端运行:
120
+
121
+ ```powershell
122
+ .\auto-backup.ps1 -Path "D:\MyProject"
123
+ ```
124
+
125
+ ### 项目配置
126
+
127
+ 编辑 `.cursor-guard.json` 定义保护哪些文件:
128
+
129
+ ```json
130
+ {
131
+ "protect": ["src/**", "lib/**", "package.json"],
132
+ "ignore": ["node_modules/**", "dist/**"],
133
+ "auto_backup_interval_seconds": 60,
134
+ "secrets_patterns": [".env", ".env.*", "*.key", "*.pem"],
135
+ "retention": { "mode": "days", "days": 30 }
136
+ }
137
+ ```
138
+
139
+ ---
140
+
141
+ ## 自动备份脚本
142
+
143
+ 在使用 Cursor 时,在**单独的终端窗口**中运行:
144
+
145
+ ```powershell
146
+ .\auto-backup.ps1 -Path "D:\MyProject"
147
+
148
+ # 自定义间隔(默认 60 秒):
149
+ .\auto-backup.ps1 -Path "D:\MyProject" -IntervalSeconds 30
150
+ ```
151
+
152
+ 脚本使用 Git 底层命令快照到 `cursor-guard/auto-backup` 分支——不会切换分支,也不会影响你的工作索引。
153
+
154
+ > **注意**:请在独立的 PowerShell 窗口中运行此脚本,不要在 Cursor 的集成终端中运行,因为 Cursor 终端可能干扰 Git 底层命令。
155
+
156
+ ---
157
+
158
+ ## 恢复
159
+
160
+ 出问题时,直接用自然语言告诉 AI 代理即可:
161
+
162
+ ### 按时间恢复
163
+
164
+ > "帮我恢复到5分钟前"
165
+ > "恢复到今天下午3点的状态"
166
+ > "回到昨天的版本"
167
+
168
+ ### 按版本恢复
169
+
170
+ > "恢复到上一个版本"
171
+ > "回到前3个版本"
172
+ > "撤销最近两次修改"
173
+
174
+ ### 指定文件恢复
175
+
176
+ > "把 src/app.py 恢复到10分钟前"
177
+ > "把 src/app.py 恢复到上一个版本"
178
+
179
+ 代理会自动搜索 Git 历史和自动备份快照,列出匹配版本供你选择,确认后执行恢复。
180
+
181
+ ### 恢复优先级
182
+
183
+ 1. **Git** — `git restore`, `git reset`, `git reflog`
184
+ 2. **自动备份分支** — `cursor-guard/auto-backup`
185
+ 3. **影子拷贝** — `.cursor-guard-backup/<时间戳>/`
186
+ 4. **对话上下文** — 代理 Read 调用捕获的原始文件内容
187
+ 5. **编辑器历史** — VS Code/Cursor Timeline(辅助)
188
+
189
+ 详细恢复命令见 [references/recovery.md](references/recovery.md)。
190
+
191
+ ---
192
+
193
+ ## 触发关键词
194
+
195
+ 技能在以下信号时激活:
196
+
197
+ - AI 代理的文件编辑、删除、重命名
198
+ - 恢复请求:"回滚"、"误删"、"丢版本"、"改不回来"
199
+ - 按时间恢复:"恢复到N分钟前"、"恢复到下午3点"、"回到昨天"
200
+ - 按版本恢复:"恢复到上一个版本"、"前N个版本"、"撤销最近N次修改"
201
+ - 历史问题:Checkpoint 丢失、Timeline 不工作、保存失败
202
+
203
+ ---
204
+
205
+ ## 文件说明
206
+
207
+ | 文件 | 用途 |
208
+ |------|------|
209
+ | `SKILL.md` | AI 代理的主要技能指令 |
210
+ | `references/auto-backup.ps1` | PowerShell 自动备份监控脚本 |
211
+ | `references/recovery.md` | 恢复命令模板 |
212
+ | `references/cursor-guard.example.json` | 示例项目配置 |
213
+ | `references/cursor-guard.schema.json` | 配置文件的 JSON Schema |
214
+
215
+ ---
216
+
217
+ ## 已知限制
218
+
219
+ - **二进制文件**:Git 快照可以存储二进制文件(图片、编译产物),但无法进行有意义的 diff 或部分恢复。
220
+ - **未跟踪文件**:从未提交到 Git 的文件无法从 Git 历史恢复。影子拷贝(`backup_strategy: "shadow"` 或 `"both"`)是未跟踪文件的唯一安全网。
221
+ - **并发 Agent**:如果多个 AI 代理线程同时写入同一文件,快照无法防止竞态条件。请避免并行编辑同一文件。
222
+ - **外部工具修改索引**:在 `auto-backup.ps1` 运行期间,其他修改 Git 索引的工具(如 Git GUI、IDE Git 集成)可能冲突。脚本使用临时索引来最小化风险,但边缘情况仍存在。
223
+ - **Git worktree**:自动备份脚本支持 worktree 布局(`git rev-parse --git-dir`),但未在所有特殊配置下测试(如 `--separate-git-dir`)。
224
+ - **Cursor 终端干扰**:Cursor 集成终端会向 `git commit` 命令注入 `--trailer` 标志,导致 `commit-tree` 等底层命令异常。请始终在**独立的 PowerShell 窗口**中运行 `auto-backup.ps1`。
225
+ - **大型仓库**:对于非常大的仓库,备份循环中的 `git add -A` 可能较慢。使用 `.cursor-guard.json` 中的 `protect` 模式缩小范围。
226
+
227
+ ## 环境要求
228
+
229
+ - **Git** — 主要备份策略
230
+ - **PowerShell 5.1+** — 自动备份脚本(Windows 自带)
231
+ - **Cursor IDE** — 需启用 Agent 模式
232
+
233
+ ---
234
+
235
+ ## 许可证
236
+
237
+ MIT
package/SKILL.md CHANGED
@@ -19,6 +19,7 @@ Use this skill when any of the following appear:
19
19
  - **History confusion**: Checkpoints missing, Timeline/local history not rolling back, "save failed" after external writes.
20
20
  - **Parallel context**: Multiple repos or branches; unclear which folder is the workspace root.
21
21
  - **Recovery asks**: e.g. "改不回来", "丢版本", "回滚", "reflog", "误删", or English equivalents.
22
+ - **Time/version recovery**: e.g. "恢复到5分钟前", "恢复到前3个版本", "回到上一个版本", "restore to 10 minutes ago", "go back 2 versions", "恢复到下午3点的状态".
22
23
 
23
24
  If none of the above, do not expand scope; answer normally.
24
25
 
@@ -33,6 +34,9 @@ On first trigger in a session, check if the workspace root contains `.cursor-gua
33
34
  "protect": ["src/**", "lib/**", "package.json"],
34
35
  "ignore": ["node_modules/**", "dist/**", "*.log"],
35
36
 
37
+ // "git": auto-backup to a dedicated branch (default)
38
+ // "shadow": file copies to .cursor-guard-backup/<timestamp>/
39
+ // "both": git branch snapshot + shadow copies
36
40
  "backup_strategy": "git",
37
41
  "auto_backup_interval_seconds": 60,
38
42
 
@@ -87,15 +91,46 @@ When the target file of an edit **falls outside the protected scope**, the agent
87
91
 
88
92
  **Before any High-risk operation on a protected file:**
89
93
 
94
+ Use a **temporary index and dedicated ref** so the user's staged/unstaged state is never touched:
95
+
96
+ ```bash
97
+ # 1. Create temp index from HEAD
98
+ GIT_INDEX_FILE=.git/guard-snapshot-index git read-tree HEAD
99
+
100
+ # 2. Stage working-tree files into temp index
101
+ GIT_INDEX_FILE=.git/guard-snapshot-index git add -A
102
+
103
+ # 3. Write tree and create commit on a guard ref (not on the user's branch)
104
+ TREE=$(GIT_INDEX_FILE=.git/guard-snapshot-index git write-tree)
105
+ COMMIT=$(git commit-tree $TREE -p HEAD -m "guard: snapshot before ai edit")
106
+ git update-ref refs/guard/snapshot $COMMIT
107
+
108
+ # 4. Cleanup
109
+ rm .git/guard-snapshot-index
90
110
  ```
91
- git add -A && git commit -m "guard: snapshot before ai edit" --no-verify
111
+
112
+ **PowerShell equivalent** (for agent Shell calls):
113
+
114
+ ```powershell
115
+ $guardIdx = Join-Path (git rev-parse --git-dir) "guard-snapshot-index"
116
+ $env:GIT_INDEX_FILE = $guardIdx
117
+ git read-tree HEAD
118
+ git add -A
119
+ $tree = git write-tree
120
+ $env:GIT_INDEX_FILE = $null
121
+ Remove-Item $guardIdx -Force -ErrorAction SilentlyContinue
122
+ $commit = git commit-tree $tree -p HEAD -m "guard: snapshot before ai edit"
123
+ git update-ref refs/guard/snapshot $commit
92
124
  ```
93
125
 
94
126
  - Run this via Shell tool BEFORE the first Write / StrReplace / Delete call.
95
- - If `.cursor-guard.json` exists with `protect` patterns, the agent may scope the commit: `git add <protected-paths>` instead of `-A` to keep the snapshot focused.
96
- - If `git status` shows nothing to commit, that's fine the existing HEAD is the rollback point.
127
+ - The user's index (staged files) and current branch are **never modified**.
128
+ - If `.cursor-guard.json` exists with `protect` patterns, scope `git add` to those paths instead of `-A`.
97
129
  - Record the commit hash (short) and report it to the user.
98
- - Before committing, check staged files against `secrets_patterns` (§0). Exclude any matches and warn the user.
130
+ - To restore: `git restore --source=refs/guard/snapshot -- <file>`.
131
+ - Before writing the tree, check staged files against `secrets_patterns` (§0). Exclude any matches and warn the user.
132
+
133
+ **Simplified fallback**: If the plumbing approach fails (e.g. `commit-tree` not available), the agent MAY fall back to `git stash push -m "guard: snapshot" --keep-index` + `git stash pop` to shelter and restore the user's state. Report which method was used in the status block.
99
134
 
100
135
  **Before any Medium-risk operation:**
101
136
 
@@ -151,14 +186,26 @@ When editing 3+ files in one task:
151
186
 
152
187
  ## 4. Backup Strategy (Priority)
153
188
 
154
- 1. **Git local commits** primary safety net. Short WIP commits before risky AI runs.
155
- 2. **Shadow copy** (`.cursor-guard-backup/`) — fallback for non-git or when user wants extra insurance.
156
- 3. **Auto-backup script** see [references/auto-backup.ps1](references/auto-backup.ps1) for a PowerShell watcher that auto-commits on file change.
189
+ There are two distinct backup mechanisms. Do not confuse them:
190
+
191
+ | | **Git branch snapshot** | **Shadow copy** |
192
+ |---|---|---|
193
+ | **What** | Commits to `cursor-guard/auto-backup` branch via plumbing | File copies to `.cursor-guard-backup/<timestamp>/` |
194
+ | **Who creates** | `auto-backup.ps1` (when `backup_strategy` = `git` or `both`) | `auto-backup.ps1` (when `backup_strategy` = `shadow` or `both`); or the agent manually (§2b) |
195
+ | **Who cleans up** | Manual: `git branch -D cursor-guard/auto-backup` | `auto-backup.ps1` per `retention` config; or manual |
196
+ | **Restore** | `git restore --source=cursor-guard/auto-backup -- <file>` | `Copy-Item ".cursor-guard-backup/<ts>/<file>" "<path>"` |
197
+ | **Requires Git** | Yes | No (fallback for non-git repos) |
198
+
199
+ **Priority order for the agent:**
200
+
201
+ 1. **Guard ref snapshot** (`refs/guard/snapshot`) — agent creates before each high-risk edit using temp index (§2a). Does not pollute user's branch or staging area.
202
+ 2. **Git branch auto-backup** (`cursor-guard/auto-backup`) — periodic snapshots by `auto-backup.ps1`.
203
+ 3. **Shadow copy** (`.cursor-guard-backup/`) — fallback for non-git repos, or as extra insurance when `backup_strategy = "both"`.
157
204
  4. **Editor habits** — Ctrl+S frequently; optional extensions are user-configured, mention only if asked.
158
205
 
159
206
  **Hard default:** Do NOT `git push` unless the user explicitly asks. Scope = **local only**.
160
207
 
161
- **Retention:** Shadow copies are auto-cleaned by `auto-backup.ps1` per the `retention` config (default: keep 30 days). For manual cleanup of the backup branch, see [references/recovery.md](references/recovery.md).
208
+ **Retention:** The `retention` config in `.cursor-guard.json` controls cleanup of **shadow copy directories** only. Git branch snapshots are not subject to retention; clean them manually (see [references/recovery.md](references/recovery.md)).
162
209
 
163
210
  ---
164
211
 
@@ -172,6 +219,126 @@ When editing 3+ files in one task:
172
219
 
173
220
  ---
174
221
 
222
+ ## 5a. Time-Based & Version-Based Recovery
223
+
224
+ When the user requests recovery using time or version references, follow this workflow:
225
+
226
+ ### Trigger Phrases (Chinese & English)
227
+
228
+ | Pattern | Type | Example |
229
+ |---------|------|---------|
230
+ | "恢复到 N 分钟/小时前", "N minutes/hours ago" | Time-based | "恢复到5分钟前", "restore to 10 minutes ago" |
231
+ | "恢复到前 N 个版本", "go back N versions" | Version-based | "恢复到前3个版本", "go back 2 versions" |
232
+ | "恢复到上一个版本", "previous version" | Version-based (N=1) | "回到上一个版本", "undo last change" |
233
+ | "恢复到今天下午3点", "restore to 3pm" | Time-based (absolute) | "恢复到下午3点的状态" |
234
+ | "恢复到昨天的版本", "yesterday's version" | Time-based | "恢复到昨天" |
235
+
236
+ ### Step 1: Parse the Request
237
+
238
+ Extract two things from the user's request:
239
+ - **Target scope**: specific file(s) or entire project?
240
+ - **Reference point**: a time expression or a version count?
241
+
242
+ If unclear, ask: "你想恢复哪个文件?还是整个项目?" / "Which file(s) do you want to restore?"
243
+
244
+ ### Step 2: Find Matching Commits
245
+
246
+ **For time-based requests**, the goal is to find the **latest commit AT or BEFORE the target time** — not commits after it.
247
+
248
+ ```bash
249
+ # "恢复到5分钟前" → find the most recent commit BEFORE that point
250
+ git log --oneline --before="5 minutes ago" -5 -- <file>
251
+
252
+ # Auto-backup branch (if exists)
253
+ git log cursor-guard/auto-backup --oneline --before="5 minutes ago" -5 -- <file>
254
+
255
+ # Reflog as fallback (shows all HEAD movements)
256
+ git reflog --before="5 minutes ago" -5
257
+ ```
258
+
259
+ Time expression mapping (always use `--before` to find the state AT that point):
260
+ - "5分钟前" / "5 minutes ago" → `--before="5 minutes ago"`
261
+ - "1小时前" / "1 hour ago" → `--before="1 hour ago"`
262
+ - "今天下午3点" → `--before="today 15:00"`
263
+ - "昨天" / "yesterday" → `--before="yesterday 23:59"`
264
+
265
+ **Key rule**: the first result from `--before` is the closest commit at or before the target time — that is the correct restore point.
266
+
267
+ **For version-based requests**, use commit offset:
268
+
269
+ ```bash
270
+ # N versions ago on current branch
271
+ git log --oneline -<N+5> -- <file>
272
+
273
+ # Or use HEAD~N directly
274
+ git show HEAD~<N>:<file>
275
+
276
+ # Auto-backup branch
277
+ git log cursor-guard/auto-backup --oneline -<N+5> -- <file>
278
+ ```
279
+
280
+ ### Step 3: Present Candidates to User
281
+
282
+ **Selection rule**: prefer the **latest commit AT or BEFORE the target time**. This is always candidate #1 in the `--before` results. Only if no commit exists before the target time, inform the user and offer the closest commit after it as an approximation.
283
+
284
+ Show a numbered list of matching commits with timestamps:
285
+
286
+ ```
287
+ Found these snapshots / 找到以下快照:
288
+
289
+ → 1. [abc1234] 2026-03-21 16:05:32 — guard: snapshot before ai edit ← closest before target
290
+ 2. [def5678] 2026-03-21 16:02:15 — guard: auto-backup 2026-03-21 16:02:15
291
+ 3. [ghi9012] 2026-03-21 15:58:40 — feat: add login page
292
+
293
+ Recommended: #1 (closest to target time). Restore this one? / 推荐 #1(最接近目标时间)。恢复这个?
294
+ ```
295
+
296
+ **Rules**:
297
+ - If only ONE candidate is found, confirm with the user before restoring.
298
+ - If MULTIPLE candidates, pre-select #1 (closest before target) but let the user pick another.
299
+ - If NO candidates before the target time:
300
+ - Check auto-backup branch: `git rev-parse --verify cursor-guard/auto-backup`
301
+ - Check shadow copies: `Get-ChildItem .cursor-guard-backup/ -Directory | Sort-Object Name -Descending`
302
+ - If still nothing, report clearly: "No snapshot found before that time. The earliest available is [hash] at [time]. Do you want to use it?"
303
+ - **Never silently pick a version.** Always show and confirm.
304
+
305
+ ### Step 4: Execute Recovery
306
+
307
+ **Single file recovery:**
308
+
309
+ ```bash
310
+ git restore --source=<commit-hash> -- <path/to/file>
311
+ ```
312
+
313
+ **Entire project recovery** (destructive — require explicit confirmation):
314
+
315
+ ```bash
316
+ # Show what will change first
317
+ git diff <commit-hash> -- .
318
+
319
+ # After user confirms:
320
+ git restore --source=<commit-hash> -- .
321
+ ```
322
+
323
+ **From shadow copy:**
324
+
325
+ ```powershell
326
+ # Find the closest timestamp directory
327
+ Get-ChildItem .cursor-guard-backup/ -Directory | Sort-Object Name -Descending
328
+
329
+ # Restore
330
+ Copy-Item ".cursor-guard-backup/<timestamp>/<file>" "<original-path>"
331
+ ```
332
+
333
+ ### Step 5: Verify & Report
334
+
335
+ After restoring, always:
336
+ 1. Show the restored file content (or diff) so the user can verify
337
+ 2. Report the recovery in the status block (§6)
338
+ 3. Suggest creating a new snapshot of the current (restored) state
339
+
340
+ ---
341
+
175
342
  ## 6. Output to User (When This Skill Was Used)
176
343
 
177
344
  When you followed this skill's workflow, end with a short **status block**:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-guard",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
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",
@@ -22,6 +22,7 @@
22
22
  "files": [
23
23
  "SKILL.md",
24
24
  "README.md",
25
+ "README.zh-CN.md",
25
26
  "LICENSE",
26
27
  "references/"
27
28
  ],
@@ -37,10 +37,16 @@ $ErrorActionPreference = "Stop"
37
37
  $resolved = (Resolve-Path $Path).Path
38
38
  Set-Location $resolved
39
39
 
40
- # ── Paths ──────────────────────────────────────────────────────────
41
- $gitDir = Join-Path $resolved ".git"
42
- $lockFile = Join-Path $gitDir "cursor-guard.lock"
43
- $guardIndex = Join-Path $gitDir "cursor-guard-index"
40
+ # ── Paths (worktree-safe: uses git rev-parse instead of hard-coding .git) ──
41
+ $gitDir = (git rev-parse --git-dir 2>$null)
42
+ if (-not $gitDir) {
43
+ $gitDir = Join-Path $resolved ".git"
44
+ } else {
45
+ $gitDir = (Resolve-Path $gitDir -ErrorAction SilentlyContinue).Path
46
+ if (-not $gitDir) { $gitDir = Join-Path $resolved ".git" }
47
+ }
48
+ $lockFile = Join-Path $gitDir "cursor-guard.lock"
49
+ $guardIndex = Join-Path $gitDir "cursor-guard-index"
44
50
  $backupDir = Join-Path $resolved ".cursor-guard-backup"
45
51
  $logFilePath = Join-Path $backupDir "backup.log"
46
52
 
@@ -56,6 +62,7 @@ trap { Invoke-Cleanup; break }
56
62
  $protectPatterns = @()
57
63
  $ignorePatterns = @()
58
64
  $secretsPatterns = @(".env", ".env.*", "*.key", "*.pem", "*.p12", "*.pfx", "credentials*")
65
+ $backupStrategy = "git"
59
66
  $retentionMode = "days"
60
67
  $retentionDays = 30
61
68
  $retentionMaxCnt = 100
@@ -69,6 +76,7 @@ if (Test-Path $cfgPath) {
69
76
  if ($cfg.protect) { $protectPatterns = @($cfg.protect) }
70
77
  if ($cfg.ignore) { $ignorePatterns = @($cfg.ignore) }
71
78
  if ($cfg.secrets_patterns) { $secretsPatterns = @($cfg.secrets_patterns) }
79
+ if ($cfg.backup_strategy) { $backupStrategy = $cfg.backup_strategy }
72
80
  if ($cfg.auto_backup_interval_seconds -and $IntervalSeconds -eq 0) {
73
81
  $IntervalSeconds = $cfg.auto_backup_interval_seconds
74
82
  }
@@ -88,7 +96,8 @@ if (Test-Path $cfgPath) {
88
96
  if ($IntervalSeconds -eq 0) { $IntervalSeconds = 60 }
89
97
 
90
98
  # ── Git repo check ───────────────────────────────────────────────
91
- if (-not (Test-Path $gitDir)) {
99
+ $isRepo = git rev-parse --is-inside-work-tree 2>$null
100
+ if ($isRepo -ne "true") {
92
101
  $ans = Read-Host "Directory is not a Git repo. Initialize? (y/n)"
93
102
  if ($ans -eq 'y') {
94
103
  git init
@@ -126,6 +135,20 @@ if (-not (git rev-parse --verify $branchRef 2>$null)) {
126
135
  Write-Host "[guard] Created branch: $branch" -ForegroundColor Green
127
136
  }
128
137
 
138
+ # ── Ensure .cursor-guard-backup/ is git-ignored ─────────────────
139
+ $excludeFile = Join-Path $gitDir "info/exclude"
140
+ $excludeDir = Split-Path $excludeFile
141
+ if (-not (Test-Path $excludeDir)) { New-Item -ItemType Directory -Force $excludeDir | Out-Null }
142
+ $excludeEntry = ".cursor-guard-backup/"
143
+ if (Test-Path $excludeFile) {
144
+ $content = Get-Content $excludeFile -Raw -ErrorAction SilentlyContinue
145
+ if (-not $content -or $content -notmatch [regex]::Escape($excludeEntry)) {
146
+ Add-Content $excludeFile "`n$excludeEntry"
147
+ }
148
+ } else {
149
+ Set-Content $excludeFile $excludeEntry
150
+ }
151
+
129
152
  # ── Log directory & helpers ──────────────────────────────────────
130
153
  if (-not (Test-Path $backupDir)) { New-Item -ItemType Directory -Force $backupDir | Out-Null }
131
154
 
@@ -209,10 +232,50 @@ function Invoke-RetentionCleanup {
209
232
  } catch {}
210
233
  }
211
234
 
235
+ # ── Shadow copy helper ────────────────────────────────────────────
236
+ function Invoke-ShadowCopy {
237
+ $ts = Get-Date -Format 'yyyyMMdd_HHmmss'
238
+ $snapDir = Join-Path $backupDir $ts
239
+ New-Item -ItemType Directory -Force $snapDir | Out-Null
240
+
241
+ $files = if ($protectPatterns.Count -gt 0) {
242
+ $protectPatterns | ForEach-Object { Get-ChildItem $resolved -Recurse -File -Filter $_ -ErrorAction SilentlyContinue }
243
+ } else {
244
+ Get-ChildItem $resolved -Recurse -File -ErrorAction SilentlyContinue |
245
+ Where-Object { $_.FullName -notmatch '[\\/](\.git|\.cursor-guard-backup|node_modules)[\\/]' }
246
+ }
247
+
248
+ $copied = 0
249
+ foreach ($f in $files) {
250
+ $rel = $f.FullName.Substring($resolved.Length + 1)
251
+ $skip = $false
252
+ foreach ($ig in $ignorePatterns) {
253
+ $re = '^' + [regex]::Escape($ig).Replace('\*\*','.*').Replace('\*','[^/\\]*').Replace('\?','.') + '$'
254
+ if ($rel -match $re) { $skip = $true; break }
255
+ }
256
+ foreach ($pat in $secretsPatterns) {
257
+ $re = '^' + [regex]::Escape($pat).Replace('\*','.*').Replace('\?','.') + '$'
258
+ if ($rel -match $re -or $f.Name -match $re) { $skip = $true; break }
259
+ }
260
+ if ($skip) { continue }
261
+ $dest = Join-Path $snapDir $rel
262
+ $destDir = Split-Path $dest
263
+ if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Force $destDir | Out-Null }
264
+ Copy-Item $f.FullName $dest -Force
265
+ $copied++
266
+ }
267
+ if ($copied -gt 0) {
268
+ Write-Log "Shadow copy $ts ($copied files)"
269
+ } else {
270
+ Remove-Item $snapDir -Recurse -Force -ErrorAction SilentlyContinue
271
+ }
272
+ return $copied
273
+ }
274
+
212
275
  # ── Banner ───────────────────────────────────────────────────────
213
276
  Write-Host ""
214
277
  Write-Host "[guard] Watching '$resolved' every ${IntervalSeconds}s (Ctrl+C to stop)" -ForegroundColor Cyan
215
- Write-Host "[guard] Branch: $branch | Retention: $retentionMode ($retentionDays days / $retentionMaxCnt count / ${retentionMaxMB} MB)" -ForegroundColor Cyan
278
+ Write-Host "[guard] Strategy: $backupStrategy | Branch: $branch | Retention: $retentionMode ($retentionDays days / $retentionMaxCnt count / ${retentionMaxMB} MB)" -ForegroundColor Cyan
216
279
  Write-Host "[guard] Log: $logFilePath" -ForegroundColor Cyan
217
280
  Write-Host ""
218
281
 
@@ -226,63 +289,64 @@ try {
226
289
  $dirty = git status --porcelain 2>$null
227
290
  if (-not $dirty) { continue }
228
291
 
229
- try {
230
- # Use a temporary index file the main index and branch are never touched
231
- $env:GIT_INDEX_FILE = $guardIndex
232
-
233
- # Seed temp index from the current backup-branch tree
234
- $parentHash = git rev-parse --verify $branchRef 2>$null
235
- if ($parentHash) { git read-tree $branchRef 2>$null }
236
-
237
- # Stage protected files from the working tree into temp index
238
- if ($protectPatterns.Count -gt 0) {
239
- foreach ($p in $protectPatterns) { git add -- $p 2>$null }
240
- } else {
241
- git add -A 2>$null
242
- }
243
- foreach ($ig in $ignorePatterns) {
244
- git rm --cached --ignore-unmatch -rq -- $ig 2>$null
245
- }
292
+ # ── Git branch snapshot ──────────────────────────────────
293
+ if ($backupStrategy -eq "git" -or $backupStrategy -eq "both") {
294
+ try {
295
+ $env:GIT_INDEX_FILE = $guardIndex
246
296
 
247
- Remove-SecretsFromIndex
297
+ $parentHash = git rev-parse --verify $branchRef 2>$null
298
+ if ($parentHash) { git read-tree $branchRef 2>$null }
248
299
 
249
- # Build tree object and compare with parent
250
- $newTree = git write-tree
251
- $parentTree = if ($parentHash) { git rev-parse "${branchRef}^{tree}" 2>$null } else { $null }
252
-
253
- if ($newTree -eq $parentTree) {
254
- Write-Host "[guard] $(Get-Date -Format 'HH:mm:ss') tree unchanged, skipped." -ForegroundColor DarkGray
255
- continue
256
- }
257
-
258
- # Create commit via plumbing — no checkout, no hooks, no branch switch
259
- $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
260
- $msg = "guard: auto-backup $ts"
261
- $commitHash = if ($parentHash) {
262
- git commit-tree $newTree -p $parentHash -m $msg
263
- } else {
264
- git commit-tree $newTree -m $msg
265
- }
266
- git update-ref $branchRef $commitHash
300
+ if ($protectPatterns.Count -gt 0) {
301
+ foreach ($p in $protectPatterns) { git add -- $p 2>$null }
302
+ } else {
303
+ git add -A 2>$null
304
+ }
305
+ foreach ($ig in $ignorePatterns) {
306
+ git rm --cached --ignore-unmatch -rq -- $ig 2>$null
307
+ }
267
308
 
268
- if (-not $commitHash) {
269
- Write-Log "ERROR: commit-tree failed, snapshot skipped" Red
270
- continue
309
+ Remove-SecretsFromIndex
310
+
311
+ $newTree = git write-tree
312
+ $parentTree = if ($parentHash) { git rev-parse "${branchRef}^{tree}" 2>$null } else { $null }
313
+
314
+ if ($newTree -eq $parentTree) {
315
+ Write-Host "[guard] $(Get-Date -Format 'HH:mm:ss') tree unchanged, skipped." -ForegroundColor DarkGray
316
+ } else {
317
+ $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
318
+ $msg = "guard: auto-backup $ts"
319
+ $commitHash = if ($parentHash) {
320
+ git commit-tree $newTree -p $parentHash -m $msg
321
+ } else {
322
+ git commit-tree $newTree -m $msg
323
+ }
324
+
325
+ if (-not $commitHash) {
326
+ Write-Log "ERROR: commit-tree failed, snapshot skipped" Red
327
+ } else {
328
+ git update-ref $branchRef $commitHash
329
+ $short = $commitHash.Substring(0, 7)
330
+ if ($parentTree) {
331
+ $diff = git diff-tree --no-commit-id --name-only -r $parentTree $newTree 2>$null
332
+ $count = if ($diff) { @($diff).Count } else { 0 }
333
+ } else {
334
+ $all = git ls-tree --name-only -r $newTree 2>$null
335
+ $count = if ($all) { @($all).Count } else { 0 }
336
+ }
337
+ Write-Log "Git snapshot $short ($count files)"
338
+ }
339
+ }
271
340
  }
272
-
273
- $short = $commitHash.Substring(0, 7)
274
- if ($parentTree) {
275
- $diff = git diff-tree --no-commit-id --name-only -r $parentTree $newTree 2>$null
276
- $count = if ($diff) { @($diff).Count } else { 0 }
277
- } else {
278
- $all = git ls-tree --name-only -r $newTree 2>$null
279
- $count = if ($all) { @($all).Count } else { 0 }
341
+ finally {
342
+ $env:GIT_INDEX_FILE = $null
343
+ Remove-Item $guardIndex -Force -ErrorAction SilentlyContinue
280
344
  }
281
- Write-Log "Snapshot $short ($count files)"
282
345
  }
283
- finally {
284
- $env:GIT_INDEX_FILE = $null
285
- Remove-Item $guardIndex -Force -ErrorAction SilentlyContinue
346
+
347
+ # ── Shadow copy ──────────────────────────────────────────
348
+ if ($backupStrategy -eq "shadow" -or $backupStrategy -eq "both") {
349
+ Invoke-ShadowCopy | Out-Null
286
350
  }
287
351
 
288
352
  # Periodic retention cleanup every 10 cycles
@@ -34,21 +34,40 @@ git restore --source=<commit> -- <path/to/file>
34
34
 
35
35
  ## Undo uncommitted changes (entire repo) — **destructive**
36
36
 
37
+ **Always preview first / 务必先预览:**
38
+
37
39
  ```bash
40
+ # Step 1: Preview what will be reverted / 预览将要还原的内容
41
+ git diff
42
+
43
+ # Step 2: Preview what untracked files would be removed / 预览将被删除的未跟踪文件
44
+ git clean -fdn # dry-run: shows what WOULD be deleted
45
+
46
+ # Step 3: Only after user confirms / 用户确认后再执行
38
47
  git restore .
39
- git clean -fd # removes untracked files/dirs — DANGEROUS
40
48
  ```
41
49
 
42
- Only suggest `git clean -fd` if the user explicitly wants untracked removal; warn about data loss.
50
+ Only suggest `git clean -fd` if the user explicitly wants untracked removal; warn about data loss:
51
+
52
+ ```bash
53
+ # DANGEROUS: removes untracked files — only after explicit confirmation
54
+ # 危险:删除未跟踪文件——仅在用户明确确认后执行
55
+ git clean -fd
56
+ ```
43
57
 
44
58
  ## Recover "lost" commits / after reset
45
59
 
46
60
  ```bash
61
+ # Step 1: Find the lost commit / 找到丢失的提交
47
62
  git reflog
48
- # find the commit hash, then:
63
+
64
+ # Step 2: Create a recovery branch (safe, non-destructive) / 创建恢复分支(安全)
49
65
  git branch recover-branch <hash>
50
- # or (destructive — discards uncommitted work):
51
- git reset --hard <hash>
66
+
67
+ # Step 3 (alternative): Hard reset DESTRUCTIVE, preview first
68
+ # 硬重置——破坏性操作,先预览
69
+ git diff HEAD <hash> --stat # preview what changes
70
+ git reset --hard <hash> # only after confirmation
52
71
  ```
53
72
 
54
73
  ## Restore deleted file from HEAD (if it was committed)
@@ -65,6 +84,98 @@ git stash list
65
84
  git stash pop
66
85
  ```
67
86
 
87
+ ## Restore to N minutes/hours ago / 恢复到 N 分钟/小时前
88
+
89
+ The goal is to find the **latest commit AT or BEFORE** the target time.
90
+
91
+ 目标是找到目标时间点**之前(含)最近的一次提交**。
92
+
93
+ ```bash
94
+ # Find the most recent commit BEFORE N minutes ago
95
+ # 查找 N 分钟前之前最近的提交
96
+ git log --oneline --before="5 minutes ago" -5 -- <file>
97
+
98
+ # Find the most recent commit BEFORE N hours ago
99
+ # 查找 N 小时前之前最近的提交
100
+ git log --oneline --before="2 hours ago" -5 -- <file>
101
+
102
+ # Reflog as fallback (captures resets, amends, etc.)
103
+ # Reflog 作为兜底(能捕获 reset、amend 等操作)
104
+ git reflog --before="5 minutes ago" -5
105
+
106
+ # Restore file to the first (closest) commit found above
107
+ # 恢复到上面找到的第一个(最近的)提交
108
+ git restore --source=<commit-hash> -- <file>
109
+ ```
110
+
111
+ ## Restore to a specific time / 恢复到指定时间点
112
+
113
+ ```bash
114
+ # Find the closest commit before a specific time
115
+ # 查找指定时间点之前最近的提交
116
+ git log --oneline --before="2026-03-21 15:00" -5 -- <file>
117
+ git log --oneline --before="today 15:00" -5 -- <file>
118
+
119
+ # Yesterday / 昨天
120
+ git log --oneline --after="yesterday 00:00" --before="yesterday 23:59" -- <file>
121
+
122
+ # Restore
123
+ git restore --source=<commit-hash> -- <file>
124
+ ```
125
+
126
+ ## Restore to N versions ago / 恢复到前 N 个版本
127
+
128
+ ```bash
129
+ # Show recent N commits for a file
130
+ # 查看某文件最近 N 个提交
131
+ git log --oneline -10 -- <file>
132
+
133
+ # Restore to previous version (1 version ago)
134
+ # 恢复到上一个版本
135
+ git restore --source=HEAD~1 -- <file>
136
+
137
+ # Restore to 3 versions ago
138
+ # 恢复到前 3 个版本
139
+ git restore --source=HEAD~3 -- <file>
140
+
141
+ # Preview what the file looked like N versions ago (without restoring)
142
+ # 预览 N 个版本前的文件内容(不实际恢复)
143
+ git show HEAD~3:<file>
144
+
145
+ # Diff current vs N versions ago
146
+ # 对比当前和 N 个版本前的差异
147
+ git diff HEAD~3 -- <file>
148
+ ```
149
+
150
+ > **Note / 注意**: `HEAD~N` counts commits on the current branch. If you want the Nth commit that *changed this specific file*, use:
151
+ >
152
+ > `HEAD~N` 是按分支提交计数。如果想找第 N 次**修改该文件**的提交,用:
153
+ >
154
+ > ```bash
155
+ > # Find the 3rd most recent commit that touched this file
156
+ > git log --oneline -3 -- <file>
157
+ > # Then use the hash from the output
158
+ > git restore --source=<hash> -- <file>
159
+ > ```
160
+
161
+ ## Restore entire project to a point in time / 恢复整个项目到某个时间点
162
+
163
+ ```bash
164
+ # CAUTION: This affects ALL files. Review carefully!
165
+ # 注意:这会影响所有文件,请仔细检查!
166
+
167
+ # Step 1: Find the target commit / 第一步:找到目标提交
168
+ git log --oneline --before="10 minutes ago" -5
169
+
170
+ # Step 2: Preview what will change / 第二步:预览变更
171
+ git diff <commit-hash> -- .
172
+
173
+ # Step 3: Restore (after confirmation) / 第三步:恢复(确认后)
174
+ git restore --source=<commit-hash> -- .
175
+ ```
176
+
177
+ ---
178
+
68
179
  ## Recover from auto-backup branch
69
180
 
70
181
  The `auto-backup.ps1` script stores periodic snapshots on a dedicated branch via plumbing commands:
@@ -81,6 +192,14 @@ git restore --source=<commit-hash> -- <path/to/file>
81
192
 
82
193
  # Diff your working copy against the auto-backup version
83
194
  git diff cursor-guard/auto-backup -- <path/to/file>
195
+
196
+ # Time-based: find auto-backup snapshot from before N minutes ago
197
+ # 按时间查找:N 分钟前之前最近的自动备份快照
198
+ git log cursor-guard/auto-backup --oneline --before="5 minutes ago" -5 -- <path/to/file>
199
+
200
+ # Version-based: list recent N auto-backup snapshots
201
+ # 按版本查找:最近 N 个自动备份快照
202
+ git log cursor-guard/auto-backup --oneline -10 -- <path/to/file>
84
203
  ```
85
204
 
86
205
  ## If not a Git repo yet
@@ -100,11 +219,20 @@ This does **not** recover past work from before `init`.
100
219
  If `.cursor-guard-backup/` exists, find snapshots:
101
220
 
102
221
  ```powershell
103
- # List all backup timestamps
222
+ # List all backup timestamps / 列出所有备份时间戳
104
223
  Get-ChildItem .cursor-guard-backup/ -Directory | Sort-Object Name -Descending
105
224
 
106
- # Restore a specific file from a timestamp
225
+ # Restore a specific file from a timestamp / 从某个时间戳恢复文件
107
226
  Copy-Item ".cursor-guard-backup/<timestamp>/<filename>" "<original-path>"
227
+
228
+ # Find the closest shadow copy to N minutes ago / 查找 N 分钟前最近的影子拷贝
229
+ $target = (Get-Date).AddMinutes(-5)
230
+ Get-ChildItem .cursor-guard-backup/ -Directory |
231
+ Where-Object { $_.Name -match '^\d{8}_\d{6}$' } |
232
+ ForEach-Object {
233
+ $dt = [datetime]::ParseExact($_.Name, "yyyyMMdd_HHmmss", $null)
234
+ [PSCustomObject]@{ Name = $_.Name; Time = $dt; Diff = [math]::Abs(($dt - $target).TotalSeconds) }
235
+ } | Sort-Object Diff | Select-Object -First 3
108
236
  ```
109
237
 
110
238
  ---