cursor-history 0.5.1 → 0.8.0

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.
Files changed (83) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +385 -2
  3. package/dist/cli/commands/backup.d.ts +9 -0
  4. package/dist/cli/commands/backup.d.ts.map +1 -0
  5. package/dist/cli/commands/backup.js +168 -0
  6. package/dist/cli/commands/backup.js.map +1 -0
  7. package/dist/cli/commands/export.d.ts.map +1 -1
  8. package/dist/cli/commands/export.js +39 -7
  9. package/dist/cli/commands/export.js.map +1 -1
  10. package/dist/cli/commands/list-backups.d.ts +9 -0
  11. package/dist/cli/commands/list-backups.d.ts.map +1 -0
  12. package/dist/cli/commands/list-backups.js +166 -0
  13. package/dist/cli/commands/list-backups.js.map +1 -0
  14. package/dist/cli/commands/list.d.ts.map +1 -1
  15. package/dist/cli/commands/list.js +44 -9
  16. package/dist/cli/commands/list.js.map +1 -1
  17. package/dist/cli/commands/migrate-session.d.ts +12 -0
  18. package/dist/cli/commands/migrate-session.d.ts.map +1 -0
  19. package/dist/cli/commands/migrate-session.js +125 -0
  20. package/dist/cli/commands/migrate-session.js.map +1 -0
  21. package/dist/cli/commands/migrate.d.ts +13 -0
  22. package/dist/cli/commands/migrate.d.ts.map +1 -0
  23. package/dist/cli/commands/migrate.js +122 -0
  24. package/dist/cli/commands/migrate.js.map +1 -0
  25. package/dist/cli/commands/restore.d.ts +9 -0
  26. package/dist/cli/commands/restore.d.ts.map +1 -0
  27. package/dist/cli/commands/restore.js +192 -0
  28. package/dist/cli/commands/restore.js.map +1 -0
  29. package/dist/cli/commands/search.d.ts.map +1 -1
  30. package/dist/cli/commands/search.js +31 -3
  31. package/dist/cli/commands/search.js.map +1 -1
  32. package/dist/cli/commands/show.d.ts.map +1 -1
  33. package/dist/cli/commands/show.js +32 -4
  34. package/dist/cli/commands/show.js.map +1 -1
  35. package/dist/cli/errors.d.ts +56 -0
  36. package/dist/cli/errors.d.ts.map +1 -0
  37. package/dist/cli/errors.js +90 -0
  38. package/dist/cli/errors.js.map +1 -0
  39. package/dist/cli/index.js +11 -1
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/core/backup.d.ts +89 -0
  42. package/dist/core/backup.d.ts.map +1 -0
  43. package/dist/core/backup.js +709 -0
  44. package/dist/core/backup.js.map +1 -0
  45. package/dist/core/migrate.d.ts +40 -0
  46. package/dist/core/migrate.d.ts.map +1 -0
  47. package/dist/core/migrate.js +586 -0
  48. package/dist/core/migrate.js.map +1 -0
  49. package/dist/core/storage.d.ts +78 -6
  50. package/dist/core/storage.d.ts.map +1 -1
  51. package/dist/core/storage.js +327 -45
  52. package/dist/core/storage.js.map +1 -1
  53. package/dist/core/types.d.ts +280 -0
  54. package/dist/core/types.d.ts.map +1 -1
  55. package/dist/lib/backup.d.ts +98 -0
  56. package/dist/lib/backup.d.ts.map +1 -0
  57. package/dist/lib/backup.js +108 -0
  58. package/dist/lib/backup.js.map +1 -0
  59. package/dist/lib/config.d.ts +33 -0
  60. package/dist/lib/config.d.ts.map +1 -0
  61. package/dist/lib/config.js +81 -0
  62. package/dist/lib/config.js.map +1 -0
  63. package/dist/lib/errors.d.ts +257 -30
  64. package/dist/lib/errors.d.ts.map +1 -1
  65. package/dist/lib/errors.js +404 -54
  66. package/dist/lib/errors.js.map +1 -1
  67. package/dist/lib/index.d.ts +219 -0
  68. package/dist/lib/index.d.ts.map +1 -0
  69. package/dist/lib/index.js +520 -0
  70. package/dist/lib/index.js.map +1 -0
  71. package/dist/lib/platform.d.ts +11 -0
  72. package/dist/lib/platform.d.ts.map +1 -1
  73. package/dist/lib/platform.js +32 -0
  74. package/dist/lib/platform.js.map +1 -1
  75. package/dist/lib/types.d.ts +374 -0
  76. package/dist/lib/types.d.ts.map +1 -0
  77. package/dist/lib/types.js +9 -0
  78. package/dist/lib/types.js.map +1 -0
  79. package/dist/lib/utils.d.ts +17 -0
  80. package/dist/lib/utils.d.ts.map +1 -0
  81. package/dist/lib/utils.js +20 -0
  82. package/dist/lib/utils.js.map +1 -0
  83. package/package.json +32 -4
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2025 Borui
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,9 +1,119 @@
1
- # cursor-history
1
+ # Cursor History
2
2
 
3
- CLI tool to browse, search, and export your Cursor AI chat history.
3
+ <p align="center">
4
+ <img src="docs/logo.png" alt="cursor-history logo" width="200">
5
+ </p>
6
+
7
+ [![npm version](https://img.shields.io/npm/v/cursor-history.svg)](https://www.npmjs.com/package/cursor-history)
8
+ [![npm downloads](https://img.shields.io/npm/dm/cursor-history.svg)](https://www.npmjs.com/package/cursor-history)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+ [![Node.js](https://img.shields.io/badge/Node.js-20%2B-green.svg)](https://nodejs.org/)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue.svg)](https://www.typescriptlang.org/)
12
+
13
+ **The ultimate open-source tool for browsing, searching, exporting, and backing up your Cursor AI chat history.**
14
+
15
+ A POSIX-style CLI tool that does one thing well: access your Cursor AI chat history. Built on Unix philosophy—simple, composable, and focused.
16
+
17
+ ```bash
18
+ # Pipe-friendly: combine with other tools
19
+ cursor-history list --json | jq '.[] | select(.messageCount > 10)'
20
+ cursor-history export 1 | grep -i "api" | head -20
21
+ cursor-history search "bug" --json | jq -r '.[].sessionId' | xargs -I {} cursor-history export {}
22
+ ```
23
+
24
+ Never lose a conversation again. Whether you need to find that perfect code snippet from last week, migrate your history to a new machine, or create reliable backups of all your AI-assisted development sessions—cursor-history has you covered. Free, open-source, and built by the community for the community.
25
+
26
+ ## Example Output
27
+
28
+ ### List Sessions
29
+
30
+ <pre>
31
+ <span style="color: #888">cursor-history list</span>
32
+
33
+ <span style="color: #5fd7ff">cursor-history</span> - Chat History Browser
34
+
35
+ <span style="color: #5fd7ff">Sessions (showing 3 of 42):</span>
36
+
37
+ <span style="color: #af87ff">#1</span> <span style="color: #87d787">12/26 09:15 AM</span> <span style="color: #d7d787">cursor_chat_history</span>
38
+ <span style="color: #888">15 messages · Updated 2 min ago</span>
39
+ <span style="color: #fff">"Help me fix the migration path issue..."</span>
40
+
41
+ <span style="color: #af87ff">#2</span> <span style="color: #87d787">12/25 03:22 PM</span> <span style="color: #d7d787">my-react-app</span>
42
+ <span style="color: #888">8 messages · Updated 18 hours ago</span>
43
+ <span style="color: #fff">"Add authentication to the app..."</span>
44
+
45
+ <span style="color: #af87ff">#3</span> <span style="color: #87d787">12/24 11:30 AM</span> <span style="color: #d7d787">api-server</span>
46
+ <span style="color: #888">23 messages · Updated 2 days ago</span>
47
+ <span style="color: #fff">"Create REST endpoints for users..."</span>
48
+ </pre>
49
+
50
+ ### Show Session Details
51
+
52
+ <pre>
53
+ <span style="color: #888">cursor-history show 1</span>
54
+
55
+ <span style="color: #5fd7ff">Session #1</span> · <span style="color: #d7d787">cursor_chat_history</span>
56
+ <span style="color: #888">15 messages · Created 12/26 09:15 AM</span>
57
+
58
+ ────────────────────────────────────────
59
+
60
+ <span style="color: #87d787">You:</span> <span style="color: #888">09:15:23 AM</span>
61
+
62
+ Help me fix the migration path issue in the codebase
63
+
64
+ ────────────────────────────────────────
65
+
66
+ <span style="color: #af87ff">Assistant:</span> <span style="color: #888">09:15:45 AM</span>
67
+
68
+ I'll help you fix the migration path issue. Let me first examine
69
+ the relevant files.
70
+
71
+ ────────────────────────────────────────
72
+
73
+ <span style="color: #d7af5f">Tool:</span> <span style="color: #888">09:15:46 AM</span>
74
+ <span style="color: #d7af5f">🔧 Read File</span>
75
+ <span style="color: #888">File:</span> <span style="color: #5fd7ff">src/core/migrate.ts</span>
76
+ <span style="color: #888">Content:</span> <span style="color: #fff">export function migrateSession(sessionId: string...</span>
77
+ <span style="color: #87d787">Status: ✓ completed</span>
78
+
79
+ ────────────────────────────────────────
80
+
81
+ <span style="color: #d7af5f">Tool:</span> <span style="color: #888">09:16:02 AM</span>
82
+ <span style="color: #d7af5f">🔧 Edit File</span>
83
+ <span style="color: #888">File:</span> <span style="color: #5fd7ff">src/core/migrate.ts</span>
84
+
85
+ <span style="color: #87d787">```diff</span>
86
+ <span style="color: #87d787"> + function transformPath(path: string): string {</span>
87
+ <span style="color: #87d787"> + return path.replace(sourcePrefix, destPrefix);</span>
88
+ <span style="color: #87d787"> + }</span>
89
+ <span style="color: #87d787">```</span>
90
+
91
+ <span style="color: #87d787">Status: ✓ completed</span>
92
+
93
+ ────────────────────────────────────────
94
+
95
+ <span style="color: #5f87d7">Thinking:</span> <span style="color: #888">09:16:02 AM</span>
96
+ <span style="color: #5f87d7">💭</span> <span style="color: #888">Now I need to update the function to call transformPath
97
+ for each file reference in the bubble data...</span>
98
+
99
+ ────────────────────────────────────────
100
+
101
+ <span style="color: #af87ff">Assistant:</span> <span style="color: #888">09:16:30 AM</span>
102
+
103
+ I've added the path transformation logic. The migration will now
104
+ update all file paths when moving sessions between workspaces.
105
+
106
+ ────────────────────────────────────────
107
+
108
+ <span style="color: #ff5f5f">Error:</span> <span style="color: #888">09:17:01 AM</span>
109
+ <span style="color: #ff5f5f">❌</span> <span style="color: #ff5f5f">Build failed: Cannot find module './utils'</span>
110
+
111
+ ────────────────────────────────────────
112
+ </pre>
4
113
 
5
114
  ## Features
6
115
 
116
+ - **Dual interface** - Use as CLI tool or import as a library in your Node.js projects
7
117
  - **List sessions** - View all chat sessions across workspaces
8
118
  - **View full conversations** - See complete chat history with:
9
119
  - AI responses with natural language explanations
@@ -13,6 +123,8 @@ CLI tool to browse, search, and export your Cursor AI chat history.
13
123
  - Message timestamps
14
124
  - **Search** - Find conversations by keyword with highlighted matches
15
125
  - **Export** - Save sessions as Markdown or JSON files
126
+ - **Migrate** - Move or copy sessions between workspaces (e.g., when renaming projects)
127
+ - **Backup & Restore** - Create full backups of all chat history and restore when needed
16
128
  - **Cross-platform** - Works on macOS, Windows, and Linux
17
129
 
18
130
  ## Installation
@@ -127,6 +239,65 @@ cursor-history export --all -o ./exports/
127
239
  cursor-history export 1 --force
128
240
  ```
129
241
 
242
+ ### Migrate Sessions
243
+
244
+ ```bash
245
+ # Move a single session to another workspace
246
+ cursor-history migrate-session 1 /path/to/new/project
247
+
248
+ # Move multiple sessions (comma-separated indices or IDs)
249
+ cursor-history migrate-session 1,3,5 /path/to/project
250
+
251
+ # Copy instead of move (keeps original)
252
+ cursor-history migrate-session --copy 1 /path/to/project
253
+
254
+ # Preview what would happen without making changes
255
+ cursor-history migrate-session --dry-run 1 /path/to/project
256
+
257
+ # Move all sessions from one workspace to another
258
+ cursor-history migrate /old/project /new/project
259
+
260
+ # Copy all sessions (backup)
261
+ cursor-history migrate --copy /project /backup/project
262
+
263
+ # Force merge with existing sessions at destination
264
+ cursor-history migrate --force /old/project /existing/project
265
+ ```
266
+
267
+ ### Backup & Restore
268
+
269
+ ```bash
270
+ # Create a backup of all chat history
271
+ cursor-history backup
272
+
273
+ # Create backup to specific file
274
+ cursor-history backup -o ~/my-backup.zip
275
+
276
+ # Overwrite existing backup
277
+ cursor-history backup --force
278
+
279
+ # List available backups
280
+ cursor-history list-backups
281
+
282
+ # List backups in a specific directory
283
+ cursor-history list-backups -d /path/to/backups
284
+
285
+ # Restore from a backup
286
+ cursor-history restore ~/cursor-history-backups/backup.zip
287
+
288
+ # Restore to a custom location
289
+ cursor-history restore backup.zip --target /custom/cursor/data
290
+
291
+ # Force overwrite existing data
292
+ cursor-history restore backup.zip --force
293
+
294
+ # View sessions from a backup without restoring
295
+ cursor-history list --backup ~/backup.zip
296
+ cursor-history show 1 --backup ~/backup.zip
297
+ cursor-history search "query" --backup ~/backup.zip
298
+ cursor-history export 1 --backup ~/backup.zip
299
+ ```
300
+
130
301
  ### Global Options
131
302
 
132
303
  ```bash
@@ -178,6 +349,189 @@ When browsing your chat history, you'll see:
178
349
 
179
350
  The tool automatically finds and reads your Cursor chat history from these locations.
180
351
 
352
+ ## Library API
353
+
354
+ In addition to the CLI, you can use cursor-history as a library in your Node.js projects:
355
+
356
+ ```typescript
357
+ import {
358
+ listSessions,
359
+ getSession,
360
+ searchSessions,
361
+ exportSessionToMarkdown
362
+ } from 'cursor-history';
363
+
364
+ // List all sessions with pagination
365
+ const result = listSessions({ limit: 10 });
366
+ console.log(`Found ${result.pagination.total} sessions`);
367
+
368
+ for (const session of result.data) {
369
+ console.log(`${session.id}: ${session.messageCount} messages`);
370
+ }
371
+
372
+ // Get a specific session (zero-based index)
373
+ const session = getSession(0);
374
+ console.log(session.messages);
375
+
376
+ // Search across all sessions
377
+ const results = searchSessions('authentication', { context: 2 });
378
+ for (const match of results) {
379
+ console.log(match.match);
380
+ }
381
+
382
+ // Export to Markdown
383
+ const markdown = exportSessionToMarkdown(0);
384
+ ```
385
+
386
+ ### Migration API
387
+
388
+ ```typescript
389
+ import { migrateSession, migrateWorkspace } from 'cursor-history';
390
+
391
+ // Move a session to another workspace
392
+ const results = migrateSession({
393
+ sessions: 3, // index or ID
394
+ destination: '/path/to/new/project'
395
+ });
396
+
397
+ // Copy multiple sessions (keeps originals)
398
+ const results = migrateSession({
399
+ sessions: [1, 3, 5],
400
+ destination: '/path/to/project',
401
+ mode: 'copy'
402
+ });
403
+
404
+ // Migrate all sessions between workspaces
405
+ const result = migrateWorkspace({
406
+ source: '/old/project',
407
+ destination: '/new/project'
408
+ });
409
+ console.log(`Migrated ${result.successCount} sessions`);
410
+ ```
411
+
412
+ ### Backup API
413
+
414
+ ```typescript
415
+ import {
416
+ createBackup,
417
+ restoreBackup,
418
+ validateBackup,
419
+ listBackups,
420
+ getDefaultBackupDir
421
+ } from 'cursor-history';
422
+
423
+ // Create a backup
424
+ const result = await createBackup({
425
+ outputPath: '~/my-backup.zip',
426
+ force: true,
427
+ onProgress: (progress) => {
428
+ console.log(`${progress.phase}: ${progress.filesCompleted}/${progress.totalFiles}`);
429
+ }
430
+ });
431
+ console.log(`Backup created: ${result.backupPath}`);
432
+ console.log(`Sessions: ${result.manifest.stats.sessionCount}`);
433
+
434
+ // Validate a backup
435
+ const validation = validateBackup('~/backup.zip');
436
+ if (validation.status === 'valid') {
437
+ console.log('Backup is valid');
438
+ } else if (validation.status === 'warnings') {
439
+ console.log('Backup has warnings:', validation.corruptedFiles);
440
+ }
441
+
442
+ // Restore from backup
443
+ const restoreResult = restoreBackup({
444
+ backupPath: '~/backup.zip',
445
+ force: true
446
+ });
447
+ console.log(`Restored ${restoreResult.filesRestored} files`);
448
+
449
+ // List available backups
450
+ const backups = listBackups(); // Scans ~/cursor-history-backups/
451
+ for (const backup of backups) {
452
+ console.log(`${backup.filename}: ${backup.manifest?.stats.sessionCount} sessions`);
453
+ }
454
+
455
+ // Read sessions from backup without restoring
456
+ const sessions = listSessions({ backupPath: '~/backup.zip' });
457
+ ```
458
+
459
+ ### Available Functions
460
+
461
+ | Function | Description |
462
+ |----------|-------------|
463
+ | `listSessions(config?)` | List sessions with pagination |
464
+ | `getSession(index, config?)` | Get full session by index |
465
+ | `searchSessions(query, config?)` | Search across sessions |
466
+ | `exportSessionToJson(index, config?)` | Export session to JSON |
467
+ | `exportSessionToMarkdown(index, config?)` | Export session to Markdown |
468
+ | `exportAllSessionsToJson(config?)` | Export all sessions to JSON |
469
+ | `exportAllSessionsToMarkdown(config?)` | Export all sessions to Markdown |
470
+ | `migrateSession(config)` | Move/copy sessions to another workspace |
471
+ | `migrateWorkspace(config)` | Move/copy all sessions between workspaces |
472
+ | `createBackup(config?)` | Create full backup of all chat history |
473
+ | `restoreBackup(config)` | Restore chat history from backup |
474
+ | `validateBackup(path)` | Validate backup integrity |
475
+ | `listBackups(directory?)` | List available backup files |
476
+ | `getDefaultBackupDir()` | Get default backup directory path |
477
+ | `getDefaultDataPath()` | Get platform-specific Cursor data path |
478
+
479
+ ### Configuration Options
480
+
481
+ ```typescript
482
+ interface LibraryConfig {
483
+ dataPath?: string; // Custom Cursor data path
484
+ workspace?: string; // Filter by workspace path
485
+ limit?: number; // Pagination limit
486
+ offset?: number; // Pagination offset
487
+ context?: number; // Search context lines
488
+ backupPath?: string; // Read from backup file instead of live data
489
+ }
490
+ ```
491
+
492
+ ### Error Handling
493
+
494
+ ```typescript
495
+ import {
496
+ listSessions,
497
+ createBackup,
498
+ isDatabaseLockedError,
499
+ isDatabaseNotFoundError,
500
+ isSessionNotFoundError,
501
+ isWorkspaceNotFoundError,
502
+ isBackupError,
503
+ isRestoreError,
504
+ isInvalidBackupError
505
+ } from 'cursor-history';
506
+
507
+ try {
508
+ const result = listSessions();
509
+ } catch (err) {
510
+ if (isDatabaseLockedError(err)) {
511
+ console.error('Database locked - close Cursor and retry');
512
+ } else if (isDatabaseNotFoundError(err)) {
513
+ console.error('Cursor data not found');
514
+ } else if (isSessionNotFoundError(err)) {
515
+ console.error('Session not found');
516
+ } else if (isWorkspaceNotFoundError(err)) {
517
+ console.error('Workspace not found - open project in Cursor first');
518
+ }
519
+ }
520
+
521
+ // Backup-specific errors
522
+ try {
523
+ const result = await createBackup();
524
+ } catch (err) {
525
+ if (isBackupError(err)) {
526
+ console.error('Backup failed:', err.message);
527
+ } else if (isInvalidBackupError(err)) {
528
+ console.error('Invalid backup file');
529
+ } else if (isRestoreError(err)) {
530
+ console.error('Restore failed:', err.message);
531
+ }
532
+ }
533
+ ```
534
+
181
535
  ## Development
182
536
 
183
537
  ### Building from Source
@@ -220,6 +574,35 @@ This project uses GitHub Actions for automatic NPM publishing. To release a new
220
574
  2. Go to your GitHub repository settings → Secrets and variables → Actions
221
575
  3. Add a new repository secret named `NPM_TOKEN` with your NPM token
222
576
 
577
+ ## Contributing
578
+
579
+ We welcome contributions from the community! Here's how you can help:
580
+
581
+ ### Reporting Issues
582
+
583
+ - **Bug reports**: [Open an issue](https://github.com/S2thend/cursor_chat_history/issues/new) with steps to reproduce, expected vs actual behavior, and your environment (OS, Node.js version)
584
+ - **Feature requests**: [Open an issue](https://github.com/S2thend/cursor_chat_history/issues/new) describing the feature and its use case
585
+
586
+ ### Submitting Pull Requests
587
+
588
+ 1. Fork the repository
589
+ 2. Create a feature branch (`git checkout -b feature/my-feature`)
590
+ 3. Make your changes
591
+ 4. Run tests and linting (`npm test && npm run lint`)
592
+ 5. Commit your changes (`git commit -m 'Add my feature'`)
593
+ 6. Push to your fork (`git push origin feature/my-feature`)
594
+ 7. [Open a Pull Request](https://github.com/S2thend/cursor_chat_history/pulls)
595
+
596
+ ### Development Setup
597
+
598
+ ```bash
599
+ git clone https://github.com/S2thend/cursor_chat_history.git
600
+ cd cursor_chat_history
601
+ npm install
602
+ npm run build
603
+ npm test
604
+ ```
605
+
223
606
  ## License
224
607
 
225
608
  MIT
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Backup command - create full backup of all chat history
3
+ */
4
+ import type { Command } from 'commander';
5
+ /**
6
+ * Register the backup command
7
+ */
8
+ export declare function registerBackupCommand(program: Command): void;
9
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/backup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsGzC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoF5D"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Backup command - create full backup of all chat history
3
+ */
4
+ import pc from 'picocolors';
5
+ import { createBackup } from '../../core/backup.js';
6
+ import { handleError, ExitCode } from '../errors.js';
7
+ import { expandPath, contractPath } from '../../lib/platform.js';
8
+ /**
9
+ * Format file size for display
10
+ */
11
+ function formatSize(bytes) {
12
+ if (bytes < 1024) {
13
+ return `${bytes} B`;
14
+ }
15
+ if (bytes < 1024 * 1024) {
16
+ return `${(bytes / 1024).toFixed(1)} KB`;
17
+ }
18
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
19
+ }
20
+ /**
21
+ * Format duration for display
22
+ */
23
+ function formatDuration(ms) {
24
+ if (ms < 1000) {
25
+ return `${ms}ms`;
26
+ }
27
+ return `${(ms / 1000).toFixed(1)}s`;
28
+ }
29
+ /**
30
+ * T021: Progress display for backup command
31
+ */
32
+ function displayProgress(progress) {
33
+ const phases = {
34
+ scanning: '🔍 Scanning for database files...',
35
+ 'backing-up': '📦 Backing up databases...',
36
+ compressing: '🗜️ Compressing into zip...',
37
+ finalizing: '✨ Finalizing backup...',
38
+ };
39
+ const phaseText = phases[progress.phase];
40
+ const fileProgress = progress.totalFiles > 0
41
+ ? ` [${progress.filesCompleted}/${progress.totalFiles}]`
42
+ : '';
43
+ const currentFile = progress.currentFile ? ` ${pc.dim(progress.currentFile)}` : '';
44
+ // Clear line and print progress
45
+ process.stdout.write(`\r${phaseText}${fileProgress}${currentFile}`.padEnd(80));
46
+ }
47
+ /**
48
+ * Format backup result for JSON output
49
+ */
50
+ function formatBackupResultJson(result) {
51
+ return JSON.stringify({
52
+ success: result.success,
53
+ backupPath: result.backupPath,
54
+ durationMs: result.durationMs,
55
+ ...(result.error && { error: result.error }),
56
+ manifest: result.manifest,
57
+ }, null, 2);
58
+ }
59
+ /**
60
+ * Format backup result for human-readable output
61
+ */
62
+ function formatBackupResult(result) {
63
+ const lines = [];
64
+ if (result.success) {
65
+ lines.push(pc.green('✓ Backup created successfully!'));
66
+ lines.push('');
67
+ lines.push(` ${pc.bold('Location:')} ${contractPath(result.backupPath)}`);
68
+ lines.push(` ${pc.bold('Size:')} ${formatSize(result.manifest.stats.totalSize)}`);
69
+ lines.push(` ${pc.bold('Sessions:')} ${result.manifest.stats.sessionCount}`);
70
+ lines.push(` ${pc.bold('Workspaces:')} ${result.manifest.stats.workspaceCount}`);
71
+ lines.push(` ${pc.bold('Files:')} ${result.manifest.files.length} database files`);
72
+ lines.push(` ${pc.bold('Duration:')} ${formatDuration(result.durationMs)}`);
73
+ }
74
+ else {
75
+ lines.push(pc.red('✗ Backup failed'));
76
+ lines.push('');
77
+ if (result.error) {
78
+ lines.push(` ${pc.bold('Error:')} ${result.error}`);
79
+ }
80
+ }
81
+ return lines.join('\n');
82
+ }
83
+ /**
84
+ * Register the backup command
85
+ */
86
+ export function registerBackupCommand(program) {
87
+ program
88
+ .command('backup')
89
+ .description('Create a full backup of all Cursor chat history')
90
+ .option('-o, --output <path>', 'Output file path (default: ~/cursor-history-backups/<timestamp>.zip)')
91
+ .option('-f, --force', 'Overwrite existing backup file')
92
+ .action(async (options, command) => {
93
+ const globalOptions = command.parent?.opts();
94
+ const useJson = options.json ?? globalOptions?.json ?? false;
95
+ const customPath = options.dataPath ?? globalOptions?.dataPath;
96
+ try {
97
+ // Resolve output path if provided
98
+ const outputPath = options.output ? expandPath(options.output) : undefined;
99
+ // Show progress if not JSON mode
100
+ const onProgress = useJson ? undefined : displayProgress;
101
+ // Create backup
102
+ const result = await createBackup({
103
+ sourcePath: customPath ? expandPath(customPath) : undefined,
104
+ outputPath,
105
+ force: options.force ?? false,
106
+ onProgress,
107
+ });
108
+ // Clear progress line
109
+ if (!useJson) {
110
+ process.stdout.write('\r'.padEnd(80) + '\r');
111
+ }
112
+ // Handle different error cases with appropriate exit codes
113
+ if (!result.success) {
114
+ // T022: No data to backup
115
+ if (result.error?.includes('No Cursor data found')) {
116
+ if (useJson) {
117
+ console.log(formatBackupResultJson(result));
118
+ }
119
+ else {
120
+ console.error(pc.yellow('No Cursor data found to backup.'));
121
+ console.error(pc.dim('Make sure Cursor has been used and has chat history.'));
122
+ }
123
+ process.exit(ExitCode.USAGE_ERROR);
124
+ }
125
+ // T023: File exists without --force
126
+ if (result.error?.includes('already exists')) {
127
+ if (useJson) {
128
+ console.log(formatBackupResultJson(result));
129
+ }
130
+ else {
131
+ console.error(pc.red('Backup file already exists.'));
132
+ console.error(pc.dim('Use --force to overwrite.'));
133
+ }
134
+ process.exit(ExitCode.NOT_FOUND);
135
+ }
136
+ // T024: Insufficient disk space
137
+ if (result.error?.includes('Insufficient disk space')) {
138
+ if (useJson) {
139
+ console.log(formatBackupResultJson(result));
140
+ }
141
+ else {
142
+ console.error(pc.red('Insufficient disk space for backup.'));
143
+ }
144
+ process.exit(ExitCode.IO_ERROR);
145
+ }
146
+ // Generic error
147
+ if (useJson) {
148
+ console.log(formatBackupResultJson(result));
149
+ }
150
+ else {
151
+ console.error(formatBackupResult(result));
152
+ }
153
+ process.exit(ExitCode.GENERAL_ERROR);
154
+ }
155
+ // Success
156
+ if (useJson) {
157
+ console.log(formatBackupResultJson(result));
158
+ }
159
+ else {
160
+ console.log(formatBackupResult(result));
161
+ }
162
+ }
163
+ catch (error) {
164
+ handleError(error);
165
+ }
166
+ });
167
+ }
168
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../../src/cli/commands/backup.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBzC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoJ5D"}
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BzC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiM5D"}