From 0a3f48f13fefde7981c065ebea493727f981da96 Mon Sep 17 00:00:00 2001 From: Dicky Moore Date: Sun, 8 Feb 2026 22:16:06 +0000 Subject: [PATCH] fix: address coderabbit workflow migration follow-ups --- docs/tutorials/getting-started.md | 50 +++++------ .../4-implementation/create-story/workflow.md | 9 +- .../document-project/instructions.md | 81 ++++++++++++++++-- src/core/tasks/validate-workflow.md | 10 ++- test/test-installation-components.js | 22 +++-- .../ide/shared/workflow-command-generator.js | 84 +++++++++---------- tools/cli/installers/lib/modules/manager.js | 3 - 7 files changed, 165 insertions(+), 94 deletions(-) diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index 2d959bc92..dee65a26d 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -78,15 +78,15 @@ Work through phases 1-3. **Use fresh chats for each workflow.** ### Phase 1: Analysis (Optional) All workflows in this phase are optional: -- **brainstorming** — Guided ideation -- **research** — Market and technical research -- **create-product-brief** — Recommended foundation document +- **brainstorming** (`bmad-bmm-brainstorming`) — Guided ideation +- **research** (`bmad-bmm-research`) — Market and technical research +- **create-product-brief** (`bmad-bmm-create-product-brief`) — Recommended foundation document ### Phase 2: Planning (Required) **For BMad Method and Enterprise tracks:** 1. Load the **PM agent** in a new chat -2. Run the `prd` workflow +2. Run the `create-prd` workflow (`bmad-bmm-create-prd`) 3. Output: `PRD.md` **For Quick Flow track:** @@ -100,7 +100,7 @@ If your project has a user interface, load the **UX-Designer agent** and run the **Create Architecture** 1. Load the **Architect agent** in a new chat -2. Run `create-architecture` +2. Run `create-architecture` (`bmad-bmm-create-architecture`) 3. Output: Architecture document with technical decisions **Create Epics and Stories** @@ -110,12 +110,12 @@ Epics and stories are now created *after* architecture. This produces better qua ::: 1. Load the **PM agent** in a new chat -2. Run `create-epics-and-stories` +2. Run `create-epics-and-stories` (`bmad-bmm-create-epics-and-stories`) 3. The workflow uses both PRD and Architecture to create technically-informed stories **Implementation Readiness Check** *(Highly Recommended)* 1. Load the **Architect agent** in a new chat -2. Run `check-implementation-readiness` +2. Run `check-implementation-readiness` (`bmad-bmm-check-implementation-readiness`) 3. Validates cohesion across all planning documents ## Step 2: Build Your Project @@ -124,7 +124,7 @@ Once planning is complete, move to implementation. **Each workflow should run in ### Initialize Sprint Planning -Load the **SM agent** and run `sprint-planning`. This creates `sprint-status.yaml` to track all epics and stories. +Load the **SM agent** and run `sprint-planning` (`bmad-bmm-sprint-planning`). This creates `sprint-status.yaml` to track all epics and stories. ### The Build Cycle @@ -132,11 +132,11 @@ For each story, repeat this cycle with fresh chats: | Step | Agent | Workflow | Purpose | | ---- | ----- | -------------- | ---------------------------------- | -| 1 | SM | `create-story` | Create story file from epic | -| 2 | DEV | `dev-story` | Implement the story | -| 3 | DEV | `code-review` | Quality validation *(recommended)* | +| 1 | SM | `create-story` (`bmad-bmm-create-story`) | Create story file from epic | +| 2 | DEV | `dev-story` (`bmad-bmm-dev-story`) | Implement the story | +| 3 | DEV | `code-review` (`bmad-bmm-code-review`) | Quality validation *(recommended)* | -After completing all stories in an epic, load the **SM agent** and run `retrospective`. +After completing all stories in an epic, load the **SM agent** and run `retrospective` (`bmad-bmm-retrospective`). ## What You've Accomplished @@ -162,17 +162,17 @@ your-project/ ## Quick Reference -| Workflow | Agent | Purpose | -| -------------------------------- | --------- | ------------------------------------ | -| `help` | Any | Get guidance on what to do next | -| `prd` | PM | Create Product Requirements Document | -| `create-architecture` | Architect | Create architecture document | -| `create-epics-and-stories` | PM | Break down PRD into epics | -| `check-implementation-readiness` | Architect | Validate planning cohesion | -| `sprint-planning` | SM | Initialize sprint tracking | -| `create-story` | SM | Create a story file | -| `dev-story` | DEV | Implement a story | -| `code-review` | DEV | Review implemented code | +| Workflow | Slash Command | Agent | Purpose | +| -------------------------------- | ------------------------------------- | --------- | ------------------------------------ | +| `help` | `bmad-help` | Any | Get guidance on what to do next | +| `create-prd` | `bmad-bmm-create-prd` | PM | Create Product Requirements Document | +| `create-architecture` | `bmad-bmm-create-architecture` | Architect | Create architecture document | +| `create-epics-and-stories` | `bmad-bmm-create-epics-and-stories` | PM | Break down PRD into epics | +| `check-implementation-readiness` | `bmad-bmm-check-implementation-readiness` | Architect | Validate planning cohesion | +| `sprint-planning` | `bmad-bmm-sprint-planning` | SM | Initialize sprint tracking | +| `create-story` | `bmad-bmm-create-story` | SM | Create a story file | +| `dev-story` | `bmad-bmm-dev-story` | DEV | Implement a story | +| `code-review` | `bmad-bmm-code-review` | DEV | Review implemented code | ## Common Questions @@ -183,7 +183,7 @@ Only for BMad Method and Enterprise tracks. Quick Flow skips from tech-spec to i Yes. The SM agent has a `correct-course` workflow for handling scope changes. **What if I want to brainstorm first?** -Load the Analyst agent and run `brainstorming` before starting your PRD. +Load the Analyst agent and run `brainstorming` (`bmad-bmm-brainstorming`) before starting your PRD. **Do I need to follow a strict order?** Not strictly. Once you learn the flow, you can run workflows directly using the Quick Reference above. @@ -192,7 +192,7 @@ Not strictly. Once you learn the flow, you can run workflows directly using the - **During workflows** — Agents guide you with questions and explanations - **Community** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues) -- **Stuck?** — Run `help` to see what to do next +- **Stuck?** — Run `help` (`bmad-help` on most platforms) to see what to do next ## Key Takeaways diff --git a/src/bmm/workflows/4-implementation/create-story/workflow.md b/src/bmm/workflows/4-implementation/create-story/workflow.md index bf226c4d3..219a885e6 100644 --- a/src/bmm/workflows/4-implementation/create-story/workflow.md +++ b/src/bmm/workflows/4-implementation/create-story/workflow.md @@ -59,7 +59,7 @@ input_file_patterns: Parse user-provided story path: extract epic_num, story_num, story_title from format like "1-2-user-auth" Set {{epic_num}}, {{story_num}}, {{story_key}} from user input - GOTO step 2a + GOTO step 2 Check if {{sprint_status}} file exists for auto discover @@ -85,12 +85,12 @@ input_file_patterns: Parse user input: extract epic_num, story_num, story_title Set {{epic_num}}, {{story_num}}, {{story_key}} from user input - GOTO step 2a + GOTO step 2 Use user-provided path for story documents - GOTO step 2a + GOTO step 2 @@ -152,7 +152,7 @@ input_file_patterns: 📊 Epic {{epic_num}} status updated to in-progress - GOTO step 2a + GOTO step 2 @@ -174,6 +174,7 @@ input_file_patterns: (As a, I want, so that) - Detailed acceptance criteria (already BDD formatted) - Technical requirements specific to this story - Business context and value - Success criteria + Set {{previous_story_num}} = {{story_num}} - 1 Load previous story file: {{story_dir}}/{{epic_num}}-{{previous_story_num}}-*.md **PREVIOUS STORY INTELLIGENCE:** - Dev notes and learnings from previous story - Review feedback and corrections needed - Files that were created/modified and their patterns - Testing approaches that worked/didn't work - Problems encountered and solutions found - Code patterns established Extract diff --git a/src/bmm/workflows/document-project/instructions.md b/src/bmm/workflows/document-project/instructions.md index 8b2269913..a8315fcd9 100644 --- a/src/bmm/workflows/document-project/instructions.md +++ b/src/bmm/workflows/document-project/instructions.md @@ -18,6 +18,13 @@ - Set suggestion = "" - Set next_workflow = "" - Set next_agent = "" + - Set status_file_path = "" + - Set field_type = "" + - Set workflow_mode = "" + - Set scan_level = "" + - Set subworkflow_success = false + - Set status_update_success = false + - Set cached_project_types = "" Attempt to load workflow status directly from `{output_folder}/bmm-workflow-status.yaml`: @@ -29,10 +36,18 @@ - Extract field_type, warning, suggestion, next_workflow, next_agent if present - If file is missing, unreadable, or malformed: - Keep defaults and continue in standalone mode + - Set status_load_error_reason from the caught file/parse error (e.g., missing file, permission denied, YAML parse error) + - Set warning = "Unable to load workflow status from {output_folder}/bmm-workflow-status.yaml: {{status_load_error_reason}}" + - Output warning and continue in standalone mode - {{suggestion}} + + {{suggestion}} + + + {{warning}} + Note: Documentation workflow can run standalone. Continuing without progress tracking. Set standalone_mode = true Set status_file_found = false @@ -62,7 +77,9 @@ Note: This may be auto-invoked by prd for brownfield documentation. Continue with documentation? (y/n) - {{suggestion}} + + {{suggestion}} + Exit workflow @@ -78,14 +95,33 @@ Read state file and extract: timestamps, mode, scan_level, current_step, completed_steps, project_classification + Validate last_updated from state file: + - If last_updated is missing or invalid, set state_age_hours = 999 and mark state as stale + - Otherwise parse timestamp and continue + Extract cached project_type_id(s) from state file if present Calculate age of state file (current time - last_updated) Display: "Found old state file (>24 hours). Starting fresh scan." - Create archive directory: {output_folder}/.archive/ - Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json + Attempt to create archive directory: {output_folder}/.archive/ + + Failed to create archive directory at {output_folder}/.archive/. Keeping existing state and exiting to avoid data loss. + Set resume_mode = true + Exit workflow + + Attempt to archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json + + Failed to archive old state file. Keeping existing state and exiting to avoid data loss. + Set resume_mode = true + Exit workflow + Set resume_mode = false + Set workflow_mode = "" + Set scan_level = "" + Set cached_project_types = "" + Set current_step = "" + Set subworkflow_success = false Continue to Step 3 @@ -112,15 +148,25 @@ Your choice [1/2/3]: Set resume_mode = true - Set workflow_mode = {{mode}} + Validate persisted mode before assigning workflow_mode: + - If mode is one of [deep_dive, initial_scan, full_rescan], set workflow_mode = {{mode}} + - Otherwise set workflow_mode = "full_rescan", set resume_mode = false, and continue as fresh scan + Set subworkflow_success = false Load findings summaries from state file Load cached project_type_id(s) from state file CONDITIONAL CSV LOADING FOR RESUME: + + No cached project types found. Falling back to full CSV load. + Load project-types.csv and architecture_registry.csv + Load documentation_requirements_csv for active project classification + + For each cached project_type_id, load ONLY the corresponding row from: {documentation_requirements_csv} Skip loading project-types.csv and architecture_registry.csv (not needed on resume) Store loaded doc requirements for use in remaining steps + Display: "Resuming {{workflow_mode}} from {{current_step}} with cached project type(s): {{cached_project_types}}" @@ -152,9 +198,21 @@ Your choice [1/2/3]: - Create archive directory: {output_folder}/.archive/ - Move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json + Attempt to create archive directory: {output_folder}/.archive/ + + Failed to create archive directory. Keeping existing state and exiting to avoid data loss. + Set resume_mode = true + Exit workflow + + Attempt to move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json + + Failed to archive old state file. Keeping existing state and exiting to avoid data loss. + Set resume_mode = true + Exit workflow + Set resume_mode = false + Reset workflow_mode, scan_level, cached_project_types, current_step to defaults + Set subworkflow_success = false Continue to Step 3 @@ -198,6 +256,7 @@ Your choice [1/2/3]: Set workflow_mode = "full_rescan" + Set scan_level = "standard" Display: "Starting full project rescan..." Read fully and follow: {installed_path}/workflows/full-scan-instructions.md Set subworkflow_success = true only if delegated workflow completed without HALT/error @@ -234,6 +293,7 @@ Your choice [1/2/3]: Set workflow_mode = "initial_scan" + Set scan_level = "initial" Display: "No existing documentation found. Starting initial project scan..." Read fully and follow: {installed_path}/workflows/full-scan-instructions.md Set subworkflow_success = true only if delegated workflow completed without HALT/error @@ -282,8 +342,13 @@ Your choice [1/2/3]: **Status Updated:** Progress tracking updated. **Next Steps:** -- **Next required:** {{next_workflow}} ({{next_agent}} agent) - Run `bmad-help` if you need recommended next workflows. + + - **Next required:** {{next_workflow}} ({{next_agent}} agent) + + + - **Next required:** not specified + diff --git a/src/core/tasks/validate-workflow.md b/src/core/tasks/validate-workflow.md index 1ffac96e6..65846e0f4 100644 --- a/src/core/tasks/validate-workflow.md +++ b/src/core/tasks/validate-workflow.md @@ -31,7 +31,7 @@ Execute a validation checklist against a target file and report findings clearly - Path-like tokens in checklist items - First matching path from glob patterns supplied by checklist/input - Normalize all candidate paths relative to repo root and resolve `.`/`..`. - - Validate candidate existence and expected file type (`.yaml`, `.yml`, `.json`, or checklist-defined extension). + - Validate candidate existence and expected file type (`.md`, `.yaml`, `.yml`, `.json`, or checklist-defined extension). - If multiple valid candidates remain, prefer explicit key fields over inferred tokens. - If no valid candidate is found, prompt user with schema example: - `Please provide the exact file path (relative to repo root), e.g. ./workflows/ci.yml` @@ -50,11 +50,17 @@ Execute a validation checklist against a target file and report findings clearly - If checklist requires edits/auto-fixes, follow safe-edit protocol: - Ask for confirmation before editing. - Create backup snapshot of target file before changes. + - Use deterministic backup location: `{project-root}/.bmad-tmp/validate-workflow/`. + - Name backup as `{target-file-name}.{timestamp}.bak` and diff as `{target-file-name}.{timestamp}.diff`. + - If temp backup directory cannot be created, fall back to adjacent backup file `{target-file}.bak`. - Generate reversible diff preview and show it to user. - Apply edits only after user approval. - Run syntax/validation checks against edited file. - If validation fails or user cancels, rollback from backup and report rollback status. - - Record backup/diff locations in task output. + - Record full backup and diff paths in task output. + - Support `retain_artifacts` flag (default `false`) to keep backup/diff artifacts when requested. 6. **Finalize** - Confirm completion and provide the final validation summary. + - If edits succeeded and `retain_artifacts` is `false`, delete backup/diff artifacts and report cleanup status. + - If edits failed or rollback occurred, preserve backup/diff artifacts and report rollback path explicitly. diff --git a/test/test-installation-components.js b/test/test-installation-components.js index 17bed97ee..12bd0e211 100644 --- a/test/test-installation-components.js +++ b/test/test-installation-components.js @@ -114,6 +114,12 @@ async function runTests() { console.log(`========================================${colors.reset}\n`); const projectRoot = path.join(__dirname, '..'); + const tmpRoots = []; + const trackTmp = async (prefix) => { + const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix)); + tmpRoots.push(dir); + return dir; + }; // ============================================================ // Test 1: YAML → XML Agent Compilation (In-Memory) @@ -432,7 +438,7 @@ async function runTests() { console.log(`${colors.yellow}Test Suite 11: Gemini Template Extension Guard${colors.reset}\n`); try { - const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-gemini-install-')); + const tmpRoot = await trackTmp('bmad-gemini-install-'); const projectDir = path.join(tmpRoot, 'project'); const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME); await fs.ensureDir(projectDir); @@ -470,7 +476,7 @@ async function runTests() { console.log(`${colors.yellow}Test Suite 12: Manifest Stale Entry Cleanup Guard${colors.reset}\n`); try { - const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-manifest-clean-')); + const tmpRoot = await trackTmp('bmad-manifest-clean-'); const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME); await fs.copy(path.join(projectRoot, 'src', 'core'), path.join(bmadDir, 'core')); await fs.copy(path.join(projectRoot, 'src', 'bmm'), path.join(bmadDir, 'bmm')); @@ -505,7 +511,7 @@ async function runTests() { console.log(`${colors.yellow}Test Suite 13: Internal Task Exposure Guard${colors.reset}\n`); try { - const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-task-filter-')); + const tmpRoot = await trackTmp('bmad-task-filter-'); const projectDir = path.join(tmpRoot, 'project'); const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME); const commandsDir = path.join(tmpRoot, 'commands'); @@ -592,7 +598,7 @@ web_bundle: console.log(`${colors.yellow}Test Suite 16: Task/Tool Standalone + CRLF Guard${colors.reset}\n`); try { - const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-standalone-crlf-')); + const tmpRoot = await trackTmp('bmad-standalone-crlf-'); const coreTasksDir = path.join(tmpRoot, '_bmad', 'core', 'tasks'); const coreToolsDir = path.join(tmpRoot, '_bmad', 'core', 'tools'); await fs.ensureDir(coreTasksDir); @@ -717,7 +723,7 @@ internal: true console.log(`${colors.yellow}Test Suite 18: Codex Task Visibility Guard${colors.reset}\n`); try { - const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-codex-visibility-')); + const tmpRoot = await trackTmp('bmad-codex-visibility-'); const projectDir = path.join(tmpRoot, 'project'); const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME); await fs.ensureDir(projectDir); @@ -751,7 +757,7 @@ internal: true console.log(`${colors.yellow}Test Suite 19: Empty Artifact Target Guard${colors.reset}\n`); try { - const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-empty-target-')); + const tmpRoot = await trackTmp('bmad-empty-target-'); const projectDir = path.join(tmpRoot, 'project'); const bmadDir = path.join(tmpRoot, BMAD_FOLDER_NAME); await fs.ensureDir(projectDir); @@ -856,6 +862,10 @@ internal: true console.log(''); + for (const tmpRoot of tmpRoots) { + await fs.remove(tmpRoot).catch(() => {}); + } + // ============================================================ // Summary // ============================================================ diff --git a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js index 8ce9ae3e9..75151e167 100644 --- a/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +++ b/tools/cli/installers/lib/ide/shared/workflow-command-generator.js @@ -75,10 +75,10 @@ class WorkflowCommandGenerator { if (workflowRelPath.includes('_bmad/')) { const parts = workflowRelPath.split(/_bmad\//); if (parts.length > 1) { - workflowRelPath = parts.slice(1).join('/'); + workflowRelPath = parts.at(-1); } - } else if (workflowRelPath.includes('/src/')) { - const match = workflowRelPath.match(/\/src\/([^/]+)\/(.+)/); + } else if (workflowRelPath.includes('/src/') || workflowRelPath.startsWith('src/')) { + const match = workflowRelPath.match(/(?:^|\/)src\/([^/]+)\/(.+)/); if (match) { workflowRelPath = `${match[1]}/${match[2]}`; } @@ -119,30 +119,9 @@ class WorkflowCommandGenerator { * Generate command content for a workflow */ async generateCommandContent(workflow, bmadDir) { - // Determine template based on workflow file type - const templatePath = path.join(path.dirname(this.templatePath), 'workflow-commander.md'); - - // Load the appropriate template - const template = await fs.readFile(templatePath, 'utf8'); - - // Convert source path to installed path - // From: /Users/.../src/bmm/workflows/.../workflow.md - // To: {project-root}/_bmad/bmm/workflows/.../workflow.md - let workflowPath = workflow.path; - - // Extract the relative path from source - if (workflowPath.includes('/src/bmm/')) { - // bmm is directly under src/ - const match = workflowPath.match(/\/src\/bmm\/(.+)/); - if (match) { - workflowPath = `${this.bmadFolderName}/bmm/${match[1]}`; - } - } else if (workflowPath.includes('/src/core/')) { - const match = workflowPath.match(/\/src\/core\/(.+)/); - if (match) { - workflowPath = `${this.bmadFolderName}/core/${match[1]}`; - } - } + // Load the workflow command template + const template = await fs.readFile(this.templatePath, 'utf8'); + const workflowPath = this.mapSourcePathToInstalled(workflow.path); // Replace template variables return template @@ -212,14 +191,15 @@ class WorkflowCommandGenerator { When running any workflow: 1. Resolve loader paths: - Primary: {project-root}/${this.bmadFolderName}/core/tasks/workflow.md - - Fallback: {project-root}/src/core/tasks/workflow.md + - Optional dev fallback: {project-root}/src/core/tasks/workflow.md (only if it exists and is readable) 2. Check the primary path exists and is readable before loading -3. If primary is missing/unreadable, log a warning with the path and error, then try fallback -4. If fallback is also missing/unreadable, log an error with both attempted paths and stop -5. LOAD the resolved workflow loader file -6. Pass the workflow path as 'workflow-config' parameter -7. Follow workflow.md instructions EXACTLY -8. Save outputs after EACH section +3. If primary is missing/unreadable, log a warning with the primary path and error +4. Only if the dev fallback exists and is readable, try the fallback path; otherwise skip it +5. If no readable loader is found, log an error with all attempted readable paths and stop +6. LOAD the resolved workflow loader file +7. Pass the workflow path as 'workflow-config' parameter +8. Follow workflow.md instructions EXACTLY +9. Save outputs after EACH section ## Modes - Normal: Full interaction @@ -230,21 +210,33 @@ When running any workflow: } transformWorkflowPath(workflowPath) { - let transformed = workflowPath; + return this.mapSourcePathToInstalled(workflowPath, true); + } - if (workflowPath.includes('/src/bmm/')) { - const match = workflowPath.match(/\/src\/bmm\/(.+)/); - if (match) { - transformed = `{project-root}/${this.bmadFolderName}/bmm/${match[1]}`; - } - } else if (workflowPath.includes('/src/core/')) { - const match = workflowPath.match(/\/src\/core\/(.+)/); - if (match) { - transformed = `{project-root}/${this.bmadFolderName}/core/${match[1]}`; - } + mapSourcePathToInstalled(sourcePath, includeProjectRootPrefix = false) { + if (!sourcePath) { + return sourcePath; } - return transformed; + const normalized = sourcePath.replaceAll('\\', '/'); + const srcMatch = normalized.match(/(?:^|\/)src\/([^/]+)\/(.+)/); + if (srcMatch) { + const mapped = `${this.bmadFolderName}/${srcMatch[1]}/${srcMatch[2]}`; + return includeProjectRootPrefix ? `{project-root}/${mapped}` : mapped; + } + + if (normalized.includes('_bmad/')) { + const parts = normalized.split(/_bmad\//); + const relative = parts.at(-1); + const mapped = `${this.bmadFolderName}/${relative}`; + return includeProjectRootPrefix ? `{project-root}/${mapped}` : mapped; + } + + if (normalized.startsWith(`${this.bmadFolderName}/`)) { + return includeProjectRootPrefix ? `{project-root}/${normalized}` : normalized; + } + + return sourcePath; } async loadWorkflowManifest(bmadDir) { diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js index 05109dbca..a81c7b15c 100644 --- a/tools/cli/installers/lib/modules/manager.js +++ b/tools/cli/installers/lib/modules/manager.js @@ -813,7 +813,6 @@ class ModuleManager { const newline = frontmatterMatch[0].includes('\r\n') ? '\r\n' : '\n'; try { - const yaml = require('yaml'); const parsed = yaml.parse(frontmatterMatch[1]); if (!parsed || typeof parsed !== 'object' || !Object.prototype.hasOwnProperty.call(parsed, 'web_bundle')) { @@ -897,7 +896,6 @@ class ModuleManager { let manifestData = {}; if (await fs.pathExists(manifestPath)) { const manifestContent = await fs.readFile(manifestPath, 'utf8'); - const yaml = require('yaml'); manifestData = yaml.parse(manifestContent); } if (!manifestData.agentCustomizations) { @@ -906,7 +904,6 @@ class ModuleManager { manifestData.agentCustomizations[path.relative(bmadDir, customizePath)] = originalHash; // Write back to manifest - const yaml = require('yaml'); // Clean the manifest data to remove any non-serializable values const cleanManifestData = structuredClone(manifestData);