agentinit 1.16.0 → 1.16.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.
- package/CHANGELOG.md +16 -2
- package/README.md +5 -2
- package/dist/cli.js +438 -96
- package/dist/core/pluginManager.d.ts +11 -0
- package/dist/core/pluginManager.d.ts.map +1 -1
- package/dist/core/pluginManager.js +274 -9
- package/dist/core/pluginManager.js.map +1 -1
- package/dist/core/skillsManager.d.ts +5 -0
- package/dist/core/skillsManager.d.ts.map +1 -1
- package/dist/core/skillsManager.js +173 -74
- package/dist/core/skillsManager.js.map +1 -1
- package/dist/types/skills.d.ts +1 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -42,8 +42,18 @@ export declare class PluginManager {
|
|
|
42
42
|
private getClaudeNativeInstallTarget;
|
|
43
43
|
private readClaudeInstalledPlugins;
|
|
44
44
|
private saveClaudeInstalledPlugins;
|
|
45
|
+
private readClaudeKnownMarketplaces;
|
|
46
|
+
private saveClaudeKnownMarketplaces;
|
|
45
47
|
private readClaudeSettings;
|
|
46
48
|
private saveClaudeSettings;
|
|
49
|
+
private findClaudeMarketplaceRoot;
|
|
50
|
+
private readClaudeMarketplaceManifest;
|
|
51
|
+
private saveClaudeMarketplaceManifest;
|
|
52
|
+
private resolveMarketplaceSourcePath;
|
|
53
|
+
private readClaudePluginMetadata;
|
|
54
|
+
private copyClaudeMarketplacePlugin;
|
|
55
|
+
private getClaudeMarketplaceSource;
|
|
56
|
+
private materializeClaudeMarketplace;
|
|
47
57
|
private installNativeClaudePlugin;
|
|
48
58
|
private toNativePluginPreview;
|
|
49
59
|
private removeNativeClaudePlugin;
|
|
@@ -125,6 +135,7 @@ export declare class PluginManager {
|
|
|
125
135
|
* Install skills from a plugin, deduplicating by shared directory
|
|
126
136
|
*/
|
|
127
137
|
private installPluginSkills;
|
|
138
|
+
private getPortableSkillAgents;
|
|
128
139
|
/**
|
|
129
140
|
* Apply MCP servers from a plugin to each target agent
|
|
130
141
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluginManager.d.ts","sourceRoot":"","sources":["../../src/core/pluginManager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EAGjB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EAErB,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,aAAa,EAAE,MAAM,CAAC;IACtC,SAAgB,eAAe,EAAE,MAAM,CAAC;IACxC,SAAgB,WAAW,EAAE,MAAM,EAAE,CAAC;gBAGpC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EAAE;CAaxB;
|
|
1
|
+
{"version":3,"file":"pluginManager.d.ts","sourceRoot":"","sources":["../../src/core/pluginManager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EAGjB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EAErB,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,aAAa,EAAE,MAAM,CAAC;IACtC,SAAgB,eAAe,EAAE,MAAM,CAAC;IACxC,SAAgB,WAAW,EAAE,MAAM,EAAE,CAAC;gBAGpC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EAAE;CAaxB;AA6BD,KAAK,qBAAqB,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAgEF,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,uBAAuB,CAA0C;gBAE7D,YAAY,CAAC,EAAE,YAAY;IAKvC,OAAO,CAAC,qBAAqB;YAIf,0BAA0B;YAM1B,2BAA2B;IASzC,OAAO,CAAC,0BAA0B;IAS5B,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5G,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,0BAA0B;IA8BlC,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,sBAAsB;YAQhB,wBAAwB;IA6FhC,uBAAuB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,QAAQ,GAAE,MAAM,EAAO,GACtB,OAAO,CAAC,gBAAgB,GAAG;QAAE,kBAAkB,CAAC,EAAE,qBAAqB,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC;YAY1F,iBAAiB;YAiEjB,qBAAqB;IAY7B,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAM,GAC/C,OAAO,CAAC,sBAAsB,CAAC;IAa5B,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAM,GAC/C,OAAO,CAAC,sBAAsB,CAAC;IAUlC,OAAO,CAAC,sBAAsB;YAQhB,2BAA2B;YA0B3B,4BAA4B;YAwC5B,0BAA0B;YAkB1B,0BAA0B;YAI1B,2BAA2B;YAiB3B,2BAA2B;YAI3B,kBAAkB;YAsBlB,kBAAkB;YAIlB,yBAAyB;YAgBzB,6BAA6B;YA0B7B,6BAA6B;IAW3C,OAAO,CAAC,4BAA4B;YAatB,wBAAwB;YAkBxB,2BAA2B;IAYzC,OAAO,CAAC,0BAA0B;YAkCpB,4BAA4B;YAgE5B,yBAAyB;IAiHvC,OAAO,CAAC,qBAAqB;YASf,wBAAwB;IAsDtC;;;;;;;;OAQG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,YAAY;IA4EpF,iBAAiB,IAAI,MAAM,EAAE;IAI7B;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI3D;;OAEG;IACG,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAkDnD,wBAAwB;YAoBxB,4BAA4B;YAiB5B,gBAAgB;IAU9B;;OAEG;IACG,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBjF;;OAEG;IACG,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAyEjH;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAY5D;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAarF;;OAEG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwC3F;;OAEG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiC3F;;OAEG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmB5F;;;OAGG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAajE;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,GAAG,GAAG,eAAe,EAAE;IA6BlD;;OAEG;IACG,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA8BtG;;OAEG;YACW,2BAA2B;IAuCzC;;;OAGG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC;IAiF/B;;OAEG;YACW,mBAAmB;IAwEjC,OAAO,CAAC,sBAAsB;IA4B9B;;OAEG;YACW,qBAAqB;IAkDnC;;OAEG;IACG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAehG;;;OAGG;IACG,sBAAsB,CAC1B,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,gBAAgB,EAAE,KAAK,EAAE,CAAC;QAC1B,oBAAoB,EAAE,MAAM,EAAE,CAAC;KAChC,CAAC,CAAC;IAoDH;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAYjF;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlG;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlG;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAgBzH;;OAEG;IACG,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,OAAO,CAAA;KAAO,GACnE,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CA0MpD"}
|
|
@@ -38,6 +38,12 @@ function getRegistryPath(projectPath, global) {
|
|
|
38
38
|
function getClaudeInstalledPluginsPath() {
|
|
39
39
|
return join(homedir(), '.claude', 'plugins', 'installed_plugins.json');
|
|
40
40
|
}
|
|
41
|
+
function getClaudeKnownMarketplacesPath() {
|
|
42
|
+
return join(homedir(), '.claude', 'plugins', 'known_marketplaces.json');
|
|
43
|
+
}
|
|
44
|
+
function getClaudeMarketplaceInstallPath(namespace) {
|
|
45
|
+
return join(homedir(), '.claude', 'plugins', 'marketplaces', namespace);
|
|
46
|
+
}
|
|
41
47
|
function getClaudeSettingsPath() {
|
|
42
48
|
return join(homedir(), '.claude', 'settings.json');
|
|
43
49
|
}
|
|
@@ -292,6 +298,8 @@ export class PluginManager {
|
|
|
292
298
|
(async () => !!manifest.commands || await isDirectory(join(pluginDir, 'commands')))(),
|
|
293
299
|
(async () => !!manifest.hooks || await isDirectory(join(pluginDir, 'hooks')))(),
|
|
294
300
|
(async () => !!manifest.agents || await isDirectory(join(pluginDir, 'agents')))(),
|
|
301
|
+
isDirectory(join(pluginDir, 'skills')),
|
|
302
|
+
(async () => !!manifest.mcpServers || await fileExists(join(pluginDir, '.mcp.json')))(),
|
|
295
303
|
isDirectory(join(pluginDir, 'prompts')),
|
|
296
304
|
isDirectory(join(pluginDir, 'schemas')),
|
|
297
305
|
isDirectory(join(pluginDir, 'scripts')),
|
|
@@ -301,10 +309,12 @@ export class PluginManager {
|
|
|
301
309
|
...(featureChecks[0] ? ['commands'] : []),
|
|
302
310
|
...(featureChecks[1] ? ['hooks'] : []),
|
|
303
311
|
...(featureChecks[2] ? ['agents'] : []),
|
|
304
|
-
...(featureChecks[3] ? ['
|
|
305
|
-
...(featureChecks[4] ? ['
|
|
306
|
-
...(featureChecks[5] ? ['
|
|
307
|
-
...(featureChecks[6] ? ['
|
|
312
|
+
...(featureChecks[3] ? ['skills'] : []),
|
|
313
|
+
...(featureChecks[4] ? ['mcp servers'] : []),
|
|
314
|
+
...(featureChecks[5] ? ['prompts'] : []),
|
|
315
|
+
...(featureChecks[6] ? ['schemas'] : []),
|
|
316
|
+
...(featureChecks[7] ? ['scripts'] : []),
|
|
317
|
+
...(featureChecks[8] ? ['templates'] : []),
|
|
308
318
|
];
|
|
309
319
|
}
|
|
310
320
|
async getClaudeNativeInstallTarget(plugin, pluginDir) {
|
|
@@ -329,12 +339,13 @@ export class PluginManager {
|
|
|
329
339
|
const baseNamespace = plugin.nativeClaudeBundle?.bundleName
|
|
330
340
|
|| plugin.source.marketplace
|
|
331
341
|
|| (plugin.source.owner && plugin.source.repo ? `${plugin.source.owner}-${plugin.source.repo}` : plugin.name);
|
|
332
|
-
const namespace =
|
|
342
|
+
const namespace = this.slugifyPluginNamespace(baseNamespace);
|
|
333
343
|
const versionDir = this.slugifyPluginNamespace(plugin.version || '0.0.0');
|
|
334
344
|
return {
|
|
335
345
|
namespace,
|
|
336
346
|
pluginKey: `${plugin.name}@${namespace}`,
|
|
337
347
|
installPath: join(homedir(), '.claude', 'plugins', 'cache', namespace, plugin.name, versionDir),
|
|
348
|
+
marketplacePath: getClaudeMarketplaceInstallPath(namespace),
|
|
338
349
|
features,
|
|
339
350
|
};
|
|
340
351
|
}
|
|
@@ -358,6 +369,25 @@ export class PluginManager {
|
|
|
358
369
|
async saveClaudeInstalledPlugins(state) {
|
|
359
370
|
await writeFile(getClaudeInstalledPluginsPath(), JSON.stringify(state, null, 2));
|
|
360
371
|
}
|
|
372
|
+
async readClaudeKnownMarketplaces() {
|
|
373
|
+
const content = await readFileIfExists(getClaudeKnownMarketplacesPath());
|
|
374
|
+
if (!content) {
|
|
375
|
+
return {};
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
const parsed = JSON.parse(content);
|
|
379
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
380
|
+
return {};
|
|
381
|
+
}
|
|
382
|
+
return parsed;
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return {};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async saveClaudeKnownMarketplaces(state) {
|
|
389
|
+
await writeFile(getClaudeKnownMarketplacesPath(), JSON.stringify(state, null, 2));
|
|
390
|
+
}
|
|
361
391
|
async readClaudeSettings() {
|
|
362
392
|
const content = await readFileIfExists(getClaudeSettingsPath());
|
|
363
393
|
if (!content) {
|
|
@@ -380,6 +410,154 @@ export class PluginManager {
|
|
|
380
410
|
async saveClaudeSettings(state) {
|
|
381
411
|
await writeFile(getClaudeSettingsPath(), JSON.stringify(state, null, 2));
|
|
382
412
|
}
|
|
413
|
+
async findClaudeMarketplaceRoot(pluginDir) {
|
|
414
|
+
let currentDir = resolve(pluginDir);
|
|
415
|
+
while (true) {
|
|
416
|
+
if (await fileExists(join(currentDir, '.claude-plugin', 'marketplace.json'))) {
|
|
417
|
+
return currentDir;
|
|
418
|
+
}
|
|
419
|
+
const parentDir = dirname(currentDir);
|
|
420
|
+
if (parentDir === currentDir) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
currentDir = parentDir;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async readClaudeMarketplaceManifest(marketplaceDir) {
|
|
427
|
+
const manifestContent = await readFileIfExists(join(marketplaceDir, '.claude-plugin', 'marketplace.json'));
|
|
428
|
+
if (!manifestContent) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
const parsed = JSON.parse(manifestContent);
|
|
433
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
const plugins = Array.isArray(parsed.plugins)
|
|
437
|
+
? parsed.plugins.filter((entry) => !!entry && typeof entry === 'object' && !Array.isArray(entry))
|
|
438
|
+
: [];
|
|
439
|
+
return {
|
|
440
|
+
...parsed,
|
|
441
|
+
plugins,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async saveClaudeMarketplaceManifest(marketplaceDir, manifest) {
|
|
449
|
+
await fs.mkdir(join(marketplaceDir, '.claude-plugin'), { recursive: true });
|
|
450
|
+
await writeFile(join(marketplaceDir, '.claude-plugin', 'marketplace.json'), JSON.stringify(manifest, null, 2));
|
|
451
|
+
}
|
|
452
|
+
resolveMarketplaceSourcePath(baseDir, relativePath) {
|
|
453
|
+
const resolvedPath = resolve(baseDir, relativePath);
|
|
454
|
+
const relativePathFromBase = relative(resolve(baseDir), resolvedPath);
|
|
455
|
+
if (relativePathFromBase.startsWith('..')
|
|
456
|
+
|| relativePathFromBase.includes('/../')
|
|
457
|
+
|| relativePathFromBase.includes('\\..\\')) {
|
|
458
|
+
throw new Error(`Invalid marketplace source path "${relativePath}" in ${baseDir}`);
|
|
459
|
+
}
|
|
460
|
+
return resolvedPath;
|
|
461
|
+
}
|
|
462
|
+
async readClaudePluginMetadata(pluginDir) {
|
|
463
|
+
const manifestContent = await readFileIfExists(join(pluginDir, '.claude-plugin', 'plugin.json'));
|
|
464
|
+
if (!manifestContent) {
|
|
465
|
+
return {};
|
|
466
|
+
}
|
|
467
|
+
try {
|
|
468
|
+
const manifest = JSON.parse(manifestContent);
|
|
469
|
+
return {
|
|
470
|
+
...(typeof manifest.description === 'string' ? { description: manifest.description } : {}),
|
|
471
|
+
...(typeof manifest.version === 'string' ? { version: manifest.version } : {}),
|
|
472
|
+
...(manifest.author ? { author: manifest.author } : {}),
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
catch {
|
|
476
|
+
return {};
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
async copyClaudeMarketplacePlugin(sourcePluginDir, marketplacePath, pluginName) {
|
|
480
|
+
const marketplacePluginPath = join(marketplacePath, 'plugins', pluginName);
|
|
481
|
+
await fs.mkdir(dirname(marketplacePluginPath), { recursive: true });
|
|
482
|
+
await fs.rm(marketplacePluginPath, { recursive: true, force: true }).catch(() => { });
|
|
483
|
+
await fs.cp(sourcePluginDir, marketplacePluginPath, { recursive: true, dereference: true });
|
|
484
|
+
return marketplacePluginPath;
|
|
485
|
+
}
|
|
486
|
+
getClaudeMarketplaceSource(plugin, marketplaceRoot, marketplacePath) {
|
|
487
|
+
if (plugin.source.type === 'github') {
|
|
488
|
+
if (plugin.source.owner && plugin.source.repo) {
|
|
489
|
+
return {
|
|
490
|
+
source: 'github',
|
|
491
|
+
repo: `${plugin.source.owner}/${plugin.source.repo}`,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
if (plugin.source.url) {
|
|
495
|
+
return {
|
|
496
|
+
source: 'git',
|
|
497
|
+
url: plugin.source.url,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (plugin.source.type === 'local') {
|
|
502
|
+
return {
|
|
503
|
+
source: 'directory',
|
|
504
|
+
path: resolve(marketplaceRoot || plugin.source.path || marketplacePath),
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
source: 'directory',
|
|
509
|
+
path: marketplacePath,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
async materializeClaudeMarketplace(plugin, pluginDir, target) {
|
|
513
|
+
const marketplaceRoot = await this.findClaudeMarketplaceRoot(pluginDir);
|
|
514
|
+
const marketplaceSource = this.getClaudeMarketplaceSource(plugin, marketplaceRoot, target.marketplacePath);
|
|
515
|
+
await fs.mkdir(target.marketplacePath, { recursive: true });
|
|
516
|
+
const existingManifest = await this.readClaudeMarketplaceManifest(target.marketplacePath);
|
|
517
|
+
const sourceManifest = marketplaceRoot
|
|
518
|
+
? await this.readClaudeMarketplaceManifest(marketplaceRoot)
|
|
519
|
+
: null;
|
|
520
|
+
const mergedManifest = {
|
|
521
|
+
...(sourceManifest || {}),
|
|
522
|
+
...(existingManifest || {}),
|
|
523
|
+
name: target.namespace,
|
|
524
|
+
};
|
|
525
|
+
const mergedEntries = new Map();
|
|
526
|
+
for (const entry of existingManifest?.plugins || []) {
|
|
527
|
+
if (typeof entry.name === 'string' && entry.name) {
|
|
528
|
+
mergedEntries.set(entry.name, entry);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (marketplaceRoot && sourceManifest) {
|
|
532
|
+
for (const entry of sourceManifest.plugins || []) {
|
|
533
|
+
if (typeof entry.name !== 'string' || !entry.name || typeof entry.source !== 'string' || !entry.source) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const sourcePluginDir = this.resolveMarketplaceSourcePath(marketplaceRoot, entry.source);
|
|
537
|
+
await this.copyClaudeMarketplacePlugin(sourcePluginDir, target.marketplacePath, entry.name);
|
|
538
|
+
mergedEntries.set(entry.name, {
|
|
539
|
+
...entry,
|
|
540
|
+
source: `./plugins/${entry.name}`,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
await this.copyClaudeMarketplacePlugin(pluginDir, target.marketplacePath, plugin.name);
|
|
546
|
+
const pluginMetadata = await this.readClaudePluginMetadata(pluginDir);
|
|
547
|
+
mergedEntries.set(plugin.name, {
|
|
548
|
+
...(mergedEntries.get(plugin.name) || {}),
|
|
549
|
+
name: plugin.name,
|
|
550
|
+
source: `./plugins/${plugin.name}`,
|
|
551
|
+
...(plugin.description ? { description: plugin.description } : {}),
|
|
552
|
+
...(plugin.version ? { version: plugin.version } : {}),
|
|
553
|
+
...pluginMetadata,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
mergedManifest.plugins = [...mergedEntries.values()]
|
|
557
|
+
.sort((left, right) => (left.name || '').localeCompare(right.name || ''));
|
|
558
|
+
await this.saveClaudeMarketplaceManifest(target.marketplacePath, mergedManifest);
|
|
559
|
+
return { source: marketplaceSource };
|
|
560
|
+
}
|
|
383
561
|
async installNativeClaudePlugin(plugin, pluginDir, agents) {
|
|
384
562
|
const installed = [];
|
|
385
563
|
const skipped = [];
|
|
@@ -400,7 +578,10 @@ export class PluginManager {
|
|
|
400
578
|
}
|
|
401
579
|
warnings.push(`Claude Code-native plugin components detected (${featureLabel}); they will only work in Claude Code and install into ~/.claude/plugins.`);
|
|
402
580
|
const claudeInstalled = await this.readClaudeInstalledPlugins();
|
|
403
|
-
const
|
|
581
|
+
const legacyKeys = Object.keys(claudeInstalled.plugins).filter(key => key !== nativeTarget.pluginKey && key.startsWith(`${plugin.name}@agentinit-`));
|
|
582
|
+
const conflictingKey = Object.keys(claudeInstalled.plugins).find(key => key !== nativeTarget.pluginKey
|
|
583
|
+
&& !legacyKeys.includes(key)
|
|
584
|
+
&& key.startsWith(`${plugin.name}@`));
|
|
404
585
|
if (conflictingKey) {
|
|
405
586
|
skipped.push({
|
|
406
587
|
agent: 'claude',
|
|
@@ -412,6 +593,7 @@ export class PluginManager {
|
|
|
412
593
|
await fs.rm(nativeTarget.installPath, { recursive: true, force: true }).catch(() => { });
|
|
413
594
|
await fs.mkdir(dirname(nativeTarget.installPath), { recursive: true });
|
|
414
595
|
await fs.cp(pluginDir, nativeTarget.installPath, { recursive: true, dereference: true });
|
|
596
|
+
const marketplace = await this.materializeClaudeMarketplace(plugin, pluginDir, nativeTarget);
|
|
415
597
|
const now = new Date().toISOString();
|
|
416
598
|
claudeInstalled.plugins[nativeTarget.pluginKey] = [{
|
|
417
599
|
scope: 'user',
|
|
@@ -420,13 +602,41 @@ export class PluginManager {
|
|
|
420
602
|
installedAt: now,
|
|
421
603
|
lastUpdated: now,
|
|
422
604
|
}];
|
|
605
|
+
const legacyEntries = legacyKeys.flatMap(key => claudeInstalled.plugins[key] || []);
|
|
606
|
+
for (const legacyKey of legacyKeys) {
|
|
607
|
+
delete claudeInstalled.plugins[legacyKey];
|
|
608
|
+
}
|
|
423
609
|
await this.saveClaudeInstalledPlugins(claudeInstalled);
|
|
424
610
|
const claudeSettings = await this.readClaudeSettings();
|
|
425
611
|
claudeSettings.enabledPlugins = {
|
|
426
612
|
...(claudeSettings.enabledPlugins || {}),
|
|
427
613
|
[nativeTarget.pluginKey]: true,
|
|
428
614
|
};
|
|
615
|
+
claudeSettings.extraKnownMarketplaces = {
|
|
616
|
+
...(claudeSettings.extraKnownMarketplaces || {}),
|
|
617
|
+
[nativeTarget.namespace]: {
|
|
618
|
+
source: marketplace.source,
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
for (const legacyKey of legacyKeys) {
|
|
622
|
+
if (claudeSettings.enabledPlugins && legacyKey in claudeSettings.enabledPlugins) {
|
|
623
|
+
delete claudeSettings.enabledPlugins[legacyKey];
|
|
624
|
+
}
|
|
625
|
+
}
|
|
429
626
|
await this.saveClaudeSettings(claudeSettings);
|
|
627
|
+
const knownMarketplaces = await this.readClaudeKnownMarketplaces();
|
|
628
|
+
knownMarketplaces[nativeTarget.namespace] = {
|
|
629
|
+
source: marketplace.source,
|
|
630
|
+
installLocation: nativeTarget.marketplacePath,
|
|
631
|
+
lastUpdated: now,
|
|
632
|
+
};
|
|
633
|
+
await this.saveClaudeKnownMarketplaces(knownMarketplaces);
|
|
634
|
+
for (const entry of legacyEntries) {
|
|
635
|
+
await fs.rm(entry.installPath, { recursive: true, force: true }).catch(() => { });
|
|
636
|
+
}
|
|
637
|
+
for (const legacyKey of legacyKeys) {
|
|
638
|
+
warnings.push(`Replaced legacy AgentInit Claude plugin install ${legacyKey} with ${nativeTarget.pluginKey}.`);
|
|
639
|
+
}
|
|
430
640
|
installed.push({
|
|
431
641
|
agent: 'claude',
|
|
432
642
|
pluginKey: nativeTarget.pluginKey,
|
|
@@ -447,6 +657,9 @@ export class PluginManager {
|
|
|
447
657
|
const claudeInstalled = await this.readClaudeInstalledPlugins();
|
|
448
658
|
const entries = claudeInstalled.plugins[component.pluginKey] || [];
|
|
449
659
|
const remainingEntries = entries.filter(entry => entry.installPath !== component.installPath);
|
|
660
|
+
const marketplaceNamespace = component.pluginKey.includes('@')
|
|
661
|
+
? component.pluginKey.split('@').slice(1).join('@')
|
|
662
|
+
: '';
|
|
450
663
|
if (remainingEntries.length > 0) {
|
|
451
664
|
claudeInstalled.plugins[component.pluginKey] = remainingEntries;
|
|
452
665
|
}
|
|
@@ -458,8 +671,34 @@ export class PluginManager {
|
|
|
458
671
|
if (claudeSettings.enabledPlugins && component.pluginKey in claudeSettings.enabledPlugins) {
|
|
459
672
|
const { [component.pluginKey]: _removed, ...remainingEnabledPlugins } = claudeSettings.enabledPlugins;
|
|
460
673
|
claudeSettings.enabledPlugins = remainingEnabledPlugins;
|
|
461
|
-
await this.saveClaudeSettings(claudeSettings);
|
|
462
674
|
}
|
|
675
|
+
const namespaceStillInstalled = marketplaceNamespace
|
|
676
|
+
? Object.keys(claudeInstalled.plugins).some(pluginKey => pluginKey.endsWith(`@${marketplaceNamespace}`))
|
|
677
|
+
: false;
|
|
678
|
+
if (!namespaceStillInstalled && marketplaceNamespace) {
|
|
679
|
+
if (claudeSettings.extraKnownMarketplaces && marketplaceNamespace in claudeSettings.extraKnownMarketplaces) {
|
|
680
|
+
delete claudeSettings.extraKnownMarketplaces[marketplaceNamespace];
|
|
681
|
+
}
|
|
682
|
+
const knownMarketplaces = await this.readClaudeKnownMarketplaces();
|
|
683
|
+
if (marketplaceNamespace in knownMarketplaces) {
|
|
684
|
+
delete knownMarketplaces[marketplaceNamespace];
|
|
685
|
+
await this.saveClaudeKnownMarketplaces(knownMarketplaces);
|
|
686
|
+
}
|
|
687
|
+
await fs.rm(getClaudeMarketplaceInstallPath(marketplaceNamespace), { recursive: true, force: true }).catch(() => { });
|
|
688
|
+
}
|
|
689
|
+
else if (marketplaceNamespace) {
|
|
690
|
+
const pluginName = component.pluginKey.split('@')[0] || '';
|
|
691
|
+
const marketplacePath = getClaudeMarketplaceInstallPath(marketplaceNamespace);
|
|
692
|
+
const manifest = await this.readClaudeMarketplaceManifest(marketplacePath);
|
|
693
|
+
if (pluginName && manifest) {
|
|
694
|
+
manifest.plugins = (manifest.plugins || [])
|
|
695
|
+
.filter(entry => entry.name !== pluginName);
|
|
696
|
+
const marketplacePluginPath = join(marketplacePath, 'plugins', pluginName);
|
|
697
|
+
await fs.rm(marketplacePluginPath, { recursive: true, force: true }).catch(() => { });
|
|
698
|
+
await this.saveClaudeMarketplaceManifest(marketplacePath, manifest);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
await this.saveClaudeSettings(claudeSettings);
|
|
463
702
|
await fs.rm(component.installPath, { recursive: true, force: true }).catch(() => { });
|
|
464
703
|
return true;
|
|
465
704
|
}
|
|
@@ -1000,10 +1239,17 @@ ${body.trim()}
|
|
|
1000
1239
|
warnings: plugin.warnings,
|
|
1001
1240
|
};
|
|
1002
1241
|
}
|
|
1242
|
+
const nativeClaudeTarget = await this.getClaudeNativeInstallTarget(plugin, plugin.resolvedPluginDir);
|
|
1243
|
+
const portableSkillAgents = nativeClaudeTarget
|
|
1244
|
+
? this.getPortableSkillAgents(agents, projectPath, options.global)
|
|
1245
|
+
: agents;
|
|
1246
|
+
const portableMcpAgents = nativeClaudeTarget
|
|
1247
|
+
? agents.filter(agent => agent.id !== 'claude')
|
|
1248
|
+
: agents;
|
|
1003
1249
|
// 5. Install skills (deduplicated by shared directory)
|
|
1004
|
-
const skillResult = await this.installPluginSkills(plugin, projectPath,
|
|
1250
|
+
const skillResult = await this.installPluginSkills(plugin, projectPath, portableSkillAgents, options);
|
|
1005
1251
|
// 6. Apply MCP servers per agent
|
|
1006
|
-
const mcpResult = await this.applyPluginMcpServers(plugin, projectPath,
|
|
1252
|
+
const mcpResult = await this.applyPluginMcpServers(plugin, projectPath, portableMcpAgents, options.global);
|
|
1007
1253
|
// 7. Install agent-native plugin payloads when supported.
|
|
1008
1254
|
const nativePluginResult = await this.installNativeClaudePlugin(plugin, plugin.resolvedPluginDir, agents);
|
|
1009
1255
|
const installWarnings = [...plugin.warnings, ...nativePluginResult.warnings];
|
|
@@ -1077,6 +1323,25 @@ ${body.trim()}
|
|
|
1077
1323
|
}
|
|
1078
1324
|
return { installed, skipped };
|
|
1079
1325
|
}
|
|
1326
|
+
getPortableSkillAgents(agents, projectPath, global) {
|
|
1327
|
+
const claudeAgent = agents.find(agent => agent.id === 'claude');
|
|
1328
|
+
if (!claudeAgent || !claudeAgent.supportsSkills()) {
|
|
1329
|
+
return agents;
|
|
1330
|
+
}
|
|
1331
|
+
const claudeSkillsDir = claudeAgent.getSkillsDir(projectPath, global);
|
|
1332
|
+
if (!claudeSkillsDir) {
|
|
1333
|
+
return agents.filter(agent => agent.id !== 'claude');
|
|
1334
|
+
}
|
|
1335
|
+
return agents.filter(agent => {
|
|
1336
|
+
if (agent.id === 'claude') {
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
if (!agent.supportsSkills()) {
|
|
1340
|
+
return true;
|
|
1341
|
+
}
|
|
1342
|
+
return agent.getSkillsDir(projectPath, global) !== claudeSkillsDir;
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1080
1345
|
/**
|
|
1081
1346
|
* Apply MCP servers from a plugin to each target agent
|
|
1082
1347
|
*/
|