bmad-method 4.41.0 → 4.42.1

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.
@@ -74,6 +74,12 @@ class IdeSetup extends BaseIdeSetup {
74
74
  case 'qwen-code': {
75
75
  return this.setupQwenCode(installDir, selectedAgent);
76
76
  }
77
+ case 'codex': {
78
+ return this.setupCodex(installDir, selectedAgent, { webEnabled: false });
79
+ }
80
+ case 'codex-web': {
81
+ return this.setupCodex(installDir, selectedAgent, { webEnabled: true });
82
+ }
77
83
  default: {
78
84
  console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
79
85
  return false;
@@ -81,6 +87,175 @@ class IdeSetup extends BaseIdeSetup {
81
87
  }
82
88
  }
83
89
 
90
+ async setupCodex(installDir, selectedAgent, options) {
91
+ options = options ?? { webEnabled: false };
92
+ // Codex reads AGENTS.md at the project root as project memory (CLI & Web).
93
+ // Inject/update a BMAD section with guidance, directory, and details.
94
+ const filePath = path.join(installDir, 'AGENTS.md');
95
+ const startMarker = '<!-- BEGIN: BMAD-AGENTS -->';
96
+ const endMarker = '<!-- END: BMAD-AGENTS -->';
97
+
98
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
99
+ const tasks = await this.getAllTaskIds(installDir);
100
+
101
+ // Build BMAD section content
102
+ let section = '';
103
+ section += `${startMarker}\n`;
104
+ section += `# BMAD-METHOD Agents and Tasks\n\n`;
105
+ section += `This section is auto-generated by BMAD-METHOD for Codex. Codex merges this AGENTS.md into context.\n\n`;
106
+ section += `## How To Use With Codex\n\n`;
107
+ section += `- Codex CLI: run \`codex\` in this project. Reference an agent naturally, e.g., "As dev, implement ...".\n`;
108
+ section += `- Codex Web: open this repo and reference roles the same way; Codex reads \`AGENTS.md\`.\n`;
109
+ section += `- Commit \`.bmad-core\` and this \`AGENTS.md\` file to your repo so Codex (Web/CLI) can read full agent definitions.\n`;
110
+ section += `- Refresh this section after agent updates: \`npx bmad-method install -f -i codex\`.\n\n`;
111
+
112
+ section += `### Helpful Commands\n\n`;
113
+ section += `- List agents: \`npx bmad-method list:agents\`\n`;
114
+ section += `- Reinstall BMAD core and regenerate AGENTS.md: \`npx bmad-method install -f -i codex\`\n`;
115
+ section += `- Validate configuration: \`npx bmad-method validate\`\n\n`;
116
+
117
+ // Agents directory table
118
+ section += `## Agents\n\n`;
119
+ section += `### Directory\n\n`;
120
+ section += `| Title | ID | When To Use |\n|---|---|---|\n`;
121
+ const agentSummaries = [];
122
+ for (const agentId of agents) {
123
+ const agentPath = await this.findAgentPath(agentId, installDir);
124
+ if (!agentPath) continue;
125
+ const raw = await fileManager.readFile(agentPath);
126
+ const yamlMatch = raw.match(/```ya?ml\r?\n([\s\S]*?)```/);
127
+ const yamlBlock = yamlMatch ? yamlMatch[1].trim() : null;
128
+ const title = await this.getAgentTitle(agentId, installDir);
129
+ const whenToUse = yamlBlock?.match(/whenToUse:\s*"?([^\n"]+)"?/i)?.[1]?.trim() || '';
130
+ agentSummaries.push({ agentId, title, whenToUse, yamlBlock, raw, path: agentPath });
131
+ section += `| ${title} | ${agentId} | ${whenToUse || '—'} |\n`;
132
+ }
133
+ section += `\n`;
134
+
135
+ // Detailed agent sections
136
+ for (const { agentId, title, whenToUse, yamlBlock, raw, path: agentPath } of agentSummaries) {
137
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
138
+ section += `### ${title} (id: ${agentId})\n`;
139
+ section += `Source: ${relativePath}\n\n`;
140
+ if (whenToUse) section += `- When to use: ${whenToUse}\n`;
141
+ section += `- How to activate: Mention "As ${agentId}, ..." or "Use ${title} to ..."\n\n`;
142
+ if (yamlBlock) {
143
+ section += '```yaml\n' + yamlBlock + '\n```\n\n';
144
+ } else {
145
+ section += '```md\n' + raw.trim() + '\n```\n\n';
146
+ }
147
+ }
148
+
149
+ // Tasks
150
+ if (tasks && tasks.length > 0) {
151
+ section += `## Tasks\n\n`;
152
+ section += `These are reusable task briefs you can reference directly in Codex.\n\n`;
153
+ for (const taskId of tasks) {
154
+ const taskPath = await this.findTaskPath(taskId, installDir);
155
+ if (!taskPath) continue;
156
+ const raw = await fileManager.readFile(taskPath);
157
+ const relativePath = path.relative(installDir, taskPath).replaceAll('\\', '/');
158
+ section += `### Task: ${taskId}\n`;
159
+ section += `Source: ${relativePath}\n`;
160
+ section += `- How to use: "Use task ${taskId} with the appropriate agent" and paste relevant parts as needed.\n\n`;
161
+ section += '```md\n' + raw.trim() + '\n```\n\n';
162
+ }
163
+ }
164
+
165
+ section += `${endMarker}\n`;
166
+
167
+ // Write or update AGENTS.md
168
+ let finalContent = '';
169
+ if (await fileManager.pathExists(filePath)) {
170
+ const existing = await fileManager.readFile(filePath);
171
+ if (existing.includes(startMarker) && existing.includes(endMarker)) {
172
+ // Replace existing BMAD block
173
+ const pattern = String.raw`${startMarker}[\s\S]*?${endMarker}`;
174
+ const replaced = existing.replace(new RegExp(pattern, 'm'), section);
175
+ finalContent = replaced;
176
+ } else {
177
+ // Append BMAD block to existing file
178
+ finalContent = existing.trimEnd() + `\n\n` + section;
179
+ }
180
+ } else {
181
+ // Create fresh AGENTS.md with a small header and BMAD block
182
+ finalContent += '# Project Agents\n\n';
183
+ finalContent += 'This file provides guidance and memory for Codex CLI.\n\n';
184
+ finalContent += section;
185
+ }
186
+
187
+ await fileManager.writeFile(filePath, finalContent);
188
+ console.log(chalk.green('✓ Created/updated AGENTS.md for Codex CLI integration'));
189
+ console.log(
190
+ chalk.dim(
191
+ 'Codex reads AGENTS.md automatically. Run `codex` in this project to use BMAD agents.',
192
+ ),
193
+ );
194
+
195
+ // Optionally add helpful npm scripts if a package.json exists
196
+ try {
197
+ const pkgPath = path.join(installDir, 'package.json');
198
+ if (await fileManager.pathExists(pkgPath)) {
199
+ const pkgRaw = await fileManager.readFile(pkgPath);
200
+ const pkg = JSON.parse(pkgRaw);
201
+ pkg.scripts = pkg.scripts || {};
202
+ const updated = { ...pkg.scripts };
203
+ if (!updated['bmad:refresh']) updated['bmad:refresh'] = 'bmad-method install -f -i codex';
204
+ if (!updated['bmad:list']) updated['bmad:list'] = 'bmad-method list:agents';
205
+ if (!updated['bmad:validate']) updated['bmad:validate'] = 'bmad-method validate';
206
+ const changed = JSON.stringify(updated) !== JSON.stringify(pkg.scripts);
207
+ if (changed) {
208
+ const newPkg = { ...pkg, scripts: updated };
209
+ await fileManager.writeFile(pkgPath, JSON.stringify(newPkg, null, 2) + '\n');
210
+ console.log(chalk.green('✓ Added npm scripts: bmad:refresh, bmad:list, bmad:validate'));
211
+ }
212
+ }
213
+ } catch {
214
+ console.log(
215
+ chalk.yellow('⚠︎ Skipped adding npm scripts (package.json not writable or invalid)'),
216
+ );
217
+ }
218
+
219
+ // Adjust .gitignore behavior depending on Codex mode
220
+ try {
221
+ const gitignorePath = path.join(installDir, '.gitignore');
222
+ const ignoreLines = ['# BMAD (local only)', '.bmad-core/', '.bmad-*/'];
223
+ const exists = await fileManager.pathExists(gitignorePath);
224
+ if (options.webEnabled) {
225
+ if (exists) {
226
+ let gi = await fileManager.readFile(gitignorePath);
227
+ // Remove lines that ignore BMAD dot-folders
228
+ const updated = gi
229
+ .split(/\r?\n/)
230
+ .filter((l) => !/^\s*\.bmad-core\/?\s*$/.test(l) && !/^\s*\.bmad-\*\/?\s*$/.test(l))
231
+ .join('\n');
232
+ if (updated !== gi) {
233
+ await fileManager.writeFile(gitignorePath, updated.trimEnd() + '\n');
234
+ console.log(chalk.green('✓ Updated .gitignore to include .bmad-core in commits'));
235
+ }
236
+ }
237
+ } else {
238
+ // Local-only: add ignores if missing
239
+ let base = exists ? await fileManager.readFile(gitignorePath) : '';
240
+ const haveCore = base.includes('.bmad-core/');
241
+ const haveStar = base.includes('.bmad-*/');
242
+ if (!haveCore || !haveStar) {
243
+ const sep = base.endsWith('\n') || base.length === 0 ? '' : '\n';
244
+ const add = [!haveCore || !haveStar ? ignoreLines.join('\n') : '']
245
+ .filter(Boolean)
246
+ .join('\n');
247
+ const out = base + sep + add + '\n';
248
+ await fileManager.writeFile(gitignorePath, out);
249
+ console.log(chalk.green('✓ Added .bmad-core/* to .gitignore for local-only Codex setup'));
250
+ }
251
+ }
252
+ } catch {
253
+ console.log(chalk.yellow('⚠︎ Could not update .gitignore (skipping)'));
254
+ }
255
+
256
+ return true;
257
+ }
258
+
84
259
  async setupCursor(installDir, selectedAgent) {
85
260
  const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
86
261
  const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmad-method",
3
- "version": "4.41.0",
3
+ "version": "4.42.1",
4
4
  "description": "BMad Method installer - AI-powered Agile development framework",
5
5
  "keywords": [
6
6
  "bmad",
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+
3
+ # Setup script for git hooks
4
+ echo "Setting up git hooks..."
5
+
6
+ # Install husky
7
+ npm install --save-dev husky
8
+
9
+ # Initialize husky
10
+ npx husky init
11
+
12
+ # Create pre-commit hook
13
+ cat > .husky/pre-commit << 'EOF'
14
+ #!/usr/bin/env sh
15
+ . "$(dirname -- "$0")/_/husky.sh"
16
+
17
+ # Run validation checks before commit
18
+ echo "Running pre-commit checks..."
19
+
20
+ npm run validate
21
+ npm run format:check
22
+ npm run lint
23
+
24
+ if [ $? -ne 0 ]; then
25
+ echo "❌ Pre-commit checks failed. Please fix the issues before committing."
26
+ echo " Run 'npm run format' to fix formatting issues"
27
+ echo " Run 'npm run lint:fix' to fix some lint issues"
28
+ exit 1
29
+ fi
30
+
31
+ echo "✅ Pre-commit checks passed!"
32
+ EOF
33
+
34
+ chmod +x .husky/pre-commit
35
+
36
+ echo "✅ Git hooks setup complete!"
37
+ echo "Now commits will be validated before they're created."