ba-kit-cli 2.0.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 (80) hide show
  1. package/README.md +160 -0
  2. package/bin/ba-kit.js +2 -0
  3. package/dist/commands/cache.d.ts +8 -0
  4. package/dist/commands/cache.d.ts.map +1 -0
  5. package/dist/commands/cache.js +43 -0
  6. package/dist/commands/cache.js.map +1 -0
  7. package/dist/commands/completion.d.ts +9 -0
  8. package/dist/commands/completion.d.ts.map +1 -0
  9. package/dist/commands/completion.js +172 -0
  10. package/dist/commands/completion.js.map +1 -0
  11. package/dist/commands/init.d.ts +6 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/init.js +142 -0
  14. package/dist/commands/init.js.map +1 -0
  15. package/dist/commands/restore.d.ts +6 -0
  16. package/dist/commands/restore.d.ts.map +1 -0
  17. package/dist/commands/restore.js +168 -0
  18. package/dist/commands/restore.js.map +1 -0
  19. package/dist/commands/status.d.ts +6 -0
  20. package/dist/commands/status.d.ts.map +1 -0
  21. package/dist/commands/status.js +154 -0
  22. package/dist/commands/status.js.map +1 -0
  23. package/dist/commands/update.d.ts +6 -0
  24. package/dist/commands/update.d.ts.map +1 -0
  25. package/dist/commands/update.js +300 -0
  26. package/dist/commands/update.js.map +1 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +120 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/lib/cache.d.ts +50 -0
  32. package/dist/lib/cache.d.ts.map +1 -0
  33. package/dist/lib/cache.js +152 -0
  34. package/dist/lib/cache.js.map +1 -0
  35. package/dist/lib/config.d.ts +25 -0
  36. package/dist/lib/config.d.ts.map +1 -0
  37. package/dist/lib/config.js +67 -0
  38. package/dist/lib/config.js.map +1 -0
  39. package/dist/lib/copier.d.ts +10 -0
  40. package/dist/lib/copier.d.ts.map +1 -0
  41. package/dist/lib/copier.js +79 -0
  42. package/dist/lib/copier.js.map +1 -0
  43. package/dist/lib/differ.d.ts +16 -0
  44. package/dist/lib/differ.d.ts.map +1 -0
  45. package/dist/lib/differ.js +51 -0
  46. package/dist/lib/differ.js.map +1 -0
  47. package/dist/lib/downloader.d.ts +11 -0
  48. package/dist/lib/downloader.d.ts.map +1 -0
  49. package/dist/lib/downloader.js +110 -0
  50. package/dist/lib/downloader.js.map +1 -0
  51. package/dist/lib/hasher.d.ts +18 -0
  52. package/dist/lib/hasher.d.ts.map +1 -0
  53. package/dist/lib/hasher.js +54 -0
  54. package/dist/lib/hasher.js.map +1 -0
  55. package/dist/lib/manifest.d.ts +30 -0
  56. package/dist/lib/manifest.d.ts.map +1 -0
  57. package/dist/lib/manifest.js +72 -0
  58. package/dist/lib/manifest.js.map +1 -0
  59. package/dist/types.d.ts +91 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +21 -0
  62. package/dist/types.js.map +1 -0
  63. package/dist/utils/constants.d.ts +13 -0
  64. package/dist/utils/constants.d.ts.map +1 -0
  65. package/dist/utils/constants.js +38 -0
  66. package/dist/utils/constants.js.map +1 -0
  67. package/dist/utils/errors.d.ts +60 -0
  68. package/dist/utils/errors.d.ts.map +1 -0
  69. package/dist/utils/errors.js +99 -0
  70. package/dist/utils/errors.js.map +1 -0
  71. package/dist/utils/logger.d.ts +43 -0
  72. package/dist/utils/logger.d.ts.map +1 -0
  73. package/dist/utils/logger.js +107 -0
  74. package/dist/utils/logger.js.map +1 -0
  75. package/dist/utils/prompts.d.ts +18 -0
  76. package/dist/utils/prompts.d.ts.map +1 -0
  77. package/dist/utils/prompts.js +63 -0
  78. package/dist/utils/prompts.js.map +1 -0
  79. package/man/ba-kit.1 +194 -0
  80. package/package.json +77 -0
@@ -0,0 +1,168 @@
1
+ import { join, dirname } from 'path';
2
+ import { copyFile, mkdir, stat } from 'fs/promises';
3
+ import chalk from 'chalk';
4
+ import { log, spinner } from '../utils/logger.js';
5
+ import { CONFIG } from '../utils/constants.js';
6
+ import { manifestExists, readManifest, writeManifest } from '../lib/manifest.js';
7
+ import { hashFile } from '../lib/hasher.js';
8
+ import { downloadBaKit, cleanupDownload } from '../lib/downloader.js';
9
+ import { selectFilesToRestore, confirmRestore } from '../utils/prompts.js';
10
+ /**
11
+ * Restore modified files to original
12
+ */
13
+ export async function restore(file, options) {
14
+ const projectPath = process.cwd();
15
+ const agentDir = join(projectPath, CONFIG.AGENT_DIR);
16
+ // Check if ba-kit is installed
17
+ if (!await manifestExists(projectPath)) {
18
+ log.error('Not a BA-Kit project. Run `ba-kit init` first.');
19
+ process.exit(1);
20
+ }
21
+ const manifest = await readManifest(projectPath);
22
+ // Find modified files
23
+ const modifiedFiles = await findModifiedFiles(manifest, agentDir);
24
+ if (modifiedFiles.length === 0) {
25
+ log.success('No modified files to restore.');
26
+ return;
27
+ }
28
+ // Determine which files to restore
29
+ let filesToRestore = [];
30
+ if (file) {
31
+ // Specific file requested
32
+ if (!modifiedFiles.includes(file)) {
33
+ log.error(`File not found or not modified: ${file}`);
34
+ log.dim('Modified files:');
35
+ modifiedFiles.forEach(f => log.dim(` - ${f}`));
36
+ process.exit(1);
37
+ }
38
+ filesToRestore = [file];
39
+ }
40
+ else if (options.all) {
41
+ // Restore all
42
+ filesToRestore = modifiedFiles;
43
+ }
44
+ else {
45
+ // Interactive selection
46
+ console.log('');
47
+ console.log(chalk.bold('Modified Files:'));
48
+ modifiedFiles.forEach(f => console.log(` ${chalk.yellow('✎')} ${f}`));
49
+ console.log('');
50
+ filesToRestore = await selectFilesToRestore(modifiedFiles);
51
+ if (filesToRestore.length === 0) {
52
+ log.warn('No files selected.');
53
+ return;
54
+ }
55
+ }
56
+ // Confirm
57
+ if (!options.yes) {
58
+ const confirmed = await confirmRestore(filesToRestore.length);
59
+ if (!confirmed) {
60
+ log.warn('Aborted.');
61
+ return;
62
+ }
63
+ }
64
+ let extractedPath;
65
+ let needsCleanup = true;
66
+ // Use local source if specified, otherwise download from GitHub
67
+ if (options.local) {
68
+ const localSpinner = spinner('Using local BA-Kit source...').start();
69
+ try {
70
+ extractedPath = options.local;
71
+ const s = await stat(extractedPath);
72
+ if (!s.isDirectory()) {
73
+ throw new Error('Local source must be a directory');
74
+ }
75
+ needsCleanup = false;
76
+ localSpinner.succeed('Using local source');
77
+ }
78
+ catch (error) {
79
+ localSpinner.fail('Failed to use local source');
80
+ log.error(error.message);
81
+ process.exit(1);
82
+ }
83
+ }
84
+ else {
85
+ const downloadSpinner = spinner('Fetching original files...').start();
86
+ try {
87
+ const result = await downloadBaKit(manifest.branch, projectPath);
88
+ extractedPath = result.extractedPath;
89
+ downloadSpinner.succeed('Fetched originals');
90
+ }
91
+ catch (error) {
92
+ downloadSpinner.fail('Failed to fetch');
93
+ log.error(error.message);
94
+ process.exit(1);
95
+ }
96
+ }
97
+ // Restore files
98
+ const restoreSpinner = spinner('Restoring files...').start();
99
+ const restoredHashes = {};
100
+ try {
101
+ for (const filePath of filesToRestore) {
102
+ const entry = manifest.files[filePath];
103
+ if (!entry)
104
+ continue;
105
+ const destPath = join(agentDir, filePath);
106
+ const srcPath = join(extractedPath, entry.source_path);
107
+ // Backup first
108
+ const backupDir = join(projectPath, CONFIG.BACKUP_DIR, 'restore');
109
+ await mkdir(backupDir, { recursive: true });
110
+ const backupPath = join(backupDir, `${filePath.replace(/\//g, '_')}.${Date.now()}`);
111
+ try {
112
+ await copyFile(destPath, backupPath);
113
+ }
114
+ catch {
115
+ // File might be deleted, skip backup
116
+ }
117
+ // Copy original
118
+ await mkdir(dirname(destPath), { recursive: true });
119
+ await copyFile(srcPath, destPath);
120
+ // Update hash
121
+ const newHash = await hashFile(destPath);
122
+ restoredHashes[filePath] = {
123
+ ...entry,
124
+ current_hash: newHash,
125
+ };
126
+ }
127
+ restoreSpinner.succeed(`Restored ${filesToRestore.length} file(s)`);
128
+ }
129
+ catch (error) {
130
+ restoreSpinner.fail('Failed to restore');
131
+ log.error(error.message);
132
+ process.exit(1);
133
+ }
134
+ // Update manifest
135
+ const newManifest = {
136
+ ...manifest,
137
+ updated_at: new Date().toISOString(),
138
+ files: { ...manifest.files, ...restoredHashes },
139
+ };
140
+ await writeManifest(projectPath, newManifest);
141
+ // Cleanup
142
+ if (needsCleanup) {
143
+ await cleanupDownload(extractedPath);
144
+ }
145
+ console.log('');
146
+ log.success('Files restored to original state.');
147
+ log.dim(`Backups saved to ${CONFIG.BACKUP_DIR}/restore/`);
148
+ }
149
+ /**
150
+ * Find files that have been modified locally
151
+ */
152
+ async function findModifiedFiles(manifest, agentDir) {
153
+ const modified = [];
154
+ for (const [filePath, entry] of Object.entries(manifest.files)) {
155
+ try {
156
+ const currentHash = await hashFile(join(agentDir, filePath));
157
+ if (currentHash !== entry.original_hash) {
158
+ modified.push(filePath);
159
+ }
160
+ }
161
+ catch {
162
+ // File deleted - also counts as modified
163
+ modified.push(filePath);
164
+ }
165
+ }
166
+ return modified.sort();
167
+ }
168
+ //# sourceMappingURL=restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../src/commands/restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { StatusOptions } from '../types.js';
2
+ /**
3
+ * Show BA-Kit installation status
4
+ */
5
+ export declare function status(options: StatusOptions): Promise<void>;
6
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAA0B,MAAM,aAAa,CAAC;AAEzE;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgElE"}
@@ -0,0 +1,154 @@
1
+ import { join } from 'path';
2
+ import { readdir } from 'fs/promises';
3
+ import chalk from 'chalk';
4
+ import { log, table } from '../utils/logger.js';
5
+ import { CONFIG } from '../utils/constants.js';
6
+ import { manifestExists, readManifest } from '../lib/manifest.js';
7
+ import { hashFilesParallel } from '../lib/hasher.js';
8
+ import { downloadBaKit, cleanupDownload } from '../lib/downloader.js';
9
+ /**
10
+ * Show BA-Kit installation status
11
+ */
12
+ export async function status(options) {
13
+ const projectPath = process.cwd();
14
+ const agentDir = join(projectPath, CONFIG.AGENT_DIR);
15
+ // Check if ba-kit is installed
16
+ if (!await manifestExists(projectPath)) {
17
+ log.error('Not a BA-Kit project. Run `ba-kit init` first.');
18
+ process.exit(1);
19
+ }
20
+ const manifest = await readManifest(projectPath);
21
+ // Header
22
+ console.log('');
23
+ console.log(chalk.bold('BA-Kit Status'));
24
+ console.log(chalk.dim('─'.repeat(50)));
25
+ console.log(` Installed: ${chalk.cyan('v' + manifest.version)}`);
26
+ console.log(` Branch: ${chalk.dim(manifest.branch)}`);
27
+ console.log(` Updated: ${chalk.dim(formatDate(manifest.updated_at))}`);
28
+ // Check remote if requested
29
+ if (options.remote) {
30
+ await checkRemote(manifest);
31
+ }
32
+ console.log(chalk.dim('─'.repeat(50)));
33
+ // Analyze files
34
+ const analysis = await analyzeFiles(manifest, agentDir);
35
+ // Print stats
36
+ const stats = {
37
+ unchanged: analysis.filter(f => f.status === 'unchanged').length,
38
+ modified: analysis.filter(f => f.status === 'modified').length,
39
+ deleted: analysis.filter(f => f.status === 'deleted').length,
40
+ added: analysis.filter(f => f.status === 'added').length,
41
+ };
42
+ console.log('');
43
+ console.log(` ${chalk.dim('○')} Unchanged: ${stats.unchanged}`);
44
+ console.log(` ${chalk.yellow('✎')} Modified: ${stats.modified}`);
45
+ console.log(` ${chalk.red('✗')} Deleted: ${stats.deleted}`);
46
+ console.log(` ${chalk.green('+')} Added: ${stats.added}`);
47
+ console.log('');
48
+ // Show details if any changes
49
+ if (stats.modified + stats.deleted > 0) {
50
+ console.log(chalk.bold('Changed Files:'));
51
+ for (const file of analysis) {
52
+ if (file.status !== 'unchanged' && file.status !== 'added') {
53
+ table.row(file.status, file.path);
54
+ }
55
+ }
56
+ console.log('');
57
+ log.dim('Run `ba-kit update` to sync with upstream.');
58
+ }
59
+ else if (stats.added > 0) {
60
+ console.log(chalk.bold('User-Added Files:'));
61
+ for (const file of analysis.filter(f => f.status === 'added')) {
62
+ table.row('added', file.path);
63
+ }
64
+ console.log('');
65
+ }
66
+ else {
67
+ log.success('All files are in sync with upstream.');
68
+ }
69
+ }
70
+ /**
71
+ * Analyze all files against manifest using parallel hashing
72
+ */
73
+ async function analyzeFiles(manifest, agentDir) {
74
+ const results = [];
75
+ const manifestFiles = new Set(Object.keys(manifest.files));
76
+ // Build list of files to hash
77
+ const filePaths = Object.keys(manifest.files).map(f => join(agentDir, f));
78
+ // Hash all files in parallel for better performance
79
+ const hashes = await hashFilesParallel(filePaths);
80
+ // Check manifest files against hashes
81
+ for (const [filePath, entry] of Object.entries(manifest.files)) {
82
+ const fullPath = join(agentDir, filePath);
83
+ const currentHash = hashes.get(fullPath);
84
+ if (!currentHash) {
85
+ results.push({ path: filePath, status: 'deleted' });
86
+ }
87
+ else if (currentHash === entry.original_hash) {
88
+ results.push({ path: filePath, status: 'unchanged' });
89
+ }
90
+ else {
91
+ results.push({ path: filePath, status: 'modified' });
92
+ }
93
+ }
94
+ // Check for user-added files
95
+ const allFiles = await walkDir(agentDir);
96
+ for (const file of allFiles) {
97
+ const relativePath = file.replace(agentDir + '/', '');
98
+ if (relativePath === CONFIG.MANIFEST_FILE)
99
+ continue;
100
+ if (!manifestFiles.has(relativePath)) {
101
+ results.push({ path: relativePath, status: 'added' });
102
+ }
103
+ }
104
+ return results.sort((a, b) => a.path.localeCompare(b.path));
105
+ }
106
+ /**
107
+ * Walk directory recursively
108
+ */
109
+ async function walkDir(dir) {
110
+ const files = [];
111
+ const entries = await readdir(dir, { withFileTypes: true });
112
+ for (const entry of entries) {
113
+ const fullPath = join(dir, entry.name);
114
+ if (entry.isDirectory()) {
115
+ // Skip hidden dirs except .agent itself
116
+ if (!entry.name.startsWith('.')) {
117
+ files.push(...await walkDir(fullPath));
118
+ }
119
+ }
120
+ else {
121
+ // Skip hidden files
122
+ if (!entry.name.startsWith('.')) {
123
+ files.push(fullPath);
124
+ }
125
+ }
126
+ }
127
+ return files;
128
+ }
129
+ /**
130
+ * Check remote for updates
131
+ */
132
+ async function checkRemote(manifest) {
133
+ try {
134
+ const { extractedPath, version } = await downloadBaKit(manifest.branch, process.cwd());
135
+ await cleanupDownload(extractedPath);
136
+ if (version !== manifest.version) {
137
+ console.log(` Latest: ${chalk.green('v' + version)} ${chalk.yellow('(update available)')}`);
138
+ }
139
+ else {
140
+ console.log(` Latest: ${chalk.green('v' + version)} ${chalk.dim('(up to date)')}`);
141
+ }
142
+ }
143
+ catch {
144
+ console.log(` Latest: ${chalk.red('(cannot check)')}`);
145
+ }
146
+ }
147
+ /**
148
+ * Format ISO date string
149
+ */
150
+ function formatDate(isoDate) {
151
+ const date = new Date(isoDate);
152
+ return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
153
+ }
154
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { UpdateOptions } from '../types.js';
2
+ /**
3
+ * Update BA-Kit to latest version
4
+ */
5
+ export declare function update(options: UpdateOptions): Promise<void>;
6
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAkC,MAAM,aAAa,CAAC;AAEjF;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqJlE"}
@@ -0,0 +1,300 @@
1
+ import { join, dirname } from 'path';
2
+ import { readFile, copyFile, mkdir, stat, readdir } from 'fs/promises';
3
+ import chalk from 'chalk';
4
+ import { log, spinner } from '../utils/logger.js';
5
+ import { CONFIG } from '../utils/constants.js';
6
+ import { manifestExists, readManifest, writeManifest } from '../lib/manifest.js';
7
+ import { hashFile } from '../lib/hasher.js';
8
+ import { downloadBaKit, cleanupDownload } from '../lib/downloader.js';
9
+ import { showDiff } from '../lib/differ.js';
10
+ import { promptConflict } from '../utils/prompts.js';
11
+ /**
12
+ * Update BA-Kit to latest version
13
+ */
14
+ export async function update(options) {
15
+ const projectPath = process.cwd();
16
+ const agentDir = join(projectPath, CONFIG.AGENT_DIR);
17
+ // Check if ba-kit is installed
18
+ if (!await manifestExists(projectPath)) {
19
+ log.error('Not a BA-Kit project. Run `ba-kit init` first.');
20
+ process.exit(1);
21
+ }
22
+ const manifest = await readManifest(projectPath);
23
+ log.info(`Current version: v${manifest.version}`);
24
+ let extractedPath;
25
+ let remoteVersion;
26
+ let needsCleanup = true;
27
+ // Use local source if specified, otherwise download from GitHub
28
+ if (options.local) {
29
+ const localSpinner = spinner('Using local BA-Kit source...').start();
30
+ try {
31
+ extractedPath = options.local;
32
+ const s = await stat(extractedPath);
33
+ if (!s.isDirectory()) {
34
+ throw new Error('Local source must be a directory');
35
+ }
36
+ remoteVersion = await getLocalVersion(extractedPath);
37
+ needsCleanup = false;
38
+ localSpinner.succeed(`Local version: v${remoteVersion}`);
39
+ }
40
+ catch (error) {
41
+ localSpinner.fail('Failed to use local source');
42
+ log.error(error.message);
43
+ process.exit(1);
44
+ }
45
+ }
46
+ else {
47
+ const downloadSpinner = spinner('Fetching latest BA-Kit...').start();
48
+ try {
49
+ const result = await downloadBaKit(manifest.branch, projectPath);
50
+ extractedPath = result.extractedPath;
51
+ remoteVersion = result.version;
52
+ downloadSpinner.succeed(`Latest version: v${remoteVersion}`);
53
+ }
54
+ catch (error) {
55
+ downloadSpinner.fail('Failed to fetch latest');
56
+ log.error(error.message);
57
+ process.exit(1);
58
+ }
59
+ }
60
+ // Analyze changes
61
+ const analyzeSpinner = spinner('Analyzing changes...').start();
62
+ const changes = await analyzeChanges(manifest, agentDir, extractedPath);
63
+ analyzeSpinner.stop();
64
+ // Summary
65
+ const stats = {
66
+ skip: changes.filter(c => c.action === 'skip').length,
67
+ update: changes.filter(c => c.action === 'update').length,
68
+ conflict: changes.filter(c => c.action === 'conflict').length,
69
+ new: changes.filter(c => c.action === 'new').length,
70
+ };
71
+ console.log('');
72
+ console.log(chalk.bold('Change Summary:'));
73
+ console.log(` ${chalk.dim('○')} No change: ${stats.skip}`);
74
+ console.log(` ${chalk.blue('↓')} Will update: ${stats.update}`);
75
+ console.log(` ${chalk.green('+')} New files: ${stats.new}`);
76
+ console.log(` ${chalk.red('⚡')} Conflicts: ${stats.conflict}`);
77
+ console.log('');
78
+ // Dry run mode
79
+ if (options.dryRun) {
80
+ log.info('Dry run mode - no changes applied.');
81
+ if (needsCleanup)
82
+ await cleanupDownload(extractedPath);
83
+ return;
84
+ }
85
+ // Nothing to do
86
+ if (stats.update === 0 && stats.conflict === 0 && stats.new === 0) {
87
+ log.success('Already up to date!');
88
+ if (needsCleanup)
89
+ await cleanupDownload(extractedPath);
90
+ return;
91
+ }
92
+ // Warn about conflicts in --yes mode
93
+ if (options.yes && stats.conflict > 0) {
94
+ log.warn(`${stats.conflict} conflicts found. Skipping conflicted files.`);
95
+ log.dim('Re-run without --yes to resolve conflicts interactively.');
96
+ }
97
+ // Apply updates
98
+ const updatedFiles = {};
99
+ let updatedCount = 0;
100
+ for (const change of changes) {
101
+ if (change.action === 'skip')
102
+ continue;
103
+ if (change.action === 'update' || change.action === 'new') {
104
+ // Auto-update
105
+ if (!options.yes) {
106
+ log.dim(`Updating ${change.path}...`);
107
+ }
108
+ await applyUpdate(change, agentDir, extractedPath);
109
+ const newHash = await hashFile(join(agentDir, change.path));
110
+ updatedFiles[change.path] = {
111
+ original_hash: newHash,
112
+ current_hash: newHash,
113
+ source_path: change.sourcePath,
114
+ };
115
+ updatedCount++;
116
+ }
117
+ if (change.action === 'conflict') {
118
+ // Skip conflicts in --yes mode
119
+ if (options.yes) {
120
+ log.dim(`Skipping conflict: ${change.path}`);
121
+ continue;
122
+ }
123
+ const resolved = await handleConflict(change, agentDir, extractedPath);
124
+ if (resolved) {
125
+ const newHash = await hashFile(join(agentDir, change.path));
126
+ updatedFiles[change.path] = {
127
+ original_hash: newHash,
128
+ current_hash: newHash,
129
+ source_path: change.sourcePath,
130
+ };
131
+ updatedCount++;
132
+ }
133
+ }
134
+ }
135
+ // Update manifest
136
+ const newManifest = {
137
+ ...manifest,
138
+ version: remoteVersion,
139
+ updated_at: new Date().toISOString(),
140
+ files: { ...manifest.files, ...updatedFiles },
141
+ };
142
+ await writeManifest(projectPath, newManifest);
143
+ // Cleanup
144
+ if (needsCleanup)
145
+ await cleanupDownload(extractedPath);
146
+ console.log('');
147
+ if (updatedCount > 0) {
148
+ log.success(`Updated ${updatedCount} file(s) to v${remoteVersion}`);
149
+ }
150
+ else {
151
+ log.success(`Manifest updated to v${remoteVersion}`);
152
+ }
153
+ }
154
+ /**
155
+ * Get version from local ba-kit source
156
+ */
157
+ async function getLocalVersion(path) {
158
+ try {
159
+ const changelog = await readFile(join(path, 'CHANGELOG.md'), 'utf8');
160
+ const match = changelog.match(/##\s+\[?v?(\d+\.\d+\.\d+)/);
161
+ if (match)
162
+ return match[1];
163
+ }
164
+ catch {
165
+ // ignore
166
+ }
167
+ return 'local';
168
+ }
169
+ /**
170
+ * Analyze changes between local and remote
171
+ */
172
+ async function analyzeChanges(manifest, agentDir, remotePath) {
173
+ const changes = [];
174
+ const remoteFiles = await mapRemoteFiles(remotePath);
175
+ for (const [targetPath, sourcePath] of Object.entries(remoteFiles)) {
176
+ const localPath = join(agentDir, targetPath);
177
+ const remoteFullPath = join(remotePath, sourcePath);
178
+ const manifestEntry = manifest.files[targetPath];
179
+ try {
180
+ const localHash = await hashFile(localPath);
181
+ const remoteHash = await hashFile(remoteFullPath);
182
+ if (!manifestEntry) {
183
+ // New file from upstream
184
+ changes.push({ path: targetPath, sourcePath, action: 'new' });
185
+ }
186
+ else if (localHash === manifestEntry.original_hash) {
187
+ // Local unchanged
188
+ if (localHash === remoteHash) {
189
+ changes.push({ path: targetPath, action: 'skip' });
190
+ }
191
+ else {
192
+ changes.push({ path: targetPath, sourcePath, action: 'update' });
193
+ }
194
+ }
195
+ else {
196
+ // Local modified
197
+ if (remoteHash === manifestEntry.original_hash) {
198
+ // Remote unchanged, keep local
199
+ changes.push({ path: targetPath, action: 'skip' });
200
+ }
201
+ else {
202
+ // Both changed - conflict!
203
+ changes.push({
204
+ path: targetPath,
205
+ sourcePath,
206
+ action: 'conflict',
207
+ localHash,
208
+ remoteHash,
209
+ });
210
+ }
211
+ }
212
+ }
213
+ catch {
214
+ // Local file missing - treat as new
215
+ changes.push({ path: targetPath, sourcePath, action: 'new' });
216
+ }
217
+ }
218
+ return changes;
219
+ }
220
+ /**
221
+ * Map remote files to target paths based on FILE_MAP config
222
+ */
223
+ async function mapRemoteFiles(remotePath) {
224
+ const files = {};
225
+ async function walk(dir, targetPrefix, sourcePrefix) {
226
+ const entries = await readdir(dir, { withFileTypes: true });
227
+ for (const entry of entries) {
228
+ if (CONFIG.EXCLUDE.includes(entry.name))
229
+ continue;
230
+ const sourcePath = join(sourcePrefix, entry.name);
231
+ const targetPath = join(targetPrefix, entry.name);
232
+ if (entry.isDirectory()) {
233
+ await walk(join(dir, entry.name), targetPath, sourcePath);
234
+ }
235
+ else {
236
+ files[targetPath] = sourcePath;
237
+ }
238
+ }
239
+ }
240
+ for (const [src, dest] of Object.entries(CONFIG.FILE_MAP)) {
241
+ const fullSrc = join(remotePath, src);
242
+ try {
243
+ const s = await stat(fullSrc);
244
+ if (s.isDirectory()) {
245
+ await walk(fullSrc, dest, src);
246
+ }
247
+ else {
248
+ files[dest] = src;
249
+ }
250
+ }
251
+ catch {
252
+ // source doesn't exist
253
+ }
254
+ }
255
+ return files;
256
+ }
257
+ /**
258
+ * Apply update to a file
259
+ */
260
+ async function applyUpdate(change, agentDir, remotePath) {
261
+ const destPath = join(agentDir, change.path);
262
+ const srcPath = join(remotePath, change.sourcePath);
263
+ await mkdir(dirname(destPath), { recursive: true });
264
+ await copyFile(srcPath, destPath);
265
+ }
266
+ /**
267
+ * Handle conflict interactively
268
+ */
269
+ async function handleConflict(change, agentDir, remotePath) {
270
+ const localPath = join(agentDir, change.path);
271
+ const remoteSrcPath = join(remotePath, change.sourcePath);
272
+ while (true) {
273
+ const action = await promptConflict(change.path);
274
+ switch (action) {
275
+ case 'keep':
276
+ log.dim(`Keeping local: ${change.path}`);
277
+ return false;
278
+ case 'overwrite':
279
+ await copyFile(remoteSrcPath, localPath);
280
+ log.dim(`Updated: ${change.path}`);
281
+ return true;
282
+ case 'diff': {
283
+ const localContent = await readFile(localPath, 'utf8');
284
+ const remoteContent = await readFile(remoteSrcPath, 'utf8');
285
+ showDiff(remoteContent, localContent, change.path);
286
+ break; // Loop again to prompt
287
+ }
288
+ case 'backup': {
289
+ const backupDir = join(agentDir, '..', CONFIG.BACKUP_DIR);
290
+ await mkdir(backupDir, { recursive: true });
291
+ const backupPath = join(backupDir, change.path.replace(/\//g, '_'));
292
+ await copyFile(localPath, backupPath);
293
+ await copyFile(remoteSrcPath, localPath);
294
+ log.dim(`Backed up & updated: ${change.path}`);
295
+ return true;
296
+ }
297
+ }
298
+ }
299
+ }
300
+ //# sourceMappingURL=update.js.map