bmad-fh 6.0.0-alpha.23 → 6.0.0-alpha.23.50b728f9

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.
@@ -1,13 +1,12 @@
1
-
2
1
  /**
3
2
  * Workflow Migration Script
4
- *
3
+ *
5
4
  * Updates workflow.yaml files to support the multi-scope system.
6
5
  * Primarily updates test_dir and other path variables to use scope-aware paths.
7
- *
6
+ *
8
7
  * Usage:
9
8
  * node migrate-workflows.js [--dry-run] [--verbose]
10
- *
9
+ *
11
10
  * Options:
12
11
  * --dry-run Show what would be changed without making changes
13
12
  * --verbose Show detailed output
@@ -28,48 +27,42 @@ const PATH_MIGRATIONS = [
28
27
  {
29
28
  pattern: /\{output_folder\}\/tests/g,
30
29
  replacement: '{scope_tests}',
31
- description: 'test directory to scope_tests'
30
+ description: 'test directory to scope_tests',
32
31
  },
33
32
  {
34
33
  pattern: /\{config_source:implementation_artifacts\}\/tests/g,
35
34
  replacement: '{config_source:scope_tests}',
36
- description: 'implementation_artifacts tests to scope_tests'
35
+ description: 'implementation_artifacts tests to scope_tests',
37
36
  },
38
37
  // Planning artifacts
39
38
  {
40
39
  pattern: /\{output_folder\}\/planning-artifacts/g,
41
40
  replacement: '{config_source:planning_artifacts}',
42
- description: 'output_folder planning to config_source'
41
+ description: 'output_folder planning to config_source',
43
42
  },
44
- // Implementation artifacts
43
+ // Implementation artifacts
45
44
  {
46
45
  pattern: /\{output_folder\}\/implementation-artifacts/g,
47
46
  replacement: '{config_source:implementation_artifacts}',
48
- description: 'output_folder implementation to config_source'
49
- }
47
+ description: 'output_folder implementation to config_source',
48
+ },
50
49
  ];
51
50
 
52
51
  // Variables that indicate scope requirement
53
- const SCOPE_INDICATORS = [
54
- '{scope}',
55
- '{scope_path}',
56
- '{scope_tests}',
57
- '{scope_planning}',
58
- '{scope_implementation}'
59
- ];
52
+ const SCOPE_INDICATORS = ['{scope}', '{scope_path}', '{scope_tests}', '{scope_planning}', '{scope_implementation}'];
60
53
 
61
54
  /**
62
55
  * Find all workflow.yaml files
63
56
  */
64
57
  async function findWorkflowFiles(basePath) {
65
58
  const files = [];
66
-
59
+
67
60
  async function walk(dir) {
68
61
  const entries = await fs.readdir(dir, { withFileTypes: true });
69
-
62
+
70
63
  for (const entry of entries) {
71
64
  const fullPath = path.join(dir, entry.name);
72
-
65
+
73
66
  if (entry.isDirectory()) {
74
67
  // Skip node_modules and hidden directories
75
68
  if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
@@ -80,7 +73,7 @@ async function findWorkflowFiles(basePath) {
80
73
  }
81
74
  }
82
75
  }
83
-
76
+
84
77
  await walk(basePath);
85
78
  return files;
86
79
  }
@@ -89,7 +82,7 @@ async function findWorkflowFiles(basePath) {
89
82
  * Check if a workflow already uses scope variables
90
83
  */
91
84
  function usesScope(content) {
92
- return SCOPE_INDICATORS.some(indicator => content.includes(indicator));
85
+ return SCOPE_INDICATORS.some((indicator) => content.includes(indicator));
93
86
  }
94
87
 
95
88
  /**
@@ -101,20 +94,20 @@ function analyzeWorkflow(content, filePath) {
101
94
  needsMigration: false,
102
95
  alreadyScoped: false,
103
96
  suggestions: [],
104
- currentVariables: []
97
+ currentVariables: [],
105
98
  };
106
-
99
+
107
100
  // Check if already uses scope
108
101
  if (usesScope(content)) {
109
102
  analysis.alreadyScoped = true;
110
103
  return analysis;
111
104
  }
112
-
105
+
113
106
  // Find variables that might need migration
114
107
  const variablePattern = /\{[^}]+\}/g;
115
108
  const matches = content.match(variablePattern) || [];
116
109
  analysis.currentVariables = [...new Set(matches)];
117
-
110
+
118
111
  // Check each migration pattern
119
112
  for (const migration of PATH_MIGRATIONS) {
120
113
  if (migration.pattern.test(content)) {
@@ -122,21 +115,21 @@ function analyzeWorkflow(content, filePath) {
122
115
  analysis.suggestions.push({
123
116
  description: migration.description,
124
117
  pattern: migration.pattern.toString(),
125
- replacement: migration.replacement
118
+ replacement: migration.replacement,
126
119
  });
127
120
  }
128
121
  }
129
-
122
+
130
123
  // Check for test_dir variable
131
124
  if (content.includes('test_dir:') || content.includes('test_dir:')) {
132
125
  analysis.needsMigration = true;
133
126
  analysis.suggestions.push({
134
127
  description: 'Has test_dir variable - may need scope_tests',
135
128
  pattern: 'test_dir',
136
- replacement: 'scope_tests via config_source'
129
+ replacement: 'scope_tests via config_source',
137
130
  });
138
131
  }
139
-
132
+
140
133
  return analysis;
141
134
  }
142
135
 
@@ -146,14 +139,14 @@ function analyzeWorkflow(content, filePath) {
146
139
  function migrateWorkflow(content) {
147
140
  let migrated = content;
148
141
  let changes = [];
149
-
142
+
150
143
  for (const migration of PATH_MIGRATIONS) {
151
144
  if (migration.pattern.test(migrated)) {
152
145
  migrated = migrated.replace(migration.pattern, migration.replacement);
153
146
  changes.push(migration.description);
154
147
  }
155
148
  }
156
-
149
+
157
150
  return { content: migrated, changes };
158
151
  }
159
152
 
@@ -163,12 +156,12 @@ function migrateWorkflow(content) {
163
156
  function addScopeMarker(content) {
164
157
  try {
165
158
  const parsed = yaml.parse(content);
166
-
159
+
167
160
  // Add scope_required if not present
168
161
  if (!parsed.scope_required) {
169
162
  parsed.scope_required = false; // Default to false for backward compatibility
170
163
  }
171
-
164
+
172
165
  return yaml.stringify(parsed, { lineWidth: 120 });
173
166
  } catch {
174
167
  // If YAML parsing fails, return original
@@ -183,37 +176,37 @@ async function main() {
183
176
  const args = new Set(process.argv.slice(2));
184
177
  const dryRun = args.has('--dry-run');
185
178
  const verbose = args.has('--verbose');
186
-
179
+
187
180
  console.log(chalk.bold('\nWorkflow Migration Script'));
188
181
  console.log(chalk.dim('Updating workflow.yaml files for multi-scope support\n'));
189
-
182
+
190
183
  if (dryRun) {
191
184
  console.log(chalk.yellow('DRY RUN MODE - No changes will be made\n'));
192
185
  }
193
-
186
+
194
187
  // Find all workflow files
195
188
  console.log(chalk.blue('Scanning for workflow.yaml files...'));
196
189
  const files = await findWorkflowFiles(SRC_PATH);
197
190
  console.log(chalk.green(`Found ${files.length} workflow.yaml files\n`));
198
-
191
+
199
192
  // Analysis results
200
193
  const results = {
201
194
  analyzed: 0,
202
195
  alreadyScoped: 0,
203
196
  migrated: 0,
204
197
  noChanges: 0,
205
- errors: []
198
+ errors: [],
206
199
  };
207
-
200
+
208
201
  // Process each file
209
202
  for (const filePath of files) {
210
203
  const relativePath = path.relative(SRC_PATH, filePath);
211
204
  results.analyzed++;
212
-
205
+
213
206
  try {
214
207
  const content = await fs.readFile(filePath, 'utf8');
215
208
  const analysis = analyzeWorkflow(content, filePath);
216
-
209
+
217
210
  if (analysis.alreadyScoped) {
218
211
  results.alreadyScoped++;
219
212
  if (verbose) {
@@ -221,7 +214,7 @@ async function main() {
221
214
  }
222
215
  continue;
223
216
  }
224
-
217
+
225
218
  if (!analysis.needsMigration) {
226
219
  results.noChanges++;
227
220
  if (verbose) {
@@ -229,16 +222,16 @@ async function main() {
229
222
  }
230
223
  continue;
231
224
  }
232
-
225
+
233
226
  // Apply migration
234
227
  const { content: migrated, changes } = migrateWorkflow(content);
235
-
228
+
236
229
  if (changes.length > 0) {
237
230
  console.log(chalk.cyan(` ● ${relativePath}`));
238
231
  for (const change of changes) {
239
232
  console.log(chalk.dim(` → ${change}`));
240
233
  }
241
-
234
+
242
235
  if (!dryRun) {
243
236
  await fs.writeFile(filePath, migrated, 'utf8');
244
237
  }
@@ -246,13 +239,12 @@ async function main() {
246
239
  } else {
247
240
  results.noChanges++;
248
241
  }
249
-
250
242
  } catch (error) {
251
243
  results.errors.push({ file: relativePath, error: error.message });
252
244
  console.log(chalk.red(` ✗ ${relativePath} - Error: ${error.message}`));
253
245
  }
254
246
  }
255
-
247
+
256
248
  // Print summary
257
249
  console.log(chalk.bold('\n─────────────────────────────────────'));
258
250
  console.log(chalk.bold('Summary'));
@@ -265,17 +257,17 @@ async function main() {
265
257
  console.log(chalk.red(` Errors: ${results.errors.length}`));
266
258
  }
267
259
  console.log();
268
-
260
+
269
261
  if (dryRun && results.migrated > 0) {
270
262
  console.log(chalk.yellow('Run without --dry-run to apply changes\n'));
271
263
  }
272
-
264
+
273
265
  // Exit with error code if there were errors
274
266
  process.exit(results.errors.length > 0 ? 1 : 0);
275
267
  }
276
268
 
277
269
  // Run
278
- main().catch(error => {
270
+ main().catch((error) => {
279
271
  console.error(chalk.red('Fatal error:'), error.message);
280
272
  process.exit(1);
281
273
  });