Skip to content

Instantly share code, notes, and snippets.

@Manojbhat09
Created April 14, 2025 08:56
Show Gist options
  • Save Manojbhat09/a71ee0774d166d9e02fb49bb6d95b48d to your computer and use it in GitHub Desktop.
Save Manojbhat09/a71ee0774d166d9e02fb49bb6d95b48d to your computer and use it in GitHub Desktop.
Cursor SQLite Data Extractor: Windows Conversations and Prompts. Python scripts to scan SQLite database files (`state.vscdb` and `state.vscdb.backup`) used by Cursor for extracting conversation history and text-based prompts. If conversation data is not available, the scripts fall back to extracting prompts (e.g., `textDescription` fields). Outp…
#!/usr/bin/env python3
# wsl
import sqlite3
import json
from pathlib import Path
from datetime import datetime
# path to WorkspaceStorage on Windows or any paths with folders and state.vscdb inside
ENTRY_PATH="/mnt/c/Users/manoj/AppData/Roaming/Cursor/User/workspaceStorage"
def extract_conversations(cursor, table_name):
"""
Try to extract conversation data from the specified table.
Looks for dicts containing 'conversation' fields.
"""
print(f" Searching for conversations in table '{table_name}'...")
conversations = []
try:
cursor.execute(f"SELECT key, value FROM {table_name} LIMIT 1000;")
rows = cursor.fetchall()
for key, value in rows:
try:
# Decode value if it's a BLOB
if isinstance(value, bytes):
value = value.decode('utf-8')
# Attempt to parse JSON
parsed = json.loads(value) if value else None
# Check for conversation-like data
if isinstance(parsed, dict) and 'conversation' in parsed:
conversations.append({'key': key, 'conversation': parsed['conversation']})
except:
# Ignore malformed rows
pass
except Exception as e:
print(f" Error extracting conversations from '{table_name}': {e}")
return conversations
def extract_prompts(cursor, table_name):
"""
Try to extract prompts using the 'textDescription' field or related data from the specified table.
"""
print(f" Searching for prompts in table '{table_name}'...")
prompts = []
try:
cursor.execute(f"SELECT key, value FROM {table_name} LIMIT 1000;")
rows = cursor.fetchall()
for key, value in rows:
try:
# Decode value if it's a BLOB
if isinstance(value, bytes):
value = value.decode('utf-8')
# Attempt to parse JSON
parsed = json.loads(value) if value else None
# Look for prompts in known fields
if isinstance(parsed, list):
for item in parsed:
if isinstance(item, dict) and 'textDescription' in item:
prompts.append(item['textDescription'])
elif isinstance(parsed, dict) and 'textDescription' in parsed:
prompts.append(parsed['textDescription'])
except:
# Ignore malformed rows
pass
except Exception as e:
print(f" Error extracting prompts from '{table_name}': {e}")
return prompts
def scan_database(db_path):
"""
Scan a single SQLite database for conversations and prompts.
"""
print(f"\nScanning database: {db_path}")
conversations = []
prompts = []
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# List all tables in the database
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = cursor.fetchall()
for table_name, in tables:
# Attempt to extract conversations
conversations.extend(extract_conversations(cursor, table_name))
# Attempt to extract prompts
prompts.extend(extract_prompts(cursor, table_name))
conn.close()
except Exception as e:
print(f" Error scanning database {db_path}: {e}")
return conversations, prompts
def save_to_markdown(output_file, conversations, prompts):
"""
Save conversations and prompts to a Markdown file.
"""
with open(output_file, 'a', encoding='utf-8') as f:
if conversations:
f.write("# Conversations\n")
for conv in conversations:
f.write(f"## Key: {conv['key']}\n")
for message in conv['conversation']:
sender = "User" if message.get('type') == 1 else "Assistant"
text = message.get('text', '').strip()
f.write(f"**{sender}**: {text}\n")
f.write("\n---\n")
else:
f.write("# No conversations found.\n")
if prompts:
f.write("\n# Prompts\n")
for i, prompt in enumerate(prompts, 1):
f.write(f"{i}. {prompt.strip()}\n")
def scan_directory(base_path):
"""
Scan all SQLite databases in the directory and subdirectories for conversation and prompt data.
"""
base_path = Path(base_path)
print(f"Scanning directory: {base_path}")
if not base_path.exists():
print(f"Directory does not exist: {base_path}")
return
# Prepare an output Markdown file
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
output_file = output_dir / f"conversations_and_prompts_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
db_files = list(base_path.rglob("state.vscdb")) + list(base_path.rglob("state.vscdb.backup"))
if not db_files:
print("No database files found.")
return
print(f"Found {len(db_files)} database files.")
for db_file in db_files:
conversations, prompts = scan_database(db_file)
save_to_markdown(output_file, conversations, prompts)
print(f"\nData extraction completed! Results saved to {output_file}")
def main():
"""
Main function to scan a directory and extract conversations and prompts.
"""
# Update this path to your workspaceStorage directory
base_path = Path(ENTRY_PATH)
scan_directory(base_path)
if __name__ == "__main__":
main()
'''
Output looks like this:
(base) mbhat@manoj:~/cursor-stuff$ cat output/conversations_and_prompts_20250414_014537.md
# No conversations found.
# No conversations found.
# No conversations found.
# No conversations found.
# Prompts
1. write code to make a cybersecurity software
2. write code to make a cybersecurity software
3. write code to make a cybersecurity software
4. write code to make a cybersecurity software
5. write code for a simple cybersecurity software run using C++ backend
6. CMakeLists.txt
7. file_monitor.h
8. process_monitor.h
9. network_monitor.h
10. file_monitor.cpp
11. process_monitor.cpp
12. network_monitor.cpp
13. main.cpp
14. README.md
# No conversations found.
# Prompts
1. Create a website frontend that can use the repo as a service on a different server while the client requests it for 3D file from the input image on the frontend and the server creates it and sends the data to the client. I want to host it myself and be able to use it on mobile and any type of device to take pictures of objects around me from the camera of the system and use it to create 3D objects and save it as .fbx file or one that can be used on any convinent viewer. Also on the frontend there should be space to view the 3D file using threejs. Meaning from image to 3d object that the user can place it on a threejs scene
# No conversations found.
# No conversations found.
# No conversations found.
# Prompts
1. what is needed to do to install this on chrome ?
2. what is needed to do to install this on chrome ?
3. what is needed to do to install this on chrome ?
4. I need to modify the files so as to make it work with "Load unpacked" option
# No conversations found.
# No conversations found.
'''
#!/usr/bin/env python3
#wsl
import sqlite3
import json
from pathlib import Path
import os
# path to WorkspaceStorage on Windows or any paths with folders and state.vscdb inside
ENTRY_PATH="/mnt/c/Users/manoj/AppData/Roaming/Cursor/User/workspaceStorage"
def inspect_table(cursor, table_name):
"""
Inspect a table and search for any conversation-like data.
Prints out potential matches.
"""
print(f"Inspecting table: {table_name}")
try:
# Fetch a sample of rows
cursor.execute(f"SELECT key, value FROM {table_name} LIMIT 100;")
rows = cursor.fetchall()
print(f" Found {len(rows)} rows in table '{table_name}'.")
for key, value in rows:
# Attempt to decode the value
try:
if isinstance(value, bytes):
# Attempt to decode if the value is a BLOB
value = value.decode('utf-8')
# Try parsing as JSON
parsed = json.loads(value) if isinstance(value, str) else None
# Check for conversation-like data
if isinstance(parsed, dict) and ('conversation' in parsed or 'messages' in parsed):
print(f" Potential conversation found for key '{key}':")
print(json.dumps(parsed, indent=2))
elif isinstance(parsed, list) and all(isinstance(item, dict) for item in parsed):
print(f" Potential list of conversations/messages found for key '{key}':")
print(json.dumps(parsed[:2], indent=2)) # Show a sample of 2 items
except Exception as e:
# If decoding fails, just skip
continue
except Exception as e:
print(f" Error inspecting table '{table_name}': {e}")
def scan_database(db_path):
"""
Scan a single SQLite database for tables and search for conversation data.
"""
print(f"\nScanning database: {db_path}")
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# List all tables in the database
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = cursor.fetchall()
if not tables:
print(" No tables found in the database.")
return
print(f" Found tables: {[t[0] for t in tables]}")
# Inspect each table for potential conversation data
for table_name, in tables:
inspect_table(cursor, table_name)
conn.close()
except Exception as e:
print(f" Error scanning database {db_path}: {e}")
def scan_directory(base_path):
"""
Scan all `state.vscdb` and `state.vscdb.backup` files in a directory and subdirectories.
"""
base_path = Path(base_path)
print(f"Scanning directory: {base_path}")
if not base_path.exists():
print(f"Directory does not exist: {base_path}")
return
# Find all files named `state.vscdb` or `state.vscdb.backup`
db_files = list(base_path.rglob("state.vscdb")) + list(base_path.rglob("state.vscdb.backup"))
if not db_files:
print(f"No database files found in {base_path}.")
return
print(f"Found {len(db_files)} database files.")
for db_file in db_files:
scan_database(db_file)
def main():
"""
Main function to scan a directory for conversation-like data in SQLite databases.
"""
# Update this path to your `workspaceStorage` directory
base_path = Path(ENTRY_PATH)
scan_directory(base_path)
if __name__ == "__main__":
main()
'''
THe output is like this:
(base) mbhat@manoj:~/cursor-stuff$ python scan_conversation_data.py
Scanning directory: /mnt/c/Users/manoj/AppData/Roaming/Cursor/User/workspaceStorage
Found 17 database files.
Scanning database: /mnt/c/Users/manoj/AppData/Roaming/Cursor/User/workspaceStorage/0d3805e2acc52ab98013bbe30bcc4cdb/state.vscdb
Found tables: ['ItemTable', 'cursorDiskKV']
Inspecting table: ItemTable
Found 55 rows in table 'ItemTable'.
Potential list of conversations/messages found for key 'workbench.auxiliarybar.viewContainersWorkspaceState':
[
{
"id": "workbench.panel.aichat",
"visible": true
},
{
"id": "workbench.panel.composerViewPane2",
"visible": false
}
]
Potential list of conversations/messages found for key 'aiService.generations':
[]
Potential list of conversations/messages found for key 'aiService.prompts':
[]
Potential list of conversations/messages found for key 'history.entries':
[]
Potential list of conversations/messages found for key 'interactive.sessions':
[]
Potential list of conversations/messages found for key 'comments.continueOnComments':
[]
Potential list of conversations/messages found for key 'chat.editing.autosaveDisabled':
[]
Potential list of conversations/messages found for key 'workbench.panel.viewContainersWorkspaceState':
[
{
"id": "workbench.panel.markers",
"visible": true
},
{
"id": "workbench.panel.output",
"visible": true
}
]
Potential list of conversations/messages found for key 'terminal.integrated.environmentVariableCollectionsV2':
[
{
"extensionIdentifier": "vscode.git",
"collection": [
[
"GIT_ASKPASS",
{
"variable": "GIT_ASKPASS",
"value": "c:\\Users\\manoj\\AppData\\Local\\Programs\\cursor\\resources\\app\\extensions\\git\\dist\\askpass.sh",
"type": 1,
"options": {
"applyAtProcessCreation": true,
"applyAtShellIntegration": false
}
}
],
[
"VSCODE_GIT_ASKPASS_NODE",
{
"variable": "VSCODE_GIT_ASKPASS_NODE",
"value": "C:\\Users\\manoj\\AppData\\Local\\Programs\\cursor\\Cursor.exe",
"type": 1,
"options": {
"applyAtProcessCreation": true,
"applyAtShellIntegration": false
}
}
],
[
"VSCODE_GIT_ASKPASS_EXTRA_ARGS",
{
"variable": "VSCODE_GIT_ASKPASS_EXTRA_ARGS",
"value": "",
"type": 1,
"options": {
"applyAtProcessCreation": true,
"applyAtShellIntegration": false
}
}
],
[
"VSCODE_GIT_ASKPASS_MAIN",
{
"variable": "VSCODE_GIT_ASKPASS_MAIN",
"value": "c:\\Users\\manoj\\AppData\\Local\\Programs\\cursor\\resources\\app\\extensions\\git\\dist\\askpass-main.js",
"type": 1,
"options": {
"applyAtProcessCreation": true,
"applyAtShellIntegration": false
}
}
],
[
"VSCODE_GIT_IPC_HANDLE",
{
"variable": "VSCODE_GIT_IPC_HANDLE",
"value": "\\\\.\\pipe\\vscode-git-d8efc8ddbb-sock",
"type": 1,
"options": {
"applyAtProcessCreation": true,
"applyAtShellIntegration": false
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment