claudeup 3.4.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 +1 -1
- package/src/data/marketplaces.js +40 -7
- package/src/data/marketplaces.ts +44 -7
- package/src/prerunner/index.js +2 -2
- package/src/prerunner/index.ts +2 -2
- package/src/services/claude-settings.js +87 -23
- package/src/services/claude-settings.ts +93 -23
- package/src/ui/App.js +1 -1
- package/src/ui/App.tsx +1 -1
package/package.json
CHANGED
package/src/data/marketplaces.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { formatMarketplaceName } from "../utils/string-utils.js";
|
|
2
|
+
/**
|
|
3
|
+
* Known repo aliases — GitHub redirects the old repo to the new one,
|
|
4
|
+
* so these should be treated as identical for deduplication.
|
|
5
|
+
*/
|
|
6
|
+
const REPO_ALIASES = {
|
|
7
|
+
"madappgang/claude-code": "madappgang/magus",
|
|
8
|
+
};
|
|
9
|
+
/** Normalize a repo string through known aliases. */
|
|
10
|
+
function normalizeRepo(repo) {
|
|
11
|
+
const lower = repo.toLowerCase();
|
|
12
|
+
return REPO_ALIASES[lower] || lower;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Deprecated marketplace names that should be hidden if the canonical
|
|
16
|
+
* marketplace is already present. Maps deprecated name → canonical name.
|
|
17
|
+
*/
|
|
18
|
+
export const deprecatedMarketplaces = {
|
|
19
|
+
"mag-claude-plugins": "magus",
|
|
20
|
+
"MadAppGang-claude-code": "magus",
|
|
21
|
+
};
|
|
2
22
|
export const defaultMarketplaces = [
|
|
3
23
|
{
|
|
4
24
|
name: "magus",
|
|
@@ -37,23 +57,36 @@ export function getMarketplaceByName(name) {
|
|
|
37
57
|
}
|
|
38
58
|
// Get all available marketplaces from local cache + hardcoded defaults
|
|
39
59
|
// Local cache is primary source of truth, defaults are fallback
|
|
40
|
-
// Deduplicates by repo URL to avoid showing same marketplace twice
|
|
60
|
+
// Deduplicates by normalized repo URL to avoid showing same marketplace twice
|
|
41
61
|
export function getAllMarketplaces(localMarketplaces) {
|
|
42
62
|
const all = new Map();
|
|
43
63
|
const seenRepos = new Set();
|
|
44
64
|
// Primary source: local cache (what's actually cloned)
|
|
45
65
|
if (localMarketplaces) {
|
|
46
66
|
for (const [name, local] of localMarketplaces) {
|
|
47
|
-
const repo = local.gitRepo || "";
|
|
67
|
+
const repo = normalizeRepo(local.gitRepo || "");
|
|
68
|
+
// Skip deprecated marketplaces if their canonical replacement exists
|
|
69
|
+
// (or will be added from defaults)
|
|
70
|
+
const canonical = deprecatedMarketplaces[name];
|
|
71
|
+
if (canonical) {
|
|
72
|
+
// If canonical already in the map or in defaults, skip this entry
|
|
73
|
+
if (all.has(canonical) || defaultMarketplaces.some((m) => m.name === canonical)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Skip if another marketplace already claimed this repo URL
|
|
78
|
+
if (repo && seenRepos.has(repo))
|
|
79
|
+
continue;
|
|
48
80
|
if (repo)
|
|
49
|
-
seenRepos.add(repo
|
|
81
|
+
seenRepos.add(repo);
|
|
50
82
|
// Check if this marketplace has defaults (for official/featured flags)
|
|
51
83
|
const defaultMp = defaultMarketplaces.find((m) => m.name === name);
|
|
52
84
|
all.set(name, {
|
|
53
85
|
name,
|
|
54
|
-
displayName
|
|
55
|
-
|
|
56
|
-
|
|
86
|
+
// Prefer default displayName over stale local clone data
|
|
87
|
+
displayName: defaultMp?.displayName || local.name || formatMarketplaceName(name),
|
|
88
|
+
source: { source: "github", repo: defaultMp?.source.repo || local.gitRepo || "" },
|
|
89
|
+
description: defaultMp?.description || local.description || "",
|
|
57
90
|
official: defaultMp?.official ?? repo.toLowerCase().includes("anthropics/"),
|
|
58
91
|
featured: defaultMp?.featured,
|
|
59
92
|
});
|
|
@@ -61,7 +94,7 @@ export function getAllMarketplaces(localMarketplaces) {
|
|
|
61
94
|
}
|
|
62
95
|
// Fallback: hardcoded defaults (only if their repo isn't already represented)
|
|
63
96
|
for (const mp of defaultMarketplaces) {
|
|
64
|
-
const repo = mp.source.repo
|
|
97
|
+
const repo = normalizeRepo(mp.source.repo || "");
|
|
65
98
|
if (!all.has(mp.name) && !seenRepos.has(repo)) {
|
|
66
99
|
all.set(mp.name, mp);
|
|
67
100
|
if (repo)
|
package/src/data/marketplaces.ts
CHANGED
|
@@ -2,6 +2,29 @@ import type { Marketplace } from "../types/index.js";
|
|
|
2
2
|
import type { LocalMarketplace } from "../services/local-marketplace.js";
|
|
3
3
|
import { formatMarketplaceName } from "../utils/string-utils.js";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Known repo aliases — GitHub redirects the old repo to the new one,
|
|
7
|
+
* so these should be treated as identical for deduplication.
|
|
8
|
+
*/
|
|
9
|
+
const REPO_ALIASES: Record<string, string> = {
|
|
10
|
+
"madappgang/claude-code": "madappgang/magus",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Normalize a repo string through known aliases. */
|
|
14
|
+
function normalizeRepo(repo: string): string {
|
|
15
|
+
const lower = repo.toLowerCase();
|
|
16
|
+
return REPO_ALIASES[lower] || lower;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Deprecated marketplace names that should be hidden if the canonical
|
|
21
|
+
* marketplace is already present. Maps deprecated name → canonical name.
|
|
22
|
+
*/
|
|
23
|
+
export const deprecatedMarketplaces: Record<string, string> = {
|
|
24
|
+
"mag-claude-plugins": "magus",
|
|
25
|
+
"MadAppGang-claude-code": "magus",
|
|
26
|
+
};
|
|
27
|
+
|
|
5
28
|
export const defaultMarketplaces: Marketplace[] = [
|
|
6
29
|
{
|
|
7
30
|
name: "magus",
|
|
@@ -45,7 +68,7 @@ export function getMarketplaceByName(name: string): Marketplace | undefined {
|
|
|
45
68
|
|
|
46
69
|
// Get all available marketplaces from local cache + hardcoded defaults
|
|
47
70
|
// Local cache is primary source of truth, defaults are fallback
|
|
48
|
-
// Deduplicates by repo URL to avoid showing same marketplace twice
|
|
71
|
+
// Deduplicates by normalized repo URL to avoid showing same marketplace twice
|
|
49
72
|
export function getAllMarketplaces(
|
|
50
73
|
localMarketplaces?: Map<string, LocalMarketplace>,
|
|
51
74
|
): Marketplace[] {
|
|
@@ -55,17 +78,31 @@ export function getAllMarketplaces(
|
|
|
55
78
|
// Primary source: local cache (what's actually cloned)
|
|
56
79
|
if (localMarketplaces) {
|
|
57
80
|
for (const [name, local] of localMarketplaces) {
|
|
58
|
-
const repo = local.gitRepo || "";
|
|
59
|
-
|
|
81
|
+
const repo = normalizeRepo(local.gitRepo || "");
|
|
82
|
+
|
|
83
|
+
// Skip deprecated marketplaces if their canonical replacement exists
|
|
84
|
+
// (or will be added from defaults)
|
|
85
|
+
const canonical = deprecatedMarketplaces[name];
|
|
86
|
+
if (canonical) {
|
|
87
|
+
// If canonical already in the map or in defaults, skip this entry
|
|
88
|
+
if (all.has(canonical) || defaultMarketplaces.some((m) => m.name === canonical)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Skip if another marketplace already claimed this repo URL
|
|
94
|
+
if (repo && seenRepos.has(repo)) continue;
|
|
95
|
+
if (repo) seenRepos.add(repo);
|
|
60
96
|
|
|
61
97
|
// Check if this marketplace has defaults (for official/featured flags)
|
|
62
98
|
const defaultMp = defaultMarketplaces.find((m) => m.name === name);
|
|
63
99
|
|
|
64
100
|
all.set(name, {
|
|
65
101
|
name,
|
|
66
|
-
displayName
|
|
67
|
-
|
|
68
|
-
|
|
102
|
+
// Prefer default displayName over stale local clone data
|
|
103
|
+
displayName: defaultMp?.displayName || local.name || formatMarketplaceName(name),
|
|
104
|
+
source: { source: "github" as const, repo: defaultMp?.source.repo || local.gitRepo || "" },
|
|
105
|
+
description: defaultMp?.description || local.description || "",
|
|
69
106
|
official:
|
|
70
107
|
defaultMp?.official ?? repo.toLowerCase().includes("anthropics/"),
|
|
71
108
|
featured: defaultMp?.featured,
|
|
@@ -75,7 +112,7 @@ export function getAllMarketplaces(
|
|
|
75
112
|
|
|
76
113
|
// Fallback: hardcoded defaults (only if their repo isn't already represented)
|
|
77
114
|
for (const mp of defaultMarketplaces) {
|
|
78
|
-
const repo = mp.source.repo
|
|
115
|
+
const repo = normalizeRepo(mp.source.repo || "");
|
|
79
116
|
if (!all.has(mp.name) && !seenRepos.has(repo)) {
|
|
80
117
|
all.set(mp.name, mp);
|
|
81
118
|
if (repo) seenRepos.add(repo);
|
package/src/prerunner/index.js
CHANGED
|
@@ -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
|
|
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)
|
|
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());
|
package/src/prerunner/index.ts
CHANGED
|
@@ -24,13 +24,13 @@ export async function prerunClaude(
|
|
|
24
24
|
const cache = new UpdateCache();
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
|
-
// STEP 0: Migrate
|
|
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)
|
|
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
|
|
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
|
-
|
|
433
|
+
const oldName = OLD_MARKETPLACE_NAMES.find((n) => key.endsWith(`@${n}`));
|
|
434
|
+
if (oldName) {
|
|
433
435
|
const pluginName = key.slice(0, key.lastIndexOf("@"));
|
|
434
|
-
|
|
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
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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,32 +529,86 @@ export async function migrateMarketplaceRename(projectPath) {
|
|
|
519
529
|
}
|
|
520
530
|
}
|
|
521
531
|
catch { /* skip if unreadable */ }
|
|
522
|
-
// 4. known_marketplaces.json — rename
|
|
532
|
+
// 4. known_marketplaces.json — rename old keys + physical directory cleanup
|
|
533
|
+
const pluginsDir = path.join(os.homedir(), ".claude", "plugins", "marketplaces");
|
|
534
|
+
const newDir = path.join(pluginsDir, NEW_MARKETPLACE_NAME);
|
|
523
535
|
try {
|
|
524
536
|
const known = await readKnownMarketplaces();
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
537
|
+
let knownModified = false;
|
|
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;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (knownModified) {
|
|
534
562
|
await writeKnownMarketplaces(known);
|
|
535
563
|
result.knownMarketplacesMigrated = true;
|
|
536
564
|
}
|
|
537
565
|
}
|
|
538
566
|
catch { /* skip if unreadable */ }
|
|
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
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
catch { /* non-fatal: directory cleanup is best-effort */ }
|
|
582
|
+
}
|
|
583
|
+
// 4c. Update git remote URL in the marketplace clone (old → new repo)
|
|
584
|
+
try {
|
|
585
|
+
if (await fs.pathExists(path.join(newDir, ".git"))) {
|
|
586
|
+
const { execSync } = await import("node:child_process");
|
|
587
|
+
const remote = execSync("git remote get-url origin", {
|
|
588
|
+
cwd: newDir, encoding: "utf-8", timeout: 5000,
|
|
589
|
+
}).trim();
|
|
590
|
+
if (remote.includes("claude-code") && remote.includes("MadAppGang")) {
|
|
591
|
+
const newRemote = remote.replace("claude-code", NEW_MARKETPLACE_NAME);
|
|
592
|
+
execSync(`git remote set-url origin "${newRemote}"`, {
|
|
593
|
+
cwd: newDir, encoding: "utf-8", timeout: 5000,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
catch { /* non-fatal: git remote update is best-effort */ }
|
|
539
599
|
// 5. installed_plugins.json — rename plugin ID keys
|
|
540
600
|
try {
|
|
541
601
|
const registry = await readInstalledPluginsRegistry();
|
|
542
602
|
let regCount = 0;
|
|
543
603
|
const newPlugins = {};
|
|
544
604
|
for (const [pluginId, entries] of Object.entries(registry.plugins)) {
|
|
545
|
-
|
|
605
|
+
const oldName = OLD_MARKETPLACE_NAMES.find((n) => pluginId.endsWith(`@${n}`));
|
|
606
|
+
if (oldName) {
|
|
546
607
|
const pluginName = pluginId.slice(0, pluginId.lastIndexOf("@"));
|
|
547
|
-
|
|
608
|
+
const newKey = `${pluginName}@${NEW_MARKETPLACE_NAME}`;
|
|
609
|
+
if (!newPlugins[newKey]) {
|
|
610
|
+
newPlugins[newKey] = entries;
|
|
611
|
+
}
|
|
548
612
|
regCount++;
|
|
549
613
|
}
|
|
550
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
|
|
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
|
-
|
|
652
|
+
const oldName = OLD_MARKETPLACE_NAMES.find((n) => key.endsWith(`@${n}`));
|
|
653
|
+
if (oldName) {
|
|
652
654
|
const pluginName = key.slice(0, key.lastIndexOf("@"));
|
|
653
|
-
|
|
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
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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,32 +758,92 @@ export async function migrateMarketplaceRename(
|
|
|
748
758
|
}
|
|
749
759
|
} catch { /* skip if unreadable */ }
|
|
750
760
|
|
|
751
|
-
// 4. known_marketplaces.json — rename
|
|
761
|
+
// 4. known_marketplaces.json — rename old keys + physical directory cleanup
|
|
762
|
+
const pluginsDir = path.join(os.homedir(), ".claude", "plugins", "marketplaces");
|
|
763
|
+
const newDir = path.join(pluginsDir, NEW_MARKETPLACE_NAME);
|
|
764
|
+
|
|
752
765
|
try {
|
|
753
766
|
const known = await readKnownMarketplaces();
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
767
|
+
let knownModified = false;
|
|
768
|
+
|
|
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;
|
|
784
|
+
}
|
|
785
|
+
|
|
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
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (knownModified) {
|
|
763
798
|
await writeKnownMarketplaces(known);
|
|
764
799
|
result.knownMarketplacesMigrated = true;
|
|
765
800
|
}
|
|
766
801
|
} catch { /* skip if unreadable */ }
|
|
767
802
|
|
|
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
|
+
}
|
|
814
|
+
}
|
|
815
|
+
} catch { /* non-fatal: directory cleanup is best-effort */ }
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// 4c. Update git remote URL in the marketplace clone (old → new repo)
|
|
819
|
+
try {
|
|
820
|
+
if (await fs.pathExists(path.join(newDir, ".git"))) {
|
|
821
|
+
const { execSync } = await import("node:child_process");
|
|
822
|
+
const remote = execSync("git remote get-url origin", {
|
|
823
|
+
cwd: newDir, encoding: "utf-8", timeout: 5000,
|
|
824
|
+
}).trim();
|
|
825
|
+
if (remote.includes("claude-code") && remote.includes("MadAppGang")) {
|
|
826
|
+
const newRemote = remote.replace("claude-code", NEW_MARKETPLACE_NAME);
|
|
827
|
+
execSync(`git remote set-url origin "${newRemote}"`, {
|
|
828
|
+
cwd: newDir, encoding: "utf-8", timeout: 5000,
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
} catch { /* non-fatal: git remote update is best-effort */ }
|
|
833
|
+
|
|
768
834
|
// 5. installed_plugins.json — rename plugin ID keys
|
|
769
835
|
try {
|
|
770
836
|
const registry = await readInstalledPluginsRegistry();
|
|
771
837
|
let regCount = 0;
|
|
772
838
|
const newPlugins: typeof registry.plugins = {};
|
|
773
839
|
for (const [pluginId, entries] of Object.entries(registry.plugins)) {
|
|
774
|
-
|
|
840
|
+
const oldName = OLD_MARKETPLACE_NAMES.find((n) => pluginId.endsWith(`@${n}`));
|
|
841
|
+
if (oldName) {
|
|
775
842
|
const pluginName = pluginId.slice(0, pluginId.lastIndexOf("@"));
|
|
776
|
-
|
|
843
|
+
const newKey = `${pluginName}@${NEW_MARKETPLACE_NAME}`;
|
|
844
|
+
if (!newPlugins[newKey]) {
|
|
845
|
+
newPlugins[newKey] = entries;
|
|
846
|
+
}
|
|
777
847
|
regCount++;
|
|
778
848
|
} else {
|
|
779
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
|
|
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
|
|
268
|
+
// Migrate old marketplace names → magus (idempotent), then repair plugin.json files
|
|
269
269
|
migrateMarketplaceRename()
|
|
270
270
|
.catch(() => {}); // non-blocking, best-effort
|
|
271
271
|
|