claude-autopm 2.11.0 ā 2.11.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/bin/commands/plugin.js +126 -1
- package/lib/plugins/PluginManager.js +131 -0
- package/package.json +1 -1
package/bin/commands/plugin.js
CHANGED
|
@@ -24,7 +24,7 @@ module.exports = {
|
|
|
24
24
|
.positional('action', {
|
|
25
25
|
describe: 'Plugin action to perform',
|
|
26
26
|
type: 'string',
|
|
27
|
-
choices: ['list', 'search', 'install', 'uninstall', 'info', 'enable', 'disable']
|
|
27
|
+
choices: ['list', 'search', 'install', 'uninstall', 'update', 'info', 'enable', 'disable']
|
|
28
28
|
})
|
|
29
29
|
.positional('name', {
|
|
30
30
|
describe: 'Plugin name (without @claudeautopm/plugin- prefix)',
|
|
@@ -40,6 +40,8 @@ module.exports = {
|
|
|
40
40
|
.example('autopm plugin search cloud', 'Search for cloud-related plugins')
|
|
41
41
|
.example('autopm plugin install cloud', 'Install cloud plugin')
|
|
42
42
|
.example('autopm plugin uninstall cloud', 'Remove cloud plugin')
|
|
43
|
+
.example('autopm plugin update', 'Update all installed plugins')
|
|
44
|
+
.example('autopm plugin update cloud devops', 'Update specific plugins')
|
|
43
45
|
.example('autopm plugin info cloud', 'Show cloud plugin details')
|
|
44
46
|
.epilogue(`
|
|
45
47
|
š¦ Plugin Management
|
|
@@ -121,6 +123,12 @@ Usage:
|
|
|
121
123
|
}
|
|
122
124
|
await handleDisable(manager, argv.name, argv);
|
|
123
125
|
break;
|
|
126
|
+
case 'update':
|
|
127
|
+
// argv.name is optional - if not provided, update all
|
|
128
|
+
// argv._ contains additional arguments after the command
|
|
129
|
+
const pluginsToUpdate = argv.name ? [argv.name, ...(argv._.slice(3) || [])] : null;
|
|
130
|
+
await handleUpdate(manager, pluginsToUpdate, argv);
|
|
131
|
+
break;
|
|
124
132
|
default:
|
|
125
133
|
console.error(chalk.red(`Unknown action: ${argv.action}`));
|
|
126
134
|
process.exit(1);
|
|
@@ -393,3 +401,120 @@ async function handleDisable(manager, pluginName, argv) {
|
|
|
393
401
|
console.log(chalk.gray('Note: Agents remain in .claude/agents/ but plugin is marked as disabled'));
|
|
394
402
|
console.log('');
|
|
395
403
|
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Handle 'update' command
|
|
407
|
+
*/
|
|
408
|
+
async function handleUpdate(manager, pluginNames, argv) {
|
|
409
|
+
console.log(chalk.bold('\nš Updating Plugins\n'));
|
|
410
|
+
|
|
411
|
+
// Get list of installed plugins
|
|
412
|
+
const installed = manager.getInstalledPlugins();
|
|
413
|
+
|
|
414
|
+
if (installed.length === 0) {
|
|
415
|
+
console.log(chalk.yellow('No plugins installed to update.'));
|
|
416
|
+
console.log('');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Determine which plugins to update
|
|
421
|
+
let toUpdate = [];
|
|
422
|
+
if (pluginNames && pluginNames.length > 0) {
|
|
423
|
+
// Update specific plugins
|
|
424
|
+
for (const name of pluginNames) {
|
|
425
|
+
const fullName = name.startsWith('plugin-') ? name : `plugin-${name}`;
|
|
426
|
+
if (!installed.includes(fullName)) {
|
|
427
|
+
console.log(chalk.yellow(`ā Plugin ${name} is not installed, skipping`));
|
|
428
|
+
} else {
|
|
429
|
+
toUpdate.push(fullName);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
} else {
|
|
433
|
+
// Update all installed plugins
|
|
434
|
+
toUpdate = installed;
|
|
435
|
+
console.log(chalk.gray(`Updating all ${installed.length} installed plugin(s)...\n`));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (toUpdate.length === 0) {
|
|
439
|
+
console.log(chalk.yellow('No plugins to update.'));
|
|
440
|
+
console.log('');
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const results = {
|
|
445
|
+
updated: [],
|
|
446
|
+
failed: [],
|
|
447
|
+
skipped: [],
|
|
448
|
+
upToDate: []
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// Update each plugin
|
|
452
|
+
for (const pluginName of toUpdate) {
|
|
453
|
+
const shortName = pluginName.replace('plugin-', '');
|
|
454
|
+
|
|
455
|
+
try {
|
|
456
|
+
console.log(chalk.bold(`\nš¦ Updating ${shortName}...`));
|
|
457
|
+
|
|
458
|
+
const result = await manager.updatePlugin(pluginName, {
|
|
459
|
+
verbose: argv.verbose,
|
|
460
|
+
force: argv.force
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
if (result.updated) {
|
|
464
|
+
results.updated.push({
|
|
465
|
+
name: shortName,
|
|
466
|
+
oldVersion: result.oldVersion,
|
|
467
|
+
newVersion: result.newVersion,
|
|
468
|
+
stats: result.stats
|
|
469
|
+
});
|
|
470
|
+
console.log(chalk.green(`ā
Updated ${shortName} (${result.oldVersion} ā ${result.newVersion})`));
|
|
471
|
+
|
|
472
|
+
if (argv.verbose && result.stats) {
|
|
473
|
+
console.log(chalk.gray(` Agents: ${result.stats.agents || 0}, Commands: ${result.stats.commands || 0}, Rules: ${result.stats.rules || 0}`));
|
|
474
|
+
}
|
|
475
|
+
} else if (result.upToDate) {
|
|
476
|
+
results.upToDate.push(shortName);
|
|
477
|
+
console.log(chalk.gray(`ā ${shortName} is already up to date (${result.currentVersion})`));
|
|
478
|
+
} else {
|
|
479
|
+
results.skipped.push(shortName);
|
|
480
|
+
console.log(chalk.yellow(`ā Skipped ${shortName}: ${result.reason || 'Unknown reason'}`));
|
|
481
|
+
}
|
|
482
|
+
} catch (error) {
|
|
483
|
+
results.failed.push({ name: shortName, error: error.message });
|
|
484
|
+
console.log(chalk.red(`ā Failed to update ${shortName}: ${error.message}`));
|
|
485
|
+
|
|
486
|
+
if (argv.verbose) {
|
|
487
|
+
console.error(chalk.red(error.stack));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Summary
|
|
493
|
+
console.log(chalk.bold('\nš Update Summary\n'));
|
|
494
|
+
console.log(`${chalk.green('ā
Updated:')} ${results.updated.length}`);
|
|
495
|
+
console.log(`${chalk.gray('ā Up to date:')} ${results.upToDate.length}`);
|
|
496
|
+
console.log(`${chalk.yellow('ā Skipped:')} ${results.skipped.length}`);
|
|
497
|
+
console.log(`${chalk.red('ā Failed:')} ${results.failed.length}`);
|
|
498
|
+
console.log('');
|
|
499
|
+
|
|
500
|
+
if (results.updated.length > 0) {
|
|
501
|
+
console.log(chalk.bold('Updated Plugins:'));
|
|
502
|
+
for (const plugin of results.updated) {
|
|
503
|
+
console.log(` ⢠${plugin.name} (${plugin.oldVersion} ā ${plugin.newVersion})`);
|
|
504
|
+
}
|
|
505
|
+
console.log('');
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (results.failed.length > 0) {
|
|
509
|
+
console.log(chalk.bold(chalk.red('Failed Updates:')));
|
|
510
|
+
for (const plugin of results.failed) {
|
|
511
|
+
console.log(chalk.red(` ⢠${plugin.name}: ${plugin.error}`));
|
|
512
|
+
}
|
|
513
|
+
console.log('');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Exit with error if any updates failed
|
|
517
|
+
if (results.failed.length > 0) {
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
@@ -908,6 +908,137 @@ class PluginManager extends EventEmitter {
|
|
|
908
908
|
}
|
|
909
909
|
}
|
|
910
910
|
|
|
911
|
+
/**
|
|
912
|
+
* Update an installed plugin to the latest version
|
|
913
|
+
* @param {string} pluginName - Plugin name (with or without scope)
|
|
914
|
+
* @param {Object} options - Update options
|
|
915
|
+
* @param {boolean} options.verbose - Show detailed output
|
|
916
|
+
* @param {boolean} options.force - Force update even if versions match
|
|
917
|
+
* @returns {Promise<Object>} Update result
|
|
918
|
+
*/
|
|
919
|
+
async updatePlugin(pluginName, options = {}) {
|
|
920
|
+
const { verbose = false, force = false } = options;
|
|
921
|
+
const { execSync } = require('child_process');
|
|
922
|
+
|
|
923
|
+
const fullName = pluginName.includes('/') ? pluginName : `${this.options.scopePrefix}/${pluginName}`;
|
|
924
|
+
const shortName = pluginName.replace(`${this.options.scopePrefix}/`, '');
|
|
925
|
+
|
|
926
|
+
this.emit('update:start', { name: fullName });
|
|
927
|
+
|
|
928
|
+
try {
|
|
929
|
+
// Check if plugin is installed
|
|
930
|
+
if (!this.isInstalled(shortName)) {
|
|
931
|
+
throw new Error(`Plugin ${shortName} is not installed. Use 'autopm plugin install ${shortName}' to install it.`);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// Get current installed version from plugin.json
|
|
935
|
+
const plugin = this.plugins.get(fullName);
|
|
936
|
+
if (!plugin || !plugin.loaded) {
|
|
937
|
+
await this.loadPlugin(fullName);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
const currentMetadata = this.plugins.get(fullName)?.metadata;
|
|
941
|
+
const currentVersion = currentMetadata?.version || 'unknown';
|
|
942
|
+
|
|
943
|
+
// Check npm for available version
|
|
944
|
+
let availableVersion;
|
|
945
|
+
try {
|
|
946
|
+
const npmInfo = execSync(`npm view ${fullName} version`, { encoding: 'utf-8' }).trim();
|
|
947
|
+
availableVersion = npmInfo;
|
|
948
|
+
} catch (error) {
|
|
949
|
+
throw new Error(`Failed to check npm for ${fullName}: ${error.message}`);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Compare versions
|
|
953
|
+
if (currentVersion === availableVersion && !force) {
|
|
954
|
+
this.emit('update:skipped', {
|
|
955
|
+
name: fullName,
|
|
956
|
+
reason: 'Already up to date',
|
|
957
|
+
version: currentVersion
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
return {
|
|
961
|
+
upToDate: true,
|
|
962
|
+
currentVersion,
|
|
963
|
+
updated: false
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
if (verbose) {
|
|
968
|
+
console.log(` Current version: ${currentVersion}`);
|
|
969
|
+
console.log(` Available version: ${availableVersion}`);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Uninstall old version
|
|
973
|
+
if (verbose) {
|
|
974
|
+
console.log(` Removing old version...`);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
const wasEnabled = this.isEnabled(shortName);
|
|
978
|
+
await this.uninstallPlugin(fullName);
|
|
979
|
+
|
|
980
|
+
// Update npm package globally
|
|
981
|
+
if (verbose) {
|
|
982
|
+
console.log(` Updating npm package...`);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
try {
|
|
986
|
+
execSync(`npm update -g ${fullName}`, {
|
|
987
|
+
stdio: verbose ? 'inherit' : 'ignore'
|
|
988
|
+
});
|
|
989
|
+
} catch (error) {
|
|
990
|
+
throw new Error(`Failed to update npm package: ${error.message}`);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// Reload plugin metadata from updated package
|
|
994
|
+
await this.discoverPlugins();
|
|
995
|
+
|
|
996
|
+
// Reinstall with new version
|
|
997
|
+
if (verbose) {
|
|
998
|
+
console.log(` Installing new version...`);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const installResult = await this.installPlugin(fullName);
|
|
1002
|
+
|
|
1003
|
+
// Restore enabled state
|
|
1004
|
+
if (wasEnabled) {
|
|
1005
|
+
this.enablePlugin(shortName);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
this.emit('update:complete', {
|
|
1009
|
+
name: fullName,
|
|
1010
|
+
oldVersion: currentVersion,
|
|
1011
|
+
newVersion: availableVersion,
|
|
1012
|
+
stats: {
|
|
1013
|
+
agents: installResult.agentsInstalled,
|
|
1014
|
+
commands: installResult.commandsInstalled,
|
|
1015
|
+
rules: installResult.rulesInstalled,
|
|
1016
|
+
hooks: installResult.hooksInstalled,
|
|
1017
|
+
scripts: installResult.scriptsInstalled
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
return {
|
|
1022
|
+
updated: true,
|
|
1023
|
+
oldVersion: currentVersion,
|
|
1024
|
+
newVersion: availableVersion,
|
|
1025
|
+
stats: {
|
|
1026
|
+
agents: installResult.agentsInstalled,
|
|
1027
|
+
commands: installResult.commandsInstalled,
|
|
1028
|
+
rules: installResult.rulesInstalled,
|
|
1029
|
+
hooks: installResult.hooksInstalled,
|
|
1030
|
+
scripts: installResult.scriptsInstalled
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
} catch (error) {
|
|
1034
|
+
this.emit('update:error', {
|
|
1035
|
+
name: fullName,
|
|
1036
|
+
error: error.message
|
|
1037
|
+
});
|
|
1038
|
+
throw error;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
911
1042
|
/**
|
|
912
1043
|
* Get list of installed plugins (from registry)
|
|
913
1044
|
*/
|
package/package.json
CHANGED