claudeup 3.3.0 → 3.4.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 CHANGED
@@ -99,7 +99,7 @@ Releases are automated via GitHub Actions using [npm Trusted Publishing](https:/
99
99
  ```
100
100
 
101
101
  2. **Configure Trusted Publisher on npmjs.com** (already done):
102
- - Repository: `MadAppGang/claude-code`
102
+ - Repository: `MadAppGang/magus`
103
103
  - Workflow: `claudeup-release.yml`
104
104
 
105
105
  ### Releasing New Versions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeup",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "TUI tool for managing Claude Code plugins, MCPs, and configuration",
5
5
  "type": "module",
6
6
  "main": "src/main.tsx",
@@ -34,12 +34,12 @@
34
34
  "license": "MIT",
35
35
  "repository": {
36
36
  "type": "git",
37
- "url": "https://github.com/MadAppGang/claude-code"
37
+ "url": "https://github.com/MadAppGang/magus"
38
38
  },
39
39
  "bugs": {
40
- "url": "https://github.com/MadAppGang/claude-code/issues"
40
+ "url": "https://github.com/MadAppGang/magus/issues"
41
41
  },
42
- "homepage": "https://github.com/MadAppGang/claude-code/tree/main/tools/claudeup#readme",
42
+ "homepage": "https://github.com/MadAppGang/magus/tree/main/tools/claudeup#readme",
43
43
  "engines": {
44
44
  "bun": ">=1.0.0"
45
45
  },
@@ -5,7 +5,7 @@ export const cliTools = [
5
5
  description: "TUI tool for managing Claude Code plugins, MCPs, and configuration",
6
6
  installCommand: "npm install -g claudeup",
7
7
  checkCommand: "claudeup --version",
8
- website: "https://github.com/MadAppGang/claude-code/tree/main/tools/claudeup",
8
+ website: "https://github.com/MadAppGang/magus/tree/main/tools/claudeup",
9
9
  category: "ai-coding",
10
10
  packageManager: "npm",
11
11
  packageName: "claudeup",
@@ -19,7 +19,7 @@ export const cliTools: CliTool[] = [
19
19
  installCommand: "npm install -g claudeup",
20
20
  checkCommand: "claudeup --version",
21
21
  website:
22
- "https://github.com/MadAppGang/claude-code/tree/main/tools/claudeup",
22
+ "https://github.com/MadAppGang/magus/tree/main/tools/claudeup",
23
23
  category: "ai-coding",
24
24
  packageManager: "npm",
25
25
  packageName: "claudeup",
@@ -1,11 +1,11 @@
1
1
  import { formatMarketplaceName } from "../utils/string-utils.js";
2
2
  export const defaultMarketplaces = [
3
3
  {
4
- name: "mag-claude-plugins",
5
- displayName: "MadAppGang Plugins",
4
+ name: "magus",
5
+ displayName: "Magus",
6
6
  source: {
7
7
  source: "github",
8
- repo: "MadAppGang/claude-code",
8
+ repo: "MadAppGang/magus",
9
9
  },
10
10
  description: "Professional plugins for frontend, backend, and code analysis",
11
11
  official: false,
@@ -68,9 +68,9 @@ export function getAllMarketplaces(localMarketplaces) {
68
68
  seenRepos.add(repo);
69
69
  }
70
70
  }
71
- // Sort: MadAppGang first, then alphabetically
71
+ // Sort: Magus first, then alphabetically
72
72
  return Array.from(all.values()).sort((a, b) => {
73
- // MadAppGang always first
73
+ // Magus (MadAppGang) always first
74
74
  const aIsMag = a.source.repo?.toLowerCase().includes("madappgang/");
75
75
  const bIsMag = b.source.repo?.toLowerCase().includes("madappgang/");
76
76
  if (aIsMag && !bIsMag)
@@ -4,11 +4,11 @@ import { formatMarketplaceName } from "../utils/string-utils.js";
4
4
 
5
5
  export const defaultMarketplaces: Marketplace[] = [
6
6
  {
7
- name: "mag-claude-plugins",
8
- displayName: "MadAppGang Plugins",
7
+ name: "magus",
8
+ displayName: "Magus",
9
9
  source: {
10
10
  source: "github",
11
- repo: "MadAppGang/claude-code",
11
+ repo: "MadAppGang/magus",
12
12
  },
13
13
  description:
14
14
  "Professional plugins for frontend, backend, and code analysis",
@@ -82,9 +82,9 @@ export function getAllMarketplaces(
82
82
  }
83
83
  }
84
84
 
85
- // Sort: MadAppGang first, then alphabetically
85
+ // Sort: Magus first, then alphabetically
86
86
  return Array.from(all.values()).sort((a, b) => {
87
- // MadAppGang always first
87
+ // Magus (MadAppGang) always first
88
88
  const aIsMag = a.source.repo?.toLowerCase().includes("madappgang/");
89
89
  const bIsMag = b.source.repo?.toLowerCase().includes("madappgang/");
90
90
  if (aIsMag && !bIsMag) return -1;
@@ -1,7 +1,7 @@
1
1
  import { UpdateCache } from "../services/update-cache.js";
2
2
  import { getAvailablePlugins, clearMarketplaceCache, saveInstalledPluginVersion, } from "../services/plugin-manager.js";
3
3
  import { runClaude } from "../services/claude-runner.js";
4
- import { recoverMarketplaceSettings } from "../services/claude-settings.js";
4
+ import { recoverMarketplaceSettings, migrateMarketplaceRename } from "../services/claude-settings.js";
5
5
  /**
6
6
  * Prerun orchestration: Check for updates, apply them, then run claude
7
7
  * @param claudeArgs - Arguments to pass to claude CLI
@@ -11,6 +11,14 @@ import { recoverMarketplaceSettings } from "../services/claude-settings.js";
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)
15
+ const migration = await migrateMarketplaceRename();
16
+ const migTotal = migration.projectMigrated + migration.globalMigrated
17
+ + migration.localMigrated + migration.registryMigrated
18
+ + (migration.knownMarketplacesMigrated ? 1 : 0);
19
+ if (migTotal > 0) {
20
+ console.log(`✓ Migrated ${migTotal} plugin reference(s) from mag-claude-plugins → magus`);
21
+ }
14
22
  // STEP 1: Check if we should update (time-based cache, or forced)
15
23
  const shouldUpdate = options.force || (await cache.shouldCheckForUpdates());
16
24
  if (options.force) {
@@ -5,7 +5,7 @@ import {
5
5
  saveInstalledPluginVersion,
6
6
  } from "../services/plugin-manager.js";
7
7
  import { runClaude } from "../services/claude-runner.js";
8
- import { recoverMarketplaceSettings } from "../services/claude-settings.js";
8
+ import { recoverMarketplaceSettings, migrateMarketplaceRename } from "../services/claude-settings.js";
9
9
 
10
10
  export interface PrerunOptions {
11
11
  force?: boolean; // Bypass cache and force update check
@@ -24,6 +24,15 @@ 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)
28
+ const migration = await migrateMarketplaceRename();
29
+ const migTotal = migration.projectMigrated + migration.globalMigrated
30
+ + migration.localMigrated + migration.registryMigrated
31
+ + (migration.knownMarketplacesMigrated ? 1 : 0);
32
+ if (migTotal > 0) {
33
+ console.log(`✓ Migrated ${migTotal} plugin reference(s) from mag-claude-plugins → magus`);
34
+ }
35
+
27
36
  // STEP 1: Check if we should update (time-based cache, or forced)
28
37
  const shouldUpdate = options.force || (await cache.shouldCheckForUpdates());
29
38
 
@@ -156,7 +156,12 @@ export async function setAllowMcp(_allow, _projectPath) {
156
156
  export async function enablePlugin(pluginId, enabled, projectPath) {
157
157
  const settings = await readSettings(projectPath);
158
158
  settings.enabledPlugins = settings.enabledPlugins || {};
159
- settings.enabledPlugins[pluginId] = enabled;
159
+ if (enabled) {
160
+ settings.enabledPlugins[pluginId] = true;
161
+ }
162
+ else {
163
+ delete settings.enabledPlugins[pluginId];
164
+ }
160
165
  await writeSettings(settings, projectPath);
161
166
  }
162
167
  export async function getEnabledPlugins(projectPath) {
@@ -175,7 +180,12 @@ export async function getLocalInstalledPluginVersions(projectPath) {
175
180
  export async function enableLocalPlugin(pluginId, enabled, projectPath) {
176
181
  const settings = await readLocalSettings(projectPath);
177
182
  settings.enabledPlugins = settings.enabledPlugins || {};
178
- settings.enabledPlugins[pluginId] = enabled;
183
+ if (enabled) {
184
+ settings.enabledPlugins[pluginId] = true;
185
+ }
186
+ else {
187
+ delete settings.enabledPlugins[pluginId];
188
+ }
179
189
  await writeLocalSettings(settings, projectPath);
180
190
  }
181
191
  export async function saveLocalInstalledPluginVersion(pluginId, version, projectPath) {
@@ -284,7 +294,12 @@ export async function getGlobalConfiguredMarketplaces() {
284
294
  export async function enableGlobalPlugin(pluginId, enabled) {
285
295
  const settings = await readGlobalSettings();
286
296
  settings.enabledPlugins = settings.enabledPlugins || {};
287
- settings.enabledPlugins[pluginId] = enabled;
297
+ if (enabled) {
298
+ settings.enabledPlugins[pluginId] = true;
299
+ }
300
+ else {
301
+ delete settings.enabledPlugins[pluginId];
302
+ }
288
303
  await writeGlobalSettings(settings);
289
304
  }
290
305
  export async function getGlobalEnabledPlugins() {
@@ -398,8 +413,155 @@ export async function getMarketplaceAutoUpdate(marketplaceName) {
398
413
  const known = await readKnownMarketplaces();
399
414
  return known[marketplaceName]?.autoUpdate;
400
415
  }
416
+ // =============================================================================
417
+ // MARKETPLACE RENAME MIGRATION: mag-claude-plugins → magus
418
+ // =============================================================================
419
+ const OLD_MARKETPLACE_NAME = "mag-claude-plugins";
420
+ const NEW_MARKETPLACE_NAME = "magus";
421
+ /**
422
+ * Rename plugin keys in a Record from old marketplace to new.
423
+ * e.g., "frontend@mag-claude-plugins" → "frontend@magus"
424
+ * Returns [migratedRecord, count] — count=0 means no changes.
425
+ */
426
+ function migratePluginKeys(record) {
427
+ if (!record)
428
+ return [{}, 0];
429
+ const migrated = {};
430
+ let count = 0;
431
+ for (const [key, value] of Object.entries(record)) {
432
+ if (key.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
433
+ const pluginName = key.slice(0, key.lastIndexOf("@"));
434
+ migrated[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = value;
435
+ count++;
436
+ }
437
+ else {
438
+ migrated[key] = value;
439
+ }
440
+ }
441
+ return [migrated, count];
442
+ }
443
+ /**
444
+ * Migrate a single settings object in-place.
445
+ * Returns number of keys renamed.
446
+ */
447
+ function migrateSettingsObject(settings) {
448
+ let total = 0;
449
+ const [ep, epCount] = migratePluginKeys(settings.enabledPlugins);
450
+ if (epCount > 0) {
451
+ settings.enabledPlugins = ep;
452
+ total += epCount;
453
+ }
454
+ const [iv, ivCount] = migratePluginKeys(settings.installedPluginVersions);
455
+ if (ivCount > 0) {
456
+ settings.installedPluginVersions = iv;
457
+ total += ivCount;
458
+ }
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
+ }
466
+ return total;
467
+ }
468
+ /**
469
+ * Migrate all settings from mag-claude-plugins to magus.
470
+ * Safe to call multiple times — no-ops if already migrated.
471
+ * Runs across project settings, global settings, local settings,
472
+ * known_marketplaces.json, and installed_plugins.json.
473
+ */
474
+ export async function migrateMarketplaceRename(projectPath) {
475
+ const result = {
476
+ projectMigrated: 0,
477
+ globalMigrated: 0,
478
+ localMigrated: 0,
479
+ knownMarketplacesMigrated: false,
480
+ registryMigrated: 0,
481
+ };
482
+ // 1. Project settings
483
+ try {
484
+ const settings = await readSettings(projectPath);
485
+ const count = migrateSettingsObject(settings);
486
+ if (count > 0) {
487
+ await writeSettings(settings, projectPath);
488
+ result.projectMigrated = count;
489
+ }
490
+ }
491
+ catch { /* skip if unreadable */ }
492
+ // 2. Global settings
493
+ try {
494
+ const settings = await readGlobalSettings();
495
+ const count = migrateSettingsObject(settings);
496
+ if (count > 0) {
497
+ await writeGlobalSettings(settings);
498
+ result.globalMigrated = count;
499
+ }
500
+ }
501
+ catch { /* skip if unreadable */ }
502
+ // 3. Local settings (settings.local.json)
503
+ try {
504
+ const local = await readLocalSettings(projectPath);
505
+ let localCount = 0;
506
+ const [ep, epCount] = migratePluginKeys(local.enabledPlugins);
507
+ if (epCount > 0) {
508
+ local.enabledPlugins = ep;
509
+ localCount += epCount;
510
+ }
511
+ const [iv, ivCount] = migratePluginKeys(local.installedPluginVersions);
512
+ if (ivCount > 0) {
513
+ local.installedPluginVersions = iv;
514
+ localCount += ivCount;
515
+ }
516
+ if (localCount > 0) {
517
+ await writeLocalSettings(local, projectPath);
518
+ result.localMigrated = localCount;
519
+ }
520
+ }
521
+ catch { /* skip if unreadable */ }
522
+ // 4. known_marketplaces.json — rename the key
523
+ try {
524
+ const known = await readKnownMarketplaces();
525
+ if (known[OLD_MARKETPLACE_NAME]) {
526
+ known[NEW_MARKETPLACE_NAME] = {
527
+ ...known[OLD_MARKETPLACE_NAME],
528
+ source: {
529
+ ...known[OLD_MARKETPLACE_NAME].source,
530
+ repo: "MadAppGang/magus",
531
+ },
532
+ };
533
+ delete known[OLD_MARKETPLACE_NAME];
534
+ await writeKnownMarketplaces(known);
535
+ result.knownMarketplacesMigrated = true;
536
+ }
537
+ }
538
+ catch { /* skip if unreadable */ }
539
+ // 5. installed_plugins.json — rename plugin ID keys
540
+ try {
541
+ const registry = await readInstalledPluginsRegistry();
542
+ let regCount = 0;
543
+ const newPlugins = {};
544
+ for (const [pluginId, entries] of Object.entries(registry.plugins)) {
545
+ if (pluginId.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
546
+ const pluginName = pluginId.slice(0, pluginId.lastIndexOf("@"));
547
+ newPlugins[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = entries;
548
+ regCount++;
549
+ }
550
+ else {
551
+ newPlugins[pluginId] = entries;
552
+ }
553
+ }
554
+ if (regCount > 0) {
555
+ registry.plugins = newPlugins;
556
+ await writeInstalledPluginsRegistry(registry);
557
+ result.registryMigrated = regCount;
558
+ }
559
+ }
560
+ catch { /* skip if unreadable */ }
561
+ return result;
562
+ }
401
563
  /**
402
- * Check if a marketplace is from MadAppGang
564
+ * Check if a marketplace is from Magus (MadAppGang)
403
565
  */
404
566
  function isMadAppGangMarketplace(entry) {
405
567
  const repo = entry.source?.repo?.toLowerCase() || "";
@@ -407,7 +569,7 @@ function isMadAppGangMarketplace(entry) {
407
569
  }
408
570
  /**
409
571
  * Recover/sync marketplace settings:
410
- * - Enable autoUpdate for MadAppGang marketplaces that don't have it set
572
+ * - Enable autoUpdate for Magus marketplaces that don't have it set
411
573
  * - Remove entries for marketplaces whose installLocation no longer exists
412
574
  */
413
575
  export async function recoverMarketplaceSettings() {
@@ -424,7 +586,7 @@ export async function recoverMarketplaceSettings() {
424
586
  result.removed.push(name);
425
587
  continue;
426
588
  }
427
- // Enable autoUpdate if not set - only for MadAppGang marketplaces
589
+ // Enable autoUpdate if not set - only for Magus (MadAppGang) marketplaces
428
590
  if (entry.autoUpdate === undefined && isMadAppGangMarketplace(entry)) {
429
591
  entry.autoUpdate = true;
430
592
  result.enabledAutoUpdate.push(name);
@@ -225,7 +225,11 @@ export async function enablePlugin(
225
225
  ): Promise<void> {
226
226
  const settings = await readSettings(projectPath);
227
227
  settings.enabledPlugins = settings.enabledPlugins || {};
228
- settings.enabledPlugins[pluginId] = enabled;
228
+ if (enabled) {
229
+ settings.enabledPlugins[pluginId] = true;
230
+ } else {
231
+ delete settings.enabledPlugins[pluginId];
232
+ }
229
233
  await writeSettings(settings, projectPath);
230
234
  }
231
235
 
@@ -258,7 +262,11 @@ export async function enableLocalPlugin(
258
262
  ): Promise<void> {
259
263
  const settings = await readLocalSettings(projectPath);
260
264
  settings.enabledPlugins = settings.enabledPlugins || {};
261
- settings.enabledPlugins[pluginId] = enabled;
265
+ if (enabled) {
266
+ settings.enabledPlugins[pluginId] = true;
267
+ } else {
268
+ delete settings.enabledPlugins[pluginId];
269
+ }
262
270
  await writeLocalSettings(settings, projectPath);
263
271
  }
264
272
 
@@ -432,7 +440,11 @@ export async function enableGlobalPlugin(
432
440
  ): Promise<void> {
433
441
  const settings = await readGlobalSettings();
434
442
  settings.enabledPlugins = settings.enabledPlugins || {};
435
- settings.enabledPlugins[pluginId] = enabled;
443
+ if (enabled) {
444
+ settings.enabledPlugins[pluginId] = true;
445
+ } else {
446
+ delete settings.enabledPlugins[pluginId];
447
+ }
436
448
  await writeGlobalSettings(settings);
437
449
  }
438
450
 
@@ -617,8 +629,168 @@ export interface MarketplaceRecoveryResult {
617
629
  removed: string[];
618
630
  }
619
631
 
632
+ // =============================================================================
633
+ // MARKETPLACE RENAME MIGRATION: mag-claude-plugins → magus
634
+ // =============================================================================
635
+
636
+ const OLD_MARKETPLACE_NAME = "mag-claude-plugins";
637
+ const NEW_MARKETPLACE_NAME = "magus";
638
+
639
+ /**
640
+ * Rename plugin keys in a Record from old marketplace to new.
641
+ * e.g., "frontend@mag-claude-plugins" → "frontend@magus"
642
+ * Returns [migratedRecord, count] — count=0 means no changes.
643
+ */
644
+ function migratePluginKeys<T>(
645
+ record: Record<string, T> | undefined,
646
+ ): [Record<string, T>, number] {
647
+ if (!record) return [{}, 0];
648
+ const migrated: Record<string, T> = {};
649
+ let count = 0;
650
+ for (const [key, value] of Object.entries(record)) {
651
+ if (key.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
652
+ const pluginName = key.slice(0, key.lastIndexOf("@"));
653
+ migrated[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = value;
654
+ count++;
655
+ } else {
656
+ migrated[key] = value;
657
+ }
658
+ }
659
+ return [migrated, count];
660
+ }
661
+
662
+ /**
663
+ * Migrate a single settings object in-place.
664
+ * Returns number of keys renamed.
665
+ */
666
+ function migrateSettingsObject(settings: ClaudeSettings): number {
667
+ let total = 0;
668
+
669
+ const [ep, epCount] = migratePluginKeys(settings.enabledPlugins);
670
+ if (epCount > 0) {
671
+ settings.enabledPlugins = ep;
672
+ total += epCount;
673
+ }
674
+
675
+ const [iv, ivCount] = migratePluginKeys(settings.installedPluginVersions);
676
+ if (ivCount > 0) {
677
+ settings.installedPluginVersions = iv;
678
+ total += ivCount;
679
+ }
680
+
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
+ }
688
+
689
+ return total;
690
+ }
691
+
692
+ export interface MigrationResult {
693
+ projectMigrated: number;
694
+ globalMigrated: number;
695
+ localMigrated: number;
696
+ knownMarketplacesMigrated: boolean;
697
+ registryMigrated: number;
698
+ }
699
+
700
+ /**
701
+ * Migrate all settings from mag-claude-plugins to magus.
702
+ * Safe to call multiple times — no-ops if already migrated.
703
+ * Runs across project settings, global settings, local settings,
704
+ * known_marketplaces.json, and installed_plugins.json.
705
+ */
706
+ export async function migrateMarketplaceRename(
707
+ projectPath?: string,
708
+ ): Promise<MigrationResult> {
709
+ const result: MigrationResult = {
710
+ projectMigrated: 0,
711
+ globalMigrated: 0,
712
+ localMigrated: 0,
713
+ knownMarketplacesMigrated: false,
714
+ registryMigrated: 0,
715
+ };
716
+
717
+ // 1. Project settings
718
+ try {
719
+ const settings = await readSettings(projectPath);
720
+ const count = migrateSettingsObject(settings);
721
+ if (count > 0) {
722
+ await writeSettings(settings, projectPath);
723
+ result.projectMigrated = count;
724
+ }
725
+ } catch { /* skip if unreadable */ }
726
+
727
+ // 2. Global settings
728
+ try {
729
+ const settings = await readGlobalSettings();
730
+ const count = migrateSettingsObject(settings);
731
+ if (count > 0) {
732
+ await writeGlobalSettings(settings);
733
+ result.globalMigrated = count;
734
+ }
735
+ } catch { /* skip if unreadable */ }
736
+
737
+ // 3. Local settings (settings.local.json)
738
+ try {
739
+ const local = await readLocalSettings(projectPath);
740
+ let localCount = 0;
741
+ const [ep, epCount] = migratePluginKeys(local.enabledPlugins);
742
+ if (epCount > 0) { local.enabledPlugins = ep; localCount += epCount; }
743
+ const [iv, ivCount] = migratePluginKeys(local.installedPluginVersions);
744
+ if (ivCount > 0) { local.installedPluginVersions = iv; localCount += ivCount; }
745
+ if (localCount > 0) {
746
+ await writeLocalSettings(local, projectPath);
747
+ result.localMigrated = localCount;
748
+ }
749
+ } catch { /* skip if unreadable */ }
750
+
751
+ // 4. known_marketplaces.json — rename the key
752
+ try {
753
+ const known = await readKnownMarketplaces();
754
+ if (known[OLD_MARKETPLACE_NAME]) {
755
+ known[NEW_MARKETPLACE_NAME] = {
756
+ ...known[OLD_MARKETPLACE_NAME],
757
+ source: {
758
+ ...known[OLD_MARKETPLACE_NAME].source,
759
+ repo: "MadAppGang/magus",
760
+ },
761
+ };
762
+ delete known[OLD_MARKETPLACE_NAME];
763
+ await writeKnownMarketplaces(known);
764
+ result.knownMarketplacesMigrated = true;
765
+ }
766
+ } catch { /* skip if unreadable */ }
767
+
768
+ // 5. installed_plugins.json — rename plugin ID keys
769
+ try {
770
+ const registry = await readInstalledPluginsRegistry();
771
+ let regCount = 0;
772
+ const newPlugins: typeof registry.plugins = {};
773
+ for (const [pluginId, entries] of Object.entries(registry.plugins)) {
774
+ if (pluginId.endsWith(`@${OLD_MARKETPLACE_NAME}`)) {
775
+ const pluginName = pluginId.slice(0, pluginId.lastIndexOf("@"));
776
+ newPlugins[`${pluginName}@${NEW_MARKETPLACE_NAME}`] = entries;
777
+ regCount++;
778
+ } else {
779
+ newPlugins[pluginId] = entries;
780
+ }
781
+ }
782
+ if (regCount > 0) {
783
+ registry.plugins = newPlugins;
784
+ await writeInstalledPluginsRegistry(registry);
785
+ result.registryMigrated = regCount;
786
+ }
787
+ } catch { /* skip if unreadable */ }
788
+
789
+ return result;
790
+ }
791
+
620
792
  /**
621
- * Check if a marketplace is from MadAppGang
793
+ * Check if a marketplace is from Magus (MadAppGang)
622
794
  */
623
795
  function isMadAppGangMarketplace(entry: KnownMarketplaceEntry): boolean {
624
796
  const repo = entry.source?.repo?.toLowerCase() || "";
@@ -627,7 +799,7 @@ function isMadAppGangMarketplace(entry: KnownMarketplaceEntry): boolean {
627
799
 
628
800
  /**
629
801
  * Recover/sync marketplace settings:
630
- * - Enable autoUpdate for MadAppGang marketplaces that don't have it set
802
+ * - Enable autoUpdate for Magus marketplaces that don't have it set
631
803
  * - Remove entries for marketplaces whose installLocation no longer exists
632
804
  */
633
805
  export async function recoverMarketplaceSettings(): Promise<MarketplaceRecoveryResult> {
@@ -649,7 +821,7 @@ export async function recoverMarketplaceSettings(): Promise<MarketplaceRecoveryR
649
821
  continue;
650
822
  }
651
823
 
652
- // Enable autoUpdate if not set - only for MadAppGang marketplaces
824
+ // Enable autoUpdate if not set - only for Magus (MadAppGang) marketplaces
653
825
  if (entry.autoUpdate === undefined && isMadAppGangMarketplace(entry)) {
654
826
  entry.autoUpdate = true;
655
827
  result.enabledAutoUpdate.push(name);
@@ -398,8 +398,11 @@ export async function removeInstalledPluginVersion(pluginId, projectPath) {
398
398
  const settings = await readSettings(projectPath);
399
399
  if (settings.installedPluginVersions) {
400
400
  delete settings.installedPluginVersions[pluginId];
401
- await writeSettings(settings, projectPath);
402
401
  }
402
+ if (settings.enabledPlugins) {
403
+ delete settings.enabledPlugins[pluginId];
404
+ }
405
+ await writeSettings(settings, projectPath);
403
406
  // Remove from installed_plugins.json registry
404
407
  await removeFromInstalledPluginsRegistry(pluginId, "project", projectPath ? path.resolve(projectPath) : undefined);
405
408
  }
@@ -560,8 +560,11 @@ export async function removeInstalledPluginVersion(
560
560
  const settings = await readSettings(projectPath);
561
561
  if (settings.installedPluginVersions) {
562
562
  delete settings.installedPluginVersions[pluginId];
563
- await writeSettings(settings, projectPath);
564
563
  }
564
+ if (settings.enabledPlugins) {
565
+ delete settings.enabledPlugins[pluginId];
566
+ }
567
+ await writeSettings(settings, projectPath);
565
568
 
566
569
  // Remove from installed_plugins.json registry
567
570
  await removeFromInstalledPluginsRegistry(
@@ -43,7 +43,7 @@ function extractAllEnvVarReferences(obj) {
43
43
  }
44
44
  /**
45
45
  * Get the path to a plugin's mcp-config.json in the marketplace cache
46
- * @param marketplaceName - Name of the marketplace (e.g., "mag-claude-plugins")
46
+ * @param marketplaceName - Name of the marketplace (e.g., "magus")
47
47
  * @param pluginSource - Plugin source path from marketplace.json (e.g., "./plugins/frontend")
48
48
  * @returns Full path to mcp-config.json or undefined if not found
49
49
  */
@@ -98,7 +98,7 @@ function generateLabel(varName) {
98
98
  * Get all environment variable requirements for a plugin
99
99
  * Extracts ${VAR_NAME} patterns from the plugin's mcp-config.json
100
100
  *
101
- * @param marketplaceName - Name of the marketplace (e.g., "mag-claude-plugins")
101
+ * @param marketplaceName - Name of the marketplace (e.g., "magus")
102
102
  * @param pluginSource - Plugin source path from marketplace.json (e.g., "./plugins/frontend")
103
103
  * @returns Array of required env vars with metadata
104
104
  */
@@ -74,7 +74,7 @@ interface McpServerConfig {
74
74
 
75
75
  /**
76
76
  * Get the path to a plugin's mcp-config.json in the marketplace cache
77
- * @param marketplaceName - Name of the marketplace (e.g., "mag-claude-plugins")
77
+ * @param marketplaceName - Name of the marketplace (e.g., "magus")
78
78
  * @param pluginSource - Plugin source path from marketplace.json (e.g., "./plugins/frontend")
79
79
  * @returns Full path to mcp-config.json or undefined if not found
80
80
  */
@@ -142,7 +142,7 @@ function generateLabel(varName: string): string {
142
142
  * Get all environment variable requirements for a plugin
143
143
  * Extracts ${VAR_NAME} patterns from the plugin's mcp-config.json
144
144
  *
145
- * @param marketplaceName - Name of the marketplace (e.g., "mag-claude-plugins")
145
+ * @param marketplaceName - Name of the marketplace (e.g., "magus")
146
146
  * @param pluginSource - Plugin source path from marketplace.json (e.g., "./plugins/frontend")
147
147
  * @returns Array of required env vars with metadata
148
148
  */
@@ -7,7 +7,7 @@ const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
7
7
  export interface UpdateCacheData {
8
8
  lastUpdateCheck: string; // ISO timestamp
9
9
  lastUpdateResult: {
10
- updated: string[]; // ["frontend@mag-claude-plugins v3.13.0", ...]
10
+ updated: string[]; // ["frontend@magus v3.13.0", ...]
11
11
  failed: string[]; // Marketplaces that failed
12
12
  autoUpdated?: Array<{
13
13
  pluginId: string;
package/src/ui/App.js CHANGED
@@ -7,6 +7,7 @@ import { DimensionsProvider, useDimensions, } from "./state/DimensionsContext.js
7
7
  import { ModalContainer } from "./components/modals/index.js";
8
8
  import { PluginsScreen, McpScreen, McpRegistryScreen, StatusLineScreen, EnvVarsScreen, CliToolsScreen, ModelSelectorScreen, } from "./screens/index.js";
9
9
  import { repairAllMarketplaces } from "../services/local-marketplace.js";
10
+ import { migrateMarketplaceRename } from "../services/claude-settings.js";
10
11
  import { checkForUpdates, getCurrentVersion, } from "../services/version-check.js";
11
12
  import { useKeyboardHandler } from "./hooks/useKeyboardHandler.js";
12
13
  import { ProgressBar } from "./components/layout/ProgressBar.js";
@@ -181,8 +182,9 @@ function AppContentInner({ showDebug, onDebugToggle, updateInfo, onExit, }) {
181
182
  type: "SHOW_PROGRESS",
182
183
  state: { message: "Scanning marketplaces..." },
183
184
  });
184
- // Note: Marketplace updates should be done via Claude Code's /plugin marketplace update
185
- // Just repair plugin.json files
185
+ // Migrate mag-claude-plugins magus (idempotent), then repair plugin.json files
186
+ migrateMarketplaceRename()
187
+ .catch(() => { }); // non-blocking, best-effort
186
188
  repairAllMarketplaces()
187
189
  .then(async () => {
188
190
  dispatch({ type: "HIDE_PROGRESS" });
package/src/ui/App.tsx CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  } from "./screens/index.js";
24
24
  import type { Screen } from "./state/types.js";
25
25
  import { repairAllMarketplaces } from "../services/local-marketplace.js";
26
+ import { migrateMarketplaceRename } from "../services/claude-settings.js";
26
27
  import {
27
28
  checkForUpdates,
28
29
  getCurrentVersion,
@@ -264,8 +265,10 @@ function AppContentInner({
264
265
  state: { message: "Scanning marketplaces..." },
265
266
  });
266
267
 
267
- // Note: Marketplace updates should be done via Claude Code's /plugin marketplace update
268
- // Just repair plugin.json files
268
+ // Migrate mag-claude-plugins magus (idempotent), then repair plugin.json files
269
+ migrateMarketplaceRename()
270
+ .catch(() => {}); // non-blocking, best-effort
271
+
269
272
  repairAllMarketplaces()
270
273
  .then(async () => {
271
274
  dispatch({ type: "HIDE_PROGRESS" });
@@ -265,7 +265,7 @@ export function PluginsScreen() {
265
265
  await modal.message("Add Marketplace", "To add a marketplace, run this command in your terminal:\n\n" +
266
266
  " claude marketplace add owner/repo\n\n" +
267
267
  "Examples:\n" +
268
- " claude marketplace add MadAppGang/claude-code\n" +
268
+ " claude marketplace add MadAppGang/magus\n" +
269
269
  " claude marketplace add anthropics/claude-plugins-official\n\n" +
270
270
  "Auto-update is enabled by default for new marketplaces.\n\n" +
271
271
  "After adding, refresh claudeup with 'r' to see the new marketplace.", "info");
@@ -344,7 +344,7 @@ export function PluginsScreen() {
344
344
  "To add a marketplace, run this command in your terminal:\n\n" +
345
345
  " claude marketplace add owner/repo\n\n" +
346
346
  "Examples:\n" +
347
- " claude marketplace add MadAppGang/claude-code\n" +
347
+ " claude marketplace add MadAppGang/magus\n" +
348
348
  " claude marketplace add anthropics/claude-plugins-official\n\n" +
349
349
  "Auto-update is enabled by default for new marketplaces.\n\n" +
350
350
  "After adding, refresh claudeup with 'r' to see the new marketplace.",
@@ -3,7 +3,7 @@
3
3
  */
4
4
  /**
5
5
  * Format marketplace name for display
6
- * e.g., "mag-claude-plugins" -> "Mag Claude Plugins"
6
+ * e.g., "magus" -> "Magus"
7
7
  */
8
8
  export function formatMarketplaceName(name) {
9
9
  return name
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * Format marketplace name for display
7
- * e.g., "mag-claude-plugins" -> "Mag Claude Plugins"
7
+ * e.g., "magus" -> "Magus"
8
8
  */
9
9
  export function formatMarketplaceName(name: string): string {
10
10
  return name