cursor-guard 1.2.0 → 1.3.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
@@ -157,7 +157,9 @@ The script uses Git plumbing commands to snapshot to `cursor-guard/auto-backup`
157
157
 
158
158
  ## Recovery
159
159
 
160
- If something goes wrong, just tell the AI agent in natural language:
160
+ If something goes wrong, just tell the AI agent in natural language.
161
+
162
+ **Default behavior**: Before any restore, the agent automatically preserves your current version so you can undo the restore if needed. You don't need to ask for this — it happens by default. To skip, explicitly say "don't preserve current version" or "skip backup before restore".
161
163
 
162
164
  ### By time
163
165
 
@@ -176,7 +178,14 @@ If something goes wrong, just tell the AI agent in natural language:
176
178
  > "restore src/app.py to 10 minutes ago"
177
179
  > "restore src/app.py to the previous version"
178
180
 
179
- The agent will automatically search Git history and auto-backup snapshots, show you matching versions to choose from, and restore after your confirmation.
181
+ The agent will:
182
+ 1. **Preserve your current version** first (unless you opt out)
183
+ 2. Search Git history and auto-backup snapshots
184
+ 3. Show matching versions for you to choose
185
+ 4. Restore after your confirmation
186
+ 5. Report both the pre-restore backup ref and the restore result
187
+
188
+ If the pre-restore backup fails, the agent will **not** proceed — it will wait for your explicit confirmation before restoring without a safety net.
180
189
 
181
190
  ### Recovery priority
182
191
 
package/README.zh-CN.md CHANGED
@@ -157,7 +157,9 @@ cp .cursor/skills/cursor-guard/references/cursor-guard.example.json .cursor-guar
157
157
 
158
158
  ## 恢复
159
159
 
160
- 出问题时,直接用自然语言告诉 AI 代理即可:
160
+ 出问题时,直接用自然语言告诉 AI 代理即可。
161
+
162
+ **默认行为**:执行任何恢复操作前,代理会自动保留你的当前版本,方便恢复后反悔。无需额外请求,这是默认行为。如需跳过,请明确说"不保留当前版本"或"直接覆盖恢复"。
161
163
 
162
164
  ### 按时间恢复
163
165
 
@@ -176,7 +178,14 @@ cp .cursor/skills/cursor-guard/references/cursor-guard.example.json .cursor-guar
176
178
  > "把 src/app.py 恢复到10分钟前"
177
179
  > "把 src/app.py 恢复到上一个版本"
178
180
 
179
- 代理会自动搜索 Git 历史和自动备份快照,列出匹配版本供你选择,确认后执行恢复。
181
+ 代理会:
182
+ 1. **先保留你的当前版本**(除非你明确选择跳过)
183
+ 2. 搜索 Git 历史和自动备份快照
184
+ 3. 列出匹配版本供你选择
185
+ 4. 确认后执行恢复
186
+ 5. 报告恢复前备份引用和恢复结果
187
+
188
+ 如果保留当前版本失败,代理**不会**继续恢复——会等你明确确认后才会在没有安全网的情况下恢复。
180
189
 
181
190
  ### 恢复优先级
182
191
 
package/SKILL.md CHANGED
@@ -302,7 +302,104 @@ Recommended: #1 (closest to target time). Restore this one? / 推荐 #1(最接
302
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
303
  - **Never silently pick a version.** Always show and confirm.
304
304
 
305
- ### Step 4: Execute Recovery
305
+ ### Step 4: Preserve Current Version Before Restore (MANDATORY)
306
+
307
+ > **Rule: `restore_requires_preserve_current_by_default`**
308
+ >
309
+ > Every restore operation MUST first preserve the current state, THEN restore. This is non-negotiable unless the user explicitly opts out.
310
+
311
+ **4a. Check if user opted out**
312
+
313
+ Skip preservation ONLY if the user explicitly said one of:
314
+ - "不保留当前版本" / "不用备份当前版本" / "直接覆盖恢复"
315
+ - "skip backup before restore" / "don't preserve current" / "just restore"
316
+
317
+ If opted out, inform: "你已明确表示不保留当前版本,我将直接恢复。" and jump to Step 5.
318
+
319
+ **4b. Determine preservation scope**
320
+
321
+ | Restore scope | What to preserve |
322
+ |---------------|-----------------|
323
+ | Single file | Only that file's current state |
324
+ | Multiple files | All files that will be overwritten |
325
+ | Entire project | Full project snapshot |
326
+
327
+ **4c. Check if there are changes to preserve**
328
+
329
+ ```bash
330
+ # For single file: check if file differs from the restore target
331
+ git diff <target-commit> -- <file>
332
+
333
+ # For project: check overall status
334
+ git status --porcelain
335
+ ```
336
+
337
+ If the file/project is **identical** to the restore target (no diff), inform:
338
+ "当前版本与目标版本相同,无需保留,跳过备份。" / "Current version is identical to target, no backup needed."
339
+ Then jump to Step 5.
340
+
341
+ If the working tree is clean AND HEAD matches the restore target, inform:
342
+ "当前无可保留变更,直接恢复。" / "No changes to preserve, proceeding with restore."
343
+ Then jump to Step 5.
344
+
345
+ **4d. Create preservation snapshot**
346
+
347
+ Use the same temp-index plumbing as §2a to avoid polluting the user's staging area:
348
+
349
+ **Git repo (preferred):**
350
+
351
+ ```powershell
352
+ $guardIdx = Join-Path (git rev-parse --git-dir) "guard-pre-restore-index"
353
+ $env:GIT_INDEX_FILE = $guardIdx
354
+
355
+ # For single file: read HEAD tree then update just the target file
356
+ git read-tree HEAD
357
+ git add -- <file>
358
+
359
+ # For project: snapshot everything
360
+ git read-tree HEAD
361
+ git add -A
362
+
363
+ $tree = git write-tree
364
+ $env:GIT_INDEX_FILE = $null
365
+ Remove-Item $guardIdx -Force -ErrorAction SilentlyContinue
366
+
367
+ $commit = git commit-tree $tree -p HEAD -m "guard: preserve current before restore to <target>"
368
+ git update-ref refs/guard/pre-restore $commit
369
+ ```
370
+
371
+ Record the short hash and the ref `refs/guard/pre-restore`.
372
+
373
+ **Non-Git fallback (shadow copy):**
374
+
375
+ ```powershell
376
+ $ts = Get-Date -Format 'yyyyMMdd_HHmmss'
377
+ $dir = ".cursor-guard-backup/pre-restore-$ts"
378
+ New-Item -ItemType Directory -Force $dir | Out-Null
379
+ Copy-Item "<file>" "$dir/<file>"
380
+ ```
381
+
382
+ **4e. Handle preservation failure**
383
+
384
+ If the snapshot fails (e.g. disk full, permission error):
385
+ 1. **Do NOT proceed with restore.** Default is to abort.
386
+ 2. Inform the user: "当前版本保留失败。默认不继续恢复;如果你确认不保留当前状态也要继续,请明确说明。" / "Failed to preserve current version. Restore aborted by default. If you want to continue without backup, please confirm explicitly."
387
+ 3. Only proceed if the user explicitly confirms: "即使不保留也继续" / "continue without backup".
388
+
389
+ **4f. Inform user of preservation result**
390
+
391
+ Before executing restore, tell the user:
392
+ ```
393
+ 在恢复前,我已保留当前版本:
394
+ - 备份引用: refs/guard/pre-restore (abc1234)
395
+ - 恢复方式: git restore --source=refs/guard/pre-restore -- <file>
396
+
397
+ Current version preserved before restore:
398
+ - Backup ref: refs/guard/pre-restore (abc1234)
399
+ - To undo: git restore --source=refs/guard/pre-restore -- <file>
400
+ ```
401
+
402
+ ### Step 5: Execute Recovery
306
403
 
307
404
  **Single file recovery:**
308
405
 
@@ -330,12 +427,23 @@ Get-ChildItem .cursor-guard-backup/ -Directory | Sort-Object Name -Descending
330
427
  Copy-Item ".cursor-guard-backup/<timestamp>/<file>" "<original-path>"
331
428
  ```
332
429
 
333
- ### Step 5: Verify & Report
430
+ ### Step 6: Verify & Report
334
431
 
335
432
  After restoring, always:
336
433
  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
434
+ 2. Report the recovery in the status block (§6a), including **both** the pre-restore backup ref and the restore target
435
+ 3. Tell the user how to undo the restore if needed
436
+
437
+ **Status block for restore operations:**
438
+
439
+ ```markdown
440
+ **Cursor Guard — restore status**
441
+ - **Pre-restore backup**: `refs/guard/pre-restore` (`<short-hash>`) or `shadow copy at .cursor-guard-backup/pre-restore-<ts>/` or `skipped (user opted out)` or `skipped (no changes)`
442
+ - **Restored to**: `<target-hash>` / `<target description>`
443
+ - **Scope**: single file `<path>` / N files / entire project
444
+ - **Result**: success / failed
445
+ - **To undo restore**: `git restore --source=refs/guard/pre-restore -- <file>`
446
+ ```
339
447
 
340
448
  ---
341
449
 
@@ -360,15 +468,17 @@ Skip the block for unrelated turns.
360
468
 
361
469
  1. **MUST snapshot before high-risk ops** — git commit or shadow copy. No exceptions unless user explicitly declines.
362
470
  2. **MUST Read before Write** — never overwrite a file the agent hasn't read in the current turn.
363
- 3. **Do not** treat Timeline/Checkpoints as the only or primary recovery path.
364
- 4. **Do not** recommend Checkpoints as long-term or sole backup.
365
- 5. **No automatic push** to remotes; local commits only unless user requests push.
366
- 6. **Be honest** about limits: terminal side effects, binary files, and non-tracked paths are not fully reversible without prior commits.
367
- 7. **Do not** run `git clean`, `reset --hard`, or other destructive Git commands unless the user clearly asked; always show what would be affected first.
368
- 8. **Do not** delete files via the Delete tool without explicit per-file confirmation from the user.
369
- 9. **Do not** modify or delete `.cursor-guard.json` unless the user explicitly asks accidental config changes silently alter protection scope.
370
- 10. **Use `--no-verify`** on all guard snapshot commits to bypass pre-commit hooks that could fail or modify files.
371
- 11. **Concurrent agents**: if multiple Agent threads are active, warn the user to avoid simultaneous writes to the same file. Snapshots cannot prevent race conditions between parallel agents.
471
+ 3. **MUST preserve current version before restore** every restore operation must first snapshot the current state (§5a Step 4). Skip ONLY when: (a) user explicitly opts out, (b) current state is identical to target, or (c) no changes exist. If preservation fails, abort restore by default.
472
+ 4. **Do not** treat Timeline/Checkpoints as the only or primary recovery path.
473
+ 5. **Do not** recommend Checkpoints as long-term or sole backup.
474
+ 6. **No automatic push** to remotes; local commits only unless user requests push.
475
+ 7. **Be honest** about limits: terminal side effects, binary files, and non-tracked paths are not fully reversible without prior commits.
476
+ 8. **Do not** run `git clean`, `reset --hard`, or other destructive Git commands unless the user clearly asked; always show what would be affected first.
477
+ 9. **Do not** delete files via the Delete tool without explicit per-file confirmation from the user.
478
+ 10. **Do not** modify or delete `.cursor-guard.json` unless the user explicitly asks accidental config changes silently alter protection scope.
479
+ 11. **Use `--no-verify`** on all guard snapshot commits to bypass pre-commit hooks that could fail or modify files.
480
+ 12. **Concurrent agents**: if multiple Agent threads are active, warn the user to avoid simultaneous writes to the same file. Snapshots cannot prevent race conditions between parallel agents.
481
+ 13. **Preservation must not pollute** — all pre-restore backups use temp index + dedicated ref (`refs/guard/pre-restore`). The user's staging area, working tree, and commit history on their branch are never modified by the preservation process.
372
482
 
373
483
  ---
374
484
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-guard",
3
- "version": "1.2.0",
3
+ "version": "1.3.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",
@@ -4,6 +4,72 @@ Replace `<path>` / `<file>` with real paths. Run from repository root. **Review
4
4
 
5
5
  ---
6
6
 
7
+ ## Preserve current version before restore / 恢复前保留当前版本
8
+
9
+ > **Default behavior**: Every restore operation must first preserve current state.
10
+ >
11
+ > **默认行为**:每次恢复操作前必须先保留当前版本。
12
+
13
+ ### Single file / 单文件
14
+
15
+ ```powershell
16
+ # Preserve current file state via temp index (does not touch staging area)
17
+ # 通过临时索引保留当前文件(不影响暂存区)
18
+ $guardIdx = Join-Path (git rev-parse --git-dir) "guard-pre-restore-index"
19
+ $env:GIT_INDEX_FILE = $guardIdx
20
+ git read-tree HEAD
21
+ git add -- <file>
22
+ $tree = git write-tree
23
+ $env:GIT_INDEX_FILE = $null
24
+ Remove-Item $guardIdx -Force -ErrorAction SilentlyContinue
25
+ $commit = git commit-tree $tree -p HEAD -m "guard: preserve current before restore"
26
+ git update-ref refs/guard/pre-restore $commit
27
+ Write-Host "Pre-restore backup: $($commit.Substring(0,7))"
28
+ ```
29
+
30
+ ### Entire project / 整个项目
31
+
32
+ ```powershell
33
+ # Same as above but with git add -A
34
+ $guardIdx = Join-Path (git rev-parse --git-dir) "guard-pre-restore-index"
35
+ $env:GIT_INDEX_FILE = $guardIdx
36
+ git read-tree HEAD
37
+ git add -A
38
+ $tree = git write-tree
39
+ $env:GIT_INDEX_FILE = $null
40
+ Remove-Item $guardIdx -Force -ErrorAction SilentlyContinue
41
+ $commit = git commit-tree $tree -p HEAD -m "guard: preserve current before restore"
42
+ git update-ref refs/guard/pre-restore $commit
43
+ Write-Host "Pre-restore backup: $($commit.Substring(0,7))"
44
+ ```
45
+
46
+ ### Non-Git fallback (shadow copy) / 非 Git 备选方案
47
+
48
+ ```powershell
49
+ $ts = Get-Date -Format 'yyyyMMdd_HHmmss'
50
+ $dir = ".cursor-guard-backup/pre-restore-$ts"
51
+ New-Item -ItemType Directory -Force $dir | Out-Null
52
+ Copy-Item "<file>" "$dir/<filename>"
53
+ Write-Host "Pre-restore shadow copy: $dir"
54
+ ```
55
+
56
+ ### Undo a restore (recover pre-restore state) / 撤销恢复(回到恢复前的状态)
57
+
58
+ ```bash
59
+ # Restore single file to pre-restore state
60
+ # 将单个文件恢复到恢复前的状态
61
+ git restore --source=refs/guard/pre-restore -- <file>
62
+
63
+ # Restore entire project to pre-restore state
64
+ # 将整个项目恢复到恢复前的状态
65
+ git restore --source=refs/guard/pre-restore -- .
66
+
67
+ # From shadow copy / 从影子拷贝恢复
68
+ Copy-Item ".cursor-guard-backup/pre-restore-<ts>/<file>" "<original-path>"
69
+ ```
70
+
71
+ ---
72
+
7
73
  ## Inspect current state
8
74
 
9
75
  ```bash