elliot-stack 1.0.20 → 1.0.21

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 (2) hide show
  1. package/bin/install.cjs +66 -5
  2. package/package.json +1 -1
package/bin/install.cjs CHANGED
@@ -11,13 +11,74 @@ const readline = require('readline');
11
11
  const HOME = os.homedir();
12
12
  const CLAUDE_DIR = path.join(HOME, '.claude');
13
13
  const SKILLS_DIR = path.join(CLAUDE_DIR, 'skills');
14
- const BACKUP_DIR = path.join(CLAUDE_DIR, '.estack-backup');
14
+ const BACKUP_DIR = path.join(HOME, '.estack-backup');
15
15
  const CHECKSUMS_FILE = path.join(CLAUDE_DIR, '.estack-checksums.json');
16
16
  const SETTINGS_FILE = path.join(CLAUDE_DIR, 'settings.json');
17
17
  const PACKAGE_SKILLS_DIR = path.join(__dirname, '..', 'skills');
18
18
  const HOOKS_DIR = path.join(CLAUDE_DIR, 'hooks');
19
19
  const PACKAGE_HOOKS_DIR = path.join(__dirname, '..', 'hooks');
20
20
 
21
+ // ── Migrate backup dir from old location (inside .claude) to user root ──────
22
+ (function migrateBackupDir() {
23
+ const OLD_BACKUP_DIR = path.join(CLAUDE_DIR, '.estack-backup');
24
+ if (!fs.existsSync(OLD_BACKUP_DIR)) return;
25
+ if (fs.existsSync(BACKUP_DIR)) return; // new location already exists, leave both alone
26
+ const silent = process.argv.includes('--silent');
27
+ const isDryRun = process.argv.includes('--dry-run') ||
28
+ (!__dirname.includes('node_modules') && !process.argv.includes('--install'));
29
+ if (isDryRun) {
30
+ if (!silent) {
31
+ process.stderr.write(
32
+ 'estack: [dry run] Would move backup dir from ~/.claude/.estack-backup/ to ~/.estack-backup/\n'
33
+ );
34
+ }
35
+ return;
36
+ }
37
+ try {
38
+ fs.renameSync(OLD_BACKUP_DIR, BACKUP_DIR);
39
+ if (!silent) {
40
+ process.stderr.write(
41
+ 'estack: moved backup dir from ~/.claude/.estack-backup/ to ~/.estack-backup/\n'
42
+ );
43
+ }
44
+ } catch (e) {
45
+ // rename across drives/filesystems — fall back to copy+delete
46
+ try {
47
+ copyDirRaw(OLD_BACKUP_DIR, BACKUP_DIR);
48
+ removeDirRaw(OLD_BACKUP_DIR);
49
+ if (!silent) {
50
+ process.stderr.write(
51
+ 'estack: migrated backup dir from ~/.claude/.estack-backup/ to ~/.estack-backup/\n'
52
+ );
53
+ }
54
+ } catch (e2) {
55
+ process.stderr.write(
56
+ 'estack: WARNING — could not migrate backup dir from ' + OLD_BACKUP_DIR +
57
+ ' to ' + BACKUP_DIR + ': ' + e2.message + '\n'
58
+ );
59
+ }
60
+ }
61
+ })();
62
+
63
+ function copyDirRaw(src, dest) {
64
+ fs.mkdirSync(dest, { recursive: true });
65
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
66
+ const s = path.join(src, entry.name);
67
+ const d = path.join(dest, entry.name);
68
+ if (entry.isDirectory()) copyDirRaw(s, d);
69
+ else fs.copyFileSync(s, d);
70
+ }
71
+ }
72
+
73
+ function removeDirRaw(dir) {
74
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
75
+ const full = path.join(dir, entry.name);
76
+ if (entry.isDirectory()) removeDirRaw(full);
77
+ else fs.unlinkSync(full);
78
+ }
79
+ fs.rmdirSync(dir);
80
+ }
81
+
21
82
  // ── Flags ──────────────────────────────────────────────────────────────────
22
83
  const SILENT = process.argv.includes('--silent');
23
84
  const STARTUP = process.argv.includes('--startup');
@@ -560,7 +621,7 @@ async function main() {
560
621
  if (modifiedAction === 'merge') {
561
622
  if (!DRY_RUN) backupSkill(name);
562
623
  mergedSkills.push(name);
563
- console.log((DRY_RUN ? ' [dry run] Would back up ' : ' Backed up ') + name + ' → ~/.claude/.estack-backup/' + name);
624
+ console.log((DRY_RUN ? ' [dry run] Would back up ' : ' Backed up ') + name + ' → ~/.estack-backup/' + name);
564
625
  }
565
626
  // overwrite or merge — fall through to install
566
627
  } else if (!needsUpdate.includes(name) && fs.existsSync(path.join(SKILLS_DIR, name))) {
@@ -595,7 +656,7 @@ async function main() {
595
656
  if (modifiedAction === 'merge') {
596
657
  if (!DRY_RUN) backupHook(filename);
597
658
  mergedHooks.push(filename);
598
- console.log((DRY_RUN ? ' [dry run] Would back up hook ' : ' Backed up hook ') + filename + ' → ~/.claude/.estack-backup/hooks/' + filename);
659
+ console.log((DRY_RUN ? ' [dry run] Would back up hook ' : ' Backed up hook ') + filename + ' → ~/.estack-backup/hooks/' + filename);
599
660
  }
600
661
  // overwrite or merge — fall through to install
601
662
  } else if (!hooksNeedingUpdate.includes(filename) && fs.existsSync(path.join(HOOKS_DIR, filename))) {
@@ -647,12 +708,12 @@ async function main() {
647
708
  if (mergedSkills.length > 0) {
648
709
  console.log('\nLocal changes backed up for: ' + mergedSkills.join(', '));
649
710
  console.log('Ask Claude to merge your changes:');
650
- console.log(' "Merge my estack changes from ~/.claude/.estack-backup/"');
711
+ console.log(' "Merge my estack changes from ~/.estack-backup/"');
651
712
  }
652
713
 
653
714
  if (mergedHooks.length > 0) {
654
715
  console.log('\nLocal hook changes backed up for: ' + mergedHooks.join(', '));
655
- console.log('Backed up to ~/.claude/.estack-backup/hooks/');
716
+ console.log('Backed up to ~/.estack-backup/hooks/');
656
717
  }
657
718
 
658
719
  if (DRY_RUN) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elliot-stack",
3
- "version": "1.0.20",
3
+ "version": "1.0.21",
4
4
  "description": "Elliot's skill stack for Claude Code — install via npx elliot-stack@latest",
5
5
  "bin": {
6
6
  "elliot-stack": "bin/install.cjs"