From 97a533e298aeca9da529b8a9e68e4ea1416ea048 Mon Sep 17 00:00:00 2001 From: PinkyD Date: Tue, 24 Feb 2026 16:43:33 -0800 Subject: [PATCH 1/4] fix(installer): remove double-escaping of quotes in CSV manifest pipeline (#1746) * fix(installer): remove double-escaping of quotes in CSV manifest pipeline cleanForCSV() pre-escaped " to "" before storing in memory, then escapeCsv() escaped again at CSV write time. After csv-parse round-trip (which only un-escapes once), descriptions retained doubled quotes instead of originals, corrupting generated output files. Fix: remove the redundant quote escaping from cleanForCSV() since escapeCsv() already handles CSV quoting correctly at write time. Co-Authored-By: Claude Opus 4.6 * fix(installer): use single quotes for description in Gemini workflow templates Replace triple-quoted """{{description}}""" with single-quoted '{{description}}' to avoid TOML escaping issues in Gemini workflow templates. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- tools/cli/installers/lib/core/manifest-generator.js | 10 ++++------ .../ide/templates/combined/gemini-workflow-yaml.toml | 2 +- .../lib/ide/templates/combined/gemini-workflow.toml | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index bc4694a6d..06e2e3f4b 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -24,16 +24,14 @@ class ManifestGenerator { } /** - * Clean text for CSV output by normalizing whitespace and escaping quotes + * Clean text for CSV output by normalizing whitespace. + * Note: Quote escaping is handled by escapeCsv() at write time. * @param {string} text - Text to clean - * @returns {string} Cleaned text safe for CSV + * @returns {string} Cleaned text */ cleanForCSV(text) { if (!text) return ''; - return text - .trim() - .replaceAll(/\s+/g, ' ') // Normalize all whitespace (including newlines) to single space - .replaceAll('"', '""'); // Escape quotes for CSV + return text.trim().replaceAll(/\s+/g, ' '); // Normalize all whitespace (including newlines) to single space } /** diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml index 063ca0d0b..bc6c8da39 100644 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +++ b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml @@ -1,4 +1,4 @@ -description = """{{description}}""" +description = '{{description}}' prompt = """ Execute the BMAD '{{name}}' workflow. diff --git a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml index 526241061..3306cce04 100644 --- a/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +++ b/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml @@ -1,4 +1,4 @@ -description = """{{description}}""" +description = '{{description}}' prompt = """ Execute the BMAD '{{name}}' workflow. From 5ed436cda0ab5d36c8ef18514ea0fba509ebbb6c Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Mon, 23 Feb 2026 17:12:16 -0600 Subject: [PATCH 2/4] 6.0.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6c137900..2ffca11a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bmad-method", - "version": "6.0.2", + "version": "6.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bmad-method", - "version": "6.0.2", + "version": "6.0.3", "license": "MIT", "dependencies": { "@clack/core": "^1.0.0", diff --git a/package.json b/package.json index 0fce31566..773c5704f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "bmad-method", - "version": "6.0.2", + "version": "6.0.3", "description": "Breakthrough Method of Agile AI-driven Development", "keywords": [ "agile", From 72a9325a405764549458a635df0c8723981e7ed6 Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Wed, 25 Feb 2026 10:11:24 -0700 Subject: [PATCH 3/4] docs: rebrand BMAD acronym to Build More Architect Dreams (#1765) Update the BMAD acronym expansion from "Breakthrough Method of Agile AI Driven Development" to "Build More Architect Dreams" across README, docs homepage, and package.json description. Co-authored-by: Brian --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ce377b569..dc878cc46 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org) [![Discord](https://img.shields.io/badge/Discord-Join%20Community-7289da?logo=discord&logoColor=white)](https://discord.gg/gk8jAdXWmj) -**Breakthrough Method of Agile AI Driven Development** — An AI-driven agile development module for the BMad Method Module Ecosystem, the best and most comprehensive Agile AI Driven Development framework that has true scale-adaptive intelligence that adjusts from bug fixes to enterprise systems. +**Build More Architect Dreams** — An AI-driven agile development module for the BMad Method Module Ecosystem, the best and most comprehensive Agile AI Driven Development framework that has true scale-adaptive intelligence that adjusts from bug fixes to enterprise systems. **100% free and open source.** No paywalls. No gated content. No gated Discord. We believe in empowering everyone, not just those who can pay for a gated community or courses. diff --git a/docs/index.md b/docs/index.md index 7fd3fa245..8d414bbbe 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,7 +3,7 @@ title: Welcome to the BMad Method description: AI-driven development framework with specialized agents, guided workflows, and intelligent planning --- -The BMad Method (**B**reakthrough **M**ethod of **A**gile AI **D**riven Development) is an AI-driven development framework module within the BMad Method Ecosystem that helps you build software through the whole process from ideation and planning all the way through agentic implementation. It provides specialized AI agents, guided workflows, and intelligent planning that adapts to your project's complexity, whether you're fixing a bug or building an enterprise platform. +The BMad Method (**B**uild **M**ore **A**rchitect **D**reams) is an AI-driven development framework module within the BMad Method Ecosystem that helps you build software through the whole process from ideation and planning all the way through agentic implementation. It provides specialized AI agents, guided workflows, and intelligent planning that adapts to your project's complexity, whether you're fixing a bug or building an enterprise platform. If you're comfortable working with AI coding assistants like Claude, Cursor, or GitHub Copilot, you're ready to get started. From 6bfc937bd3f687e99ed9632e14b6c8902e1dcd8d Mon Sep 17 00:00:00 2001 From: Davor Racic Date: Wed, 25 Feb 2026 18:12:05 +0100 Subject: [PATCH 4/4] fix(installer): OpenCode integration: replace `name` frontmatter with `mode: all` and update directory names (#1764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(opencode): use mode: all in agent template, remove name frontmatter, fix directory names - Replace name: '{{name}}' with mode: all in opencode-agent.md mode: all enables both Tab-key agent switching in the TUI and @subagent invocation via the Task tool (mode: primary blocked subagent use) - Remove name: '{{name}}' from opencode-task/tool/workflow/workflow-yaml templates OpenCode derives command name from filename, not from a name frontmatter field; the bare {{name}} value was overriding the bmad- prefixed filename causing name collisions with built-in OpenCode commands (fixes #1762) - Fix deprecated singular directory names in platform-codes.yaml: .opencode/agent -> .opencode/agents, .opencode/command -> .opencode/commands - Add legacy_targets migration: cleanup() now removes stale bmad-* files from old singular directories on reinstall so existing users don't get duplicates - Fix removeEmptyParents to continue walking up to parent when starting dir is already absent instead of breaking early Co-Authored-By: Claude Sonnet 4.6 * fix(opencode): address code review findings for cleanup and schema docs - Add project boundary guard to removeEmptyParents() using path.resolve and startsWith check to prevent traversal outside projectDir (Augment) - Fix JSDoc: "Recursively remove" -> "Walk up ancestor directories" - Add user-visible migration log message when processing legacy_targets - Document legacy_targets field in Installer Config Schema comment block in platform-codes.yaml (CodeRabbit + Augment) Co-Authored-By: Claude Sonnet 4.6 * fix(opencode): improve removeEmptyParents error handling and loop clarity - Distinguish recoverable errors (ENOTEMPTY, ENOENT) from fatal errors in removeEmptyParents() catch block — skip level and continue upward on TOCTOU races or concurrent removal, break only on fatal errors (EACCES) - Add comment clarifying loop invariant for missing-path continue branch Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Brian --- .../cli/installers/lib/ide/_config-driven.js | 32 ++++++++++++++++--- .../installers/lib/ide/platform-codes.yaml | 9 ++++-- .../ide/templates/combined/opencode-agent.md | 2 +- .../ide/templates/combined/opencode-task.md | 1 - .../ide/templates/combined/opencode-tool.md | 1 - .../combined/opencode-workflow-yaml.md | 1 - .../templates/combined/opencode-workflow.md | 1 - 7 files changed, 35 insertions(+), 12 deletions(-) diff --git a/tools/cli/installers/lib/ide/_config-driven.js b/tools/cli/installers/lib/ide/_config-driven.js index 85196cf76..d1552700f 100644 --- a/tools/cli/installers/lib/ide/_config-driven.js +++ b/tools/cli/installers/lib/ide/_config-driven.js @@ -453,6 +453,15 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}} * @param {string} projectDir - Project directory */ async cleanup(projectDir, options = {}) { + // Migrate legacy target directories (e.g. .opencode/agent → .opencode/agents) + if (this.installerConfig?.legacy_targets) { + if (!options.silent) await prompts.log.message(' Migrating legacy directories...'); + for (const legacyDir of this.installerConfig.legacy_targets) { + await this.cleanupTarget(projectDir, legacyDir, options); + await this.removeEmptyParents(projectDir, legacyDir); + } + } + // Clean all target directories if (this.installerConfig?.targets) { const parentDirs = new Set(); @@ -532,24 +541,37 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}} } } /** - * Recursively remove empty directories walking up from dir toward projectDir + * Walk up ancestor directories from relativeDir toward projectDir, removing each if empty * Stops at projectDir boundary — never removes projectDir itself * @param {string} projectDir - Project root (boundary) * @param {string} relativeDir - Relative directory to start from */ async removeEmptyParents(projectDir, relativeDir) { + const resolvedProject = path.resolve(projectDir); let current = relativeDir; let last = null; while (current && current !== '.' && current !== last) { last = current; - const fullPath = path.join(projectDir, current); + const fullPath = path.resolve(projectDir, current); + // Boundary guard: never traverse outside projectDir + if (!fullPath.startsWith(resolvedProject + path.sep) && fullPath !== resolvedProject) break; try { - if (!(await fs.pathExists(fullPath))) break; + if (!(await fs.pathExists(fullPath))) { + // Dir already gone — advance current; last is reset at top of next iteration + current = path.dirname(current); + continue; + } const remaining = await fs.readdir(fullPath); if (remaining.length > 0) break; await fs.rmdir(fullPath); - } catch { - break; + } catch (error) { + // ENOTEMPTY: TOCTOU race (file added between readdir and rmdir) — skip level, continue upward + // ENOENT: dir removed by another process between pathExists and rmdir — skip level, continue upward + if (error.code === 'ENOTEMPTY' || error.code === 'ENOENT') { + current = path.dirname(current); + continue; + } + break; // fatal error (e.g. EACCES) — stop upward walk } current = path.dirname(current); } diff --git a/tools/cli/installers/lib/ide/platform-codes.yaml b/tools/cli/installers/lib/ide/platform-codes.yaml index 16723f9c5..2d9e8c129 100644 --- a/tools/cli/installers/lib/ide/platform-codes.yaml +++ b/tools/cli/installers/lib/ide/platform-codes.yaml @@ -131,11 +131,14 @@ platforms: category: ide description: "OpenCode terminal coding assistant" installer: + legacy_targets: + - .opencode/agent + - .opencode/command targets: - - target_dir: .opencode/agent + - target_dir: .opencode/agents template_type: opencode artifact_types: [agents] - - target_dir: .opencode/command + - target_dir: .opencode/commands template_type: opencode artifact_types: [workflows, tasks, tools] @@ -191,6 +194,8 @@ platforms: # template_type: string # Default template type to use # header_template: string (optional) # Override for header/frontmatter template # body_template: string (optional) # Override for body/content template +# legacy_targets: array (optional) # Old target dirs to clean up on reinstall (migration) +# - string # Relative path, e.g. .opencode/agent # targets: array (optional) # For multi-target installations # - target_dir: string # template_type: string diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md b/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md index 65f0a771d..828d673ac 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md @@ -1,5 +1,5 @@ --- -name: '{{name}}' +mode: all description: '{{description}}' --- diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-task.md b/tools/cli/installers/lib/ide/templates/combined/opencode-task.md index 98b3a5d77..772f9c9eb 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-task.md @@ -1,5 +1,4 @@ --- -name: '{{name}}' description: '{{description}}' --- diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md b/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md index 1ae9c9ac8..88c317e63 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md @@ -1,5 +1,4 @@ --- -name: '{{name}}' description: '{{description}}' --- diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md index a6f5cb96f..88838cc1c 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md @@ -1,5 +1,4 @@ --- -name: '{{name}}' description: '{{description}}' --- diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md index a6f5cb96f..88838cc1c 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md @@ -1,5 +1,4 @@ --- -name: '{{name}}' description: '{{description}}' ---