claudeup 3.5.0 → 3.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeup",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "TUI tool for managing Claude Code plugins, MCPs, and configuration",
5
5
  "type": "module",
6
6
  "main": "src/main.tsx",
@@ -17,6 +17,7 @@ function normalizeRepo(repo) {
17
17
  */
18
18
  export const deprecatedMarketplaces = {
19
19
  "mag-claude-plugins": "magus",
20
+ "MadAppGang-claude-code": "magus",
20
21
  };
21
22
  export const defaultMarketplaces = [
22
23
  {
@@ -22,6 +22,7 @@ function normalizeRepo(repo: string): string {
22
22
  */
23
23
  export const deprecatedMarketplaces: Record<string, string> = {
24
24
  "mag-claude-plugins": "magus",
25
+ "MadAppGang-claude-code": "magus",
25
26
  };
26
27
 
27
28
  export const defaultMarketplaces: Marketplace[] = [
@@ -11,13 +11,13 @@ import { recoverMarketplaceSettings, migrateMarketplaceRename } from "../service
11
11
  export async function prerunClaude(claudeArgs, options = {}) {
12
12
  const cache = new UpdateCache();
13
13
  try {
14
- // STEP 0: Migrate mag-claude-plugins → magus (idempotent, no-ops if already migrated)
14
+ // STEP 0: Migrate old marketplace names → magus (idempotent, no-ops if already migrated)
15
15
  const migration = await migrateMarketplaceRename();
16
16
  const migTotal = migration.projectMigrated + migration.globalMigrated
17
17
  + migration.localMigrated + migration.registryMigrated
18
18
  + (migration.knownMarketplacesMigrated ? 1 : 0);
19
19
  if (migTotal > 0) {
20
- console.log(`✓ Migrated ${migTotal} plugin reference(s) from mag-claude-plugins → magus`);
20
+ console.log(`✓ Migrated ${migTotal} plugin reference(s) → magus`);
21
21
  }
22
22
  // STEP 1: Check if we should update (time-based cache, or forced)
23
23
  const shouldUpdate = options.force || (await cache.shouldCheckForUpdates());
@@ -24,13 +24,13 @@ export async function prerunClaude(
24
24
  const cache = new UpdateCache();
25
25
 
26
26
  try {
27
- // STEP 0: Migrate mag-claude-plugins → magus (idempotent, no-ops if already migrated)
27
+ // STEP 0: Migrate old marketplace names → magus (idempotent, no-ops if already migrated)
28
28
  const migration = await migrateMarketplaceRename();
29
29
  const migTotal = migration.projectMigrated + migration.globalMigrated
30
30
  + migration.localMigrated + migration.registryMigrated
31
31
  + (migration.knownMarketplacesMigrated ? 1 : 0);
32
32
  if (migTotal > 0) {
33
- console.log(`✓ Migrated ${migTotal} plugin reference(s) from mag-claude-plugins → magus`);
33
+ console.log(`✓ Migrated ${migTotal} plugin reference(s) → magus`);
34
34
  }
35
35
 
36
36
  // STEP 1: Check if we should update (time-based cache, or forced)
@@ -414,13 +414,14 @@ export async function getMarketplaceAutoUpdate(marketplaceName) {
414
414
  return known[marketplaceName]?.autoUpdate;
415
415
  }
416
416
  // =============================================================================
417
- // MARKETPLACE RENAME MIGRATION: mag-claude-plugins → magus
417
+ // MARKETPLACE RENAME MIGRATION: mag-claude-plugins / MadAppGang-claude-code → magus
418
418
  // =============================================================================
419
- const OLD_MARKETPLACE_NAME = "mag-claude-plugins";
419
+ const OLD_MARKETPLACE_NAMES = ["mag-claude-plugins", "MadAppGang-claude-code"];
420
420
  const NEW_MARKETPLACE_NAME = "magus";
421
421
  /**
422
- * Rename plugin keys in a Record from old marketplace to new.
422
+ * Rename plugin keys in a Record from any old marketplace name to new.
423
423
  * e.g., "frontend@mag-claude-plugins" → "frontend@magus"
424
+ * "dev@MadAppGang-claude-code" → "dev@magus"
424
425
  * Returns [migratedRecord, count] — count=0 means no changes.
425
426
  */
426
427
  function migratePluginKeys(record) {
@@ -429,9 +430,14 @@ function migratePluginKeys(record) {
429
430
  const migrated = {};
430
431
  let count = 0;
431
432
  for (const [key, value] of Object.entries(record)) {
432
- if (key.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
433
+ const oldName = OLD_MARKETPLACE_NAMES.find((n) => key.endsWith(`@${n}`));
434
+ if (oldName) {
433
435
  const pluginName = key.slice(0, key.lastIndexOf("@"));
434
- migrated[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = value;
436
+ const newKey = `${pluginName}@${NEW_MARKETPLACE_NAME}`;
437
+ // Don't overwrite if canonical key already exists
438
+ if (!record[newKey]) {
439
+ migrated[newKey] = value;
440
+ }
435
441
  count++;
436
442
  }
437
443
  else {
@@ -456,12 +462,16 @@ function migrateSettingsObject(settings) {
456
462
  settings.installedPluginVersions = iv;
457
463
  total += ivCount;
458
464
  }
459
- // Migrate extraKnownMarketplaces key
460
- if (settings.extraKnownMarketplaces?.[OLD_MARKETPLACE_NAME]) {
461
- const entry = settings.extraKnownMarketplaces[OLD_MARKETPLACE_NAME];
462
- delete settings.extraKnownMarketplaces[OLD_MARKETPLACE_NAME];
463
- settings.extraKnownMarketplaces[NEW_MARKETPLACE_NAME] = entry;
464
- total++;
465
+ // Migrate extraKnownMarketplaces keys
466
+ for (const oldName of OLD_MARKETPLACE_NAMES) {
467
+ if (settings.extraKnownMarketplaces?.[oldName]) {
468
+ const entry = settings.extraKnownMarketplaces[oldName];
469
+ delete settings.extraKnownMarketplaces[oldName];
470
+ if (!settings.extraKnownMarketplaces[NEW_MARKETPLACE_NAME]) {
471
+ settings.extraKnownMarketplaces[NEW_MARKETPLACE_NAME] = entry;
472
+ }
473
+ total++;
474
+ }
465
475
  }
466
476
  return total;
467
477
  }
@@ -519,33 +529,34 @@ export async function migrateMarketplaceRename(projectPath) {
519
529
  }
520
530
  }
521
531
  catch { /* skip if unreadable */ }
522
- // 4. known_marketplaces.json — rename the key + physical directory cleanup
532
+ // 4. known_marketplaces.json — rename old keys + physical directory cleanup
523
533
  const pluginsDir = path.join(os.homedir(), ".claude", "plugins", "marketplaces");
524
- const oldDir = path.join(pluginsDir, OLD_MARKETPLACE_NAME);
525
534
  const newDir = path.join(pluginsDir, NEW_MARKETPLACE_NAME);
526
535
  try {
527
536
  const known = await readKnownMarketplaces();
528
537
  let knownModified = false;
529
- if (known[OLD_MARKETPLACE_NAME]) {
530
- const oldEntry = known[OLD_MARKETPLACE_NAME];
531
- // If canonical entry already exists, just delete the old one
532
- if (!known[NEW_MARKETPLACE_NAME]) {
533
- known[NEW_MARKETPLACE_NAME] = {
534
- ...oldEntry,
535
- source: {
536
- ...oldEntry.source,
537
- repo: "MadAppGang/magus",
538
- },
539
- };
538
+ for (const oldName of OLD_MARKETPLACE_NAMES) {
539
+ if (known[oldName]) {
540
+ const oldEntry = known[oldName];
541
+ // If canonical entry doesn't exist yet, create it
542
+ if (!known[NEW_MARKETPLACE_NAME]) {
543
+ known[NEW_MARKETPLACE_NAME] = {
544
+ ...oldEntry,
545
+ source: {
546
+ ...oldEntry.source,
547
+ repo: "MadAppGang/magus",
548
+ },
549
+ };
550
+ }
551
+ delete known[oldName];
552
+ knownModified = true;
553
+ }
554
+ // Ensure installLocation doesn't reference old directory names
555
+ if (known[NEW_MARKETPLACE_NAME]?.installLocation?.includes(oldName)) {
556
+ known[NEW_MARKETPLACE_NAME].installLocation =
557
+ known[NEW_MARKETPLACE_NAME].installLocation.replace(oldName, NEW_MARKETPLACE_NAME);
558
+ knownModified = true;
540
559
  }
541
- delete known[OLD_MARKETPLACE_NAME];
542
- knownModified = true;
543
- }
544
- // Ensure installLocation points to new directory name
545
- if (known[NEW_MARKETPLACE_NAME]?.installLocation?.includes(OLD_MARKETPLACE_NAME)) {
546
- known[NEW_MARKETPLACE_NAME].installLocation =
547
- known[NEW_MARKETPLACE_NAME].installLocation.replace(OLD_MARKETPLACE_NAME, NEW_MARKETPLACE_NAME);
548
- knownModified = true;
549
560
  }
550
561
  if (knownModified) {
551
562
  await writeKnownMarketplaces(known);
@@ -553,31 +564,33 @@ export async function migrateMarketplaceRename(projectPath) {
553
564
  }
554
565
  }
555
566
  catch { /* skip if unreadable */ }
556
- // 4b. Rename/remove the old physical directory (runs even if key was already migrated)
557
- try {
558
- if (await fs.pathExists(oldDir)) {
559
- if (!(await fs.pathExists(newDir))) {
560
- await fs.rename(oldDir, newDir);
561
- }
562
- else {
563
- // Both exist — remove the old one (magus dir is canonical)
564
- await fs.remove(oldDir);
567
+ // 4b. Rename/remove old physical directories (runs even if keys were already migrated)
568
+ for (const oldName of OLD_MARKETPLACE_NAMES) {
569
+ const oldDir = path.join(pluginsDir, oldName);
570
+ try {
571
+ if (await fs.pathExists(oldDir)) {
572
+ if (!(await fs.pathExists(newDir))) {
573
+ await fs.rename(oldDir, newDir);
574
+ }
575
+ else {
576
+ // Both exist — remove the old one (magus dir is canonical)
577
+ await fs.remove(oldDir);
578
+ }
565
579
  }
566
580
  }
581
+ catch { /* non-fatal: directory cleanup is best-effort */ }
567
582
  }
568
- catch { /* non-fatal: directory cleanup is best-effort */ }
569
583
  // 4c. Update git remote URL in the marketplace clone (old → new repo)
570
584
  try {
571
- const marketplaceDir = await fs.pathExists(newDir) ? newDir : oldDir;
572
- if (await fs.pathExists(path.join(marketplaceDir, ".git"))) {
585
+ if (await fs.pathExists(path.join(newDir, ".git"))) {
573
586
  const { execSync } = await import("node:child_process");
574
587
  const remote = execSync("git remote get-url origin", {
575
- cwd: marketplaceDir, encoding: "utf-8", timeout: 5000,
588
+ cwd: newDir, encoding: "utf-8", timeout: 5000,
576
589
  }).trim();
577
590
  if (remote.includes("claude-code") && remote.includes("MadAppGang")) {
578
591
  const newRemote = remote.replace("claude-code", NEW_MARKETPLACE_NAME);
579
592
  execSync(`git remote set-url origin "${newRemote}"`, {
580
- cwd: marketplaceDir, encoding: "utf-8", timeout: 5000,
593
+ cwd: newDir, encoding: "utf-8", timeout: 5000,
581
594
  });
582
595
  }
583
596
  }
@@ -589,9 +602,13 @@ export async function migrateMarketplaceRename(projectPath) {
589
602
  let regCount = 0;
590
603
  const newPlugins = {};
591
604
  for (const [pluginId, entries] of Object.entries(registry.plugins)) {
592
- if (pluginId.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
605
+ const oldName = OLD_MARKETPLACE_NAMES.find((n) => pluginId.endsWith(`@${n}`));
606
+ if (oldName) {
593
607
  const pluginName = pluginId.slice(0, pluginId.lastIndexOf("@"));
594
- newPlugins[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = entries;
608
+ const newKey = `${pluginName}@${NEW_MARKETPLACE_NAME}`;
609
+ if (!newPlugins[newKey]) {
610
+ newPlugins[newKey] = entries;
611
+ }
595
612
  regCount++;
596
613
  }
597
614
  else {
@@ -630,15 +630,16 @@ export interface MarketplaceRecoveryResult {
630
630
  }
631
631
 
632
632
  // =============================================================================
633
- // MARKETPLACE RENAME MIGRATION: mag-claude-plugins → magus
633
+ // MARKETPLACE RENAME MIGRATION: mag-claude-plugins / MadAppGang-claude-code → magus
634
634
  // =============================================================================
635
635
 
636
- const OLD_MARKETPLACE_NAME = "mag-claude-plugins";
636
+ const OLD_MARKETPLACE_NAMES = ["mag-claude-plugins", "MadAppGang-claude-code"];
637
637
  const NEW_MARKETPLACE_NAME = "magus";
638
638
 
639
639
  /**
640
- * Rename plugin keys in a Record from old marketplace to new.
640
+ * Rename plugin keys in a Record from any old marketplace name to new.
641
641
  * e.g., "frontend@mag-claude-plugins" → "frontend@magus"
642
+ * "dev@MadAppGang-claude-code" → "dev@magus"
642
643
  * Returns [migratedRecord, count] — count=0 means no changes.
643
644
  */
644
645
  function migratePluginKeys<T>(
@@ -648,9 +649,14 @@ function migratePluginKeys<T>(
648
649
  const migrated: Record<string, T> = {};
649
650
  let count = 0;
650
651
  for (const [key, value] of Object.entries(record)) {
651
- if (key.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
652
+ const oldName = OLD_MARKETPLACE_NAMES.find((n) => key.endsWith(`@${n}`));
653
+ if (oldName) {
652
654
  const pluginName = key.slice(0, key.lastIndexOf("@"));
653
- migrated[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = value;
655
+ const newKey = `${pluginName}@${NEW_MARKETPLACE_NAME}`;
656
+ // Don't overwrite if canonical key already exists
657
+ if (!record[newKey]) {
658
+ migrated[newKey] = value;
659
+ }
654
660
  count++;
655
661
  } else {
656
662
  migrated[key] = value;
@@ -678,12 +684,16 @@ function migrateSettingsObject(settings: ClaudeSettings): number {
678
684
  total += ivCount;
679
685
  }
680
686
 
681
- // Migrate extraKnownMarketplaces key
682
- if (settings.extraKnownMarketplaces?.[OLD_MARKETPLACE_NAME]) {
683
- const entry = settings.extraKnownMarketplaces[OLD_MARKETPLACE_NAME];
684
- delete settings.extraKnownMarketplaces[OLD_MARKETPLACE_NAME];
685
- settings.extraKnownMarketplaces[NEW_MARKETPLACE_NAME] = entry;
686
- total++;
687
+ // Migrate extraKnownMarketplaces keys
688
+ for (const oldName of OLD_MARKETPLACE_NAMES) {
689
+ if (settings.extraKnownMarketplaces?.[oldName]) {
690
+ const entry = settings.extraKnownMarketplaces[oldName];
691
+ delete settings.extraKnownMarketplaces[oldName];
692
+ if (!settings.extraKnownMarketplaces[NEW_MARKETPLACE_NAME]) {
693
+ settings.extraKnownMarketplaces[NEW_MARKETPLACE_NAME] = entry;
694
+ }
695
+ total++;
696
+ }
687
697
  }
688
698
 
689
699
  return total;
@@ -748,40 +758,40 @@ export async function migrateMarketplaceRename(
748
758
  }
749
759
  } catch { /* skip if unreadable */ }
750
760
 
751
- // 4. known_marketplaces.json — rename the key + physical directory cleanup
761
+ // 4. known_marketplaces.json — rename old keys + physical directory cleanup
752
762
  const pluginsDir = path.join(os.homedir(), ".claude", "plugins", "marketplaces");
753
- const oldDir = path.join(pluginsDir, OLD_MARKETPLACE_NAME);
754
763
  const newDir = path.join(pluginsDir, NEW_MARKETPLACE_NAME);
755
764
 
756
765
  try {
757
766
  const known = await readKnownMarketplaces();
758
767
  let knownModified = false;
759
768
 
760
- if (known[OLD_MARKETPLACE_NAME]) {
761
- const oldEntry = known[OLD_MARKETPLACE_NAME];
762
-
763
- // If canonical entry already exists, just delete the old one
764
- if (!known[NEW_MARKETPLACE_NAME]) {
765
- known[NEW_MARKETPLACE_NAME] = {
766
- ...oldEntry,
767
- source: {
768
- ...oldEntry.source,
769
- repo: "MadAppGang/magus",
770
- },
771
- };
769
+ for (const oldName of OLD_MARKETPLACE_NAMES) {
770
+ if (known[oldName]) {
771
+ const oldEntry = known[oldName];
772
+ // If canonical entry doesn't exist yet, create it
773
+ if (!known[NEW_MARKETPLACE_NAME]) {
774
+ known[NEW_MARKETPLACE_NAME] = {
775
+ ...oldEntry,
776
+ source: {
777
+ ...oldEntry.source,
778
+ repo: "MadAppGang/magus",
779
+ },
780
+ };
781
+ }
782
+ delete known[oldName];
783
+ knownModified = true;
772
784
  }
773
- delete known[OLD_MARKETPLACE_NAME];
774
- knownModified = true;
775
- }
776
785
 
777
- // Ensure installLocation points to new directory name
778
- if (known[NEW_MARKETPLACE_NAME]?.installLocation?.includes(OLD_MARKETPLACE_NAME)) {
779
- known[NEW_MARKETPLACE_NAME].installLocation =
780
- known[NEW_MARKETPLACE_NAME].installLocation.replace(
781
- OLD_MARKETPLACE_NAME,
782
- NEW_MARKETPLACE_NAME,
783
- );
784
- knownModified = true;
786
+ // Ensure installLocation doesn't reference old directory names
787
+ if (known[NEW_MARKETPLACE_NAME]?.installLocation?.includes(oldName)) {
788
+ known[NEW_MARKETPLACE_NAME].installLocation =
789
+ known[NEW_MARKETPLACE_NAME].installLocation.replace(
790
+ oldName,
791
+ NEW_MARKETPLACE_NAME,
792
+ );
793
+ knownModified = true;
794
+ }
785
795
  }
786
796
 
787
797
  if (knownModified) {
@@ -790,30 +800,32 @@ export async function migrateMarketplaceRename(
790
800
  }
791
801
  } catch { /* skip if unreadable */ }
792
802
 
793
- // 4b. Rename/remove the old physical directory (runs even if key was already migrated)
794
- try {
795
- if (await fs.pathExists(oldDir)) {
796
- if (!(await fs.pathExists(newDir))) {
797
- await fs.rename(oldDir, newDir);
798
- } else {
799
- // Both exist — remove the old one (magus dir is canonical)
800
- await fs.remove(oldDir);
803
+ // 4b. Rename/remove old physical directories (runs even if keys were already migrated)
804
+ for (const oldName of OLD_MARKETPLACE_NAMES) {
805
+ const oldDir = path.join(pluginsDir, oldName);
806
+ try {
807
+ if (await fs.pathExists(oldDir)) {
808
+ if (!(await fs.pathExists(newDir))) {
809
+ await fs.rename(oldDir, newDir);
810
+ } else {
811
+ // Both exist — remove the old one (magus dir is canonical)
812
+ await fs.remove(oldDir);
813
+ }
801
814
  }
802
- }
803
- } catch { /* non-fatal: directory cleanup is best-effort */ }
815
+ } catch { /* non-fatal: directory cleanup is best-effort */ }
816
+ }
804
817
 
805
818
  // 4c. Update git remote URL in the marketplace clone (old → new repo)
806
819
  try {
807
- const marketplaceDir = await fs.pathExists(newDir) ? newDir : oldDir;
808
- if (await fs.pathExists(path.join(marketplaceDir, ".git"))) {
820
+ if (await fs.pathExists(path.join(newDir, ".git"))) {
809
821
  const { execSync } = await import("node:child_process");
810
822
  const remote = execSync("git remote get-url origin", {
811
- cwd: marketplaceDir, encoding: "utf-8", timeout: 5000,
823
+ cwd: newDir, encoding: "utf-8", timeout: 5000,
812
824
  }).trim();
813
825
  if (remote.includes("claude-code") && remote.includes("MadAppGang")) {
814
826
  const newRemote = remote.replace("claude-code", NEW_MARKETPLACE_NAME);
815
827
  execSync(`git remote set-url origin "${newRemote}"`, {
816
- cwd: marketplaceDir, encoding: "utf-8", timeout: 5000,
828
+ cwd: newDir, encoding: "utf-8", timeout: 5000,
817
829
  });
818
830
  }
819
831
  }
@@ -825,9 +837,13 @@ export async function migrateMarketplaceRename(
825
837
  let regCount = 0;
826
838
  const newPlugins: typeof registry.plugins = {};
827
839
  for (const [pluginId, entries] of Object.entries(registry.plugins)) {
828
- if (pluginId.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
840
+ const oldName = OLD_MARKETPLACE_NAMES.find((n) => pluginId.endsWith(`@${n}`));
841
+ if (oldName) {
829
842
  const pluginName = pluginId.slice(0, pluginId.lastIndexOf("@"));
830
- newPlugins[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = entries;
843
+ const newKey = `${pluginName}@${NEW_MARKETPLACE_NAME}`;
844
+ if (!newPlugins[newKey]) {
845
+ newPlugins[newKey] = entries;
846
+ }
831
847
  regCount++;
832
848
  } else {
833
849
  newPlugins[pluginId] = entries;
package/src/ui/App.js CHANGED
@@ -182,7 +182,7 @@ function AppContentInner({ showDebug, onDebugToggle, updateInfo, onExit, }) {
182
182
  type: "SHOW_PROGRESS",
183
183
  state: { message: "Scanning marketplaces..." },
184
184
  });
185
- // Migrate mag-claude-plugins → magus (idempotent), then repair plugin.json files
185
+ // Migrate old marketplace names → magus (idempotent), then repair plugin.json files
186
186
  migrateMarketplaceRename()
187
187
  .catch(() => { }); // non-blocking, best-effort
188
188
  repairAllMarketplaces()
package/src/ui/App.tsx CHANGED
@@ -265,7 +265,7 @@ function AppContentInner({
265
265
  state: { message: "Scanning marketplaces..." },
266
266
  });
267
267
 
268
- // Migrate mag-claude-plugins → magus (idempotent), then repair plugin.json files
268
+ // Migrate old marketplace names → magus (idempotent), then repair plugin.json files
269
269
  migrateMarketplaceRename()
270
270
  .catch(() => {}); // non-blocking, best-effort
271
271