cursor-history 0.6.0 → 0.9.1
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.
- package/LICENSE +7 -0
- package/README.md +371 -9
- package/dist/cli/commands/backup.d.ts +9 -0
- package/dist/cli/commands/backup.d.ts.map +1 -0
- package/dist/cli/commands/backup.js +168 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +38 -6
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/list-backups.d.ts +9 -0
- package/dist/cli/commands/list-backups.d.ts.map +1 -0
- package/dist/cli/commands/list-backups.js +166 -0
- package/dist/cli/commands/list-backups.js.map +1 -0
- package/dist/cli/commands/list.d.ts.map +1 -1
- package/dist/cli/commands/list.js +44 -9
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/migrate-session.d.ts +12 -0
- package/dist/cli/commands/migrate-session.d.ts.map +1 -0
- package/dist/cli/commands/migrate-session.js +125 -0
- package/dist/cli/commands/migrate-session.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +13 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +122 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/restore.d.ts +9 -0
- package/dist/cli/commands/restore.d.ts.map +1 -0
- package/dist/cli/commands/restore.js +192 -0
- package/dist/cli/commands/restore.js.map +1 -0
- package/dist/cli/commands/search.d.ts.map +1 -1
- package/dist/cli/commands/search.js +30 -2
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/show.d.ts.map +1 -1
- package/dist/cli/commands/show.js +31 -3
- package/dist/cli/commands/show.js.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/backup.d.ts +86 -0
- package/dist/core/backup.d.ts.map +1 -0
- package/dist/core/backup.js +727 -0
- package/dist/core/backup.js.map +1 -0
- package/dist/core/database/debug.d.ts +12 -0
- package/dist/core/database/debug.d.ts.map +1 -0
- package/dist/core/database/debug.js +16 -0
- package/dist/core/database/debug.js.map +1 -0
- package/dist/core/database/drivers/better-sqlite3.d.ts +11 -0
- package/dist/core/database/drivers/better-sqlite3.d.ts.map +1 -0
- package/dist/core/database/drivers/better-sqlite3.js +93 -0
- package/dist/core/database/drivers/better-sqlite3.js.map +1 -0
- package/dist/core/database/drivers/node-sqlite.d.ts +15 -0
- package/dist/core/database/drivers/node-sqlite.d.ts.map +1 -0
- package/dist/core/database/drivers/node-sqlite.js +135 -0
- package/dist/core/database/drivers/node-sqlite.js.map +1 -0
- package/dist/core/database/errors.d.ts +24 -0
- package/dist/core/database/errors.d.ts.map +1 -0
- package/dist/core/database/errors.js +38 -0
- package/dist/core/database/errors.js.map +1 -0
- package/dist/core/database/index.d.ts +98 -0
- package/dist/core/database/index.d.ts.map +1 -0
- package/dist/core/database/index.js +125 -0
- package/dist/core/database/index.js.map +1 -0
- package/dist/core/database/registry.d.ts +81 -0
- package/dist/core/database/registry.d.ts.map +1 -0
- package/dist/core/database/registry.js +171 -0
- package/dist/core/database/registry.js.map +1 -0
- package/dist/core/database/types.d.ts +115 -0
- package/dist/core/database/types.d.ts.map +1 -0
- package/dist/core/database/types.js +8 -0
- package/dist/core/database/types.js.map +1 -0
- package/dist/core/migrate.d.ts +40 -0
- package/dist/core/migrate.d.ts.map +1 -0
- package/dist/core/migrate.js +586 -0
- package/dist/core/migrate.js.map +1 -0
- package/dist/core/storage.d.ts +84 -10
- package/dist/core/storage.d.ts.map +1 -1
- package/dist/core/storage.js +319 -33
- package/dist/core/storage.js.map +1 -1
- package/dist/core/types.d.ts +252 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/lib/backup.d.ts +98 -0
- package/dist/lib/backup.d.ts.map +1 -0
- package/dist/lib/backup.js +108 -0
- package/dist/lib/backup.js.map +1 -0
- package/dist/lib/config.d.ts +3 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +10 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts +229 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +361 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/index.d.ts +133 -24
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +212 -49
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/platform.d.ts +11 -0
- package/dist/lib/platform.d.ts.map +1 -1
- package/dist/lib/platform.js +32 -0
- package/dist/lib/platform.js.map +1 -1
- package/dist/lib/types.d.ts +267 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +23 -3
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command for migrating all sessions between workspaces
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* cursor-history migrate <source> <destination>
|
|
6
|
+
* cursor-history migrate /old/project /new/project
|
|
7
|
+
* cursor-history migrate --copy /project /backup/project
|
|
8
|
+
* cursor-history migrate --dry-run /old/path /new/path
|
|
9
|
+
* cursor-history migrate --force /old/path /existing/path
|
|
10
|
+
*/
|
|
11
|
+
import pc from 'picocolors';
|
|
12
|
+
import { migrateWorkspace } from '../../core/migrate.js';
|
|
13
|
+
import { expandPath } from '../../lib/platform.js';
|
|
14
|
+
import { isWorkspaceNotFoundError, isSameWorkspaceError, isNoSessionsFoundError, isDestinationHasSessionsError, isNestedPathError, } from '../../lib/errors.js';
|
|
15
|
+
export function registerMigrateCommand(program) {
|
|
16
|
+
program
|
|
17
|
+
.command('migrate')
|
|
18
|
+
.description('Move or copy all sessions from one workspace to another')
|
|
19
|
+
.argument('<source>', 'Source workspace path')
|
|
20
|
+
.argument('<destination>', 'Destination workspace path')
|
|
21
|
+
.option('--dry-run', 'Preview migration without making changes')
|
|
22
|
+
.option('--copy', 'Copy sessions instead of moving (keeps originals)')
|
|
23
|
+
.option('-f, --force', 'Proceed even if destination has existing sessions')
|
|
24
|
+
.option('--debug', 'Show detailed path transformation logs')
|
|
25
|
+
.action(async (sourceArg, destinationArg, options) => {
|
|
26
|
+
const globalOptions = program.opts();
|
|
27
|
+
const dataPath = globalOptions.dataPath;
|
|
28
|
+
const jsonOutput = globalOptions.json || options.json;
|
|
29
|
+
try {
|
|
30
|
+
// Expand ~ in paths
|
|
31
|
+
const source = expandPath(sourceArg);
|
|
32
|
+
const destination = expandPath(destinationArg);
|
|
33
|
+
// Determine mode
|
|
34
|
+
const mode = options.copy ? 'copy' : 'move';
|
|
35
|
+
// Perform migration
|
|
36
|
+
const result = await migrateWorkspace({
|
|
37
|
+
source,
|
|
38
|
+
destination,
|
|
39
|
+
mode,
|
|
40
|
+
dryRun: options.dryRun ?? false,
|
|
41
|
+
force: options.force ?? false,
|
|
42
|
+
dataPath,
|
|
43
|
+
debug: options.debug ?? false,
|
|
44
|
+
});
|
|
45
|
+
// Output results
|
|
46
|
+
if (jsonOutput) {
|
|
47
|
+
console.log(JSON.stringify(result, null, 2));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
outputResult(result);
|
|
51
|
+
}
|
|
52
|
+
// Exit with error code if any failures
|
|
53
|
+
if (!result.success) {
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (jsonOutput) {
|
|
59
|
+
console.log(JSON.stringify({ error: formatError(error) }, null, 2));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.error(pc.red(formatError(error)));
|
|
63
|
+
}
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function outputResult(result) {
|
|
69
|
+
if (result.dryRun) {
|
|
70
|
+
console.log(pc.yellow('Dry run - no changes made\n'));
|
|
71
|
+
}
|
|
72
|
+
const action = result.dryRun ? 'Would migrate' : 'Migrated';
|
|
73
|
+
const modeLabel = result.mode === 'copy' ? 'copied' : 'moved';
|
|
74
|
+
console.log(`${action} ${pc.bold(result.totalSessions)} session(s) from:`);
|
|
75
|
+
console.log(` ${pc.cyan(result.source)}`);
|
|
76
|
+
console.log(`to:`);
|
|
77
|
+
console.log(` ${pc.cyan(result.destination)}\n`);
|
|
78
|
+
if (result.successCount > 0) {
|
|
79
|
+
const actionLabel = result.dryRun ? `would be ${modeLabel}` : modeLabel;
|
|
80
|
+
console.log(pc.green(`✓ ${result.successCount} session(s) ${actionLabel} successfully`));
|
|
81
|
+
}
|
|
82
|
+
if (result.failureCount > 0) {
|
|
83
|
+
console.log(pc.red(`✗ ${result.failureCount} session(s) failed to migrate:\n`));
|
|
84
|
+
for (const r of result.results.filter((r) => !r.success)) {
|
|
85
|
+
console.log(` ${pc.red('✗')} ${pc.cyan(r.sessionId.slice(0, 8))}...`);
|
|
86
|
+
console.log(` ${pc.red(r.error ?? 'Unknown error')}\n`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Overall status
|
|
90
|
+
if (result.success) {
|
|
91
|
+
console.log(pc.green('\n✓ Migration completed successfully'));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.log(pc.red('\n✗ Migration completed with errors'));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function formatError(error) {
|
|
98
|
+
if (isWorkspaceNotFoundError(error)) {
|
|
99
|
+
return `Workspace not found: ${error.path}\nPlease open the project in Cursor first to create the workspace.`;
|
|
100
|
+
}
|
|
101
|
+
if (isSameWorkspaceError(error)) {
|
|
102
|
+
return `Source and destination are the same: ${error.path}\nSpecify different source and destination paths.`;
|
|
103
|
+
}
|
|
104
|
+
if (isNoSessionsFoundError(error)) {
|
|
105
|
+
return `No sessions found for workspace: ${error.path}\nRun 'cursor-history list --workspace "${error.path}"' to verify.`;
|
|
106
|
+
}
|
|
107
|
+
if (isDestinationHasSessionsError(error)) {
|
|
108
|
+
return `Destination already has ${error.sessionCount} session(s): ${error.path}\nUse --force to proceed (will add sessions alongside existing ones).`;
|
|
109
|
+
}
|
|
110
|
+
if (isNestedPathError(error)) {
|
|
111
|
+
return `Destination is nested within source: ${error.destination} is inside ${error.source}\nThis would cause infinite path replacement loops. Choose a different destination.`;
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof Error) {
|
|
114
|
+
// Check for database lock error
|
|
115
|
+
if (error.message.includes('SQLITE_BUSY') || error.message.includes('database is locked')) {
|
|
116
|
+
return 'Database is locked. Please close Cursor and try again.';
|
|
117
|
+
}
|
|
118
|
+
return error.message;
|
|
119
|
+
}
|
|
120
|
+
return String(error);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/cli/commands/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,6BAA6B,EAC7B,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAY7B,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,yDAAyD,CAAC;SACtE,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC;SAC7C,QAAQ,CAAC,eAAe,EAAE,4BAA4B,CAAC;SACvD,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;SAC/D,MAAM,CAAC,QAAQ,EAAE,mDAAmD,CAAC;SACrE,MAAM,CAAC,aAAa,EAAE,mDAAmD,CAAC;SAC1E,MAAM,CAAC,SAAS,EAAE,wCAAwC,CAAC;SAC3D,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,cAAsB,EAAE,OAAuB,EAAE,EAAE;QACnF,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,EAA2C,CAAC;QAC9E,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC;QACxC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;QAEtD,IAAI,CAAC;YACH,oBAAoB;YACpB,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;YACrC,MAAM,WAAW,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;YAE/C,iBAAiB;YACjB,MAAM,IAAI,GAAkB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YAE3D,oBAAoB;YACpB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;gBACpC,MAAM;gBACN,WAAW;gBACX,IAAI;gBACJ,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;gBAC/B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;gBAC7B,QAAQ;gBACR,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;aAC9B,CAAC,CAAC;YAEH,iBAAiB;YACjB,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,YAAY,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;YAED,uCAAuC;YACvC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACtE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,YAAY,CAAC,MAAgC;IACpD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;IAC5D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAE9D,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAElD,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,YAAY,eAAe,WAAW,eAAe,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,kCAAkC,CAAC,CAAC,CAAC;QAEhF,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,iBAAiB;IACjB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,wBAAwB,KAAK,CAAC,IAAI,oEAAoE,CAAC;IAChH,CAAC;IAED,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,wCAAwC,KAAK,CAAC,IAAI,mDAAmD,CAAC;IAC/G,CAAC;IAED,IAAI,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,oCAAoC,KAAK,CAAC,IAAI,2CAA2C,KAAK,CAAC,IAAI,eAAe,CAAC;IAC5H,CAAC;IAED,IAAI,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO,2BAA2B,KAAK,CAAC,YAAY,gBAAgB,KAAK,CAAC,IAAI,uEAAuE,CAAC;IACxJ,CAAC;IAED,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,wCAAwC,KAAK,CAAC,WAAW,cAAc,KAAK,CAAC,MAAM,qFAAqF,CAAC;IAClL,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,gCAAgC;QAChC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC1F,OAAO,wDAAwD,CAAC;QAClE,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Restore command - restore chat history from a backup file
|
|
3
|
+
*/
|
|
4
|
+
import type { Command } from 'commander';
|
|
5
|
+
/**
|
|
6
|
+
* Register the restore command
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerRestoreCommand(program: Command): void;
|
|
9
|
+
//# sourceMappingURL=restore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/restore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqGzC;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiH7D"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Restore command - restore chat history from a backup file
|
|
3
|
+
*/
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { restoreBackup, validateBackup } from '../../core/backup.js';
|
|
7
|
+
import { handleError, ExitCode } from '../errors.js';
|
|
8
|
+
import { expandPath, contractPath } from '../../lib/platform.js';
|
|
9
|
+
/**
|
|
10
|
+
* Format duration for display
|
|
11
|
+
*/
|
|
12
|
+
function formatDuration(ms) {
|
|
13
|
+
if (ms < 1000) {
|
|
14
|
+
return `${ms}ms`;
|
|
15
|
+
}
|
|
16
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* T050: Progress display for restore command
|
|
20
|
+
*/
|
|
21
|
+
function displayProgress(progress) {
|
|
22
|
+
const phases = {
|
|
23
|
+
validating: '🔍 Validating backup integrity...',
|
|
24
|
+
extracting: '📦 Extracting files...',
|
|
25
|
+
finalizing: '✨ Finalizing restore...',
|
|
26
|
+
};
|
|
27
|
+
const phaseText = phases[progress.phase];
|
|
28
|
+
const fileProgress = progress.totalFiles > 0
|
|
29
|
+
? ` [${progress.filesCompleted}/${progress.totalFiles}]`
|
|
30
|
+
: '';
|
|
31
|
+
const currentFile = progress.currentFile ? ` ${pc.dim(progress.currentFile)}` : '';
|
|
32
|
+
// Show integrity status during validation
|
|
33
|
+
const integrityText = progress.phase === 'validating' && progress.integrityStatus === 'warnings'
|
|
34
|
+
? pc.yellow(' (some files have warnings)')
|
|
35
|
+
: '';
|
|
36
|
+
// Clear line and print progress
|
|
37
|
+
process.stdout.write(`\r${phaseText}${fileProgress}${currentFile}${integrityText}`.padEnd(80));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Format restore result for JSON output
|
|
41
|
+
*/
|
|
42
|
+
function formatRestoreResultJson(result) {
|
|
43
|
+
return JSON.stringify({
|
|
44
|
+
success: result.success,
|
|
45
|
+
targetPath: result.targetPath,
|
|
46
|
+
filesRestored: result.filesRestored,
|
|
47
|
+
durationMs: result.durationMs,
|
|
48
|
+
...(result.warnings.length > 0 && { warnings: result.warnings }),
|
|
49
|
+
...(result.error && { error: result.error }),
|
|
50
|
+
}, null, 2);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Format restore result for human-readable output
|
|
54
|
+
*/
|
|
55
|
+
function formatRestoreResult(result) {
|
|
56
|
+
const lines = [];
|
|
57
|
+
if (result.success) {
|
|
58
|
+
lines.push(pc.green('✓ Backup restored successfully!'));
|
|
59
|
+
lines.push('');
|
|
60
|
+
lines.push(` ${pc.bold('Target:')} ${contractPath(result.targetPath)}`);
|
|
61
|
+
lines.push(` ${pc.bold('Files restored:')} ${result.filesRestored}`);
|
|
62
|
+
lines.push(` ${pc.bold('Duration:')} ${formatDuration(result.durationMs)}`);
|
|
63
|
+
if (result.warnings.length > 0) {
|
|
64
|
+
lines.push('');
|
|
65
|
+
lines.push(pc.yellow(' Warnings:'));
|
|
66
|
+
for (const warning of result.warnings) {
|
|
67
|
+
lines.push(` ${pc.dim('•')} ${warning}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
lines.push(pc.red('✗ Restore failed'));
|
|
73
|
+
lines.push('');
|
|
74
|
+
if (result.error) {
|
|
75
|
+
lines.push(` ${pc.bold('Error:')} ${result.error}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return lines.join('\n');
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Register the restore command
|
|
82
|
+
*/
|
|
83
|
+
export function registerRestoreCommand(program) {
|
|
84
|
+
program
|
|
85
|
+
.command('restore <backup>')
|
|
86
|
+
.description('Restore chat history from a backup file')
|
|
87
|
+
.option('-t, --target <path>', 'Target Cursor data path (default: platform-specific Cursor data directory)')
|
|
88
|
+
.option('-f, --force', 'Overwrite existing data without prompting')
|
|
89
|
+
.action(async (backupArg, options, command) => {
|
|
90
|
+
const globalOptions = command.parent?.opts();
|
|
91
|
+
const useJson = options.json ?? globalOptions?.json ?? false;
|
|
92
|
+
const customPath = options.dataPath ?? globalOptions?.dataPath;
|
|
93
|
+
// Resolve backup path
|
|
94
|
+
const backupPath = expandPath(backupArg);
|
|
95
|
+
try {
|
|
96
|
+
// T051: Check if backup file exists
|
|
97
|
+
if (!existsSync(backupPath)) {
|
|
98
|
+
if (useJson) {
|
|
99
|
+
console.log(JSON.stringify({ error: 'Backup file not found', path: backupPath }));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.error(pc.red('Backup file not found:'));
|
|
103
|
+
console.error(pc.dim(` ${backupPath}`));
|
|
104
|
+
}
|
|
105
|
+
process.exit(ExitCode.USAGE_ERROR);
|
|
106
|
+
}
|
|
107
|
+
// T052: Validate backup before attempting restore
|
|
108
|
+
const validation = validateBackup(backupPath);
|
|
109
|
+
if (validation.status === 'invalid') {
|
|
110
|
+
if (useJson) {
|
|
111
|
+
console.log(JSON.stringify({
|
|
112
|
+
error: 'Invalid or corrupted backup',
|
|
113
|
+
errors: validation.errors
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.error(pc.red('Invalid or corrupted backup file:'));
|
|
118
|
+
for (const err of validation.errors) {
|
|
119
|
+
console.error(pc.dim(` ${err}`));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
process.exit(ExitCode.NOT_FOUND);
|
|
123
|
+
}
|
|
124
|
+
// Show warning for backups with integrity issues
|
|
125
|
+
if (validation.status === 'warnings' && !useJson) {
|
|
126
|
+
console.log(pc.yellow(`Warning: Backup has ${validation.corruptedFiles.length} file(s) with checksum mismatches.`));
|
|
127
|
+
console.log(pc.dim('These files will be restored but may be corrupted.\n'));
|
|
128
|
+
}
|
|
129
|
+
// Resolve target path if provided
|
|
130
|
+
const targetPath = options.target
|
|
131
|
+
? expandPath(options.target)
|
|
132
|
+
: (customPath ? expandPath(customPath) : undefined);
|
|
133
|
+
// Show progress if not JSON mode
|
|
134
|
+
const onProgress = useJson ? undefined : displayProgress;
|
|
135
|
+
// Perform restore
|
|
136
|
+
const result = restoreBackup({
|
|
137
|
+
backupPath,
|
|
138
|
+
targetPath,
|
|
139
|
+
force: options.force ?? false,
|
|
140
|
+
onProgress,
|
|
141
|
+
});
|
|
142
|
+
// Clear progress line
|
|
143
|
+
if (!useJson) {
|
|
144
|
+
process.stdout.write('\r'.padEnd(80) + '\r');
|
|
145
|
+
}
|
|
146
|
+
// Handle different error cases with appropriate exit codes
|
|
147
|
+
if (!result.success) {
|
|
148
|
+
// T053: Target exists without --force
|
|
149
|
+
if (result.error?.includes('already has Cursor data')) {
|
|
150
|
+
if (useJson) {
|
|
151
|
+
console.log(formatRestoreResultJson(result));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.error(pc.red('Target directory already has Cursor data.'));
|
|
155
|
+
console.error(pc.dim('Use --force to overwrite existing data.'));
|
|
156
|
+
}
|
|
157
|
+
process.exit(ExitCode.IO_ERROR);
|
|
158
|
+
}
|
|
159
|
+
// T054: Integrity check failures
|
|
160
|
+
if (result.error?.includes('integrity') || result.error?.includes('checksum')) {
|
|
161
|
+
if (useJson) {
|
|
162
|
+
console.log(formatRestoreResultJson(result));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
console.error(pc.red('Backup integrity check failed.'));
|
|
166
|
+
console.error(pc.dim(result.error));
|
|
167
|
+
}
|
|
168
|
+
process.exit(5); // Special exit code for integrity failures
|
|
169
|
+
}
|
|
170
|
+
// Generic error
|
|
171
|
+
if (useJson) {
|
|
172
|
+
console.log(formatRestoreResultJson(result));
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
console.error(formatRestoreResult(result));
|
|
176
|
+
}
|
|
177
|
+
process.exit(ExitCode.GENERAL_ERROR);
|
|
178
|
+
}
|
|
179
|
+
// Success
|
|
180
|
+
if (useJson) {
|
|
181
|
+
console.log(formatRestoreResultJson(result));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
console.log(formatRestoreResult(result));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
handleError(error);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=restore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../src/cli/commands/restore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/search.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/search.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwE5D"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Search command - search across chat sessions
|
|
3
3
|
*/
|
|
4
|
+
import pc from 'picocolors';
|
|
4
5
|
import { searchSessions } from '../../core/storage.js';
|
|
6
|
+
import { validateBackup } from '../../core/backup.js';
|
|
5
7
|
import { formatSearchResultsTable, formatSearchResultsJson } from '../formatters/index.js';
|
|
6
8
|
import { NoSearchResultsError, handleError } from '../errors.js';
|
|
7
|
-
import { expandPath } from '../../lib/platform.js';
|
|
9
|
+
import { expandPath, contractPath } from '../../lib/platform.js';
|
|
8
10
|
/**
|
|
9
11
|
* Register the search command
|
|
10
12
|
*/
|
|
@@ -14,15 +16,37 @@ export function registerSearchCommand(program) {
|
|
|
14
16
|
.description('Search chat history for a keyword')
|
|
15
17
|
.option('-n, --limit <number>', 'Maximum results to show', '10')
|
|
16
18
|
.option('-c, --context <chars>', 'Context characters around match', '50')
|
|
19
|
+
.option('-b, --backup <path>', 'Search in backup file instead of live data')
|
|
17
20
|
.action(async (query, options, command) => {
|
|
18
21
|
const globalOptions = command.parent?.opts();
|
|
19
22
|
const useJson = options.json ?? globalOptions?.json ?? false;
|
|
20
23
|
const customPath = options.dataPath ?? globalOptions?.dataPath;
|
|
21
24
|
const workspaceFilter = options.workspace ?? globalOptions?.workspace;
|
|
25
|
+
const backupPath = options.backup ? expandPath(options.backup) : undefined;
|
|
22
26
|
const limit = parseInt(options.limit ?? '10', 10);
|
|
23
27
|
const contextChars = parseInt(options.context ?? '50', 10);
|
|
28
|
+
// T036: Validate backup if searching from backup
|
|
29
|
+
if (backupPath) {
|
|
30
|
+
const validation = validateBackup(backupPath);
|
|
31
|
+
if (validation.status === 'invalid') {
|
|
32
|
+
if (useJson) {
|
|
33
|
+
console.log(JSON.stringify({ error: 'Invalid backup', errors: validation.errors }));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.error(pc.red('Invalid backup file:'));
|
|
37
|
+
for (const err of validation.errors) {
|
|
38
|
+
console.error(pc.dim(` ${err}`));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
process.exit(3);
|
|
42
|
+
}
|
|
43
|
+
if (validation.status === 'warnings' && !useJson) {
|
|
44
|
+
console.error(pc.yellow(`Warning: Backup has integrity issues (${validation.corruptedFiles.length} corrupted files)`));
|
|
45
|
+
console.error(pc.dim('Continuing with intact files...\n'));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
24
48
|
try {
|
|
25
|
-
const results = searchSessions(query, { limit, contextChars, workspacePath: workspaceFilter }, customPath ? expandPath(customPath) : undefined);
|
|
49
|
+
const results = await searchSessions(query, { limit, contextChars, workspacePath: workspaceFilter }, customPath ? expandPath(customPath) : undefined, backupPath);
|
|
26
50
|
if (results.length === 0) {
|
|
27
51
|
if (useJson) {
|
|
28
52
|
console.log(JSON.stringify({ query, count: 0, totalMatches: 0, results: [] }));
|
|
@@ -32,6 +56,10 @@ export function registerSearchCommand(program) {
|
|
|
32
56
|
}
|
|
33
57
|
return;
|
|
34
58
|
}
|
|
59
|
+
// Show backup source indicator if searching from backup
|
|
60
|
+
if (backupPath && !useJson) {
|
|
61
|
+
console.log(pc.dim(`Searching in backup: ${contractPath(backupPath)}\n`));
|
|
62
|
+
}
|
|
35
63
|
if (useJson) {
|
|
36
64
|
console.log(formatSearchResultsJson(results, query));
|
|
37
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/cli/commands/search.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/cli/commands/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/show.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/show.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBzC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+E1D"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Show command - display a single chat session in detail
|
|
3
3
|
*/
|
|
4
|
+
import pc from 'picocolors';
|
|
4
5
|
import { getSession, listSessions } from '../../core/storage.js';
|
|
6
|
+
import { validateBackup } from '../../core/backup.js';
|
|
5
7
|
import { formatSessionDetail, formatSessionJson } from '../formatters/index.js';
|
|
6
8
|
import { SessionNotFoundError, handleError } from '../errors.js';
|
|
7
|
-
import { expandPath } from '../../lib/platform.js';
|
|
9
|
+
import { expandPath, contractPath } from '../../lib/platform.js';
|
|
8
10
|
/**
|
|
9
11
|
* Register the show command
|
|
10
12
|
*/
|
|
@@ -16,21 +18,47 @@ export function registerShowCommand(program) {
|
|
|
16
18
|
.option('-t, --think', 'Show full thinking/reasoning text')
|
|
17
19
|
.option('--tool', 'Show full tool call details (commands, content, results)')
|
|
18
20
|
.option('-e, --error', 'Show full error messages (default: truncated)')
|
|
21
|
+
.option('-b, --backup <path>', 'Read from backup file instead of live data')
|
|
19
22
|
.action(async (indexArg, options, command) => {
|
|
20
23
|
const globalOptions = command.parent?.opts();
|
|
21
24
|
const useJson = options.json ?? globalOptions?.json ?? false;
|
|
22
25
|
const customPath = options.dataPath ?? globalOptions?.dataPath;
|
|
26
|
+
const backupPath = options.backup ? expandPath(options.backup) : undefined;
|
|
23
27
|
const index = parseInt(indexArg, 10);
|
|
24
28
|
if (isNaN(index) || index < 1) {
|
|
25
29
|
handleError(new Error(`Invalid index: ${indexArg}. Must be a positive number.`));
|
|
26
30
|
}
|
|
31
|
+
// T035: Validate backup if reading from backup
|
|
32
|
+
if (backupPath) {
|
|
33
|
+
const validation = validateBackup(backupPath);
|
|
34
|
+
if (validation.status === 'invalid') {
|
|
35
|
+
if (useJson) {
|
|
36
|
+
console.log(JSON.stringify({ error: 'Invalid backup', errors: validation.errors }));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.error(pc.red('Invalid backup file:'));
|
|
40
|
+
for (const err of validation.errors) {
|
|
41
|
+
console.error(pc.dim(` ${err}`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
process.exit(3);
|
|
45
|
+
}
|
|
46
|
+
if (validation.status === 'warnings' && !useJson) {
|
|
47
|
+
console.error(pc.yellow(`Warning: Backup has integrity issues (${validation.corruptedFiles.length} corrupted files)`));
|
|
48
|
+
console.error(pc.dim('Continuing with intact files...\n'));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
27
51
|
try {
|
|
28
|
-
const session = getSession(index, customPath ? expandPath(customPath) : undefined);
|
|
52
|
+
const session = await getSession(index, customPath ? expandPath(customPath) : undefined, backupPath);
|
|
29
53
|
if (!session) {
|
|
30
54
|
// Get max index for error message
|
|
31
|
-
const sessions = listSessions({ limit: 0, all: true }, customPath ? expandPath(customPath) : undefined);
|
|
55
|
+
const sessions = await listSessions({ limit: 0, all: true }, customPath ? expandPath(customPath) : undefined, backupPath);
|
|
32
56
|
throw new SessionNotFoundError(index, sessions.length);
|
|
33
57
|
}
|
|
58
|
+
// Show backup source indicator if reading from backup
|
|
59
|
+
if (backupPath && !useJson) {
|
|
60
|
+
console.log(pc.dim(`Reading from backup: ${contractPath(backupPath)}\n`));
|
|
61
|
+
}
|
|
34
62
|
if (useJson) {
|
|
35
63
|
console.log(formatSessionJson(session, session.workspacePath));
|
|
36
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/cli/commands/show.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/cli/commands/show.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -25,10 +25,20 @@ async function loadCommands() {
|
|
|
25
25
|
const { registerShowCommand } = await import('./commands/show.js');
|
|
26
26
|
const { registerSearchCommand } = await import('./commands/search.js');
|
|
27
27
|
const { registerExportCommand } = await import('./commands/export.js');
|
|
28
|
+
const { registerMigrateSessionCommand } = await import('./commands/migrate-session.js');
|
|
29
|
+
const { registerMigrateCommand } = await import('./commands/migrate.js');
|
|
30
|
+
const { registerBackupCommand } = await import('./commands/backup.js');
|
|
31
|
+
const { registerRestoreCommand } = await import('./commands/restore.js');
|
|
32
|
+
const { registerListBackupsCommand } = await import('./commands/list-backups.js');
|
|
28
33
|
registerListCommand(program);
|
|
29
34
|
registerShowCommand(program);
|
|
30
35
|
registerSearchCommand(program);
|
|
31
36
|
registerExportCommand(program);
|
|
37
|
+
registerMigrateSessionCommand(program);
|
|
38
|
+
registerMigrateCommand(program);
|
|
39
|
+
registerBackupCommand(program);
|
|
40
|
+
registerRestoreCommand(program);
|
|
41
|
+
registerListBackupsCommand(program);
|
|
32
42
|
}
|
|
33
43
|
// Main execution
|
|
34
44
|
async function main() {
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEpD,iCAAiC;AACjC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAE1F,CAAC;AAEF,sBAAsB;AACtB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,gBAAgB,CAAC;KACtB,WAAW,CAAC,yCAAyC,CAAC;KACtD,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,qBAAqB,CAAC;KACpE,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;KACzC,MAAM,CAAC,oBAAoB,EAAE,8BAA8B,CAAC;KAC5D,MAAM,CAAC,wBAAwB,EAAE,0BAA0B,CAAC,CAAC;AAEhE,oDAAoD;AACpD,KAAK,UAAU,YAAY;IACzB,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACnE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACnE,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACvE,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core backup and restore functionality
|
|
3
|
+
*
|
|
4
|
+
* This module provides low-level backup operations:
|
|
5
|
+
* - SQLite database backup using pluggable driver system
|
|
6
|
+
* - Zip creation/extraction using adm-zip
|
|
7
|
+
* - Manifest generation with checksums
|
|
8
|
+
* - Integrity validation
|
|
9
|
+
*/
|
|
10
|
+
import type { Database as DatabaseInterface } from './database/types.js';
|
|
11
|
+
import type { BackupManifest, BackupFileEntry, BackupStats, BackupConfig, BackupResult, RestoreConfig, RestoreResult, BackupValidation, BackupInfo } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* T005: Get the default backup directory path
|
|
14
|
+
* Returns ~/cursor-history-backups/
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDefaultBackupDir(): string;
|
|
17
|
+
/**
|
|
18
|
+
* T006: Compute SHA-256 checksum of a buffer
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeChecksum(buffer: Buffer): string;
|
|
21
|
+
/**
|
|
22
|
+
* T007: Generate a timestamped backup filename
|
|
23
|
+
* Format: cursor_history_backup_YYYY-MM-DD_HHMMSS.zip
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateBackupFilename(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Information about a discovered database file
|
|
28
|
+
*/
|
|
29
|
+
export interface DatabaseFileInfo {
|
|
30
|
+
/** Absolute path to the database file */
|
|
31
|
+
absolutePath: string;
|
|
32
|
+
/** Path relative to the Cursor data directory (for zip storage) */
|
|
33
|
+
relativePath: string;
|
|
34
|
+
/** File size in bytes */
|
|
35
|
+
size: number;
|
|
36
|
+
/** File type */
|
|
37
|
+
type: 'global-db' | 'workspace-db' | 'workspace-json';
|
|
38
|
+
/** Workspace ID (for workspace DBs) */
|
|
39
|
+
workspaceId?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* T008: Scan for all database files in the Cursor data directory
|
|
43
|
+
* Discovers globalStorage/state.vscdb and workspaceStorage/{id}/state.vscdb
|
|
44
|
+
*/
|
|
45
|
+
export declare function scanDatabaseFiles(dataPath: string): DatabaseFileInfo[];
|
|
46
|
+
/**
|
|
47
|
+
* T009: Create a manifest object from file entries and stats
|
|
48
|
+
*/
|
|
49
|
+
export declare function createManifest(files: BackupFileEntry[], stats: BackupStats): BackupManifest;
|
|
50
|
+
/**
|
|
51
|
+
* T013: Check if there's enough disk space for the backup
|
|
52
|
+
* Returns { available, required, sufficient }
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkDiskSpace(outputPath: string, requiredBytes: number): {
|
|
55
|
+
available: number;
|
|
56
|
+
required: number;
|
|
57
|
+
sufficient: boolean;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* T012-T016: Create a full backup of all Cursor chat history
|
|
61
|
+
*/
|
|
62
|
+
export declare function createBackup(config?: BackupConfig): Promise<BackupResult>;
|
|
63
|
+
/**
|
|
64
|
+
* T025: Open a database from a backup zip file
|
|
65
|
+
* Uses the pluggable driver system to open the database.
|
|
66
|
+
* Extracts to a temp file since SQLite needs file access.
|
|
67
|
+
* Returns a Database interface compatible with the pluggable driver system.
|
|
68
|
+
*/
|
|
69
|
+
export declare function openBackupDatabase(backupPath: string, dbPath: string): DatabaseInterface;
|
|
70
|
+
/**
|
|
71
|
+
* Read manifest from a backup file
|
|
72
|
+
*/
|
|
73
|
+
export declare function readBackupManifest(backupPath: string): BackupManifest | null;
|
|
74
|
+
/**
|
|
75
|
+
* T026: Validate backup integrity
|
|
76
|
+
*/
|
|
77
|
+
export declare function validateBackup(backupPath: string): BackupValidation;
|
|
78
|
+
/**
|
|
79
|
+
* T040-T045: Restore backup to Cursor data directory
|
|
80
|
+
*/
|
|
81
|
+
export declare function restoreBackup(config: RestoreConfig): RestoreResult;
|
|
82
|
+
/**
|
|
83
|
+
* T055-T057: List all backup files in a directory
|
|
84
|
+
*/
|
|
85
|
+
export declare function listBackups(directory?: string): BackupInfo[];
|
|
86
|
+
//# sourceMappingURL=backup.d.ts.map
|