Merge 961c50f752 into e3f756488a
This commit is contained in:
commit
b49d55f981
|
|
@ -73,3 +73,6 @@ z*/
|
||||||
.agentvibes/
|
.agentvibes/
|
||||||
.kiro/
|
.kiro/
|
||||||
.roo
|
.roo
|
||||||
|
|
||||||
|
# Generated voice map (user-specific)
|
||||||
|
.bmad/_cfg/agent-voice-map.csv
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ Load config from `{project-root}/{bmad_folder}/bmm/config.yaml` and resolve:
|
||||||
|
|
||||||
- `installed_path` = `{project-root}/{bmad_folder}/core/workflows/party-mode`
|
- `installed_path` = `{project-root}/{bmad_folder}/core/workflows/party-mode`
|
||||||
- `agent_manifest_path` = `{project-root}/{bmad_folder}/_cfg/agent-manifest.csv`
|
- `agent_manifest_path` = `{project-root}/{bmad_folder}/_cfg/agent-manifest.csv`
|
||||||
|
- `agent_voice_map_path` = `{project-root}/{bmad_folder}/_cfg/agent-voice-map.csv`
|
||||||
- `standalone_mode` = `true` (party mode is an interactive workflow)
|
- `standalone_mode` = `true` (party mode is an interactive workflow)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -63,6 +64,16 @@ Parse CSV manifest to extract agent entries with complete information:
|
||||||
|
|
||||||
Build complete agent roster with merged personalities for conversation orchestration.
|
Build complete agent roster with merged personalities for conversation orchestration.
|
||||||
|
|
||||||
|
### Voice Map Loading (Optional)
|
||||||
|
|
||||||
|
If `agent_voice_map_path` exists, load agent voice configuration:
|
||||||
|
|
||||||
|
- **agent** (agent identifier matching manifest name)
|
||||||
|
- **voice** (TTS voice name for the agent)
|
||||||
|
- **intro** (introduction message the agent uses when joining party mode)
|
||||||
|
|
||||||
|
Merge voice map data with agent roster for TTS integration and personalized introductions.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## EXECUTION
|
## EXECUTION
|
||||||
|
|
@ -81,7 +92,15 @@ Welcome {{user_name}}! All BMAD agents are here and ready for a dynamic group di
|
||||||
|
|
||||||
**Let me introduce our collaborating agents:**
|
**Let me introduce our collaborating agents:**
|
||||||
|
|
||||||
[Load agent roster and display 2-3 most diverse agents as examples]
|
[Load agent roster and display all agents with their icons and titles]
|
||||||
|
|
||||||
|
**Agent Introductions (if voice map with intros is available):**
|
||||||
|
|
||||||
|
For each agent in the roster, if they have an intro message from the voice map:
|
||||||
|
|
||||||
|
- Have the agent speak their intro message in-character
|
||||||
|
- Use TTS to voice the introduction with their assigned voice
|
||||||
|
- Format: `Bash: .claude/hooks/bmad-speak.sh "[Agent Name]" "[Their intro message]"`
|
||||||
|
|
||||||
**What would you like to discuss with the team today?**"
|
**What would you like to discuss with the team today?**"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,18 @@ module.exports = {
|
||||||
// Run AgentVibes installer
|
// Run AgentVibes installer
|
||||||
const { execSync } = require('node:child_process');
|
const { execSync } = require('node:child_process');
|
||||||
try {
|
try {
|
||||||
|
// Clear ALL npm config env vars to prevent inheritance issues
|
||||||
|
// when BMAD is invoked with --prefix flag
|
||||||
|
// npm sets many npm_config_* and npm_package_* vars that can interfere
|
||||||
|
const cleanEnv = Object.fromEntries(
|
||||||
|
Object.entries(process.env).filter(([key]) => !key.startsWith('npm_config_') && !key.startsWith('npm_package_')),
|
||||||
|
);
|
||||||
|
|
||||||
execSync('npx agentvibes@latest install', {
|
execSync('npx agentvibes@latest install', {
|
||||||
cwd: result.projectDir,
|
cwd: result.projectDir,
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
shell: true,
|
shell: true,
|
||||||
|
env: cleanEnv,
|
||||||
});
|
});
|
||||||
console.log(chalk.green('\n✓ AgentVibes installation complete'));
|
console.log(chalk.green('\n✓ AgentVibes installation complete'));
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -824,6 +824,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
const manifestStats = await manifestGen.generateManifests(bmadDir, config.modules || [], this.installedFiles, {
|
const manifestStats = await manifestGen.generateManifests(bmadDir, config.modules || [], this.installedFiles, {
|
||||||
ides: config.ides || [],
|
ides: config.ides || [],
|
||||||
preservedModules: config._preserveModules || [], // Scan these from installed bmad/ dir
|
preservedModules: config._preserveModules || [], // Scan these from installed bmad/ dir
|
||||||
|
agentVibes: { enabled: this.enableAgentVibes || false }, // Track AgentVibes TTS configuration
|
||||||
});
|
});
|
||||||
|
|
||||||
spinner.succeed(
|
spinner.succeed(
|
||||||
|
|
@ -1058,7 +1059,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
path: bmadDir,
|
path: bmadDir,
|
||||||
modules: config.modules,
|
modules: config.modules,
|
||||||
ides: config.ides,
|
ides: config.ides,
|
||||||
needsAgentVibes: this.enableAgentVibes && !config.agentVibesInstalled,
|
needsAgentVibes: this.enableAgentVibes, // Always run installer if enabled - handles updates too
|
||||||
projectDir: projectDir,
|
projectDir: projectDir,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -1966,6 +1967,38 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for AgentVibes TTS - prompt if not previously configured
|
||||||
|
// Read existing manifest to check if AgentVibes was previously set
|
||||||
|
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml');
|
||||||
|
let agentVibesEnabled = false;
|
||||||
|
let agentVibesPreviouslyConfigured = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
const manifest = yaml.load(manifestContent);
|
||||||
|
// Check if AgentVibes was previously configured (exists in manifest)
|
||||||
|
if (manifest.agentVibes !== undefined) {
|
||||||
|
agentVibesPreviouslyConfigured = true;
|
||||||
|
agentVibesEnabled = manifest.agentVibes?.enabled || false;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Manifest doesn't exist or can't be read - treat as not configured
|
||||||
|
}
|
||||||
|
|
||||||
|
// If AgentVibes wasn't previously configured, prompt the user
|
||||||
|
// Use configuredIdes from line 1904 for smart default (Y if Claude Code is selected)
|
||||||
|
if (!agentVibesPreviouslyConfigured) {
|
||||||
|
const { UI } = require('../../../lib/ui');
|
||||||
|
const ui = new UI();
|
||||||
|
const agentVibesConfig = await ui.promptAgentVibes(projectDir, configuredIdes);
|
||||||
|
|
||||||
|
if (agentVibesConfig.enableTts) {
|
||||||
|
agentVibesEnabled = true;
|
||||||
|
promptedForNewFields = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!promptedForNewFields) {
|
if (!promptedForNewFields) {
|
||||||
console.log(chalk.green('✓ All configuration is up to date, no new options to configure'));
|
console.log(chalk.green('✓ All configuration is up to date, no new options to configure'));
|
||||||
}
|
}
|
||||||
|
|
@ -2003,6 +2036,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
_quickUpdate: true, // Flag to skip certain prompts
|
_quickUpdate: true, // Flag to skip certain prompts
|
||||||
_preserveModules: skippedModules, // Preserve these in manifest even though we didn't update them
|
_preserveModules: skippedModules, // Preserve these in manifest even though we didn't update them
|
||||||
_savedIdeConfigs: savedIdeConfigs, // Pass saved IDE configs to installer
|
_savedIdeConfigs: savedIdeConfigs, // Pass saved IDE configs to installer
|
||||||
|
enableAgentVibes: agentVibesEnabled, // AgentVibes TTS configuration
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call the standard install method
|
// Call the standard install method
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@ class ManifestGenerator {
|
||||||
// Filter out any undefined/null values from IDE list
|
// Filter out any undefined/null values from IDE list
|
||||||
this.selectedIdes = resolvedIdes.filter((ide) => ide && typeof ide === 'string');
|
this.selectedIdes = resolvedIdes.filter((ide) => ide && typeof ide === 'string');
|
||||||
|
|
||||||
|
// Store AgentVibes configuration for manifest
|
||||||
|
this.agentVibes = options.agentVibes || null;
|
||||||
|
|
||||||
// Collect workflow data
|
// Collect workflow data
|
||||||
await this.collectWorkflows(selectedModules);
|
await this.collectWorkflows(selectedModules);
|
||||||
|
|
||||||
|
|
@ -71,6 +74,7 @@ class ManifestGenerator {
|
||||||
await this.writeMainManifest(cfgDir),
|
await this.writeMainManifest(cfgDir),
|
||||||
await this.writeWorkflowManifest(cfgDir),
|
await this.writeWorkflowManifest(cfgDir),
|
||||||
await this.writeAgentManifest(cfgDir),
|
await this.writeAgentManifest(cfgDir),
|
||||||
|
await this.writeVoiceMap(cfgDir),
|
||||||
await this.writeTaskManifest(cfgDir),
|
await this.writeTaskManifest(cfgDir),
|
||||||
await this.writeToolManifest(cfgDir),
|
await this.writeToolManifest(cfgDir),
|
||||||
await this.writeFilesManifest(cfgDir),
|
await this.writeFilesManifest(cfgDir),
|
||||||
|
|
@ -446,6 +450,7 @@ class ManifestGenerator {
|
||||||
},
|
},
|
||||||
modules: this.modules,
|
modules: this.modules,
|
||||||
ides: this.selectedIdes,
|
ides: this.selectedIdes,
|
||||||
|
agentVibes: this.agentVibes, // Track AgentVibes TTS configuration
|
||||||
};
|
};
|
||||||
|
|
||||||
const yamlStr = yaml.dump(manifest, {
|
const yamlStr = yaml.dump(manifest, {
|
||||||
|
|
@ -581,6 +586,80 @@ class ManifestGenerator {
|
||||||
return csvPath;
|
return csvPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write agent voice map CSV for AgentVibes TTS integration
|
||||||
|
* Maps agent IDs to default Piper TTS voices and intro messages
|
||||||
|
* AgentVibes will use this if present, otherwise falls back to its own defaults
|
||||||
|
* @returns {string} Path to the voice map file
|
||||||
|
*/
|
||||||
|
async writeVoiceMap(cfgDir) {
|
||||||
|
const csvPath = path.join(cfgDir, 'agent-voice-map.csv');
|
||||||
|
|
||||||
|
// Default voice assignments and intros for BMAD agents
|
||||||
|
// These can be customized by editing the generated CSV
|
||||||
|
const agentDefaults = {
|
||||||
|
'bmad-master': {
|
||||||
|
voice: 'en_US-lessac-medium',
|
||||||
|
intro: 'Greetings! The BMad Master is here to orchestrate and guide you through any workflow.',
|
||||||
|
},
|
||||||
|
analyst: {
|
||||||
|
voice: 'en_US-kristin-medium',
|
||||||
|
intro: "Hi there! I'm Mary, your Business Analyst. I'll help uncover the real requirements.",
|
||||||
|
},
|
||||||
|
architect: {
|
||||||
|
voice: 'en_GB-alan-medium',
|
||||||
|
intro: "Hello! Winston here, your Architect. I'll ensure we build something scalable and pragmatic.",
|
||||||
|
},
|
||||||
|
dev: {
|
||||||
|
voice: 'en_US-joe-medium',
|
||||||
|
intro: 'Hey! Amelia here, your Developer. Ready to turn specs into working code.',
|
||||||
|
},
|
||||||
|
pm: {
|
||||||
|
voice: 'en_US-ryan-high',
|
||||||
|
intro: "Hey team! John here, your Product Manager. Let's make sure we're building the right thing.",
|
||||||
|
},
|
||||||
|
sm: {
|
||||||
|
voice: 'en_US-amy-medium',
|
||||||
|
intro: "Hi everyone! Bob here, your Scrum Master. I'll keep us focused and moving forward.",
|
||||||
|
},
|
||||||
|
tea: {
|
||||||
|
voice: 'en_US-kusal-medium',
|
||||||
|
intro: 'Hello! Murat here, your Test Architect. Quality is my obsession.',
|
||||||
|
},
|
||||||
|
'tech-writer': {
|
||||||
|
voice: 'jenny',
|
||||||
|
intro: "Hi! I'm Paige, your Technical Writer. I'll make sure everything is documented clearly.",
|
||||||
|
},
|
||||||
|
'ux-designer': {
|
||||||
|
voice: 'kristin',
|
||||||
|
intro: 'Hey! Sally here, your UX Designer. The user experience is my top priority.',
|
||||||
|
},
|
||||||
|
'frame-expert': {
|
||||||
|
voice: 'en_GB-alan-medium',
|
||||||
|
intro: "Hello! Saif here, your Visual Design Expert. I'll help visualize your ideas.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fallback values for agents not in the default map
|
||||||
|
const fallbackVoice = 'en_US-lessac-medium';
|
||||||
|
const fallbackIntro = 'Hello! Ready to help with the discussion.';
|
||||||
|
|
||||||
|
let csv = 'agent,voice,intro\n';
|
||||||
|
|
||||||
|
// Add voice mapping and intro for each discovered agent
|
||||||
|
for (const agent of this.agents) {
|
||||||
|
const defaults = agentDefaults[agent.name] || {};
|
||||||
|
const voice = defaults.voice || fallbackVoice;
|
||||||
|
const intro = defaults.intro || fallbackIntro;
|
||||||
|
// Escape quotes in intro for CSV
|
||||||
|
const escapedIntro = intro.replaceAll('"', '""');
|
||||||
|
csv += `${agent.name},${voice},"${escapedIntro}"\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(csvPath, csv);
|
||||||
|
return csvPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write task manifest CSV
|
* Write task manifest CSV
|
||||||
* @returns {string} Path to the manifest file
|
* @returns {string} Path to the manifest file
|
||||||
|
|
|
||||||
|
|
@ -119,13 +119,14 @@ class UI {
|
||||||
const moduleChoices = await this.getModuleChoices(installedModuleIds);
|
const moduleChoices = await this.getModuleChoices(installedModuleIds);
|
||||||
const selectedModules = await this.selectModules(moduleChoices);
|
const selectedModules = await this.selectModules(moduleChoices);
|
||||||
|
|
||||||
// Prompt for AgentVibes TTS integration
|
|
||||||
const agentVibesConfig = await this.promptAgentVibes(confirmedDirectory);
|
|
||||||
|
|
||||||
// Collect IDE tool selection AFTER configuration prompts (fixes Windows/PowerShell hang)
|
// Collect IDE tool selection AFTER configuration prompts (fixes Windows/PowerShell hang)
|
||||||
// This allows text-based prompts to complete before the checkbox prompt
|
// This allows text-based prompts to complete before the checkbox prompt
|
||||||
const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
||||||
|
|
||||||
|
// Prompt for AgentVibes TTS integration AFTER tool selection
|
||||||
|
// Default to Y if Claude Code is selected (since AgentVibes only works with Claude Code)
|
||||||
|
const agentVibesConfig = await this.promptAgentVibes(confirmedDirectory, toolSelection.ides);
|
||||||
|
|
||||||
// No more screen clearing - keep output flowing
|
// No more screen clearing - keep output flowing
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -753,7 +754,7 @@ class UI {
|
||||||
* - Markers: src/core/workflows/party-mode/instructions.md:101, src/modules/bmm/agents/*.md
|
* - Markers: src/core/workflows/party-mode/instructions.md:101, src/modules/bmm/agents/*.md
|
||||||
* - GitHub Issue: paulpreibisch/AgentVibes#36
|
* - GitHub Issue: paulpreibisch/AgentVibes#36
|
||||||
*/
|
*/
|
||||||
async promptAgentVibes(projectDir) {
|
async promptAgentVibes(projectDir, selectedIdes = []) {
|
||||||
CLIUtils.displaySection('🎤 Voice Features', 'Enable TTS for multi-agent conversations');
|
CLIUtils.displaySection('🎤 Voice Features', 'Enable TTS for multi-agent conversations');
|
||||||
|
|
||||||
// Check if AgentVibes is already installed
|
// Check if AgentVibes is already installed
|
||||||
|
|
@ -765,20 +766,21 @@ class UI {
|
||||||
console.log(chalk.dim(' AgentVibes not detected'));
|
console.log(chalk.dim(' AgentVibes not detected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default to Y if Claude Code is selected (AgentVibes only works with Claude Code)
|
||||||
|
const claudeCodeSelected = selectedIdes.includes('claude-code');
|
||||||
|
const defaultValue = claudeCodeSelected;
|
||||||
|
|
||||||
const answers = await inquirer.prompt([
|
const answers = await inquirer.prompt([
|
||||||
{
|
{
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'enableTts',
|
name: 'enableTts',
|
||||||
message: 'Enable Agents to Speak Out loud (powered by Agent Vibes? Claude Code only currently)',
|
message: 'Enable Agents to Speak Out loud (powered by AgentVibes, Claude Code only)',
|
||||||
default: false, // Default to yes - recommended for best experience
|
default: defaultValue,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (answers.enableTts && !agentVibesInstalled) {
|
// Note: AgentVibes installer runs at end of BMAD install if enabled and not already installed
|
||||||
console.log(chalk.yellow('\n ⚠️ AgentVibes not installed'));
|
// No need to show warning here - the installer will handle it
|
||||||
console.log(chalk.dim(' Install AgentVibes separately to enable TTS:'));
|
|
||||||
console.log(chalk.dim(' https://github.com/paulpreibisch/AgentVibes\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled: answers.enableTts,
|
enabled: answers.enableTts,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue