cursor-chat-recovery 0.2.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.
- cursor_chat_recovery-0.2.0/.github/workflows/ci.yml +16 -0
- cursor_chat_recovery-0.2.0/.gitignore +13 -0
- cursor_chat_recovery-0.2.0/LICENSE +21 -0
- cursor_chat_recovery-0.2.0/PKG-INFO +124 -0
- cursor_chat_recovery-0.2.0/README.md +114 -0
- cursor_chat_recovery-0.2.0/docs/superpowers/plans/2026-05-27-cursor-chat-tool.md +2989 -0
- cursor_chat_recovery-0.2.0/docs/superpowers/plans/2026-06-11-tui-performance-ux.md +1488 -0
- cursor_chat_recovery-0.2.0/docs/superpowers/specs/2026-05-27-cursor-chat-tool-design.md +381 -0
- cursor_chat_recovery-0.2.0/docs/superpowers/specs/2026-06-11-tui-performance-ux-design.md +159 -0
- cursor_chat_recovery-0.2.0/pyproject.toml +45 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/__init__.py +0 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/cli.py +150 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/model.py +85 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/operations.py +326 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/paths.py +61 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/schema.py +99 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/storage.py +192 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/__init__.py +0 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/actions.py +54 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/app.py +342 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/dialogs.py +369 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/filtering.py +40 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/loading.py +56 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/screen_chats.py +184 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/screen_messages.py +138 -0
- cursor_chat_recovery-0.2.0/src/cursor_chat_recovery/tui/screen_workspaces.py +211 -0
- cursor_chat_recovery-0.2.0/tests/__init__.py +0 -0
- cursor_chat_recovery-0.2.0/tests/conftest.py +25 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/__init__.py +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/globalStorage_corrupt.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/globalStorage_minimal.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/globalStorage_schema_drift.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/make_fixture.py +158 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/workspaceStorage/ws-alpha/state.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/workspaceStorage/ws-beta/obsolete +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/workspaceStorage/ws-beta/state.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/workspaceStorage/ws-delta/state.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/workspaceStorage/ws-epsilon/state.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/fixtures/workspaceStorage/ws-remote/state.vscdb +0 -0
- cursor_chat_recovery-0.2.0/tests/test_cli.py +56 -0
- cursor_chat_recovery-0.2.0/tests/test_operations.py +199 -0
- cursor_chat_recovery-0.2.0/tests/test_paths.py +37 -0
- cursor_chat_recovery-0.2.0/tests/test_schema.py +38 -0
- cursor_chat_recovery-0.2.0/tests/test_storage.py +166 -0
- cursor_chat_recovery-0.2.0/tests/test_tui_smoke.py +553 -0
- cursor_chat_recovery-0.2.0/uv.lock +432 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
strategy:
|
|
7
|
+
matrix:
|
|
8
|
+
python: ["3.10", "3.11", "3.12"]
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v4
|
|
11
|
+
- uses: astral-sh/setup-uv@v3
|
|
12
|
+
- run: uv python install ${{ matrix.python }}
|
|
13
|
+
- run: uv sync --dev
|
|
14
|
+
- run: uv run pytest
|
|
15
|
+
- run: uv run ruff check
|
|
16
|
+
- run: uv run mypy src/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kuba Kwiecien
|
|
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,124 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cursor-chat-recovery
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Inventory, view, reassign, and export Cursor chats
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: prompt-toolkit>=3.0.43
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# cursor-chat-recovery
|
|
12
|
+
|
|
13
|
+
[](https://github.com/kwiscion/cursor-chat-recovery/actions/workflows/ci.yml)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
[](pyproject.toml)
|
|
16
|
+
|
|
17
|
+
Did your Cursor chats disappear after you moved, renamed, or re-opened a project? They're not gone. This is an interactive terminal UI to **recover, browse, move, and export Cursor AI chat history** — across all your projects.
|
|
18
|
+
|
|
19
|
+
## Why chats "disappear"
|
|
20
|
+
|
|
21
|
+
Cursor identifies each workspace by a hash of its identifier URI. Reopening a project from a different path, or saving an Untitled multi-folder workspace as a `.code-workspace` file, mints a new workspace identity and detaches all prior chats from the sidebar. The conversations are still in `globalStorage/state.vscdb` keyed by `composerId` — they just need their `workspaceIdentifier` rewritten to point at the new workspace. That's what this tool does, with backups at every step.
|
|
22
|
+
|
|
23
|
+
It's also useful when nothing is broken: browse every chat you've ever had in any project, move chats between workspaces, and export conversations to Markdown.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
Requires Python 3.10+. With [uv](https://docs.astral.sh/uv/):
|
|
28
|
+
|
|
29
|
+
uv tool install git+https://github.com/kwiscion/cursor-chat-recovery
|
|
30
|
+
|
|
31
|
+
or with pipx:
|
|
32
|
+
|
|
33
|
+
pipx install git+https://github.com/kwiscion/cursor-chat-recovery
|
|
34
|
+
|
|
35
|
+
Both install the `cursor-chat-recovery` executable (and a short alias, `ccr`).
|
|
36
|
+
After `uv tool install`, ensure `~/.local/bin` is on your PATH (run `uv tool update-shell` once if needed).
|
|
37
|
+
|
|
38
|
+
To run from a clone without installing: `uv run cursor-chat-recovery`.
|
|
39
|
+
|
|
40
|
+
## Use
|
|
41
|
+
|
|
42
|
+
cursor-chat-recovery # interactive TUI (or: ccr)
|
|
43
|
+
cursor-chat-recovery --readonly # TUI with mutations disabled
|
|
44
|
+
cursor-chat-recovery --list # workspaces table to stdout
|
|
45
|
+
cursor-chat-recovery --list --json
|
|
46
|
+
cursor-chat-recovery --export <COMPOSER_ID> --format markdown -o chat.md
|
|
47
|
+
cursor-chat-recovery --reassign <COMPOSER_IDS,COMMA,SEP> <TARGET_WS_ID> --yes
|
|
48
|
+
cursor-chat-recovery --merge <SRC_WS_ID> <TARGET_WS_ID> --yes
|
|
49
|
+
|
|
50
|
+
Close Cursor before any mutation. The tool refuses to write while Cursor is running.
|
|
51
|
+
|
|
52
|
+
## Keys
|
|
53
|
+
|
|
54
|
+
### Global
|
|
55
|
+
|
|
56
|
+
| Key | Action |
|
|
57
|
+
|-----|--------|
|
|
58
|
+
| `?` | Open help screen |
|
|
59
|
+
| `q` | Quit |
|
|
60
|
+
| `esc` | Back / cancel (clears an active filter first) |
|
|
61
|
+
| `ctrl-c` | Force quit |
|
|
62
|
+
|
|
63
|
+
### Workspaces (project list)
|
|
64
|
+
|
|
65
|
+
| Key | Action |
|
|
66
|
+
|-----|--------|
|
|
67
|
+
| `up` / `down` | Move selection |
|
|
68
|
+
| `pgup` / `pgdn` | Page up / down |
|
|
69
|
+
| `home` / `end` | Jump to first / last |
|
|
70
|
+
| `enter` | Open workspace's chats |
|
|
71
|
+
| `s` | Cycle sort order (last activity → chat count → name → health) |
|
|
72
|
+
| `/` | Filter by name or path (`enter` keeps filter, `esc` clears) |
|
|
73
|
+
|
|
74
|
+
### Chats (within a workspace)
|
|
75
|
+
|
|
76
|
+
| Key | Action |
|
|
77
|
+
|-----|--------|
|
|
78
|
+
| `up` / `down` | Move selection |
|
|
79
|
+
| `pgup` / `pgdn` | Page up / down |
|
|
80
|
+
| `enter` | View messages |
|
|
81
|
+
| `space` | Select / deselect chat for bulk actions |
|
|
82
|
+
| `a` | Select all chats |
|
|
83
|
+
| `A` | Deselect all chats |
|
|
84
|
+
| `m` | Move selected (or highlighted) chats to another workspace (`r` is a legacy alias) |
|
|
85
|
+
| `e` | Export selected (or highlighted) chats to Markdown files |
|
|
86
|
+
|
|
87
|
+
### Messages (within a chat)
|
|
88
|
+
|
|
89
|
+
| Key | Action |
|
|
90
|
+
|-----|--------|
|
|
91
|
+
| `up` / `down`, `pgup` / `pgdn`, `home` / `end` | Scroll |
|
|
92
|
+
| `e` | Export this chat |
|
|
93
|
+
|
|
94
|
+
### Moving chats
|
|
95
|
+
|
|
96
|
+
Press `m` on the chats screen to open the move-target picker. Workspaces are
|
|
97
|
+
identified by name, path, chat count, and last activity so ambiguous short
|
|
98
|
+
names are distinguishable. Type `/` to filter the list; the current workspace
|
|
99
|
+
is marked and cannot be selected as a target. After you confirm, a timestamped
|
|
100
|
+
backup is written to `~/.cursor-chat-recovery/backups/` before any data is
|
|
101
|
+
touched. Cursor must be closed before the move is attempted; the tool refuses
|
|
102
|
+
to write while Cursor is running.
|
|
103
|
+
|
|
104
|
+
## Safety
|
|
105
|
+
|
|
106
|
+
- Per-session full DB backup written next to `state.vscdb` on first mutation.
|
|
107
|
+
- Per-op headers backup under `~/.cursor-chat-recovery/backups/`.
|
|
108
|
+
- Read-only mode auto-engages on schema mismatch or detected Cursor-running.
|
|
109
|
+
- Reassign is reversible: the per-op backup restores the prior `composer.composerHeaders`.
|
|
110
|
+
|
|
111
|
+
## Schema drift
|
|
112
|
+
|
|
113
|
+
When Cursor changes its schema, the tool detects the mismatch on startup and shows a copy-pastable prompt you can paste into a coding agent to adapt the tool. The agent prompt names the affected files and what to change.
|
|
114
|
+
|
|
115
|
+
## Development
|
|
116
|
+
|
|
117
|
+
uv sync --dev
|
|
118
|
+
uv run pytest
|
|
119
|
+
uv run ruff check
|
|
120
|
+
uv run mypy src/
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# cursor-chat-recovery
|
|
2
|
+
|
|
3
|
+
[](https://github.com/kwiscion/cursor-chat-recovery/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](pyproject.toml)
|
|
6
|
+
|
|
7
|
+
Did your Cursor chats disappear after you moved, renamed, or re-opened a project? They're not gone. This is an interactive terminal UI to **recover, browse, move, and export Cursor AI chat history** — across all your projects.
|
|
8
|
+
|
|
9
|
+
## Why chats "disappear"
|
|
10
|
+
|
|
11
|
+
Cursor identifies each workspace by a hash of its identifier URI. Reopening a project from a different path, or saving an Untitled multi-folder workspace as a `.code-workspace` file, mints a new workspace identity and detaches all prior chats from the sidebar. The conversations are still in `globalStorage/state.vscdb` keyed by `composerId` — they just need their `workspaceIdentifier` rewritten to point at the new workspace. That's what this tool does, with backups at every step.
|
|
12
|
+
|
|
13
|
+
It's also useful when nothing is broken: browse every chat you've ever had in any project, move chats between workspaces, and export conversations to Markdown.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
Requires Python 3.10+. With [uv](https://docs.astral.sh/uv/):
|
|
18
|
+
|
|
19
|
+
uv tool install git+https://github.com/kwiscion/cursor-chat-recovery
|
|
20
|
+
|
|
21
|
+
or with pipx:
|
|
22
|
+
|
|
23
|
+
pipx install git+https://github.com/kwiscion/cursor-chat-recovery
|
|
24
|
+
|
|
25
|
+
Both install the `cursor-chat-recovery` executable (and a short alias, `ccr`).
|
|
26
|
+
After `uv tool install`, ensure `~/.local/bin` is on your PATH (run `uv tool update-shell` once if needed).
|
|
27
|
+
|
|
28
|
+
To run from a clone without installing: `uv run cursor-chat-recovery`.
|
|
29
|
+
|
|
30
|
+
## Use
|
|
31
|
+
|
|
32
|
+
cursor-chat-recovery # interactive TUI (or: ccr)
|
|
33
|
+
cursor-chat-recovery --readonly # TUI with mutations disabled
|
|
34
|
+
cursor-chat-recovery --list # workspaces table to stdout
|
|
35
|
+
cursor-chat-recovery --list --json
|
|
36
|
+
cursor-chat-recovery --export <COMPOSER_ID> --format markdown -o chat.md
|
|
37
|
+
cursor-chat-recovery --reassign <COMPOSER_IDS,COMMA,SEP> <TARGET_WS_ID> --yes
|
|
38
|
+
cursor-chat-recovery --merge <SRC_WS_ID> <TARGET_WS_ID> --yes
|
|
39
|
+
|
|
40
|
+
Close Cursor before any mutation. The tool refuses to write while Cursor is running.
|
|
41
|
+
|
|
42
|
+
## Keys
|
|
43
|
+
|
|
44
|
+
### Global
|
|
45
|
+
|
|
46
|
+
| Key | Action |
|
|
47
|
+
|-----|--------|
|
|
48
|
+
| `?` | Open help screen |
|
|
49
|
+
| `q` | Quit |
|
|
50
|
+
| `esc` | Back / cancel (clears an active filter first) |
|
|
51
|
+
| `ctrl-c` | Force quit |
|
|
52
|
+
|
|
53
|
+
### Workspaces (project list)
|
|
54
|
+
|
|
55
|
+
| Key | Action |
|
|
56
|
+
|-----|--------|
|
|
57
|
+
| `up` / `down` | Move selection |
|
|
58
|
+
| `pgup` / `pgdn` | Page up / down |
|
|
59
|
+
| `home` / `end` | Jump to first / last |
|
|
60
|
+
| `enter` | Open workspace's chats |
|
|
61
|
+
| `s` | Cycle sort order (last activity → chat count → name → health) |
|
|
62
|
+
| `/` | Filter by name or path (`enter` keeps filter, `esc` clears) |
|
|
63
|
+
|
|
64
|
+
### Chats (within a workspace)
|
|
65
|
+
|
|
66
|
+
| Key | Action |
|
|
67
|
+
|-----|--------|
|
|
68
|
+
| `up` / `down` | Move selection |
|
|
69
|
+
| `pgup` / `pgdn` | Page up / down |
|
|
70
|
+
| `enter` | View messages |
|
|
71
|
+
| `space` | Select / deselect chat for bulk actions |
|
|
72
|
+
| `a` | Select all chats |
|
|
73
|
+
| `A` | Deselect all chats |
|
|
74
|
+
| `m` | Move selected (or highlighted) chats to another workspace (`r` is a legacy alias) |
|
|
75
|
+
| `e` | Export selected (or highlighted) chats to Markdown files |
|
|
76
|
+
|
|
77
|
+
### Messages (within a chat)
|
|
78
|
+
|
|
79
|
+
| Key | Action |
|
|
80
|
+
|-----|--------|
|
|
81
|
+
| `up` / `down`, `pgup` / `pgdn`, `home` / `end` | Scroll |
|
|
82
|
+
| `e` | Export this chat |
|
|
83
|
+
|
|
84
|
+
### Moving chats
|
|
85
|
+
|
|
86
|
+
Press `m` on the chats screen to open the move-target picker. Workspaces are
|
|
87
|
+
identified by name, path, chat count, and last activity so ambiguous short
|
|
88
|
+
names are distinguishable. Type `/` to filter the list; the current workspace
|
|
89
|
+
is marked and cannot be selected as a target. After you confirm, a timestamped
|
|
90
|
+
backup is written to `~/.cursor-chat-recovery/backups/` before any data is
|
|
91
|
+
touched. Cursor must be closed before the move is attempted; the tool refuses
|
|
92
|
+
to write while Cursor is running.
|
|
93
|
+
|
|
94
|
+
## Safety
|
|
95
|
+
|
|
96
|
+
- Per-session full DB backup written next to `state.vscdb` on first mutation.
|
|
97
|
+
- Per-op headers backup under `~/.cursor-chat-recovery/backups/`.
|
|
98
|
+
- Read-only mode auto-engages on schema mismatch or detected Cursor-running.
|
|
99
|
+
- Reassign is reversible: the per-op backup restores the prior `composer.composerHeaders`.
|
|
100
|
+
|
|
101
|
+
## Schema drift
|
|
102
|
+
|
|
103
|
+
When Cursor changes its schema, the tool detects the mismatch on startup and shows a copy-pastable prompt you can paste into a coding agent to adapt the tool. The agent prompt names the affected files and what to change.
|
|
104
|
+
|
|
105
|
+
## Development
|
|
106
|
+
|
|
107
|
+
uv sync --dev
|
|
108
|
+
uv run pytest
|
|
109
|
+
uv run ruff check
|
|
110
|
+
uv run mypy src/
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
[MIT](LICENSE)
|