diff --git a/pr.md b/pr.md deleted file mode 100644 index 11fb53ce..00000000 --- a/pr.md +++ /dev/null @@ -1,81 +0,0 @@ -## Summary - -This PR fixes bugs affecting task/tool installation across IDEs: - -1. **CRLF Line Ending Bug** - Frontmatter parsing failed on Windows due to CRLF (`\r\n`) line endings -2. **Gemini CLI TOML Support** - Tasks/tools were generated as `.md` files instead of `.toml` for Gemini CLI -3. **File Extension Preservation** - `.xml` task/tool files had incorrect paths (hardcoded `.md`) - -## Problem - -### Issue 1: Tasks not installed on Windows -The manifest generator's regex `^---\n` expected LF-only line endings, but Windows files have CRLF. This caused: -- YAML frontmatter parsing to silently fail -- All `.md` tasks defaulting to `standalone: false` -- Tasks like `bmad-help` not being installed despite having `standalone: true` in their frontmatter - -### Issue 2: Gemini CLI incompatibility -The `TaskToolCommandGenerator` hardcoded markdown format for all IDEs, but Gemini CLI requires TOML format. Agents and workflows already used the template system correctly, but tasks/tools did not. - -### Issue 3: Incorrect file extensions in paths -The `relativePath` property was hardcoded to `.md`, so tasks/tools with `.xml` extension got incorrect paths like `bmm/tasks/foo.md` instead of `bmm/tasks/foo.xml`. - -## Solution - -### Fix 1: CRLF-aware regex (4 files) -Changed frontmatter regex from `^---\n` to `^---\r?\n` to handle both Windows (CRLF) and Unix (LF) line endings. - -**Files modified:** -- `tools/cli/installers/lib/core/manifest-generator.js` (3 occurrences) -- `tools/cli/installers/lib/core/dependency-resolver.js` (1 occurrence) - -### Fix 2: Template-based task/tool generation -Extended the existing template system (used by agents/workflows) to also handle tasks/tools. - -**New files:** -- `tools/cli/installers/lib/ide/templates/combined/gemini-task.toml` -- `tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml` -- `tools/cli/installers/lib/ide/templates/combined/default-task.md` -- `tools/cli/installers/lib/ide/templates/combined/default-tool.md` - -**Modified files:** -- `tools/cli/installers/lib/ide/shared/task-tool-command-generator.js` - - Added `collectTaskToolArtifacts()` method - - Added constructor with `bmadFolderName` parameter -- `tools/cli/installers/lib/ide/_config-driven.js` - - Added `writeTaskToolArtifacts()` method with `artifact_types` filtering - - Updated `installToTarget()` to use template system - - Updated `renderTemplate()` to handle task/tool paths - -### Fix 3: File extension preservation (4d7ca00) -The `relativePath` property was hardcoded to `.md` extension, causing incorrect paths for `.xml` task/tool files. - -**Modified files:** -- `tools/cli/installers/lib/ide/shared/task-tool-command-generator.js` - - Extract actual extension from source path with `.md` fallback - - Fixed misleading comments ("underscore format" → "dash format") -- `tools/cli/installers/lib/ide/templates/combined/gemini-task.toml` - - Fixed branding: "BMad" → "BMAD" -- `tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml` - - Fixed branding: "BMad" → "BMAD" - -## Test Plan - -- [x] Windows install (CMD) - tasks installed with correct frontmatter parsing -- [x] WSL/Linux install - tasks installed correctly -- [x] Gemini CLI generates `.toml` files for tasks/tools -- [x] Claude Code generates `.md` files for tasks/tools -- [x] All other IDEs (Cursor, Windsurf, Trae, etc.) generate `.md` files -- [x] `bmad-help` task now correctly has `standalone: true` in manifest -- [x] Existing agent/workflow installation unaffected -- [x] `.xml` tasks/tools get correct extension in `relativePath` - -## Breaking Changes - -None - this is purely a bug fix. Existing installations will work correctly after reinstall. - ---- - -Generated with [Claude Code](https://claude.ai/code) - -Co-Authored-By: Claude Opus 4.5 diff --git a/tools/cli/installers/lib/ide/codex.js b/tools/cli/installers/lib/ide/codex.js index 60250a39..86fd0240 100644 --- a/tools/cli/installers/lib/ide/codex.js +++ b/tools/cli/installers/lib/ide/codex.js @@ -104,7 +104,10 @@ class CodexSetup extends BaseIdeSetup { ); taskArtifacts.push({ type: 'task', + name: task.name, + displayName: task.name, module: task.module, + path: task.path, sourcePath: task.path, relativePath: path.join(task.module, 'tasks', `${task.name}.md`), content, @@ -116,7 +119,7 @@ class CodexSetup extends BaseIdeSetup { const workflowCount = await workflowGenerator.writeDashArtifacts(destDir, workflowArtifacts); // Also write tasks using underscore format - const ttGen = new TaskToolCommandGenerator(); + const ttGen = new TaskToolCommandGenerator(this.bmadFolderName); const tasksWritten = await ttGen.writeDashArtifacts(destDir, taskArtifacts); const written = agentCount + workflowCount + tasksWritten; @@ -214,7 +217,10 @@ class CodexSetup extends BaseIdeSetup { artifacts.push({ type: 'task', + name: task.name, + displayName: task.name, module: task.module, + path: task.path, sourcePath: task.path, relativePath: path.join(task.module, 'tasks', `${task.name}.md`), content, diff --git a/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js b/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js index 664b0cfb..aea043e4 100644 --- a/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js @@ -142,9 +142,33 @@ class TaskToolCommandGenerator { const description = item.description || `Execute ${item.displayName || item.name}`; // Convert path to use {project-root} placeholder + // Handle undefined/missing path by constructing from module and name let itemPath = item.path; - if (itemPath && typeof itemPath === 'string' && itemPath.startsWith('bmad/')) { - itemPath = `{project-root}/${itemPath}`; + if (!itemPath || typeof itemPath !== 'string') { + // Fallback: construct path from module and name if path is missing + const typePlural = type === 'task' ? 'tasks' : 'tools'; + itemPath = `{project-root}/${this.bmadFolderName}/${item.module}/${typePlural}/${item.name}.md`; + } else { + // Normalize path separators to forward slashes + itemPath = itemPath.replaceAll('\\', '/'); + + // Extract relative path from absolute paths (Windows or Unix) + // Look for _bmad/ or bmad/ in the path and extract everything after it + // Match patterns like: /_bmad/core/tasks/... or /bmad/core/tasks/... + const bmadMatch = itemPath.match(/\/_bmad\/(.+)$/) || itemPath.match(/\/bmad\/(.+)$/); + if (bmadMatch) { + // Found /_bmad/ or /bmad/ - use relative path after it + itemPath = `{project-root}/${this.bmadFolderName}/${bmadMatch[1]}`; + } else if (itemPath.startsWith('_bmad/')) { + // Relative path starting with _bmad/ + itemPath = `{project-root}/${this.bmadFolderName}/${itemPath.slice(6)}`; + } else if (itemPath.startsWith('bmad/')) { + // Relative path starting with bmad/ + itemPath = `{project-root}/${this.bmadFolderName}/${itemPath.slice(5)}`; + } else if (!itemPath.startsWith('{project-root}')) { + // For other relative paths, prefix with project root and bmad folder + itemPath = `{project-root}/${this.bmadFolderName}/${itemPath}`; + } } return `--- diff --git a/tools/cli/lib/agent/installer.js b/tools/cli/lib/agent/installer.js index b55502ed..a7650453 100644 --- a/tools/cli/lib/agent/installer.js +++ b/tools/cli/lib/agent/installer.js @@ -42,7 +42,7 @@ function findBmadConfig(startPath = process.cwd()) { * @returns {string} Resolved path */ function resolvePath(pathStr, context) { - return pathStr.replaceAll('{project-root}', context.projectRoot).replaceAll('{bmad-folder}', context_bmadFolder); + return pathStr.replaceAll('{project-root}', context.projectRoot).replaceAll('{bmad-folder}', context.bmadFolder); } /**