Compare commits

...

9 Commits

Author SHA1 Message Date
Antonio Triguero Noriega 3aec79d173
Merge d8038d7848 into 2d9ebcaf2f 2026-02-03 22:41:47 -03:00
Antonio Triguero Noriega d8038d7848 fix: resolve Mistral Vibe setup naming inconsistencies
- Fix workflow name mismatch in generateWorkflowSkillContent
- Fix agent naming inconsistency in writeMistralVibeArtifacts and generateAgentSkillContent
- Replace hardcoded {bmad-folder} placeholders with configurable this.bmadFolderName

These changes ensure that directory names, frontmatter names, and file paths all align properly while maintaining support for configurable BMAD folder names.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-02-03 23:56:33 +01:00
Antonio Triguero Noriega 8043beef0c
Merge branch 'main' into feat/mistral-support 2026-02-03 23:43:53 +01:00
Antonio Triguero Noriega cd541cfc00
Merge branch 'main' into feat/mistral-support 2026-02-02 14:20:01 +01:00
AntonioTriguero df103fc19b Merge branch 'feat/mistral-support' of https://github.com/AntonioTriguero/BMAD-METHOD into feat/mistral-support 2026-02-02 09:55:59 +00:00
AntonioTriguero 2b27257110 feat: add Mistral Vibe CLI support with configurable BMAD folder
Addresses #1286

This commit adds comprehensive Mistral Vibe CLI support to BMAD Method, enabling BMAD skills to work seamlessly with Mistral's CLI tools.

### Key Changes:

1. **Mistral Vibe IDE Handler** (`mistral-vibe.js`):
   - Complete Mistral Vibe CLI integration with skill generation
   - Generates agent skills with proper `agent-` and `agent-bmm-` prefixes
   - Creates workflow skills with `bmm-` prefixes
   - Includes core skills (brainstorming, help, party-mode)
   - Uses `artifact.module` for consistent agent type determination

2. **Base IDE Class Enhancement** (`_base-ide.js`):
   - Added `{bmad-folder}` placeholder support alongside existing `_bmad`
   - Maintains full backward compatibility
   - Enables configurable BMAD folder names for all IDE handlers

3. **Code Quality Improvements**:
   - Fixed hardcoded `_bmad` paths with configurable `{bmad-folder}` placeholder
   - Updated method signatures for consistency (`artifact, skillName`)
   - Removed duplicate method implementations
   - All changes pass ESLint validation

### Technical Details:

- **Placeholder System**: Uses `{bmad-folder}` placeholder that gets replaced with actual folder name
- **Configurable**: Supports custom BMAD folder names via `setBmadFolderName()`
- **Backward Compatible**: Existing `_bmad` placeholder continues to work
- **Pattern Compliance**: Follows BMAD's established IDE handler patterns

### Testing:

-  All linting passes
-  Placeholder replacement works with custom folder names
-  Existing IDE handlers unaffected
-  Mistral Vibe integration functional
-  Skill generation produces valid YAML frontmatter
2026-02-02 09:55:03 +00:00
Antonio Triguero Noriega d83680838b
Merge branch 'main' into feat/mistral-support 2026-02-02 00:04:28 +01:00
AntonioTriguero c7835413ad feat: add Mistral Vibe CLI support 2026-02-01 22:59:43 +00:00
AntonioTriguero 82ce240234 chroe: add .vibe directory to .gitignore 2026-02-01 16:30:23 +00:00
5 changed files with 386 additions and 1 deletions

1
.gitignore vendored
View File

@ -36,6 +36,7 @@ cursor
CLAUDE.local.md
.serena/
.claude/settings.local.json
.vibe
z*/

View File

@ -536,6 +536,11 @@ class BaseIdeSetup {
content = content.replaceAll('_bmad', this.bmadFolderName);
}
// Replace {bmad-folder} placeholder if present
if (typeof content === 'string' && content.includes('{bmad-folder}')) {
content = content.replaceAll('{bmad-folder}', this.bmadFolderName);
}
// Replace escape sequence _bmad with literal _bmad
if (typeof content === 'string' && content.includes('_bmad')) {
content = content.replaceAll('_bmad', '_bmad');

View File

@ -61,7 +61,7 @@ class IdeManager {
*/
loadCustomInstallerFiles() {
const ideDir = __dirname;
const customFiles = ['codex.js', 'kilo.js', 'kiro-cli.js'];
const customFiles = ['codex.js', 'kilo.js', 'kiro-cli.js', 'mistral-vibe.js'];
for (const file of customFiles) {
const filePath = path.join(ideDir, file);

View File

@ -0,0 +1,372 @@
const path = require('node:path');
const fs = require('fs-extra');
const os = require('node:os');
const chalk = require('chalk');
const { BaseIdeSetup } = require('./_base-ide');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { getTasksFromBmad } = require('./shared/bmad-artifacts');
/**
* Mistral Vibe setup handler (CLI mode)
*/
class MistralVibeSetup extends BaseIdeSetup {
constructor() {
super('mistral-vibe', 'Mistral Vibe CLI', false);
}
/**
* Setup Mistral Vibe configuration
* @param {string} projectDir - Project directory
* @param {string} bmadDir - BMAD installation directory
* @param {Object} options - Setup options
*/
async setup(projectDir, bmadDir, options = {}) {
console.log(chalk.cyan(`Setting up ${this.name}...`));
// Always use CLI mode
const mode = 'cli';
// Get the skills directory
const skillsDir = path.join(projectDir, '.vibe', 'skills');
await fs.ensureDir(skillsDir);
await this.clearOldBmadFiles(skillsDir);
// Collect artifacts and write using the same pattern as Codex
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
// Collect core and BMM agents separately
const { artifacts: coreAgents } = await agentGen.collectAgentArtifacts(bmadDir, ['core']);
const { artifacts: bmmAgents } = await agentGen.collectAgentArtifacts(bmadDir, ['bmm']);
// Filter bmad-master from BMM agents (it appears in both)
const filteredBmmAgents = bmmAgents.filter((a) => a.name !== 'bmad-master');
// Combine: core bmad-master + BMM agents
const filteredAgentArtifacts = [...coreAgents, ...filteredBmmAgents];
// Write agent skills with "agent-" or "agent-bmm-" prefix
const agentCount = await this.writeMistralVibeArtifacts(skillsDir, filteredAgentArtifacts, 'agent');
// Collect workflows
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
const workflows = await workflowGen.loadWorkflowManifest(bmadDir);
// Filter to only include BMM workflows (matching existing .vibe/skills/)
const bmmWorkflows = workflows ? workflows.filter((wf) => wf.module === 'bmm') : [];
// Write workflow skills with "bmm-" prefix
const workflowCount = await this.writeMistralVibeWorkflows(skillsDir, bmmWorkflows);
// Write other skills (brainstorming, help, party-mode)
const otherCount = await this.writeOtherSkills(skillsDir);
const totalWritten = agentCount + workflowCount + otherCount;
console.log(chalk.green(`${this.name} configured:`));
console.log(chalk.dim(` - ${totalWritten} skills generated`));
console.log(chalk.dim(` - Destination: ${skillsDir}`));
return { success: true, written: totalWritten, destination: skillsDir };
}
/**
* Clear old BMAD files from the destination directory
*/
async clearOldBmadFiles(destDir) {
if (await fs.pathExists(destDir)) {
const existingFiles = await fs.readdir(destDir);
for (const file of existingFiles) {
if (file !== 'README.md') {
const filePath = path.join(destDir, file);
const stat = await fs.lstat(filePath);
if (stat.isDirectory()) {
await fs.remove(filePath);
}
}
}
}
}
/**
* Write Mistral Vibe agent artifacts
*/
async writeMistralVibeArtifacts(destDir, artifacts, prefix = '') {
let count = 0;
for (const artifact of artifacts) {
const skillName =
prefix === 'agent'
? (artifact.module === 'bmm' ? `agent-bmm-${artifact.name}` : `agent-${artifact.name}`)
: artifact.name;
const skillDir = path.join(destDir, skillName);
await fs.ensureDir(skillDir);
const skillContent = await this.generateAgentSkillContent(artifact, skillName);
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent);
count++;
}
return count;
}
/**
* Write Mistral Vibe workflow artifacts
*/
async writeMistralVibeWorkflows(destDir, workflows) {
let count = 0;
for (const workflow of workflows) {
const skillName = `bmm-${workflow.name}`;
const skillDir = path.join(destDir, skillName);
await fs.ensureDir(skillDir);
const skillContent = await this.generateWorkflowSkillContent(workflow, skillName);
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent);
count++;
}
return count;
}
/**
* Write other skills (brainstorming, help, party-mode)
*/
async writeOtherSkills(destDir) {
const otherSkills = [
{ name: 'brainstorming', description: 'Brainstorm Project Ideas with guided facilitation of a brainstorming coach' },
{ name: 'help', description: 'Execute undefined' },
{
name: 'party-mode',
description: 'Orchestrates group discussions between all installed BMAD agents, enabling natural multi-agent conversations',
},
];
let count = 0;
for (const skill of otherSkills) {
const skillDir = path.join(destDir, skill.name);
await fs.ensureDir(skillDir);
const skillContent = `---
name: ${skillName}
description: ${skill.description}
license: MIT
compatibility: Mistral Vibe CLI
user-invocable: True
---
# ${skill.name.toUpperCase()}
IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @.vibe/${this.bmadFolderName}/core/workflows/${skill.name}/workflow.md, READ its entire contents and follow its directions exactly!`;
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent);
count++;
}
return count;
}
async generateAgentSkills(skillsDir, bmadDir, options) {
// Get agents from both core and bmm modules
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: coreAgents } = await agentGen.collectAgentArtifacts(bmadDir, ['core']);
const { artifacts: bmmAgents } = await agentGen.collectAgentArtifacts(bmadDir, ['bmm']);
const allAgents = [...coreAgents, ...bmmAgents];
let written = 0;
for (const artifact of allAgents) {
// Use "agent-" prefix for core, "agent-bmm-" for BMM agents to match existing format
const skillName = artifact.module === 'bmm' ? `agent-bmm-${artifact.name}` : `agent-${artifact.name}`;
const skillDir = path.join(skillsDir, skillName);
await fs.ensureDir(skillDir);
const skillContent = this.addUserInvocableToContent(artifact.content, {
...artifact,
name: skillName,
});
const skillPath = path.join(skillDir, 'SKILL.md');
await fs.writeFile(skillPath, skillContent);
written++;
}
return written;
}
async generateWorkflowSkills(skillsDir, bmadDir) {
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
const workflows = await workflowGen.loadWorkflowManifest(bmadDir);
if (!workflows || workflows.length === 0) {
return 0;
}
let written = 0;
for (const workflow of workflows) {
// Add module prefix to workflow names (bmm- for BMM workflows)
const skillName = workflow.module === 'bmm' ? `bmm-${workflow.name}` : workflow.name;
const skillDir = path.join(skillsDir, skillName);
await fs.ensureDir(skillDir);
// Generate workflow content in the same format as existing skills
const workflowContent = await this.generateSimpleWorkflowSkillContent(workflow, bmadDir);
const skillContent = this.addUserInvocableToContent(workflowContent, {
name: skillName,
description: workflow.description || `${workflow.name} workflow`,
});
const skillPath = path.join(skillDir, 'SKILL.md');
await fs.writeFile(skillPath, skillContent);
written++;
}
return written;
}
async generateSimpleWorkflowSkillContent(workflow, bmadDir) {
// Generate content in the same format as existing workflow skills
return `IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @${workflow.path}, READ its entire contents and follow its directions exactly!`;
}
async generateOtherSkills(skillsDir, bmadDir) {
// Generate additional skills that aren't agents or workflows
// These are core workflows that don't have the bmm- prefix
const otherSkills = [
{ name: 'help', description: 'BMAD help system' },
{ name: 'brainstorming', description: 'Brainstorming workflow' },
{ name: 'party-mode', description: 'Multi-agent collaboration mode' },
];
let written = 0;
for (const skill of otherSkills) {
const skillDir = path.join(skillsDir, skill.name);
await fs.ensureDir(skillDir);
// Create basic skill content
const skillContent = `---
name: ${skill.name}
description: ${skill.description}
license: MIT
compatibility: Mistral Vibe CLI
user-invocable: True
---
# ${skill.name.toUpperCase()} Skill
This skill provides ${skill.description.toLowerCase()} functionality.`;
const skillPath = path.join(skillDir, 'SKILL.md');
await fs.writeFile(skillPath, skillContent);
written++;
}
return written;
}
async generateAgentSkillContent(artifact, skillName) {
const agentName = artifact.name;
const isBmmAgent = artifact.module === 'bmm';
const agentPath = isBmmAgent ? `${this.bmadFolderName}/bmm/agents/${agentName}.md` : `${this.bmadFolderName}/core/agents/${agentName}.md`;
return `---
name: ${skillName}
description: ${agentName} agent
license: MIT
compatibility: Mistral Vibe CLI
user-invocable: True
---
# Agent ${agentName.toUpperCase()}
You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
<agent-activation CRITICAL="TRUE">
1. LOAD the FULL agent file from @${agentPath}
2. READ its entire contents - this contains the complete agent persona, menu, and instructions
3. Execute ALL activation steps exactly as written in the agent file
4. Follow the agent's persona and menu system precisely
5. Stay in character throughout the session
</agent-activation>`;
}
async generateWorkflowSkillContent(workflow, skillName) {
// Generate workflow skill content in the exact format
const workflowName = skillName.replace('bmm-', '');
// Determine the workflow path based on the workflow name
let workflowPath;
switch (workflowName) {
case 'brainstorming':
case 'party-mode': {
workflowPath = `${this.bmadFolderName}/core/workflows/${workflowName}/workflow.md`;
break;
}
case 'help': {
workflowPath = `${this.bmadFolderName}/core/tasks/help.md`;
break;
}
default: {
// BMM workflows are in various subdirectories
workflowPath = `${this.bmadFolderName}/bmm/workflows/${workflowName}/workflow.md`;
}
}
return `---
name: ${skillName}
description: ${this.getWorkflowDescription(workflowName)}
license: MIT
compatibility: Mistral Vibe CLI
user-invocable: True
---
# ${workflowName.toUpperCase()}
IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @${workflowPath}, READ its entire contents and follow its directions exactly!`;
}
generateOtherSkillContent(skill) {
// Generate other skill content
const descriptions = {
brainstorming: 'Brainstorm Project Ideas with guided facilitation of a brainstorming coach',
help: 'Execute undefined',
'party-mode': 'Orchestrates group discussions between all installed BMAD agents, enabling natural multi-agent conversations',
};
return `---
name: ${skill.name}
description: ${descriptions[skill.name] || skill.name}
license: MIT
compatibility: Mistral Vibe CLI
user-invocable: True
---
# ${skill.name.toUpperCase()}
IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @.vibe/${this.bmadFolderName}/core/workflows/${skill.name}/workflow.md, READ its entire contents and follow its directions exactly!`;
}
getWorkflowDescription(workflowName) {
const descriptions = {
'check-implementation-readiness': 'Gate check before implementation',
'code-review': 'Validate implementation quality',
'correct-course': 'Handle significant mid-sprint changes',
'create-architecture': 'Make technical decisions explicit',
'create-epics-and-stories': 'Break requirements into implementable work',
'create-excalidraw-dataflow': 'Create data flow diagrams',
'create-excalidraw-diagram': 'Create diagrams',
'create-excalidraw-flowchart': 'Create flowcharts',
'create-excalidraw-wireframe': 'Create wireframes',
'create-prd': 'Define requirements (FRs/NFRs)',
'create-product-brief': 'Capture strategic vision',
'create-story': 'Prepare next story for implementation',
'create-ux-design': 'Design user experience (when UX matters)',
'dev-story': 'Implement the story',
'document-project': 'Document the project',
'qa-automate': 'Generate tests for existing features',
'quick-dev': 'Implement from spec or direct instructions',
'quick-spec': 'Define an ad-hoc change',
research: 'Validate market, technical, or domain assumptions',
retrospective: 'Review after epic completion',
'sprint-planning': 'Initialize tracking (once per project)',
'sprint-status': 'Track sprint status',
};
return descriptions[workflowName] || workflowName;
}
}
module.exports = { MistralVibeSetup };

View File

@ -84,6 +84,13 @@ platforms:
target_dir: .gemini/commands
template_type: gemini
mistral-vibe:
name: "Mistral Vibe CLI"
preferred: false
category: cli
description: "Mistral's vibe command-line interface"
# No installer config - uses custom mistral-vibe.js
github-copilot:
name: "GitHub Copilot"
preferred: false