claude-autopm 2.11.0 → 2.12.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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-autopm",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "Autonomous Project Management Framework for Claude Code - Advanced AI-powered development automation",
5
5
  "main": "bin/autopm.js",
6
6
  "workspaces": [