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.
@@ -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
+ };