bmad-fh 6.0.0-alpha.23 → 6.0.0-alpha.23.6fbcf839

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
  };
@@ -416,7 +416,7 @@ class ModuleManager {
416
416
  if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
417
417
  const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
418
418
  try {
419
- execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
419
+ execSync('npm install --production --ignore-scripts --no-audit --no-fund --prefer-offline --no-progress', {
420
420
  cwd: moduleCacheDir,
421
421
  stdio: 'pipe',
422
422
  timeout: 120_000, // 2 minute timeout
@@ -441,7 +441,7 @@ class ModuleManager {
441
441
  if (packageJsonNewer) {
442
442
  const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
443
443
  try {
444
- execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
444
+ execSync('npm install --production --ignore-scripts --no-audit --no-fund --prefer-offline --no-progress', {
445
445
  cwd: moduleCacheDir,
446
446
  stdio: 'pipe',
447
447
  timeout: 120_000, // 2 minute timeout