cursor-guard 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Cursor Guard
2
+
3
+ Protects your code from accidental AI overwrite or deletion in [Cursor](https://cursor.com).
4
+
5
+ ## What It Does
6
+
7
+ 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:
8
+
9
+ - **Mandatory pre-write snapshots** — Git commit or shadow copy before any destructive operation
10
+ - **Read before Write** — The agent must read a file before overwriting it
11
+ - **Review before apply** — Diff previews and explicit confirmation for dangerous ops
12
+ - **Deterministic recovery** — Clear priority-ordered recovery paths (Git → shadow copies → conversation context → editor history)
13
+ - **Configurable scope** — Protect only what matters via `.cursor-guard.json`
14
+ - **Secrets filtering** — Sensitive files (`.env`, keys, certificates) are auto-excluded from backups
15
+ - **Auto-backup script** — A PowerShell watcher that periodically snapshots to a dedicated Git branch without disturbing your working tree
16
+
17
+ ## Installation
18
+
19
+ ### For Cursor (as an Agent Skill)
20
+
21
+ Copy the `cursor-guard/` folder into your Cursor skills directory:
22
+
23
+ ```
24
+ ~/.cursor/skills/cursor-guard/
25
+ ```
26
+
27
+ Or per-project:
28
+
29
+ ```
30
+ <project-root>/.cursor/skills/cursor-guard/
31
+ ```
32
+
33
+ The skill activates automatically when the AI agent detects risky operations (file edits, deletes, renames) or when you mention recovery-related terms.
34
+
35
+ ### Project Configuration (Optional)
36
+
37
+ Copy the example config to your workspace root and customize:
38
+
39
+ ```bash
40
+ cp .cursor/skills/cursor-guard/references/cursor-guard.example.json .cursor-guard.json
41
+ ```
42
+
43
+ Edit `.cursor-guard.json` to define which files to protect:
44
+
45
+ ```json
46
+ {
47
+ "protect": ["src/**", "lib/**", "package.json"],
48
+ "ignore": ["node_modules/**", "dist/**"],
49
+ "auto_backup_interval_seconds": 60,
50
+ "secrets_patterns": [".env", ".env.*", "*.key", "*.pem"],
51
+ "retention": { "mode": "days", "days": 30 }
52
+ }
53
+ ```
54
+
55
+ ## Auto-Backup Script
56
+
57
+ Run in a separate terminal while working in Cursor:
58
+
59
+ ```powershell
60
+ .\auto-backup.ps1 -Path "D:\MyProject"
61
+
62
+ # Custom interval (default 60s):
63
+ .\auto-backup.ps1 -Path "D:\MyProject" -IntervalSeconds 30
64
+ ```
65
+
66
+ The script uses Git plumbing commands to snapshot to `cursor-guard/auto-backup` branch — it never switches branches or touches your working index.
67
+
68
+ ## Recovery
69
+
70
+ If something goes wrong, recovery follows this priority:
71
+
72
+ 1. **Git** — `git restore`, `git reset`, `git reflog`
73
+ 2. **Shadow copies** — `.cursor-guard-backup/<timestamp>/`
74
+ 3. **Conversation context** — Original file content captured by agent Read calls
75
+ 4. **Editor history** — VS Code/Cursor Timeline (auxiliary)
76
+
77
+ See [references/recovery.md](references/recovery.md) for detailed commands.
78
+
79
+ ## Trigger Keywords
80
+
81
+ The skill activates on these signals:
82
+
83
+ - File edits, deletes, renames by the AI agent
84
+ - Recovery requests: "回滚", "误删", "丢版本", "rollback", "undo", "recover"
85
+ - History issues: checkpoints missing, Timeline not working, save failures
86
+
87
+ ## Files
88
+
89
+ | File | Purpose |
90
+ |------|---------|
91
+ | `SKILL.md` | Main skill instructions for the AI agent |
92
+ | `references/auto-backup.ps1` | PowerShell auto-backup watcher script |
93
+ | `references/recovery.md` | Recovery command templates |
94
+ | `references/cursor-guard.example.json` | Example project configuration |
95
+ | `references/cursor-guard.schema.json` | JSON Schema for config validation |
96
+
97
+ ## Requirements
98
+
99
+ - **Git** (for primary backup strategy)
100
+ - **PowerShell 5.1+** (for auto-backup script; Windows built-in)
101
+ - **Cursor IDE** with Agent mode enabled
102
+
103
+ ## License
104
+
105
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,221 @@
1
+ ---
2
+ name: cursor-guard
3
+ description: >-
4
+ Protects code from accidental AI overwrite or deletion in Cursor: mandatory
5
+ pre-write snapshots, review-before-apply, local Git safety net, and
6
+ deterministic recovery. Trigger on code loss, rollback, checkpoints,
7
+ Timeline/local history, tool vs editor saves, multi-root workspaces, or safe
8
+ AI editing workflows (including Chinese phrases like 回滚, 误删, 丢版本).
9
+ ---
10
+
11
+ # Cursor Guard — Strong Protection Mode
12
+
13
+ ## When This Skill Applies (Triggers)
14
+
15
+ Use this skill when any of the following appear:
16
+
17
+ - **Auto disk writes**: Agent/tools edit files without the user reviewing a diff first.
18
+ - **Deletes or renames**: Bulk delete, `rm`, refactor that removes paths.
19
+ - **History confusion**: Checkpoints missing, Timeline/local history not rolling back, "save failed" after external writes.
20
+ - **Parallel context**: Multiple repos or branches; unclear which folder is the workspace root.
21
+ - **Recovery asks**: e.g. "改不回来", "丢版本", "回滚", "reflog", "误删", or English equivalents.
22
+
23
+ If none of the above, do not expand scope; answer normally.
24
+
25
+ ---
26
+
27
+ ## 0. Load Project Config (If Exists)
28
+
29
+ On first trigger in a session, check if the workspace root contains `.cursor-guard.json`. If found, **read it** and apply throughout:
30
+
31
+ ```jsonc
32
+ {
33
+ "protect": ["src/**", "lib/**", "package.json"],
34
+ "ignore": ["node_modules/**", "dist/**", "*.log"],
35
+
36
+ "backup_strategy": "git",
37
+ "auto_backup_interval_seconds": 60,
38
+
39
+ // Sensitive file patterns — auto-excluded from backup even if in protect scope.
40
+ // Built-in defaults: .env, .env.*, *.key, *.pem, *.p12, *.pfx, credentials*
41
+ "secrets_patterns": [".env", ".env.*", "*.key", "*.pem"],
42
+
43
+ // Retention for shadow copies. mode: "days" | "count" | "size"
44
+ "retention": { "mode": "days", "days": 30, "max_count": 100, "max_size_mb": 500 }
45
+ }
46
+ ```
47
+
48
+ **Resolution rules:**
49
+ - `protect` set + `ignore` set → file must match a `protect` pattern AND not match any `ignore` pattern.
50
+ - Only `protect` set → only matching files are protected.
51
+ - Only `ignore` set → everything is protected except matching files.
52
+ - Neither set → protect everything (same as before).
53
+
54
+ **`secrets_patterns`**: Glob patterns for sensitive files (`.env`, keys, certificates). Matching files are **auto-excluded** from backup commits, even within `protect` scope. Built-in defaults: `.env`, `.env.*`, `*.key`, `*.pem`, `*.p12`, `*.pfx`, `credentials*`. Set this field to override.
55
+
56
+ **`retention`**: Controls automatic cleanup of old shadow-copy snapshots in `.cursor-guard-backup/`:
57
+ - `"days"` (default): keep snapshots from the last N days (default **30**).
58
+ - `"count"`: keep the N most recent snapshots (default 100).
59
+ - `"size"`: keep total shadow-copy folder under N MB (default 500).
60
+
61
+ **If no config file exists**, the agent operates in "protect everything" mode (backward compatible). Mention to the user that they can create `.cursor-guard.json` to narrow scope — see [references/cursor-guard.example.json](references/cursor-guard.example.json).
62
+
63
+ When the target file of an edit **falls outside the protected scope**, the agent:
64
+ - Still applies "Read before Write" (Hard Rule §2).
65
+ - Skips the mandatory git snapshot / shadow copy step.
66
+ - Notes `outside protection scope` in the status block.
67
+
68
+ ---
69
+
70
+ ## 1. Assess Risk (First)
71
+
72
+ | Signal | Risk |
73
+ |--------|------|
74
+ | Multi-file edits, `delete_file`, terminal `rm`, or **Write** to existing file | **High** |
75
+ | Single small edit (`StrReplace` with narrow scope), user explicitly asked | **Medium** |
76
+ | Read-only explanation, no writes | **Low** |
77
+
78
+ ---
79
+
80
+ ## 2. Mandatory Pre-Write Backup Protocol (ENFORCED)
81
+
82
+ > **This is not optional.** The agent MUST execute these steps before making
83
+ > destructive or high-risk changes. Skipping is only allowed when the user
84
+ > explicitly says "不用备份" / "skip backup".
85
+
86
+ ### 2a. If workspace IS a Git repo
87
+
88
+ **Before any High-risk operation on a protected file:**
89
+
90
+ ```
91
+ git add -A && git commit -m "guard: snapshot before ai edit" --no-verify
92
+ ```
93
+
94
+ - 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.
97
+ - 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.
99
+
100
+ **Before any Medium-risk operation:**
101
+
102
+ - At minimum, run `git diff -- <target_file>` and `git status` so the user sees current state.
103
+ - Recommend a snapshot commit; proceed without it only if the user confirms.
104
+
105
+ ### 2b. If workspace is NOT a Git repo
106
+
107
+ **Before any High-risk operation, offer TWO options (pick one):**
108
+
109
+ 1. **Quick git init** (preferred):
110
+ ```
111
+ git init && git add -A && git commit -m "guard: initial snapshot" --no-verify
112
+ ```
113
+ 2. **Shadow copy** (fallback if user declines git):
114
+ - Copy the target file(s) to `.cursor-guard-backup/<timestamp>/` via Shell.
115
+ - Example:
116
+ ```powershell
117
+ $ts = Get-Date -Format 'yyyyMMdd_HHmmss'
118
+ New-Item -ItemType Directory -Force ".cursor-guard-backup/$ts"
119
+ Copy-Item "src/app.py" ".cursor-guard-backup/$ts/app.py"
120
+ ```
121
+ - Add `.cursor-guard-backup/` to `.gitignore` if git is later initialized.
122
+
123
+ **If user declines BOTH:** document refusal in the status block (§6), state the file cannot be recovered if lost, and proceed only with explicit "我了解风险,继续" confirmation.
124
+
125
+ ### 2c. Multi-file batch operations
126
+
127
+ When editing 3+ files in one task:
128
+
129
+ 1. Create the snapshot commit covering ALL files first.
130
+ 2. Apply changes file-by-file; if any step fails, offer to `git restore` all files back to the snapshot.
131
+ 3. After all edits succeed, offer a clean commit with a real message.
132
+
133
+ ---
134
+
135
+ ## 3. Protection Strategy During Edits
136
+
137
+ **Before applying AI changes:**
138
+
139
+ 1. **Preview**: Show a clear **diff-style summary** (paths + intent). For substantial edits, prefer patch-sized chunks.
140
+ 2. **Destructive ops**: For deletes or large rewrites, **confirm explicitly** (one short question). Do not assume "cleanup" permission.
141
+ 3. **Workspace root**: State which directory is treated as project root; avoid touching paths outside it unless the user asked.
142
+ 4. **Read before Write**: The agent MUST Read a file's current content before using Write to overwrite it. This ensures the full original content is captured in conversation context as a last-resort recovery source.
143
+ 5. **Rename / Move**: Treat renames and moves as a delete + create. Snapshot the original path before proceeding; note both old and new paths in the status block so history can be traced.
144
+
145
+ **After tool writes (agent wrote to disk directly):**
146
+
147
+ - Tell the user: editor buffer may be stale → **`Revert File`** (Ctrl+Shift+P → "Revert File") or close & reopen tab.
148
+ - Do **not** claim Timeline/Checkpoints will capture tool writes.
149
+
150
+ ---
151
+
152
+ ## 4. Backup Strategy (Priority)
153
+
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.
157
+ 4. **Editor habits** — Ctrl+S frequently; optional extensions are user-configured, mention only if asked.
158
+
159
+ **Hard default:** Do NOT `git push` unless the user explicitly asks. Scope = **local only**.
160
+
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).
162
+
163
+ ---
164
+
165
+ ## 5. Recovery Strategy (Priority Order)
166
+
167
+ 1. **Git**: `git status` → `git diff` → `git restore` → `git reset` → `git reflog` — see [references/recovery.md](references/recovery.md).
168
+ 2. **Shadow copies**: Check `.cursor-guard-backup/` for timestamped copies.
169
+ 3. **Conversation context**: If the agent Read the file before overwriting, the original content is in this chat — offer to re-write it back.
170
+ 4. **Editor Local History / Timeline**: auxiliary, per-file; unreliable for tool-only disk writes.
171
+ 5. **Cursor Checkpoints**: auxiliary; tied to Agent UI; not a long-term backup.
172
+
173
+ ---
174
+
175
+ ## 6. Output to User (When This Skill Was Used)
176
+
177
+ When you followed this skill's workflow, end with a short **status block**:
178
+
179
+ ```markdown
180
+ **Cursor Guard — status**
181
+ - **Risk**: low / medium / high
182
+ - **Snapshot**: `<short-hash>` or `shadow copy at .cursor-guard-backup/<ts>/` or `none (user declined)`
183
+ - **Done**: (e.g. snapshot committed / diff previewed / recovery completed)
184
+ - **Next step**: (one concrete command or one UI action)
185
+ - **Recovery ref**: `references/recovery.md` in this skill folder
186
+ ```
187
+
188
+ Skip the block for unrelated turns.
189
+
190
+ ---
191
+
192
+ ## Hard Rules (Non-Negotiable)
193
+
194
+ 1. **MUST snapshot before high-risk ops** — git commit or shadow copy. No exceptions unless user explicitly declines.
195
+ 2. **MUST Read before Write** — never overwrite a file the agent hasn't read in the current turn.
196
+ 3. **Do not** treat Timeline/Checkpoints as the only or primary recovery path.
197
+ 4. **Do not** recommend Checkpoints as long-term or sole backup.
198
+ 5. **No automatic push** to remotes; local commits only unless user requests push.
199
+ 6. **Be honest** about limits: terminal side effects, binary files, and non-tracked paths are not fully reversible without prior commits.
200
+ 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.
201
+ 8. **Do not** delete files via the Delete tool without explicit per-file confirmation from the user.
202
+ 9. **Do not** modify or delete `.cursor-guard.json` unless the user explicitly asks — accidental config changes silently alter protection scope.
203
+ 10. **Use `--no-verify`** on all guard snapshot commits to bypass pre-commit hooks that could fail or modify files.
204
+ 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.
205
+
206
+ ---
207
+
208
+ ## Optional: Project Conventions
209
+
210
+ - If the workspace has `.cursor-guard.json`, the agent MUST read and follow it (see §0).
211
+ - If `.cursor-guard-backup/` folder exists, align shadow copy paths with it.
212
+ - Template config: [references/cursor-guard.example.json](references/cursor-guard.example.json) — copy to workspace root and customize.
213
+
214
+ ---
215
+
216
+ ## Further Reading
217
+
218
+ - Recovery commands: [references/recovery.md](references/recovery.md)
219
+ - Auto-backup script: [references/auto-backup.ps1](references/auto-backup.ps1)
220
+ - Config JSON Schema: [references/cursor-guard.schema.json](references/cursor-guard.schema.json)
221
+ - Example config: [references/cursor-guard.example.json](references/cursor-guard.example.json)
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "cursor-guard",
3
+ "version": "1.0.0",
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.",
5
+ "keywords": [
6
+ "cursor",
7
+ "cursor-ide",
8
+ "ai-safety",
9
+ "code-protection",
10
+ "git-backup",
11
+ "snapshot",
12
+ "recovery",
13
+ "agent-skill"
14
+ ],
15
+ "author": "zhangqiang8vipp",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/zhangqiang8vipp/cursor-guard.git"
20
+ },
21
+ "homepage": "https://github.com/zhangqiang8vipp/cursor-guard",
22
+ "files": [
23
+ "SKILL.md",
24
+ "README.md",
25
+ "LICENSE",
26
+ "references/"
27
+ ],
28
+ "main": "SKILL.md"
29
+ }
@@ -0,0 +1,295 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Auto-backup script for Cursor Guard.
4
+ Periodically snapshots protected files to a local Git branch using
5
+ plumbing commands — never switches branches or disturbs the main index.
6
+ Reads .cursor-guard.json for scope, secrets, and retention settings.
7
+
8
+ .USAGE
9
+ # Run in a separate PowerShell window while working in Cursor:
10
+ .\auto-backup.ps1 -Path "D:\MyProject"
11
+
12
+ # Custom interval (default 60 seconds):
13
+ .\auto-backup.ps1 -Path "D:\MyProject" -IntervalSeconds 30
14
+
15
+ # Stop: Ctrl+C or close the PowerShell window.
16
+
17
+ .NOTES
18
+ - Snapshots go to branch `cursor-guard/auto-backup` via plumbing commands.
19
+ - Never switches branches, never touches the main index.
20
+ - Does NOT push to any remote.
21
+ - Sensitive files matching secrets_patterns are auto-excluded.
22
+ - Shadow copies are cleaned per retention policy (default: keep 30 days).
23
+ - Log file: .cursor-guard-backup/backup.log
24
+ - IMPORTANT: Run this script in a SEPARATE PowerShell window, NOT inside
25
+ Cursor's integrated terminal. Cursor's terminal injects --trailer flags
26
+ into git commit commands, which corrupts plumbing calls like commit-tree.
27
+ #>
28
+
29
+ param(
30
+ [Parameter(Mandatory)]
31
+ [string]$Path,
32
+
33
+ [int]$IntervalSeconds = 0
34
+ )
35
+
36
+ $ErrorActionPreference = "Stop"
37
+ $resolved = (Resolve-Path $Path).Path
38
+ Set-Location $resolved
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"
44
+ $backupDir = Join-Path $resolved ".cursor-guard-backup"
45
+ $logFilePath = Join-Path $backupDir "backup.log"
46
+
47
+ # ── Cleanup on exit ───────────────────────────────────────────────
48
+ function Invoke-Cleanup {
49
+ $env:GIT_INDEX_FILE = $null
50
+ Remove-Item $guardIndex -Force -ErrorAction SilentlyContinue
51
+ Remove-Item $lockFile -Force -ErrorAction SilentlyContinue
52
+ }
53
+ trap { Invoke-Cleanup; break }
54
+
55
+ # ── Defaults ──────────────────────────────────────────────────────
56
+ $protectPatterns = @()
57
+ $ignorePatterns = @()
58
+ $secretsPatterns = @(".env", ".env.*", "*.key", "*.pem", "*.p12", "*.pfx", "credentials*")
59
+ $retentionMode = "days"
60
+ $retentionDays = 30
61
+ $retentionMaxCnt = 100
62
+ $retentionMaxMB = 500
63
+
64
+ # ── Load .cursor-guard.json ──────────────────────────────────────
65
+ $cfgPath = Join-Path $resolved ".cursor-guard.json"
66
+ if (Test-Path $cfgPath) {
67
+ try {
68
+ $cfg = Get-Content $cfgPath -Raw | ConvertFrom-Json
69
+ if ($cfg.protect) { $protectPatterns = @($cfg.protect) }
70
+ if ($cfg.ignore) { $ignorePatterns = @($cfg.ignore) }
71
+ if ($cfg.secrets_patterns) { $secretsPatterns = @($cfg.secrets_patterns) }
72
+ if ($cfg.auto_backup_interval_seconds -and $IntervalSeconds -eq 0) {
73
+ $IntervalSeconds = $cfg.auto_backup_interval_seconds
74
+ }
75
+ if ($cfg.retention) {
76
+ if ($cfg.retention.mode) { $retentionMode = $cfg.retention.mode }
77
+ if ($cfg.retention.days) { $retentionDays = $cfg.retention.days }
78
+ if ($cfg.retention.max_count) { $retentionMaxCnt = $cfg.retention.max_count }
79
+ if ($cfg.retention.max_size_mb) { $retentionMaxMB = $cfg.retention.max_size_mb }
80
+ }
81
+ Write-Host "[guard] Config loaded protect=$($protectPatterns.Count) ignore=$($ignorePatterns.Count) retention=$retentionMode" -ForegroundColor Cyan
82
+ }
83
+ catch {
84
+ Write-Host "[guard] WARNING: .cursor-guard.json parse error - using defaults." -ForegroundColor Yellow
85
+ Write-Host " $_" -ForegroundColor Yellow
86
+ }
87
+ }
88
+ if ($IntervalSeconds -eq 0) { $IntervalSeconds = 60 }
89
+
90
+ # ── Git repo check ───────────────────────────────────────────────
91
+ if (-not (Test-Path $gitDir)) {
92
+ $ans = Read-Host "Directory is not a Git repo. Initialize? (y/n)"
93
+ if ($ans -eq 'y') {
94
+ git init
95
+ $gi = Join-Path $resolved ".gitignore"
96
+ $entry = ".cursor-guard-backup/"
97
+ if (Test-Path $gi) {
98
+ $content = Get-Content $gi -Raw
99
+ if ($content -notmatch [regex]::Escape($entry)) {
100
+ Add-Content $gi "`n$entry"
101
+ }
102
+ } else {
103
+ Set-Content $gi $entry
104
+ }
105
+ git add -A; git commit -m "guard: initial snapshot" --no-verify
106
+ Write-Host "[guard] Repo initialized with snapshot." -ForegroundColor Green
107
+ } else {
108
+ Write-Host "[guard] Git is required. Exiting." -ForegroundColor Red
109
+ exit 1
110
+ }
111
+ }
112
+
113
+ # ── Lock file (prevent multiple instances) ───────────────────────
114
+ if (Test-Path $lockFile) {
115
+ Write-Host "[guard] ERROR: Lock file exists ($lockFile)." -ForegroundColor Red
116
+ Write-Host " If no other instance is running, delete it and retry." -ForegroundColor Red
117
+ exit 1
118
+ }
119
+ Set-Content $lockFile "pid=$PID`nstarted=$(Get-Date -Format 'o')"
120
+
121
+ # ── Backup branch ───────────────────────────────────────────────
122
+ $branch = "cursor-guard/auto-backup"
123
+ $branchRef = "refs/heads/$branch"
124
+ if (-not (git rev-parse --verify $branchRef 2>$null)) {
125
+ git branch $branch HEAD 2>$null
126
+ Write-Host "[guard] Created branch: $branch" -ForegroundColor Green
127
+ }
128
+
129
+ # ── Log directory & helpers ──────────────────────────────────────
130
+ if (-not (Test-Path $backupDir)) { New-Item -ItemType Directory -Force $backupDir | Out-Null }
131
+
132
+ function Write-Log {
133
+ param([string]$Msg, [ConsoleColor]$Color = "Green")
134
+ $line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') $Msg"
135
+ Add-Content -Path $logFilePath -Value $line -ErrorAction SilentlyContinue
136
+ Write-Host "[guard] $line" -ForegroundColor $Color
137
+ }
138
+
139
+ # ── Secrets filter ───────────────────────────────────────────────
140
+ function Remove-SecretsFromIndex {
141
+ $files = git ls-files --cached 2>$null
142
+ if (-not $files) { return }
143
+ $excluded = @()
144
+ foreach ($f in $files) {
145
+ $leaf = Split-Path $f -Leaf
146
+ foreach ($pat in $secretsPatterns) {
147
+ $re = '^' + [regex]::Escape($pat).Replace('\*','.*').Replace('\?','.') + '$'
148
+ if ($f -match $re -or $leaf -match $re) {
149
+ git rm --cached --ignore-unmatch -q -- $f 2>$null
150
+ $excluded += $f
151
+ break
152
+ }
153
+ }
154
+ }
155
+ if ($excluded.Count -gt 0) {
156
+ Write-Log "Secrets auto-excluded: $($excluded -join ', ')" Yellow
157
+ }
158
+ }
159
+
160
+ # ── Retention cleanup ────────────────────────────────────────────
161
+ function Invoke-RetentionCleanup {
162
+ # Clean shadow-copy directories named yyyyMMdd_HHmmss
163
+ $dirs = Get-ChildItem $backupDir -Directory -ErrorAction SilentlyContinue |
164
+ Where-Object { $_.Name -match '^\d{8}_\d{6}$' } |
165
+ Sort-Object Name -Descending
166
+ if ($dirs -and $dirs.Count -gt 0) {
167
+ $removed = 0
168
+ switch ($retentionMode) {
169
+ "days" {
170
+ $cutoff = (Get-Date).AddDays(-$retentionDays)
171
+ foreach ($d in $dirs) {
172
+ try {
173
+ $dt = [datetime]::ParseExact($d.Name, "yyyyMMdd_HHmmss", $null)
174
+ if ($dt -lt $cutoff) { Remove-Item $d.FullName -Recurse -Force; $removed++ }
175
+ } catch {}
176
+ }
177
+ }
178
+ "count" {
179
+ if ($dirs.Count -gt $retentionMaxCnt) {
180
+ $dirs | Select-Object -Skip $retentionMaxCnt |
181
+ ForEach-Object { Remove-Item $_.FullName -Recurse -Force; $removed++ }
182
+ }
183
+ }
184
+ "size" {
185
+ $totalMB = (Get-ChildItem $backupDir -Recurse -File -ErrorAction SilentlyContinue |
186
+ Measure-Object Length -Sum).Sum / 1MB
187
+ $oldest = $dirs | Sort-Object Name
188
+ foreach ($d in $oldest) {
189
+ if ($totalMB -le $retentionMaxMB) { break }
190
+ $sz = (Get-ChildItem $d.FullName -Recurse -File |
191
+ Measure-Object Length -Sum).Sum / 1MB
192
+ Remove-Item $d.FullName -Recurse -Force
193
+ $totalMB -= $sz; $removed++
194
+ }
195
+ }
196
+ }
197
+ if ($removed -gt 0) {
198
+ Write-Log "Retention ($retentionMode): cleaned $removed old snapshot(s)" DarkGray
199
+ }
200
+ }
201
+
202
+ # Disk-space warning
203
+ try {
204
+ $letter = (Split-Path $resolved -Qualifier) -replace ':$',''
205
+ $drv = Get-PSDrive $letter
206
+ $freeGB = [math]::Round($drv.Free / 1GB, 1)
207
+ if ($freeGB -lt 1) { Write-Log "WARNING: disk critically low - ${freeGB} GB free" Red }
208
+ elseif ($freeGB -lt 5) { Write-Log "Disk note: ${freeGB} GB free" Yellow }
209
+ } catch {}
210
+ }
211
+
212
+ # ── Banner ───────────────────────────────────────────────────────
213
+ Write-Host ""
214
+ 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
216
+ Write-Host "[guard] Log: $logFilePath" -ForegroundColor Cyan
217
+ Write-Host ""
218
+
219
+ # ── Main loop ────────────────────────────────────────────────────
220
+ $cycle = 0
221
+ try {
222
+ while ($true) {
223
+ Start-Sleep -Seconds $IntervalSeconds
224
+ $cycle++
225
+
226
+ $dirty = git status --porcelain 2>$null
227
+ if (-not $dirty) { continue }
228
+
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
+ }
246
+
247
+ Remove-SecretsFromIndex
248
+
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
267
+
268
+ if (-not $commitHash) {
269
+ Write-Log "ERROR: commit-tree failed, snapshot skipped" Red
270
+ continue
271
+ }
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 }
280
+ }
281
+ Write-Log "Snapshot $short ($count files)"
282
+ }
283
+ finally {
284
+ $env:GIT_INDEX_FILE = $null
285
+ Remove-Item $guardIndex -Force -ErrorAction SilentlyContinue
286
+ }
287
+
288
+ # Periodic retention cleanup every 10 cycles
289
+ if ($cycle % 10 -eq 0) { Invoke-RetentionCleanup }
290
+ }
291
+ }
292
+ finally {
293
+ Invoke-Cleanup
294
+ Write-Host "`n[guard] Stopped." -ForegroundColor Cyan
295
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "_comment_schema": "Optional: add \"$schema\" pointing to cursor-guard.schema.json for IDE validation. Adjust the path to where you placed the schema file.",
3
+
4
+ "_comment_mode": "Two modes: whitelist (set 'protect') or blacklist (set 'ignore'). If both are set, 'protect' is checked first, then 'ignore' excludes from it.",
5
+
6
+ "protect": [
7
+ "src/**",
8
+ "lib/**",
9
+ "*.config.js",
10
+ "*.config.ts",
11
+ "package.json",
12
+ "tsconfig.json",
13
+ ".env.example"
14
+ ],
15
+
16
+ "ignore": [
17
+ "node_modules/**",
18
+ "dist/**",
19
+ "build/**",
20
+ ".next/**",
21
+ "coverage/**",
22
+ "*.log",
23
+ "*.tmp",
24
+ ".cursor-guard-backup/**"
25
+ ],
26
+
27
+ "backup_strategy": "git",
28
+ "auto_backup_interval_seconds": 60,
29
+
30
+ "_comment_secrets": "Glob patterns for sensitive files — auto-excluded from backup even if matched by 'protect'. Built-in defaults: .env, .env.*, *.key, *.pem, *.p12, *.pfx, credentials*",
31
+ "secrets_patterns": [
32
+ ".env",
33
+ ".env.*",
34
+ "*.key",
35
+ "*.pem"
36
+ ],
37
+
38
+ "_comment_retention": "Retention policy for shadow copies. mode: 'days' (default, keep N days), 'count' (keep N newest snapshots), 'size' (keep total under N MB).",
39
+ "retention": {
40
+ "mode": "days",
41
+ "days": 30,
42
+ "max_count": 100,
43
+ "max_size_mb": 500
44
+ }
45
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Cursor Guard Configuration",
4
+ "description": "Controls which files are protected, backup strategy, secrets filtering, and retention policy for the cursor-guard skill.",
5
+ "type": "object",
6
+ "properties": {
7
+ "protect": {
8
+ "type": "array",
9
+ "items": { "type": "string" },
10
+ "description": "Whitelist glob patterns relative to workspace root. Only matching files get backup protection. If empty or missing, all files are protected."
11
+ },
12
+ "ignore": {
13
+ "type": "array",
14
+ "items": { "type": "string" },
15
+ "description": "Blacklist glob patterns. Matching files are excluded even if they match 'protect'. Applied on top of .gitignore."
16
+ },
17
+ "backup_strategy": {
18
+ "type": "string",
19
+ "enum": ["git", "shadow", "both"],
20
+ "default": "git",
21
+ "description": "Primary backup method: 'git' (local commits), 'shadow' (.cursor-guard-backup/ copies), or 'both'."
22
+ },
23
+ "auto_backup_interval_seconds": {
24
+ "type": "integer",
25
+ "minimum": 5,
26
+ "default": 60,
27
+ "description": "Interval in seconds for auto-backup.ps1 to check for changes."
28
+ },
29
+ "secrets_patterns": {
30
+ "type": "array",
31
+ "items": { "type": "string" },
32
+ "description": "Glob patterns for sensitive files auto-excluded from backups. Built-in defaults: .env, .env.*, *.key, *.pem, *.p12, *.pfx, credentials*"
33
+ },
34
+ "retention": {
35
+ "type": "object",
36
+ "description": "Controls automatic cleanup of old shadow-copy snapshots.",
37
+ "properties": {
38
+ "mode": {
39
+ "type": "string",
40
+ "enum": ["days", "count", "size"],
41
+ "default": "days",
42
+ "description": "'days': keep snapshots from the last N days. 'count': keep N newest snapshots. 'size': keep total size under N MB."
43
+ },
44
+ "days": {
45
+ "type": "integer",
46
+ "minimum": 1,
47
+ "default": 30,
48
+ "description": "Number of days to retain snapshots (when mode='days')."
49
+ },
50
+ "max_count": {
51
+ "type": "integer",
52
+ "minimum": 1,
53
+ "default": 100,
54
+ "description": "Maximum number of snapshots to keep (when mode='count')."
55
+ },
56
+ "max_size_mb": {
57
+ "type": "integer",
58
+ "minimum": 10,
59
+ "default": 500,
60
+ "description": "Maximum total size in MB for shadow copies (when mode='size')."
61
+ }
62
+ },
63
+ "additionalProperties": false
64
+ }
65
+ },
66
+ "additionalProperties": true
67
+ }
@@ -0,0 +1,177 @@
1
+ # Recovery Command Templates
2
+
3
+ Replace `<path>` / `<file>` with real paths. Run from repository root. **Review output before destructive commands.**
4
+
5
+ ---
6
+
7
+ ## Inspect current state
8
+
9
+ ```bash
10
+ git status
11
+ git diff
12
+ git log --oneline -10
13
+ ```
14
+
15
+ ## Recent commits (compact)
16
+
17
+ ```bash
18
+ git log --oneline -20 --decorate
19
+ ```
20
+
21
+ ## Restore one file to last commit (discard working tree changes)
22
+
23
+ ```bash
24
+ git restore --source=HEAD -- <path/to/file>
25
+ ```
26
+
27
+ ## Restore one file from a specific commit
28
+
29
+ ```bash
30
+ git restore --source=<commit> -- <path/to/file>
31
+ ```
32
+
33
+ > Avoid shell redirects (`git show <commit>:file > file`) on Windows — they can corrupt encoding. Prefer `git restore --source`.
34
+
35
+ ## Undo uncommitted changes (entire repo) — **destructive**
36
+
37
+ ```bash
38
+ git restore .
39
+ git clean -fd # removes untracked files/dirs — DANGEROUS
40
+ ```
41
+
42
+ Only suggest `git clean -fd` if the user explicitly wants untracked removal; warn about data loss.
43
+
44
+ ## Recover "lost" commits / after reset
45
+
46
+ ```bash
47
+ git reflog
48
+ # find the commit hash, then:
49
+ git branch recover-branch <hash>
50
+ # or (destructive — discards uncommitted work):
51
+ git reset --hard <hash>
52
+ ```
53
+
54
+ ## Restore deleted file from HEAD (if it was committed)
55
+
56
+ ```bash
57
+ git restore --source=HEAD -- <path/to/deleted/file>
58
+ ```
59
+
60
+ ## Stash (quick shelter before experiments)
61
+
62
+ ```bash
63
+ git stash push -m "wip before experiment"
64
+ git stash list
65
+ git stash pop
66
+ ```
67
+
68
+ ## Recover from auto-backup branch
69
+
70
+ The `auto-backup.ps1` script stores periodic snapshots on a dedicated branch via plumbing commands:
71
+
72
+ ```bash
73
+ # List recent auto-backup snapshots
74
+ git log cursor-guard/auto-backup --oneline -20
75
+
76
+ # Restore a file from the latest auto-backup
77
+ git restore --source=cursor-guard/auto-backup -- <path/to/file>
78
+
79
+ # Restore from a specific auto-backup snapshot
80
+ git restore --source=<commit-hash> -- <path/to/file>
81
+
82
+ # Diff your working copy against the auto-backup version
83
+ git diff cursor-guard/auto-backup -- <path/to/file>
84
+ ```
85
+
86
+ ## If not a Git repo yet
87
+
88
+ ```bash
89
+ git init
90
+ git add -A
91
+ git commit -m "guard: initial snapshot" --no-verify
92
+ ```
93
+
94
+ This does **not** recover past work from before `init`.
95
+
96
+ ---
97
+
98
+ ## Shadow Copy Recovery (Non-Git Fallback)
99
+
100
+ If `.cursor-guard-backup/` exists, find snapshots:
101
+
102
+ ```powershell
103
+ # List all backup timestamps
104
+ Get-ChildItem .cursor-guard-backup/ -Directory | Sort-Object Name -Descending
105
+
106
+ # Restore a specific file from a timestamp
107
+ Copy-Item ".cursor-guard-backup/<timestamp>/<filename>" "<original-path>"
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Windows-Specific Notes
113
+
114
+ - **Long paths**: If you get path errors, enable long path support:
115
+ ```powershell
116
+ git config --local core.longpaths true # use --global for system-wide
117
+ ```
118
+ - **Line endings**: Git may show spurious diffs due to CRLF/LF. Check with:
119
+ ```bash
120
+ git diff --check
121
+ ```
122
+ Fix with `git config --local core.autocrlf true` if desired (or `--global` for system-wide).
123
+ - **PowerShell quoting**: Use single quotes for paths with spaces in PowerShell:
124
+ ```powershell
125
+ git restore --source=HEAD -- 'src/my file.py'
126
+ ```
127
+ - **File locks**: If a file is locked by another process (e.g. Cursor still has it open), `git restore` may fail. Close the tab first or use:
128
+ ```powershell
129
+ # Force close file handle (admin required, use with caution)
130
+ # Prefer: just close the file tab in Cursor, then retry git restore.
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Non-Git Auxiliary Recovery
136
+
137
+ - **VS Code / Cursor Timeline (Local History)**: per-file; access via right-click file tab → "Open Timeline". May miss tool-only writes (Write/StrReplace via agent).
138
+ - **Checkpoints**: inside Agent thread UI only. Not guaranteed for all edit paths. Not long-term storage.
139
+ - **Conversation context**: if the agent used the Read tool on a file before overwriting it, the original content exists in the chat history. Ask the agent to re-write the original content back.
140
+ - **Recycle Bin (Windows)**: only catches files deleted via Explorer, NOT via `rm` / `Remove-Item` / agent Delete tool.
141
+
142
+ ---
143
+
144
+ ## Backup Cleanup
145
+
146
+ ### Shadow copies
147
+
148
+ ```powershell
149
+ # List all shadow copy snapshots (newest first)
150
+ Get-ChildItem .cursor-guard-backup/ -Directory | Sort-Object Name -Descending
151
+
152
+ # Delete snapshots older than 30 days
153
+ $cutoff = (Get-Date).AddDays(-30)
154
+ Get-ChildItem .cursor-guard-backup/ -Directory | Where-Object {
155
+ try { [datetime]::ParseExact($_.Name, "yyyyMMdd_HHmmss", $null) -lt $cutoff } catch { $false }
156
+ } | Remove-Item -Recurse -Force
157
+ ```
158
+
159
+ ### Auto-backup branch
160
+
161
+ ```bash
162
+ # View auto-backup history
163
+ git log cursor-guard/auto-backup --oneline -30
164
+
165
+ # Delete the branch entirely (script will recreate it on next run)
166
+ git branch -D cursor-guard/auto-backup
167
+
168
+ # Reclaim disk space after removing old branches
169
+ git gc --prune=now
170
+ ```
171
+
172
+ ### Log file
173
+
174
+ ```powershell
175
+ # View recent backup log entries
176
+ Get-Content .cursor-guard-backup/backup.log -Tail 30
177
+ ```