bmad-method 6.2.3-next.24 → 6.2.3-next.26

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.
@@ -375,8 +375,6 @@ class ManifestGenerator {
375
375
  // Read existing manifest to preserve install date
376
376
  let existingInstallDate = null;
377
377
  const existingModulesMap = new Map();
378
- let existingCustomModules = [];
379
-
380
378
  if (await fs.pathExists(manifestPath)) {
381
379
  try {
382
380
  const existingContent = await fs.readFile(manifestPath, 'utf8');
@@ -397,12 +395,6 @@ class ManifestGenerator {
397
395
  }
398
396
  }
399
397
  }
400
-
401
- if (existingManifest.customModules && Array.isArray(existingManifest.customModules)) {
402
- // We filter here so manifest regeneration preserves source metadata only for custom modules that
403
- // are still installed. Without that, customModules can retain stale entries for modules that were removed.
404
- existingCustomModules = existingManifest.customModules.filter((customModule) => installedModuleSet.has(customModule?.id));
405
- }
406
398
  } catch {
407
399
  // If we can't read existing manifest, continue with defaults
408
400
  }
@@ -438,7 +430,6 @@ class ManifestGenerator {
438
430
  lastUpdated: new Date().toISOString(),
439
431
  },
440
432
  modules: updatedModules,
441
- customModules: existingCustomModules,
442
433
  ides: this.selectedIdes,
443
434
  };
444
435
 
@@ -97,7 +97,6 @@ class Manifest {
97
97
  lastUpdated: manifestData.installation?.lastUpdated,
98
98
  modules: moduleNames, // Simple array of module names for backward compatibility
99
99
  modulesDetailed: hasDetailedModules ? modules : null, // New detailed format
100
- customModules: manifestData.customModules || [], // Keep for backward compatibility
101
100
  ides: manifestData.ides || [],
102
101
  };
103
102
  } catch (error) {
@@ -254,7 +253,6 @@ class Manifest {
254
253
  lastUpdated: manifest.installation?.lastUpdated,
255
254
  modules: moduleNames,
256
255
  modulesDetailed: hasDetailedModules ? modules : null,
257
- customModules: manifest.customModules || [],
258
256
  ides: manifest.ides || [],
259
257
  };
260
258
  }
@@ -783,52 +781,6 @@ class Manifest {
783
781
 
784
782
  return configs;
785
783
  }
786
- /**
787
- * Add a custom module to the manifest with its source path
788
- * @param {string} bmadDir - Path to bmad directory
789
- * @param {Object} customModule - Custom module info
790
- */
791
- async addCustomModule(bmadDir, customModule) {
792
- const manifest = await this.read(bmadDir);
793
- if (!manifest) {
794
- throw new Error('No manifest found');
795
- }
796
-
797
- if (!manifest.customModules) {
798
- manifest.customModules = [];
799
- }
800
-
801
- // Check if custom module already exists
802
- const existingIndex = manifest.customModules.findIndex((m) => m.id === customModule.id);
803
- if (existingIndex === -1) {
804
- // Add new entry
805
- manifest.customModules.push(customModule);
806
- } else {
807
- // Update existing entry
808
- manifest.customModules[existingIndex] = customModule;
809
- }
810
-
811
- await this.update(bmadDir, { customModules: manifest.customModules });
812
- }
813
-
814
- /**
815
- * Remove a custom module from the manifest
816
- * @param {string} bmadDir - Path to bmad directory
817
- * @param {string} moduleId - Module ID to remove
818
- */
819
- async removeCustomModule(bmadDir, moduleId) {
820
- const manifest = await this.read(bmadDir);
821
- if (!manifest || !manifest.customModules) {
822
- return;
823
- }
824
-
825
- const index = manifest.customModules.findIndex((m) => m.id === moduleId);
826
- if (index !== -1) {
827
- manifest.customModules.splice(index, 1);
828
- await this.update(bmadDir, { customModules: manifest.customModules });
829
- }
830
- }
831
-
832
784
  /**
833
785
  * Get module version info from source
834
786
  * @param {string} moduleName - Module name/code
@@ -866,29 +818,8 @@ class Manifest {
866
818
  };
867
819
  }
868
820
 
869
- // Custom module: resolve path from source or cache before reading version
870
- const customSourcePath = moduleSourcePath || path.join(bmadDir, '_config', 'custom', moduleName);
871
- const version = await this._readMarketplaceVersion(moduleName, customSourcePath);
872
-
873
- const cacheDir = path.join(bmadDir, '_config', 'custom', moduleName);
874
- const moduleYamlPath = path.join(cacheDir, 'module.yaml');
875
-
876
- if (await fs.pathExists(moduleYamlPath)) {
877
- try {
878
- const yamlContent = await fs.readFile(moduleYamlPath, 'utf8');
879
- const moduleConfig = yaml.parse(yamlContent);
880
- return {
881
- version: version || moduleConfig.version || null,
882
- source: 'custom',
883
- npmPackage: moduleConfig.npmPackage || null,
884
- repoUrl: moduleConfig.repoUrl || null,
885
- };
886
- } catch (error) {
887
- await prompts.log.warn(`Failed to read module.yaml for ${moduleName}: ${error.message}`);
888
- }
889
- }
890
-
891
821
  // Unknown module
822
+ const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath);
892
823
  return {
893
824
  version,
894
825
  source: 'unknown',
@@ -98,11 +98,10 @@ class OfficialModules {
98
98
  /**
99
99
  * List all available built-in modules (core and bmm).
100
100
  * All other modules come from external-official-modules.yaml
101
- * @returns {Object} Object with modules array and customModules array
101
+ * @returns {Object} Object with modules array
102
102
  */
103
103
  async listAvailable() {
104
104
  const modules = [];
105
- const customModules = [];
106
105
 
107
106
  // Add built-in core module (directly under src/core-skills)
108
107
  const corePath = getSourcePath('core-skills');
@@ -122,7 +121,7 @@ class OfficialModules {
122
121
  }
123
122
  }
124
123
 
125
- return { modules, customModules };
124
+ return { modules };
126
125
  }
127
126
 
128
127
  /**
@@ -133,25 +132,12 @@ class OfficialModules {
133
132
  * @returns {Object|null} Module info or null if not a valid module
134
133
  */
135
134
  async getModuleInfo(modulePath, defaultName, sourceDescription) {
136
- // Check for module structure (module.yaml OR custom.yaml)
137
135
  const moduleConfigPath = path.join(modulePath, 'module.yaml');
138
- const rootCustomConfigPath = path.join(modulePath, 'custom.yaml');
139
- let configPath = null;
140
136
 
141
- if (await fs.pathExists(moduleConfigPath)) {
142
- configPath = moduleConfigPath;
143
- } else if (await fs.pathExists(rootCustomConfigPath)) {
144
- configPath = rootCustomConfigPath;
145
- }
146
-
147
- // Skip if this doesn't look like a module
148
- if (!configPath) {
137
+ if (!(await fs.pathExists(moduleConfigPath))) {
149
138
  return null;
150
139
  }
151
140
 
152
- // Mark as custom if it's using custom.yaml OR if it's outside src/bmm or src/core
153
- const isCustomSource =
154
- sourceDescription !== 'src/bmm-skills' && sourceDescription !== 'src/core-skills' && sourceDescription !== 'src/modules';
155
141
  const moduleInfo = {
156
142
  id: defaultName,
157
143
  path: modulePath,
@@ -162,12 +148,11 @@ class OfficialModules {
162
148
  description: 'BMAD Module',
163
149
  version: '5.0.0',
164
150
  source: sourceDescription,
165
- isCustom: configPath === rootCustomConfigPath || isCustomSource,
166
151
  };
167
152
 
168
153
  // Read module config for metadata
169
154
  try {
170
- const configContent = await fs.readFile(configPath, 'utf8');
155
+ const configContent = await fs.readFile(moduleConfigPath, 'utf8');
171
156
  const config = yaml.parse(configContent);
172
157
 
173
158
  // Use the code property as the id if available
@@ -824,20 +809,15 @@ class OfficialModules {
824
809
  const results = [];
825
810
 
826
811
  for (const moduleName of modules) {
827
- // Resolve module.yaml path - custom paths first, then standard location, then OfficialModules search
812
+ // Resolve module.yaml path - standard location first, then OfficialModules search
828
813
  let moduleConfigPath = null;
829
- const customPath = this.customModulePaths?.get(moduleName);
830
- if (customPath) {
831
- moduleConfigPath = path.join(customPath, 'module.yaml');
814
+ const standardPath = path.join(getModulePath(moduleName), 'module.yaml');
815
+ if (await fs.pathExists(standardPath)) {
816
+ moduleConfigPath = standardPath;
832
817
  } else {
833
- const standardPath = path.join(getModulePath(moduleName), 'module.yaml');
834
- if (await fs.pathExists(standardPath)) {
835
- moduleConfigPath = standardPath;
836
- } else {
837
- const moduleSourcePath = await this.findModuleSource(moduleName, { silent: true });
838
- if (moduleSourcePath) {
839
- moduleConfigPath = path.join(moduleSourcePath, 'module.yaml');
840
- }
818
+ const moduleSourcePath = await this.findModuleSource(moduleName, { silent: true });
819
+ if (moduleSourcePath) {
820
+ moduleConfigPath = path.join(moduleSourcePath, 'module.yaml');
841
821
  }
842
822
  }
843
823
 
@@ -882,12 +862,9 @@ class OfficialModules {
882
862
  * @param {Array} modules - List of modules to configure (including 'core')
883
863
  * @param {string} projectDir - Target project directory
884
864
  * @param {Object} options - Additional options
885
- * @param {Map} options.customModulePaths - Map of module ID to source path for custom modules
886
865
  * @param {boolean} options.skipPrompts - Skip prompts and use defaults (for --yes flag)
887
866
  */
888
867
  async collectAllConfigurations(modules, projectDir, options = {}) {
889
- // Store custom module paths for use in collectModuleConfig
890
- this.customModulePaths = options.customModulePaths || new Map();
891
868
  this.skipPrompts = options.skipPrompts || false;
892
869
  this.modulesToCustomize = undefined;
893
870
  await this.loadExistingConfig(projectDir);
@@ -1042,25 +1019,7 @@ class OfficialModules {
1042
1019
  }
1043
1020
  }
1044
1021
 
1045
- let configPath = null;
1046
- let isCustomModule = false;
1047
-
1048
- if (await fs.pathExists(moduleConfigPath)) {
1049
- configPath = moduleConfigPath;
1050
- } else {
1051
- // Check if this is a custom module with custom.yaml
1052
- const moduleSourcePath = await this.findModuleSource(moduleName, { silent: true });
1053
-
1054
- if (moduleSourcePath) {
1055
- const rootCustomConfigPath = path.join(moduleSourcePath, 'custom.yaml');
1056
-
1057
- if (await fs.pathExists(rootCustomConfigPath)) {
1058
- isCustomModule = true;
1059
- // For custom modules, we don't have an install-config schema, so just use existing values
1060
- // The custom.yaml values will be loaded and merged during installation
1061
- }
1062
- }
1063
-
1022
+ if (!(await fs.pathExists(moduleConfigPath))) {
1064
1023
  // No config schema for this module - use existing values
1065
1024
  if (this._existingConfig && this._existingConfig[moduleName]) {
1066
1025
  if (!this.collectedConfig[moduleName]) {
@@ -1071,7 +1030,7 @@ class OfficialModules {
1071
1030
  return false;
1072
1031
  }
1073
1032
 
1074
- const configContent = await fs.readFile(configPath, 'utf8');
1033
+ const configContent = await fs.readFile(moduleConfigPath, 'utf8');
1075
1034
  const moduleConfig = yaml.parse(configContent);
1076
1035
 
1077
1036
  if (!moduleConfig) {
@@ -1332,16 +1291,7 @@ class OfficialModules {
1332
1291
  this.allAnswers = {};
1333
1292
  }
1334
1293
  // Load module's config
1335
- // First, check if we have a custom module path for this module
1336
- let moduleConfigPath = null;
1337
-
1338
- if (this.customModulePaths && this.customModulePaths.has(moduleName)) {
1339
- const customPath = this.customModulePaths.get(moduleName);
1340
- moduleConfigPath = path.join(customPath, 'module.yaml');
1341
- } else {
1342
- // Try the standard src/modules location
1343
- moduleConfigPath = path.join(getModulePath(moduleName), 'module.yaml');
1344
- }
1294
+ let moduleConfigPath = path.join(getModulePath(moduleName), 'module.yaml');
1345
1295
 
1346
1296
  // If not found in src/modules or custom paths, search the project
1347
1297
  if (!(await fs.pathExists(moduleConfigPath))) {