Compare commits
6 Commits
5f4d744318
...
74977ece6a
| Author | SHA1 | Date |
|---|---|---|
|
|
74977ece6a | |
|
|
cf50f4935d | |
|
|
ddd0e8fbf2 | |
|
|
9e70b1d41c | |
|
|
9a3a46314e | |
|
|
a4c394fc78 |
|
|
@ -3,6 +3,8 @@
|
||||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||||
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
||||||
<critical>Generate all documents in {document_output_language}</critical>
|
<critical>Generate all documents in {document_output_language}</critical>
|
||||||
|
<critical>ALWAYS reload {{sprint_status}} (docs/sprint-artifacts/sprint-status.yaml by default) from disk immediately before reading or
|
||||||
|
updating statuses. Multiple workflows change this file between runs; never rely on a previously loaded copy or cached memory.</critical>
|
||||||
|
|
||||||
<critical>🔥 YOU ARE AN ADVERSARIAL CODE REVIEWER - Find what's wrong or missing! 🔥</critical>
|
<critical>🔥 YOU ARE AN ADVERSARIAL CODE REVIEWER - Find what's wrong or missing! 🔥</critical>
|
||||||
<critical>Your purpose: Validate story file claims against actual implementation</critical>
|
<critical>Your purpose: Validate story file claims against actual implementation</critical>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
<critical>The workflow execution engine is governed by: {project-root}/{bmad_folder}/core/tasks/workflow.xml</critical>
|
<critical>The workflow execution engine is governed by: {project-root}/{bmad_folder}/core/tasks/workflow.xml</critical>
|
||||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||||
<critical>Communicate all responses in {communication_language} and generate all documents in {document_output_language}</critical>
|
<critical>Communicate all responses in {communication_language} and generate all documents in {document_output_language}</critical>
|
||||||
|
<critical>ALWAYS reload {{sprint_status}} (docs/sprint-artifacts/sprint-status.yaml by default) from disk immediately before reading or
|
||||||
|
updating statuses. Multiple workflows change this file between runs; never rely on a previously loaded copy or cached memory.</critical>
|
||||||
|
|
||||||
<critical>🔥 CRITICAL MISSION: You are creating the ULTIMATE story context engine that prevents LLM developer mistakes, omissions or
|
<critical>🔥 CRITICAL MISSION: You are creating the ULTIMATE story context engine that prevents LLM developer mistakes, omissions or
|
||||||
disasters! 🔥</critical>
|
disasters! 🔥</critical>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||||
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
|
||||||
<critical>Generate all documents in {document_output_language}</critical>
|
<critical>Generate all documents in {document_output_language}</critical>
|
||||||
|
<critical>ALWAYS reload {{sprint_status}} (docs/sprint-artifacts/sprint-status.yaml by default) from disk immediately before reading or
|
||||||
|
updating statuses. Multiple workflows change this file between runs; never rely on a previously loaded copy or cached memory.</critical>
|
||||||
<critical>Only modify the story file in these areas: Tasks/Subtasks checkboxes, Dev Agent Record (Debug Log, Completion Notes), File List,
|
<critical>Only modify the story file in these areas: Tasks/Subtasks checkboxes, Dev Agent Record (Debug Log, Completion Notes), File List,
|
||||||
Change Log, and Status</critical>
|
Change Log, and Status</critical>
|
||||||
<critical>Execute ALL steps in exact order; do NOT skip steps</critical>
|
<critical>Execute ALL steps in exact order; do NOT skip steps</critical>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ PARTY MODE PROTOCOL:
|
||||||
- Create natural back-and-forth with user actively participating
|
- Create natural back-and-forth with user actively participating
|
||||||
- Show disagreements, diverse perspectives, authentic team dynamics
|
- Show disagreements, diverse perspectives, authentic team dynamics
|
||||||
</critical>
|
</critical>
|
||||||
|
<critical>ALWAYS reload {{sprint_status_file}} (docs/sprint-artifacts/sprint-status.yaml by default) from disk immediately before reading or updating statuses. Multiple workflows change this file between runs; never rely on a previously loaded copy or cached memory.</critical>
|
||||||
|
|
||||||
<workflow>
|
<workflow>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,19 @@ class CustomModuleCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate hash of a file or directory
|
* Stream a file into the hash to avoid loading entire file into memory
|
||||||
|
*/
|
||||||
|
async hashFileStream(filePath, hash) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const stream = require('node:fs').createReadStream(filePath);
|
||||||
|
stream.on('data', (chunk) => hash.update(chunk));
|
||||||
|
stream.on('end', resolve);
|
||||||
|
stream.on('error', reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate hash of a file or directory using streaming to minimize memory usage
|
||||||
*/
|
*/
|
||||||
async calculateHash(sourcePath) {
|
async calculateHash(sourcePath) {
|
||||||
const hash = crypto.createHash('sha256');
|
const hash = crypto.createHash('sha256');
|
||||||
|
|
@ -76,14 +88,14 @@ class CustomModuleCache {
|
||||||
files.sort(); // Ensure consistent order
|
files.sort(); // Ensure consistent order
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const content = await fs.readFile(file);
|
|
||||||
const relativePath = path.relative(sourcePath, file);
|
const relativePath = path.relative(sourcePath, file);
|
||||||
hash.update(relativePath + '|' + content.toString('base64'));
|
// Hash the path first, then stream file contents
|
||||||
|
hash.update(relativePath + '|');
|
||||||
|
await this.hashFileStream(file, hash);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For single files
|
// For single files, stream directly into hash
|
||||||
const content = await fs.readFile(sourcePath);
|
await this.hashFileStream(sourcePath, hash);
|
||||||
hash.update(content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash.digest('hex');
|
return hash.digest('hex');
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ const { CLIUtils } = require('../../../lib/cli-utils');
|
||||||
const { ManifestGenerator } = require('./manifest-generator');
|
const { ManifestGenerator } = require('./manifest-generator');
|
||||||
const { IdeConfigManager } = require('./ide-config-manager');
|
const { IdeConfigManager } = require('./ide-config-manager');
|
||||||
const { replaceAgentSidecarFolders } = require('./post-install-sidecar-replacement');
|
const { replaceAgentSidecarFolders } = require('./post-install-sidecar-replacement');
|
||||||
|
const { CustomHandler } = require('../custom/handler');
|
||||||
|
|
||||||
class Installer {
|
class Installer {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -407,7 +408,10 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
* @param {string[]} config.ides - IDEs to configure
|
* @param {string[]} config.ides - IDEs to configure
|
||||||
* @param {boolean} config.skipIde - Skip IDE configuration
|
* @param {boolean} config.skipIde - Skip IDE configuration
|
||||||
*/
|
*/
|
||||||
async install(config) {
|
async install(originalConfig) {
|
||||||
|
// Clone config to avoid mutating the caller's object
|
||||||
|
const config = { ...originalConfig };
|
||||||
|
|
||||||
// Display BMAD logo
|
// Display BMAD logo
|
||||||
CLIUtils.displayLogo();
|
CLIUtils.displayLogo();
|
||||||
|
|
||||||
|
|
@ -440,7 +444,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
|
|
||||||
// Handle selectedFiles (from existing install path or manual directory input)
|
// Handle selectedFiles (from existing install path or manual directory input)
|
||||||
if (config.customContent && config.customContent.selected && config.customContent.selectedFiles) {
|
if (config.customContent && config.customContent.selected && config.customContent.selectedFiles) {
|
||||||
const { CustomHandler } = require('../custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
for (const customFile of config.customContent.selectedFiles) {
|
for (const customFile of config.customContent.selectedFiles) {
|
||||||
const customInfo = await customHandler.getCustomInfo(customFile, path.resolve(config.directory));
|
const customInfo = await customHandler.getCustomInfo(customFile, path.resolve(config.directory));
|
||||||
|
|
@ -837,9 +840,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
// Regular custom content from user input (non-cached)
|
// Regular custom content from user input (non-cached)
|
||||||
if (finalCustomContent && finalCustomContent.selected && finalCustomContent.selectedFiles) {
|
if (finalCustomContent && finalCustomContent.selected && finalCustomContent.selectedFiles) {
|
||||||
// Add custom modules to the installation list
|
// Add custom modules to the installation list
|
||||||
|
const customHandler = new CustomHandler();
|
||||||
for (const customFile of finalCustomContent.selectedFiles) {
|
for (const customFile of finalCustomContent.selectedFiles) {
|
||||||
const { CustomHandler } = require('../custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
|
||||||
const customInfo = await customHandler.getCustomInfo(customFile, projectDir);
|
const customInfo = await customHandler.getCustomInfo(customFile, projectDir);
|
||||||
if (customInfo && customInfo.id) {
|
if (customInfo && customInfo.id) {
|
||||||
allModules.push(customInfo.id);
|
allModules.push(customInfo.id);
|
||||||
|
|
@ -929,7 +931,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
|
|
||||||
// Finally check regular custom content
|
// Finally check regular custom content
|
||||||
if (!isCustomModule && finalCustomContent && finalCustomContent.selected && finalCustomContent.selectedFiles) {
|
if (!isCustomModule && finalCustomContent && finalCustomContent.selected && finalCustomContent.selectedFiles) {
|
||||||
const { CustomHandler } = require('../custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
for (const customFile of finalCustomContent.selectedFiles) {
|
for (const customFile of finalCustomContent.selectedFiles) {
|
||||||
const info = await customHandler.getCustomInfo(customFile, projectDir);
|
const info = await customHandler.getCustomInfo(customFile, projectDir);
|
||||||
|
|
@ -943,7 +944,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
|
|
||||||
if (isCustomModule && customInfo) {
|
if (isCustomModule && customInfo) {
|
||||||
// Install custom module using CustomHandler but as a proper module
|
// Install custom module using CustomHandler but as a proper module
|
||||||
const { CustomHandler } = require('../custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
|
|
||||||
// Install to module directory instead of custom directory
|
// Install to module directory instead of custom directory
|
||||||
|
|
@ -972,19 +972,39 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
if (await fs.pathExists(customDir)) {
|
if (await fs.pathExists(customDir)) {
|
||||||
// Move contents to module directory
|
// Move contents to module directory
|
||||||
const items = await fs.readdir(customDir);
|
const items = await fs.readdir(customDir);
|
||||||
for (const item of items) {
|
const movedItems = [];
|
||||||
const srcPath = path.join(customDir, item);
|
try {
|
||||||
const destPath = path.join(moduleTargetPath, item);
|
for (const item of items) {
|
||||||
|
const srcPath = path.join(customDir, item);
|
||||||
|
const destPath = path.join(moduleTargetPath, item);
|
||||||
|
|
||||||
// If destination exists, remove it first (or we could merge)
|
// If destination exists, remove it first (or we could merge)
|
||||||
if (await fs.pathExists(destPath)) {
|
if (await fs.pathExists(destPath)) {
|
||||||
await fs.remove(destPath);
|
await fs.remove(destPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.move(srcPath, destPath);
|
||||||
|
movedItems.push({ src: srcPath, dest: destPath });
|
||||||
}
|
}
|
||||||
|
} catch (moveError) {
|
||||||
await fs.move(srcPath, destPath);
|
// Rollback: restore any successfully moved items
|
||||||
|
for (const moved of movedItems) {
|
||||||
|
try {
|
||||||
|
await fs.move(moved.dest, moved.src);
|
||||||
|
} catch {
|
||||||
|
// Best-effort rollback - log if it fails
|
||||||
|
console.error(`Failed to rollback ${moved.dest} during cleanup`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Failed to move custom module files: ${moveError.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await fs.remove(tempCustomPath);
|
try {
|
||||||
|
await fs.remove(tempCustomPath);
|
||||||
|
} catch (cleanupError) {
|
||||||
|
// Non-fatal: temp directory cleanup failed but files were moved successfully
|
||||||
|
console.warn(`Warning: Could not clean up temp directory: ${cleanupError.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create module config (include collected config from module.yaml prompts)
|
// Create module config (include collected config from module.yaml prompts)
|
||||||
|
|
@ -1066,9 +1086,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
config.customContent.selectedFiles
|
config.customContent.selectedFiles
|
||||||
) {
|
) {
|
||||||
// Filter out custom modules that were already installed
|
// Filter out custom modules that were already installed
|
||||||
|
const customHandler = new CustomHandler();
|
||||||
for (const customFile of config.customContent.selectedFiles) {
|
for (const customFile of config.customContent.selectedFiles) {
|
||||||
const { CustomHandler } = require('../custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
|
||||||
const customInfo = await customHandler.getCustomInfo(customFile, projectDir);
|
const customInfo = await customHandler.getCustomInfo(customFile, projectDir);
|
||||||
|
|
||||||
// Skip if this was installed as a module
|
// Skip if this was installed as a module
|
||||||
|
|
@ -1080,7 +1099,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
|
|
||||||
if (remainingCustomContent.length > 0) {
|
if (remainingCustomContent.length > 0) {
|
||||||
spinner.start('Installing remaining custom content...');
|
spinner.start('Installing remaining custom content...');
|
||||||
const { CustomHandler } = require('../custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
|
|
||||||
// Use the remaining files
|
// Use the remaining files
|
||||||
|
|
@ -2581,18 +2599,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
installedModules,
|
installedModules,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle both old return format (array) and new format (object)
|
const { validCustomModules, keptModulesWithoutSources } = customModuleResult;
|
||||||
let validCustomModules = [];
|
|
||||||
let keptModulesWithoutSources = [];
|
|
||||||
|
|
||||||
if (Array.isArray(customModuleResult)) {
|
|
||||||
// Old format - just an array
|
|
||||||
validCustomModules = customModuleResult;
|
|
||||||
} else if (customModuleResult && typeof customModuleResult === 'object') {
|
|
||||||
// New format - object with two arrays
|
|
||||||
validCustomModules = customModuleResult.validCustomModules || [];
|
|
||||||
keptModulesWithoutSources = customModuleResult.keptModulesWithoutSources || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const customModulesFromManifest = validCustomModules.map((m) => ({
|
const customModulesFromManifest = validCustomModules.map((m) => ({
|
||||||
...m,
|
...m,
|
||||||
|
|
@ -3371,7 +3378,10 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
|
|
||||||
// If no missing sources, return immediately
|
// If no missing sources, return immediately
|
||||||
if (customModulesWithMissingSources.length === 0) {
|
if (customModulesWithMissingSources.length === 0) {
|
||||||
return validCustomModules;
|
return {
|
||||||
|
validCustomModules,
|
||||||
|
keptModulesWithoutSources: [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop any spinner for interactive prompts
|
// Stop any spinner for interactive prompts
|
||||||
|
|
|
||||||
|
|
@ -125,12 +125,15 @@ class WorkflowCommandGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const coreWorkflowPath = `${this.bmadFolderName}/core/tasks/workflow.xml`;
|
||||||
|
|
||||||
// Replace template variables
|
// Replace template variables
|
||||||
return template
|
return template
|
||||||
.replaceAll('{{name}}', workflow.name)
|
.replaceAll('{{name}}', workflow.name)
|
||||||
.replaceAll('{{module}}', workflow.module)
|
.replaceAll('{{module}}', workflow.module)
|
||||||
.replaceAll('{{description}}', workflow.description)
|
.replaceAll('{{description}}', workflow.description)
|
||||||
.replaceAll('{{workflow_path}}', workflowPath)
|
.replaceAll('{{workflow_path}}', workflowPath)
|
||||||
|
.replaceAll('{{core_workflow_path}}', coreWorkflowPath)
|
||||||
.replaceAll('{bmad_folder}', this.bmadFolderName)
|
.replaceAll('{bmad_folder}', this.bmadFolderName)
|
||||||
.replaceAll('{*bmad_folder*}', '{bmad_folder}');
|
.replaceAll('{*bmad_folder*}', '{bmad_folder}');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ description: '{{description}}'
|
||||||
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded:
|
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded:
|
||||||
|
|
||||||
<steps CRITICAL="TRUE">
|
<steps CRITICAL="TRUE">
|
||||||
1. Always LOAD the FULL @{bmad_folder}/core/tasks/workflow.xml
|
1. Always LOAD the FULL @{{core_workflow_path}}
|
||||||
2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config @{{workflow_path}}
|
2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config @{{workflow_path}}
|
||||||
3. Pass the yaml path {{workflow_path}} as 'workflow-config' parameter to the workflow.xml instructions
|
3. Pass the yaml path {{workflow_path}} as 'workflow-config' parameter to the workflow.xml instructions
|
||||||
4. Follow workflow.xml instructions EXACTLY as written to process and follow the specific workflow config and its instructions
|
4. Follow workflow.xml instructions EXACTLY as written to process and follow the specific workflow config and its instructions
|
||||||
|
|
|
||||||
|
|
@ -391,8 +391,8 @@ class ModuleManager {
|
||||||
if (config.code === moduleName) {
|
if (config.code === moduleName) {
|
||||||
return modulePath;
|
return modulePath;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (error) {
|
||||||
// Skip if can't read config
|
throw new Error(`Failed to parse module.yaml at ${configPath}: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const path = require('node:path');
|
||||||
const os = require('node:os');
|
const os = require('node:os');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const { CLIUtils } = require('./cli-utils');
|
const { CLIUtils } = require('./cli-utils');
|
||||||
|
const { CustomHandler } = require('../installers/lib/custom/handler');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UI utilities for the installer
|
* UI utilities for the installer
|
||||||
|
|
@ -150,7 +151,6 @@ class UI {
|
||||||
const { CustomModuleCache } = require('../installers/lib/core/custom-module-cache');
|
const { CustomModuleCache } = require('../installers/lib/core/custom-module-cache');
|
||||||
const cache = new CustomModuleCache(bmadDir);
|
const cache = new CustomModuleCache(bmadDir);
|
||||||
|
|
||||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
||||||
|
|
||||||
|
|
@ -218,7 +218,6 @@ class UI {
|
||||||
customContentConfig.selectedFiles = selectedCustomContent.map((mod) => mod.replace('__CUSTOM_CONTENT__', ''));
|
customContentConfig.selectedFiles = selectedCustomContent.map((mod) => mod.replace('__CUSTOM_CONTENT__', ''));
|
||||||
// Convert custom content to module IDs for installation
|
// Convert custom content to module IDs for installation
|
||||||
const customContentModuleIds = [];
|
const customContentModuleIds = [];
|
||||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
for (const customFile of customContentConfig.selectedFiles) {
|
for (const customFile of customContentConfig.selectedFiles) {
|
||||||
// Get the module info to extract the ID
|
// Get the module info to extract the ID
|
||||||
|
|
@ -637,8 +636,8 @@ class UI {
|
||||||
moduleData = yaml.load(yamlContent);
|
moduleData = yaml.load(yamlContent);
|
||||||
foundPath = configPath;
|
foundPath = configPath;
|
||||||
break;
|
break;
|
||||||
} catch {
|
} catch (error) {
|
||||||
// Continue to next path
|
throw new Error(`Failed to parse config at ${configPath}: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -654,20 +653,11 @@ class UI {
|
||||||
cached: true,
|
cached: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Debug: show what paths we tried to check
|
// Module config not found - skip silently (non-critical)
|
||||||
console.log(chalk.dim(`DEBUG: No module config found for ${cachedModule.id}`));
|
|
||||||
console.log(
|
|
||||||
chalk.dim(
|
|
||||||
`DEBUG: Tried paths:`,
|
|
||||||
possibleConfigPaths.map((p) => p.replace(cachedModule.cachePath, '.')),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
console.log(chalk.dim(`DEBUG: cachedModule:`, JSON.stringify(cachedModule, null, 2)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (customContentConfig.customPath) {
|
} else if (customContentConfig.customPath) {
|
||||||
// Existing installation - show from directory
|
// Existing installation - show from directory
|
||||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
||||||
|
|
||||||
|
|
@ -882,7 +872,6 @@ class UI {
|
||||||
expandedPath = this.expandUserPath(directory.trim());
|
expandedPath = this.expandUserPath(directory.trim());
|
||||||
|
|
||||||
// Check if directory has custom content
|
// Check if directory has custom content
|
||||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
const customFiles = await customHandler.findCustomContent(expandedPath);
|
const customFiles = await customHandler.findCustomContent(expandedPath);
|
||||||
|
|
||||||
|
|
@ -1277,7 +1266,6 @@ class UI {
|
||||||
const resolvedPath = CLIUtils.expandPath(customPath);
|
const resolvedPath = CLIUtils.expandPath(customPath);
|
||||||
|
|
||||||
// Find custom content
|
// Find custom content
|
||||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
||||||
const customHandler = new CustomHandler();
|
const customHandler = new CustomHandler();
|
||||||
const customFiles = await customHandler.findCustomContent(resolvedPath);
|
const customFiles = await customHandler.findCustomContent(resolvedPath);
|
||||||
|
|
||||||
|
|
@ -1302,12 +1290,10 @@ class UI {
|
||||||
|
|
||||||
// Display found items
|
// Display found items
|
||||||
console.log(chalk.cyan(`\nFound ${customFiles.length} custom content file(s):`));
|
console.log(chalk.cyan(`\nFound ${customFiles.length} custom content file(s):`));
|
||||||
const { CustomHandler: CustomHandler2 } = require('../installers/lib/custom/handler');
|
|
||||||
const customHandler2 = new CustomHandler2();
|
|
||||||
const customContentItems = [];
|
const customContentItems = [];
|
||||||
|
|
||||||
for (const customFile of customFiles) {
|
for (const customFile of customFiles) {
|
||||||
const customInfo = await customHandler2.getCustomInfo(customFile);
|
const customInfo = await customHandler.getCustomInfo(customFile);
|
||||||
if (customInfo) {
|
if (customInfo) {
|
||||||
customContentItems.push({
|
customContentItems.push({
|
||||||
name: `${chalk.cyan('✓')} ${customInfo.name} ${chalk.gray(`(${customInfo.relativePath})`)}`,
|
name: `${chalk.cyan('✓')} ${customInfo.name} ${chalk.gray(`(${customInfo.relativePath})`)}`,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue