mirror of
https://github.com/bmadcode/BMAD-METHOD.git
synced 2025-12-17 09:45:25 +00:00
feat: Add project-specific installation option for Codex CLI
Add support for choosing between global and project-specific installation locations for Codex CLI prompts with CODEX_HOME configuration instructions. Changes: - Add collectConfiguration() to prompt for installation location (default: global) - Support global (~/.codex/prompts) and project-specific (<project>/.codex/prompts) - Display OS-specific CODEX_HOME setup instructions before user confirms - Update detect() and cleanup() to handle both installation locations Installation options: - Global: Simple, works immediately, but prompts reference specific .bmad path - Project-specific: Requires CODEX_HOME, better for multi-project workflows - Unix/Mac: alias codex='CODEX_HOME="$PWD/.codex" codex' - Windows: codex.cmd wrapper with %~dp0
This commit is contained in:
parent
0ca164de34
commit
a8a5a48e00
@ -15,6 +15,67 @@ class CodexSetup extends BaseIdeSetup {
|
||||
super('codex', 'Codex', true); // preferred IDE
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect configuration choices before installation
|
||||
* @param {Object} options - Configuration options
|
||||
* @returns {Object} Collected configuration
|
||||
*/
|
||||
async collectConfiguration(options = {}) {
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
let confirmed = false;
|
||||
let installLocation = 'global';
|
||||
|
||||
while (!confirmed) {
|
||||
const { location } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'location',
|
||||
message: 'Where would you like to install Codex CLI prompts?',
|
||||
choices: [
|
||||
{
|
||||
name: 'Global - Simple for single project ' + '(~/.codex/prompts, but references THIS project only)',
|
||||
value: 'global',
|
||||
},
|
||||
{
|
||||
name: `Project-specific - Recommended for real work (requires CODEX_HOME=<project-dir>${path.sep}.codex)`,
|
||||
value: 'project',
|
||||
},
|
||||
],
|
||||
default: 'global',
|
||||
},
|
||||
]);
|
||||
|
||||
installLocation = location;
|
||||
|
||||
// Display detailed instructions for the chosen option
|
||||
console.log('');
|
||||
if (installLocation === 'project') {
|
||||
console.log(this.getProjectSpecificInstructions());
|
||||
} else {
|
||||
console.log(this.getGlobalInstructions());
|
||||
}
|
||||
|
||||
// Confirm the choice
|
||||
const { proceed } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'proceed',
|
||||
message: 'Proceed with this installation option?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
confirmed = proceed;
|
||||
|
||||
if (!confirmed) {
|
||||
console.log(chalk.yellow("\n Let's choose a different installation option.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
return { installLocation };
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Codex configuration
|
||||
* @param {string} projectDir - Project directory
|
||||
@ -27,9 +88,12 @@ class CodexSetup extends BaseIdeSetup {
|
||||
// Always use CLI mode
|
||||
const mode = 'cli';
|
||||
|
||||
// Get installation location from pre-collected config or default to global
|
||||
const installLocation = options.preCollectedConfig?.installLocation || 'global';
|
||||
|
||||
const { artifacts, counts } = await this.collectClaudeArtifacts(projectDir, bmadDir, options);
|
||||
|
||||
const destDir = this.getCodexPromptDir();
|
||||
const destDir = this.getCodexPromptDir(projectDir, installLocation);
|
||||
await fs.ensureDir(destDir);
|
||||
await this.clearOldBmadFiles(destDir);
|
||||
const written = await this.flattenAndWriteArtifacts(artifacts, destDir);
|
||||
@ -45,22 +109,6 @@ class CodexSetup extends BaseIdeSetup {
|
||||
console.log(chalk.dim(` - ${written} Codex prompt files written`));
|
||||
console.log(chalk.dim(` - Destination: ${destDir}`));
|
||||
|
||||
// Prominent notice about home directory installation
|
||||
console.log('');
|
||||
console.log(chalk.bold.cyan('═'.repeat(70)));
|
||||
console.log(chalk.bold.yellow(' IMPORTANT: Codex Configuration'));
|
||||
console.log(chalk.bold.cyan('═'.repeat(70)));
|
||||
console.log('');
|
||||
console.log(chalk.white(' Prompts have been installed to your HOME DIRECTORY, not this project.'));
|
||||
console.log(chalk.white(' No .codex file was created in the project root.'));
|
||||
console.log('');
|
||||
console.log(chalk.green(' ✓ You can now use slash commands (/) in Codex CLI'));
|
||||
console.log(chalk.dim(' Example: /bmad-bmm-agents-pm'));
|
||||
console.log(chalk.dim(' Type / to see all available commands'));
|
||||
console.log('');
|
||||
console.log(chalk.bold.cyan('═'.repeat(70)));
|
||||
console.log('');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
mode,
|
||||
@ -68,21 +116,36 @@ class CodexSetup extends BaseIdeSetup {
|
||||
counts,
|
||||
destination: destDir,
|
||||
written,
|
||||
installLocation,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect Codex installation by checking for BMAD prompt exports
|
||||
*/
|
||||
async detect(_projectDir) {
|
||||
const destDir = this.getCodexPromptDir();
|
||||
async detect(projectDir) {
|
||||
// Check both global and project-specific locations
|
||||
const globalDir = this.getCodexPromptDir(null, 'global');
|
||||
const projectDir_local = projectDir || process.cwd();
|
||||
const projectSpecificDir = this.getCodexPromptDir(projectDir_local, 'project');
|
||||
|
||||
if (!(await fs.pathExists(destDir))) {
|
||||
return false;
|
||||
// Check global location
|
||||
if (await fs.pathExists(globalDir)) {
|
||||
const entries = await fs.readdir(globalDir);
|
||||
if (entries.some((entry) => entry.startsWith('bmad-'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const entries = await fs.readdir(destDir);
|
||||
return entries.some((entry) => entry.startsWith('bmad-'));
|
||||
// Check project-specific location
|
||||
if (await fs.pathExists(projectSpecificDir)) {
|
||||
const entries = await fs.readdir(projectSpecificDir);
|
||||
if (entries.some((entry) => entry.startsWith('bmad-'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +205,10 @@ class CodexSetup extends BaseIdeSetup {
|
||||
};
|
||||
}
|
||||
|
||||
getCodexPromptDir() {
|
||||
getCodexPromptDir(projectDir = null, location = 'global') {
|
||||
if (location === 'project' && projectDir) {
|
||||
return path.join(projectDir, '.codex', 'prompts');
|
||||
}
|
||||
return path.join(os.homedir(), '.codex', 'prompts');
|
||||
}
|
||||
|
||||
@ -192,11 +258,96 @@ class CodexSetup extends BaseIdeSetup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup Codex configuration (no-op until export destination is finalized)
|
||||
* Get instructions for global installation
|
||||
* @returns {string} Instructions text
|
||||
*/
|
||||
async cleanup() {
|
||||
const destDir = this.getCodexPromptDir();
|
||||
await this.clearOldBmadFiles(destDir);
|
||||
getGlobalInstructions(destDir) {
|
||||
const lines = [
|
||||
'',
|
||||
chalk.bold.cyan('═'.repeat(70)),
|
||||
chalk.bold.yellow(' IMPORTANT: Codex Configuration'),
|
||||
chalk.bold.cyan('═'.repeat(70)),
|
||||
'',
|
||||
chalk.white(' /prompts installed globally to your HOME DIRECTORY.'),
|
||||
'',
|
||||
chalk.yellow(' ⚠️ These prompts reference a specific .bmad path'),
|
||||
chalk.dim(" To use with other projects, you'd need to copy the .bmad dir"),
|
||||
'',
|
||||
chalk.green(' ✓ You can now use /commands in Codex CLI'),
|
||||
chalk.dim(' Example: /bmad-bmm-agents-pm'),
|
||||
chalk.dim(' Type / to see all available commands'),
|
||||
'',
|
||||
chalk.bold.cyan('═'.repeat(70)),
|
||||
'',
|
||||
];
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instructions for project-specific installation
|
||||
* @param {string} projectDir - Optional project directory
|
||||
* @param {string} destDir - Optional destination directory
|
||||
* @returns {string} Instructions text
|
||||
*/
|
||||
getProjectSpecificInstructions(projectDir = null, destDir = null) {
|
||||
const isWindows = os.platform() === 'win32';
|
||||
|
||||
const commonLines = [
|
||||
'',
|
||||
chalk.bold.cyan('═'.repeat(70)),
|
||||
chalk.bold.yellow(' Project-Specific Codex Configuration'),
|
||||
chalk.bold.cyan('═'.repeat(70)),
|
||||
'',
|
||||
chalk.white(' Prompts will be installed to: ') + chalk.cyan(destDir || '<project>/.codex/prompts'),
|
||||
'',
|
||||
chalk.bold.yellow(' ⚠️ REQUIRED: You must set CODEX_HOME to use these prompts'),
|
||||
'',
|
||||
];
|
||||
|
||||
const windowsLines = [
|
||||
chalk.bold(' Create a codex.cmd file in your project root:'),
|
||||
'',
|
||||
chalk.green(' @echo off'),
|
||||
chalk.green(' set CODEX_HOME=%~dp0.codex'),
|
||||
chalk.green(' codex %*'),
|
||||
'',
|
||||
chalk.dim(String.raw` Then run: .\codex instead of codex`),
|
||||
chalk.dim(' (The %~dp0 gets the directory of the .cmd file)'),
|
||||
];
|
||||
|
||||
const unixLines = [
|
||||
chalk.bold(' Add this alias to your ~/.bashrc or ~/.zshrc:'),
|
||||
'',
|
||||
chalk.green(' alias codex=\'CODEX_HOME="$PWD/.codex" codex\''),
|
||||
'',
|
||||
chalk.dim(' After adding, run: source ~/.bashrc (or source ~/.zshrc)'),
|
||||
chalk.dim(' (The $PWD uses your current working directory)'),
|
||||
];
|
||||
const closingLines = [
|
||||
'',
|
||||
chalk.dim(' This tells Codex CLI to use prompts from this project instead of ~/.codex'),
|
||||
'',
|
||||
chalk.bold.cyan('═'.repeat(70)),
|
||||
'',
|
||||
];
|
||||
|
||||
const lines = [...commonLines, ...(isWindows ? windowsLines : unixLines), ...closingLines];
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup Codex configuration
|
||||
*/
|
||||
async cleanup(projectDir = null) {
|
||||
// Clean both global and project-specific locations
|
||||
const globalDir = this.getCodexPromptDir(null, 'global');
|
||||
await this.clearOldBmadFiles(globalDir);
|
||||
|
||||
if (projectDir) {
|
||||
const projectSpecificDir = this.getCodexPromptDir(projectDir, 'project');
|
||||
await this.clearOldBmadFiles(projectSpecificDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user