@accelerationguy/accel 1.0.1 → 1.0.2

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.js +244 -0
  2. package/package.json +1 -1
package/bin/install.js CHANGED
@@ -489,6 +489,234 @@ function deregisterHooks() {
489
489
  }
490
490
  }
491
491
 
492
+ // ─── User Data Paths (preserved during updates) ─────────────
493
+ const USER_DATA_PATTERNS = [
494
+ // Vector user config
495
+ 'modules/vector/vector.json',
496
+ 'modules/vector/.vector-template/vector.json',
497
+ 'modules/vector/sessions/',
498
+ // Momentum workspace data
499
+ 'modules/momentum/data/',
500
+ 'modules/momentum/workspace.json',
501
+ 'modules/momentum/operator.json',
502
+ // Drive project state
503
+ 'modules/drive/.drive/',
504
+ // Event bus (user's events and archive)
505
+ 'events/',
506
+ ];
507
+
508
+ function isUserData(relativePath) {
509
+ return USER_DATA_PATTERNS.some((pattern) => relativePath.startsWith(pattern));
510
+ }
511
+
512
+ // ─── Backup ─────────────────────────────────────────────────
513
+ function createBackup() {
514
+ if (!fs.existsSync(ACCEL_HOME)) return null;
515
+
516
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
517
+ const backupDir = path.join(os.homedir(), `.accel-backup-${timestamp}`);
518
+
519
+ copyRecursive(ACCEL_HOME, backupDir);
520
+ return backupDir;
521
+ }
522
+
523
+ // ─── Smart Update ───────────────────────────────────────────
524
+ function updateModule(moduleId) {
525
+ const mod = MODULES.find((m) => m.id === moduleId);
526
+ if (!mod) throw new Error(`Unknown module: ${moduleId}`);
527
+
528
+ const srcDir = path.join(PACKAGE_DIR, 'modules', moduleId);
529
+ const destDir = path.join(ACCEL_HOME, 'modules', moduleId);
530
+ const commandsDir = path.join(CLAUDE_HOME, 'commands', moduleId);
531
+
532
+ // Collect user data files before update
533
+ const preserved = new Map();
534
+ if (fs.existsSync(destDir)) {
535
+ collectUserData(destDir, ACCEL_HOME, preserved);
536
+ }
537
+
538
+ // Remove old module code (but we have preserved user data in memory)
539
+ if (fs.existsSync(destDir)) {
540
+ fs.rmSync(destDir, { recursive: true, force: true });
541
+ }
542
+ if (fs.existsSync(commandsDir)) {
543
+ fs.rmSync(commandsDir, { recursive: true, force: true });
544
+ }
545
+
546
+ // Install fresh module code
547
+ fs.mkdirSync(destDir, { recursive: true });
548
+ fs.mkdirSync(commandsDir, { recursive: true });
549
+ copyRecursive(srcDir, destDir);
550
+
551
+ // Copy slash commands
552
+ const cmdSrcDirs = [
553
+ 'commands', 'tasks', 'src/commands', 'src/tasks',
554
+ 'skillsmith/tasks', 'skillsmith',
555
+ 'mission-control/tasks', 'mission-control',
556
+ ];
557
+ for (const cmdDir of cmdSrcDirs) {
558
+ const cmdSrc = path.join(srcDir, cmdDir);
559
+ if (fs.existsSync(cmdSrc)) {
560
+ const entries = fs.readdirSync(cmdSrc);
561
+ for (const entry of entries) {
562
+ const entryPath = path.join(cmdSrc, entry);
563
+ if (entry.endsWith('.md') && fs.statSync(entryPath).isFile()) {
564
+ fs.copyFileSync(entryPath, path.join(commandsDir, entry));
565
+ }
566
+ }
567
+ }
568
+ }
569
+
570
+ // Restore user data on top of fresh code
571
+ let restoredCount = 0;
572
+ for (const [relativePath, content] of preserved) {
573
+ const fullPath = path.join(ACCEL_HOME, relativePath);
574
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
575
+ fs.writeFileSync(fullPath, content);
576
+ restoredCount++;
577
+ }
578
+
579
+ // Reinstall hooks and MCP if needed
580
+ if (mod.hasHooks) {
581
+ const hooksSrc = path.join(srcDir, 'hooks');
582
+ const srcHooks = path.join(srcDir, 'src', 'hooks');
583
+ const hooksDir = fs.existsSync(hooksSrc) ? hooksSrc : fs.existsSync(srcHooks) ? srcHooks : null;
584
+ if (hooksDir) {
585
+ const hooksDest = path.join(CLAUDE_HOME, 'hooks');
586
+ fs.mkdirSync(hooksDest, { recursive: true });
587
+ copyRecursive(hooksDir, hooksDest);
588
+ }
589
+ }
590
+
591
+ if (mod.hasMcp) {
592
+ const mcpSrc = path.join(srcDir, 'mcp');
593
+ const pkgMcp = path.join(srcDir, 'src', 'packages', `momentum-mcp`);
594
+ const mcpDir = fs.existsSync(mcpSrc) ? mcpSrc : fs.existsSync(pkgMcp) ? pkgMcp : null;
595
+ if (mcpDir) {
596
+ const mcpDest = path.join(ACCEL_HOME, 'mcp', moduleId);
597
+ fs.mkdirSync(mcpDest, { recursive: true });
598
+ copyRecursive(mcpDir, mcpDest);
599
+ if (fs.existsSync(path.join(mcpDest, 'package.json'))) {
600
+ try {
601
+ execFileSync('npm', ['install', '--production', '--silent'], { cwd: mcpDest, stdio: 'pipe' });
602
+ } catch {}
603
+ }
604
+ }
605
+ }
606
+
607
+ return restoredCount;
608
+ }
609
+
610
+ function collectUserData(dir, baseDir, preserved) {
611
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
612
+ for (const entry of entries) {
613
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
614
+ const fullPath = path.join(dir, entry.name);
615
+ const relativePath = path.relative(baseDir, fullPath);
616
+
617
+ if (entry.isDirectory()) {
618
+ collectUserData(fullPath, baseDir, preserved);
619
+ } else if (isUserData(relativePath)) {
620
+ preserved.set(relativePath, fs.readFileSync(fullPath));
621
+ }
622
+ }
623
+ }
624
+
625
+ async function runUpdate() {
626
+ if (!fs.existsSync(MANIFEST_PATH)) {
627
+ console.log(`\n ${c.yellow}Nothing to update. Run \`npx @accelerationguy/accel\` to install first.${c.reset}\n`);
628
+ process.exit(0);
629
+ }
630
+
631
+ const manifest = JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
632
+ const installedVersion = manifest.version;
633
+ const packageJson = JSON.parse(fs.readFileSync(path.join(PACKAGE_DIR, 'package.json'), 'utf8'));
634
+ const newVersion = packageJson.version;
635
+
636
+ console.log(`\n ${c.cyan}${c.bold}${BRAND} Update${c.reset}\n`);
637
+ console.log(` Installed: v${installedVersion}`);
638
+ console.log(` Available: v${newVersion}`);
639
+
640
+ if (installedVersion === newVersion) {
641
+ console.log(`\n ${c.green}Already up to date!${c.reset}\n`);
642
+ process.exit(0);
643
+ }
644
+
645
+ // Show what's installed
646
+ const installedModules = Object.keys(manifest.modules);
647
+ console.log(`\n Modules: ${installedModules.map((id) => {
648
+ const mod = MODULES.find((m) => m.id === id);
649
+ return mod ? mod.name : id;
650
+ }).join(', ')}`);
651
+
652
+ // Create backup
653
+ console.log(`\n ${c.dim}Creating backup...${c.reset}`);
654
+ const backupDir = createBackup();
655
+ if (backupDir) {
656
+ console.log(` ${c.green}\u2713${c.reset} Backup saved to ${backupDir}`);
657
+ }
658
+
659
+ // Update each installed module
660
+ console.log(`\n ${c.bold}Updating...${c.reset}\n`);
661
+
662
+ const updated = [];
663
+ const failed = [];
664
+ let totalPreserved = 0;
665
+
666
+ for (const modId of installedModules) {
667
+ const mod = MODULES.find((m) => m.id === modId);
668
+ if (!mod) continue;
669
+ try {
670
+ const restoredCount = updateModule(modId);
671
+ totalPreserved += restoredCount;
672
+ updated.push(modId);
673
+ const preserved = restoredCount > 0 ? ` ${c.dim}(${restoredCount} user files preserved)${c.reset}` : '';
674
+ console.log(` ${c.green}\u2713${c.reset} ${mod.name} updated${preserved}`);
675
+ } catch (e) {
676
+ failed.push({ id: modId, error: e.message });
677
+ console.log(` ${c.red}\u2717${c.reset} ${mod.name} failed: ${e.message}`);
678
+ }
679
+ }
680
+
681
+ // Update event bus schemas
682
+ setupEventBus();
683
+
684
+ // Update manifest version
685
+ if (updated.length > 0) {
686
+ manifest.version = newVersion;
687
+ manifest.updatedAt = new Date().toISOString();
688
+ manifest.previousVersion = installedVersion;
689
+ fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
690
+
691
+ // Re-register hooks and MCP (in case format changed)
692
+ registerHooks(updated);
693
+ registerMcpServers(updated);
694
+ installClaudeMdBlock();
695
+ }
696
+
697
+ // Summary
698
+ console.log('');
699
+ if (failed.length > 0) {
700
+ console.log(` ${c.yellow}${updated.length}/${installedModules.length} modules updated.${c.reset}`);
701
+ for (const f of failed) {
702
+ console.log(` ${c.red}\u2717${c.reset} ${f.id}: ${f.error}`);
703
+ }
704
+ if (backupDir) {
705
+ console.log(`\n ${c.dim}Backup at ${backupDir} — restore with: cp -R ${backupDir}/ ~/.accel/${c.reset}`);
706
+ }
707
+ } else {
708
+ console.log(` ${c.green}${c.bold}Updated ${BRAND} v${installedVersion} \u2192 v${newVersion}${c.reset}`);
709
+ if (totalPreserved > 0) {
710
+ console.log(` ${c.dim}${totalPreserved} user data files preserved (rules, workspace, configs)${c.reset}`);
711
+ }
712
+ console.log(`\n Restart Claude Code to pick up changes.`);
713
+ if (backupDir) {
714
+ console.log(` ${c.dim}Backup at ${backupDir} (safe to delete if everything works)${c.reset}`);
715
+ }
716
+ }
717
+ console.log('');
718
+ }
719
+
492
720
  // ─── Event Bus Setup ────────────────────────────────────────
493
721
  function setupEventBus() {
494
722
  const eventsDir = path.join(ACCEL_HOME, 'events');
@@ -549,6 +777,7 @@ async function main() {
549
777
  const isStatus = args.includes('status');
550
778
  const isUninstall = args.includes('uninstall');
551
779
  const isUpdate = args.includes('update');
780
+ const isBackup = args.includes('backup');
552
781
 
553
782
  if (isStatus) {
554
783
  if (!fs.existsSync(MANIFEST_PATH)) {
@@ -564,6 +793,21 @@ async function main() {
564
793
  process.exit(0);
565
794
  }
566
795
 
796
+ if (isUpdate) {
797
+ await runUpdate();
798
+ process.exit(0);
799
+ }
800
+
801
+ if (isBackup) {
802
+ if (!fs.existsSync(ACCEL_HOME)) {
803
+ console.log(`\n ${c.yellow}Nothing to back up. No Accelerate installation found.${c.reset}\n`);
804
+ process.exit(0);
805
+ }
806
+ const backupDir = createBackup();
807
+ console.log(`\n ${c.green}\u2713${c.reset} Backup created at: ${backupDir}\n`);
808
+ process.exit(0);
809
+ }
810
+
567
811
  if (isUninstall) {
568
812
  console.log(`\n ${c.yellow}Uninstalling ${BRAND}...${c.reset}`);
569
813
  if (fs.existsSync(ACCEL_HOME)) fs.rmSync(ACCEL_HOME, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accelerationguy/accel",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Accelerate — Unified Claude Code Agent Framework by Acceleration Guy",
5
5
  "bin": {
6
6
  "accel": "./bin/install.js"