cursor-chat-cleaner 0.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 João Vilaça
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.
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: cursor-chat-cleaner
3
+ Version: 0.1.0
4
+ Summary: Find, back up, and delete Cursor chats on macOS
5
+ Author: João Vilaça
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/vilaca/cursor-chat-cleaner
8
+ Project-URL: Repository, https://github.com/vilaca/cursor-chat-cleaner
9
+ Project-URL: Issues, https://github.com/vilaca/cursor-chat-cleaner/issues
10
+ Project-URL: Security, https://github.com/vilaca/cursor-chat-cleaner/security
11
+ Keywords: chat-history,cleanup,backup,sqlite,macos
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: System :: Archiving :: Backup
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ # cursor-chat-cleaner
31
+
32
+ CLI to list, view, back up, and delete Cursor chats on macOS.
33
+
34
+ Requires **macOS** and **Python 3.10+**. No extra packages.
35
+
36
+ Tested with Cursor 3.17.21. Cursor's storage is an internal implementation
37
+ detail and may change between releases; destructive commands fail closed when
38
+ the required schema is not recognized.
39
+
40
+ This is an independent community project. It is not affiliated with or
41
+ endorsed by Anysphere.
42
+
43
+ ## Create the environment
44
+
45
+ From the repo root:
46
+
47
+ ```bash
48
+ python3 -m venv .venv
49
+ source .venv/bin/activate
50
+ python -m pip install -U pip
51
+ python -m pip install -e .
52
+ ```
53
+
54
+ Check it:
55
+
56
+ ```bash
57
+ cursor-chat-cleaner --help
58
+ ```
59
+
60
+ Later sessions:
61
+
62
+ ```bash
63
+ source .venv/bin/activate
64
+ ```
65
+
66
+ To leave the env: `deactivate`.
67
+
68
+ Without installing, you can run:
69
+
70
+ ```bash
71
+ PYTHONPATH=src python3 -m cursor_chat_cleaner --help
72
+ ```
73
+
74
+ ## Commands
75
+
76
+ `list` shows **archived** chats unless you pass `--all` or `--id`.
77
+
78
+ ```bash
79
+ cursor-chat-cleaner list
80
+ cursor-chat-cleaner list --all
81
+ cursor-chat-cleaner list --repo e1f --all
82
+ cursor-chat-cleaner list --id <composer-id>
83
+ cursor-chat-cleaner list --sort size
84
+ cursor-chat-cleaner list --sort title --reverse
85
+ cursor-chat-cleaner list --sort repo
86
+ cursor-chat-cleaner list --older-than 30
87
+ cursor-chat-cleaner --user-dir ~/Library/Application\ Support/Cursor\ Nightly/User list
88
+ cursor-chat-cleaner list --repos
89
+ cursor-chat-cleaner list --repos --all
90
+ cursor-chat-cleaner list --json
91
+ ```
92
+
93
+ `--sort` accepts `updated` (default, newest first), `created`, `size` (largest first), `title`, `repo`, or `workspace`. `--reverse` flips that default.
94
+
95
+ `stats` totals models, line churn, files, and context tokens (all chats unless `--archived`).
96
+
97
+ ```bash
98
+ cursor-chat-cleaner stats
99
+ cursor-chat-cleaner stats --repo e1f
100
+ cursor-chat-cleaner stats --archived
101
+ cursor-chat-cleaner stats --json
102
+ ```
103
+
104
+ `view` prints one chat (user/assistant text and compact tool lines). Thinking is hidden unless `--thinking`.
105
+
106
+ ```bash
107
+ cursor-chat-cleaner view <composer-id>
108
+ cursor-chat-cleaner view <composer-id> --thinking
109
+ cursor-chat-cleaner view <composer-id> --json
110
+ ```
111
+
112
+ `backup` writes a copy and leaves the original in place. It copies **archived** chats only, unless you pass `--id`, `--repo`, or `--all` (`--repo` includes active chats, same as `delete --repo`).
113
+
114
+ ```bash
115
+ cursor-chat-cleaner backup
116
+ cursor-chat-cleaner backup --id <composer-id> --dest ~/Desktop/chat-backup
117
+ cursor-chat-cleaner backup --repo e1f --dest ~/Desktop/e1f-chats
118
+ ```
119
+
120
+ `delete` removes **archived** chats only, unless you pass `--id` or `--repo` (those include active chats in the match). If the selection includes active chats, delete prints a warning before the dry-run or `--yes` step.
121
+
122
+ ```bash
123
+ cursor-chat-cleaner delete --dry-run
124
+ cursor-chat-cleaner delete --yes --backup
125
+ cursor-chat-cleaner delete --id <composer-id> --yes --backup ~/Desktop/chat-backup
126
+ cursor-chat-cleaner delete --repo e1f --dry-run
127
+ cursor-chat-cleaner delete --repo e1f --yes --backup
128
+ cursor-chat-cleaner delete --older-than 30 --yes --backup
129
+ ```
130
+
131
+ `--backup` without a path uses `~/cursor-chat-cleaner-backups/<timestamp>`. Each backup has `manifest.json`, `chats.sqlite`, optional `search.json`, and copied transcripts. Backup directories are restricted to the current user (`0700`); data files are written as `0600`.
132
+
133
+ Backups are archival snapshots for inspection and retention. This project does
134
+ not provide a restore command, and copying backup data into live Cursor storage
135
+ is unsupported.
136
+
137
+ `--vacuum` runs SQLite `VACUUM` after delete so the database file can shrink. That needs roughly as much free disk as the current DB size.
138
+
139
+ If the main delete succeeds but search-index or transcript cleanup fails, the error prints the pending chat IDs. Cleanup is idempotent, so it is safe to retry:
140
+
141
+ ```bash
142
+ cursor-chat-cleaner cleanup --id <composer-id>
143
+ cursor-chat-cleaner cleanup --id <composer-id> --yes
144
+ ```
145
+
146
+ ## Safety
147
+
148
+ - **Quit Cursor** before `--yes`. An open session can rewrite history after you delete.
149
+ - `--yes` is required to change anything. Without it, delete is a dry-run.
150
+ - `--force` deletes while Cursor is still running. History may come back.
151
+ - Cursor's process state is checked again immediately before the database write.
152
+ - Preview first: `list` / `view` / `delete --dry-run`.
153
+ - `delete` refuses to write if `state.vscdb` is missing `composerHeaders` (or its `isArchived` columns) or if `composer.composerHeaders.tableGateEnabled` is not true. App version is not used as the lock.
154
+
155
+ ## After a delete: Developer: GC Agent KV Blobs
156
+
157
+ Deleting a chat does **not** remove leftover hash-keyed rows in `state.vscdb`: `agentKv:blob:<hash>`, `composer.content.<hash>`, and `inlineDiff:<workspace>:<id>`. Those hold tool results, diffs, and other payloads keyed by hash, not by chat id, so they become orphans.
158
+
159
+ This tool cannot safely garbage-collect them. After Cursor is quit and delete finishes:
160
+
161
+ 1. Open Cursor.
162
+ 2. `Cmd+Shift+P`
163
+ 3. Run **Developer: GC Agent KV Blobs**
164
+
165
+ That command does not remove chats from the sidebar. It drops unreferenced `agentKv` blobs so `state.vscdb` can shrink. `composer.content` and `inlineDiff` rows may still remain.
166
+
167
+ ## Where chats live
168
+
169
+ | Location | What |
170
+ | --- | --- |
171
+ | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` | Chat headers, messages, checkpoints |
172
+ | `~/Library/Application Support/Cursor/User/globalStorage/conversation-search.db` | Search index |
173
+ | `~/Library/Application Support/Cursor/User/workspaceStorage/<id>/workspace.json` | Maps a workspace id to a folder (repo name) |
174
+ | `~/.cursor/projects/*/agent-transcripts/<composer-id>/` | Plain transcript files |
175
+
176
+ Do not delete `state.vscdb` as a file. That can break Cursor history.
177
+
178
+ ## Architecture
179
+
180
+ - `cli.py` owns command parsing, confirmation, and output.
181
+ - `store.py` orchestrates chat reads, backups, deletion, cleanup, and statistics.
182
+ - `schema.py` contains the version-sensitive Cursor table and key contract.
183
+ - `transcripts.py` is the containment boundary for transcript discovery, sizing, copying, and deletion.
184
+
185
+ ## Tests
186
+
187
+ ```bash
188
+ source .venv/bin/activate
189
+ PYTHONPATH=src python -m unittest discover -s tests -v
190
+ ```
191
+
192
+ The tests run against sanitized, schema-only snapshots from the documented
193
+ Cursor versions. These fixtures contain no chat content or other user data.
194
+
195
+ ## License
196
+
197
+ Licensed under the [MIT License](LICENSE).
@@ -0,0 +1,168 @@
1
+ # cursor-chat-cleaner
2
+
3
+ CLI to list, view, back up, and delete Cursor chats on macOS.
4
+
5
+ Requires **macOS** and **Python 3.10+**. No extra packages.
6
+
7
+ Tested with Cursor 3.17.21. Cursor's storage is an internal implementation
8
+ detail and may change between releases; destructive commands fail closed when
9
+ the required schema is not recognized.
10
+
11
+ This is an independent community project. It is not affiliated with or
12
+ endorsed by Anysphere.
13
+
14
+ ## Create the environment
15
+
16
+ From the repo root:
17
+
18
+ ```bash
19
+ python3 -m venv .venv
20
+ source .venv/bin/activate
21
+ python -m pip install -U pip
22
+ python -m pip install -e .
23
+ ```
24
+
25
+ Check it:
26
+
27
+ ```bash
28
+ cursor-chat-cleaner --help
29
+ ```
30
+
31
+ Later sessions:
32
+
33
+ ```bash
34
+ source .venv/bin/activate
35
+ ```
36
+
37
+ To leave the env: `deactivate`.
38
+
39
+ Without installing, you can run:
40
+
41
+ ```bash
42
+ PYTHONPATH=src python3 -m cursor_chat_cleaner --help
43
+ ```
44
+
45
+ ## Commands
46
+
47
+ `list` shows **archived** chats unless you pass `--all` or `--id`.
48
+
49
+ ```bash
50
+ cursor-chat-cleaner list
51
+ cursor-chat-cleaner list --all
52
+ cursor-chat-cleaner list --repo e1f --all
53
+ cursor-chat-cleaner list --id <composer-id>
54
+ cursor-chat-cleaner list --sort size
55
+ cursor-chat-cleaner list --sort title --reverse
56
+ cursor-chat-cleaner list --sort repo
57
+ cursor-chat-cleaner list --older-than 30
58
+ cursor-chat-cleaner --user-dir ~/Library/Application\ Support/Cursor\ Nightly/User list
59
+ cursor-chat-cleaner list --repos
60
+ cursor-chat-cleaner list --repos --all
61
+ cursor-chat-cleaner list --json
62
+ ```
63
+
64
+ `--sort` accepts `updated` (default, newest first), `created`, `size` (largest first), `title`, `repo`, or `workspace`. `--reverse` flips that default.
65
+
66
+ `stats` totals models, line churn, files, and context tokens (all chats unless `--archived`).
67
+
68
+ ```bash
69
+ cursor-chat-cleaner stats
70
+ cursor-chat-cleaner stats --repo e1f
71
+ cursor-chat-cleaner stats --archived
72
+ cursor-chat-cleaner stats --json
73
+ ```
74
+
75
+ `view` prints one chat (user/assistant text and compact tool lines). Thinking is hidden unless `--thinking`.
76
+
77
+ ```bash
78
+ cursor-chat-cleaner view <composer-id>
79
+ cursor-chat-cleaner view <composer-id> --thinking
80
+ cursor-chat-cleaner view <composer-id> --json
81
+ ```
82
+
83
+ `backup` writes a copy and leaves the original in place. It copies **archived** chats only, unless you pass `--id`, `--repo`, or `--all` (`--repo` includes active chats, same as `delete --repo`).
84
+
85
+ ```bash
86
+ cursor-chat-cleaner backup
87
+ cursor-chat-cleaner backup --id <composer-id> --dest ~/Desktop/chat-backup
88
+ cursor-chat-cleaner backup --repo e1f --dest ~/Desktop/e1f-chats
89
+ ```
90
+
91
+ `delete` removes **archived** chats only, unless you pass `--id` or `--repo` (those include active chats in the match). If the selection includes active chats, delete prints a warning before the dry-run or `--yes` step.
92
+
93
+ ```bash
94
+ cursor-chat-cleaner delete --dry-run
95
+ cursor-chat-cleaner delete --yes --backup
96
+ cursor-chat-cleaner delete --id <composer-id> --yes --backup ~/Desktop/chat-backup
97
+ cursor-chat-cleaner delete --repo e1f --dry-run
98
+ cursor-chat-cleaner delete --repo e1f --yes --backup
99
+ cursor-chat-cleaner delete --older-than 30 --yes --backup
100
+ ```
101
+
102
+ `--backup` without a path uses `~/cursor-chat-cleaner-backups/<timestamp>`. Each backup has `manifest.json`, `chats.sqlite`, optional `search.json`, and copied transcripts. Backup directories are restricted to the current user (`0700`); data files are written as `0600`.
103
+
104
+ Backups are archival snapshots for inspection and retention. This project does
105
+ not provide a restore command, and copying backup data into live Cursor storage
106
+ is unsupported.
107
+
108
+ `--vacuum` runs SQLite `VACUUM` after delete so the database file can shrink. That needs roughly as much free disk as the current DB size.
109
+
110
+ If the main delete succeeds but search-index or transcript cleanup fails, the error prints the pending chat IDs. Cleanup is idempotent, so it is safe to retry:
111
+
112
+ ```bash
113
+ cursor-chat-cleaner cleanup --id <composer-id>
114
+ cursor-chat-cleaner cleanup --id <composer-id> --yes
115
+ ```
116
+
117
+ ## Safety
118
+
119
+ - **Quit Cursor** before `--yes`. An open session can rewrite history after you delete.
120
+ - `--yes` is required to change anything. Without it, delete is a dry-run.
121
+ - `--force` deletes while Cursor is still running. History may come back.
122
+ - Cursor's process state is checked again immediately before the database write.
123
+ - Preview first: `list` / `view` / `delete --dry-run`.
124
+ - `delete` refuses to write if `state.vscdb` is missing `composerHeaders` (or its `isArchived` columns) or if `composer.composerHeaders.tableGateEnabled` is not true. App version is not used as the lock.
125
+
126
+ ## After a delete: Developer: GC Agent KV Blobs
127
+
128
+ Deleting a chat does **not** remove leftover hash-keyed rows in `state.vscdb`: `agentKv:blob:<hash>`, `composer.content.<hash>`, and `inlineDiff:<workspace>:<id>`. Those hold tool results, diffs, and other payloads keyed by hash, not by chat id, so they become orphans.
129
+
130
+ This tool cannot safely garbage-collect them. After Cursor is quit and delete finishes:
131
+
132
+ 1. Open Cursor.
133
+ 2. `Cmd+Shift+P`
134
+ 3. Run **Developer: GC Agent KV Blobs**
135
+
136
+ That command does not remove chats from the sidebar. It drops unreferenced `agentKv` blobs so `state.vscdb` can shrink. `composer.content` and `inlineDiff` rows may still remain.
137
+
138
+ ## Where chats live
139
+
140
+ | Location | What |
141
+ | --- | --- |
142
+ | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` | Chat headers, messages, checkpoints |
143
+ | `~/Library/Application Support/Cursor/User/globalStorage/conversation-search.db` | Search index |
144
+ | `~/Library/Application Support/Cursor/User/workspaceStorage/<id>/workspace.json` | Maps a workspace id to a folder (repo name) |
145
+ | `~/.cursor/projects/*/agent-transcripts/<composer-id>/` | Plain transcript files |
146
+
147
+ Do not delete `state.vscdb` as a file. That can break Cursor history.
148
+
149
+ ## Architecture
150
+
151
+ - `cli.py` owns command parsing, confirmation, and output.
152
+ - `store.py` orchestrates chat reads, backups, deletion, cleanup, and statistics.
153
+ - `schema.py` contains the version-sensitive Cursor table and key contract.
154
+ - `transcripts.py` is the containment boundary for transcript discovery, sizing, copying, and deletion.
155
+
156
+ ## Tests
157
+
158
+ ```bash
159
+ source .venv/bin/activate
160
+ PYTHONPATH=src python -m unittest discover -s tests -v
161
+ ```
162
+
163
+ The tests run against sanitized, schema-only snapshots from the documented
164
+ Cursor versions. These fixtures contain no chat content or other user data.
165
+
166
+ ## License
167
+
168
+ Licensed under the [MIT License](LICENSE).
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cursor-chat-cleaner"
7
+ version = "0.1.0"
8
+ description = "Find, back up, and delete Cursor chats on macOS"
9
+ authors = [{ name = "João Vilaça" }]
10
+ readme = "README.md"
11
+ requires-python = ">=3.10"
12
+ license = "MIT"
13
+ license-files = ["LICENSE"]
14
+ keywords = ["chat-history", "cleanup", "backup", "sqlite", "macos"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: MacOS",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3 :: Only",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
27
+ "Topic :: System :: Archiving :: Backup",
28
+ "Topic :: Utilities",
29
+ ]
30
+
31
+ [project.scripts]
32
+ cursor-chat-cleaner = "cursor_chat_cleaner.cli:main"
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/vilaca/cursor-chat-cleaner"
36
+ Repository = "https://github.com/vilaca/cursor-chat-cleaner"
37
+ Issues = "https://github.com/vilaca/cursor-chat-cleaner/issues"
38
+ Security = "https://github.com/vilaca/cursor-chat-cleaner/security"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from cursor_chat_cleaner.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())