installer functional

This commit is contained in:
Brian Madison
2025-06-12 22:38:24 -05:00
parent bf09224e05
commit 8916211ba9
39 changed files with 1769 additions and 419 deletions

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ Thumbs.db
CLAUDE.md
.ai/*
test-project-install/*

View File

@@ -1,6 +0,0 @@
{
"recommendations": [
"davidanson.vscode-markdownlint",
"streetsidesoftware.code-spell-checker"
]
}

40
.vscode/settings.json vendored
View File

@@ -1,40 +0,0 @@
{
"cSpell.words": [
"agentic",
"Axios",
"BMAD",
"Centricity",
"dataclass",
"docstrings",
"emergently",
"explorative",
"frontends",
"golint",
"Goroutines",
"HSTS",
"httpx",
"Immer",
"implementability",
"Inclusivity",
"Luxon",
"pasteable",
"Pino",
"Polyrepo",
"Pydantic",
"pyproject",
"rescope",
"roadmaps",
"roleplay",
"runbooks",
"Serilog",
"shadcn",
"structlog",
"Systemization",
"taskroot",
"Testcontainers",
"tmpl",
"VARCHAR",
"venv",
"WCAG"
]
}

View File

@@ -1,110 +0,0 @@
# Role: BMAD Master Orchestrator IDE Agent
## File References
`taskroot`: `bmad-core/tasks/`
`templates`: `bmad-core/templates/`
`checklists`: `bmad-core/checklists/`
`ide-agents`: `bmad-core/ide-agents/`
`agents`: `bmad-core/agents/`
`personas`: `bmad-core/personas/`
`workflows`: `bmad-core/workflows/`
`knowledge-base`: `bmad-core/data/bmad-kb.md`
`create-doc`: `taskroot/create-doc`
## Persona
- **Name:** BMad
- **Role:** Master Orchestrator & Technical Expert
- **Identity:** The unified interface to all BMAD-METHOD capabilities, able to dynamically transform into any specialized agent or execute any task
- **Focus:** Orchestrating the right agent or capability for each user need, maintaining efficiency by loading resources only when needed
- **Style:** Helpful, encouraging, technically brilliant yet approachable. Breaks down complex topics while maintaining professional friendliness
## Core Principles (Always Active)
- **Dynamic Transformation:** Can become any IDE agent or full agent (with persona) on demand, loading files only when needed
- **Efficient Resource Management:** Never pre-load agents, templates, or knowledge base - discover and load at runtime
- **Intelligent Routing:** Assess user needs and recommend the best approach, agent, or workflow
- **Runtime Discovery:** Dynamically discover available resources (agents, templates, tasks) from file system when needed
- **Context Awareness:** Track current state and guide users to next logical steps
- **Numbered Options Protocol:** When presenting multiple options, always use numbered lists for easy selection
- **Lazy Loading:** Only load the knowledge base when explicitly requested via \*kb-mode command
## Critical Startup Operating Instructions
1. Announce your name and role: "Hey! I'm BMad, your BMAD-METHOD orchestrator. I can become any specialized agent or help you with any BMAD task. You can type `*help` at any time to see available options."
2. Assess what the user wants to accomplish
3. If request matches a specific agent's expertise, suggest becoming that agent
4. If request is generic, offer numbered options or execute directly
5. Only load specific resources (agents, templates, KB) when actually needed
## Commands
### Core Commands
- `*help` - Show these available commands as a numbered list offering selection
- `*chat-mode` - Enter conversational mode, staying in character while offering `taskroot/advanced-elicitation` when providing advice or multiple options. Ends if other task or command is given
- `*kb-mode` - Load knowledge base and enter full BMAD-METHOD help mode
- `*status` - Show current context, active agent (if any), and progress
### Agent Management
- `*ide-agent {name/role}` - Transform into specified IDE agent (fuzzy match supported)
- `*agent {name/role}` - Load full agent with persona (uses more context)
- `*agent-exit` - Return to BMAD orchestrator mode
- `*list-agents` - Show available IDE agents and agents (Name and Role) for numbered list choice selection
### Dynamic Task Execution
- `*create {template}` - Create document using specified template with `create-doc` task (fuzzy match)
- `*run {checklist}` - Execute specified checklist validation with `taskroot/execute-checklist`
- `*task {task-name}` - Run any task from taskroot (fuzzy match), if none specified, offer numbered list of tasks from `taskroot`
- `*workflow {type}` - Start specified workflow or list available workflows for selection
### Discovery Commands
- `*list-templates` - Discover and show numbered list of available templates for selection to create
- `*list-tasks` - Discover and show numbered list of available tasks for selection to execute
- `*list-checklists` - Discover and show numbered list of available checklists for selection to run
- `*list-workflows` - Discover and show numbered list of available workflows for selection to activate
## Agent Transformation Protocol
When user requests agent transformation:
1. Fuzzy match the requested name/role against available agents
2. For IDE agents: Load the `ide-agents` file and fully become that agent
3. For full agents: Load both the `agents` file and any references files in the agent such as `personas`, merge capabilities
4. Announce the transformation clearly
5. Operate as that agent until \*agent-exit command
## Runtime Discovery Protocol
Instead of hard-coding lists, generate lists from folders when requested and user asked or was not specific.
Use Fuzzy Matching with 85% confidence. If unsure offer the list of whats in a folder. Examples of fuzzy matching:
- "create prd" → matches "prd-tmpl.md"
- "become architect" → matches "architect.ide.md"
- "run po checklist" → matches "po-master-checklist.md"
## Knowledge Base Protocol
The knowledge base is only loaded when:
1. User explicitly runs \*kb-mode command
2. User asks detailed questions about BMAD methodology when in chat mode
3. User requests comprehensive help beyond basic commands that is not clear already or embedded in a workflow
This keeps context usage minimal for normal operations. ALWAYS indicate KB has been loaded if loaded.
## Workflow Guidance
When user needs guidance:
1. Ask about project type (greenfield/brownfield)
2. Ask about scope (UI/service/fullstack)
3. Recommend appropriate workflow
4. Guide through workflow stages with appropriate agents
Remember: As BMAD orchestrator, you have access to ALL capabilities but load them intelligently based on user needs. Always provide clear next steps and maintain efficiency by loading only what's needed.

View File

@@ -1,25 +0,0 @@
# /exit-persona
## Description
Returns Claude to default assistant mode, exiting any active IDE agent persona.
**Usage:** `/exit-agent`
## Behavior
- Immediately exits the current agent persona if one is active
- Returns to standard Claude Code assistant capabilities
- Clears any agent-specific context or workflows
- Confirms the exit to the user
## Example
```text
User: /exit-agent
Claude: Exited IDE agent mode. I'm now back to my standard Claude Code assistant capabilities.
```
## Related Commands
- `/ide-agent` - Switch to a specific IDE agent persona

View File

@@ -1,25 +0,0 @@
# /ide-agent
## Description
Switches Claude to embody a specific IDE agent persona from the BMAD-METHOD framework.
**Usage:** `/ide-agent <agent-name>` or `/ide-agent` (to list available agents)
**Instructions:**
IMPORTANT: When an agent name is provided (e.g., `/ide-agent pm`):
1. IMMEDIATELY read the file at `bmad-core/ide-agents/{agent-name}.ide.md`
2. DO NOT search for related files or use the Task tool
3. Start operating as that agent persona right away
For complete behavior details, see `bmad-core/utils/agent-switcher.ide.md`.
## Related Commands
### /exit-agent
Returns Claude to default assistant mode, exiting any active IDE agent persona.
**Usage:** `/exit-agent` or `/exit`

View File

@@ -1,17 +0,0 @@
---
description:
globs:
alwaysApply: true
---
# IDE Agent Slash Commands
## Slash Commands
### `/ide-agent` or `/ide-agent <agent-name>`
When the user types `/ide-agent` or `/ide-agent <agent-name>`, read and follow the complete instructions in `bmad-core/utils/agent-switcher.ide.md`.
### `/exit-agent`, `/exit-persona`, or `/exit`
When the user types any of these exit commands, follow the "Exiting Agent Mode" instructions in `bmad-core/utils/agent-switcher.ide.md`.

View File

@@ -1,7 +0,0 @@
# IDE Agent Slash Commands
## Commands
When the user types at the start of a line `ide-agent` or `ide-agent <agent-name>`, read and follow the complete instructions in `bmad-core/utils/agent-switcher.ide.md`.
When the user types at the start of a line `exit-agent`, follow the "Exiting Agent Mode" instructions in `bmad-core/utils/agent-switcher.ide.md`.

View File

@@ -1,129 +0,0 @@
# BMAD Method Installation Configuration
# This file defines what files are included in each installation profile
installation-profiles:
minimal:
name: "IDE Agents Only"
description: "Minimal setup for IDE usage (recommended for beginners)"
files:
- "bmad-core/ide-agents/*.ide.md"
- "bmad-core/utils/agent-switcher.ide.md"
- "bmad-core/data/bmad-kb.md"
- "bmad-core/data/technical-preferences.md"
- "bmad-core/utils/template-format.md"
core:
extends: minimal
name: "IDE + Web Agents"
description: "Includes web agent configurations for building web-compatible bundles"
files:
- "bmad-core/agents/*.yml"
- "bmad-core/templates/web-agent-startup-instructions-template.md"
teams:
extends: core
name: "Teams & Workflows"
description: "Full team collaboration setup with pre-configured workflows"
files:
- "bmad-core/agent-teams/*.yml"
- "bmad-core/workflows/*.yml"
- "bmad-core/utils/workflow-management.md"
developer:
extends: teams
name: "Full Developer Kit"
description: "Everything including agent creation tools and schemas"
files:
- "bmad-core/tasks/create-*.md"
- "bmad-core/schemas/*.yml"
- "bmad-core/tasks/shard-doc.md"
- "bmad-core/tasks/index-docs.md"
# IDE-specific configuration for generating rules/commands
ide-configurations:
cursor:
name: "Cursor"
rule-file: ".cursorrules"
format: "single-file"
command-prefix: ""
instructions: |
# To use BMAD agents in Cursor:
# 1. Press Ctrl+L (Cmd+L on Mac) to open the chat
# 2. Type the agent name (e.g., "dev", "pm", "architect")
# 3. The agent will adopt that persona for the conversation
claude-code:
name: "Claude Code"
rule-dir: ".claude/commands/"
format: "multi-file"
command-suffix: ".md"
instructions: |
# To use BMAD agents in Claude Code:
# 1. Type /agent-name (e.g., "/dev", "/pm", "/architect")
# 2. Claude will switch to that agent's persona
windsurf:
name: "Windsurf"
rule-dir: ".windsurf/rules/"
format: "single-file"
rule-file: "bmad-agents.md"
instructions: |
# To use BMAD agents in Windsurf:
# 1. Type /agent-name (e.g., "/dev", "/pm")
# 2. Windsurf will adopt that agent's persona
roo:
name: "Roo"
# Configuration TBD - needs research
format: "unknown"
instructions: |
# Roo configuration coming soon
# Manual setup: Copy IDE agent files to your Roo configuration
cline:
name: "Cline"
# Configuration TBD - needs research
format: "unknown"
instructions: |
# Cline configuration coming soon
# Manual setup: Copy IDE agent files to your Cline configuration
# Web agent export configuration
web-agents:
source-dir: "web-build"
available-agents:
- name: "analyst"
file: "analyst.md"
description: "Business Analyst agent for requirements gathering"
- name: "pm"
file: "pm.md"
description: "Product Manager agent for product strategy"
- name: "architect"
file: "architect.md"
description: "Solution Architect agent for technical design"
- name: "po"
file: "po.md"
description: "Product Owner agent for backlog management"
- name: "sm"
file: "sm.md"
description: "Scrum Master agent for Agile processes"
- name: "dev"
file: "dev.md"
description: "Developer agent for implementation"
- name: "qa"
file: "qa.md"
description: "QA Engineer agent for testing"
- name: "ux"
file: "ux-expert.md"
description: "UX Expert agent for user experience"
teams:
- name: "fullstack"
file: "team-fullstack.md"
description: "Full-stack development team"
- name: "no-ui"
file: "team-no-ui.md"
description: "Backend/service development team"
- name: "all"
file: "team-all.md"
description: "Complete Agile team with all roles"

View File

@@ -1,50 +0,0 @@
{
"name": "bmad-method",
"version": "4.0.0",
"description": "BMAD Method installer - Easy setup for AI-powered Agile development agents",
"bin": {
"bmad": "./bin/bmad.js"
},
"main": "lib/installer.js",
"scripts": {
"test": "jest",
"lint": "eslint lib/**/*.js bin/**/*.js"
},
"keywords": [
"bmad",
"agile",
"ai",
"agents",
"development",
"methodology",
"installer"
],
"author": "Brian (BMad) Madison",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/your-org/bmad-method.git"
},
"engines": {
"node": ">=14.0.0"
},
"dependencies": {
"chalk": "^4.1.2",
"commander": "^9.4.1",
"fs-extra": "^11.1.0",
"glob": "^8.0.3",
"inquirer": "^8.2.5",
"js-yaml": "^4.1.0",
"ora": "^5.4.1"
},
"devDependencies": {
"eslint": "^8.0.0",
"jest": "^29.5.0"
},
"files": [
"bin/",
"lib/",
"config/",
"templates/"
]
}

3
package-lock.json generated
View File

@@ -12,9 +12,6 @@
"commander": "^9.4.1",
"js-yaml": "^4.1.0"
},
"bin": {
"bmad-build": "tools/cli.js"
},
"devDependencies": {
"jest": "^29.5.0"
},

View File

@@ -6,11 +6,11 @@
"bin": {},
"scripts": {
"build": "node tools/cli.js build",
"install": "node tools/installer/bin/bmad.js install",
"build:agents": "node tools/cli.js build --agents-only",
"build:teams": "node tools/cli.js build --teams-only",
"list:agents": "node tools/cli.js list:agents",
"validate": "node tools/cli.js validate",
"analyze:deps": "echo 'Dependency analysis not yet implemented'"
"validate": "node tools/cli.js validate"
},
"dependencies": {
"commander": "^9.4.1",

View File

@@ -7,7 +7,7 @@ class WebBuilder {
this.rootDir = options.rootDir || process.cwd();
this.outputDirs = options.outputDirs || [
path.join(this.rootDir, 'dist'),
path.join(this.rootDir, 'web-build')
path.join(this.rootDir, 'bmad-core', 'web-bundles')
];
this.resolver = new DependencyResolver(this.rootDir);
this.templatePath = path.join(this.rootDir, 'bmad-core', 'templates', 'web-agent-startup-instructions-template.md');

View File

@@ -48,9 +48,9 @@ program
program
.command('list:agents')
.description('List all available agents')
.action(() => {
.action(async () => {
const builder = new WebBuilder({ rootDir: process.cwd() });
const agents = builder.listAgents();
const agents = await builder.resolver.listAgents();
console.log('Available agents:');
agents.forEach(agent => console.log(` - ${agent}`));
});
@@ -61,8 +61,23 @@ program
.action(async () => {
const builder = new WebBuilder({ rootDir: process.cwd() });
try {
await builder.validate();
console.log('All configurations are valid!');
// Validate by attempting to build all agents and teams
const agents = await builder.resolver.listAgents();
const teams = await builder.resolver.listTeams();
console.log('Validating agents...');
for (const agent of agents) {
await builder.resolver.resolveAgentDependencies(agent);
console.log(`${agent}`);
}
console.log('\nValidating teams...');
for (const team of teams) {
await builder.resolver.resolveTeamDependencies(team);
console.log(`${team}`);
}
console.log('\nAll configurations are valid!');
} catch (error) {
console.error('Validation failed:', error.message);
process.exit(1);

158
tools/installer/bin/bmad.js Executable file
View File

@@ -0,0 +1,158 @@
#!/usr/bin/env node
const { program } = require('commander');
const inquirer = require('inquirer');
const chalk = require('chalk');
const path = require('path');
const { version } = require('../package.json');
const installer = require('../lib/installer');
program
.version(version)
.description('BMAD Method installer - AI-powered Agile development framework');
program
.command('install')
.description('Install BMAD Method agents and tools')
.option('-f, --full', 'Install complete bmad-core folder')
.option('-a, --agent <agent>', 'Install specific agent with dependencies')
.option('-d, --directory <path>', 'Installation directory (default: ./bmad-core)')
.option('-i, --ide <ide>', 'Configure for specific IDE (cursor, claude-code, windsurf)')
.action(async (options) => {
try {
if (!options.full && !options.agent) {
// Interactive mode
const answers = await promptInstallation(options);
await installer.install(answers);
} else {
// Direct mode
const config = {
installType: options.full ? 'full' : 'single-agent',
agent: options.agent,
directory: options.directory || './bmad-core',
ide: options.ide
};
await installer.install(config);
}
} catch (error) {
console.error(chalk.red('Installation failed:'), error.message);
process.exit(1);
}
});
program
.command('update')
.description('Update existing BMAD installation')
.option('--force', 'Force update, overwriting modified files')
.option('--dry-run', 'Show what would be updated without making changes')
.action(async (options) => {
try {
await installer.update(options);
} catch (error) {
console.error(chalk.red('Update failed:'), error.message);
process.exit(1);
}
});
program
.command('list')
.description('List available agents')
.action(async () => {
try {
await installer.listAgents();
} catch (error) {
console.error(chalk.red('Error:'), error.message);
process.exit(1);
}
});
program
.command('status')
.description('Show installation status')
.action(async () => {
try {
await installer.showStatus();
} catch (error) {
console.error(chalk.red('Error:'), error.message);
process.exit(1);
}
});
async function promptInstallation(options) {
console.log(chalk.bold.blue(`\nWelcome to BMAD Method Installer v${version}\n`));
const answers = {};
// Ask for installation directory
const { directory } = await inquirer.prompt([
{
type: 'input',
name: 'directory',
message: 'Where would you like to install BMAD?',
default: './bmad-core'
}
]);
answers.directory = directory;
// Ask for installation type
const { installType } = await inquirer.prompt([
{
type: 'list',
name: 'installType',
message: 'How would you like to install BMAD?',
choices: [
{
name: 'Complete installation (recommended) - All agents and tools',
value: 'full'
},
{
name: 'Single agent - Choose one agent to install',
value: 'single-agent'
}
]
}
]);
answers.installType = installType;
// If single agent, ask which one
if (installType === 'single-agent') {
const agents = await installer.getAvailableAgents();
const { agent } = await inquirer.prompt([
{
type: 'list',
name: 'agent',
message: 'Select an agent to install:',
choices: agents.map(a => ({
name: `${a.id} - ${a.name} (${a.description})`,
value: a.id
}))
}
]);
answers.agent = agent;
}
// Ask for IDE configuration
const { ide } = await inquirer.prompt([
{
type: 'list',
name: 'ide',
message: 'Which IDE are you using?',
choices: [
{ name: 'Cursor', value: 'cursor' },
{ name: 'Claude Code', value: 'claude-code' },
{ name: 'Windsurf', value: 'windsurf' },
{ name: 'Other/Manual setup', value: null }
]
}
]);
answers.ide = ide;
return answers;
}
program.parse(process.argv);
// Show help if no command provided
if (!process.argv.slice(2).length) {
program.outputHelp();
}

View File

@@ -0,0 +1,167 @@
# BMAD Method Installation Configuration
# Simplified installer with two options: full copy or single agent
installation-options:
full:
name: "Complete BMAD Core"
description: "Copy the entire bmad-core folder with all agents, templates, and tools"
action: "copy-folder"
source: "bmad-core"
single-agent:
name: "Single Agent"
description: "Select and install a single agent with its dependencies"
action: "copy-agent"
# Agent dependency mappings
# These are the core files that should be included with any single agent installation
agent-dependencies:
core-files:
- "bmad-core/data/bmad-kb.md"
- "bmad-core/data/technical-preferences.md"
- "bmad-core/utils/template-format.md"
# Agent-specific dependencies (parsed from agent files or explicitly defined)
dev:
- "bmad-core/templates/story-tmpl.md"
- "bmad-core/checklists/story-dod-checklist.md"
pm:
- "bmad-core/templates/prd-tmpl.md"
- "bmad-core/checklists/pm-checklist.md"
- "bmad-core/tasks/advanced-elicitation.md"
architect:
- "bmad-core/templates/architecture-tmpl.md"
- "bmad-core/checklists/architect-checklist.md"
sm:
- "bmad-core/templates/story-tmpl.md"
- "bmad-core/checklists/story-draft-checklist.md"
- "bmad-core/workflows/*.yml"
po:
- "bmad-core/checklists/po-master-checklist.md"
- "bmad-core/templates/acceptance-criteria-tmpl.md"
analyst:
- "bmad-core/templates/prd-tmpl.md"
- "bmad-core/tasks/advanced-elicitation.md"
qa:
- "bmad-core/checklists/story-dod-checklist.md"
- "bmad-core/templates/test-plan-tmpl.md"
ux-expert:
- "bmad-core/templates/ux-tmpl.md"
# Meta agents typically need access to more resources
bmad-master:
- "bmad-core/templates/*.md"
- "bmad-core/tasks/*.md"
- "bmad-core/schemas/*.yml"
bmad-orchestrator:
- "bmad-core/agent-teams/*.yml"
- "bmad-core/workflows/*.yml"
# IDE-specific configuration for generating rules/commands
ide-configurations:
cursor:
name: "Cursor"
rule-dir: ".cursor/rules/"
format: "multi-file"
command-suffix: ".mdc"
instructions: |
# To use BMAD agents in Cursor:
# 1. Press Ctrl+L (Cmd+L on Mac) to open the chat
# 2. Type @agent-name (e.g., "@dev", "@pm", "@architect")
# 3. The agent will adopt that persona for the conversation
claude-code:
name: "Claude Code"
rule-dir: ".claude/commands/"
format: "multi-file"
command-suffix: ".md"
instructions: |
# To use BMAD agents in Claude Code:
# 1. Type /agent-name (e.g., "/dev", "/pm", "/architect")
# 2. Claude will switch to that agent's persona
windsurf:
name: "Windsurf"
rule-dir: ".windsurf/rules/"
format: "multi-file"
command-suffix: ".md"
instructions: |
# To use BMAD agents in Windsurf:
# 1. Type @agent-name (e.g., "@dev", "@pm")
# 2. Windsurf will adopt that agent's persona
roo:
name: "Roo"
# Configuration TBD - needs research
format: "unknown"
instructions: |
# Roo configuration coming soon
# Manual setup: Copy IDE agent files to your Roo configuration
cline:
name: "Cline"
# Configuration TBD - needs research
format: "unknown"
instructions: |
# Cline configuration coming soon
# Manual setup: Copy IDE agent files to your Cline configuration
# Available agents for single-agent installation
available-agents:
- id: "analyst"
name: "Business Analyst"
file: "bmad-core/agents/analyst.md"
description: "Requirements gathering and analysis"
- id: "pm"
name: "Product Manager"
file: "bmad-core/agents/pm.md"
description: "Product strategy and roadmap planning"
- id: "architect"
name: "Solution Architect"
file: "bmad-core/agents/architect.md"
description: "Technical design and architecture"
- id: "po"
name: "Product Owner"
file: "bmad-core/agents/po.md"
description: "Backlog management and prioritization"
- id: "sm"
name: "Scrum Master"
file: "bmad-core/agents/sm.md"
description: "Agile process and story creation"
- id: "dev"
name: "Developer"
file: "bmad-core/agents/dev.md"
description: "Code implementation and testing"
- id: "qa"
name: "QA Engineer"
file: "bmad-core/agents/qa.md"
description: "Quality assurance and testing"
- id: "ux-expert"
name: "UX Expert"
file: "bmad-core/agents/ux-expert.md"
description: "User experience design"
- id: "bmad-master"
name: "BMAD Master"
file: "bmad-core/agents/bmad-master.md"
description: "BMAD framework expert and guide"
- id: "bmad-orchestrator"
name: "BMAD Orchestrator"
file: "bmad-core/agents/bmad-orchestrator.md"
description: "Multi-agent workflow coordinator"

View File

@@ -0,0 +1,62 @@
const fs = require('fs-extra');
const path = require('path');
const yaml = require('js-yaml');
class ConfigLoader {
constructor() {
this.configPath = path.join(__dirname, '..', 'config', 'install.config.yml');
this.config = null;
}
async load() {
if (this.config) return this.config;
try {
const configContent = await fs.readFile(this.configPath, 'utf8');
this.config = yaml.load(configContent);
return this.config;
} catch (error) {
throw new Error(`Failed to load configuration: ${error.message}`);
}
}
async getInstallationOptions() {
const config = await this.load();
return config['installation-options'] || {};
}
async getAvailableAgents() {
const config = await this.load();
return config['available-agents'] || [];
}
async getAgentDependencies(agentId) {
const config = await this.load();
const dependencies = config['agent-dependencies'] || {};
// Always include core files
const coreFiles = dependencies['core-files'] || [];
// Add agent-specific dependencies
const agentDeps = dependencies[agentId] || [];
return [...coreFiles, ...agentDeps];
}
async getIdeConfiguration(ide) {
const config = await this.load();
const ideConfigs = config['ide-configurations'] || {};
return ideConfigs[ide] || null;
}
getBmadCorePath() {
// Get the path to bmad-core relative to the installer (now under tools)
return path.join(__dirname, '..', '..', '..', 'bmad-core');
}
getAgentPath(agentId) {
return path.join(this.getBmadCorePath(), 'agents', `${agentId}.md`);
}
}
module.exports = new ConfigLoader();

View File

@@ -0,0 +1,154 @@
const fs = require('fs-extra');
const path = require('path');
const crypto = require('crypto');
const glob = require('glob');
const chalk = require('chalk');
class FileManager {
constructor() {
this.manifestDir = '.bmad';
this.manifestFile = 'install-manifest.yml';
}
async copyFile(source, destination) {
try {
await fs.ensureDir(path.dirname(destination));
await fs.copy(source, destination);
return true;
} catch (error) {
console.error(chalk.red(`Failed to copy ${source}:`), error.message);
return false;
}
}
async copyDirectory(source, destination) {
try {
await fs.ensureDir(destination);
await fs.copy(source, destination);
return true;
} catch (error) {
console.error(chalk.red(`Failed to copy directory ${source}:`), error.message);
return false;
}
}
async copyGlobPattern(pattern, sourceDir, destDir) {
const files = glob.sync(pattern, { cwd: sourceDir });
const copied = [];
for (const file of files) {
const sourcePath = path.join(sourceDir, file);
const destPath = path.join(destDir, file);
if (await this.copyFile(sourcePath, destPath)) {
copied.push(file);
}
}
return copied;
}
async calculateFileHash(filePath) {
try {
const content = await fs.readFile(filePath);
return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
} catch (error) {
return null;
}
}
async createManifest(installDir, config, files) {
const manifestPath = path.join(installDir, this.manifestDir, this.manifestFile);
const manifest = {
version: require('../package.json').version,
installed_at: new Date().toISOString(),
install_type: config.installType,
agent: config.agent || null,
ide_setup: config.ide || null,
files: []
};
// Add file information
for (const file of files) {
const filePath = path.join(installDir, file);
const hash = await this.calculateFileHash(filePath);
manifest.files.push({
path: file,
hash: hash,
modified: false
});
}
// Write manifest
await fs.ensureDir(path.dirname(manifestPath));
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
return manifest;
}
async readManifest(installDir) {
const manifestPath = path.join(installDir, this.manifestDir, this.manifestFile);
try {
const content = await fs.readFile(manifestPath, 'utf8');
return JSON.parse(content);
} catch (error) {
return null;
}
}
async checkModifiedFiles(installDir, manifest) {
const modified = [];
for (const file of manifest.files) {
const filePath = path.join(installDir, file.path);
const currentHash = await this.calculateFileHash(filePath);
if (currentHash && currentHash !== file.hash) {
modified.push(file.path);
}
}
return modified;
}
async backupFile(filePath) {
const backupPath = filePath + '.bak';
let counter = 1;
let finalBackupPath = backupPath;
// Find a unique backup filename
while (await fs.pathExists(finalBackupPath)) {
finalBackupPath = `${filePath}.bak${counter}`;
counter++;
}
await fs.copy(filePath, finalBackupPath);
return finalBackupPath;
}
async ensureDirectory(dirPath) {
await fs.ensureDir(dirPath);
}
async pathExists(filePath) {
return fs.pathExists(filePath);
}
async readFile(filePath) {
return fs.readFile(filePath, 'utf8');
}
async writeFile(filePath, content) {
await fs.ensureDir(path.dirname(filePath));
await fs.writeFile(filePath, content);
}
async removeDirectory(dirPath) {
await fs.remove(dirPath);
}
}
module.exports = new FileManager();

View File

@@ -0,0 +1,189 @@
const path = require('path');
const fileManager = require('./file-manager');
const configLoader = require('./config-loader');
const chalk = require('chalk');
class IdeSetup {
async setup(ide, installDir, selectedAgent = null) {
const ideConfig = await configLoader.getIdeConfiguration(ide);
if (!ideConfig) {
console.log(chalk.yellow(`\nNo configuration available for ${ide}`));
return false;
}
switch (ide) {
case 'cursor':
return this.setupCursor(installDir, selectedAgent);
case 'claude-code':
return this.setupClaudeCode(installDir, selectedAgent);
case 'windsurf':
return this.setupWindsurf(installDir, selectedAgent);
default:
console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
return false;
}
}
async setupCursor(installDir, selectedAgent) {
const cursorRulesDir = path.join(installDir, '.cursor', 'rules');
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
await fileManager.ensureDirectory(cursorRulesDir);
for (const agentId of agents) {
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
let agentPath = path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`);
if (!await fileManager.pathExists(agentPath)) {
agentPath = path.join(installDir, 'agents', `${agentId}.md`);
}
if (await fileManager.pathExists(agentPath)) {
const agentContent = await fileManager.readFile(agentPath);
const mdcPath = path.join(cursorRulesDir, `${agentId}.mdc`);
// Create MDC content with proper format
let mdcContent = '\n---\n';
mdcContent += 'description: \n';
mdcContent += 'globs: []\n';
mdcContent += 'alwaysApply: false\n';
mdcContent += '---\n\n';
mdcContent += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
mdcContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(agentId)} agent persona.\n\n`;
mdcContent += '## Agent Activation\n\n';
mdcContent += 'CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
mdcContent += '```yml\n';
// Extract just the YAML content from the agent file
const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
if (yamlMatch) {
mdcContent += yamlMatch[1].trim();
} else {
// If no YAML found, include the whole content minus the header
mdcContent += agentContent.replace(/^#.*$/m, '').trim();
}
mdcContent += '\n```\n\n';
mdcContent += '## File Reference\n\n';
mdcContent += `The complete agent definition is available in [bmad-core/agents/${agentId}.md](mdc:bmad-core/agents/${agentId}.md).\n\n`;
mdcContent += '## Usage\n\n';
mdcContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(agentId)} persona and follow all instructions defined in the YML configuration above.\n`;
await fileManager.writeFile(mdcPath, mdcContent);
console.log(chalk.green(`✓ Created rule: ${agentId}.mdc`));
}
}
console.log(chalk.green(`\n✓ Created Cursor rules in ${cursorRulesDir}`));
return true;
}
async setupClaudeCode(installDir, selectedAgent) {
const commandsDir = path.join(installDir, '.claude', 'commands');
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
await fileManager.ensureDirectory(commandsDir);
for (const agentId of agents) {
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
let agentPath = path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`);
if (!await fileManager.pathExists(agentPath)) {
agentPath = path.join(installDir, 'agents', `${agentId}.md`);
}
const commandPath = path.join(commandsDir, `${agentId}.md`);
if (await fileManager.pathExists(agentPath)) {
// Create command file with agent content
const agentContent = await fileManager.readFile(agentPath);
// Add command header
let commandContent = `# /${agentId} Command\n\n`;
commandContent += `When this command is used, adopt the following agent persona:\n\n`;
commandContent += agentContent;
await fileManager.writeFile(commandPath, commandContent);
console.log(chalk.green(`✓ Created command: /${agentId}`));
}
}
console.log(chalk.green(`\n✓ Created Claude Code commands in ${commandsDir}`));
return true;
}
async setupWindsurf(installDir, selectedAgent) {
const windsurfRulesDir = path.join(installDir, '.windsurf', 'rules');
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
await fileManager.ensureDirectory(windsurfRulesDir);
for (const agentId of agents) {
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
let agentPath = path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`);
if (!await fileManager.pathExists(agentPath)) {
agentPath = path.join(installDir, 'agents', `${agentId}.md`);
}
if (await fileManager.pathExists(agentPath)) {
const agentContent = await fileManager.readFile(agentPath);
const mdPath = path.join(windsurfRulesDir, `${agentId}.md`);
// Create MD content (similar to Cursor but without frontmatter)
let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(agentId)} agent persona.\n\n`;
mdContent += '## Agent Activation\n\n';
mdContent += 'CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
mdContent += '```yml\n';
// Extract just the YAML content from the agent file
const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
if (yamlMatch) {
mdContent += yamlMatch[1].trim();
} else {
// If no YAML found, include the whole content minus the header
mdContent += agentContent.replace(/^#.*$/m, '').trim();
}
mdContent += '\n```\n\n';
mdContent += '## File Reference\n\n';
mdContent += `The complete agent definition is available in [bmad-core/agents/${agentId}.md](bmad-core/agents/${agentId}.md).\n\n`;
mdContent += '## Usage\n\n';
mdContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(agentId)} persona and follow all instructions defined in the YML configuration above.\n`;
await fileManager.writeFile(mdPath, mdContent);
console.log(chalk.green(`✓ Created rule: ${agentId}.md`));
}
}
console.log(chalk.green(`\n✓ Created Windsurf rules in ${windsurfRulesDir}`));
return true;
}
async getAllAgentIds(installDir) {
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
let agentsDir = path.join(installDir, 'bmad-core', 'agents');
if (!await fileManager.pathExists(agentsDir)) {
agentsDir = path.join(installDir, 'agents');
}
const glob = require('glob');
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
return agentFiles.map(file => path.basename(file, '.md'));
}
getAgentTitle(agentId) {
const agentTitles = {
'analyst': 'Business Analyst',
'architect': 'Solution Architect',
'bmad-master': 'BMAD Master',
'bmad-orchestrator': 'BMAD Orchestrator',
'dev': 'Developer',
'pm': 'Product Manager',
'po': 'Product Owner',
'qa': 'QA Specialist',
'sm': 'Scrum Master',
'ux-expert': 'UX Expert'
};
return agentTitles[agentId] || agentId;
}
}
module.exports = new IdeSetup();

View File

@@ -0,0 +1,269 @@
const chalk = require('chalk');
const ora = require('ora');
const path = require('path');
const configLoader = require('./config-loader');
const fileManager = require('./file-manager');
const ideSetup = require('./ide-setup');
class Installer {
async install(config) {
const spinner = ora('Installing BMAD Method...').start();
try {
// Resolve installation directory
const installDir = path.resolve(config.directory);
// Check if directory already exists
if (await fileManager.pathExists(installDir)) {
const manifest = await fileManager.readManifest(installDir);
if (manifest) {
spinner.fail('BMAD is already installed in this directory');
console.log(chalk.yellow('\nUse "bmad update" to update the existing installation'));
return;
}
}
let files = [];
if (config.installType === 'full') {
// Full installation - copy entire bmad-core folder as a subdirectory
spinner.text = 'Copying complete bmad-core folder...';
const sourceDir = configLoader.getBmadCorePath();
const bmadCoreDestDir = path.join(installDir, 'bmad-core');
await fileManager.copyDirectory(sourceDir, bmadCoreDestDir);
// Get list of all files for manifest
const glob = require('glob');
files = glob.sync('**/*', {
cwd: bmadCoreDestDir,
nodir: true,
ignore: ['**/.git/**', '**/node_modules/**']
}).map(file => path.join('bmad-core', file));
} else if (config.installType === 'single-agent') {
// Single agent installation
spinner.text = `Installing ${config.agent} agent...`;
// Copy agent file
const agentPath = configLoader.getAgentPath(config.agent);
const destAgentPath = path.join(installDir, 'agents', `${config.agent}.md`);
await fileManager.copyFile(agentPath, destAgentPath);
files.push(`agents/${config.agent}.md`);
// Copy dependencies
const dependencies = await configLoader.getAgentDependencies(config.agent);
const sourceBase = configLoader.getBmadCorePath();
for (const dep of dependencies) {
spinner.text = `Copying dependency: ${dep}`;
if (dep.includes('*')) {
// Handle glob patterns
const copiedFiles = await fileManager.copyGlobPattern(
dep.replace('bmad-core/', ''),
sourceBase,
installDir
);
files.push(...copiedFiles);
} else {
// Handle single files
const sourcePath = path.join(sourceBase, dep.replace('bmad-core/', ''));
const destPath = path.join(installDir, dep.replace('bmad-core/', ''));
if (await fileManager.copyFile(sourcePath, destPath)) {
files.push(dep.replace('bmad-core/', ''));
}
}
}
}
// Set up IDE integration if requested
if (config.ide) {
spinner.text = `Setting up ${config.ide} integration...`;
// For full installations, IDE rules should be in the root install dir, not bmad-core
await ideSetup.setup(config.ide, installDir, config.agent);
}
// Create manifest
spinner.text = 'Creating installation manifest...';
await fileManager.createManifest(installDir, config, files);
spinner.succeed('Installation complete!');
// Show success message
console.log(chalk.green('\n✓ BMAD Method installed successfully!\n'));
if (config.ide) {
const ideConfig = await configLoader.getIdeConfiguration(config.ide);
if (ideConfig && ideConfig.instructions) {
console.log(chalk.bold('To use BMAD agents in ' + ideConfig.name + ':'));
console.log(ideConfig.instructions);
}
} else {
console.log(chalk.yellow('No IDE configuration was set up.'));
console.log('You can manually configure your IDE using the agent files in:', installDir);
}
if (config.installType === 'single-agent') {
console.log(chalk.dim('\nNeed other agents? Run: npx bmad-method install --agent=<name>'));
console.log(chalk.dim('Need everything? Run: npx bmad-method install --full'));
}
} catch (error) {
spinner.fail('Installation failed');
throw error;
}
}
async update(options) {
const spinner = ora('Checking for updates...').start();
try {
// Find existing installation
const installDir = await this.findInstallation();
if (!installDir) {
spinner.fail('No BMAD installation found');
return;
}
const manifest = await fileManager.readManifest(installDir);
if (!manifest) {
spinner.fail('Invalid installation - manifest not found');
return;
}
// Check for modified files
spinner.text = 'Checking for modified files...';
const modifiedFiles = await fileManager.checkModifiedFiles(installDir, manifest);
if (modifiedFiles.length > 0 && !options.force) {
spinner.warn('Found modified files');
console.log(chalk.yellow('\nThe following files have been modified:'));
modifiedFiles.forEach(file => console.log(` - ${file}`));
if (!options.dryRun) {
console.log(chalk.yellow('\nUse --force to overwrite modified files'));
console.log(chalk.yellow('or manually backup your changes first'));
}
return;
}
if (options.dryRun) {
spinner.info('Dry run - no changes will be made');
console.log('\nFiles that would be updated:');
manifest.files.forEach(file => console.log(` - ${file.path}`));
return;
}
// Perform update
spinner.text = 'Updating files...';
// Backup modified files if forcing
if (modifiedFiles.length > 0 && options.force) {
for (const file of modifiedFiles) {
const filePath = path.join(installDir, file);
const backupPath = await fileManager.backupFile(filePath);
console.log(chalk.dim(` Backed up: ${file}${path.basename(backupPath)}`));
}
}
// Re-run installation with same config
const config = {
installType: manifest.install_type,
agent: manifest.agent,
directory: installDir,
ide: manifest.ide_setup
};
await this.install(config);
} catch (error) {
spinner.fail('Update failed');
throw error;
}
}
async listAgents() {
const agents = await configLoader.getAvailableAgents();
console.log(chalk.bold('\nAvailable BMAD Agents:\n'));
agents.forEach(agent => {
console.log(chalk.cyan(` ${agent.id.padEnd(20)}`), agent.description);
});
console.log(chalk.dim('\nInstall with: npx bmad-method install --agent=<id>\n'));
}
async showStatus() {
const installDir = await this.findInstallation();
if (!installDir) {
console.log(chalk.yellow('No BMAD installation found in current directory tree'));
return;
}
const manifest = await fileManager.readManifest(installDir);
if (!manifest) {
console.log(chalk.red('Invalid installation - manifest not found'));
return;
}
console.log(chalk.bold('\nBMAD Installation Status:\n'));
console.log(` Directory: ${installDir}`);
console.log(` Version: ${manifest.version}`);
console.log(` Installed: ${new Date(manifest.installed_at).toLocaleDateString()}`);
console.log(` Type: ${manifest.install_type}`);
if (manifest.agent) {
console.log(` Agent: ${manifest.agent}`);
}
if (manifest.ide_setup) {
console.log(` IDE Setup: ${manifest.ide_setup}`);
}
console.log(` Total Files: ${manifest.files.length}`);
// Check for modifications
const modifiedFiles = await fileManager.checkModifiedFiles(installDir, manifest);
if (modifiedFiles.length > 0) {
console.log(chalk.yellow(` Modified Files: ${modifiedFiles.length}`));
}
console.log('');
}
async getAvailableAgents() {
return configLoader.getAvailableAgents();
}
async findInstallation() {
// Look for bmad-core in current directory or parent directories
let currentDir = process.cwd();
while (currentDir !== path.dirname(currentDir)) {
const bmadDir = path.join(currentDir, 'bmad-core');
const manifestPath = path.join(bmadDir, '.bmad', 'install-manifest.yml');
if (await fileManager.pathExists(manifestPath)) {
return bmadDir;
}
currentDir = path.dirname(currentDir);
}
// Also check if we're inside a bmad-core directory
if (path.basename(process.cwd()) === 'bmad-core') {
const manifestPath = path.join(process.cwd(), '.bmad', 'install-manifest.yml');
if (await fileManager.pathExists(manifestPath)) {
return process.cwd();
}
}
return null;
}
}
module.exports = new Installer();

704
tools/installer/package-lock.json generated Normal file
View File

@@ -0,0 +1,704 @@
{
"name": "bmad-method",
"version": "4.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bmad-method",
"version": "4.0.0",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"commander": "^9.4.1",
"fs-extra": "^11.1.0",
"inquirer": "^8.2.5",
"js-yaml": "^4.1.0",
"ora": "^5.4.1"
},
"bin": {
"bmad": "bin/bmad.js",
"bmad-method": "bin/bmad.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
"license": "MIT",
"dependencies": {
"type-fest": "^0.21.3"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"license": "MIT",
"dependencies": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"license": "MIT"
},
"node_modules/cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
"license": "MIT",
"dependencies": {
"restore-cursor": "^3.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/cli-spinners": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
"integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
"license": "MIT",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
"license": "ISC",
"engines": {
"node": ">= 10"
}
},
"node_modules/clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
"license": "MIT",
"engines": {
"node": ">=0.8"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/commander": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
"license": "MIT",
"engines": {
"node": "^12.20.0 || >=14"
}
},
"node_modules/defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
"integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
"license": "MIT",
"dependencies": {
"clone": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"license": "MIT",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/external-editor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
"license": "MIT",
"dependencies": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
},
"engines": {
"node": ">=4"
}
},
"node_modules/figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"license": "MIT",
"dependencies": {
"escape-string-regexp": "^1.0.5"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/fs-extra": {
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
"integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=14.14"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/inquirer": {
"version": "8.2.6",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
"integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
"license": "MIT",
"dependencies": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.1",
"cli-cursor": "^3.1.0",
"cli-width": "^3.0.0",
"external-editor": "^3.0.3",
"figures": "^3.0.0",
"lodash": "^4.17.21",
"mute-stream": "0.0.8",
"ora": "^5.4.1",
"run-async": "^2.4.0",
"rxjs": "^7.5.5",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6",
"wrap-ansi": "^6.0.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
"integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
"license": "ISC"
},
"node_modules/onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"license": "MIT",
"dependencies": {
"mimic-fn": "^2.1.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ora": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
"integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
"license": "MIT",
"dependencies": {
"bl": "^4.1.0",
"chalk": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-spinners": "^2.5.0",
"is-interactive": "^1.0.0",
"is-unicode-supported": "^0.1.0",
"log-symbols": "^4.1.0",
"strip-ansi": "^6.0.0",
"wcwidth": "^1.0.1"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
"license": "MIT",
"dependencies": {
"onetime": "^5.1.0",
"signal-exit": "^3.0.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"license": "MIT"
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"license": "MIT",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/type-fest": {
"version": "0.21.3",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"license": "MIT",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
"integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
"license": "MIT",
"dependencies": {
"defaults": "^1.0.3"
}
},
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
}
}
}

View File

@@ -0,0 +1,43 @@
{
"name": "bmad-method",
"version": "4.0.0",
"description": "BMAD Method installer - AI-powered Agile development framework",
"main": "lib/installer.js",
"bin": {
"bmad": "./bin/bmad.js",
"bmad-method": "./bin/bmad.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"bmad",
"agile",
"ai",
"development",
"framework",
"installer",
"agents"
],
"author": "BMAD Team",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"commander": "^9.4.1",
"fs-extra": "^11.1.0",
"inquirer": "^8.2.5",
"js-yaml": "^4.1.0",
"ora": "^5.4.1"
},
"engines": {
"node": ">=14.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/bmad-team/bmad-method.git"
},
"bugs": {
"url": "https://github.com/bmad-team/bmad-method/issues"
},
"homepage": "https://github.com/bmad-team/bmad-method#readme"
}