cursor-workspace-tool 0.1.0__py3-none-any.whl

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,494 @@
1
+ Metadata-Version: 2.4
2
+ Name: cursor-workspace-tool
3
+ Version: 0.1.0
4
+ Summary: Inspect and manage Cursor workspaces and AI Chat / Composer history across Windows and WSL/Linux.
5
+ Author-email: Aviv Raz <avivraz123@gmail.com>
6
+ License-Expression: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/aviv-raz/cursor-workspace-tool
8
+ Project-URL: Repository, https://github.com/aviv-raz/cursor-workspace-tool
9
+ Project-URL: Issues, https://github.com/aviv-raz/cursor-workspace-tool/issues
10
+ Keywords: cursor,vscode,workspace,ai-chat,composer,wsl,cli
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Quality Assurance
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ # Cursor Workspace Tool
31
+
32
+ [![PyPI](https://img.shields.io/pypi/v/cursor-workspace-tool.svg)](https://pypi.org/project/cursor-workspace-tool/)
33
+ [![Python](https://img.shields.io/pypi/pyversions/cursor-workspace-tool.svg)](https://pypi.org/project/cursor-workspace-tool/)
34
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)
35
+
36
+ A single-file, dependency-free command-line tool for inspecting and managing
37
+ [Cursor](https://cursor.com) editor **workspaces** and their **AI Chat / Composer**
38
+ history — across Windows and WSL/Linux at the same time.
39
+
40
+ Cursor (like any VS Code–based editor) keeps a growing pile of `workspaceStorage`
41
+ entries and chat records that it never cleans up on its own, and it offers no
42
+ built-in way to move a conversation from one project to another. This tool lets
43
+ you see exactly what is stored, move or copy AI chats between workspaces safely,
44
+ and prune the clutter — with an automatic backup before every change.
45
+
46
+ ## Features
47
+
48
+ - **List** every Cursor workspace found across all installations, with a rich
49
+ per-category breakdown of its AI chats (`list`).
50
+ - **Inspect** the non-empty chats and drafts of any workspace, including names,
51
+ IDs, timestamps and message counts (`chats`).
52
+ - **Move or copy** AI Chats/Composers between workspaces — all of them or a
53
+ hand-picked selection — without overwriting anything at the destination
54
+ (`merge`).
55
+ - **Clean up** stale workspace entries or empty chat records, globally or for a
56
+ single workspace, with drafts always protected (`cleanup`).
57
+ - **Restore** any change from an automatic, timestamped backup (`restore`).
58
+ - **Cross-platform:** works whether Cursor runs natively on Linux or on Windows
59
+ with the Remote-WSL extension.
60
+ - **Safe by default:** write commands are dry-run unless you pass `--apply`,
61
+ always create a backup, and refuse to run against a locked database.
62
+
63
+ ## How it works
64
+
65
+ The tool automatically discovers Cursor data directories. When run from
66
+ **WSL / native Linux** it scans:
67
+
68
+ - the local Linux Cursor config (`~/.config/Cursor`), and
69
+ - every Windows user profile reachable at
70
+ `/mnt/<drive>/Users/*/AppData/Roaming/Cursor`.
71
+
72
+ The Windows scan matters because when you run Cursor on Windows and connect into
73
+ WSL via the Remote-WSL extension, **all** workspace and chat storage — including
74
+ data for WSL-remote workspaces — actually lives on the Windows side.
75
+
76
+ When run natively on **Windows** (`python.exe`), it uses `%APPDATA%\Cursor`.
77
+
78
+ You can always add extra directories (multiple users, VSCodium, etc.) with
79
+ `--root`.
80
+
81
+ ### Where the data lives
82
+
83
+ | Data | Location |
84
+ | --- | --- |
85
+ | Per-workspace metadata | `workspaceStorage/<id>/` (`workspace.json`, `state.vscdb`) |
86
+ | AI chat headers & content | `globalStorage/state.vscdb` (`composerHeaders`, `cursorDiskKV`) |
87
+
88
+ Chats are keyed by a globally-unique `composerId` and associated with a
89
+ workspace through a `workspaceId`, which is why chats can be reassigned between
90
+ workspaces without collisions.
91
+
92
+ ## Requirements
93
+
94
+ - Python 3.8+ (standard library only — no third-party packages).
95
+
96
+ ## Installation
97
+
98
+ ### Option 1 — install from PyPI (recommended)
99
+
100
+ ```bash
101
+ pip install cursor-workspace-tool
102
+ # or
103
+ uv tool install cursor-workspace-tool
104
+ ```
105
+
106
+ After installation, both of these commands are available and do the same thing:
107
+
108
+ ```bash
109
+ cursor-workspace-tool --help
110
+ cwt --help
111
+ ```
112
+
113
+ ### Option 2 — install from GitHub
114
+
115
+ ```bash
116
+ pip install git+https://github.com/aviv-raz/cursor-workspace-tool.git
117
+ # or
118
+ uv tool install git+https://github.com/aviv-raz/cursor-workspace-tool.git
119
+ ```
120
+
121
+ ### Option 3 — install from a local clone
122
+
123
+ ```bash
124
+ git clone https://github.com/aviv-raz/cursor-workspace-tool.git
125
+ cd cursor-workspace-tool
126
+ pip install .
127
+ # or: uv tool install .
128
+ ```
129
+
130
+ ### Option 4 — run the script directly
131
+
132
+ No install required (Python 3.8+, standard library only):
133
+
134
+ ```bash
135
+ git clone https://github.com/aviv-raz/cursor-workspace-tool.git
136
+ cd cursor-workspace-tool
137
+ python3 cursor_workspace_tool.py --help
138
+ ```
139
+
140
+ ## Quick start
141
+
142
+ ```bash
143
+ # See all workspaces and their chat counts
144
+ cwt list --chat-counts
145
+
146
+ # Inspect the chats of a specific workspace
147
+ cwt chats counter-service
148
+
149
+ # Preview moving those chats into another project (dry-run)
150
+ cwt merge counter-service my-other-project
151
+
152
+ # Actually perform the move
153
+ cwt merge counter-service my-other-project --apply
154
+ ```
155
+
156
+ The full command name `cursor-workspace-tool` works identically in place of `cwt`.
157
+ If you are running the script without installing, replace `cwt` with
158
+ `python3 cursor_workspace_tool.py`.
159
+
160
+ ## Contributing
161
+
162
+ Bug reports and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
163
+ for setup, safety notes, and pull-request guidelines.
164
+
165
+ ## Safety and backups
166
+
167
+ > **Close Cursor completely before any `--apply` or `restore`.**
168
+ > Cursor holds its databases open in the background; writing while it runs can
169
+ > cause data loss or lock errors. The tool checks for a locked database and
170
+ > aborts before making changes if it detects one — but this is a best-effort
171
+ > check, not a substitute for closing Cursor.
172
+
173
+ Every write creates an **automatic, timestamped backup** first (override the
174
+ location with `--backup-dir`) and prints its path when finished. You can always
175
+ roll back with `restore <backup-dir>`.
176
+
177
+ - `merge --apply` backs up the affected `globalStorage/state.vscdb` file(s) — the
178
+ destination's, and the source's too if it belongs to a different installation.
179
+ - `cleanup workspaces --apply` backs up **the entire `workspaceStorage/<id>/`
180
+ folder** of each deleted workspace **and** the relevant `globalStorage/state.vscdb`.
181
+ - `cleanup empty-chats --apply` backs up `globalStorage/state.vscdb` before
182
+ deleting empty chat records.
183
+
184
+ Each backup folder also contains a human-readable `operation-report.md`
185
+ describing exactly what happened:
186
+
187
+ - **`merge`** — source and destination workspaces, `--mode move/copy`, how many
188
+ chats were requested vs. actually transferred, and the full chat list (name,
189
+ ID, type, created/last-updated times, message count). In `copy` mode it also
190
+ records the new IDs created at the destination.
191
+ - **`cleanup workspaces`** — each deleted workspace, the reason, its path and
192
+ size, the chat records purged from it, and the totals actually removed.
193
+ - **`cleanup empty-chats`** — the workspaces scanned, the empty chats deleted,
194
+ and the totals actually removed.
195
+
196
+ If an operation aborts because the database is locked after the backup was made,
197
+ the report is saved with an `Aborted` status. The `manifest.json` in each backup
198
+ folder is the exact machine-readable mapping used by `restore`; the
199
+ `operation-report.md` is for human review.
200
+
201
+ ## Commands
202
+
203
+ ### `list` — list all workspaces
204
+
205
+ ```bash
206
+ python3 cursor_workspace_tool.py list
207
+ python3 cursor_workspace_tool.py list --chat-counts # + per-workspace chat breakdown
208
+ python3 cursor_workspace_tool.py list --details # + on-disk size (slower)
209
+ python3 cursor_workspace_tool.py list --with-chats # only workspaces whose TOTAL > 0
210
+ python3 cursor_workspace_tool.py list --root "/mnt/d/Users/other/AppData/Roaming/Cursor/User"
211
+ ```
212
+
213
+ Prints a table with: an index (`#`) you can reuse in other commands, the internal
214
+ `ID` (the `workspaceStorage` folder name), the environment `TYPE`, what Cursor
215
+ `OPENED AS`, a `CHATS` breakdown, on-disk `SIZE`, `LAST USED` time, and the
216
+ decoded `PATH`.
217
+
218
+ With `--chat-counts` or `--details`, the `CHATS` column shows a full,
219
+ non-overlapping breakdown that always sums to `TOTAL`, e.g.:
220
+
221
+ ```
222
+ UI:4 SUB-AGENT:2 ARCHIVED:0 EMPTY:6 DRAFT:0 TOTAL:12
223
+ ```
224
+
225
+ | Category | Meaning |
226
+ | --- | --- |
227
+ | `UI` | Non-empty regular chats shown in the main chat list (not subagent/archived). |
228
+ | `SUB-AGENT` | Non-empty chats created as subagents; usually hidden from the main list. |
229
+ | `ARCHIVED` | Non-empty regular chats marked archived. |
230
+ | `EMPTY` | Zero-message records that are not drafts. |
231
+ | `DRAFT` | Zero-message records flagged `isDraft` **that contain saved unsent text**. |
232
+ | `TOTAL` | Sum of the categories above. |
233
+
234
+ Completely empty drafts (no saved text) are treated as junk: they are **not**
235
+ counted in `DRAFT` and **not** included in `TOTAL`.
236
+
237
+ `--with-chats` filters the table to workspaces whose `TOTAL > 0`. It turns on
238
+ chat counting automatically. `EMPTY` records count as existing chats; fully empty
239
+ drafts do not. A workspace whose database cannot be read is excluded from the
240
+ filter rather than misreported.
241
+
242
+ **`OPENED AS` values**
243
+
244
+ - `Folder` — `PATH` is a single folder opened directly.
245
+ - `Workspace file` — `PATH` points to a `.code-workspace` file, which may define
246
+ one or many folders.
247
+ - `Empty window` — a Cursor window opened with no folder or workspace.
248
+ - `Unknown` — no valid `workspace.json`, so what was opened can't be determined.
249
+
250
+ **`TYPE` values**
251
+
252
+ - `Local (<OS>)` — a local path opened without a Remote connection. A path
253
+ containing a Windows drive letter is reported as `Local (Windows)` even when
254
+ the tool runs inside WSL; other local URIs use the generic name from
255
+ `platform.system()` (e.g. `Local (Linux)`, `Local (Darwin)`).
256
+ - `Remote (<authority>)` — a Remote connection. The value in parentheses is the
257
+ URI's raw `authority`, so current and future remote types display
258
+ automatically — e.g. a Remote-WSL URI `vscode-remote://wsl+Ubuntu/...` shows as
259
+ `Remote (wsl+Ubuntu)`.
260
+ - `Local (Windows with WSL FS: <Distro>)` — Cursor runs locally on Windows and
261
+ reaches files inside a WSL distro via `file://wsl.localhost/<Distro>/...`,
262
+ without a Remote-WSL connection.
263
+ - `Empty window` / `Unknown` — as above.
264
+
265
+ Workspaces whose folder/file no longer exists on disk (from the machine running
266
+ the tool) are marked `(MISSING)`.
267
+
268
+ ### `chats [workspace]` — non-empty chats and drafts
269
+
270
+ ```bash
271
+ python3 cursor_workspace_tool.py chats # all workspaces
272
+ python3 cursor_workspace_tool.py chats 4 # by list index
273
+ python3 cursor_workspace_tool.py chats 2199cf1cd03410b8789ae530f51a71cb # by exact id
274
+ python3 cursor_workspace_tool.py chats counter-service # by path substring
275
+ ```
276
+
277
+ Without an argument, it scans all workspaces and shows those that have non-empty
278
+ chats or drafts **with content**. Under each workspace it lists the non-empty
279
+ chats (`UI`, `SUB-AGENT`, `ARCHIVED`) and any `DRAFT` chats that contain typed
280
+ text. `EMPTY` chats and completely empty drafts (e.g. the throwaway draft created
281
+ when you open a new empty window) are never listed.
282
+
283
+ The output starts with the number of workspaces and the total number of chats
284
+ shown. Each workspace section begins with a `UI / SUB-AGENT / ARCHIVED / DRAFT /
285
+ TOTAL` summary, followed by each chat's name, `composerId`, type, creation time,
286
+ last-updated time and message count. For `DRAFT` chats the unsent draft text is
287
+ shown; the tool extracts it from the chat's saved input (flat text, rich-text
288
+ input tree, or header subtitle).
289
+
290
+ The optional `[workspace]` argument restricts the output to a single workspace.
291
+
292
+ ### `merge <source> <dest>` — move or copy chats between workspaces
293
+
294
+ This command **only touches Cursor's own non-empty AI Chats/Composers**
295
+ (`composerHeaders` / `cursorDiskKV` in `globalStorage/state.vscdb`). A chat is
296
+ non-empty when it has at least one message (`bubbleId`) — the same definition
297
+ used by `chats` and the `list` counts. Empty records and drafts are skipped and
298
+ left untouched in the source, in both `move` and `copy` modes.
299
+
300
+ It does **not** touch anything else: not per-workspace `state.vscdb` keys (open
301
+ tabs, UI state, recent files), and not the `chatSessions/` / `chatEditingSessions/`
302
+ folders (those belong to the GitHub Copilot Chat extension, not Cursor's
303
+ Composer).
304
+
305
+ ```bash
306
+ # Dry-run is the default — always preview first:
307
+ python3 cursor_workspace_tool.py merge counter-service my-other-project
308
+
309
+ # Apply the move:
310
+ python3 cursor_workspace_tool.py merge counter-service my-other-project --apply
311
+
312
+ # Copy instead of move (source keeps its own copy):
313
+ python3 cursor_workspace_tool.py merge 3 7 --mode copy --apply
314
+
315
+ # Transfer only specific chats (comma-separated, or repeat the flag):
316
+ python3 cursor_workspace_tool.py merge counter-service my-other-project \
317
+ --chat-id ce5f1fbf-cf28-4fa4-a0c8-ddf616a3aa78,01234567-89ab-cdef-0123-456789abcdef
318
+ ```
319
+
320
+ **Mode (`--mode`, default `move`)**
321
+
322
+ - `--mode move` (default) — the chats are re-associated with the destination and
323
+ removed from the source. This is safe because each chat's ID is globally
324
+ unique, so it can't clobber an existing destination chat.
325
+ - `--mode copy` — the chats are duplicated at the destination under new IDs and
326
+ also remain untouched in the source; nothing is deleted or changed on either
327
+ side.
328
+
329
+ **Selecting specific chats (`--chat-id`)**
330
+
331
+ By default every non-empty source chat is selected. To pick specific ones, pass
332
+ comma-separated IDs (`--chat-id <id-1>,<id-2>`), repeat the flag, or combine both.
333
+ Selection is by `composerId` (shown by `chats`) because chat names are not
334
+ necessarily unique. If an ID doesn't belong to the source, or refers to an
335
+ empty/draft chat, the command stops without making any change.
336
+
337
+ **Overwriting on conflict (`--force`)**
338
+
339
+ During a move between two different Cursor installations, the same `composerId`
340
+ might already exist at the destination. By default such a conflict is skipped and
341
+ nothing is overwritten. `--force` replaces the existing destination chat with the
342
+ source version; the backup is made first, and the source copy is deleted only
343
+ after the destination write succeeds. `--force` is not valid with `--mode copy`,
344
+ since copy always creates a new ID.
345
+
346
+ When source and destination live in **different Cursor installations**, the tool
347
+ performs a full cross-database transfer between the two `globalStorage/state.vscdb`
348
+ files, including message content (`bubbleId`), checkpoints, and related content.
349
+
350
+ ### `cleanup workspaces [workspace]` — remove stale workspace entries
351
+
352
+ ```bash
353
+ python3 cursor_workspace_tool.py cleanup workspaces # dry-run, all
354
+ python3 cursor_workspace_tool.py cleanup workspaces --apply # delete all candidates
355
+ python3 cursor_workspace_tool.py cleanup workspaces 6ef46f8f... --apply # one workspace
356
+ ```
357
+
358
+ Finds workspaces that look like leftovers — `unknown` (missing/unreadable
359
+ `workspace.json`) or `missing` (the folder or `.code-workspace` it pointed to no
360
+ longer exists) — and deletes them **only if they have zero non-empty AI chats**.
361
+ Empty chat records alone do not protect a workspace; a workspace with even one
362
+ real chat is never deleted automatically. If chat counts can't be verified (e.g.
363
+ Cursor is running and the database is locked), the workspace is **skipped**.
364
+
365
+ Passing an explicit `[workspace]` makes it a deletion candidate even if it isn't
366
+ `unknown`/`missing`, but the zero-real-chats protection still applies.
367
+
368
+ **What is deleted (no leftovers):**
369
+
370
+ 1. **The whole `workspaceStorage/<id>/` folder** on disk (its per-workspace
371
+ `state.vscdb`, `workspace.json`, and everything else).
372
+ 2. **The leftover records in the global database** (`globalStorage/state.vscdb`) —
373
+ the `composerHeaders` and `cursorDiskKV` rows for that workspace's (empty)
374
+ chats — so no orphaned rows remain.
375
+
376
+ > The tool **never touches your actual project files** — only the metadata Cursor
377
+ > stores about the workspace. Shared `composer.content.*` blocks are intentionally
378
+ > preserved because they may be referenced by other chats.
379
+
380
+ Options:
381
+
382
+ - By default `empty-window` (the shared empty-window entry) is **not** touched —
383
+ it's considered a legitimate state, not clutter.
384
+ - `--include-empty-windows` also treats `empty-window` entries as deletion
385
+ candidates (still protected if they contain a non-empty chat).
386
+
387
+ Both the deleted folder and the affected global database are backed up first and
388
+ can be recovered with `restore`.
389
+
390
+ ### `cleanup empty-chats [workspace]` — remove empty chat records
391
+
392
+ ```bash
393
+ python3 cursor_workspace_tool.py cleanup empty-chats # dry-run, all
394
+ python3 cursor_workspace_tool.py cleanup empty-chats 6ef46f8f... # dry-run, one workspace
395
+ python3 cursor_workspace_tool.py cleanup empty-chats --apply # delete
396
+ python3 cursor_workspace_tool.py cleanup empty-chats --include-orphaned # + orphaned records
397
+ ```
398
+
399
+ Deletes only Composer records with zero messages (`bubble_count = 0`), without
400
+ deleting any workspace or project files. Drafts (zero-message records flagged
401
+ `isDraft`) are **always protected** and listed separately at the end with their
402
+ unsent text, so you can see what's in them before deciding. This information is
403
+ also saved in `operation-report.md`.
404
+
405
+ **`--include-orphaned`** — by default only workspaces that still have a
406
+ `workspaceStorage` folder are scanned. This flag also scans the global database
407
+ directly and finds empty chats whose `workspaceId` **has no `workspaceStorage`
408
+ folder** (orphaned records left after a workspace folder was deleted, or created
409
+ by a different installation). Orphans are marked `[orphaned - no workspaceStorage
410
+ folder]` in the output. Only **empty** chats are removed and drafts stay
411
+ protected. The flag is opt-in and is ignored when a specific `[workspace]` is
412
+ given. Workspaces that can't be read (usually because Cursor is running) are
413
+ skipped with a warning.
414
+
415
+ Before `--apply`, the tool verifies the database isn't locked, backs up
416
+ `globalStorage/state.vscdb`, and writes an `operation-report.md`. Dry-run is
417
+ always the default.
418
+
419
+ ### `restore <backup-dir>` — roll back a previous change
420
+
421
+ ```bash
422
+ python3 cursor_workspace_tool.py restore ~/.cache/cursor-workspace-tool/backups/20260721_174531
423
+ ```
424
+
425
+ Shows which files/folders are in the backup and where they will be restored
426
+ (using the exact `manifest.json` saved at backup time — not path guessing), and
427
+ asks for confirmation before copying them back over the originals. Works for both
428
+ `merge` backups (individual files) and `cleanup` backups (whole folders).
429
+
430
+ ## Identifying a workspace
431
+
432
+ Anywhere a workspace argument is accepted (`chats`, `merge`, `cleanup`), you can pass:
433
+
434
+ - the **index** (`#`) from the most recent `list` output (cached between runs),
435
+ - the **exact ID** (the folder name under `workspaceStorage/`), or
436
+ - a **path substring**, as long as it's unique (if several match, the tool lists
437
+ them and asks you to be more specific).
438
+
439
+ ## FAQ: why are there "weird" values in the `PATH` column?
440
+
441
+ These are all **normal**. Cursor never removes old `workspaceStorage` entries, so
442
+ various leftovers accumulate over time. Importantly, **you don't have to open a
443
+ project "on purpose" for an entry to be created** — each of these creates one:
444
+
445
+ - Opening a single file (e.g. `code file.txt`, or double-clicking a file), not
446
+ just a whole folder.
447
+ - Any empty "New Window" (`Ctrl/Cmd+Shift+N`), even if nothing is saved in it.
448
+ - Extensions/tools that briefly open a Cursor window (some git tools,
449
+ dev-containers, etc.).
450
+ - Moving or renaming a project folder — the **old** entry (with the previous path)
451
+ stays, and a **new** one is created for the new path.
452
+ - Deleting a project or `.code-workspace` file from disk without closing it in
453
+ Cursor first.
454
+
455
+ Specific messages:
456
+
457
+ - **`(unknown - workspace.json missing or unrecognized; ...)`** — the folder has
458
+ no valid `workspace.json`, so the original project can't be determined; likely
459
+ an orphan from a deleted/renamed workspace.
460
+ - **`(MISSING)`** — the tool checked whether the path still exists on disk (from
461
+ the machine running it) and found it gone.
462
+ - **`(empty window - no folder/workspace opened)`** — the single shared
463
+ `empty-window` entry Cursor uses whenever a window opens with nothing loaded.
464
+ - **`/`** — a valid path: a workspace opened on the WSL root directory (`/`)
465
+ itself rather than a specific project.
466
+
467
+ If these entries are no longer relevant (and in particular have no AI chats), use
468
+ the `cleanup` commands above to prune them.
469
+
470
+ ## Known limitations
471
+
472
+ - On-disk existence detection is best-effort. For non-WSL remote workspaces
473
+ (SSH, dev-containers) it can't be verified from this machine, so `cleanup` does
474
+ **not** treat them as `missing`; they're deleted only if their `workspace.json`
475
+ is entirely missing/corrupt (`unknown`) **and** they have no non-empty chats.
476
+ - When copying (`--mode copy`) a chat between two different Cursor installations,
477
+ large content blocks stored in content-addressable storage
478
+ (`composer.content.*`) are copied best-effort (by scanning the chat JSON for
479
+ references). In very rare cases of missing content, only that specific
480
+ checkpoint/diff would be inaccessible; the chat text itself is unaffected.
481
+ - The tool does not connect to WSL over `\\wsl$` from Windows. If you run it on
482
+ Windows, use WSL itself (or `--root` with a UNC path) to reach that side.
483
+
484
+ ## License
485
+
486
+ Licensed under the **GNU General Public License v3.0** (GPL-3.0). See the
487
+ [LICENSE](LICENSE) file for the full text.
488
+
489
+ This is a copyleft license: you are free to use, modify and redistribute this
490
+ tool, but any distributed derivative work must also be released under the GPL and
491
+ keep the original copyright and license notices.
492
+
493
+ Copyright (C) 2026 Aviv Raz <avivraz123@gmail.com> —
494
+ [https://github.com/aviv-raz](https://github.com/aviv-raz)
@@ -0,0 +1,7 @@
1
+ cursor_workspace_tool.py,sha256=QjcOUzwiibk_aBPpvyCoi1pNtBFmoxqyomFppjsBNeM,105148
2
+ cursor_workspace_tool-0.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
3
+ cursor_workspace_tool-0.1.0.dist-info/METADATA,sha256=2Uq8uSfxTsPXM7mbVN0Ckne-rJrjKdZfH2LTVfctASI,22573
4
+ cursor_workspace_tool-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
5
+ cursor_workspace_tool-0.1.0.dist-info/entry_points.txt,sha256=vn2VdvkKsRHef1zJxv5s9S2jNzLGoz-OqGskDkAHABA,102
6
+ cursor_workspace_tool-0.1.0.dist-info/top_level.txt,sha256=4VrPsnGx85QkSKgp-zjQHewFOja3nG1kcYNzQn9xdNY,22
7
+ cursor_workspace_tool-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ cursor-workspace-tool = cursor_workspace_tool:main
3
+ cwt = cursor_workspace_tool:main