Compare commits
No commits in common. "d097b5e82b0183da06d9bd9a4ce90b3ba9a26d7e" and "f1bfee1be3391db40b7be0961ce8154dc5cede54" have entirely different histories.
d097b5e82b
...
f1bfee1be3
|
|
@ -147,7 +147,7 @@ your-project/
|
||||||
| **Concept** | `what-are-agents.md` |
|
| **Concept** | `what-are-agents.md` |
|
||||||
| **Feature** | `quick-flow.md` |
|
| **Feature** | `quick-flow.md` |
|
||||||
| **Philosophy** | `why-solutioning-matters.md` |
|
| **Philosophy** | `why-solutioning-matters.md` |
|
||||||
| **FAQ** | `established-projects-faq.md` |
|
| **FAQ** | `brownfield-faq.md` |
|
||||||
|
|
||||||
### General Template
|
### General Template
|
||||||
|
|
||||||
|
|
@ -325,7 +325,7 @@ Add italic context at definition start for limited-scope terms:
|
||||||
- `*BMad Method/Enterprise.*`
|
- `*BMad Method/Enterprise.*`
|
||||||
- `*Phase N.*`
|
- `*Phase N.*`
|
||||||
- `*BMGD.*`
|
- `*BMGD.*`
|
||||||
- `*Established projects.*`
|
- `*Brownfield.*`
|
||||||
|
|
||||||
### Glossary Checklist
|
### Glossary Checklist
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
title: "Brownfield Development FAQ"
|
||||||
|
description: Common questions about brownfield development in the BMad Method
|
||||||
|
---
|
||||||
|
Quick answers to common questions about brownfield (existing codebase) development in the BMad Method (BMM).
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
- [Questions](#questions)
|
||||||
|
- [What is brownfield vs greenfield?](#what-is-brownfield-vs-greenfield)
|
||||||
|
- [Do I have to run document-project for brownfield?](#do-i-have-to-run-document-project-for-brownfield)
|
||||||
|
- [What if I forget to run document-project?](#what-if-i-forget-to-run-document-project)
|
||||||
|
- [Can I use Quick Spec Flow for brownfield projects?](#can-i-use-quick-spec-flow-for-brownfield-projects)
|
||||||
|
- [What if my existing code doesn't follow best practices?](#what-if-my-existing-code-doesnt-follow-best-practices)
|
||||||
|
|
||||||
|
### What is brownfield vs greenfield?
|
||||||
|
|
||||||
|
- **Greenfield** — New project, starting from scratch, clean slate
|
||||||
|
- **Brownfield** — Existing project, working with established codebase and patterns
|
||||||
|
|
||||||
|
### Do I have to run document-project for brownfield?
|
||||||
|
|
||||||
|
Highly recommended, especially if:
|
||||||
|
|
||||||
|
- No existing documentation
|
||||||
|
- Documentation is outdated
|
||||||
|
- AI agents need context about existing code
|
||||||
|
|
||||||
|
You can skip it if you have comprehensive, up-to-date documentation including `docs/index.md` or will use other tools or techniques to aid in discovery for the agent to build on an existing system.
|
||||||
|
|
||||||
|
### What if I forget to run document-project?
|
||||||
|
|
||||||
|
Don't worry about it - you can do it at any time. You can even do it during or after a project to help keep docs up to date.
|
||||||
|
|
||||||
|
### Can I use Quick Spec Flow for brownfield projects?
|
||||||
|
|
||||||
|
Yes! Quick Spec Flow works great for brownfield. It will:
|
||||||
|
|
||||||
|
- Auto-detect your existing stack
|
||||||
|
- Analyze brownfield code patterns
|
||||||
|
- Detect conventions and ask for confirmation
|
||||||
|
- Generate context-rich tech-spec that respects existing code
|
||||||
|
|
||||||
|
Perfect for bug fixes and small features in existing codebases.
|
||||||
|
|
||||||
|
### What if my existing code doesn't follow best practices?
|
||||||
|
|
||||||
|
Quick Spec Flow detects your conventions and asks: "Should I follow these existing conventions?" You decide:
|
||||||
|
|
||||||
|
- **Yes** → Maintain consistency with current codebase
|
||||||
|
- **No** → Establish new standards (document why in tech-spec)
|
||||||
|
|
||||||
|
BMM respects your choice — it won't force modernization, but it will offer it.
|
||||||
|
|
||||||
|
**Have a question not answered here?** Please [open an issue](https://github.com/bmad-code-org/BMAD-METHOD/issues) or ask in [Discord](https://discord.gg/gk8jAdXWmj) so we can add it!
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
---
|
|
||||||
title: "Established Projects FAQ"
|
|
||||||
description: Common questions about using BMad Method on established projects
|
|
||||||
---
|
|
||||||
Quick answers to common questions about working on established projects with the BMad Method (BMM).
|
|
||||||
|
|
||||||
## Questions
|
|
||||||
|
|
||||||
- [Do I have to run document-project first?](#do-i-have-to-run-document-project-first)
|
|
||||||
- [What if I forget to run document-project?](#what-if-i-forget-to-run-document-project)
|
|
||||||
- [Can I use Quick Flow for established projects?](#can-i-use-quick-flow-for-established-projects)
|
|
||||||
- [What if my existing code doesn't follow best practices?](#what-if-my-existing-code-doesnt-follow-best-practices)
|
|
||||||
|
|
||||||
### Do I have to run document-project first?
|
|
||||||
|
|
||||||
Highly recommended, especially if:
|
|
||||||
|
|
||||||
- No existing documentation
|
|
||||||
- Documentation is outdated
|
|
||||||
- AI agents need context about existing code
|
|
||||||
|
|
||||||
You can skip it if you have comprehensive, up-to-date documentation including `docs/index.md` or will use other tools or techniques to aid in discovery for the agent to build on an existing system.
|
|
||||||
|
|
||||||
### What if I forget to run document-project?
|
|
||||||
|
|
||||||
Don't worry about it - you can do it at any time. You can even do it during or after a project to help keep docs up to date.
|
|
||||||
|
|
||||||
### Can I use Quick Flow for established projects?
|
|
||||||
|
|
||||||
Yes! Quick Flow works great for established projects. It will:
|
|
||||||
|
|
||||||
- Auto-detect your existing stack
|
|
||||||
- Analyze existing code patterns
|
|
||||||
- Detect conventions and ask for confirmation
|
|
||||||
- Generate context-rich tech-spec that respects existing code
|
|
||||||
|
|
||||||
Perfect for bug fixes and small features in existing codebases.
|
|
||||||
|
|
||||||
### What if my existing code doesn't follow best practices?
|
|
||||||
|
|
||||||
Quick Flow detects your conventions and asks: "Should I follow these existing conventions?" You decide:
|
|
||||||
|
|
||||||
- **Yes** → Maintain consistency with current codebase
|
|
||||||
- **No** → Establish new standards (document why in tech-spec)
|
|
||||||
|
|
||||||
BMM respects your choice — it won't force modernization, but it will offer it.
|
|
||||||
|
|
||||||
**Have a question not answered here?** Please [open an issue](https://github.com/bmad-code-org/BMAD-METHOD/issues) or ask in [Discord](https://discord.gg/gk8jAdXWmj) so we can add it!
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
---
|
---
|
||||||
title: "Established Projects"
|
title: "Brownfield Development"
|
||||||
description: How to use BMad Method on existing codebases
|
description: How to use BMad Method on existing codebases
|
||||||
---
|
---
|
||||||
|
|
||||||
Use BMad Method effectively when working on existing projects and legacy codebases.
|
Use BMad Method effectively when working on existing projects and legacy codebases.
|
||||||
|
|
||||||
This guide covers the essential workflow for onboarding to existing projects with BMad Method.
|
## What is Brownfield Development?
|
||||||
|
|
||||||
|
**Brownfield** refers to working on existing projects with established codebases and patterns, as opposed to **greenfield** which means starting from scratch with a clean slate.
|
||||||
|
|
||||||
|
This guide covers the essential workflow for onboarding to brownfield projects with BMad Method.
|
||||||
|
|
||||||
:::note[Prerequisites]
|
:::note[Prerequisites]
|
||||||
- BMad Method installed (`npx bmad-method install`)
|
- BMad Method installed (`npx bmad-method install`)
|
||||||
|
|
@ -76,5 +80,5 @@ Pay close attention here to prevent reinventing the wheel or making decisions th
|
||||||
|
|
||||||
## More Information
|
## More Information
|
||||||
|
|
||||||
- **[Quick Fixes](/docs/how-to/quick-fixes.md)** - Bug fixes and ad-hoc changes
|
- **[Quick Fix in Brownfield](/docs/how-to/brownfield/quick-fix-in-brownfield.md)** - Bug fixes and ad-hoc changes
|
||||||
- **[Established Projects FAQ](/docs/explanation/established-projects-faq.md)** - Common questions about working on established projects
|
- **[Brownfield FAQ](/docs/explanation/brownfield-faq.md)** - Common questions about brownfield development
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
title: "Quick Fixes"
|
title: "How to Make Quick Fixes in Brownfield Projects"
|
||||||
description: How to make quick fixes and ad-hoc changes
|
description: How to make quick fixes and ad-hoc changes in brownfield projects
|
||||||
---
|
---
|
||||||
|
|
||||||
Use the **DEV agent** directly for bug fixes, refactorings, or small targeted changes that don't require the full BMad method or Quick Flow.
|
Use the **DEV agent** directly for bug fixes, refactorings, or small targeted changes that don't require the full BMad method or Quick Flow.
|
||||||
|
|
@ -73,7 +73,7 @@ Skip phases 1-3 for small, well-understood work.
|
||||||
|
|
||||||
Each document becomes context for the next phase. The PRD tells the architect what constraints matter. The architecture tells the dev agent which patterns to follow. Story files give focused, complete context for implementation. Without this structure, agents make inconsistent decisions.
|
Each document becomes context for the next phase. The PRD tells the architect what constraints matter. The architecture tells the dev agent which patterns to follow. Story files give focused, complete context for implementation. Without this structure, agents make inconsistent decisions.
|
||||||
|
|
||||||
For established projects, `document-project` creates or updates `project-context.md` - what exists in the codebase and the rules all implementation workflows must observe. Run it just before Phase 4, and again when something significant changes - structure, architecture, or those rules. You can also edit `project-context.md` by hand.
|
For brownfield projects, `document-project` creates or updates `project-context.md` - what exists in the codebase and the rules all implementation workflows must observe. Run it just before Phase 4, and again when something significant changes - structure, architecture, or those rules. You can also edit `project-context.md` by hand.
|
||||||
|
|
||||||
All implementation workflows load `project-context.md` if it exists. Additional context per workflow:
|
All implementation workflows load `project-context.md` if it exists. Additional context per workflow:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,15 +54,13 @@ Determine what was just completed:
|
||||||
|
|
||||||
1. **Load catalog** — Load `{project-root}/_bmad/_config/bmad-help.csv`
|
1. **Load catalog** — Load `{project-root}/_bmad/_config/bmad-help.csv`
|
||||||
|
|
||||||
2. **Resolve output locations and config** — Scan each folder under `_bmad/` (except `_config`) for `config.yaml`. For each workflow row, resolve its `output-location` variables against that module's config so artifact paths can be searched. Also extract `communication_language` and `project_knowledge` from each scanned module's config.
|
2. **Resolve output locations** — Scan each folder under `_bmad/` (except `_config`) for `config.yaml`. For each workflow row, resolve its `output-location` variables against that module's config so artifact paths can be searched.
|
||||||
|
|
||||||
3. **Ground in project knowledge** — If `project_knowledge` resolves to an existing path, read available documentation files (architecture docs, project overview, tech stack references) for grounding context. Use discovered project facts when composing any project-specific output. Never fabricate project-specific details — if documentation is unavailable, state so.
|
3. **Detect active module** — Use MODULE DETECTION above
|
||||||
|
|
||||||
4. **Detect active module** — Use MODULE DETECTION above
|
4. **Analyze input** — Task may provide a workflow name/code, conversational phrase, or nothing. Infer what was just completed using INPUT ANALYSIS above.
|
||||||
|
|
||||||
5. **Analyze input** — Task may provide a workflow name/code, conversational phrase, or nothing. Infer what was just completed using INPUT ANALYSIS above.
|
5. **Present recommendations** — Show next steps based on:
|
||||||
|
|
||||||
6. **Present recommendations** — Show next steps based on:
|
|
||||||
- Completed workflows detected
|
- Completed workflows detected
|
||||||
- Phase/sequence ordering (ROUTING RULES)
|
- Phase/sequence ordering (ROUTING RULES)
|
||||||
- Artifact presence
|
- Artifact presence
|
||||||
|
|
@ -76,10 +74,9 @@ Determine what was just completed:
|
||||||
- **Agent** title and display name from the CSV (e.g., "🎨 Alex (Designer)")
|
- **Agent** title and display name from the CSV (e.g., "🎨 Alex (Designer)")
|
||||||
- Brief **description**
|
- Brief **description**
|
||||||
|
|
||||||
7. **Additional guidance to convey**:
|
6. **Additional guidance to convey**:
|
||||||
- Present all output in `{communication_language}`
|
|
||||||
- Run each workflow in a **fresh context window**
|
- Run each workflow in a **fresh context window**
|
||||||
- For **validation workflows**: recommend using a different high-quality LLM if available
|
- For **validation workflows**: recommend using a different high-quality LLM if available
|
||||||
- For conversational requests: match the user's tone while presenting clearly
|
- For conversational requests: match the user's tone while presenting clearly
|
||||||
|
|
||||||
8. Return to the calling process after presenting recommendations.
|
7. Return to the calling process after presenting recommendations.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { BaseIdeSetup } = require('./_base-ide');
|
const { BaseIdeSetup } = require('./_base-ide');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const yaml = require('yaml');
|
|
||||||
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
||||||
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
|
|
||||||
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KiloCode IDE setup handler
|
* KiloCode IDE setup handler
|
||||||
|
|
@ -25,94 +22,76 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
async setup(projectDir, bmadDir, options = {}) {
|
async setup(projectDir, bmadDir, options = {}) {
|
||||||
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
||||||
|
|
||||||
// Clean up any old BMAD installation first
|
// Check for existing .kilocodemodes file
|
||||||
await this.cleanup(projectDir);
|
|
||||||
|
|
||||||
// Load existing config (may contain non-BMAD modes and other settings)
|
|
||||||
const kiloModesPath = path.join(projectDir, this.configFile);
|
const kiloModesPath = path.join(projectDir, this.configFile);
|
||||||
let config = {};
|
let existingModes = [];
|
||||||
|
let existingContent = '';
|
||||||
|
|
||||||
if (await this.pathExists(kiloModesPath)) {
|
if (await this.pathExists(kiloModesPath)) {
|
||||||
const existingContent = await this.readFile(kiloModesPath);
|
existingContent = await this.readFile(kiloModesPath);
|
||||||
try {
|
// Parse existing modes
|
||||||
config = yaml.parse(existingContent) || {};
|
const modeMatches = existingContent.matchAll(/- slug: ([\w-]+)/g);
|
||||||
} catch {
|
for (const match of modeMatches) {
|
||||||
// If parsing fails, start fresh but warn user
|
existingModes.push(match[1]);
|
||||||
console.log(chalk.yellow('Warning: Could not parse existing .kilocodemodes, starting fresh'));
|
|
||||||
config = {};
|
|
||||||
}
|
}
|
||||||
}
|
console.log(chalk.yellow(`Found existing .kilocodemodes file with ${existingModes.length} modes`));
|
||||||
|
|
||||||
// Ensure customModes array exists
|
|
||||||
if (!Array.isArray(config.customModes)) {
|
|
||||||
config.customModes = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate agent launchers
|
// Generate agent launchers
|
||||||
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
||||||
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
||||||
|
|
||||||
// Create mode objects and add to config
|
// Create modes content
|
||||||
|
let newModesContent = '';
|
||||||
let addedCount = 0;
|
let addedCount = 0;
|
||||||
|
let skippedCount = 0;
|
||||||
|
|
||||||
for (const artifact of agentArtifacts) {
|
for (const artifact of agentArtifacts) {
|
||||||
const modeObject = await this.createModeObject(artifact, projectDir);
|
const slug = `bmad-${artifact.module}-${artifact.name}`;
|
||||||
config.customModes.push(modeObject);
|
|
||||||
|
// Skip if already exists
|
||||||
|
if (existingModes.includes(slug)) {
|
||||||
|
console.log(chalk.dim(` Skipping ${slug} - already exists`));
|
||||||
|
skippedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const modeEntry = await this.createModeEntry(artifact, projectDir);
|
||||||
|
|
||||||
|
newModesContent += modeEntry;
|
||||||
addedCount++;
|
addedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write .kilocodemodes file with proper YAML structure
|
// Build final content
|
||||||
const finalContent = yaml.stringify(config, { lineWidth: 0 });
|
let finalContent = '';
|
||||||
|
if (existingContent) {
|
||||||
|
finalContent = existingContent.trim() + '\n' + newModesContent;
|
||||||
|
} else {
|
||||||
|
finalContent = 'customModes:\n' + newModesContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write .kilocodemodes file
|
||||||
await this.writeFile(kiloModesPath, finalContent);
|
await this.writeFile(kiloModesPath, finalContent);
|
||||||
|
|
||||||
// Generate workflow commands
|
|
||||||
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
|
|
||||||
const { artifacts: workflowArtifacts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
|
|
||||||
|
|
||||||
// Write to .kilocode/workflows/ directory
|
|
||||||
const workflowsDir = path.join(projectDir, '.kilocode', 'workflows');
|
|
||||||
await this.ensureDir(workflowsDir);
|
|
||||||
|
|
||||||
// Clear old BMAD workflows before writing new ones
|
|
||||||
await this.clearBmadWorkflows(workflowsDir);
|
|
||||||
|
|
||||||
// Write workflow files
|
|
||||||
const workflowCount = await workflowGenerator.writeDashArtifacts(workflowsDir, workflowArtifacts);
|
|
||||||
|
|
||||||
// Generate task and tool commands
|
|
||||||
const taskToolGen = new TaskToolCommandGenerator(this.bmadFolderName);
|
|
||||||
const { artifacts: taskToolArtifacts, counts: taskToolCounts } = await taskToolGen.collectTaskToolArtifacts(bmadDir);
|
|
||||||
|
|
||||||
// Write task/tool files to workflows directory (same location as workflows)
|
|
||||||
await taskToolGen.writeDashArtifacts(workflowsDir, taskToolArtifacts);
|
|
||||||
const taskCount = taskToolCounts.tasks || 0;
|
|
||||||
const toolCount = taskToolCounts.tools || 0;
|
|
||||||
|
|
||||||
console.log(chalk.green(`✓ ${this.name} configured:`));
|
console.log(chalk.green(`✓ ${this.name} configured:`));
|
||||||
console.log(chalk.dim(` - ${addedCount} modes added`));
|
console.log(chalk.dim(` - ${addedCount} modes added`));
|
||||||
console.log(chalk.dim(` - ${workflowCount} workflows exported`));
|
if (skippedCount > 0) {
|
||||||
console.log(chalk.dim(` - ${taskCount} tasks exported`));
|
console.log(chalk.dim(` - ${skippedCount} modes skipped (already exist)`));
|
||||||
console.log(chalk.dim(` - ${toolCount} tools exported`));
|
}
|
||||||
console.log(chalk.dim(` - Configuration file: ${this.configFile}`));
|
console.log(chalk.dim(` - Configuration file: ${this.configFile}`));
|
||||||
console.log(chalk.dim(` - Workflows directory: .kilocode/workflows/`));
|
|
||||||
console.log(chalk.dim('\n Modes will be available when you open this project in KiloCode'));
|
console.log(chalk.dim('\n Modes will be available when you open this project in KiloCode'));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
modes: addedCount,
|
modes: addedCount,
|
||||||
workflows: workflowCount,
|
skipped: skippedCount,
|
||||||
tasks: taskCount,
|
|
||||||
tools: toolCount,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mode object for an agent
|
* Create a mode entry for an agent
|
||||||
* @param {Object} artifact - Agent artifact
|
|
||||||
* @param {string} projectDir - Project directory
|
|
||||||
* @returns {Object} Mode object for YAML serialization
|
|
||||||
*/
|
*/
|
||||||
async createModeObject(artifact, projectDir) {
|
async createModeEntry(artifact, projectDir) {
|
||||||
// Extract metadata from launcher content
|
// Extract metadata from launcher content
|
||||||
const titleMatch = artifact.content.match(/title="([^"]+)"/);
|
const titleMatch = artifact.content.match(/title="([^"]+)"/);
|
||||||
const title = titleMatch ? titleMatch[1] : this.formatTitle(artifact.name);
|
const title = titleMatch ? titleMatch[1] : this.formatTitle(artifact.name);
|
||||||
|
|
@ -123,8 +102,8 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
const whenToUseMatch = artifact.content.match(/whenToUse="([^"]+)"/);
|
const whenToUseMatch = artifact.content.match(/whenToUse="([^"]+)"/);
|
||||||
const whenToUse = whenToUseMatch ? whenToUseMatch[1] : `Use for ${title} tasks`;
|
const whenToUse = whenToUseMatch ? whenToUseMatch[1] : `Use for ${title} tasks`;
|
||||||
|
|
||||||
// Get the activation header from central template (trim to avoid YAML formatting issues)
|
// Get the activation header from central template
|
||||||
const activationHeader = (await this.getAgentCommandHeader()).trim();
|
const activationHeader = await this.getAgentCommandHeader();
|
||||||
|
|
||||||
const roleDefinitionMatch = artifact.content.match(/roleDefinition="([^"]+)"/);
|
const roleDefinitionMatch = artifact.content.match(/roleDefinition="([^"]+)"/);
|
||||||
const roleDefinition = roleDefinitionMatch
|
const roleDefinition = roleDefinitionMatch
|
||||||
|
|
@ -134,15 +113,22 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
// Get relative path
|
// Get relative path
|
||||||
const relativePath = path.relative(projectDir, artifact.sourcePath).replaceAll('\\', '/');
|
const relativePath = path.relative(projectDir, artifact.sourcePath).replaceAll('\\', '/');
|
||||||
|
|
||||||
// Build mode object (KiloCode uses same schema as Roo)
|
// Build mode entry (KiloCode uses same schema as Roo)
|
||||||
return {
|
const slug = `bmad-${artifact.module}-${artifact.name}`;
|
||||||
slug: `bmad-${artifact.module}-${artifact.name}`,
|
let modeEntry = ` - slug: ${slug}\n`;
|
||||||
name: `${icon} ${title}`,
|
modeEntry += ` name: '${icon} ${title}'\n`;
|
||||||
roleDefinition: roleDefinition,
|
modeEntry += ` roleDefinition: ${roleDefinition}\n`;
|
||||||
whenToUse: whenToUse,
|
modeEntry += ` whenToUse: ${whenToUse}\n`;
|
||||||
customInstructions: `${activationHeader} Read the full YAML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode\n`,
|
modeEntry += ` customInstructions: |\n`;
|
||||||
groups: ['read', 'edit', 'browser', 'command', 'mcp'],
|
modeEntry += ` ${activationHeader} Read the full YAML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode\n`;
|
||||||
};
|
modeEntry += ` groups:\n`;
|
||||||
|
modeEntry += ` - read\n`;
|
||||||
|
modeEntry += ` - edit\n`;
|
||||||
|
modeEntry += ` - browser\n`;
|
||||||
|
modeEntry += ` - command\n`;
|
||||||
|
modeEntry += ` - mcp\n`;
|
||||||
|
|
||||||
|
return modeEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -155,22 +141,6 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
.join(' ');
|
.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear old BMAD workflow files from workflows directory
|
|
||||||
* @param {string} workflowsDir - Workflows directory path
|
|
||||||
*/
|
|
||||||
async clearBmadWorkflows(workflowsDir) {
|
|
||||||
const fs = require('fs-extra');
|
|
||||||
if (!(await fs.pathExists(workflowsDir))) return;
|
|
||||||
|
|
||||||
const entries = await fs.readdir(workflowsDir);
|
|
||||||
for (const entry of entries) {
|
|
||||||
if (entry.startsWith('bmad-') && entry.endsWith('.md')) {
|
|
||||||
await fs.remove(path.join(workflowsDir, entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup KiloCode configuration
|
* Cleanup KiloCode configuration
|
||||||
*/
|
*/
|
||||||
|
|
@ -181,30 +151,29 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
if (await fs.pathExists(kiloModesPath)) {
|
if (await fs.pathExists(kiloModesPath)) {
|
||||||
const content = await fs.readFile(kiloModesPath, 'utf8');
|
const content = await fs.readFile(kiloModesPath, 'utf8');
|
||||||
|
|
||||||
try {
|
// Remove BMAD modes only
|
||||||
const config = yaml.parse(content) || {};
|
const lines = content.split('\n');
|
||||||
|
const filteredLines = [];
|
||||||
|
let skipMode = false;
|
||||||
|
let removedCount = 0;
|
||||||
|
|
||||||
if (Array.isArray(config.customModes)) {
|
for (const line of lines) {
|
||||||
const originalCount = config.customModes.length;
|
if (/^\s*- slug: bmad-/.test(line)) {
|
||||||
// Remove BMAD modes only (keep non-BMAD modes)
|
skipMode = true;
|
||||||
config.customModes = config.customModes.filter((mode) => !mode.slug || !mode.slug.startsWith('bmad-'));
|
removedCount++;
|
||||||
const removedCount = originalCount - config.customModes.length;
|
} else if (skipMode && /^\s*- slug: /.test(line)) {
|
||||||
|
skipMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (removedCount > 0) {
|
if (!skipMode) {
|
||||||
await fs.writeFile(kiloModesPath, yaml.stringify(config, { lineWidth: 0 }));
|
filteredLines.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(kiloModesPath, filteredLines.join('\n'));
|
||||||
console.log(chalk.dim(`Removed ${removedCount} BMAD modes from .kilocodemodes`));
|
console.log(chalk.dim(`Removed ${removedCount} BMAD modes from .kilocodemodes`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
// If parsing fails, leave file as-is
|
|
||||||
console.log(chalk.yellow('Warning: Could not parse .kilocodemodes for cleanup'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up workflow files
|
|
||||||
const workflowsDir = path.join(projectDir, '.kilocode', 'workflows');
|
|
||||||
await this.clearBmadWorkflows(workflowsDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install a custom agent launcher for Kilo
|
* Install a custom agent launcher for Kilo
|
||||||
|
|
@ -216,28 +185,31 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
*/
|
*/
|
||||||
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
|
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
|
||||||
const kilocodemodesPath = path.join(projectDir, this.configFile);
|
const kilocodemodesPath = path.join(projectDir, this.configFile);
|
||||||
let config = {};
|
let existingContent = '';
|
||||||
|
|
||||||
// Read existing .kilocodemodes file
|
// Read existing .kilocodemodes file
|
||||||
if (await this.pathExists(kilocodemodesPath)) {
|
if (await this.pathExists(kilocodemodesPath)) {
|
||||||
const existingContent = await this.readFile(kilocodemodesPath);
|
existingContent = await this.readFile(kilocodemodesPath);
|
||||||
try {
|
|
||||||
config = yaml.parse(existingContent) || {};
|
|
||||||
} catch {
|
|
||||||
config = {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure customModes array exists
|
// Create custom agent mode entry
|
||||||
if (!Array.isArray(config.customModes)) {
|
|
||||||
config.customModes = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create custom agent mode object
|
|
||||||
const slug = `bmad-custom-${agentName.toLowerCase()}`;
|
const slug = `bmad-custom-${agentName.toLowerCase()}`;
|
||||||
|
const modeEntry = ` - slug: ${slug}
|
||||||
|
name: 'BMAD Custom: ${agentName}'
|
||||||
|
description: |
|
||||||
|
Custom BMAD agent: ${agentName}
|
||||||
|
|
||||||
|
**⚠️ IMPORTANT**: Run @${agentPath} first to load the complete agent!
|
||||||
|
|
||||||
|
This is a launcher for the custom BMAD agent "${agentName}". The agent will follow the persona and instructions from the main agent file.
|
||||||
|
prompt: |
|
||||||
|
@${agentPath}
|
||||||
|
always: false
|
||||||
|
permissions: all
|
||||||
|
`;
|
||||||
|
|
||||||
// Check if mode already exists
|
// Check if mode already exists
|
||||||
if (config.customModes.some((mode) => mode.slug === slug)) {
|
if (existingContent.includes(slug)) {
|
||||||
return {
|
return {
|
||||||
ide: 'kilo',
|
ide: 'kilo',
|
||||||
path: this.configFile,
|
path: this.configFile,
|
||||||
|
|
@ -247,18 +219,24 @@ class KiloSetup extends BaseIdeSetup {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom mode object
|
// Build final content
|
||||||
config.customModes.push({
|
let finalContent = '';
|
||||||
slug: slug,
|
if (existingContent) {
|
||||||
name: `BMAD Custom: ${agentName}`,
|
// Find customModes section or add it
|
||||||
description: `Custom BMAD agent: ${agentName}\n\n**⚠️ IMPORTANT**: Run @${agentPath} first to load the complete agent!\n\nThis is a launcher for the custom BMAD agent "${agentName}". The agent will follow the persona and instructions from the main agent file.\n`,
|
if (existingContent.includes('customModes:')) {
|
||||||
prompt: `@${agentPath}\n`,
|
// Append to existing customModes
|
||||||
always: false,
|
finalContent = existingContent + modeEntry;
|
||||||
permissions: 'all',
|
} else {
|
||||||
});
|
// Add customModes section
|
||||||
|
finalContent = existingContent.trim() + '\n\ncustomModes:\n' + modeEntry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create new .kilocodemodes file with customModes
|
||||||
|
finalContent = 'customModes:\n' + modeEntry;
|
||||||
|
}
|
||||||
|
|
||||||
// Write .kilocodemodes file with proper YAML structure
|
// Write .kilocodemodes file
|
||||||
await this.writeFile(kilocodemodesPath, yaml.stringify(config, { lineWidth: 0 }));
|
await this.writeFile(kilocodemodesPath, finalContent);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ide: 'kilo',
|
ide: 'kilo',
|
||||||
|
|
|
||||||
|
|
@ -124,13 +124,8 @@ platforms:
|
||||||
category: ide
|
category: ide
|
||||||
description: "OpenCode terminal coding assistant"
|
description: "OpenCode terminal coding assistant"
|
||||||
installer:
|
installer:
|
||||||
targets:
|
target_dir: .opencode/command
|
||||||
- target_dir: .opencode/agent
|
|
||||||
template_type: opencode
|
template_type: opencode
|
||||||
artifact_types: [agents]
|
|
||||||
- target_dir: .opencode/command
|
|
||||||
template_type: opencode
|
|
||||||
artifact_types: [workflows, tasks, tools]
|
|
||||||
|
|
||||||
qwen:
|
qwen:
|
||||||
name: "QwenCoder"
|
name: "QwenCoder"
|
||||||
|
|
|
||||||
|
|
@ -417,7 +417,7 @@ class ModuleManager {
|
||||||
if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
|
if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
|
||||||
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
|
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
|
||||||
try {
|
try {
|
||||||
execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', {
|
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress --legacy-peer-deps', {
|
||||||
cwd: moduleCacheDir,
|
cwd: moduleCacheDir,
|
||||||
stdio: 'pipe',
|
stdio: 'pipe',
|
||||||
timeout: 120_000, // 2 minute timeout
|
timeout: 120_000, // 2 minute timeout
|
||||||
|
|
@ -442,7 +442,7 @@ class ModuleManager {
|
||||||
if (packageJsonNewer) {
|
if (packageJsonNewer) {
|
||||||
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
|
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
|
||||||
try {
|
try {
|
||||||
execSync('npm install --omit=dev --no-audit --no-fund --no-progress --legacy-peer-deps', {
|
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress --legacy-peer-deps', {
|
||||||
cwd: moduleCacheDir,
|
cwd: moduleCacheDir,
|
||||||
stdio: 'pipe',
|
stdio: 'pipe',
|
||||||
timeout: 120_000, // 2 minute timeout
|
timeout: 120_000, // 2 minute timeout
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue