cursor-guard 1.4.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,226 +1,22 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- Cursor Guard Doctor one-command health check for your guard setup.
4
-
3
+ Thin wrapperlaunches the Node.js guard-doctor implementation.
5
4
  .USAGE
6
5
  .\guard-doctor.ps1 -Path "D:\MyProject"
7
-
8
6
  .NOTES
9
- Checks: Git availability, worktree layout, .cursor-guard.json validity,
10
- backup strategy vs environment compatibility, ignore effectiveness,
11
- pre-restore refs, shadow copy directory, disk space, and more.
7
+ Requires Node.js >= 18.
12
8
  #>
13
-
14
9
  param(
15
10
  [Parameter(Mandatory)]
16
11
  [string]$Path
17
12
  )
18
13
 
19
- $ErrorActionPreference = "Continue"
20
- $resolved = (Resolve-Path $Path -ErrorAction Stop).Path
21
- Set-Location $resolved
22
-
23
- $pass = 0; $warn = 0; $fail = 0
24
-
25
- function Write-Check {
26
- param([string]$Name, [string]$Status, [string]$Detail = "")
27
- switch ($Status) {
28
- "PASS" { $color = "Green"; $script:pass++ }
29
- "WARN" { $color = "Yellow"; $script:warn++ }
30
- "FAIL" { $color = "Red"; $script:fail++ }
31
- default { $color = "Gray" }
32
- }
33
- $line = " [$Status] $Name"
34
- if ($Detail) { $line += " — $Detail" }
35
- Write-Host $line -ForegroundColor $color
36
- }
37
-
38
- Write-Host ""
39
- Write-Host "=== Cursor Guard Doctor ===" -ForegroundColor Cyan
40
- Write-Host " Target: $resolved" -ForegroundColor Cyan
41
- Write-Host ""
42
-
43
- # ── 1. Git availability ──────────────────────────────────────────
44
- $hasGit = [bool](Get-Command git -ErrorAction SilentlyContinue)
45
- if ($hasGit) {
46
- $gitVer = (git --version 2>$null) -replace 'git version ',''
47
- Write-Check "Git installed" "PASS" "version $gitVer"
48
- } else {
49
- Write-Check "Git installed" "WARN" "git not found in PATH; only shadow strategy available"
50
- }
51
-
52
- # ── 2. Git repo status ───────────────────────────────────────────
53
- $isRepo = $false
54
- $gitDir = $null
55
- if ($hasGit) {
56
- $isRepo = (git rev-parse --is-inside-work-tree 2>$null) -eq "true"
57
- if ($isRepo) {
58
- $gitDir = (Resolve-Path (git rev-parse --git-dir 2>$null) -ErrorAction SilentlyContinue).Path
59
- $isWorktree = (git rev-parse --is-inside-work-tree 2>$null) -eq "true" -and
60
- (git rev-parse --git-common-dir 2>$null) -ne (git rev-parse --git-dir 2>$null)
61
- if ($isWorktree) {
62
- Write-Check "Git repository" "PASS" "worktree detected (git-dir: $gitDir)"
63
- } else {
64
- Write-Check "Git repository" "PASS" "standard repo"
65
- }
66
- } else {
67
- Write-Check "Git repository" "WARN" "not a Git repo; git/both strategies won't work"
68
- }
69
- }
70
-
71
- # ── 3. .cursor-guard.json ────────────────────────────────────────
72
- $cfgPath = Join-Path $resolved ".cursor-guard.json"
73
- $cfg = $null
74
- if (Test-Path $cfgPath) {
75
- try {
76
- $cfg = Get-Content $cfgPath -Raw | ConvertFrom-Json
77
- Write-Check "Config file" "PASS" ".cursor-guard.json found and valid JSON"
78
- } catch {
79
- Write-Check "Config file" "FAIL" "JSON parse error: $_"
80
- }
81
- } else {
82
- Write-Check "Config file" "WARN" "no .cursor-guard.json found; using defaults (protect everything)"
83
- }
84
-
85
- # ── 4. Strategy vs environment ────────────────────────────────────
86
- $strategy = "git"
87
- if ($cfg -and $cfg.backup_strategy) { $strategy = $cfg.backup_strategy }
88
- if ($strategy -eq "git" -or $strategy -eq "both") {
89
- if (-not $isRepo) {
90
- Write-Check "Strategy compatibility" "FAIL" "backup_strategy='$strategy' but directory is not a Git repo"
91
- } else {
92
- Write-Check "Strategy compatibility" "PASS" "backup_strategy='$strategy' and Git repo exists"
93
- }
94
- } elseif ($strategy -eq "shadow") {
95
- Write-Check "Strategy compatibility" "PASS" "backup_strategy='shadow' — no Git required"
96
- } else {
97
- Write-Check "Strategy compatibility" "FAIL" "unknown backup_strategy='$strategy' (must be git/shadow/both)"
98
- }
99
-
100
- # ── 5. Backup branch ─────────────────────────────────────────────
101
- if ($isRepo) {
102
- $branchRef = "refs/heads/cursor-guard/auto-backup"
103
- $branchExists = git rev-parse --verify $branchRef 2>$null
104
- if ($branchExists) {
105
- $commitCount = (git rev-list --count $branchRef 2>$null)
106
- Write-Check "Backup branch" "PASS" "cursor-guard/auto-backup exists ($commitCount commits)"
107
- } else {
108
- Write-Check "Backup branch" "WARN" "cursor-guard/auto-backup not created yet (will be created on first backup)"
109
- }
110
- }
111
-
112
- # ── 6. Guard refs ────────────────────────────────────────────────
113
- if ($isRepo) {
114
- $guardRefs = git for-each-ref refs/guard/ --format="%(refname)" 2>$null
115
- if ($guardRefs) {
116
- $refCount = @($guardRefs).Count
117
- $preRestoreRefs = @($guardRefs | Where-Object { $_ -match 'pre-restore/' })
118
- Write-Check "Guard refs" "PASS" "$refCount ref(s) found ($($preRestoreRefs.Count) pre-restore snapshots)"
119
- } else {
120
- Write-Check "Guard refs" "WARN" "no guard refs yet (created on first snapshot or restore)"
121
- }
122
- }
123
-
124
- # ── 7. Shadow copy directory ─────────────────────────────────────
125
- $backupDir = Join-Path $resolved ".cursor-guard-backup"
126
- if (Test-Path $backupDir) {
127
- $snapDirs = Get-ChildItem $backupDir -Directory -ErrorAction SilentlyContinue |
128
- Where-Object { $_.Name -match '^\d{8}_\d{6}$' -or $_.Name -match '^pre-restore-' }
129
- $snapCount = if ($snapDirs) { @($snapDirs).Count } else { 0 }
130
- $totalMB = [math]::Round(((Get-ChildItem $backupDir -Recurse -File -ErrorAction SilentlyContinue |
131
- Measure-Object Length -Sum).Sum / 1MB), 1)
132
- Write-Check "Shadow copies" "PASS" "$snapCount snapshot(s), ${totalMB} MB total"
133
- } else {
134
- Write-Check "Shadow copies" "WARN" ".cursor-guard-backup/ not found (will be created on first shadow backup)"
135
- }
136
-
137
- # ── 8. .gitignore / exclude coverage ────────────────────────────
138
- if ($isRepo) {
139
- $checkIgnored = git check-ignore ".cursor-guard-backup/test" 2>$null
140
- if ($checkIgnored) {
141
- Write-Check "Backup dir ignored" "PASS" ".cursor-guard-backup/ is git-ignored"
142
- } else {
143
- Write-Check "Backup dir ignored" "WARN" ".cursor-guard-backup/ may NOT be git-ignored — backup changes could trigger commits"
144
- }
14
+ $nodeCmd = if (Get-Command node -ErrorAction SilentlyContinue) { "node" } else { $null }
15
+ if (-not $nodeCmd) {
16
+ Write-Host "[guard] ERROR: Node.js not found. Install Node.js >= 18 first." -ForegroundColor Red
17
+ Write-Host " https://nodejs.org/" -ForegroundColor Yellow
18
+ exit 1
145
19
  }
146
20
 
147
- # ── 9. Config field validation ────────────────────────────────────
148
- if ($cfg) {
149
- $validStrategies = @("git", "shadow", "both")
150
- if ($cfg.backup_strategy -and $cfg.backup_strategy -notin $validStrategies) {
151
- Write-Check "Config: backup_strategy" "FAIL" "invalid value '$($cfg.backup_strategy)'"
152
- }
153
-
154
- $validPreRestore = @("always", "ask", "never")
155
- if ($cfg.pre_restore_backup -and $cfg.pre_restore_backup -notin $validPreRestore) {
156
- Write-Check "Config: pre_restore_backup" "FAIL" "invalid value '$($cfg.pre_restore_backup)'"
157
- } elseif ($cfg.pre_restore_backup -eq "never") {
158
- Write-Check "Config: pre_restore_backup" "WARN" "set to 'never' — restores won't auto-preserve current version"
159
- }
160
-
161
- if ($cfg.auto_backup_interval_seconds -and $cfg.auto_backup_interval_seconds -lt 5) {
162
- Write-Check "Config: interval" "WARN" "$($cfg.auto_backup_interval_seconds)s is below minimum (5s), will be clamped"
163
- }
164
-
165
- if ($cfg.retention -and $cfg.retention.mode) {
166
- $validModes = @("days", "count", "size")
167
- if ($cfg.retention.mode -notin $validModes) {
168
- Write-Check "Config: retention.mode" "FAIL" "invalid value '$($cfg.retention.mode)'"
169
- }
170
- }
171
- }
172
-
173
- # ── 10. Protect / Ignore effectiveness ───────────────────────────
174
- if ($cfg -and $cfg.protect) {
175
- $allFiles = Get-ChildItem $resolved -Recurse -File -ErrorAction SilentlyContinue |
176
- Where-Object { $_.FullName -notmatch '[\\/](\.git|\.cursor-guard-backup|node_modules)[\\/]' }
177
- $protectedCount = 0
178
- foreach ($f in $allFiles) {
179
- $rel = $f.FullName.Substring($resolved.Length + 1) -replace '\\','/'
180
- foreach ($pat in @($cfg.protect)) {
181
- $p = $pat -replace '\\','/'
182
- if ($rel -like $p -or (Split-Path $rel -Leaf) -like $p) { $protectedCount++; break }
183
- }
184
- }
185
- $totalCount = if ($allFiles) { @($allFiles).Count } else { 0 }
186
- Write-Check "Protect patterns" "PASS" "$protectedCount / $totalCount files matched by protect patterns"
187
- }
188
-
189
- # ── 11. Disk space ────────────────────────────────────────────────
190
- try {
191
- $letter = (Split-Path $resolved -Qualifier) -replace ':$',''
192
- $drv = Get-PSDrive $letter -ErrorAction Stop
193
- $freeGB = [math]::Round($drv.Free / 1GB, 1)
194
- if ($freeGB -lt 1) {
195
- Write-Check "Disk space" "FAIL" "${freeGB} GB free — critically low"
196
- } elseif ($freeGB -lt 5) {
197
- Write-Check "Disk space" "WARN" "${freeGB} GB free"
198
- } else {
199
- Write-Check "Disk space" "PASS" "${freeGB} GB free"
200
- }
201
- } catch {
202
- Write-Check "Disk space" "WARN" "could not determine free space"
203
- }
204
-
205
- # ── 12. Lock file ────────────────────────────────────────────────
206
- $lockFile = if ($gitDir) { Join-Path $gitDir "cursor-guard.lock" } else { Join-Path $backupDir "cursor-guard.lock" }
207
- if (Test-Path $lockFile) {
208
- $lockContent = Get-Content $lockFile -Raw -ErrorAction SilentlyContinue
209
- Write-Check "Lock file" "WARN" "lock file exists — another instance may be running. Content: $lockContent"
210
- } else {
211
- Write-Check "Lock file" "PASS" "no lock file (no running instance)"
212
- }
213
-
214
- # ── Summary ──────────────────────────────────────────────────────
215
- Write-Host ""
216
- Write-Host "=== Summary ===" -ForegroundColor Cyan
217
- Write-Host " PASS: $pass | WARN: $warn | FAIL: $fail" -ForegroundColor $(if ($fail -gt 0) { "Red" } elseif ($warn -gt 0) { "Yellow" } else { "Green" })
218
- Write-Host ""
219
- if ($fail -gt 0) {
220
- Write-Host " Fix FAIL items before relying on Cursor Guard." -ForegroundColor Red
221
- } elseif ($warn -gt 0) {
222
- Write-Host " Review WARN items to ensure everything works as expected." -ForegroundColor Yellow
223
- } else {
224
- Write-Host " All checks passed. Cursor Guard is ready." -ForegroundColor Green
225
- }
226
- Write-Host ""
21
+ $script = Join-Path (Join-Path $PSScriptRoot "bin") "cursor-guard-doctor.js"
22
+ & $nodeCmd $script --path $Path
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+ # Thin wrapper — launches the Node.js guard-doctor implementation.
3
+ # Usage: ./guard-doctor.sh /path/to/project
4
+ # Requires: Node.js >= 18
5
+
6
+ set -e
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
+
10
+ if ! command -v node &>/dev/null; then
11
+ echo "[guard] ERROR: Node.js not found. Install Node.js >= 18 first."
12
+ echo " https://nodejs.org/"
13
+ exit 1
14
+ fi
15
+
16
+ TARGET="${1:-.}"
17
+
18
+ exec node "$SCRIPT_DIR/bin/cursor-guard-doctor.js" --path "$TARGET"