Compare commits

...

7 Commits

Author SHA1 Message Date
Nikolas Hor 09ca2269a7
Merge b696e9a246 into 303e7ae290 2026-03-23 22:30:12 +00:00
Murat K Ozcan 303e7ae290
fix: issue 55 config paths (#2113)
* fix: issue 55 config paths

* Fix: ci test failure
2026-03-23 15:55:19 -05:00
Alex Verkhovsky 48152507e2
fix(quick-dev): remove redundant H1 title from spec template (#2111)
The frontmatter `title` field is the single source of truth.
The duplicate `# {title}` H1 heading was redundant and has been removed.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 01:51:53 -06:00
Alex Verkhovsky b3cf338118
refactor(quick-dev): rename tech-spec prefix to spec (#2109)
* refactor(quick-dev): rename tech-spec prefix to spec

* docs: update tech-spec references to spec
2026-03-23 00:09:05 -06:00
Alex Verkhovsky fc2b253ab5
fix(quick-dev): preserve tracking identifiers in spec slug derivation (#2108)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 23:40:44 -06:00
Alex Verkhovsky ac5cb9de5c
refactor(quick-dev): replace unconditional artifact scan with intent cascade (#2105)
Short-circuit evaluation in step-01: explicit argument → conversation
context → full artifact scan. Stops prompting as soon as intent is
unambiguous. All existing scan behaviors preserved in tier 3.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 22:40:04 -06:00
Nikolas de Hor b696e9a246 fix: use double quotes in skill templates to prevent YAML parse errors
Default skill templates used single-quoted YAML values for name
and description fields. When descriptions contain apostrophes
(e.g., "agent's workflow"), the generated YAML frontmatter would
be invalid, causing parse failures in IDEs like Antigravity.

Switches templates to double quotes and escapes any double quotes
in the description during template rendering.

Fixes #1744
2026-03-11 19:40:24 -03:00
19 changed files with 249 additions and 62 deletions

View File

@ -56,7 +56,7 @@ Critical warnings only — data loss, security issues
| Phase | Name | What Happens |
| ----- | -------- | -------------------------------------------- |
| 1 | Analysis | Brainstorm, research *(optional)* |
| 2 | Planning | Requirements — PRD or tech-spec *(required)* |
| 2 | Planning | Requirements — PRD or spec *(required)* |
```
**Skills:**

View File

@ -34,7 +34,7 @@ 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
- Generate context-rich spec that respects existing code
Perfect for bug fixes and small features in existing codebases.
@ -43,7 +43,7 @@ Perfect for bug fixes and small features in existing codebases.
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)
- **No** → Establish new standards (document why in spec)
BMM respects your choice — it won't force modernization, but it will offer it.

View File

@ -25,7 +25,7 @@ Every implementation workflow automatically loads `project-context.md` if it exi
- `bmad-create-story` — informs story creation with project patterns
- `bmad-dev-story` — guides implementation decisions
- `bmad-code-review` — validates against project standards
- `bmad-quick-dev` — applies patterns when implementing tech-specs
- `bmad-quick-dev` — applies patterns when implementing specs
- `bmad-sprint-planning`, `bmad-retrospective`, `bmad-correct-course` — provides project-wide context
## When to Create It

View File

@ -68,7 +68,7 @@ Sautez les phases 1-3 pour les travaux de faible envergure et bien compris.
| Workflow | Objectif | Produit |
|------------------|-------------------------------------------------------------------------------------|-----------------------|
| `bmad-quick-dev` | Flux rapide unifié — clarifie l'intention, planifie, implémente, révise et présente | `tech-spec.md` + code |
| `bmad-quick-dev` | Flux rapide unifié — clarifie l'intention, planifie, implémente, révise et présente | `spec-*.md` + code |
## Gestion du Contexte

View File

@ -233,7 +233,7 @@ your-project/
## Questions fréquentes
**Ai-je toujours besoin d'une architecture ?**
Uniquement pour les voies méthode BMad et Enterprise. Quick Dev passe directement de la spécification technique (tech-spec) à l'implémentation.
Uniquement pour les voies méthode BMad et Enterprise. Quick Dev passe directement de la spécification technique (spec) à l'implémentation.
**Puis-je modifier mon plan plus tard ?**
Oui. Utilisez `bmad-correct-course` pour gérer les changements de périmètre.

View File

@ -68,7 +68,7 @@ Skip phases 1-3 for small, well-understood work.
| Workflow | Purpose | Produces |
| ------------------ | --------------------------------------------------------------------------- | ---------------------- |
| `bmad-quick-dev` | Unified quick flow — clarify intent, plan, implement, review, and present | `tech-spec.md` + code |
| `bmad-quick-dev` | Unified quick flow — clarify intent, plan, implement, review, and present | `spec-*.md` + code |
## Context Management

View File

@ -69,7 +69,7 @@ BMad helps you build software through guided workflows with specialized AI agent
| Phase | Name | What Happens |
| ----- | -------------- | --------------------------------------------------- |
| 1 | Analysis | Brainstorming, research, product brief *(optional)* |
| 2 | Planning | Create requirements (PRD or tech-spec) |
| 2 | Planning | Create requirements (PRD or spec) |
| 3 | Solutioning | Design architecture *(BMad Method/Enterprise only)* |
| 4 | Implementation | Build epic by epic, story by story |
@ -237,7 +237,7 @@ your-project/
## Common Questions
**Do I always need architecture?**
Only for BMad Method and Enterprise tracks. Quick Flow skips from tech-spec to implementation.
Only for BMad Method and Enterprise tracks. Quick Flow skips from spec to implementation.
**Can I change my plan later?**
Yes. The SM agent has a `bmad-correct-course` workflow (`bmad-correct-course`) for handling scope changes.

View File

@ -56,7 +56,7 @@ Critical warnings only — data loss, security issues
| Phase | Name | What Happens |
| ----- | -------- | -------------------------------------------- |
| 1 | Analysis | Brainstorm, research *(optional)* |
| 2 | Planning | Requirements — PRD or tech-spec *(required)* |
| 2 | Planning | Requirements — PRD or spec *(required)* |
```
**Commands:**

View File

@ -54,7 +54,7 @@ BMM 尊重你的选择——它不会强制现代化,但会提供现代化选
- **agent**:智能体。在人工智能与编程文档中,指具备自主决策或执行能力的单元。
- **Quick Flow**快速流程。BMad 方法中的一种工作流程,用于快速处理既有项目。
- **tech-spec**技术规范。描述技术实现细节和标准的文档。
- **spec**:规范。描述技术实现细节和标准的文档。
- **stack**:技术栈。项目所使用的技术组合,包括框架、库、工具等。
- **conventions**:约定。代码库中遵循的编码风格、命名规则等规范。
- **modernization**:现代化。将旧代码或系统更新为更现代的技术和最佳实践的过程。

View File

@ -68,7 +68,7 @@ BMad MethodBMM是 BMad 生态系统中的一个模块,旨在遵循上下
| 工作流程 | 目的 | 产出 |
| --------------------- | --------------------------------------------------------------------------- | --------------------------- |
| `bmad-bmm-quick-dev` | 统一快速流程 — 澄清意图、规划、实现、审查和呈现 | `tech-spec.md` + 代码 |
| `bmad-bmm-quick-dev` | 统一快速流程 — 澄清意图、规划、实现、审查和呈现 | `spec-*.md` + 代码 |
## 上下文管理

View File

@ -36,7 +36,7 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
| Epics | `{planning_artifacts}/*epic*.md` (whole) or `{planning_artifacts}/*epic*/*.md` (sharded) | FULL_LOAD |
| Architecture | `{planning_artifacts}/*architecture*.md` (whole) or `{planning_artifacts}/*architecture*/*.md` (sharded) | FULL_LOAD |
| UX Design | `{planning_artifacts}/*ux*.md` (whole) or `{planning_artifacts}/*ux*/*.md` (sharded) | FULL_LOAD |
| Tech Spec | `{planning_artifacts}/*tech-spec*.md` (whole) | FULL_LOAD |
| Spec | `{planning_artifacts}/*spec-*.md` (whole) | FULL_LOAD |
| Document Project | `{project_knowledge}/index.md` (sharded) | INDEX_GUIDED |
### Context
@ -51,9 +51,9 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
**Strategy**: Course correction needs broad project context to assess change impact accurately. Load all available planning artifacts.
**Discovery Process for FULL_LOAD documents (PRD, Epics, Architecture, UX Design, Tech Spec):**
**Discovery Process for FULL_LOAD documents (PRD, Epics, Architecture, UX Design, Spec):**
1. **Search for whole document first** - Look for files matching the whole-document pattern (e.g., `*prd*.md`, `*epic*.md`, `*architecture*.md`, `*ux*.md`, `*tech-spec*.md`)
1. **Search for whole document first** - Look for files matching the whole-document pattern (e.g., `*prd*.md`, `*epic*.md`, `*architecture*.md`, `*ux*.md`, `*spec-*.md`)
2. **Check for sharded version** - If whole document not found, look for a directory with `index.md` (e.g., `prd/index.md`, `epics/index.md`)
3. **If sharded version found**:
- Read `index.md` to understand the document structure
@ -70,7 +70,7 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
**Fuzzy matching**: Be flexible with document names — users may use variations like `prd.md`, `bmm-prd.md`, `product-requirements.md`, etc.
**Missing documents**: Not all documents may exist. PRD and Epics are essential; Architecture, UX Design, Tech Spec, and Document Project are loaded if available. HALT if PRD or Epics cannot be found.
**Missing documents**: Not all documents may exist. PRD and Epics are essential; Architecture, UX Design, Spec, and Document Project are loaded if available. HALT if PRD or Epics cannot be found.
<workflow>

View File

@ -11,8 +11,6 @@ context: [] # optional: max 3 project-wide standards/docs. NO source code files.
Cohesive cross-layer stories (DB+BE+UI) stay in ONE file.
IMPORTANT: Remove all HTML comments when filling this template. -->
# {title}
<frozen-after-approval reason="human-owned intent — do not modify unless human renegotiates">
## Intent

View File

@ -1,5 +1,5 @@
---
wipFile: '{implementation_artifacts}/tech-spec-wip.md'
wipFile: '{implementation_artifacts}/spec-wip.md'
deferred_work_file: '{implementation_artifacts}/deferred-work.md'
spec_file: '' # set at runtime for plan-code-review before leaving this step
---
@ -15,13 +15,27 @@ spec_file: '' # set at runtime for plan-code-review before leaving this step
- The user chose this workflow on purpose. Later steps (e.g. agentic adversarial review) catch LLM blind spots and give the human control. Do not skip them.
- **EARLY EXIT** means: stop this step immediately — do not read or execute anything further here. Read and fully follow the target file instead. Return here ONLY if a later step explicitly says to loop back.
## ARTIFACT SCAN
## Intent check (do this first)
- `{wipFile}` exists? → Offer resume or archive.
- Active specs (`ready-for-dev`, `in-progress`, `in-review`) in `{implementation_artifacts}`? → List them and HALT. Ask user which to resume (or `[N]` for new).
- If `ready-for-dev` or `in-progress` selected: Set `spec_file`. **EARLY EXIT**`./step-03-implement.md`
- If `in-review` selected: Set `spec_file`. **EARLY EXIT**`./step-04-review.md`
- Unformatted spec or intent file lacking `status` frontmatter in `{implementation_artifacts}`? → Suggest to the user to treat its contents as the starting intent for this workflow. DO NOT attempt to infer a state and resume it.
Before listing artifacts or prompting the user, check whether you already know the intent. Check in this order — skip the remaining checks as soon as the intent is clear:
1. Explicit argument
Did the user pass a specific file path, spec name, or clear instruction this message?
- If it points to a file that matches the spec template (has `status` frontmatter with a recognized value: ready-for-dev, in-progress, or in-review) → set `spec_file` and **EARLY EXIT** to the appropriate step (step-03 for ready/in-progress, step-04 for review).
- Anything else (intent files, external docs, plans, descriptions) → ingest it as starting intent and proceed to INSTRUCTIONS. Do not attempt to infer a workflow state from it.
2. Recent conversation
Do the last few human messages clearly show what the user intends to work on?
Use the same routing as above.
3. Otherwise — scan artifacts and ask
- `{wipFile}` exists? → Offer resume or archive.
- Active specs (`ready-for-dev`, `in-progress`, `in-review`) in `{implementation_artifacts}`? → List them and HALT. Ask user which to resume (or `[N]` for new).
- If `ready-for-dev` or `in-progress` selected: Set `spec_file`. **EARLY EXIT**`./step-03-implement.md`
- If `in-review` selected: Set `spec_file`. **EARLY EXIT**`./step-04-review.md`
- Unformatted spec or intent file lacking `status` frontmatter? → Suggest treating its contents as the starting intent. Do NOT attempt to infer a state and resume it.
Never ask extra questions if you already understand what the user intends.
## INSTRUCTIONS
@ -42,7 +56,7 @@ spec_file: '' # set at runtime for plan-code-review before leaving this step
**EARLY EXIT**`./step-oneshot.md`
**b) Plan-code-review** — everything else. When uncertain whether blast radius is truly zero, choose this path.
1. Derive a valid kebab-case slug from the clarified intent. If `{implementation_artifacts}/tech-spec-{slug}.md` already exists, append `-2`, `-3`, etc. Set `spec_file` = `{implementation_artifacts}/tech-spec-{slug}.md`.
1. Derive a valid kebab-case slug from the clarified intent. If the intent references a tracking identifier (story number, issue number, ticket ID), lead the slug with it (e.g. `3-2-digest-delivery`, `gh-47-fix-auth`). If `{implementation_artifacts}/spec-{slug}.md` already exists, append `-2`, `-3`, etc. Set `spec_file` = `{implementation_artifacts}/spec-{slug}.md`.
## NEXT

View File

@ -1,5 +1,5 @@
---
wipFile: '{implementation_artifacts}/tech-spec-wip.md'
wipFile: '{implementation_artifacts}/spec-wip.md'
deferred_work_file: '{implementation_artifacts}/deferred-work.md'
---
@ -13,7 +13,7 @@ deferred_work_file: '{implementation_artifacts}/deferred-work.md'
## INSTRUCTIONS
1. Investigate codebase. _Isolate deep exploration in sub-agents/tasks where available. To prevent context snowballing, instruct subagents to give you distilled summaries only._
2. Read `./tech-spec-template.md` fully. Fill it out based on the intent and investigation, and write the result to `{wipFile}`.
2. Read `./spec-template.md` fully. Fill it out based on the intent and investigation, and write the result to `{wipFile}`.
3. Self-review against READY FOR DEVELOPMENT standard.
4. If intent gaps exist, do not fantasize, do not leave open questions, HALT and ask the human.
5. Token count check (see SCOPE STANDARD). If spec exceeds 1600 tokens:

View File

@ -72,7 +72,7 @@ YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `
### 2. Paths
- `wipFile` = `{implementation_artifacts}/tech-spec-wip.md`
- `wipFile` = `{implementation_artifacts}/spec-wip.md`
### 3. First Step Execution

View File

@ -1,7 +1,7 @@
module,phase,name,code,sequence,workflow-file,command,required,agent,options,description,output-location,outputs,
bmm,anytime,Document Project,DP,,skill:bmad-document-project,bmad-bmm-document-project,false,analyst,Create Mode,"Analyze an existing project to produce useful documentation",project-knowledge,*,
bmm,anytime,Generate Project Context,GPC,,skill:bmad-generate-project-context,bmad-bmm-generate-project-context,false,analyst,Create Mode,"Scan existing codebase to generate a lean LLM-optimized project-context.md containing critical implementation rules patterns and conventions for AI agents. Essential for brownfield projects and quick-flow.",output_folder,"project context",
bmm,anytime,Quick Dev,QQ,,skill:bmad-quick-dev,bmad-bmm-quick-dev,false,quick-flow-solo-dev,Create Mode,"Unified quick flow: clarify intent plan implement review and present in a single workflow",implementation_artifacts,"tech spec and project implementation",
bmm,anytime,Generate Project Context,GPC,,skill:bmad-generate-project-context,bmad-bmm-generate-project-context,false,analyst,Create Mode,"Scan existing codebase to generate a lean LLM-optimized project-context.md containing critical implementation rules patterns and conventions for AI agents. Essential for brownfield projects.",output_folder,"project context",
bmm,anytime,Quick Dev,QQ,,skill:bmad-quick-dev,bmad-bmm-quick-dev,false,quick-flow-solo-dev,Create Mode,"Unified intent-in code-out workflow: clarify plan implement review and present",implementation_artifacts,"spec and project implementation",
bmm,anytime,Correct Course,CC,,skill:bmad-correct-course,bmad-bmm-correct-course,false,sm,Create Mode,"Anytime: Navigate significant changes. May recommend start over update PRD redo architecture sprint planning or correct epics and stories",planning_artifacts,"change proposal",
bmm,anytime,Write Document,WD,,skill:bmad-agent-tech-writer,,false,tech-writer,,"Describe in detail what you want, and the agent will follow the documentation best practices defined in agent memory. Multi-turn conversation with subprocess for research/review.",project-knowledge,"document",
bmm,anytime,Update Standards,US,,skill:bmad-agent-tech-writer,,false,tech-writer,,"Update agent memory documentation-standards.md with your specific preferences if you discover missing document conventions.",_bmad/_memory/tech-writer-sidecar,"standards",

1 module phase name code sequence workflow-file command required agent options description output-location outputs
2 bmm anytime Document Project DP skill:bmad-document-project bmad-bmm-document-project false analyst Create Mode Analyze an existing project to produce useful documentation project-knowledge *
3 bmm anytime Generate Project Context GPC skill:bmad-generate-project-context bmad-bmm-generate-project-context false analyst Create Mode Scan existing codebase to generate a lean LLM-optimized project-context.md containing critical implementation rules patterns and conventions for AI agents. Essential for brownfield projects and quick-flow. Scan existing codebase to generate a lean LLM-optimized project-context.md containing critical implementation rules patterns and conventions for AI agents. Essential for brownfield projects. output_folder project context
4 bmm anytime Quick Dev QQ skill:bmad-quick-dev bmad-bmm-quick-dev false quick-flow-solo-dev Create Mode Unified quick flow: clarify intent plan implement review and present in a single workflow Unified intent-in code-out workflow: clarify plan implement review and present implementation_artifacts tech spec and project implementation spec and project implementation
5 bmm anytime Correct Course CC skill:bmad-correct-course bmad-bmm-correct-course false sm Create Mode Anytime: Navigate significant changes. May recommend start over update PRD redo architecture sprint planning or correct epics and stories planning_artifacts change proposal
6 bmm anytime Write Document WD skill:bmad-agent-tech-writer false tech-writer Describe in detail what you want, and the agent will follow the documentation best practices defined in agent memory. Multi-turn conversation with subprocess for research/review. project-knowledge document
7 bmm anytime Update Standards US skill:bmad-agent-tech-writer false tech-writer Update agent memory documentation-standards.md with your specific preferences if you discover missing document conventions. _bmad/_memory/tech-writer-sidecar standards

View File

@ -14,6 +14,7 @@
const path = require('node:path');
const os = require('node:os');
const fs = require('fs-extra');
const { ConfigCollector } = require('../tools/cli/installers/lib/core/config-collector');
const { ManifestGenerator } = require('../tools/cli/installers/lib/core/manifest-generator');
const { IdeManager } = require('../tools/cli/installers/lib/ide/manager');
const { clearCache, loadPlatformCodes } = require('../tools/cli/installers/lib/ide/platform-codes');
@ -1853,6 +1854,93 @@ async function runTests() {
console.log('');
// ============================================================
// Test Suite 33: ConfigCollector Prompt Normalization
// ============================================================
console.log(`${colors.yellow}Test Suite 33: ConfigCollector Prompt Normalization${colors.reset}\n`);
try {
const teaModuleConfig33 = {
test_artifacts: {
default: '_bmad-output/test-artifacts',
},
test_design_output: {
prompt: 'Where should test design documents be stored?',
default: 'test-design',
result: '{test_artifacts}/{value}',
},
test_review_output: {
prompt: 'Where should test review reports be stored?',
default: 'test-reviews',
result: '{test_artifacts}/{value}',
},
trace_output: {
prompt: 'Where should traceability reports be stored?',
default: 'traceability',
result: '{test_artifacts}/{value}',
},
};
const collector33 = new ConfigCollector();
collector33.currentProjectDir = path.join(os.tmpdir(), 'bmad-config-normalization');
collector33.allAnswers = {};
collector33.collectedConfig = {
tea: {
test_artifacts: '_bmad-output/test-artifacts',
},
};
collector33.existingConfig = {
tea: {
test_artifacts: '_bmad-output/test-artifacts',
test_design_output: '_bmad-output/test-artifacts/test-design',
test_review_output: '_bmad-output/test-artifacts/test-reviews',
trace_output: '_bmad-output/test-artifacts/traceability',
},
};
const testDesignQuestion33 = await collector33.buildQuestion(
'tea',
'test_design_output',
teaModuleConfig33.test_design_output,
teaModuleConfig33,
);
const testReviewQuestion33 = await collector33.buildQuestion(
'tea',
'test_review_output',
teaModuleConfig33.test_review_output,
teaModuleConfig33,
);
const traceQuestion33 = await collector33.buildQuestion('tea', 'trace_output', teaModuleConfig33.trace_output, teaModuleConfig33);
assert(testDesignQuestion33.default === 'test-design', 'ConfigCollector normalizes existing test_design_output prompt default');
assert(testReviewQuestion33.default === 'test-reviews', 'ConfigCollector normalizes existing test_review_output prompt default');
assert(traceQuestion33.default === 'traceability', 'ConfigCollector normalizes existing trace_output prompt default');
collector33.allAnswers = {
tea_test_artifacts: '_bmad-output/test-artifacts',
};
assert(
collector33.processResultTemplate(teaModuleConfig33.test_design_output.result, testDesignQuestion33.default) ===
'_bmad-output/test-artifacts/test-design',
'ConfigCollector re-applies test_design_output template without duplicating prefix',
);
assert(
collector33.processResultTemplate(teaModuleConfig33.test_review_output.result, testReviewQuestion33.default) ===
'_bmad-output/test-artifacts/test-reviews',
'ConfigCollector re-applies test_review_output template without duplicating prefix',
);
assert(
collector33.processResultTemplate(teaModuleConfig33.trace_output.result, traceQuestion33.default) ===
'_bmad-output/test-artifacts/traceability',
'ConfigCollector re-applies trace_output template without duplicating prefix',
);
} catch (error) {
assert(false, 'ConfigCollector prompt normalization test succeeds', error.message);
}
console.log('');
// ============================================================
// Summary
// ============================================================

View File

@ -954,31 +954,123 @@ class ConfigCollector {
return match;
}
// Look for the config value in allAnswers (already answered questions)
let configValue = this.allAnswers[configKey] || this.allAnswers[`core_${configKey}`];
// Check in already collected config
if (!configValue) {
for (const mod of Object.keys(this.collectedConfig)) {
if (mod !== '_meta' && this.collectedConfig[mod] && this.collectedConfig[mod][configKey]) {
configValue = this.collectedConfig[mod][configKey];
break;
}
}
}
// If still not found and we're in the same module, use the default from the config schema
if (!configValue && currentModule && moduleConfig && moduleConfig[configKey]) {
const referencedItem = moduleConfig[configKey];
if (referencedItem && referencedItem.default !== undefined) {
configValue = referencedItem.default;
}
}
const configValue = this.resolveConfigValue(configKey, currentModule, moduleConfig);
return configValue || match;
});
}
/**
* Clean a stored path-like value for prompt display/input reuse.
* @param {*} value - Stored value
* @returns {*} Cleaned value
*/
cleanPromptValue(value) {
if (typeof value === 'string' && value.startsWith('{project-root}/')) {
return value.replace('{project-root}/', '');
}
return value;
}
/**
* Resolve a config key from answers, collected config, existing config, or schema defaults.
* @param {string} configKey - Config key to resolve
* @param {string} currentModule - Current module name
* @param {Object} moduleConfig - Current module config schema
* @returns {*} Resolved value
*/
resolveConfigValue(configKey, currentModule = null, moduleConfig = null) {
// Look for the config value in allAnswers (already answered questions)
let configValue = this.allAnswers?.[configKey] || this.allAnswers?.[`core_${configKey}`];
if (!configValue && this.allAnswers) {
for (const [answerKey, answerValue] of Object.entries(this.allAnswers)) {
if (answerKey.endsWith(`_${configKey}`)) {
configValue = answerValue;
break;
}
}
}
// Prefer the current module's persisted value when re-prompting an existing install
if (!configValue && currentModule && this.existingConfig?.[currentModule]?.[configKey] !== undefined) {
configValue = this.existingConfig[currentModule][configKey];
}
// Check in already collected config
if (!configValue) {
for (const mod of Object.keys(this.collectedConfig)) {
if (mod !== '_meta' && this.collectedConfig[mod] && this.collectedConfig[mod][configKey]) {
configValue = this.collectedConfig[mod][configKey];
break;
}
}
}
// Fall back to other existing module config values
if (!configValue && this.existingConfig) {
for (const mod of Object.keys(this.existingConfig)) {
if (mod !== '_meta' && this.existingConfig[mod] && this.existingConfig[mod][configKey]) {
configValue = this.existingConfig[mod][configKey];
break;
}
}
}
// If still not found and we're in the same module, use the default from the config schema
if (!configValue && currentModule && moduleConfig && moduleConfig[configKey]) {
const referencedItem = moduleConfig[configKey];
if (referencedItem && referencedItem.default !== undefined) {
configValue = referencedItem.default;
}
}
return this.cleanPromptValue(configValue);
}
/**
* Convert an existing stored value back into the prompt-facing value for templated fields.
* For example, "{test_artifacts}/{value}" + "_bmad-output/test-artifacts/test-design"
* becomes "test-design" so the template is not applied twice on modify.
* @param {*} existingValue - Stored config value
* @param {string} moduleName - Module name
* @param {Object} item - Config item definition
* @param {Object} moduleConfig - Current module config schema
* @returns {*} Prompt-facing default value
*/
normalizeExistingValueForPrompt(existingValue, moduleName, item, moduleConfig = null) {
const cleanedValue = this.cleanPromptValue(existingValue);
if (typeof cleanedValue !== 'string' || typeof item?.result !== 'string' || !item.result.includes('{value}')) {
return cleanedValue;
}
const [prefixTemplate = '', suffixTemplate = ''] = item.result.split('{value}');
const prefix = this.cleanPromptValue(this.replacePlaceholders(prefixTemplate, moduleName, moduleConfig));
const suffix = this.cleanPromptValue(this.replacePlaceholders(suffixTemplate, moduleName, moduleConfig));
if ((prefix && !cleanedValue.startsWith(prefix)) || (suffix && !cleanedValue.endsWith(suffix))) {
return cleanedValue;
}
const startIndex = prefix.length;
const endIndex = suffix ? cleanedValue.length - suffix.length : cleanedValue.length;
if (endIndex < startIndex) {
return cleanedValue;
}
let promptValue = cleanedValue.slice(startIndex, endIndex);
if (promptValue.startsWith('/')) {
promptValue = promptValue.slice(1);
}
if (promptValue.endsWith('/')) {
promptValue = promptValue.slice(0, -1);
}
return promptValue || cleanedValue;
}
/**
* Build a prompt question from a config item
* @param {string} moduleName - Module name
@ -993,12 +1085,7 @@ class ConfigCollector {
let existingValue = null;
if (this.existingConfig && this.existingConfig[moduleName]) {
existingValue = this.existingConfig[moduleName][key];
// Clean up existing value - remove {project-root}/ prefix if present
// This prevents duplication when the result template adds it back
if (typeof existingValue === 'string' && existingValue.startsWith('{project-root}/')) {
existingValue = existingValue.replace('{project-root}/', '');
}
existingValue = this.normalizeExistingValueForPrompt(existingValue, moduleName, item, moduleConfig);
}
// Special handling for user_name: default to system user

View File

@ -254,8 +254,8 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
getDefaultTemplate(artifactType) {
if (artifactType === 'agent') {
return `---
name: '{{name}}'
description: '{{description}}'
name: "{{name}}"
description: "{{description}}"
disable-model-invocation: true
---
@ -269,8 +269,8 @@ You must fully embody this agent's persona and follow all activation instruction
`;
}
return `---
name: '{{name}}'
description: '{{description}}'
name: "{{name}}"
description: "{{description}}"
---
# {{name}}
@ -319,7 +319,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
.replaceAll('{{name}}', artifact.name || '')
.replaceAll('{{module}}', artifact.module || 'core')
.replaceAll('{{path}}', pathToUse)
.replaceAll('{{description}}', artifact.description || `${artifact.name} ${artifact.type || ''}`)
.replaceAll('{{description}}', (artifact.description || `${artifact.name} ${artifact.type || ''}`).replaceAll('"', String.raw`\"`))
.replaceAll('{{workflow_path}}', pathToUse);
return rendered;