elliot-stack 1.0.29 → 1.0.30
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 +1 -0
- package/package.json +1 -1
- package/skills/estack-vscode-file-recovery/SKILL.md +188 -0
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ This installs skills to `~/.agents/skills/` and symlinks them into `~/.claude/sk
|
|
|
27
27
|
| **Prompt Builder Coach** | `/estack-prompt-builder-coach` | Four-part kit for shaping, building, auditing, and scoping prompts for AI agents |
|
|
28
28
|
| **Read Claude Session History** | `/estack-read-claude-session-history` | Searches, reads, recovers, and compares Claude Code session history across sessions, projects, and backups |
|
|
29
29
|
| **Repo Search** | `/estack-repo-search` | Clones and searches external GitHub repos to answer questions about their code |
|
|
30
|
+
| **VS Code File Recovery** | `/estack-vscode-file-recovery` | Recovers permanently deleted files from VS Code or Cursor Local History, Claude session transcripts, or Windows Shadow Copies |
|
|
30
31
|
|
|
31
32
|
## Hooks
|
|
32
33
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: estack-vscode-file-recovery
|
|
3
|
+
version: 1.2.0
|
|
4
|
+
description: >
|
|
5
|
+
(vscode-file-recovery) Recover files that were permanently deleted (via rm, bash delete, or any method that bypasses the Recycle Bin) using VS Code's or Cursor's Local History snapshots, or from Claude session transcripts.
|
|
6
|
+
Use this skill immediately whenever: a file was deleted and git can't recover it (untracked or not committed), the user says "get it back", "restore that file", "I lost that file", "can you undo that delete", or any variation of wanting a deleted file recovered. Also use proactively after any rm or bash delete of files that weren't committed to git.
|
|
7
|
+
VS Code and Cursor silently save a snapshot every time you open or edit a file in the editor — this is often the only recovery path when git and Recycle Bin both fail.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# VS Code / Cursor File Recovery
|
|
11
|
+
|
|
12
|
+
When a file is deleted outside of git (with `rm`, bash, or any method that bypasses the Recycle Bin), this skill recovers it from editor Local History or Claude session transcripts.
|
|
13
|
+
|
|
14
|
+
## Recovery Sources — Try in Order
|
|
15
|
+
|
|
16
|
+
1. **Editor Local History** (VS Code or Cursor) — covered below
|
|
17
|
+
2. **Claude session transcript** — if Claude read the file in a prior session, its content may be in the JSONL. Use `/read-transcript` to search session history.
|
|
18
|
+
3. **Git** — only if the file was ever committed
|
|
19
|
+
4. **Cloud sync** (OneDrive, Dropbox) — check the cloud recycle bin / version history
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## How Editor Local History Works
|
|
24
|
+
|
|
25
|
+
VS Code and Cursor automatically save timestamped snapshots of every file opened in the editor. These live at:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
VS Code (Windows): C:\Users\[username]\AppData\Roaming\Code\User\History\
|
|
29
|
+
Cursor (Windows): C:\Users\[username]\AppData\Roaming\Cursor\User\History\
|
|
30
|
+
VS Code (Mac): ~/Library/Application Support/Code/User/History/
|
|
31
|
+
Cursor (Mac): ~/Library/Application Support/Cursor/User/History/
|
|
32
|
+
VS Code (Linux): ~/.config/Code/User/History/
|
|
33
|
+
Cursor (Linux): ~/.config/Cursor/User/History/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Each file gets a hash-named folder containing:
|
|
37
|
+
- `entries.json` — maps the original file path to snapshot IDs and timestamps
|
|
38
|
+
- `[id].[ext]` — the actual snapshot content (e.g., `dtgz.md`, `F9gm.txt`)
|
|
39
|
+
|
|
40
|
+
**Critical limitation:** VS Code only snapshots files that were actually *opened as a tab in the editor*. Files visible only in the sidebar Explorer are not captured.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Recovery Steps
|
|
45
|
+
|
|
46
|
+
### Step 1: Identify what to search for
|
|
47
|
+
|
|
48
|
+
Collect from the user (or from the deletion event):
|
|
49
|
+
- The filename (e.g., `Untitled-1.md`)
|
|
50
|
+
- The full path if known (e.g., `C:\Users\2supe\All Coding\akiflow-mcp\Untitled-1.md`)
|
|
51
|
+
- Any partial path segments (folder name, project name)
|
|
52
|
+
|
|
53
|
+
### Step 2: Search editor history for the file
|
|
54
|
+
|
|
55
|
+
Search `entries.json` files in both VS Code and Cursor History directories.
|
|
56
|
+
|
|
57
|
+
**Windows (PowerShell) — searches both editors:**
|
|
58
|
+
```powershell
|
|
59
|
+
@("Code", "Cursor") | ForEach-Object {
|
|
60
|
+
$histPath = "$env:APPDATA\$_\User\History"
|
|
61
|
+
if (Test-Path $histPath) {
|
|
62
|
+
Get-ChildItem $histPath -Recurse |
|
|
63
|
+
Where-Object { $_.Name -eq "entries.json" } |
|
|
64
|
+
ForEach-Object {
|
|
65
|
+
$content = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue
|
|
66
|
+
if ($content -like "*FILENAME_OR_PATH_PATTERN*") {
|
|
67
|
+
$_.FullName
|
|
68
|
+
$content
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Replace `FILENAME_OR_PATH_PATTERN` with the filename or path fragment. **Use `-like "*filename*"` rather than `-match "filename"` to avoid regex metacharacter issues** (`.`, `(`, `)`, `+` in filenames break `-match`).
|
|
76
|
+
|
|
77
|
+
If matching a full path, note that editors URL-encode it in `entries.json`: drive colons become `%3A`, backslashes become `/`, and spaces become `%20`. Example: `C:\Users\2supe\My App (v2).md` → `file:///c%3A/Users/2supe/My%20App%20%28v2%29.md`. **Searching by filename alone is simpler and usually sufficient.**
|
|
78
|
+
|
|
79
|
+
**Mac (bash) — searches both editors:**
|
|
80
|
+
```bash
|
|
81
|
+
for app in "Code" "Cursor"; do
|
|
82
|
+
grep -rl "FILENAME_OR_PATH_PATTERN" "$HOME/Library/Application Support/$app/User/History/" 2>/dev/null
|
|
83
|
+
done
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Step 3: Read the entries.json to find the latest snapshot
|
|
87
|
+
|
|
88
|
+
The `entries.json` looks like:
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"version": 1,
|
|
92
|
+
"resource": "file:///c%3A/Users/2supe/path/to/Untitled-1.md",
|
|
93
|
+
"entries": [
|
|
94
|
+
{"id": "F9gm.md", "source": "Workspace Edit", "timestamp": 1776196985353},
|
|
95
|
+
{"id": "U4ha.md", "source": "Workspace Edit", "timestamp": 1776197058059},
|
|
96
|
+
{"id": "dtgz.md", "source": "Workspace Edit", "timestamp": 1776197128275}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The **last entry** in the array is the most recent snapshot. Take its `id` field.
|
|
102
|
+
|
|
103
|
+
### Step 4: Read the snapshot content
|
|
104
|
+
|
|
105
|
+
```powershell
|
|
106
|
+
Get-Content "C:\Users\[username]\AppData\Roaming\Code\User\History\[hash-folder]\[id]"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or use the Read tool with the full path.
|
|
110
|
+
|
|
111
|
+
### Step 5: Restore the file
|
|
112
|
+
|
|
113
|
+
Write the content back to the original location using the Write tool.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## When Editor History Won't Help
|
|
118
|
+
|
|
119
|
+
- **File was never opened as an editor tab** — files only visible in the sidebar Explorer are not snapshotted.
|
|
120
|
+
- **History was cleared** — default retention is 30 days / 50 entries per file.
|
|
121
|
+
|
|
122
|
+
If editor history doesn't have the file, fall back to:
|
|
123
|
+
1. **`/read-transcript`** — if Claude read the file in a prior session, the content is in the session JSONL. Use `--mode search --query "filename"` to find it. Note: you need to point it at the right project's sessions — if the file lived in a different project folder, search that project's transcript directory instead.
|
|
124
|
+
2. **Windows Shadow Copies** (last resort, requires admin) — Windows VSS may have a snapshot of the volume. Check if any exist first:
|
|
125
|
+
```powershell
|
|
126
|
+
vssadmin list shadows
|
|
127
|
+
```
|
|
128
|
+
If a shadow copy exists, mount it and browse (**requires an elevated/admin shell**; the trailing backslash on the device path is required or `mklink` fails silently):
|
|
129
|
+
```powershell
|
|
130
|
+
cmd /c mklink /d C:\shadow \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\
|
|
131
|
+
```
|
|
132
|
+
Replace the device path with the one from `vssadmin list shadows`. Browse `C:\shadow\` like a normal drive to find and copy the file back. Clean up after: `cmd /c rmdir C:\shadow`.
|
|
133
|
+
3. **File recovery software** (Recuva on Windows) — only works if the disk blocks haven't been overwritten yet.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Example
|
|
138
|
+
|
|
139
|
+
**Scenario:** `rm` deleted `Untitled-1.md` which was untracked by git.
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
# Search
|
|
143
|
+
Get-ChildItem "$env:APPDATA\Code\User\History" -Recurse |
|
|
144
|
+
Where-Object { $_.Name -eq "entries.json" } |
|
|
145
|
+
ForEach-Object {
|
|
146
|
+
$content = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue
|
|
147
|
+
if ($content -like "*Untitled-1*") { $_.FullName; $content }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Result shows: C:\...\History\-6e228c75\entries.json
|
|
151
|
+
# entries.json has latest id: "dtgz.md"
|
|
152
|
+
|
|
153
|
+
# Read snapshot
|
|
154
|
+
Get-Content "C:\Users\2supe\AppData\Roaming\Code\User\History\-6e228c75\dtgz.md"
|
|
155
|
+
|
|
156
|
+
# Restore
|
|
157
|
+
# (Use Write tool to recreate the file at original path)
|
|
158
|
+
```
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Skill Feedback
|
|
162
|
+
|
|
163
|
+
If the user shares feedback about this skill — a bug, something confusing, a missing feature, or a suggestion — ask them to describe it in a bit more detail (what they expected, what happened, and any relevant context). Then file the issue using whichever method is available:
|
|
164
|
+
|
|
165
|
+
**If `gh` is installed** (`gh --version` succeeds), create the issue directly:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
gh issue create \
|
|
169
|
+
--repo ElliotDrel/e-stack \
|
|
170
|
+
--title "estack-vscode-file-recovery: <concise summary>" \
|
|
171
|
+
--body "<description from user feedback — expected vs. actual behavior and context>"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**If `gh` is not installed**, build a pre-filled URL:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
python3 -c "
|
|
178
|
+
import urllib.parse
|
|
179
|
+
title = 'estack-vscode-file-recovery: <concise summary>'
|
|
180
|
+
body = '<description from user feedback — expected vs. actual behavior and context>'
|
|
181
|
+
base = 'https://github.com/ElliotDrel/e-stack/issues/new'
|
|
182
|
+
print(base + '?title=' + urllib.parse.quote(title) + '&body=' + urllib.parse.quote(body))
|
|
183
|
+
"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Share the printed URL with the user and offer to open it in their browser.
|
|
187
|
+
|
|
188
|
+
They can also click it directly, review the pre-filled title and body, and click **Submit new issue**.
|