Compare commits

...

3 Commits

Author SHA1 Message Date
Brian Madison 966ca5db0b indicator when external modules are being downloaded during install so installer does not appear to be frozen / unresponsive. 2026-01-18 02:16:25 -06:00
forcetrainer e0318d9da8
feat: update website header with new BMAD Method branding (#1352)
* docs: apply style guide to TEA Lite quickstart

- Remove duplicate H1 header (frontmatter provides title)
- Remove horizontal rules throughout
- Convert Prerequisites to admonition
- Add Quick Path TL;DR admonition
- Convert Key Takeaway to tip admonition
- Convert TEA Workflows list to Quick Reference table
- Convert Troubleshooting to Common Questions FAQ format
- Rename Need Help to Getting Help section
- Remove redundant Feedback section

Also adds missing @clack/prompts dependency from upstream merge.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: spell out acronyms in TEA Lite quickstart

- MCP → Model Context Protocol
- E2E → End-to-end (also fix missing article)
- CI/CD → Continuous integration/continuous deployment
- ATDD → Acceptance Test-Driven Development
- TDD → Test-Driven Development
- NFR → non-functional requirements
- Remove inaccurate CRUD reference

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: spell out TDD in ATDD link text

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: update branding with new wordmark logo and banner

- Add banner image to README header
- Replace website logo with wordmark, hiding title text
- Left-align logo with sidebar by reducing header padding

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: update README banner to new design with waveform

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add banner to docs website welcome page

- Revert README to original banner
- Add waveform banner to docs site welcome page

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: use waveform banner as website header logo

- Remove banner from welcome page content
- Update header logo to use banner-bmad-method2.png

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add separate logo for dark mode

Use banner-bmad-method-dark.png in dark mode for better blending

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: update header logos for light and dark modes

- Light mode: bmad-light.png (dark blue background with lightning)
- Dark mode: bmad-dark.png (light background variant)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: clean up unused banner images and add readme2

- Remove unused banner-bmad-method2.png and bmad-wordmark.png
- Add readme2.md with upcoming features section
- Update banner-bmad-method-dark.png

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: remove unused banner image variants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: finalize header logo graphics

- Rename bmad-light2.png to bmad-light.png as final version
- Remove readme2.md draft

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Brian <bmadcode@gmail.com>
2026-01-18 00:25:12 -06:00
MarkRadaba 4a983d64a7
chore: add .github/agents to gitignore (#1353)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 23:35:08 -06:00
10 changed files with 66 additions and 25 deletions

1
.gitignore vendored
View File

@ -61,6 +61,7 @@ _bmad-output
.claude
.codex
.github/chatmodes
.github/agents
.agent
.agentvibes/
.kiro/

View File

@ -1,4 +1,4 @@
# BMad Method
![BMad Method](banner-bmad-method.png)
[![Version](https://img.shields.io/npm/v/bmad-method?color=blue&label=version)](https://www.npmjs.com/package/bmad-method)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

BIN
Wordmark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
banner-bmad-method.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

View File

@ -13,17 +13,15 @@ By the end of this 30-minute tutorial, you'll have:
- Passing tests for an existing demo app feature
:::note[Prerequisites]
- Node.js installed (v18 or later)
- Node.js installed (v20 or later)
- 30 minutes of focused time
- We'll use TodoMVC (<https://todomvc.com/examples/react/dist/>) as our demo app
- We'll use TodoMVC (<https://todomvc.com/examples/react/>) as our demo app
:::
:::tip[Quick Path]
Load TEA (`*tea`) → scaffold framework (`*framework`) → create test plan (`*test-design`) → generate tests (`*automate`) → run with `npx playwright test`.
:::
## TEA Approaches Explained
Before we start, understand the three ways to use TEA:

View File

@ -2,6 +2,7 @@ const path = require('node:path');
const fs = require('fs-extra');
const yaml = require('yaml');
const chalk = require('chalk');
const ora = require('ora');
const { XmlHandler } = require('../../../lib/xml-handler');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
const { filterCustomizationData } = require('../../../lib/agent/compiler');
@ -414,27 +415,48 @@ class ModuleManager {
// Create cache directory if it doesn't exist
await fs.ensureDir(cacheDir);
// Track if we need to install dependencies
let needsDependencyInstall = false;
let wasNewClone = false;
// Check if already cloned
if (await fs.pathExists(moduleCacheDir)) {
// Try to update if it's a git repo
const updateSpinner = ora(`Updating ${moduleInfo.name} from remote repository...`).start();
try {
const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
execSync('git fetch --depth 1', { cwd: moduleCacheDir, stdio: 'pipe' });
execSync('git checkout -f', { cwd: moduleCacheDir, stdio: 'pipe' });
execSync('git pull --ff-only', { cwd: moduleCacheDir, stdio: 'pipe' });
const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
if (currentRef === newRef) {
updateSpinner.succeed(`${moduleInfo.name} is already up to date`);
} else {
updateSpinner.succeed(`Updated ${moduleInfo.name} to latest version`);
// Force dependency install since we got new code
needsDependencyInstall = true;
}
} catch {
updateSpinner.warn(`Update failed, re-downloading ${moduleInfo.name}`);
// If update fails, remove and re-clone
await fs.remove(moduleCacheDir);
wasNewClone = true;
}
} else {
wasNewClone = true;
}
// Clone if not exists or was removed
if (!(await fs.pathExists(moduleCacheDir))) {
console.log(chalk.dim(` Cloning external module: ${moduleInfo.name}`));
if (wasNewClone) {
const cloneSpinner = ora(`Downloading ${moduleInfo.name} from remote repository...`).start();
try {
execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, {
stdio: 'pipe',
});
cloneSpinner.succeed(`Downloaded ${moduleInfo.name}`);
} catch (error) {
cloneSpinner.fail(`Failed to download ${moduleInfo.name}`);
throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`);
}
}
@ -444,11 +466,25 @@ class ModuleManager {
const nodeModulesPath = path.join(moduleCacheDir, 'node_modules');
if (await fs.pathExists(packageJsonPath)) {
// Install if node_modules doesn't exist, or if package.json is newer (dependencies changed)
const needsInstall = !(await fs.pathExists(nodeModulesPath));
let packageJsonNewer = false;
const nodeModulesMissing = !(await fs.pathExists(nodeModulesPath));
if (!needsInstall) {
// Force install if we updated or cloned new
if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
try {
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
cwd: moduleCacheDir,
stdio: 'pipe',
timeout: 120_000, // 2 minute timeout
});
installSpinner.succeed(`Installed dependencies for ${moduleInfo.name}`);
} catch (error) {
installSpinner.warn(`Failed to install dependencies for ${moduleInfo.name}`);
console.warn(chalk.yellow(` Warning: ${error.message}`));
}
} else {
// Check if package.json is newer than node_modules
let packageJsonNewer = false;
try {
const packageStats = await fs.stat(packageJsonPath);
const nodeModulesStats = await fs.stat(nodeModulesPath);
@ -457,18 +493,20 @@ class ModuleManager {
// If stat fails, assume we need to install
packageJsonNewer = true;
}
}
if (needsInstall || packageJsonNewer) {
console.log(chalk.dim(` Installing dependencies for ${moduleInfo.name}...`));
if (packageJsonNewer) {
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
try {
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
cwd: moduleCacheDir,
stdio: 'inherit',
stdio: 'pipe',
timeout: 120_000, // 2 minute timeout
});
installSpinner.succeed(`Installed dependencies for ${moduleInfo.name}`);
} catch (error) {
console.warn(chalk.yellow(` Warning: Failed to install dependencies for ${moduleInfo.name}: ${error.message}`));
installSpinner.warn(`Failed to install dependencies for ${moduleInfo.name}`);
console.warn(chalk.yellow(` Warning: ${error.message}`));
}
}
}
}

View File

@ -38,8 +38,10 @@ export default defineConfig({
tagline: 'AI-driven agile development with specialized agents and workflows that scale from bug fixes to enterprise platforms.',
logo: {
src: './public/img/logo.svg',
alt: 'BMAD Logo',
light: './public/img/bmad-light.png',
dark: './public/img/bmad-dark.png',
alt: 'BMAD Method',
replacesTitle: true,
},
favicon: '/favicon.ico',

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -222,6 +222,8 @@ header.header .header.sl-flex {
.site-title {
font-weight: 700;
margin-left: 0;
padding-left: 0;
}
/* Logo sizing - constrain to reasonable size */
@ -470,14 +472,14 @@ footer {
/* Responsive padding on navbar row only - banner stays full-width */
@media (min-width: 50rem) {
header.header .header.sl-flex {
padding-left: 2.5rem;
padding-left: 1rem;
padding-right: 2.5rem;
}
}
@media (min-width: 72rem) {
header.header .header.sl-flex {
padding-left: 3rem;
padding-left: 1rem;
padding-right: 3rem;
}
}