ownkey 0.6.0 → 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.
- package/README.md +105 -151
- package/dist/ai/factory.d.ts.map +1 -1
- package/dist/ai/factory.js +5 -1
- package/dist/ai/factory.js.map +1 -1
- package/dist/ai/ollama.d.ts +30 -0
- package/dist/ai/ollama.d.ts.map +1 -0
- package/dist/ai/ollama.js +175 -0
- package/dist/ai/ollama.js.map +1 -0
- package/dist/commands/apply.d.ts.map +1 -1
- package/dist/commands/apply.js +63 -14
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/suggest.d.ts.map +1 -1
- package/dist/commands/suggest.js +4 -0
- package/dist/commands/suggest.js.map +1 -1
- package/dist/commands/undo.d.ts +3 -0
- package/dist/commands/undo.d.ts.map +1 -0
- package/dist/commands/undo.js +197 -0
- package/dist/commands/undo.js.map +1 -0
- package/dist/core/apply/engine.d.ts +36 -0
- package/dist/core/apply/engine.d.ts.map +1 -0
- package/dist/core/apply/engine.js +179 -0
- package/dist/core/apply/engine.js.map +1 -0
- package/dist/core/apply/index.d.ts +3 -0
- package/dist/core/apply/index.d.ts.map +1 -0
- package/dist/core/apply/index.js +3 -0
- package/dist/core/apply/index.js.map +1 -0
- package/dist/core/apply/interactive.d.ts +53 -0
- package/dist/core/apply/interactive.d.ts.map +1 -0
- package/dist/core/apply/interactive.js +188 -0
- package/dist/core/apply/interactive.js.map +1 -0
- package/dist/core/backup/index.d.ts +2 -0
- package/dist/core/backup/index.d.ts.map +1 -0
- package/dist/core/backup/index.js +2 -0
- package/dist/core/backup/index.js.map +1 -0
- package/dist/core/backup/manager.d.ts +49 -0
- package/dist/core/backup/manager.d.ts.map +1 -0
- package/dist/core/backup/manager.js +133 -0
- package/dist/core/backup/manager.js.map +1 -0
- package/dist/core/diff/applier.d.ts +22 -0
- package/dist/core/diff/applier.d.ts.map +1 -0
- package/dist/core/diff/applier.js +98 -0
- package/dist/core/diff/applier.js.map +1 -0
- package/dist/core/diff/index.d.ts +4 -0
- package/dist/core/diff/index.d.ts.map +1 -0
- package/dist/core/diff/index.js +4 -0
- package/dist/core/diff/index.js.map +1 -0
- package/dist/core/diff/parser.d.ts +32 -0
- package/dist/core/diff/parser.d.ts.map +1 -0
- package/dist/core/diff/parser.js +108 -0
- package/dist/core/diff/parser.js.map +1 -0
- package/dist/core/diff/validator.d.ts +21 -0
- package/dist/core/diff/validator.d.ts.map +1 -0
- package/dist/core/diff/validator.js +86 -0
- package/dist/core/diff/validator.js.map +1 -0
- package/dist/db/client.d.ts +2 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +14 -5
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrations/002_applies.sql +32 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ParsedDiff } from '../diff/index.js';
|
|
2
|
+
export interface InteractiveOptions {
|
|
3
|
+
showFullDiff?: boolean;
|
|
4
|
+
allowPartial?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface InteractiveResult {
|
|
7
|
+
confirmed: boolean;
|
|
8
|
+
selectedHunks?: number[];
|
|
9
|
+
skipAll?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare class InteractiveMode {
|
|
12
|
+
/**
|
|
13
|
+
* Show diff preview and ask for confirmation
|
|
14
|
+
*/
|
|
15
|
+
static confirmApply(diff: ParsedDiff, options?: InteractiveOptions): Promise<InteractiveResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Show summary of changes
|
|
18
|
+
*/
|
|
19
|
+
private static showSummary;
|
|
20
|
+
/**
|
|
21
|
+
* Show full diff with syntax highlighting
|
|
22
|
+
*/
|
|
23
|
+
private static showFullDiff;
|
|
24
|
+
/**
|
|
25
|
+
* Print a single change line with color
|
|
26
|
+
*/
|
|
27
|
+
private static printChange;
|
|
28
|
+
/**
|
|
29
|
+
* Let user select which hunks to apply
|
|
30
|
+
*/
|
|
31
|
+
private static selectHunks;
|
|
32
|
+
/**
|
|
33
|
+
* Show progress for multiple files
|
|
34
|
+
*/
|
|
35
|
+
static showProgress(current: number, total: number, fileName: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Create a progress bar
|
|
38
|
+
*/
|
|
39
|
+
private static createProgressBar;
|
|
40
|
+
/**
|
|
41
|
+
* Show success message
|
|
42
|
+
*/
|
|
43
|
+
static showSuccess(filesModified: number, backupId?: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Show error message
|
|
46
|
+
*/
|
|
47
|
+
static showError(error: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Show warning message
|
|
50
|
+
*/
|
|
51
|
+
static showWarnings(warnings: string[]): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=interactive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../../src/core/apply/interactive.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,eAAe;IACxB;;OAEG;WACU,YAAY,CACrB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,iBAAiB,CAAC;IAmD7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IA+B1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAkB3B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAgB1B;;OAEG;mBACkB,WAAW;IA+BhC;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAS3E;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAUhC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAUlE;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKrC;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI;CAShD"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
export class InteractiveMode {
|
|
4
|
+
/**
|
|
5
|
+
* Show diff preview and ask for confirmation
|
|
6
|
+
*/
|
|
7
|
+
static async confirmApply(diff, options = {}) {
|
|
8
|
+
const { showFullDiff = false, allowPartial = false } = options;
|
|
9
|
+
// Show diff preview
|
|
10
|
+
console.log(chalk.bold(`\n📝 Changes to ${chalk.cyan(diff.filePath)}:\n`));
|
|
11
|
+
if (showFullDiff) {
|
|
12
|
+
this.showFullDiff(diff);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this.showSummary(diff);
|
|
16
|
+
}
|
|
17
|
+
// Ask for confirmation
|
|
18
|
+
const { action } = await inquirer.prompt([
|
|
19
|
+
{
|
|
20
|
+
type: 'list',
|
|
21
|
+
name: 'action',
|
|
22
|
+
message: 'Apply this change?',
|
|
23
|
+
choices: [
|
|
24
|
+
{ name: 'Yes - Apply this change', value: 'yes' },
|
|
25
|
+
{ name: 'No - Skip this change', value: 'no' },
|
|
26
|
+
{ name: 'View full diff', value: 'diff' },
|
|
27
|
+
...(allowPartial ? [{ name: 'Select hunks to apply', value: 'partial' }] : []),
|
|
28
|
+
{ name: 'Quit - Cancel all changes', value: 'quit' },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
switch (action) {
|
|
33
|
+
case 'yes':
|
|
34
|
+
return { confirmed: true };
|
|
35
|
+
case 'no':
|
|
36
|
+
return { confirmed: false };
|
|
37
|
+
case 'diff':
|
|
38
|
+
this.showFullDiff(diff);
|
|
39
|
+
return this.confirmApply(diff, options);
|
|
40
|
+
case 'partial':
|
|
41
|
+
const selectedHunks = await this.selectHunks(diff);
|
|
42
|
+
return { confirmed: true, selectedHunks };
|
|
43
|
+
case 'quit':
|
|
44
|
+
return { confirmed: false, skipAll: true };
|
|
45
|
+
default:
|
|
46
|
+
return { confirmed: false };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Show summary of changes
|
|
51
|
+
*/
|
|
52
|
+
static showSummary(diff) {
|
|
53
|
+
let additions = 0;
|
|
54
|
+
let deletions = 0;
|
|
55
|
+
for (const hunk of diff.hunks) {
|
|
56
|
+
for (const change of hunk.changes) {
|
|
57
|
+
if (change.type === 'add')
|
|
58
|
+
additions++;
|
|
59
|
+
if (change.type === 'remove')
|
|
60
|
+
deletions++;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
console.log(` ${chalk.green(`+${additions}`)} additions, ${chalk.red(`-${deletions}`)} deletions`);
|
|
64
|
+
console.log(` ${diff.hunks.length} hunk(s)\n`);
|
|
65
|
+
// Show first few lines of first hunk
|
|
66
|
+
if (diff.hunks.length > 0) {
|
|
67
|
+
const firstHunk = diff.hunks[0];
|
|
68
|
+
const preview = firstHunk.changes.slice(0, 5);
|
|
69
|
+
console.log(chalk.gray(' Preview:'));
|
|
70
|
+
for (const change of preview) {
|
|
71
|
+
this.printChange(change, ' ');
|
|
72
|
+
}
|
|
73
|
+
if (firstHunk.changes.length > 5) {
|
|
74
|
+
console.log(chalk.gray(` ... and ${firstHunk.changes.length - 5} more lines`));
|
|
75
|
+
}
|
|
76
|
+
console.log();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Show full diff with syntax highlighting
|
|
81
|
+
*/
|
|
82
|
+
static showFullDiff(diff) {
|
|
83
|
+
console.log(chalk.bold(`\n--- a/${diff.oldPath || diff.filePath}`));
|
|
84
|
+
console.log(chalk.bold(`+++ b/${diff.newPath || diff.filePath}\n`));
|
|
85
|
+
for (const hunk of diff.hunks) {
|
|
86
|
+
console.log(chalk.cyan(`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`));
|
|
87
|
+
for (const change of hunk.changes) {
|
|
88
|
+
this.printChange(change);
|
|
89
|
+
}
|
|
90
|
+
console.log();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Print a single change line with color
|
|
95
|
+
*/
|
|
96
|
+
static printChange(change, indent = '') {
|
|
97
|
+
const line = `${indent}${change.content}`;
|
|
98
|
+
switch (change.type) {
|
|
99
|
+
case 'add':
|
|
100
|
+
console.log(chalk.green(`+${line}`));
|
|
101
|
+
break;
|
|
102
|
+
case 'remove':
|
|
103
|
+
console.log(chalk.red(`-${line}`));
|
|
104
|
+
break;
|
|
105
|
+
case 'context':
|
|
106
|
+
console.log(chalk.gray(` ${line}`));
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Let user select which hunks to apply
|
|
112
|
+
*/
|
|
113
|
+
static async selectHunks(diff) {
|
|
114
|
+
console.log(chalk.bold('\n📋 Select hunks to apply:\n'));
|
|
115
|
+
const choices = diff.hunks.map((hunk, index) => {
|
|
116
|
+
let additions = 0;
|
|
117
|
+
let deletions = 0;
|
|
118
|
+
for (const change of hunk.changes) {
|
|
119
|
+
if (change.type === 'add')
|
|
120
|
+
additions++;
|
|
121
|
+
if (change.type === 'remove')
|
|
122
|
+
deletions++;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
name: `Hunk ${index + 1}: Lines ${hunk.oldStart}-${hunk.oldStart + hunk.oldLines} (${chalk.green(`+${additions}`)} ${chalk.red(`-${deletions}`)})`,
|
|
126
|
+
value: index,
|
|
127
|
+
checked: true,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
const { selected } = await inquirer.prompt([
|
|
131
|
+
{
|
|
132
|
+
type: 'checkbox',
|
|
133
|
+
name: 'selected',
|
|
134
|
+
message: 'Select hunks to apply:',
|
|
135
|
+
choices,
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
return selected;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Show progress for multiple files
|
|
142
|
+
*/
|
|
143
|
+
static showProgress(current, total, fileName) {
|
|
144
|
+
const percentage = Math.round((current / total) * 100);
|
|
145
|
+
const bar = this.createProgressBar(percentage, 30);
|
|
146
|
+
console.log(`\n${chalk.cyan(`[${current}/${total}]`)} ${bar} ${percentage}% - ${chalk.gray(fileName)}`);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create a progress bar
|
|
150
|
+
*/
|
|
151
|
+
static createProgressBar(percentage, width) {
|
|
152
|
+
const filled = Math.round((percentage / 100) * width);
|
|
153
|
+
const empty = width - filled;
|
|
154
|
+
return (chalk.green('█'.repeat(filled)) +
|
|
155
|
+
chalk.gray('░'.repeat(empty)));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Show success message
|
|
159
|
+
*/
|
|
160
|
+
static showSuccess(filesModified, backupId) {
|
|
161
|
+
console.log(chalk.bold.green('\n✨ Changes applied successfully!\n'));
|
|
162
|
+
console.log(` Files modified: ${chalk.cyan(filesModified)}`);
|
|
163
|
+
if (backupId) {
|
|
164
|
+
console.log(` Backup created: ${chalk.gray(backupId)}`);
|
|
165
|
+
console.log(chalk.yellow(`\n To undo: ${chalk.cyan(`ownkey undo ${backupId}`)}\n`));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Show error message
|
|
170
|
+
*/
|
|
171
|
+
static showError(error) {
|
|
172
|
+
console.log(chalk.bold.red('\n❌ Apply failed!\n'));
|
|
173
|
+
console.log(chalk.red(` Error: ${error}\n`));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Show warning message
|
|
177
|
+
*/
|
|
178
|
+
static showWarnings(warnings) {
|
|
179
|
+
if (warnings.length === 0)
|
|
180
|
+
return;
|
|
181
|
+
console.log(chalk.bold.yellow('\n⚠️ Warnings:\n'));
|
|
182
|
+
for (const warning of warnings) {
|
|
183
|
+
console.log(chalk.yellow(` • ${warning}`));
|
|
184
|
+
}
|
|
185
|
+
console.log();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../../src/core/apply/interactive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/backup/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/backup/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8B,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface BackupMetadata {
|
|
2
|
+
id: string;
|
|
3
|
+
timestamp: Date;
|
|
4
|
+
files: string[];
|
|
5
|
+
reason: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BackupInfo {
|
|
8
|
+
id: string;
|
|
9
|
+
timestamp: Date;
|
|
10
|
+
fileCount: number;
|
|
11
|
+
reason: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class BackupManager {
|
|
14
|
+
private backupDir;
|
|
15
|
+
constructor(backupDir?: string);
|
|
16
|
+
/**
|
|
17
|
+
* Create a backup of files before applying changes
|
|
18
|
+
*/
|
|
19
|
+
createBackup(files: string[], reason?: string): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* List all available backups
|
|
22
|
+
*/
|
|
23
|
+
listBackups(): Promise<BackupInfo[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Get backup metadata
|
|
26
|
+
*/
|
|
27
|
+
getBackupMetadata(backupId: string): Promise<BackupMetadata | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Restore files from a backup
|
|
30
|
+
*/
|
|
31
|
+
restore(backupId: string, files?: string[]): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Delete a backup
|
|
34
|
+
*/
|
|
35
|
+
deleteBackup(backupId: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Clean old backups (keep last N)
|
|
38
|
+
*/
|
|
39
|
+
cleanOldBackups(keep?: number): Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Generate a unique backup ID
|
|
42
|
+
*/
|
|
43
|
+
private generateBackupId;
|
|
44
|
+
/**
|
|
45
|
+
* Get backup directory path
|
|
46
|
+
*/
|
|
47
|
+
getBackupDir(): string;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/backup/manager.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,CAAC,EAAE,MAAM;IAI9B;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,MAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAsC9E;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAyB1C;;OAEG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAUzE;;OAEG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhE;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnD;;OAEG;IACG,eAAe,CAAC,IAAI,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAezD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;OAEG;IACH,YAAY,IAAI,MAAM;CAGzB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { mkdir, copyFile, readdir, rm, readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import { join, dirname, relative } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
export class BackupManager {
|
|
6
|
+
backupDir;
|
|
7
|
+
constructor(backupDir) {
|
|
8
|
+
this.backupDir = backupDir || join(homedir(), '.ownkey', 'backups');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a backup of files before applying changes
|
|
12
|
+
*/
|
|
13
|
+
async createBackup(files, reason = 'apply') {
|
|
14
|
+
const backupId = this.generateBackupId();
|
|
15
|
+
const backupPath = join(this.backupDir, backupId);
|
|
16
|
+
// Create backup directory
|
|
17
|
+
await mkdir(backupPath, { recursive: true });
|
|
18
|
+
// Copy each file
|
|
19
|
+
const copiedFiles = [];
|
|
20
|
+
for (const file of files) {
|
|
21
|
+
const relativePath = relative(process.cwd(), file);
|
|
22
|
+
const targetPath = join(backupPath, relativePath);
|
|
23
|
+
// Create parent directories
|
|
24
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
25
|
+
// Copy file
|
|
26
|
+
await copyFile(file, targetPath);
|
|
27
|
+
copiedFiles.push(relativePath);
|
|
28
|
+
}
|
|
29
|
+
// Save metadata
|
|
30
|
+
const metadata = {
|
|
31
|
+
id: backupId,
|
|
32
|
+
timestamp: new Date(),
|
|
33
|
+
files: copiedFiles,
|
|
34
|
+
reason,
|
|
35
|
+
};
|
|
36
|
+
await writeFile(join(backupPath, 'metadata.json'), JSON.stringify(metadata, null, 2), 'utf-8');
|
|
37
|
+
return backupId;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* List all available backups
|
|
41
|
+
*/
|
|
42
|
+
async listBackups() {
|
|
43
|
+
if (!existsSync(this.backupDir)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const entries = await readdir(this.backupDir);
|
|
47
|
+
const backups = [];
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
const metadataPath = join(this.backupDir, entry, 'metadata.json');
|
|
50
|
+
if (existsSync(metadataPath)) {
|
|
51
|
+
const metadata = JSON.parse(await readFile(metadataPath, 'utf-8'));
|
|
52
|
+
backups.push({
|
|
53
|
+
id: metadata.id,
|
|
54
|
+
timestamp: new Date(metadata.timestamp),
|
|
55
|
+
fileCount: metadata.files.length,
|
|
56
|
+
reason: metadata.reason,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Sort by timestamp (newest first)
|
|
61
|
+
return backups.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get backup metadata
|
|
65
|
+
*/
|
|
66
|
+
async getBackupMetadata(backupId) {
|
|
67
|
+
const metadataPath = join(this.backupDir, backupId, 'metadata.json');
|
|
68
|
+
if (!existsSync(metadataPath)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const metadata = JSON.parse(await readFile(metadataPath, 'utf-8'));
|
|
72
|
+
return metadata;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Restore files from a backup
|
|
76
|
+
*/
|
|
77
|
+
async restore(backupId, files) {
|
|
78
|
+
const metadata = await this.getBackupMetadata(backupId);
|
|
79
|
+
if (!metadata) {
|
|
80
|
+
throw new Error(`Backup not found: ${backupId}`);
|
|
81
|
+
}
|
|
82
|
+
const backupPath = join(this.backupDir, backupId);
|
|
83
|
+
const filesToRestore = files || metadata.files;
|
|
84
|
+
for (const file of filesToRestore) {
|
|
85
|
+
const sourcePath = join(backupPath, file);
|
|
86
|
+
const targetPath = join(process.cwd(), file);
|
|
87
|
+
if (existsSync(sourcePath)) {
|
|
88
|
+
// Create parent directories
|
|
89
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
90
|
+
// Restore file
|
|
91
|
+
await copyFile(sourcePath, targetPath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Delete a backup
|
|
97
|
+
*/
|
|
98
|
+
async deleteBackup(backupId) {
|
|
99
|
+
const backupPath = join(this.backupDir, backupId);
|
|
100
|
+
if (existsSync(backupPath)) {
|
|
101
|
+
await rm(backupPath, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clean old backups (keep last N)
|
|
106
|
+
*/
|
|
107
|
+
async cleanOldBackups(keep = 10) {
|
|
108
|
+
const backups = await this.listBackups();
|
|
109
|
+
if (backups.length <= keep) {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
const toDelete = backups.slice(keep);
|
|
113
|
+
for (const backup of toDelete) {
|
|
114
|
+
await this.deleteBackup(backup.id);
|
|
115
|
+
}
|
|
116
|
+
return toDelete.length;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Generate a unique backup ID
|
|
120
|
+
*/
|
|
121
|
+
generateBackupId() {
|
|
122
|
+
const now = new Date();
|
|
123
|
+
const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
|
124
|
+
return timestamp;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get backup directory path
|
|
128
|
+
*/
|
|
129
|
+
getBackupDir() {
|
|
130
|
+
return this.backupDir;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/core/backup/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ParsedDiff } from './parser.js';
|
|
2
|
+
export interface ApplyResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
filePath: string;
|
|
5
|
+
linesChanged: number;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class DiffApplier {
|
|
9
|
+
/**
|
|
10
|
+
* Apply a parsed diff to a file
|
|
11
|
+
*/
|
|
12
|
+
static apply(diff: ParsedDiff, targetPath: string): Promise<ApplyResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Apply a single hunk to file lines
|
|
15
|
+
*/
|
|
16
|
+
private static applyHunk;
|
|
17
|
+
/**
|
|
18
|
+
* Dry run - show what would change without actually applying
|
|
19
|
+
*/
|
|
20
|
+
static dryRun(diff: ParsedDiff, targetPath: string): Promise<string[]>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=applier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applier.d.ts","sourceRoot":"","sources":["../../../src/core/diff/applier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,aAAa,CAAC;AAI/C,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,WAAW;IACpB;;OAEG;WACU,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA6C9E;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IA0CxB;;OAEG;WACU,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAY/E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import { DiffValidator } from './validator.js';
|
|
3
|
+
export class DiffApplier {
|
|
4
|
+
/**
|
|
5
|
+
* Apply a parsed diff to a file
|
|
6
|
+
*/
|
|
7
|
+
static async apply(diff, targetPath) {
|
|
8
|
+
try {
|
|
9
|
+
// Validate first
|
|
10
|
+
const validation = await DiffValidator.validate(diff, targetPath);
|
|
11
|
+
if (!validation.valid) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
filePath: targetPath,
|
|
15
|
+
linesChanged: 0,
|
|
16
|
+
error: `Validation failed: ${validation.errors.join(', ')}`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// Read file
|
|
20
|
+
const fileContent = await readFile(targetPath, 'utf-8');
|
|
21
|
+
const lines = fileContent.split('\n');
|
|
22
|
+
// Apply hunks
|
|
23
|
+
let linesChanged = 0;
|
|
24
|
+
let offset = 0; // Track line number shifts
|
|
25
|
+
for (const hunk of diff.hunks) {
|
|
26
|
+
const result = this.applyHunk(hunk, lines, offset);
|
|
27
|
+
linesChanged += result.linesChanged;
|
|
28
|
+
offset += result.offset;
|
|
29
|
+
}
|
|
30
|
+
// Write back
|
|
31
|
+
await writeFile(targetPath, lines.join('\n'), 'utf-8');
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
filePath: targetPath,
|
|
35
|
+
linesChanged,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
filePath: targetPath,
|
|
42
|
+
linesChanged: 0,
|
|
43
|
+
error: error.message,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Apply a single hunk to file lines
|
|
49
|
+
*/
|
|
50
|
+
static applyHunk(hunk, lines, offset) {
|
|
51
|
+
let linesChanged = 0;
|
|
52
|
+
let currentOffset = offset;
|
|
53
|
+
let fileLineIndex = hunk.oldStart - 1 + offset;
|
|
54
|
+
// Collect changes to apply
|
|
55
|
+
const toRemove = [];
|
|
56
|
+
const toAdd = [];
|
|
57
|
+
for (const change of hunk.changes) {
|
|
58
|
+
if (change.type === 'remove') {
|
|
59
|
+
toRemove.push(fileLineIndex);
|
|
60
|
+
fileLineIndex++;
|
|
61
|
+
linesChanged++;
|
|
62
|
+
}
|
|
63
|
+
else if (change.type === 'add') {
|
|
64
|
+
toAdd.push({ index: fileLineIndex, content: change.content });
|
|
65
|
+
fileLineIndex++;
|
|
66
|
+
currentOffset++;
|
|
67
|
+
linesChanged++;
|
|
68
|
+
}
|
|
69
|
+
else if (change.type === 'context') {
|
|
70
|
+
fileLineIndex++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Apply removals (in reverse to maintain indices)
|
|
74
|
+
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
75
|
+
lines.splice(toRemove[i], 1);
|
|
76
|
+
currentOffset--;
|
|
77
|
+
}
|
|
78
|
+
// Apply additions
|
|
79
|
+
for (const add of toAdd) {
|
|
80
|
+
lines.splice(add.index, 0, add.content);
|
|
81
|
+
}
|
|
82
|
+
return { linesChanged, offset: currentOffset - offset };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Dry run - show what would change without actually applying
|
|
86
|
+
*/
|
|
87
|
+
static async dryRun(diff, targetPath) {
|
|
88
|
+
const fileContent = await readFile(targetPath, 'utf-8');
|
|
89
|
+
const lines = fileContent.split('\n').slice(); // Copy
|
|
90
|
+
let offset = 0;
|
|
91
|
+
for (const hunk of diff.hunks) {
|
|
92
|
+
const result = this.applyHunk(hunk, lines, offset);
|
|
93
|
+
offset += result.offset;
|
|
94
|
+
}
|
|
95
|
+
return lines;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=applier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applier.js","sourceRoot":"","sources":["../../../src/core/diff/applier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/diff/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/diff/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA4B,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,aAAa,EAAoB,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAe,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff Parser - Parse unified diff format
|
|
3
|
+
*/
|
|
4
|
+
export interface ParsedDiff {
|
|
5
|
+
filePath: string;
|
|
6
|
+
oldPath?: string;
|
|
7
|
+
newPath?: string;
|
|
8
|
+
hunks: Hunk[];
|
|
9
|
+
}
|
|
10
|
+
export interface Hunk {
|
|
11
|
+
oldStart: number;
|
|
12
|
+
oldLines: number;
|
|
13
|
+
newStart: number;
|
|
14
|
+
newLines: number;
|
|
15
|
+
changes: Change[];
|
|
16
|
+
}
|
|
17
|
+
export interface Change {
|
|
18
|
+
type: 'add' | 'remove' | 'context';
|
|
19
|
+
content: string;
|
|
20
|
+
lineNumber: number;
|
|
21
|
+
}
|
|
22
|
+
export declare class DiffParser {
|
|
23
|
+
/**
|
|
24
|
+
* Parse unified diff format into structured data
|
|
25
|
+
*/
|
|
26
|
+
static parse(diffText: string): ParsedDiff[];
|
|
27
|
+
/**
|
|
28
|
+
* Generate unified diff format from structured data
|
|
29
|
+
*/
|
|
30
|
+
static generate(diff: ParsedDiff): string;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/core/diff/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,MAAM;IACnB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,UAAU;IACnB;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;IAwF5C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;CAiB5C"}
|