bmad-plus 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +2 -1
- package/package.json +5 -4
- package/readme-international/README.de.md +1 -1
- package/readme-international/README.es.md +1 -1
- package/readme-international/README.fr.md +1 -1
- package/src/bmad-plus/module.yaml +29 -0
- package/tools/cli/bmad-plus-cli.js +23 -0
- package/tools/cli/commands/doctor.js +175 -0
- package/tools/cli/commands/install.js +40 -3
- package/tools/cli/commands/uninstall.js +34 -8
- package/tools/cli/commands/update.js +172 -0
- package/tools/cli/i18n.js +425 -303
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BMAD+ Update Command
|
|
3
|
+
* Updates agents and skills while preserving user config
|
|
4
|
+
*
|
|
5
|
+
* Author: Laurent Rochetta
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('node:fs');
|
|
10
|
+
const fsExtra = require('fs-extra');
|
|
11
|
+
const clack = require('@clack/prompts');
|
|
12
|
+
const pc = require('picocolors');
|
|
13
|
+
const { t } = require('../i18n');
|
|
14
|
+
|
|
15
|
+
// Same pack definitions as install.js — keep in sync
|
|
16
|
+
const PACKS = {
|
|
17
|
+
core: {
|
|
18
|
+
agents: ['agent-strategist', 'agent-architect-dev', 'agent-quality', 'agent-orchestrator'],
|
|
19
|
+
skills: ['bmad-plus-autopilot', 'bmad-plus-parallel', 'bmad-plus-sync'],
|
|
20
|
+
data: ['role-triggers.yaml'],
|
|
21
|
+
},
|
|
22
|
+
osint: {
|
|
23
|
+
agents: ['agent-shadow'],
|
|
24
|
+
skills: [],
|
|
25
|
+
externalPackage: 'osint-agent-package',
|
|
26
|
+
},
|
|
27
|
+
maker: {
|
|
28
|
+
agents: ['agent-maker'],
|
|
29
|
+
skills: [],
|
|
30
|
+
data: [],
|
|
31
|
+
},
|
|
32
|
+
seo: { agents: [], skills: [], packDir: 'pack-seo' },
|
|
33
|
+
backup: { agents: [], skills: [], packDir: 'pack-backup' },
|
|
34
|
+
animated: { agents: [], skills: [], packDir: 'pack-animated' },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
command: 'update',
|
|
39
|
+
description: 'Update BMAD+ agents and skills (preserves config)',
|
|
40
|
+
options: [
|
|
41
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
42
|
+
],
|
|
43
|
+
action: async (options) => {
|
|
44
|
+
const projectDir = path.resolve(options.directory || process.cwd());
|
|
45
|
+
const bmadSrc = path.join(__dirname, '..', '..', '..', 'src', 'bmad-plus');
|
|
46
|
+
const packageJson = require('../../../package.json');
|
|
47
|
+
|
|
48
|
+
clack.intro(pc.bgMagenta(pc.white(` BMAD+ Updater v${packageJson.version} `)));
|
|
49
|
+
|
|
50
|
+
// Check if installed
|
|
51
|
+
const manifestPath = path.join(projectDir, '_bmad', '.bmad-plus-install.json');
|
|
52
|
+
if (!fs.existsSync(manifestPath)) {
|
|
53
|
+
clack.log.error('BMAD+ is not installed in this directory.');
|
|
54
|
+
clack.log.info('Run `npx bmad-plus install` first.');
|
|
55
|
+
clack.outro(pc.red('Update aborted.'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
60
|
+
const lang = manifest.uiLanguage || 'en';
|
|
61
|
+
const i = t(lang);
|
|
62
|
+
|
|
63
|
+
clack.log.info(`📦 Installed: v${manifest.version} → Available: v${packageJson.version}`);
|
|
64
|
+
|
|
65
|
+
if (manifest.version === packageJson.version) {
|
|
66
|
+
clack.log.success(i.update_current || '✅ Already up to date!');
|
|
67
|
+
clack.outro(pc.green('Nothing to update.'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const selectedPacks = manifest.packs || ['core'];
|
|
72
|
+
clack.log.info(`${i.selected_packs}: ${selectedPacks.join(', ')}`);
|
|
73
|
+
|
|
74
|
+
const confirm = await clack.confirm({
|
|
75
|
+
message: i.update_confirm || `Update from v${manifest.version} to v${packageJson.version}?`,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!confirm || clack.isCancel(confirm)) {
|
|
79
|
+
clack.cancel(i.cancelled);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const spinner = clack.spinner();
|
|
84
|
+
spinner.start(i.update_updating || 'Updating agents and skills...');
|
|
85
|
+
|
|
86
|
+
const targetAgentsDir = path.join(projectDir, '.agents', 'skills');
|
|
87
|
+
const targetDataDir = path.join(projectDir, '.agents', 'data');
|
|
88
|
+
|
|
89
|
+
fsExtra.ensureDirSync(targetAgentsDir);
|
|
90
|
+
fsExtra.ensureDirSync(targetDataDir);
|
|
91
|
+
|
|
92
|
+
let updated = 0;
|
|
93
|
+
|
|
94
|
+
for (const packId of selectedPacks) {
|
|
95
|
+
const pack = PACKS[packId];
|
|
96
|
+
if (!pack) continue;
|
|
97
|
+
|
|
98
|
+
// Update agents
|
|
99
|
+
for (const agent of (pack.agents || [])) {
|
|
100
|
+
const src = path.join(bmadSrc, 'agents', agent);
|
|
101
|
+
const dest = path.join(targetAgentsDir, agent);
|
|
102
|
+
if (fs.existsSync(src)) {
|
|
103
|
+
fsExtra.copySync(src, dest, { overwrite: true });
|
|
104
|
+
updated++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Update skills
|
|
109
|
+
for (const skill of (pack.skills || [])) {
|
|
110
|
+
const src = path.join(bmadSrc, 'skills', skill);
|
|
111
|
+
const dest = path.join(targetAgentsDir, skill);
|
|
112
|
+
if (fs.existsSync(src)) {
|
|
113
|
+
fsExtra.copySync(src, dest, { overwrite: true });
|
|
114
|
+
updated++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Update data files
|
|
119
|
+
for (const dataFile of (pack.data || [])) {
|
|
120
|
+
const src = path.join(bmadSrc, 'data', dataFile);
|
|
121
|
+
const dest = path.join(targetDataDir, dataFile);
|
|
122
|
+
if (fs.existsSync(src)) {
|
|
123
|
+
fsExtra.copySync(src, dest, { overwrite: true });
|
|
124
|
+
updated++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Update external package (OSINT)
|
|
129
|
+
if (pack.externalPackage) {
|
|
130
|
+
const extSrc = path.join(__dirname, '..', '..', '..', pack.externalPackage, 'skills');
|
|
131
|
+
if (fs.existsSync(extSrc)) {
|
|
132
|
+
fsExtra.copySync(extSrc, targetAgentsDir, { overwrite: true });
|
|
133
|
+
updated++;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Update pack directory (SEO, Backup, Animated)
|
|
138
|
+
if (pack.packDir) {
|
|
139
|
+
const packSrc = path.join(bmadSrc, 'agents', pack.packDir);
|
|
140
|
+
const packDest = path.join(targetAgentsDir, pack.packDir);
|
|
141
|
+
if (fs.existsSync(packSrc)) {
|
|
142
|
+
fsExtra.copySync(packSrc, packDest, { overwrite: true });
|
|
143
|
+
updated++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Update module config (always)
|
|
149
|
+
const moduleYaml = path.join(bmadSrc, 'module.yaml');
|
|
150
|
+
const targetBmadDir = path.join(projectDir, '_bmad');
|
|
151
|
+
if (fs.existsSync(moduleYaml)) {
|
|
152
|
+
fsExtra.copySync(moduleYaml, path.join(targetBmadDir, 'module.yaml'));
|
|
153
|
+
updated++;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const helpCsv = path.join(bmadSrc, 'module-help.csv');
|
|
157
|
+
if (fs.existsSync(helpCsv)) {
|
|
158
|
+
fsExtra.copySync(helpCsv, path.join(targetBmadDir, 'module-help.csv'));
|
|
159
|
+
updated++;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Update manifest version (preserve everything else)
|
|
163
|
+
manifest.version = packageJson.version;
|
|
164
|
+
manifest.lastUpdated = new Date().toISOString();
|
|
165
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
166
|
+
|
|
167
|
+
spinner.stop(i.update_done ? i.update_done(updated) : `✅ ${updated} files updated to v${packageJson.version}`);
|
|
168
|
+
|
|
169
|
+
clack.log.info('📋 Config preserved: config.yaml, IDE configs, output directories');
|
|
170
|
+
clack.outro(pc.green(i.update_ready || `BMAD+ v${packageJson.version} is ready! 🚀`));
|
|
171
|
+
},
|
|
172
|
+
};
|