bmad-enhanced 1.3.8 → 1.4.0
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/README.md +103 -124
- package/package.json +1 -1
- package/scripts/install-all-agents.js +53 -207
- package/scripts/postinstall.js +10 -7
- package/scripts/update/bmad-migrate.js +58 -5
- package/scripts/update/bmad-update.js +17 -7
- package/scripts/update/bmad-version.js +20 -6
- package/scripts/update/lib/backup-manager.js +22 -58
- package/scripts/update/lib/config-merger.js +1 -35
- package/scripts/update/lib/migration-runner.js +78 -114
- package/scripts/update/lib/refresh-installation.js +132 -0
- package/scripts/update/lib/utils.js +96 -0
- package/scripts/update/lib/validator.js +31 -151
- package/scripts/update/lib/version-detector.js +36 -41
- package/scripts/update/migrations/1.0.x-to-1.3.0.js +41 -222
- package/scripts/update/migrations/1.1.x-to-1.3.0.js +7 -188
- package/scripts/update/migrations/1.2.x-to-1.3.0.js +7 -188
- package/scripts/update/migrations/registry.js +27 -52
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const { refreshInstallation } = require('./update/lib/refresh-installation');
|
|
5
6
|
|
|
6
7
|
const BOLD = '\x1b[1m';
|
|
7
8
|
const RESET = '\x1b[0m';
|
|
@@ -17,17 +18,16 @@ function printBanner() {
|
|
|
17
18
|
console.log(`${MAGENTA}${BOLD}║ ║${RESET}`);
|
|
18
19
|
console.log(`${MAGENTA}${BOLD}║ BMAD-Enhanced Complete Installer 🚀 ║${RESET}`);
|
|
19
20
|
console.log(`${MAGENTA}${BOLD}║ ║${RESET}`);
|
|
20
|
-
console.log(`${MAGENTA}${BOLD}║ Installing Emma + Wade
|
|
21
|
+
console.log(`${MAGENTA}${BOLD}║ Installing Emma + Wade Vortex Agents ║${RESET}`);
|
|
21
22
|
console.log(`${MAGENTA}${BOLD}║ ║${RESET}`);
|
|
22
23
|
console.log(`${MAGENTA}${BOLD}╚════════════════════════════════════════════════════╝${RESET}`);
|
|
23
24
|
console.log('');
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
function checkPrerequisites() {
|
|
27
|
+
function checkPrerequisites(projectRoot) {
|
|
27
28
|
console.log(`${CYAN}[1/6]${RESET} Checking prerequisites...`);
|
|
28
29
|
|
|
29
|
-
const
|
|
30
|
-
const bmadDir = path.join(targetDir, '_bmad');
|
|
30
|
+
const bmadDir = path.join(projectRoot, '_bmad');
|
|
31
31
|
|
|
32
32
|
// Create _bmad directory if it doesn't exist
|
|
33
33
|
if (!fs.existsSync(bmadDir)) {
|
|
@@ -48,160 +48,54 @@ function checkPrerequisites() {
|
|
|
48
48
|
console.log(`${GREEN} ✓${RESET} Prerequisites met`);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function
|
|
52
|
-
console.log(`${CYAN}[2/6]${RESET}
|
|
51
|
+
function archiveDeprecatedWorkflows(projectRoot) {
|
|
52
|
+
console.log(`${CYAN}[2/6]${RESET} Archiving deprecated workflows...`);
|
|
53
53
|
|
|
54
54
|
const sourceDir = path.join(__dirname, '..', '_bmad', 'bme', '_vortex');
|
|
55
|
-
const targetDir = path.join(
|
|
56
|
-
|
|
57
|
-
// Create target directory structure
|
|
58
|
-
fs.mkdirSync(path.join(targetDir, 'agents'), { recursive: true });
|
|
59
|
-
fs.mkdirSync(path.join(targetDir, 'workflows', '_deprecated', 'empathy-map', 'steps'), { recursive: true });
|
|
60
|
-
fs.mkdirSync(path.join(targetDir, 'workflows', '_deprecated', 'wireframe', 'steps'), { recursive: true });
|
|
61
|
-
|
|
62
|
-
// Copy Emma agent file
|
|
63
|
-
console.log(`${CYAN} →${RESET} Installing Emma (contextualization-expert)...`);
|
|
64
|
-
fs.copyFileSync(
|
|
65
|
-
path.join(sourceDir, 'agents', 'contextualization-expert.md'),
|
|
66
|
-
path.join(targetDir, 'agents', 'contextualization-expert.md')
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
// Copy Emma workflow files
|
|
70
|
-
const emmaWorkflowFiles = [
|
|
71
|
-
'workflow.md',
|
|
72
|
-
'empathy-map.template.md',
|
|
73
|
-
'steps/step-01-define-user.md',
|
|
74
|
-
'steps/step-02-says-thinks.md',
|
|
75
|
-
'steps/step-03-does-feels.md',
|
|
76
|
-
'steps/step-04-pain-points.md',
|
|
77
|
-
'steps/step-05-gains.md',
|
|
78
|
-
'steps/step-06-synthesize.md'
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
emmaWorkflowFiles.forEach(file => {
|
|
82
|
-
fs.copyFileSync(
|
|
83
|
-
path.join(sourceDir, 'workflows', '_deprecated', 'empathy-map', file),
|
|
84
|
-
path.join(targetDir, 'workflows', '_deprecated', 'empathy-map', file)
|
|
85
|
-
);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
console.log(`${GREEN} ✓${RESET} Emma installed`);
|
|
89
|
-
|
|
90
|
-
// Copy Wade agent file
|
|
91
|
-
console.log(`${CYAN} →${RESET} Installing Wade (lean-experiments-specialist)...`);
|
|
92
|
-
fs.copyFileSync(
|
|
93
|
-
path.join(sourceDir, 'agents', 'lean-experiments-specialist.md'),
|
|
94
|
-
path.join(targetDir, 'agents', 'lean-experiments-specialist.md')
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// Copy Wade workflow files
|
|
98
|
-
const wadeWorkflowFiles = [
|
|
99
|
-
'workflow.md',
|
|
100
|
-
'wireframe.template.md',
|
|
101
|
-
'steps/step-01-define-requirements.md',
|
|
102
|
-
'steps/step-02-user-flows.md',
|
|
103
|
-
'steps/step-03-information-architecture.md',
|
|
104
|
-
'steps/step-04-wireframe-sketch.md',
|
|
105
|
-
'steps/step-05-components.md',
|
|
106
|
-
'steps/step-06-synthesize.md'
|
|
107
|
-
];
|
|
108
|
-
|
|
109
|
-
wadeWorkflowFiles.forEach(file => {
|
|
110
|
-
fs.copyFileSync(
|
|
111
|
-
path.join(sourceDir, 'workflows', '_deprecated', 'wireframe', file),
|
|
112
|
-
path.join(targetDir, 'workflows', '_deprecated', 'wireframe', file)
|
|
113
|
-
);
|
|
114
|
-
});
|
|
55
|
+
const targetDir = path.join(projectRoot, '_bmad', 'bme', '_vortex');
|
|
115
56
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// Copy all 7 new workflow directories
|
|
119
|
-
console.log(`${CYAN} →${RESET} Installing Vortex Framework workflows...`);
|
|
120
|
-
const workflows = [
|
|
121
|
-
'lean-persona',
|
|
122
|
-
'product-vision',
|
|
123
|
-
'contextualize-scope',
|
|
124
|
-
'mvp',
|
|
125
|
-
'lean-experiment',
|
|
126
|
-
'proof-of-concept',
|
|
127
|
-
'proof-of-value'
|
|
128
|
-
];
|
|
57
|
+
// Create deprecated workflow archive directories
|
|
58
|
+
const deprecatedWorkflows = ['empathy-map', 'wireframe'];
|
|
129
59
|
|
|
130
|
-
|
|
131
|
-
const workflowSourceDir = path.join(sourceDir, 'workflows', workflow);
|
|
132
|
-
const workflowTargetDir = path.join(targetDir, 'workflows', workflow);
|
|
60
|
+
for (const workflow of deprecatedWorkflows) {
|
|
61
|
+
const workflowSourceDir = path.join(sourceDir, 'workflows', '_deprecated', workflow);
|
|
62
|
+
const workflowTargetDir = path.join(targetDir, 'workflows', '_deprecated', workflow);
|
|
133
63
|
|
|
134
64
|
if (fs.existsSync(workflowSourceDir)) {
|
|
135
65
|
fs.copySync(workflowSourceDir, workflowTargetDir);
|
|
136
|
-
console.log(`${GREEN}
|
|
137
|
-
} else {
|
|
138
|
-
console.log(`${YELLOW} ⚠${RESET} ${workflow} not found in package (skipping)`);
|
|
66
|
+
console.log(`${GREEN} ✓${RESET} Archived ${workflow} to _deprecated/`);
|
|
139
67
|
}
|
|
140
|
-
}
|
|
68
|
+
}
|
|
141
69
|
|
|
142
|
-
|
|
70
|
+
// Legacy cleanup
|
|
71
|
+
cleanupLegacyFiles(projectRoot);
|
|
143
72
|
}
|
|
144
73
|
|
|
145
|
-
function
|
|
146
|
-
console.log(`${CYAN}
|
|
147
|
-
|
|
148
|
-
const configPath = path.join(process.cwd(), '_bmad', 'bme', '_vortex', 'config.yaml');
|
|
149
|
-
const manifestPath = path.join(process.cwd(), '_bmad', '_config', 'agent-manifest.csv');
|
|
150
|
-
|
|
151
|
-
console.log(`${CYAN} →${RESET} Config path: ${configPath}`);
|
|
152
|
-
|
|
153
|
-
// Create config
|
|
154
|
-
const configContent = `---
|
|
155
|
-
submodule_name: _vortex
|
|
156
|
-
description: Contextualize and Externalize streams - Strategic framing and validated learning
|
|
157
|
-
module: bme
|
|
158
|
-
version: 1.3.8
|
|
159
|
-
|
|
160
|
-
# Output Configuration
|
|
161
|
-
output_folder: "{project-root}/_bmad-output/vortex-artifacts"
|
|
162
|
-
user_name: "{user}"
|
|
163
|
-
communication_language: "en"
|
|
164
|
-
|
|
165
|
-
# Agents in this submodule
|
|
166
|
-
agents:
|
|
167
|
-
- contextualization-expert # Emma - Contextualization Expert
|
|
168
|
-
- lean-experiments-specialist # Wade - Lean Experiments Specialist
|
|
169
|
-
|
|
170
|
-
# Workflows available
|
|
171
|
-
workflows:
|
|
172
|
-
# Emma - Contextualize Stream
|
|
173
|
-
- lean-persona # Create lean user personas
|
|
174
|
-
- product-vision # Define product vision
|
|
175
|
-
- contextualize-scope # Decide which problem space to investigate
|
|
176
|
-
|
|
177
|
-
# Wade - Externalize Stream
|
|
178
|
-
- mvp # Design Minimum Viable Product
|
|
179
|
-
- lean-experiment # Run Build-Measure-Learn cycle
|
|
180
|
-
- proof-of-concept # Validate technical feasibility
|
|
181
|
-
- proof-of-value # Validate business value
|
|
182
|
-
|
|
183
|
-
# Integration
|
|
184
|
-
party_mode_enabled: true
|
|
185
|
-
core_module: bme
|
|
186
|
-
`;
|
|
74
|
+
function cleanupLegacyFiles(projectRoot) {
|
|
75
|
+
console.log(`${CYAN} →${RESET} Cleaning up legacy files...`);
|
|
187
76
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
77
|
+
// Remove _designos directory (pre-Vortex structure) from all possible locations
|
|
78
|
+
const legacyPaths = [
|
|
79
|
+
path.join(projectRoot, '_bmad', 'bme', '_designos'),
|
|
80
|
+
path.join(projectRoot, '_bmad', '_designos'),
|
|
81
|
+
];
|
|
191
82
|
|
|
192
|
-
|
|
193
|
-
if (fs.existsSync(
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
console.error(`${RED} ✗${RESET} Config file not found after write!`);
|
|
83
|
+
for (const legacyPath of legacyPaths) {
|
|
84
|
+
if (fs.existsSync(legacyPath)) {
|
|
85
|
+
fs.removeSync(legacyPath);
|
|
86
|
+
console.log(`${GREEN} ✓${RESET} Removed legacy directory: ${path.relative(projectRoot, legacyPath)}`);
|
|
197
87
|
}
|
|
198
|
-
} catch (error) {
|
|
199
|
-
console.error(`${RED} ✗${RESET} Error creating config.yaml:`, error.message);
|
|
200
|
-
throw error;
|
|
201
88
|
}
|
|
202
89
|
|
|
203
|
-
|
|
90
|
+
console.log(`${GREEN} ✓${RESET} Legacy cleanup complete`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function createAgentManifest(projectRoot) {
|
|
94
|
+
console.log(`${CYAN}[3/6]${RESET} Creating agent manifest...`);
|
|
95
|
+
|
|
96
|
+
const manifestPath = path.join(projectRoot, '_bmad', '_config', 'agent-manifest.csv');
|
|
204
97
|
fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
|
|
98
|
+
|
|
205
99
|
const header = '"agent_id","name","title","icon","role","identity","communication_style","expertise","submodule","path"\n';
|
|
206
100
|
const emmaRow = '"contextualization-expert","Emma","Contextualization Expert","🎯","Strategic Framing + Problem-Product Space Navigator","Expert in helping teams contextualize their product strategy by defining clear problem spaces and validating assumptions. Specializes in Lean Startup methodologies, persona creation, and product vision framing. Guides teams through the critical \'Contextualize\' stream of the Vortex framework.","Strategic yet approachable - speaks in frameworks and validated learning. Like a product strategist who asks \'What are we really solving?\' and \'Who is this truly for?\' Uses Lean Startup language (hypotheses, assumptions, pivots) and focuses on clarity before action.","- Master of Lean Startup and strategic framing methodologies - Personas over demographics - focus on jobs-to-be-done and problem contexts - Vision before features - align team around the \'why\' before the \'what\' - Challenge assumptions - every belief is a hypothesis until validated - Problem-solution fit comes before product-market fit","bme","_bmad/bme/_vortex/agents/contextualization-expert.md"\n';
|
|
207
101
|
const wadeRow = '"lean-experiments-specialist","Wade","Lean Experiments Specialist","🧪","Lean Startup + Validated Learning Expert","Lean Startup practitioner specialized in running rapid experiments to validate product hypotheses. Helps teams move from assumptions to evidence through Build-Measure-Learn cycles. Guides teams through the \'Externalize\' stream - taking ideas into the real world to test with actual users.","Experimental and evidence-driven - speaks in hypotheses, metrics, and learning. Like a scientist who says \'Let\'s test that assumption\' and \'What would prove us wrong?\' Uses Lean language (MVPs, pivots, validated learning) and focuses on speed-to-insight over perfection.","- Master of Lean Startup and rapid experimentation - Build the smallest thing that tests the riskiest assumption - Measure what matters - focus on actionable metrics, not vanity metrics - Learn fast, pivot faster - every experiment teaches something - Proof-of-concept before proof-of-value - validate feasibility before business case - Fail fast is good, learn fast is better","bme","_bmad/bme/_vortex/agents/lean-experiments-specialist.md"\n';
|
|
@@ -209,30 +103,27 @@ core_module: bme
|
|
|
209
103
|
console.log(`${GREEN} ✓${RESET} Created agent-manifest.csv`);
|
|
210
104
|
}
|
|
211
105
|
|
|
212
|
-
function createOutputDirectory() {
|
|
106
|
+
function createOutputDirectory(projectRoot) {
|
|
213
107
|
console.log(`${CYAN}[4/6]${RESET} Setting up output directory...`);
|
|
214
108
|
|
|
215
|
-
const outputDir = path.join(
|
|
109
|
+
const outputDir = path.join(projectRoot, '_bmad-output', 'vortex-artifacts');
|
|
216
110
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
217
111
|
|
|
218
112
|
console.log(`${GREEN} ✓${RESET} Output directory ready`);
|
|
219
113
|
}
|
|
220
114
|
|
|
221
|
-
function verifyInstallation() {
|
|
222
|
-
console.log(`${CYAN}[
|
|
115
|
+
function verifyInstallation(projectRoot) {
|
|
116
|
+
console.log(`${CYAN}[6/6]${RESET} Verifying installation...`);
|
|
223
117
|
|
|
224
|
-
const targetDir = process.cwd();
|
|
225
118
|
const checks = [
|
|
226
119
|
{ path: '_bmad/bme/_vortex/agents/contextualization-expert.md', name: 'Emma agent file' },
|
|
227
120
|
{ path: '_bmad/bme/_vortex/agents/lean-experiments-specialist.md', name: 'Wade agent file' },
|
|
228
|
-
{ path: '_bmad/bme/_vortex/workflows/_deprecated/empathy-map/workflow.md', name: 'Emma workflow (legacy)' },
|
|
229
|
-
{ path: '_bmad/bme/_vortex/workflows/_deprecated/wireframe/workflow.md', name: 'Wade workflow (legacy)' },
|
|
230
121
|
{ path: '_bmad/bme/_vortex/config.yaml', name: 'Configuration file' },
|
|
231
122
|
];
|
|
232
123
|
|
|
233
124
|
let allChecksPass = true;
|
|
234
125
|
checks.forEach(check => {
|
|
235
|
-
const fullPath = path.join(
|
|
126
|
+
const fullPath = path.join(projectRoot, check.path);
|
|
236
127
|
if (fs.existsSync(fullPath)) {
|
|
237
128
|
console.log(`${GREEN} ✓${RESET} ${check.name}`);
|
|
238
129
|
} else {
|
|
@@ -250,24 +141,6 @@ function verifyInstallation() {
|
|
|
250
141
|
console.log(`${GREEN} ✓${RESET} All files installed successfully`);
|
|
251
142
|
}
|
|
252
143
|
|
|
253
|
-
function copyUserGuides() {
|
|
254
|
-
console.log(`${CYAN}[6/6]${RESET} Installing user guides...`);
|
|
255
|
-
|
|
256
|
-
const sourceDir = path.join(__dirname, '..', '_bmad-output', 'vortex-artifacts');
|
|
257
|
-
const targetDir = path.join(process.cwd(), '_bmad-output', 'vortex-artifacts');
|
|
258
|
-
|
|
259
|
-
// Copy user guides if they exist
|
|
260
|
-
const guides = ['EMMA-USER-GUIDE.md', 'WADE-USER-GUIDE.md'];
|
|
261
|
-
guides.forEach(guide => {
|
|
262
|
-
const sourcePath = path.join(sourceDir, guide);
|
|
263
|
-
if (fs.existsSync(sourcePath)) {
|
|
264
|
-
fs.copyFileSync(sourcePath, path.join(targetDir, guide));
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
console.log(`${GREEN} ✓${RESET} User guides installed`);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
144
|
function printSuccess() {
|
|
272
145
|
console.log('');
|
|
273
146
|
console.log(`${GREEN}${BOLD}╔════════════════════════════════════════════════════╗${RESET}`);
|
|
@@ -289,51 +162,24 @@ function printSuccess() {
|
|
|
289
162
|
console.log(' Activate Wade:');
|
|
290
163
|
console.log(` ${CYAN}cat _bmad/bme/_vortex/agents/lean-experiments-specialist.md${RESET}`);
|
|
291
164
|
console.log('');
|
|
292
|
-
console.log(`${YELLOW}Note: User guides being updated for v1.2.0${RESET}`);
|
|
293
|
-
console.log('');
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function cleanupLegacyFiles() {
|
|
297
|
-
console.log(`${CYAN} →${RESET} Cleaning up legacy files...`);
|
|
298
|
-
|
|
299
|
-
// Remove _designos directory (pre-Vortex structure) from all possible locations
|
|
300
|
-
const legacyPaths = [
|
|
301
|
-
path.join(process.cwd(), '_bmad', 'bme', '_designos'),
|
|
302
|
-
path.join(process.cwd(), '_bmad', '_designos'),
|
|
303
|
-
];
|
|
304
|
-
|
|
305
|
-
for (const legacyPath of legacyPaths) {
|
|
306
|
-
if (fs.existsSync(legacyPath)) {
|
|
307
|
-
fs.removeSync(legacyPath);
|
|
308
|
-
console.log(`${GREEN} ✓${RESET} Removed legacy directory: ${path.relative(process.cwd(), legacyPath)}`);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Remove deprecated agent files from _vortex/agents
|
|
313
|
-
const agentsDir = path.join(process.cwd(), '_bmad', 'bme', '_vortex', 'agents');
|
|
314
|
-
const deprecatedAgents = ['empathy-mapper.md', 'wireframe-designer.md'];
|
|
315
|
-
|
|
316
|
-
for (const agent of deprecatedAgents) {
|
|
317
|
-
const agentPath = path.join(agentsDir, agent);
|
|
318
|
-
if (fs.existsSync(agentPath)) {
|
|
319
|
-
fs.removeSync(agentPath);
|
|
320
|
-
console.log(`${GREEN} ✓${RESET} Removed deprecated agent: ${agent}`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
console.log(`${GREEN} ✓${RESET} Legacy cleanup complete`);
|
|
325
165
|
}
|
|
326
166
|
|
|
327
167
|
async function main() {
|
|
328
168
|
try {
|
|
169
|
+
const projectRoot = process.cwd();
|
|
170
|
+
|
|
329
171
|
printBanner();
|
|
330
|
-
checkPrerequisites();
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
172
|
+
checkPrerequisites(projectRoot);
|
|
173
|
+
archiveDeprecatedWorkflows(projectRoot);
|
|
174
|
+
createAgentManifest(projectRoot);
|
|
175
|
+
createOutputDirectory(projectRoot);
|
|
176
|
+
|
|
177
|
+
// Use refreshInstallation for agents, workflows, config, and user guides
|
|
178
|
+
console.log(`${CYAN}[5/6]${RESET} Installing agents, workflows, config, and guides...`);
|
|
179
|
+
await refreshInstallation(projectRoot, { backupGuides: false });
|
|
180
|
+
console.log(`${GREEN} ✓${RESET} Installation refreshed`);
|
|
181
|
+
|
|
182
|
+
verifyInstallation(projectRoot);
|
|
337
183
|
printSuccess();
|
|
338
184
|
} catch (error) {
|
|
339
185
|
console.error(`${RED}✗ Installation failed:${RESET}`, error.message);
|
package/scripts/postinstall.js
CHANGED
|
@@ -27,9 +27,12 @@ async function main() {
|
|
|
27
27
|
const versionDetector = require('./update/lib/version-detector');
|
|
28
28
|
const registry = require('./update/migrations/registry');
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const { findProjectRoot, compareVersions } = require('./update/lib/utils');
|
|
31
|
+
const projectRoot = findProjectRoot();
|
|
32
|
+
|
|
33
|
+
const currentVersion = versionDetector.getCurrentVersion(projectRoot);
|
|
31
34
|
const targetVersion = versionDetector.getTargetVersion();
|
|
32
|
-
const scenario = versionDetector.detectInstallationScenario();
|
|
35
|
+
const scenario = versionDetector.detectInstallationScenario(projectRoot);
|
|
33
36
|
|
|
34
37
|
// Fresh install
|
|
35
38
|
if (scenario === 'fresh' || !currentVersion) {
|
|
@@ -52,7 +55,7 @@ async function main() {
|
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
// Upgrade detected
|
|
55
|
-
if (
|
|
58
|
+
if (compareVersions(currentVersion, targetVersion) < 0) {
|
|
56
59
|
console.log(`${YELLOW}${BOLD}⚠ UPGRADE DETECTED${RESET}`);
|
|
57
60
|
console.log('');
|
|
58
61
|
console.log(` Current version: ${RED}${currentVersion}${RESET}`);
|
|
@@ -60,7 +63,7 @@ async function main() {
|
|
|
60
63
|
console.log('');
|
|
61
64
|
|
|
62
65
|
// Check for breaking changes
|
|
63
|
-
const breakingChanges = registry.getBreakingChanges(currentVersion
|
|
66
|
+
const breakingChanges = registry.getBreakingChanges(currentVersion);
|
|
64
67
|
if (breakingChanges.length > 0) {
|
|
65
68
|
console.log(`${RED}${BOLD} ⚠ Breaking changes detected!${RESET}`);
|
|
66
69
|
console.log('');
|
|
@@ -83,7 +86,7 @@ async function main() {
|
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
// Downgrade (shouldn't happen normally)
|
|
86
|
-
if (
|
|
89
|
+
if (compareVersions(currentVersion, targetVersion) > 0) {
|
|
87
90
|
console.log(`${YELLOW}Note: Package version (${targetVersion}) is older than installed version (${currentVersion})${RESET}`);
|
|
88
91
|
console.log('');
|
|
89
92
|
return;
|
|
@@ -95,8 +98,8 @@ async function main() {
|
|
|
95
98
|
console.log(` ${CYAN}npx bmad-install-agents${RESET} - Install all agents (Emma + Wade)`);
|
|
96
99
|
console.log('');
|
|
97
100
|
console.log('Or install individually:');
|
|
98
|
-
console.log(` ${CYAN}npx bmad-install-emma${RESET} - Install Emma (
|
|
99
|
-
console.log(` ${CYAN}npx bmad-install-wade${RESET} - Install Wade (
|
|
101
|
+
console.log(` ${CYAN}npx bmad-install-emma${RESET} - Install Emma (contextualization-expert)`);
|
|
102
|
+
console.log(` ${CYAN}npx bmad-install-wade${RESET} - Install Wade (lean-experiments-specialist)`);
|
|
100
103
|
console.log('');
|
|
101
104
|
}
|
|
102
105
|
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const registry = require('./migrations/registry');
|
|
5
|
+
const backupManager = require('./lib/backup-manager');
|
|
6
|
+
const { refreshInstallation } = require('./lib/refresh-installation');
|
|
7
|
+
const { findProjectRoot } = require('./lib/utils');
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* BMAD-Enhanced Migrate CLI
|
|
@@ -11,6 +14,15 @@ const registry = require('./migrations/registry');
|
|
|
11
14
|
async function main() {
|
|
12
15
|
const args = process.argv.slice(2);
|
|
13
16
|
|
|
17
|
+
// Validate project root
|
|
18
|
+
const projectRoot = findProjectRoot();
|
|
19
|
+
if (!projectRoot) {
|
|
20
|
+
console.error('');
|
|
21
|
+
console.error(chalk.red('Not in a BMAD project. Could not find _bmad/ directory.'));
|
|
22
|
+
console.error('');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
14
26
|
// No args - show available migrations
|
|
15
27
|
if (args.length === 0) {
|
|
16
28
|
showAvailableMigrations();
|
|
@@ -32,6 +44,15 @@ async function main() {
|
|
|
32
44
|
process.exit(1);
|
|
33
45
|
}
|
|
34
46
|
|
|
47
|
+
// Check if already applied
|
|
48
|
+
const configPath = require('path').join(projectRoot, '_bmad/bme/_vortex/config.yaml');
|
|
49
|
+
if (registry.hasMigrationBeenApplied(migrationName, configPath)) {
|
|
50
|
+
console.log('');
|
|
51
|
+
console.log(chalk.yellow(`Migration '${migrationName}' has already been applied.`));
|
|
52
|
+
console.log('');
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
35
56
|
// Load migration module
|
|
36
57
|
if (!migration.module) {
|
|
37
58
|
try {
|
|
@@ -44,29 +65,61 @@ async function main() {
|
|
|
44
65
|
}
|
|
45
66
|
}
|
|
46
67
|
|
|
47
|
-
// Run migration
|
|
68
|
+
// Run migration with backup and refresh
|
|
48
69
|
console.log('');
|
|
49
70
|
console.log(chalk.cyan.bold(`Running migration: ${migration.name}`));
|
|
50
71
|
console.log(chalk.gray(migration.description));
|
|
51
72
|
console.log('');
|
|
52
73
|
|
|
74
|
+
let backupMetadata = null;
|
|
75
|
+
|
|
53
76
|
try {
|
|
54
|
-
|
|
77
|
+
// Create backup before running delta
|
|
78
|
+
console.log(chalk.cyan('Creating backup...'));
|
|
79
|
+
backupMetadata = await backupManager.createBackup('manual', projectRoot);
|
|
80
|
+
console.log(chalk.green(`✓ Backup created: ${require('path').basename(backupMetadata.backup_dir)}`));
|
|
81
|
+
console.log('');
|
|
82
|
+
|
|
83
|
+
// Run the delta
|
|
84
|
+
const changes = await migration.module.apply(projectRoot);
|
|
55
85
|
|
|
56
86
|
console.log('');
|
|
57
|
-
console.log(chalk.green.bold('✓ Migration completed'));
|
|
87
|
+
console.log(chalk.green.bold('✓ Migration delta completed'));
|
|
58
88
|
console.log('');
|
|
59
|
-
console.log(chalk.cyan('
|
|
89
|
+
console.log(chalk.cyan('Delta changes:'));
|
|
60
90
|
changes.forEach(change => {
|
|
61
91
|
console.log(chalk.gray(` - ${change}`));
|
|
62
92
|
});
|
|
63
93
|
console.log('');
|
|
64
94
|
|
|
95
|
+
// Refresh installation after delta
|
|
96
|
+
console.log(chalk.cyan('Refreshing installation files...'));
|
|
97
|
+
const refreshChanges = await refreshInstallation(projectRoot);
|
|
98
|
+
console.log(chalk.green('✓ Installation refreshed'));
|
|
99
|
+
console.log('');
|
|
100
|
+
|
|
65
101
|
} catch (error) {
|
|
66
102
|
console.error('');
|
|
67
103
|
console.error(chalk.red.bold('✗ Migration failed'));
|
|
68
104
|
console.error(chalk.red(error.message));
|
|
69
105
|
console.error('');
|
|
106
|
+
|
|
107
|
+
// Rollback if we have a backup
|
|
108
|
+
if (backupMetadata) {
|
|
109
|
+
console.log(chalk.yellow('Restoring from backup...'));
|
|
110
|
+
try {
|
|
111
|
+
await backupManager.restoreBackup(backupMetadata, projectRoot);
|
|
112
|
+
console.log(chalk.green('✓ Installation restored from backup'));
|
|
113
|
+
console.log('');
|
|
114
|
+
} catch (restoreError) {
|
|
115
|
+
console.error(chalk.red('✗ Restore failed!'));
|
|
116
|
+
console.error(chalk.red(restoreError.message));
|
|
117
|
+
console.error('');
|
|
118
|
+
console.error(chalk.yellow(`Manual restore may be needed from: ${backupMetadata.backup_dir}`));
|
|
119
|
+
console.error('');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
70
123
|
if (error.stack) {
|
|
71
124
|
console.error(chalk.gray(error.stack));
|
|
72
125
|
console.error('');
|
|
@@ -95,7 +148,7 @@ function showAvailableMigrations() {
|
|
|
95
148
|
const breaking = m.breaking ? chalk.red('[BREAKING]') : chalk.green('[SAFE]');
|
|
96
149
|
console.log(` ${index + 1}. ${chalk.cyan(m.name)} ${breaking}`);
|
|
97
150
|
console.log(` ${chalk.gray(m.description)}`);
|
|
98
|
-
console.log(` ${chalk.gray(
|
|
151
|
+
console.log(` ${chalk.gray(`From: ${m.fromVersion}`)}`);
|
|
99
152
|
console.log('');
|
|
100
153
|
});
|
|
101
154
|
|
|
@@ -5,6 +5,7 @@ const chalk = require('chalk');
|
|
|
5
5
|
const versionDetector = require('./lib/version-detector');
|
|
6
6
|
const migrationRunner = require('./lib/migration-runner');
|
|
7
7
|
const registry = require('./migrations/registry');
|
|
8
|
+
const { findProjectRoot } = require('./lib/utils');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* BMAD-Enhanced Update CLI
|
|
@@ -15,7 +16,6 @@ async function main() {
|
|
|
15
16
|
const args = process.argv.slice(2);
|
|
16
17
|
const dryRun = args.includes('--dry-run');
|
|
17
18
|
const yes = args.includes('--yes') || args.includes('-y');
|
|
18
|
-
const force = args.includes('--force');
|
|
19
19
|
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
20
20
|
|
|
21
21
|
// Header
|
|
@@ -25,10 +25,20 @@ async function main() {
|
|
|
25
25
|
console.log(chalk.bold.magenta('╚════════════════════════════════════════╝'));
|
|
26
26
|
console.log('');
|
|
27
27
|
|
|
28
|
+
// Validate project root
|
|
29
|
+
const projectRoot = findProjectRoot();
|
|
30
|
+
if (!projectRoot) {
|
|
31
|
+
console.log(chalk.red('Not in a BMAD project. Could not find _bmad/ directory.'));
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log('Run: ' + chalk.cyan('npx bmad-install-agents'));
|
|
34
|
+
console.log('');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
// 1. Detect current state
|
|
29
|
-
const currentVersion = versionDetector.getCurrentVersion();
|
|
39
|
+
const currentVersion = versionDetector.getCurrentVersion(projectRoot);
|
|
30
40
|
const targetVersion = versionDetector.getTargetVersion();
|
|
31
|
-
const scenario = versionDetector.detectInstallationScenario();
|
|
41
|
+
const scenario = versionDetector.detectInstallationScenario(projectRoot);
|
|
32
42
|
|
|
33
43
|
// Handle different scenarios
|
|
34
44
|
if (scenario === 'fresh') {
|
|
@@ -88,7 +98,7 @@ async function main() {
|
|
|
88
98
|
console.log(` To: ${chalk.green(targetVersion)}`);
|
|
89
99
|
console.log('');
|
|
90
100
|
|
|
91
|
-
const migrations = registry.getMigrationsFor(currentVersion
|
|
101
|
+
const migrations = registry.getMigrationsFor(currentVersion);
|
|
92
102
|
|
|
93
103
|
if (migrations.length === 0) {
|
|
94
104
|
console.log(chalk.yellow('No migrations needed (versions compatible)'));
|
|
@@ -104,7 +114,7 @@ async function main() {
|
|
|
104
114
|
console.log('');
|
|
105
115
|
|
|
106
116
|
// 3. Show breaking changes warning
|
|
107
|
-
const breakingChanges = registry.getBreakingChanges(currentVersion
|
|
117
|
+
const breakingChanges = registry.getBreakingChanges(currentVersion);
|
|
108
118
|
if (breakingChanges.length > 0) {
|
|
109
119
|
console.log(chalk.red.bold('⚠ BREAKING CHANGES:'));
|
|
110
120
|
breakingChanges.forEach(change => {
|
|
@@ -119,7 +129,7 @@ async function main() {
|
|
|
119
129
|
console.log('');
|
|
120
130
|
|
|
121
131
|
try {
|
|
122
|
-
await migrationRunner.runMigrations(currentVersion,
|
|
132
|
+
await migrationRunner.runMigrations(currentVersion, { dryRun: true, verbose });
|
|
123
133
|
} catch (error) {
|
|
124
134
|
console.error(chalk.red('Error during preview:'), error.message);
|
|
125
135
|
process.exit(1);
|
|
@@ -148,7 +158,7 @@ async function main() {
|
|
|
148
158
|
console.log(chalk.cyan.bold('Starting migration...'));
|
|
149
159
|
|
|
150
160
|
try {
|
|
151
|
-
const result = await migrationRunner.runMigrations(currentVersion,
|
|
161
|
+
const result = await migrationRunner.runMigrations(currentVersion, { verbose });
|
|
152
162
|
|
|
153
163
|
// 7. Show success report
|
|
154
164
|
console.log('');
|
|
@@ -5,6 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const chalk = require('chalk');
|
|
6
6
|
const yaml = require('js-yaml');
|
|
7
7
|
const versionDetector = require('./lib/version-detector');
|
|
8
|
+
const { findProjectRoot, compareVersions } = require('./lib/utils');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* BMAD-Enhanced Version CLI
|
|
@@ -12,14 +13,26 @@ const versionDetector = require('./lib/version-detector');
|
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
async function main() {
|
|
15
|
-
const
|
|
16
|
+
const projectRoot = findProjectRoot();
|
|
16
17
|
const targetVersion = versionDetector.getTargetVersion();
|
|
17
|
-
const scenario = versionDetector.detectInstallationScenario();
|
|
18
18
|
|
|
19
19
|
console.log('');
|
|
20
20
|
console.log(chalk.bold('BMAD-Enhanced Version Information'));
|
|
21
21
|
console.log('');
|
|
22
22
|
|
|
23
|
+
// Not in a BMAD project
|
|
24
|
+
if (!projectRoot) {
|
|
25
|
+
console.log(chalk.yellow('Status: Not in a BMAD project'));
|
|
26
|
+
console.log(`Package version: ${chalk.cyan(targetVersion)}`);
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log('Run: ' + chalk.cyan('npx bmad-install-agents'));
|
|
29
|
+
console.log('');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const currentVersion = versionDetector.getCurrentVersion(projectRoot);
|
|
34
|
+
const scenario = versionDetector.detectInstallationScenario(projectRoot);
|
|
35
|
+
|
|
23
36
|
// Fresh install - not installed yet
|
|
24
37
|
if (scenario === 'fresh') {
|
|
25
38
|
console.log(chalk.yellow('Status: Not installed'));
|
|
@@ -64,7 +77,7 @@ async function main() {
|
|
|
64
77
|
// Status
|
|
65
78
|
if (currentVersion === targetVersion) {
|
|
66
79
|
console.log(chalk.green('Status: ✓ Up to date'));
|
|
67
|
-
} else if (
|
|
80
|
+
} else if (compareVersions(currentVersion, targetVersion) < 0) {
|
|
68
81
|
console.log(chalk.yellow('Status: ⚠ Update available'));
|
|
69
82
|
console.log('');
|
|
70
83
|
console.log('Run: ' + chalk.cyan('npx bmad-update --dry-run') + ' (to preview)');
|
|
@@ -74,7 +87,7 @@ async function main() {
|
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
// Show migration history
|
|
77
|
-
const migrationHistory = await getMigrationHistory();
|
|
90
|
+
const migrationHistory = await getMigrationHistory(projectRoot);
|
|
78
91
|
if (migrationHistory && migrationHistory.length > 0) {
|
|
79
92
|
console.log('');
|
|
80
93
|
console.log(chalk.cyan('Migration History:'));
|
|
@@ -94,10 +107,11 @@ async function main() {
|
|
|
94
107
|
|
|
95
108
|
/**
|
|
96
109
|
* Get migration history from config.yaml
|
|
110
|
+
* @param {string} projectRoot - Project root
|
|
97
111
|
* @returns {Promise<Array|null>} Migration history or null
|
|
98
112
|
*/
|
|
99
|
-
async function getMigrationHistory() {
|
|
100
|
-
const configPath = path.join(
|
|
113
|
+
async function getMigrationHistory(projectRoot) {
|
|
114
|
+
const configPath = path.join(projectRoot, '_bmad/bme/_vortex/config.yaml');
|
|
101
115
|
|
|
102
116
|
if (!fs.existsSync(configPath)) {
|
|
103
117
|
return null;
|