From a8666294cbbe543a5e124c149c915031644b6999 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 1 May 2026 15:54:05 +0800 Subject: [PATCH] fix(installer): address CodeRabbit review feedback on badge integration - Derive BADGE_PATTERN from BADGE_URL constant (configurable) - Fix git remote regex to support repo names with dots - Add try/catch around badge injection so IO errors don't abort install - Add try/catch around badge cleanup in uninstall (best-effort) - Pass noBadge through quickUpdate flow Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- tools/installer/commands/uninstall.js | 18 +++++++++++------- tools/installer/core/badge.js | 7 +++++-- tools/installer/core/installer.js | 7 ++++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/tools/installer/commands/uninstall.js b/tools/installer/commands/uninstall.js index 19b2447ad..dc2055027 100644 --- a/tools/installer/commands/uninstall.js +++ b/tools/installer/commands/uninstall.js @@ -140,14 +140,18 @@ module.exports = { await installer.uninstallModules(projectDir); s.stop('Modules & data removed'); - // Remove BMAD badge from README - const badge = require('../core/badge'); - const readmePath = await badge.findReadme(projectDir); - if (readmePath) { - const content = await fs.readFile(readmePath, 'utf8'); - if (badge.hasBadge(content)) { - await fs.writeFile(readmePath, badge.removeBadge(content), 'utf8'); + // Remove BMAD badge from README (best-effort) + try { + const badge = require('../core/badge'); + const readmePath = await badge.findReadme(projectDir); + if (readmePath) { + const content = await fs.readFile(readmePath, 'utf8'); + if (badge.hasBadge(content)) { + await fs.writeFile(readmePath, badge.removeBadge(content), 'utf8'); + } } + } catch (error) { + await prompts.log.warn(`Badge cleanup skipped: ${error.message}`); } } diff --git a/tools/installer/core/badge.js b/tools/installer/core/badge.js index 0a9b250f5..7c1274779 100644 --- a/tools/installer/core/badge.js +++ b/tools/installer/core/badge.js @@ -3,7 +3,10 @@ const { execSync } = require('node:child_process'); const fs = require('../fs-native'); const BADGE_URL = 'https://bmad-badge.vercel.app'; -const BADGE_PATTERN = /\[!\[BMAD\]\(https:\/\/bmad-badge\.vercel\.app\/[^\)]+\)\]\(https:\/\/github\.com\/bmad-code-org\/BMAD-METHOD\)/; +const escapedBadgeUrl = BADGE_URL.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +const BADGE_PATTERN = new RegExp( + `\\[!\\[BMAD\\]\\(${escapedBadgeUrl}/[^)]+\\)\\]\\(https://github\\.com/bmad-code-org/BMAD-METHOD\\)`, +); const README_NAMES = ['README.md', 'readme.md', 'README', 'readme']; function resolveGitRemote(projectDir) { @@ -15,7 +18,7 @@ function resolveGitRemote(projectDir) { }).trim(); // https://github.com/owner/repo.git - const httpsMatch = raw.match(/github\.com[:/]([^/]+)\/([^/.]+)/); + const httpsMatch = raw.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?\/?$/i); if (httpsMatch) { return { owner: httpsMatch[1], repo: httpsMatch[2] }; } diff --git a/tools/installer/core/installer.js b/tools/installer/core/installer.js index 580ecb57d..6090c2282 100644 --- a/tools/installer/core/installer.js +++ b/tools/installer/core/installer.js @@ -105,7 +105,11 @@ class Installer { // Inject BMAD badge into README if applicable if (!config.noBadge) { - await this._injectBadgeIfNeeded(paths.projectRoot, addResult); + try { + await this._injectBadgeIfNeeded(paths.projectRoot, addResult); + } catch (error) { + addResult('Badge', 'warn', `skipped: ${error.message}`); + } } // Render consolidated summary @@ -1337,6 +1341,7 @@ class Installer { directory: projectDir, modules: modulesToUpdate, ides: configuredIdes, + noBadge: config.noBadge, coreConfig: quickModules.collectedConfig.core, moduleConfigs: quickModules.collectedConfig, // Forward `--set` overrides so the post-install patch step