Skip to content

Instantly share code, notes, and snippets.

@lushkovsky-s
Last active May 10, 2025 19:52
Show Gist options
  • Save lushkovsky-s/a336000fb9fcf934af4c852893617321 to your computer and use it in GitHub Desktop.
Save lushkovsky-s/a336000fb9fcf934af4c852893617321 to your computer and use it in GitHub Desktop.
Dump Cursor notepads as JSON (Mac version)
WORKSPACE_ID=$(./get_cursor_workspace_id.sh <path>) sqlite3 "$HOME/Library/Application Support/Cursor/User/workspaceStorage/$WORKSPACE_ID/st
ate.vscdb" "SELECT value FROM ItemTable WHERE key = 'notepad.reactiveStorageId';" | python3 -c "import sys, json; pri
nt(json.dumps(json.loads(sys.stdin.read()), indent=2))" 2>/dev/null | jq '.notepads | to_entries[] | .value | {name:
.name, content: .text} '
# get_cursor_workspace_id.sh - Get Cursor workspace ID for a given path
# Check if path argument is provided
if [ $# -ne 1 ]; then
echo "Usage: 0 USD /path/to/workspace" >&2
exit 1
fi
# Normalize input path (remove trailing slash)
SEARCH_PATH="${1%/}"
# Expand tilde in path
if [[ "$SEARCH_PATH" == "~"* ]]; then
SEARCH_PATH="${SEARCH_PATH/#\~/$HOME}"
fi
# Look for workspace folders in Cursor storage
CURSOR_STORAGE_DIR="$HOME/Library/Application Support/Cursor/User/workspaceStorage"
# Try alternative location if not found
if [ ! -d "$CURSOR_STORAGE_DIR" ]; then
CURSOR_STORAGE_DIR="$HOME/Library/Application Support/Cursor/workspaceStorage"
if [ ! -d "$CURSOR_STORAGE_DIR" ]; then
echo "Error: Cursor workspace storage not found" >&2
exit 1
fi
fi
# Find workspace ID for the specified path
for dir in "$CURSOR_STORAGE_DIR"/*; do
if [ ! -d "$dir" ]; then
continue
fi
dir_id=$(basename "$dir")
# Check if workspace.json exists and extract folder path
if [ -f "$dir/workspace.json" ]; then
folder_path=$(grep -o '"folder":[^,]*' "$dir/workspace.json" 2>/dev/null | sed 's/"folder": "file:\/\/\///g' | sed 's/"//g')
if [ -n "$folder_path" ]; then
# Add leading slash if needed
if [[ $folder_path == Users/* ]]; then
folder_path="/$folder_path"
fi
# Remove trailing slash
folder_path="${folder_path%/}"
# Check for exact path match
if [ "$folder_path" = "$SEARCH_PATH" ]; then
echo "$dir_id"
exit 0
fi
fi
fi
done
# No workspace found
echo "Error: No workspace found for path: $SEARCH_PATH" >&2
exit 1
#!/bin/bash
# Validate platform
[[ "$(uname)" != "Darwin" ]] && echo "❌ macOS only" && exit 1
# Check dependencies
for bin in sqlite3 jq python3 realpath; do
command -v "$bin" >/dev/null || { echo "❌ Missing: $bin"; exit 1; }
done
# Usage
if [ $# -lt 2 ]; then
echo "Usage: migrate_cursor_notepads.sh /from/workspace /to/workspace [--dry-run]" >&2
exit 1
fi
FROM="$(realpath "${1%/}")"
TO="$(realpath "${2%/}")"
DRY_RUN=0 && [[ "$3" == "--dry-run" ]] && DRY_RUN=1
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Resolve workspace IDs
SRC_ID=$("$SCRIPT_DIR/get_cursor_workspace_id.sh" "$FROM") || exit 1
DST_ID=$("$SCRIPT_DIR/get_cursor_workspace_id.sh" "$TO") || exit 1
SRC_DB="$HOME/Library/Application Support/Cursor/User/workspaceStorage/$SRC_ID/state.vscdb"
DST_DB="$HOME/Library/Application Support/Cursor/User/workspaceStorage/$DST_ID/state.vscdb"
# Backup
BACKUP_DIR="$HOME/.cursor_backups"
mkdir -p "$BACKUP_DIR"
TS=$(date +"%Y%m%d-%H%M%S")
cp "$DST_DB" "$BACKUP_DIR/state.vscdb.bak.$DST_ID.$TS" || { echo "❌ Backup failed"; exit 1; }
# Extract notepads
RAW=$(sqlite3 "$SRC_DB" "SELECT value FROM ItemTable WHERE key = 'notepad.reactiveStorageId';")
[[ -z "$RAW" ]] && echo "⚠️ No notepads found in source" && exit 1
# Dry-run mode
if [ "$DRY_RUN" -eq 1 ]; then
echo "🧪 Dry-run only — showing source notepads:"
echo "$RAW" | jq '.notepads | to_entries[] | .value | {name: .name, text: (.text[0:60] + "...")}'
exit 0
fi
# Serialize JSON safely for SQLite
ESCAPED_JSON=$(python3 -c 'import sys, json; print(json.dumps(sys.stdin.read()))' <<< "$RAW")
# Replace or insert key safely
KEY_EXISTS=$(sqlite3 "$DST_DB" "SELECT 1 FROM ItemTable WHERE key = 'notepad.reactiveStorageId';")
if [[ "$KEY_EXISTS" == "1" ]]; then
sqlite3 "$DST_DB" "UPDATE ItemTable SET value = $ESCAPED_JSON WHERE key = 'notepad.reactiveStorageId';"
else
sqlite3 "$DST_DB" "INSERT INTO ItemTable (key, value) VALUES ('notepad.reactiveStorageId', $ESCAPED_JSON);"
fi
[[ $? -eq 0 ]] && echo "✅ Migration complete. Backup: $BACKUP_DIR/state.vscdb.bak.$DST_ID.$TS" || echo "❌ DB write failed"
@lushkovsky-s
Copy link
Author

Hey @devidw
Sorry to hear that, ig it's related to the latest cursor updates
Could you share the .vscdb file from your workspace ($HOME/Library/Application Support/Cursor/User/workspaceStorage/$WORKSPACE_ID/state.vscdb)?

@devidw
Copy link

devidw commented May 10, 2025

ah sry i didn't see this earlier, i made by deal with the lost notes, but much appreciated @lushkovsky-s <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment