Compare commits
5 Commits
f96800d330
...
3b8d5de9da
| Author | SHA1 | Date |
|---|---|---|
|
|
3b8d5de9da | |
|
|
a955c8611d | |
|
|
a8666294cb | |
|
|
4d0b0fdcd1 | |
|
|
707de90238 |
|
|
@ -109,29 +109,6 @@ module.exports = {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve owner/repo for badge (git remote → prompt fallback)
|
|
||||||
if (!config.noBadge) {
|
|
||||||
const badge = require('../core/badge');
|
|
||||||
let remote = badge.resolveGitRemote(config.directory);
|
|
||||||
if (!remote) {
|
|
||||||
const input = await prompts.text({
|
|
||||||
message: 'Enter your GitHub owner/repo for the badge (e.g., nick/my-project):',
|
|
||||||
placeholder: 'owner/repo',
|
|
||||||
validate: (v) => (!v || !v.includes('/') ? 'Format: owner/repo' : undefined),
|
|
||||||
});
|
|
||||||
if (input) {
|
|
||||||
const [owner, repo] = input.split('/');
|
|
||||||
remote = { owner, repo };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (remote) {
|
|
||||||
config.badgeOwner = remote.owner;
|
|
||||||
config.badgeRepo = remote.repo;
|
|
||||||
} else {
|
|
||||||
config.noBadge = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle cancel
|
// Handle cancel
|
||||||
if (config.actionType === 'cancel') {
|
if (config.actionType === 'cancel') {
|
||||||
await prompts.log.warn('Installation cancelled.');
|
await prompts.log.warn('Installation cancelled.');
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ const { execSync } = require('node:child_process');
|
||||||
const fs = require('../fs-native');
|
const fs = require('../fs-native');
|
||||||
|
|
||||||
const BADGE_URL = 'https://bmad-badge.vercel.app';
|
const BADGE_URL = 'https://bmad-badge.vercel.app';
|
||||||
const escapedBadgeUrl = BADGE_URL.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
const escapedBadgeUrl = BADGE_URL.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
const BADGE_PATTERN = new RegExp(`\\[!\\[BMAD\\]\\(${escapedBadgeUrl}/[^)]+\\)\\]\\(https://github\\.com/bmad-code-org/BMAD-METHOD\\)`);
|
const BADGE_PATTERN = new RegExp(
|
||||||
|
`\\[!\\[BMAD\\]\\(${escapedBadgeUrl}/[^)]+\\)\\]\\(https://github\\.com/bmad-code-org/BMAD-METHOD\\)`,
|
||||||
|
);
|
||||||
const README_NAMES = ['README.md', 'readme.md', 'README', 'readme'];
|
const README_NAMES = ['README.md', 'readme.md', 'README', 'readme'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -81,9 +83,9 @@ function injectBadge(content, owner, repo) {
|
||||||
|
|
||||||
// Find the first heading (# title)
|
// Find the first heading (# title)
|
||||||
let headingEnd = 0;
|
let headingEnd = 0;
|
||||||
for (const [i, line] of lines.entries()) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
headingEnd = i + 1;
|
headingEnd = i + 1;
|
||||||
if (line.startsWith('#')) break;
|
if (lines[i].startsWith('#')) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are existing badges right after the heading
|
// Check if there are existing badges right after the heading
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@ class Config {
|
||||||
quickUpdate,
|
quickUpdate,
|
||||||
channelOptions,
|
channelOptions,
|
||||||
setOverrides,
|
setOverrides,
|
||||||
noBadge,
|
|
||||||
badgeOwner,
|
|
||||||
badgeRepo,
|
|
||||||
}) {
|
}) {
|
||||||
this.directory = directory;
|
this.directory = directory;
|
||||||
this.modules = Object.freeze([...modules]);
|
this.modules = Object.freeze([...modules]);
|
||||||
|
|
@ -35,9 +32,6 @@ class Config {
|
||||||
// Intentionally NOT integrated with the prompt/template/schema flow; see
|
// Intentionally NOT integrated with the prompt/template/schema flow; see
|
||||||
// `tools/installer/set-overrides.js` for the rationale and tradeoffs.
|
// `tools/installer/set-overrides.js` for the rationale and tradeoffs.
|
||||||
this.setOverrides = setOverrides || {};
|
this.setOverrides = setOverrides || {};
|
||||||
this.noBadge = noBadge || false;
|
|
||||||
this.badgeOwner = badgeOwner || null;
|
|
||||||
this.badgeRepo = badgeRepo || null;
|
|
||||||
Object.freeze(this);
|
Object.freeze(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,9 +58,6 @@ class Config {
|
||||||
quickUpdate: userInput._quickUpdate || false,
|
quickUpdate: userInput._quickUpdate || false,
|
||||||
channelOptions: userInput.channelOptions || null,
|
channelOptions: userInput.channelOptions || null,
|
||||||
setOverrides: userInput.setOverrides || {},
|
setOverrides: userInput.setOverrides || {},
|
||||||
noBadge: userInput.noBadge || false,
|
|
||||||
badgeOwner: userInput.badgeOwner || null,
|
|
||||||
badgeRepo: userInput.badgeRepo || null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ class Installer {
|
||||||
// Inject BMAD badge into README if applicable
|
// Inject BMAD badge into README if applicable
|
||||||
if (!config.noBadge) {
|
if (!config.noBadge) {
|
||||||
try {
|
try {
|
||||||
await this._injectBadgeIfNeeded(paths.projectRoot, addResult, config);
|
await this._injectBadgeIfNeeded(paths.projectRoot, addResult);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addResult('Badge', 'warn', `skipped: ${error.message}`);
|
addResult('Badge', 'warn', `skipped: ${error.message}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1048,26 +1048,26 @@ class Installer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject BMAD version badge into project README.
|
* Inject BMAD version badge into project README if applicable.
|
||||||
* Uses owner/repo from config (resolved in UI layer).
|
* Skipped when --no-badge is set, when no git remote is found,
|
||||||
|
* or when no README exists.
|
||||||
* @param {string} projectDir - Project root directory
|
* @param {string} projectDir - Project root directory
|
||||||
* @param {Function} addResult - Callback to record results
|
* @param {Function} addResult - Callback to record results
|
||||||
* @param {Object} config - Installation config with badgeOwner/badgeRepo
|
|
||||||
*/
|
*/
|
||||||
async _injectBadgeIfNeeded(projectDir, addResult, config) {
|
async _injectBadgeIfNeeded(projectDir, addResult) {
|
||||||
const badge = require('../core/badge');
|
const badge = require('../core/badge');
|
||||||
|
|
||||||
const owner = config.badgeOwner;
|
const remote = badge.resolveGitRemote(projectDir);
|
||||||
const repo = config.badgeRepo;
|
if (!remote) {
|
||||||
if (!owner || !repo) {
|
addResult('Badge', 'warn', 'no git remote found');
|
||||||
addResult('Badge', 'warn', 'no owner/repo provided');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const readmePath = await badge.findReadme(projectDir);
|
const readmePath = await badge.findReadme(projectDir);
|
||||||
if (!readmePath) {
|
if (!readmePath) {
|
||||||
|
// No README — create one with the badge
|
||||||
const projectName = path.basename(projectDir);
|
const projectName = path.basename(projectDir);
|
||||||
const content = badge.createReadmeWithBadge(owner, repo, projectName);
|
const content = badge.createReadmeWithBadge(remote.owner, remote.repo, projectName);
|
||||||
const newReadmePath = path.join(projectDir, 'README.md');
|
const newReadmePath = path.join(projectDir, 'README.md');
|
||||||
await fs.writeFile(newReadmePath, content, 'utf8');
|
await fs.writeFile(newReadmePath, content, 'utf8');
|
||||||
addResult('Badge', 'ok', 'created README.md with badge');
|
addResult('Badge', 'ok', 'created README.md with badge');
|
||||||
|
|
@ -1076,15 +1076,11 @@ class Installer {
|
||||||
|
|
||||||
const content = await fs.readFile(readmePath, 'utf8');
|
const content = await fs.readFile(readmePath, 'utf8');
|
||||||
if (badge.hasBadge(content)) {
|
if (badge.hasBadge(content)) {
|
||||||
// Update badge if owner/repo changed
|
addResult('Badge', 'ok', 'already present');
|
||||||
const updated = badge.removeBadge(content);
|
|
||||||
const injected = badge.injectBadge(updated, owner, repo);
|
|
||||||
await fs.writeFile(readmePath, injected, 'utf8');
|
|
||||||
addResult('Badge', 'ok', `updated in ${path.basename(readmePath)}`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updated = badge.injectBadge(content, owner, repo);
|
const updated = badge.injectBadge(content, remote.owner, remote.repo);
|
||||||
await fs.writeFile(readmePath, updated, 'utf8');
|
await fs.writeFile(readmePath, updated, 'utf8');
|
||||||
addResult('Badge', 'ok', `added to ${path.basename(readmePath)}`);
|
addResult('Badge', 'ok', `added to ${path.basename(readmePath)}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1346,8 +1342,6 @@ class Installer {
|
||||||
modules: modulesToUpdate,
|
modules: modulesToUpdate,
|
||||||
ides: configuredIdes,
|
ides: configuredIdes,
|
||||||
noBadge: config.noBadge,
|
noBadge: config.noBadge,
|
||||||
badgeOwner: config.badgeOwner,
|
|
||||||
badgeRepo: config.badgeRepo,
|
|
||||||
coreConfig: quickModules.collectedConfig.core,
|
coreConfig: quickModules.collectedConfig.core,
|
||||||
moduleConfigs: quickModules.collectedConfig,
|
moduleConfigs: quickModules.collectedConfig,
|
||||||
// Forward `--set` overrides so the post-install patch step
|
// Forward `--set` overrides so the post-install patch step
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue