Compare commits
1 Commits
4f48577bd0
...
f370e796de
| Author | SHA1 | Date |
|---|---|---|
|
|
f370e796de |
|
|
@ -302,7 +302,6 @@ class ConfigCollector {
|
||||||
|
|
||||||
const configSpinner = await prompts.spinner();
|
const configSpinner = await prompts.spinner();
|
||||||
configSpinner.start('Configuring modules...');
|
configSpinner.start('Configuring modules...');
|
||||||
try {
|
|
||||||
for (const moduleName of defaultModules) {
|
for (const moduleName of defaultModules) {
|
||||||
const displayName = displayNameMap.get(moduleName) || moduleName.toUpperCase();
|
const displayName = displayNameMap.get(moduleName) || moduleName.toUpperCase();
|
||||||
configSpinner.message(`Configuring ${displayName}...`);
|
configSpinner.message(`Configuring ${displayName}...`);
|
||||||
|
|
@ -313,19 +312,13 @@ class ConfigCollector {
|
||||||
this._silentConfig = false;
|
this._silentConfig = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
configSpinner.stop('Module configuration complete');
|
||||||
configSpinner.stop(customizeModules.length > 0 ? 'Module defaults applied' : 'Module configuration complete');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run customized modules individually (may show interactive prompts)
|
// Run customized modules individually (may show interactive prompts)
|
||||||
for (const moduleName of customizeModules) {
|
for (const moduleName of customizeModules) {
|
||||||
await this.collectModuleConfig(moduleName, projectDir);
|
await this.collectModuleConfig(moduleName, projectDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customizeModules.length > 0) {
|
|
||||||
await prompts.log.step('Module configuration complete');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add metadata
|
// Add metadata
|
||||||
|
|
@ -1246,6 +1239,7 @@ class ConfigCollector {
|
||||||
hasOutput = true;
|
hasOutput = true;
|
||||||
|
|
||||||
const message = valueMessages[selectedValue];
|
const message = valueMessages[selectedValue];
|
||||||
|
await prompts.log.message('');
|
||||||
for (const line of message.trim().split('\n')) {
|
for (const line of message.trim().split('\n')) {
|
||||||
const trimmedLine = line.trim();
|
const trimmedLine = line.trim();
|
||||||
if (trimmedLine.endsWith(':') && !trimmedLine.startsWith(' ')) {
|
if (trimmedLine.endsWith(':') && !trimmedLine.startsWith(' ')) {
|
||||||
|
|
|
||||||
|
|
@ -527,13 +527,8 @@ class Installer {
|
||||||
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
||||||
|
|
||||||
for (const cachedModule of cachedModules) {
|
for (const cachedModule of cachedModules) {
|
||||||
|
if (cachedModule.isDirectory()) {
|
||||||
const moduleId = cachedModule.name;
|
const moduleId = cachedModule.name;
|
||||||
const cachedPath = path.join(cacheDir, moduleId);
|
|
||||||
|
|
||||||
// Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT
|
|
||||||
if (!(await fs.pathExists(cachedPath)) || !cachedModule.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if we already have this module from manifest
|
// Skip if we already have this module from manifest
|
||||||
if (customModulePaths.has(moduleId)) {
|
if (customModulePaths.has(moduleId)) {
|
||||||
|
|
@ -547,12 +542,15 @@ class Installer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cachedPath = path.join(cacheDir, moduleId);
|
||||||
|
|
||||||
// Check if this is actually a custom module (has module.yaml)
|
// Check if this is actually a custom module (has module.yaml)
|
||||||
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
||||||
if (await fs.pathExists(moduleYamlPath)) {
|
if (await fs.pathExists(moduleYamlPath)) {
|
||||||
customModulePaths.set(moduleId, cachedPath);
|
customModulePaths.set(moduleId, cachedPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update module manager with the new custom module paths from cache
|
// Update module manager with the new custom module paths from cache
|
||||||
this.moduleManager.setCustomModulePaths(customModulePaths);
|
this.moduleManager.setCustomModulePaths(customModulePaths);
|
||||||
|
|
@ -611,13 +609,8 @@ class Installer {
|
||||||
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
||||||
|
|
||||||
for (const cachedModule of cachedModules) {
|
for (const cachedModule of cachedModules) {
|
||||||
|
if (cachedModule.isDirectory()) {
|
||||||
const moduleId = cachedModule.name;
|
const moduleId = cachedModule.name;
|
||||||
const cachedPath = path.join(cacheDir, moduleId);
|
|
||||||
|
|
||||||
// Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT
|
|
||||||
if (!(await fs.pathExists(cachedPath)) || !cachedModule.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if we already have this module from manifest
|
// Skip if we already have this module from manifest
|
||||||
if (customModulePaths.has(moduleId)) {
|
if (customModulePaths.has(moduleId)) {
|
||||||
|
|
@ -631,12 +624,15 @@ class Installer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cachedPath = path.join(cacheDir, moduleId);
|
||||||
|
|
||||||
// Check if this is actually a custom module (has module.yaml)
|
// Check if this is actually a custom module (has module.yaml)
|
||||||
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
||||||
if (await fs.pathExists(moduleYamlPath)) {
|
if (await fs.pathExists(moduleYamlPath)) {
|
||||||
customModulePaths.set(moduleId, cachedPath);
|
customModulePaths.set(moduleId, cachedPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update module manager with the new custom module paths from cache
|
// Update module manager with the new custom module paths from cache
|
||||||
this.moduleManager.setCustomModulePaths(customModulePaths);
|
this.moduleManager.setCustomModulePaths(customModulePaths);
|
||||||
|
|
@ -953,11 +949,12 @@ class Installer {
|
||||||
if (!isCustomModule && config._customModuleSources && config._customModuleSources.has(moduleName)) {
|
if (!isCustomModule && config._customModuleSources && config._customModuleSources.has(moduleName)) {
|
||||||
customInfo = config._customModuleSources.get(moduleName);
|
customInfo = config._customModuleSources.get(moduleName);
|
||||||
isCustomModule = true;
|
isCustomModule = true;
|
||||||
if (customInfo.sourcePath && !customInfo.path) {
|
if (
|
||||||
customInfo.path = path.isAbsolute(customInfo.sourcePath)
|
customInfo.sourcePath &&
|
||||||
? customInfo.sourcePath
|
(customInfo.sourcePath.startsWith('_config') || customInfo.sourcePath.includes('_config/custom')) &&
|
||||||
: path.join(bmadDir, customInfo.sourcePath);
|
!customInfo.path
|
||||||
}
|
)
|
||||||
|
customInfo.path = customInfo.sourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally check regular custom content
|
// Finally check regular custom content
|
||||||
|
|
@ -2376,35 +2373,15 @@ class Installer {
|
||||||
const configuredIdes = existingInstall.ides || [];
|
const configuredIdes = existingInstall.ides || [];
|
||||||
const projectRoot = path.dirname(bmadDir);
|
const projectRoot = path.dirname(bmadDir);
|
||||||
|
|
||||||
// Get custom module sources: first from --custom-content (re-cache from source), then from cache
|
// Get custom module sources from cache
|
||||||
const customModuleSources = new Map();
|
const customModuleSources = new Map();
|
||||||
if (config.customContent?.sources?.length > 0) {
|
|
||||||
for (const source of config.customContent.sources) {
|
|
||||||
if (source.id && source.path && (await fs.pathExists(source.path))) {
|
|
||||||
customModuleSources.set(source.id, {
|
|
||||||
id: source.id,
|
|
||||||
name: source.name || source.id,
|
|
||||||
sourcePath: source.path,
|
|
||||||
cached: false, // From CLI, will be re-cached
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
||||||
if (await fs.pathExists(cacheDir)) {
|
if (await fs.pathExists(cacheDir)) {
|
||||||
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
||||||
|
|
||||||
for (const cachedModule of cachedModules) {
|
for (const cachedModule of cachedModules) {
|
||||||
|
if (cachedModule.isDirectory()) {
|
||||||
const moduleId = cachedModule.name;
|
const moduleId = cachedModule.name;
|
||||||
const cachedPath = path.join(cacheDir, moduleId);
|
|
||||||
|
|
||||||
// Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT
|
|
||||||
if (!(await fs.pathExists(cachedPath))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!cachedModule.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if we already have this module from manifest
|
// Skip if we already have this module from manifest
|
||||||
if (customModuleSources.has(moduleId)) {
|
if (customModuleSources.has(moduleId)) {
|
||||||
|
|
@ -2418,6 +2395,8 @@ class Installer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cachedPath = path.join(cacheDir, moduleId);
|
||||||
|
|
||||||
// Check if this is actually a custom module (has module.yaml)
|
// Check if this is actually a custom module (has module.yaml)
|
||||||
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
||||||
if (await fs.pathExists(moduleYamlPath)) {
|
if (await fs.pathExists(moduleYamlPath)) {
|
||||||
|
|
@ -2431,6 +2410,7 @@ class Installer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load saved IDE configurations
|
// Load saved IDE configurations
|
||||||
const savedIdeConfigs = await this.ideConfigManager.loadAllIdeConfigs(bmadDir);
|
const savedIdeConfigs = await this.ideConfigManager.loadAllIdeConfigs(bmadDir);
|
||||||
|
|
@ -2564,7 +2544,6 @@ class Installer {
|
||||||
_savedIdeConfigs: savedIdeConfigs, // Pass saved IDE configs to installer
|
_savedIdeConfigs: savedIdeConfigs, // Pass saved IDE configs to installer
|
||||||
_customModuleSources: customModuleSources, // Pass custom module sources for updates
|
_customModuleSources: customModuleSources, // Pass custom module sources for updates
|
||||||
_existingModules: installedModules, // Pass all installed modules for manifest generation
|
_existingModules: installedModules, // Pass all installed modules for manifest generation
|
||||||
customContent: config.customContent, // Pass through for re-caching from source
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call the standard install method
|
// Call the standard install method
|
||||||
|
|
|
||||||
|
|
@ -734,10 +734,8 @@ class ModuleManager {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip module root config.yaml only - generated by config collector with actual values
|
// Skip config.yaml templates - we'll generate clean ones with actual values
|
||||||
// Workflow-level config.yaml (e.g. workflows/orchestrate-story/config.yaml) must be copied
|
if (file === 'config.yaml' || file.endsWith('/config.yaml')) {
|
||||||
// for custom modules that use workflow-specific configuration
|
|
||||||
if (file === 'config.yaml') {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -245,48 +245,11 @@ class UI {
|
||||||
|
|
||||||
// Handle quick update separately
|
// Handle quick update separately
|
||||||
if (actionType === 'quick-update') {
|
if (actionType === 'quick-update') {
|
||||||
// Pass --custom-content through so installer can re-cache if cache is missing
|
// Quick update doesn't install custom content - just updates existing modules
|
||||||
let customContentForQuickUpdate = { hasCustomContent: false };
|
|
||||||
if (options.customContent) {
|
|
||||||
const paths = options.customContent
|
|
||||||
.split(',')
|
|
||||||
.map((p) => p.trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
if (paths.length > 0) {
|
|
||||||
const customPaths = [];
|
|
||||||
const selectedModuleIds = [];
|
|
||||||
const sources = [];
|
|
||||||
for (const customPath of paths) {
|
|
||||||
const expandedPath = this.expandUserPath(customPath);
|
|
||||||
const validation = this.validateCustomContentPathSync(expandedPath);
|
|
||||||
if (validation) continue;
|
|
||||||
let moduleMeta;
|
|
||||||
try {
|
|
||||||
const moduleYamlPath = path.join(expandedPath, 'module.yaml');
|
|
||||||
moduleMeta = require('yaml').parse(await fs.readFile(moduleYamlPath, 'utf-8'));
|
|
||||||
} catch {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!moduleMeta?.code) continue;
|
|
||||||
customPaths.push(expandedPath);
|
|
||||||
selectedModuleIds.push(moduleMeta.code);
|
|
||||||
sources.push({ path: expandedPath, id: moduleMeta.code, name: moduleMeta.name || moduleMeta.code });
|
|
||||||
}
|
|
||||||
if (customPaths.length > 0) {
|
|
||||||
customContentForQuickUpdate = {
|
|
||||||
hasCustomContent: true,
|
|
||||||
selected: true,
|
|
||||||
sources,
|
|
||||||
selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
|
|
||||||
selectedModuleIds,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
actionType: 'quick-update',
|
actionType: 'quick-update',
|
||||||
directory: confirmedDirectory,
|
directory: confirmedDirectory,
|
||||||
customContent: customContentForQuickUpdate,
|
customContent: { hasCustomContent: false },
|
||||||
skipPrompts: options.yes || false,
|
skipPrompts: options.yes || false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -342,7 +305,6 @@ class UI {
|
||||||
// Build custom content config similar to promptCustomContentSource
|
// Build custom content config similar to promptCustomContentSource
|
||||||
const customPaths = [];
|
const customPaths = [];
|
||||||
const selectedModuleIds = [];
|
const selectedModuleIds = [];
|
||||||
const sources = [];
|
|
||||||
|
|
||||||
for (const customPath of paths) {
|
for (const customPath of paths) {
|
||||||
const expandedPath = this.expandUserPath(customPath);
|
const expandedPath = this.expandUserPath(customPath);
|
||||||
|
|
@ -364,11 +326,6 @@ class UI {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleMeta) {
|
|
||||||
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moduleMeta.code) {
|
if (!moduleMeta.code) {
|
||||||
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
|
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -376,11 +333,6 @@ class UI {
|
||||||
|
|
||||||
customPaths.push(expandedPath);
|
customPaths.push(expandedPath);
|
||||||
selectedModuleIds.push(moduleMeta.code);
|
selectedModuleIds.push(moduleMeta.code);
|
||||||
sources.push({
|
|
||||||
path: expandedPath,
|
|
||||||
id: moduleMeta.code,
|
|
||||||
name: moduleMeta.name || moduleMeta.code,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customPaths.length > 0) {
|
if (customPaths.length > 0) {
|
||||||
|
|
@ -388,9 +340,7 @@ class UI {
|
||||||
selectedCustomModules: selectedModuleIds,
|
selectedCustomModules: selectedModuleIds,
|
||||||
customContentConfig: {
|
customContentConfig: {
|
||||||
hasCustomContent: true,
|
hasCustomContent: true,
|
||||||
selected: true,
|
paths: customPaths,
|
||||||
sources,
|
|
||||||
selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
|
|
||||||
selectedModuleIds: selectedModuleIds,
|
selectedModuleIds: selectedModuleIds,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -496,7 +446,6 @@ class UI {
|
||||||
// Build custom content config similar to promptCustomContentSource
|
// Build custom content config similar to promptCustomContentSource
|
||||||
const customPaths = [];
|
const customPaths = [];
|
||||||
const selectedModuleIds = [];
|
const selectedModuleIds = [];
|
||||||
const sources = [];
|
|
||||||
|
|
||||||
for (const customPath of paths) {
|
for (const customPath of paths) {
|
||||||
const expandedPath = this.expandUserPath(customPath);
|
const expandedPath = this.expandUserPath(customPath);
|
||||||
|
|
@ -518,11 +467,6 @@ class UI {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleMeta) {
|
|
||||||
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moduleMeta.code) {
|
if (!moduleMeta.code) {
|
||||||
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
|
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -530,19 +474,12 @@ class UI {
|
||||||
|
|
||||||
customPaths.push(expandedPath);
|
customPaths.push(expandedPath);
|
||||||
selectedModuleIds.push(moduleMeta.code);
|
selectedModuleIds.push(moduleMeta.code);
|
||||||
sources.push({
|
|
||||||
path: expandedPath,
|
|
||||||
id: moduleMeta.code,
|
|
||||||
name: moduleMeta.name || moduleMeta.code,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customPaths.length > 0) {
|
if (customPaths.length > 0) {
|
||||||
customContentConfig = {
|
customContentConfig = {
|
||||||
hasCustomContent: true,
|
hasCustomContent: true,
|
||||||
selected: true,
|
paths: customPaths,
|
||||||
sources,
|
|
||||||
selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
|
|
||||||
selectedModuleIds: selectedModuleIds,
|
selectedModuleIds: selectedModuleIds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue