bmad-fh 6.0.0-alpha.23 → 6.0.0-alpha.24

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.
@@ -32,30 +32,30 @@ function displayScopeList(scopes) {
32
32
  }
33
33
 
34
34
  console.log(chalk.bold('\n Scopes:\n'));
35
-
35
+
36
36
  // Calculate column widths
37
- const idWidth = Math.max(10, ...scopes.map(s => s.id.length)) + 2;
38
- const nameWidth = Math.max(15, ...scopes.map(s => (s.name || '').length)) + 2;
39
-
37
+ const idWidth = Math.max(10, ...scopes.map((s) => s.id.length)) + 2;
38
+ const nameWidth = Math.max(15, ...scopes.map((s) => (s.name || '').length)) + 2;
39
+
40
40
  // Header
41
41
  console.log(
42
42
  chalk.dim(' ') +
43
- chalk.bold('ID'.padEnd(idWidth)) +
44
- chalk.bold('Name'.padEnd(nameWidth)) +
45
- chalk.bold('Status'.padEnd(10)) +
46
- chalk.bold('Created')
43
+ chalk.bold('ID'.padEnd(idWidth)) +
44
+ chalk.bold('Name'.padEnd(nameWidth)) +
45
+ chalk.bold('Status'.padEnd(10)) +
46
+ chalk.bold('Created'),
47
47
  );
48
48
  console.log(chalk.dim(' ' + '─'.repeat(idWidth + nameWidth + 10 + 20)));
49
-
49
+
50
50
  // Rows
51
51
  for (const scope of scopes) {
52
52
  const statusColor = scope.status === 'active' ? chalk.green : chalk.dim;
53
53
  console.log(
54
54
  ' ' +
55
- chalk.cyan(scope.id.padEnd(idWidth)) +
56
- (scope.name || scope.id).padEnd(nameWidth) +
57
- statusColor(scope.status.padEnd(10)) +
58
- chalk.dim(formatDate(scope.created).split(' ')[0])
55
+ chalk.cyan(scope.id.padEnd(idWidth)) +
56
+ (scope.name || scope.id).padEnd(nameWidth) +
57
+ statusColor(scope.status.padEnd(10)) +
58
+ chalk.dim(formatDate(scope.created).split(' ')[0]),
59
59
  );
60
60
  }
61
61
  console.log();
@@ -69,7 +69,7 @@ function displayScopeList(scopes) {
69
69
  */
70
70
  function displayScopeInfo(scope, paths, tree) {
71
71
  console.log(chalk.bold(`\n Scope: ${scope.name || scope.id}\n`));
72
-
72
+
73
73
  console.log(chalk.dim(' ─────────────────────────────────────'));
74
74
  console.log(` ${chalk.bold('ID:')} ${chalk.cyan(scope.id)}`);
75
75
  console.log(` ${chalk.bold('Name:')} ${scope.name || 'N/A'}`);
@@ -78,13 +78,13 @@ function displayScopeInfo(scope, paths, tree) {
78
78
  console.log(` ${chalk.bold('Created:')} ${formatDate(scope.created)}`);
79
79
  console.log(` ${chalk.bold('Last Active:')} ${formatDate(scope._meta?.last_activity)}`);
80
80
  console.log(` ${chalk.bold('Artifacts:')} ${scope._meta?.artifact_count || 0}`);
81
-
81
+
82
82
  console.log(chalk.dim('\n ─────────────────────────────────────'));
83
83
  console.log(chalk.bold(' Paths:'));
84
84
  console.log(` Planning: ${chalk.dim(paths.planning)}`);
85
85
  console.log(` Implementation: ${chalk.dim(paths.implementation)}`);
86
86
  console.log(` Tests: ${chalk.dim(paths.tests)}`);
87
-
87
+
88
88
  console.log(chalk.dim('\n ─────────────────────────────────────'));
89
89
  console.log(chalk.bold(' Dependencies:'));
90
90
  if (tree.dependencies.length > 0) {
@@ -95,7 +95,7 @@ function displayScopeInfo(scope, paths, tree) {
95
95
  } else {
96
96
  console.log(chalk.dim(' None'));
97
97
  }
98
-
98
+
99
99
  console.log(chalk.bold('\n Dependents (scopes that depend on this):'));
100
100
  if (tree.dependents.length > 0) {
101
101
  for (const dep of tree.dependents) {
@@ -104,7 +104,7 @@ function displayScopeInfo(scope, paths, tree) {
104
104
  } else {
105
105
  console.log(chalk.dim(' None'));
106
106
  }
107
-
107
+
108
108
  console.log();
109
109
  }
110
110
 
@@ -113,7 +113,7 @@ function displayScopeInfo(scope, paths, tree) {
113
113
  */
114
114
  async function handleList(projectRoot, options) {
115
115
  const manager = new ScopeManager({ projectRoot });
116
-
116
+
117
117
  try {
118
118
  await manager.initialize();
119
119
  const scopes = await manager.listScopes(options.status ? { status: options.status } : {});
@@ -134,7 +134,7 @@ async function handleCreate(projectRoot, scopeId, options) {
134
134
  const manager = new ScopeManager({ projectRoot });
135
135
  const initializer = new ScopeInitializer({ projectRoot });
136
136
  const validator = new ScopeValidator();
137
-
137
+
138
138
  // If no scopeId provided, prompt for it
139
139
  if (!scopeId) {
140
140
  const inputId = await text({
@@ -143,80 +143,80 @@ async function handleCreate(projectRoot, scopeId, options) {
143
143
  validate: (value) => {
144
144
  const result = validator.validateScopeId(value);
145
145
  return result.valid ? undefined : result.error;
146
- }
146
+ },
147
147
  });
148
-
148
+
149
149
  if (isCancel(inputId)) {
150
150
  console.log(chalk.yellow('Cancelled.'));
151
151
  return;
152
152
  }
153
153
  scopeId = inputId;
154
154
  }
155
-
155
+
156
156
  // Validate scope ID
157
157
  const idValidation = validator.validateScopeId(scopeId);
158
158
  if (!idValidation.valid) {
159
159
  console.error(chalk.red(`Error: ${idValidation.error}`));
160
160
  process.exit(1);
161
161
  }
162
-
162
+
163
163
  // Get scope name if not provided
164
164
  let name = options.name;
165
165
  if (!name) {
166
166
  const inputName = await text({
167
167
  message: 'Enter scope name (human-readable):',
168
168
  placeholder: `e.g., Authentication Service`,
169
- initialValue: scopeId.charAt(0).toUpperCase() + scopeId.slice(1).replaceAll('-', ' ')
169
+ initialValue: scopeId.charAt(0).toUpperCase() + scopeId.slice(1).replaceAll('-', ' '),
170
170
  });
171
-
171
+
172
172
  if (isCancel(inputName)) {
173
173
  console.log(chalk.yellow('Cancelled.'));
174
174
  return;
175
175
  }
176
176
  name = inputName;
177
177
  }
178
-
178
+
179
179
  // Get description if not provided
180
180
  let description = options.description;
181
181
  if (!description) {
182
182
  const inputDesc = await text({
183
183
  message: 'Enter scope description (optional):',
184
- placeholder: 'Brief description of this scope'
184
+ placeholder: 'Brief description of this scope',
185
185
  });
186
-
186
+
187
187
  if (isCancel(inputDesc)) {
188
188
  console.log(chalk.yellow('Cancelled.'));
189
189
  return;
190
190
  }
191
191
  description = inputDesc || '';
192
192
  }
193
-
193
+
194
194
  console.log(chalk.blue('\nCreating scope...'));
195
-
195
+
196
196
  // Initialize scope system if needed
197
197
  await manager.initialize();
198
-
198
+
199
199
  // Check if system is initialized
200
200
  const systemInit = await initializer.isSystemInitialized();
201
201
  if (!systemInit) {
202
202
  console.log(chalk.blue('Initializing scope system...'));
203
203
  await initializer.initializeScopeSystem();
204
204
  }
205
-
205
+
206
206
  // Create scope in configuration
207
207
  const scope = await manager.createScope(scopeId, {
208
208
  name,
209
209
  description,
210
- dependencies: options.dependencies ? options.dependencies.split(',').map(d => d.trim()) : []
210
+ dependencies: options.dependencies ? options.dependencies.split(',').map((d) => d.trim()) : [],
211
211
  });
212
-
212
+
213
213
  // Create scope directory structure
214
214
  const paths = await initializer.initializeScope(scopeId, {
215
215
  name,
216
216
  description,
217
- createContext: options.context
217
+ createContext: options.context,
218
218
  });
219
-
219
+
220
220
  console.log(chalk.green(`\n✓ Scope '${scopeId}' created successfully!\n`));
221
221
  console.log(chalk.dim(' Directories created:'));
222
222
  console.log(` ${paths.planning}`);
@@ -235,20 +235,20 @@ async function handleInfo(projectRoot, scopeId) {
235
235
  console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope info <scope-id>'));
236
236
  process.exit(1);
237
237
  }
238
-
238
+
239
239
  const manager = new ScopeManager({ projectRoot });
240
-
240
+
241
241
  await manager.initialize();
242
242
  const scope = await manager.getScope(scopeId);
243
-
243
+
244
244
  if (!scope) {
245
245
  console.error(chalk.red(`Error: Scope '${scopeId}' not found.`));
246
246
  process.exit(1);
247
247
  }
248
-
248
+
249
249
  const paths = await manager.getScopePaths(scopeId);
250
250
  const tree = await manager.getDependencyTree(scopeId);
251
-
251
+
252
252
  displayScopeInfo(scope, paths, tree);
253
253
  }
254
254
 
@@ -260,39 +260,39 @@ async function handleRemove(projectRoot, scopeId, options) {
260
260
  console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope remove <scope-id>'));
261
261
  process.exit(1);
262
262
  }
263
-
263
+
264
264
  const manager = new ScopeManager({ projectRoot });
265
265
  const initializer = new ScopeInitializer({ projectRoot });
266
-
266
+
267
267
  await manager.initialize();
268
-
268
+
269
269
  const scope = await manager.getScope(scopeId);
270
270
  if (!scope) {
271
271
  console.error(chalk.red(`Error: Scope '${scopeId}' not found.`));
272
272
  process.exit(1);
273
273
  }
274
-
274
+
275
275
  // Confirm removal unless --force
276
276
  if (!options.force) {
277
277
  const confirmed = await confirm({
278
278
  message: `Are you sure you want to remove scope '${scopeId}'? This will delete all scope artifacts!`,
279
- initialValue: false
279
+ initialValue: false,
280
280
  });
281
-
281
+
282
282
  if (isCancel(confirmed) || !confirmed) {
283
283
  console.log(chalk.yellow('Cancelled.'));
284
284
  return;
285
285
  }
286
286
  }
287
-
287
+
288
288
  console.log(chalk.blue('\nRemoving scope...'));
289
-
289
+
290
290
  // Remove scope directory (with backup)
291
291
  await initializer.removeScope(scopeId, { backup: !options.noBackup });
292
-
292
+
293
293
  // Remove from configuration
294
294
  await manager.removeScope(scopeId, { force: true });
295
-
295
+
296
296
  console.log(chalk.green(`\n✓ Scope '${scopeId}' removed successfully!`));
297
297
  if (!options.noBackup) {
298
298
  console.log(chalk.dim(' A backup was created in _bmad-output/'));
@@ -306,12 +306,12 @@ async function handleRemove(projectRoot, scopeId, options) {
306
306
  async function handleInit(projectRoot) {
307
307
  const manager = new ScopeManager({ projectRoot });
308
308
  const initializer = new ScopeInitializer({ projectRoot });
309
-
309
+
310
310
  console.log(chalk.blue('\nInitializing scope system...'));
311
-
311
+
312
312
  await manager.initialize();
313
313
  await initializer.initializeScopeSystem();
314
-
314
+
315
315
  console.log(chalk.green('\n✓ Scope system initialized successfully!\n'));
316
316
  console.log(chalk.dim(' Created:'));
317
317
  console.log(` ${chalk.cyan('_bmad/_config/scopes.yaml')} - Scope configuration`);
@@ -330,12 +330,12 @@ async function handleArchive(projectRoot, scopeId) {
330
330
  console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope archive <scope-id>'));
331
331
  process.exit(1);
332
332
  }
333
-
333
+
334
334
  const manager = new ScopeManager({ projectRoot });
335
-
335
+
336
336
  await manager.initialize();
337
337
  await manager.archiveScope(scopeId);
338
-
338
+
339
339
  console.log(chalk.green(`\n✓ Scope '${scopeId}' archived.\n`));
340
340
  }
341
341
 
@@ -347,12 +347,12 @@ async function handleActivate(projectRoot, scopeId) {
347
347
  console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope activate <scope-id>'));
348
348
  process.exit(1);
349
349
  }
350
-
350
+
351
351
  const manager = new ScopeManager({ projectRoot });
352
-
352
+
353
353
  await manager.initialize();
354
354
  await manager.activateScope(scopeId);
355
-
355
+
356
356
  console.log(chalk.green(`\n✓ Scope '${scopeId}' activated.\n`));
357
357
  }
358
358
 
@@ -397,61 +397,61 @@ module.exports = {
397
397
  ['-f, --force', 'Force operation without confirmation'],
398
398
  ['--no-backup', 'Skip backup on remove'],
399
399
  ['--context', 'Create scope-specific project-context.md'],
400
- ['-s, --status <status>', 'Filter by status (active/archived)']
400
+ ['-s, --status <status>', 'Filter by status (active/archived)'],
401
401
  ],
402
402
  action: async (subcommand, id, options) => {
403
403
  try {
404
404
  // Determine project root
405
405
  const projectRoot = process.cwd();
406
-
406
+
407
407
  // Handle subcommands
408
408
  switch (subcommand) {
409
409
  case 'init': {
410
410
  await handleInit(projectRoot);
411
411
  break;
412
412
  }
413
-
413
+
414
414
  case 'list':
415
415
  case 'ls': {
416
416
  await handleList(projectRoot, options);
417
417
  break;
418
418
  }
419
-
419
+
420
420
  case 'create':
421
421
  case 'new': {
422
422
  await handleCreate(projectRoot, id, options);
423
423
  break;
424
424
  }
425
-
425
+
426
426
  case 'info':
427
427
  case 'show': {
428
428
  await handleInfo(projectRoot, id);
429
429
  break;
430
430
  }
431
-
431
+
432
432
  case 'remove':
433
433
  case 'rm':
434
434
  case 'delete': {
435
435
  await handleRemove(projectRoot, id, options);
436
436
  break;
437
437
  }
438
-
438
+
439
439
  case 'archive': {
440
440
  await handleArchive(projectRoot, id);
441
441
  break;
442
442
  }
443
-
443
+
444
444
  case 'activate': {
445
445
  await handleActivate(projectRoot, id);
446
446
  break;
447
447
  }
448
-
448
+
449
449
  case 'help':
450
450
  case undefined: {
451
451
  showHelp();
452
452
  break;
453
453
  }
454
-
454
+
455
455
  default: {
456
456
  // If subcommand looks like an ID, show info for it
457
457
  if (subcommand && !subcommand.startsWith('-')) {
@@ -461,7 +461,7 @@ module.exports = {
461
461
  }
462
462
  }
463
463
  }
464
-
464
+
465
465
  process.exit(0);
466
466
  } catch (error) {
467
467
  console.error(chalk.red(`\nError: ${error.message}`));
@@ -470,5 +470,5 @@ module.exports = {
470
470
  }
471
471
  process.exit(1);
472
472
  }
473
- }
473
+ },
474
474
  };
@@ -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
  });