From 17c9d264a91995e0f2fb9fd60d2ac81d471250c2 Mon Sep 17 00:00:00 2001 From: Q00 Date: Thu, 8 Jan 2026 14:59:43 +0900 Subject: [PATCH] fix: resolve ERR_REQUIRE_ESM by using dynamic import for inquirer Inquirer v9+ is ESM-only, causing ERR_REQUIRE_ESM when loaded via require() in CommonJS. Convert all require('inquirer') calls to dynamic import('inquirer') across 8 CLI files. Fixes #1197 --- tools/cli/commands/install.js | 2 +- .../installers/lib/core/config-collector.js | 12 +++++++++- tools/cli/installers/lib/core/installer.js | 7 +++--- tools/cli/installers/lib/ide/antigravity.js | 6 ++--- tools/cli/installers/lib/ide/claude-code.js | 6 ++--- tools/cli/installers/lib/ide/codex.js | 2 +- .../cli/installers/lib/ide/github-copilot.js | 2 +- tools/cli/lib/ui.js | 23 ++++++++++++++++++- 8 files changed, 45 insertions(+), 15 deletions(-) diff --git a/tools/cli/commands/install.js b/tools/cli/commands/install.js index 1ae5d4c0..f71d5679 100644 --- a/tools/cli/commands/install.js +++ b/tools/cli/commands/install.js @@ -1,6 +1,5 @@ const chalk = require('chalk'); const path = require('node:path'); -const inquirer = require('inquirer').default || require('inquirer'); const { Installer } = require('../installers/lib/core/installer'); const { UI } = require('../lib/ui'); @@ -72,6 +71,7 @@ module.exports = { console.log(chalk.dim(' • ElevenLabs AI (150+ premium voices)')); console.log(chalk.dim(' • Piper TTS (50+ free voices)\n')); + const { default: inquirer } = await import('inquirer'); await inquirer.prompt([ { type: 'input', diff --git a/tools/cli/installers/lib/core/config-collector.js b/tools/cli/installers/lib/core/config-collector.js index fad0f108..fb48b68d 100644 --- a/tools/cli/installers/lib/core/config-collector.js +++ b/tools/cli/installers/lib/core/config-collector.js @@ -2,10 +2,18 @@ const path = require('node:path'); const fs = require('fs-extra'); const yaml = require('yaml'); const chalk = require('chalk'); -const inquirer = require('inquirer').default || require('inquirer'); const { getProjectRoot, getModulePath } = require('../../../lib/project-root'); const { CLIUtils } = require('../../../lib/cli-utils'); +// Lazy-load inquirer (ESM module) to avoid ERR_REQUIRE_ESM +let _inquirer = null; +async function getInquirer() { + if (!_inquirer) { + _inquirer = (await import('inquirer')).default; + } + return _inquirer; +} + class ConfigCollector { constructor() { this.collectedConfig = {}; @@ -175,6 +183,7 @@ class ConfigCollector { * @returns {boolean} True if new fields were prompted, false if all fields existed */ async collectModuleConfigQuick(moduleName, projectDir, silentMode = true) { + const inquirer = await getInquirer(); this.currentProjectDir = projectDir; // Load existing config if not already loaded @@ -493,6 +502,7 @@ class ConfigCollector { * @param {boolean} skipCompletion - Skip showing completion message (for early core collection) */ async collectModuleConfig(moduleName, projectDir, skipLoadExisting = false, skipCompletion = false) { + const inquirer = await getInquirer(); this.currentProjectDir = projectDir; // Load existing config if needed and not already loaded if (!skipLoadExisting && !this.existingConfig) { diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 816dbbbc..8b7e05fd 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -2,7 +2,6 @@ const path = require('node:path'); const fs = require('fs-extra'); const chalk = require('chalk'); const ora = require('ora'); -const inquirer = require('inquirer').default || require('inquirer'); const { Detector } = require('./detector'); const { Manifest } = require('./manifest'); const { ModuleManager } = require('../modules/manager'); @@ -2140,7 +2139,7 @@ class Installer { * Private: Prompt for update action */ async promptUpdateAction() { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); return await inquirer.prompt([ { type: 'list', @@ -2157,7 +2156,7 @@ class Installer { * @param {Object} _legacyV4 - Legacy V4 detection result (unused in simplified version) */ async handleLegacyV4Migration(_projectDir, _legacyV4) { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); console.log(''); console.log(chalk.yellow.bold('⚠️ Legacy BMAD v4 detected')); @@ -2438,7 +2437,7 @@ class Installer { console.log(chalk.yellow(`\n⚠️ Found ${customModulesWithMissingSources.length} custom module(s) with missing sources:`)); - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); let keptCount = 0; let updatedCount = 0; let removedCount = 0; diff --git a/tools/cli/installers/lib/ide/antigravity.js b/tools/cli/installers/lib/ide/antigravity.js index a7fed6ea..c896d62d 100644 --- a/tools/cli/installers/lib/ide/antigravity.js +++ b/tools/cli/installers/lib/ide/antigravity.js @@ -58,7 +58,7 @@ class AntigravitySetup extends BaseIdeSetup { if (config.subagentChoices.install !== 'none') { // Ask for installation location - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); const locationAnswer = await inquirer.prompt([ { type: 'list', @@ -297,7 +297,7 @@ class AntigravitySetup extends BaseIdeSetup { choices = await this.promptSubagentInstallation(config.subagents); if (choices.install !== 'none') { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); const locationAnswer = await inquirer.prompt([ { type: 'list', @@ -334,7 +334,7 @@ class AntigravitySetup extends BaseIdeSetup { * Prompt user for subagent installation preferences */ async promptSubagentInstallation(subagentConfig) { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); // First ask if they want to install subagents const { install } = await inquirer.prompt([ diff --git a/tools/cli/installers/lib/ide/claude-code.js b/tools/cli/installers/lib/ide/claude-code.js index 35e70b0b..f2a33221 100644 --- a/tools/cli/installers/lib/ide/claude-code.js +++ b/tools/cli/installers/lib/ide/claude-code.js @@ -57,7 +57,7 @@ class ClaudeCodeSetup extends BaseIdeSetup { if (config.subagentChoices.install !== 'none') { // Ask for installation location - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); const locationAnswer = await inquirer.prompt([ { type: 'list', @@ -305,7 +305,7 @@ class ClaudeCodeSetup extends BaseIdeSetup { choices = await this.promptSubagentInstallation(config.subagents); if (choices.install !== 'none') { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); const locationAnswer = await inquirer.prompt([ { type: 'list', @@ -342,7 +342,7 @@ class ClaudeCodeSetup extends BaseIdeSetup { * Prompt user for subagent installation preferences */ async promptSubagentInstallation(subagentConfig) { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); // First ask if they want to install subagents const { install } = await inquirer.prompt([ diff --git a/tools/cli/installers/lib/ide/codex.js b/tools/cli/installers/lib/ide/codex.js index 9967057a..3ce9d910 100644 --- a/tools/cli/installers/lib/ide/codex.js +++ b/tools/cli/installers/lib/ide/codex.js @@ -21,7 +21,7 @@ class CodexSetup extends BaseIdeSetup { * @returns {Object} Collected configuration */ async collectConfiguration(options = {}) { - const inquirer = require('inquirer').default || require('inquirer'); + const { default: inquirer } = await import('inquirer'); let confirmed = false; let installLocation = 'global'; diff --git a/tools/cli/installers/lib/ide/github-copilot.js b/tools/cli/installers/lib/ide/github-copilot.js index 36d3eecb..b9dd5f98 100644 --- a/tools/cli/installers/lib/ide/github-copilot.js +++ b/tools/cli/installers/lib/ide/github-copilot.js @@ -1,7 +1,6 @@ const path = require('node:path'); const { BaseIdeSetup } = require('./_base-ide'); const chalk = require('chalk'); -const inquirer = require('inquirer').default || require('inquirer'); const { AgentCommandGenerator } = require('./shared/agent-command-generator'); /** @@ -22,6 +21,7 @@ class GitHubCopilotSetup extends BaseIdeSetup { * @returns {Object} Collected configuration */ async collectConfiguration(options = {}) { + const { default: inquirer } = await import('inquirer'); const config = {}; console.log('\n' + chalk.blue(' 🔧 VS Code Settings Configuration')); diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index ab055643..85f31ce1 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -1,11 +1,19 @@ const chalk = require('chalk'); -const inquirer = require('inquirer').default || require('inquirer'); const path = require('node:path'); const os = require('node:os'); const fs = require('fs-extra'); const { CLIUtils } = require('./cli-utils'); const { CustomHandler } = require('../installers/lib/custom/handler'); +// Lazy-load inquirer (ESM module) to avoid ERR_REQUIRE_ESM +let _inquirer = null; +async function getInquirer() { + if (!_inquirer) { + _inquirer = (await import('inquirer')).default; + } + return _inquirer; +} + /** * UI utilities for the installer */ @@ -15,6 +23,7 @@ class UI { * @returns {Object} Installation configuration */ async promptInstall() { + const inquirer = await getInquirer(); CLIUtils.displayLogo(); // Display version-specific start message from install-messages.yaml @@ -450,6 +459,7 @@ class UI { * @returns {Object} Tool configuration */ async promptToolSelection(projectDir, selectedModules) { + const inquirer = await getInquirer(); // Check for existing configured IDEs - use findBmadDir to detect custom folder names const { Detector } = require('../installers/lib/core/detector'); const { Installer } = require('../installers/lib/core/installer'); @@ -582,6 +592,7 @@ class UI { * @returns {Object} Update configuration */ async promptUpdate() { + const inquirer = await getInquirer(); const answers = await inquirer.prompt([ { type: 'confirm', @@ -606,6 +617,7 @@ class UI { * @returns {Array} Selected modules */ async promptModules(modules) { + const inquirer = await getInquirer(); const choices = modules.map((mod) => ({ name: `${mod.name} - ${mod.description}`, value: mod.id, @@ -637,6 +649,7 @@ class UI { * @returns {boolean} User confirmation */ async confirm(message, defaultValue = false) { + const inquirer = await getInquirer(); const { confirmed } = await inquirer.prompt([ { type: 'confirm', @@ -743,6 +756,7 @@ class UI { * @returns {Array} Module choices for inquirer */ async getModuleChoices(installedModuleIds, customContentConfig = null) { + const inquirer = await getInquirer(); const moduleChoices = []; const isNewInstallation = installedModuleIds.size === 0; @@ -823,6 +837,7 @@ class UI { * @returns {Array} Selected module IDs */ async selectModules(moduleChoices, defaultSelections = []) { + const inquirer = await getInquirer(); const moduleAnswer = await inquirer.prompt([ { type: 'checkbox', @@ -843,6 +858,7 @@ class UI { * @returns {Object} Directory answer from inquirer */ async promptForDirectory() { + const inquirer = await getInquirer(); return await inquirer.prompt([ { type: 'input', @@ -899,6 +915,7 @@ class UI { * @returns {boolean} Whether user confirmed */ async confirmDirectory(directory) { + const inquirer = await getInquirer(); const dirExists = await fs.pathExists(directory); if (dirExists) { @@ -1085,6 +1102,7 @@ class UI { * - GitHub Issue: paulpreibisch/AgentVibes#36 */ async promptAgentVibes(projectDir) { + const inquirer = await getInquirer(); CLIUtils.displaySection('🎤 Voice Features', 'Enable TTS for multi-agent conversations'); // Check if AgentVibes is already installed @@ -1235,6 +1253,7 @@ class UI { * @returns {Object} Custom content configuration */ async promptCustomContentSource() { + const inquirer = await getInquirer(); const customContentConfig = { hasCustomContent: true, sources: [] }; // Keep asking for more sources until user is done @@ -1372,6 +1391,7 @@ class UI { * @returns {Object} Result with selected custom modules and custom content config */ async handleCustomModulesInModifyFlow(directory, selectedModules) { + const inquirer = await getInquirer(); // Get existing installation to find custom modules const { existingInstall } = await this.getExistingInstallation(directory); @@ -1566,6 +1586,7 @@ class UI { * @returns {Promise} True if user wants to proceed, false if they cancel */ async showOldAlphaVersionWarning(installedVersion, currentVersion, bmadFolderName) { + const inquirer = await getInquirer(); const versionInfo = this.checkAlphaVersionAge(installedVersion, currentVersion); // Also warn if version is unknown or can't be parsed (legacy/unsupported)