@paths.design/caws-cli 4.0.0 → 5.0.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/dist/commands/archive.js +353 -0
- package/dist/commands/iterate.js +12 -13
- package/dist/commands/mode.js +259 -0
- package/dist/commands/plan.js +448 -0
- package/dist/commands/quality-gates.js +490 -0
- package/dist/commands/specs.js +735 -0
- package/dist/commands/status.js +552 -22
- package/dist/commands/tutorial.js +481 -0
- package/dist/commands/validate.js +137 -54
- package/dist/commands/waivers.js +101 -26
- package/dist/config/modes.js +321 -0
- package/dist/constants/spec-types.js +42 -0
- package/dist/index.js +225 -10
- package/dist/scaffold/git-hooks.js +32 -44
- package/dist/scaffold/index.js +19 -0
- package/dist/utils/quality-gates-errors.js +520 -0
- package/dist/utils/quality-gates.js +361 -0
- package/dist/utils/spec-resolver.js +602 -0
- package/dist/waivers-manager.js +49 -4
- package/package.json +6 -5
- package/templates/.cursor/hooks/caws-scope-guard.sh +64 -8
- package/templates/.cursor/hooks/validate-spec.sh +22 -12
- package/templates/.cursor/rules/{01-claims-verification.mdc → 00-claims-verification.mdc} +1 -1
- package/templates/.cursor/rules/01-working-style.mdc +50 -0
- package/templates/.cursor/rules/{02-testing-standards.mdc → 02-quality-gates.mdc} +84 -29
- package/templates/.cursor/rules/03-naming-and-refactor.mdc +33 -0
- package/templates/.cursor/rules/04-logging-language-style.mdc +23 -0
- package/templates/.cursor/rules/05-safe-defaults-guards.mdc +23 -0
- package/templates/.cursor/rules/06-typescript-conventions.mdc +36 -0
- package/templates/.cursor/rules/07-process-ops.mdc +20 -0
- package/templates/.cursor/rules/08-solid-and-architecture.mdc +16 -0
- package/templates/.cursor/rules/09-docstrings.mdc +89 -0
- package/templates/.cursor/rules/10-authorship-and-attribution.mdc +15 -0
- package/templates/.cursor/rules/11-documentation-quality-standards.mdc +390 -0
- package/templates/.cursor/rules/12-scope-management-waivers.mdc +385 -0
- package/templates/.cursor/rules/13-implementation-completeness.mdc +516 -0
- package/templates/.cursor/rules/14-language-agnostic-standards.mdc +588 -0
- package/templates/.cursor/rules/15-sophisticated-todo-detection.mdc +425 -0
- package/templates/.cursor/rules/README.md +93 -7
- package/templates/scripts/quality-gates/check-god-objects.js +146 -0
- package/templates/scripts/quality-gates/run-quality-gates.js +50 -0
- package/templates/scripts/v3/analysis/todo_analyzer.py +1950 -0
- package/dist/budget-derivation.d.ts +0 -74
- package/dist/budget-derivation.d.ts.map +0 -1
- package/dist/cicd-optimizer.d.ts +0 -142
- package/dist/cicd-optimizer.d.ts.map +0 -1
- package/dist/commands/burnup.d.ts +0 -6
- package/dist/commands/burnup.d.ts.map +0 -1
- package/dist/commands/diagnose.d.ts +0 -52
- package/dist/commands/diagnose.d.ts.map +0 -1
- package/dist/commands/evaluate.d.ts +0 -8
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/iterate.d.ts +0 -8
- package/dist/commands/iterate.d.ts.map +0 -1
- package/dist/commands/provenance.d.ts +0 -32
- package/dist/commands/provenance.d.ts.map +0 -1
- package/dist/commands/quality-monitor.d.ts +0 -17
- package/dist/commands/quality-monitor.d.ts.map +0 -1
- package/dist/commands/status.d.ts +0 -43
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/templates.d.ts +0 -74
- package/dist/commands/templates.d.ts.map +0 -1
- package/dist/commands/tool.d.ts +0 -13
- package/dist/commands/tool.d.ts.map +0 -1
- package/dist/commands/troubleshoot.d.ts +0 -8
- package/dist/commands/troubleshoot.d.ts.map +0 -1
- package/dist/commands/validate.d.ts +0 -8
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/waivers.d.ts +0 -8
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/workflow.d.ts +0 -85
- package/dist/commands/workflow.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -29
- package/dist/config/index.d.ts.map +0 -1
- package/dist/error-handler.d.ts +0 -164
- package/dist/error-handler.d.ts.map +0 -1
- package/dist/generators/jest-config.d.ts +0 -32
- package/dist/generators/jest-config.d.ts.map +0 -1
- package/dist/generators/working-spec.d.ts +0 -13
- package/dist/generators/working-spec.d.ts.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/minimal-cli.d.ts +0 -3
- package/dist/minimal-cli.d.ts.map +0 -1
- package/dist/policy/PolicyManager.d.ts +0 -104
- package/dist/policy/PolicyManager.d.ts.map +0 -1
- package/dist/scaffold/cursor-hooks.d.ts +0 -7
- package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
- package/dist/scaffold/git-hooks.d.ts +0 -20
- package/dist/scaffold/git-hooks.d.ts.map +0 -1
- package/dist/scaffold/index.d.ts +0 -20
- package/dist/scaffold/index.d.ts.map +0 -1
- package/dist/spec/SpecFileManager.d.ts +0 -146
- package/dist/spec/SpecFileManager.d.ts.map +0 -1
- package/dist/test-analysis.d.ts +0 -182
- package/dist/test-analysis.d.ts.map +0 -1
- package/dist/tool-interface.d.ts +0 -236
- package/dist/tool-interface.d.ts.map +0 -1
- package/dist/tool-loader.d.ts +0 -77
- package/dist/tool-loader.d.ts.map +0 -1
- package/dist/tool-validator.d.ts +0 -72
- package/dist/tool-validator.d.ts.map +0 -1
- package/dist/utils/detection.d.ts +0 -7
- package/dist/utils/detection.d.ts.map +0 -1
- package/dist/utils/finalization.d.ts +0 -17
- package/dist/utils/finalization.d.ts.map +0 -1
- package/dist/utils/project-analysis.d.ts +0 -14
- package/dist/utils/project-analysis.d.ts.map +0 -1
- package/dist/utils/typescript-detector.d.ts +0 -63
- package/dist/utils/typescript-detector.d.ts.map +0 -1
- package/dist/validation/spec-validation.d.ts +0 -43
- package/dist/validation/spec-validation.d.ts.map +0 -1
- package/dist/waivers-manager.d.ts +0 -167
- package/dist/waivers-manager.d.ts.map +0 -1
- package/templates/.cursor/rules/03-infrastructure-standards.mdc +0 -251
- package/templates/.cursor/rules/04-documentation-integrity.mdc +0 -291
- package/templates/.cursor/rules/05-production-readiness-checklist.mdc +0 -214
package/dist/commands/status.js
CHANGED
|
@@ -11,7 +11,7 @@ const chalk = require('chalk');
|
|
|
11
11
|
const { safeAsync, outputResult } = require('../error-handler');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Load working specification
|
|
14
|
+
* Load working specification (legacy single file approach)
|
|
15
15
|
* @param {string} specPath - Path to working spec
|
|
16
16
|
* @returns {Promise<Object|null>} Parsed spec or null
|
|
17
17
|
*/
|
|
@@ -28,6 +28,20 @@ async function loadWorkingSpec(specPath = '.caws/working-spec.yaml') {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Load specs from the new multi-spec system
|
|
33
|
+
* @returns {Promise<Array>} Array of spec objects
|
|
34
|
+
*/
|
|
35
|
+
async function loadSpecsFromMultiSpec() {
|
|
36
|
+
const { listSpecFiles } = require('./specs');
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
return await listSpecFiles();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
/**
|
|
32
46
|
* Check Git hooks status
|
|
33
47
|
* @returns {Promise<Object>} Hooks status
|
|
@@ -299,32 +313,440 @@ function displayStatus(data) {
|
|
|
299
313
|
}
|
|
300
314
|
|
|
301
315
|
/**
|
|
302
|
-
* Generate actionable suggestions based on status
|
|
316
|
+
* Generate actionable suggestions based on status and mode
|
|
303
317
|
* @param {Object} data - Status data
|
|
318
|
+
* @param {string} currentMode - Current CAWS mode
|
|
304
319
|
* @returns {string[]} Array of suggestions
|
|
305
320
|
*/
|
|
306
|
-
function generateSuggestions(data) {
|
|
321
|
+
function generateSuggestions(data, currentMode) {
|
|
322
|
+
const { spec, specs, hooks, provenance, waivers } = data;
|
|
323
|
+
const modes = require('../config/modes');
|
|
307
324
|
const suggestions = [];
|
|
308
325
|
|
|
309
|
-
|
|
310
|
-
|
|
326
|
+
// Basic setup suggestions
|
|
327
|
+
if (!spec && (!specs || specs.length === 0)) {
|
|
328
|
+
suggestions.push('Create a spec: caws specs create <id>');
|
|
311
329
|
}
|
|
312
330
|
|
|
313
|
-
|
|
331
|
+
// Mode-specific suggestions
|
|
332
|
+
if (modes.isFeatureEnabled('gitHooks', currentMode) && !hooks.installed) {
|
|
314
333
|
suggestions.push('Install Git hooks: caws hooks install');
|
|
315
334
|
}
|
|
316
335
|
|
|
317
|
-
if (
|
|
336
|
+
if (modes.isFeatureEnabled('provenance', currentMode) && !provenance.exists) {
|
|
318
337
|
suggestions.push('Initialize provenance tracking: caws provenance init');
|
|
319
338
|
}
|
|
320
339
|
|
|
321
|
-
if (
|
|
322
|
-
suggestions.push('
|
|
340
|
+
if (modes.isFeatureEnabled('waivers', currentMode) && !waivers.exists) {
|
|
341
|
+
suggestions.push('Initialize waiver system: caws waivers create (when needed)');
|
|
323
342
|
}
|
|
324
343
|
|
|
344
|
+
// Quality gate suggestions
|
|
345
|
+
if (modes.isFeatureEnabled('qualityGates', currentMode)) {
|
|
346
|
+
if (spec || (specs && specs.length > 0)) {
|
|
347
|
+
suggestions.push('Run quality gates: caws diagnose');
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Mode switching suggestion
|
|
352
|
+
suggestions.push('Switch modes: caws mode set --interactive');
|
|
353
|
+
|
|
325
354
|
return suggestions;
|
|
326
355
|
}
|
|
327
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Create progress bar string
|
|
359
|
+
* @param {number} current - Current value
|
|
360
|
+
* @param {number} total - Total value
|
|
361
|
+
* @param {number} width - Bar width
|
|
362
|
+
* @returns {string} Progress bar string
|
|
363
|
+
*/
|
|
364
|
+
function createProgressBar(current, total, width = 20) {
|
|
365
|
+
if (total === 0) return '░'.repeat(width);
|
|
366
|
+
|
|
367
|
+
const percentage = Math.min(current / total, 1);
|
|
368
|
+
const filled = Math.round(percentage * width);
|
|
369
|
+
const empty = width - filled;
|
|
370
|
+
|
|
371
|
+
return '▓'.repeat(filled) + '░'.repeat(empty);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Get color for progress percentage
|
|
376
|
+
* @param {number} percentage - Progress percentage
|
|
377
|
+
* @returns {string} Chalk color function
|
|
378
|
+
*/
|
|
379
|
+
function getProgressColor(percentage) {
|
|
380
|
+
if (percentage >= 80) return chalk.green;
|
|
381
|
+
if (percentage >= 50) return chalk.yellow;
|
|
382
|
+
return chalk.red;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Display enhanced visual status
|
|
387
|
+
* @param {Object} data - Status data
|
|
388
|
+
* @param {string} currentMode - Current CAWS mode
|
|
389
|
+
*/
|
|
390
|
+
function displayVisualStatus(data, currentMode) {
|
|
391
|
+
const { spec, specs, hooks, provenance, waivers, gates } = data;
|
|
392
|
+
const modes = require('../config/modes');
|
|
393
|
+
const tierConfig = modes.getTier(currentMode);
|
|
394
|
+
|
|
395
|
+
console.log(
|
|
396
|
+
chalk.bold.cyan(
|
|
397
|
+
`\n📊 CAWS Project Status (${tierConfig.icon} ${tierConfig.color(currentMode)})`
|
|
398
|
+
)
|
|
399
|
+
);
|
|
400
|
+
console.log(
|
|
401
|
+
chalk.cyan(
|
|
402
|
+
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'
|
|
403
|
+
)
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
// Multi-spec system status
|
|
407
|
+
if (specs && specs.length > 0) {
|
|
408
|
+
console.log(chalk.green(`✅ Specs System (${specs.length} specs)`));
|
|
409
|
+
|
|
410
|
+
// Show active specs first
|
|
411
|
+
const activeSpecs = specs.filter((s) => s.status === 'active');
|
|
412
|
+
const draftSpecs = specs.filter((s) => s.status === 'draft');
|
|
413
|
+
const completedSpecs = specs.filter((s) => s.status === 'completed');
|
|
414
|
+
|
|
415
|
+
if (activeSpecs.length > 0) {
|
|
416
|
+
console.log(
|
|
417
|
+
chalk.gray(` Active: ${activeSpecs.map((s) => `${s.id}(${s.type})`).join(', ')}`)
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
if (draftSpecs.length > 0) {
|
|
421
|
+
console.log(
|
|
422
|
+
chalk.gray(` Draft: ${draftSpecs.length} spec${draftSpecs.length > 1 ? 's' : ''}`)
|
|
423
|
+
);
|
|
424
|
+
// Show details for draft specs if not too many
|
|
425
|
+
if (draftSpecs.length <= 3) {
|
|
426
|
+
draftSpecs.forEach((s) => {
|
|
427
|
+
console.log(chalk.gray(` • ${s.id}: ${s.title}`));
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (completedSpecs.length > 0) {
|
|
432
|
+
console.log(
|
|
433
|
+
chalk.gray(
|
|
434
|
+
` Completed: ${completedSpecs.length} spec${completedSpecs.length > 1 ? 's' : ''}`
|
|
435
|
+
)
|
|
436
|
+
);
|
|
437
|
+
// Show details for completed specs if not too many
|
|
438
|
+
if (completedSpecs.length <= 3) {
|
|
439
|
+
completedSpecs.forEach((s) => {
|
|
440
|
+
console.log(chalk.gray(` • ${s.id}: ${s.title}`));
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Overall specs progress
|
|
446
|
+
const totalSpecs = specs.length;
|
|
447
|
+
const completedSpecsCount = specs.filter((s) => s.status === 'completed').length;
|
|
448
|
+
const activeSpecsCount = specs.filter((s) => s.status === 'active').length;
|
|
449
|
+
const progressPercentage =
|
|
450
|
+
totalSpecs > 0 ? Math.round((completedSpecsCount / totalSpecs) * 100) : 0;
|
|
451
|
+
const progressBar = createProgressBar(completedSpecsCount, totalSpecs);
|
|
452
|
+
const color = getProgressColor(progressPercentage);
|
|
453
|
+
|
|
454
|
+
console.log(
|
|
455
|
+
chalk.gray(
|
|
456
|
+
` Overall Progress: ${color(`${progressPercentage}%`)} ${progressBar} ${completedSpecsCount}/${totalSpecs} completed`
|
|
457
|
+
)
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
if (activeSpecsCount > 0) {
|
|
461
|
+
console.log(chalk.gray(` Active Features: ${activeSpecsCount} in progress`));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Show risk tier breakdown
|
|
465
|
+
const riskBreakdown = {};
|
|
466
|
+
specs.forEach((s) => {
|
|
467
|
+
const tier = s.risk_tier || 'T3';
|
|
468
|
+
riskBreakdown[tier] = (riskBreakdown[tier] || 0) + 1;
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
if (Object.keys(riskBreakdown).length > 1) {
|
|
472
|
+
const tierDisplay = Object.entries(riskBreakdown)
|
|
473
|
+
.map(([tier, count]) => `${tier}:${count}`)
|
|
474
|
+
.join(', ');
|
|
475
|
+
console.log(chalk.gray(` Risk Distribution: ${tierDisplay}`));
|
|
476
|
+
}
|
|
477
|
+
} else if (spec) {
|
|
478
|
+
// Legacy single spec system
|
|
479
|
+
console.log(chalk.green('✅ Working Spec'));
|
|
480
|
+
console.log(chalk.gray(` ID: ${spec.id} | Tier: ${spec.risk_tier} | Mode: ${spec.mode}`));
|
|
481
|
+
console.log(chalk.gray(` Title: ${spec.title}`));
|
|
482
|
+
|
|
483
|
+
// Acceptance Criteria Progress
|
|
484
|
+
if (spec.acceptance_criteria && spec.acceptance_criteria.length > 0) {
|
|
485
|
+
const total = spec.acceptance_criteria.length;
|
|
486
|
+
const completed = spec.acceptance_criteria.filter((c) => c.completed).length;
|
|
487
|
+
const percentage = Math.round((completed / total) * 100);
|
|
488
|
+
|
|
489
|
+
const color = getProgressColor(percentage);
|
|
490
|
+
const bar = createProgressBar(completed, total);
|
|
491
|
+
|
|
492
|
+
console.log(
|
|
493
|
+
chalk.gray(
|
|
494
|
+
` Acceptance Criteria: ${color(`${percentage}%`)} ${bar} ${completed}/${total}`
|
|
495
|
+
)
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Test Coverage (placeholder for now)
|
|
500
|
+
console.log(
|
|
501
|
+
chalk.gray(
|
|
502
|
+
` Test Coverage: ${chalk.blue('Calculating...')} ${createProgressBar(0, 100)} 0%`
|
|
503
|
+
)
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
// Risk Tier Indicator
|
|
507
|
+
const riskColor =
|
|
508
|
+
spec.risk_tier === 'T1' ? chalk.red : spec.risk_tier === 'T2' ? chalk.yellow : chalk.green;
|
|
509
|
+
console.log(
|
|
510
|
+
chalk.gray(
|
|
511
|
+
` Risk Tier: ${riskColor(spec.risk_tier)} (Quality Gates: ${riskColor('Active')})`
|
|
512
|
+
)
|
|
513
|
+
);
|
|
514
|
+
} else {
|
|
515
|
+
console.log(chalk.red('❌ No Specs Found'));
|
|
516
|
+
console.log(chalk.gray(' No working spec or specs directory found'));
|
|
517
|
+
console.log(chalk.yellow(' 💡 Run: caws specs create <id> to create specs'));
|
|
518
|
+
console.log(chalk.yellow(' 💡 Or run: caws init . for legacy single spec'));
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
console.log('');
|
|
522
|
+
|
|
523
|
+
// Git Hooks Status (only show in modes that support it)
|
|
524
|
+
if (modes.isFeatureEnabled('gitHooks', currentMode)) {
|
|
525
|
+
if (hooks.installed) {
|
|
526
|
+
const hookBar = createProgressBar(hooks.count, hooks.total);
|
|
527
|
+
console.log(chalk.green(`✅ Git Hooks`));
|
|
528
|
+
console.log(
|
|
529
|
+
chalk.gray(` ${hookBar} ${hooks.count}/${hooks.total} active: ${hooks.active.join(', ')}`)
|
|
530
|
+
);
|
|
531
|
+
} else {
|
|
532
|
+
console.log(chalk.yellow('⚠️ Git Hooks'));
|
|
533
|
+
console.log(chalk.gray(' No CAWS git hooks installed'));
|
|
534
|
+
console.log(chalk.yellow(' 💡 Run: caws hooks install'));
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
console.log('');
|
|
539
|
+
|
|
540
|
+
// Provenance Status (only show in modes that support it)
|
|
541
|
+
if (modes.isFeatureEnabled('provenance', currentMode)) {
|
|
542
|
+
if (provenance.exists) {
|
|
543
|
+
const provenanceBar = createProgressBar(provenance.count, Math.max(provenance.count, 10));
|
|
544
|
+
console.log(chalk.green('✅ Provenance'));
|
|
545
|
+
console.log(chalk.gray(` ${provenanceBar} ${provenance.count} entries`));
|
|
546
|
+
if (provenance.lastUpdate) {
|
|
547
|
+
console.log(chalk.gray(` Last update: ${getTimeSince(provenance.lastUpdate)}`));
|
|
548
|
+
}
|
|
549
|
+
} else {
|
|
550
|
+
console.log(chalk.yellow('⚠️ Provenance'));
|
|
551
|
+
console.log(chalk.gray(' Provenance tracking not initialized'));
|
|
552
|
+
console.log(chalk.yellow(' 💡 Run: caws provenance init'));
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
console.log('');
|
|
557
|
+
|
|
558
|
+
// Waivers Status (only show in modes that support it)
|
|
559
|
+
if (modes.isFeatureEnabled('waivers', currentMode)) {
|
|
560
|
+
if (waivers.exists && waivers.total > 0) {
|
|
561
|
+
const waiverBar = createProgressBar(waivers.active, waivers.total);
|
|
562
|
+
console.log(chalk.green('✅ Quality Gate Waivers'));
|
|
563
|
+
console.log(
|
|
564
|
+
chalk.gray(
|
|
565
|
+
` ${waiverBar} ${waivers.active} active, ${waivers.expired} expired, ${waivers.revoked} revoked`
|
|
566
|
+
)
|
|
567
|
+
);
|
|
568
|
+
console.log(chalk.gray(` Total: ${waivers.total} waiver${waivers.total > 1 ? 's' : ''}`));
|
|
569
|
+
} else if (waivers.exists) {
|
|
570
|
+
console.log(chalk.blue('ℹ️ Quality Gate Waivers'));
|
|
571
|
+
console.log(chalk.gray(' No waivers configured'));
|
|
572
|
+
} else {
|
|
573
|
+
console.log(chalk.yellow('⚠️ Quality Gate Waivers'));
|
|
574
|
+
console.log(chalk.gray(' Waiver system not initialized'));
|
|
575
|
+
console.log(chalk.yellow(' 💡 Run: caws waivers create (when needed)'));
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
console.log('');
|
|
580
|
+
|
|
581
|
+
// Quality Gates Status (only show in modes that support it)
|
|
582
|
+
if (modes.isFeatureEnabled('qualityGates', currentMode)) {
|
|
583
|
+
console.log(chalk.blue('🛡️ Quality Gates'));
|
|
584
|
+
if (gates.checked) {
|
|
585
|
+
if (gates.passed) {
|
|
586
|
+
console.log(chalk.green(` ${createProgressBar(1, 1)} All gates passed`));
|
|
587
|
+
gates.results?.forEach((gate) => {
|
|
588
|
+
const gateStatus = gate.status === 'passed' ? chalk.green('✓') : chalk.red('✗');
|
|
589
|
+
console.log(chalk.gray(` ${gateStatus} ${gate.name}: ${gate.message || 'OK'}`));
|
|
590
|
+
});
|
|
591
|
+
} else {
|
|
592
|
+
console.log(
|
|
593
|
+
chalk.red(
|
|
594
|
+
` ${createProgressBar(0, gates.results?.length || 1)} ${gates.failed || 0} gates failed`
|
|
595
|
+
)
|
|
596
|
+
);
|
|
597
|
+
gates.results?.forEach((gate) => {
|
|
598
|
+
const gateStatus = gate.status === 'passed' ? chalk.green('✓') : chalk.red('✗');
|
|
599
|
+
console.log(chalk.gray(` ${gateStatus} ${gate.name}: ${gate.message || 'Failed'}`));
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
console.log(chalk.gray(` ${gates.message}`));
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Progress Summary
|
|
608
|
+
const overallProgress = calculateOverallProgress(data);
|
|
609
|
+
const progressColor = getProgressColor(overallProgress);
|
|
610
|
+
const progressBar = createProgressBar(overallProgress, 100);
|
|
611
|
+
|
|
612
|
+
console.log('');
|
|
613
|
+
console.log(chalk.bold.blue('📈 Overall Progress'));
|
|
614
|
+
console.log(chalk.gray(` ${progressBar} ${progressColor(`${overallProgress}%`)} complete`));
|
|
615
|
+
|
|
616
|
+
// Suggestions (mode-aware)
|
|
617
|
+
const suggestions = generateSuggestions(data, currentMode);
|
|
618
|
+
if (suggestions.length > 0) {
|
|
619
|
+
console.log(chalk.bold.yellow('\n💡 Next Steps:'));
|
|
620
|
+
suggestions.forEach((suggestion, index) => {
|
|
621
|
+
console.log(chalk.yellow(` ${index + 1}. ${suggestion}`));
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Quick Links (mode-aware)
|
|
626
|
+
console.log(chalk.bold.blue('\n📚 Quick Actions:'));
|
|
627
|
+
if (spec || (specs && specs.length > 0)) {
|
|
628
|
+
if (modes.isFeatureEnabled('validate', currentMode)) {
|
|
629
|
+
console.log(chalk.blue(' View specs: caws specs list'));
|
|
630
|
+
}
|
|
631
|
+
if (modes.isFeatureEnabled('validate', currentMode)) {
|
|
632
|
+
console.log(chalk.blue(' Validate: caws validate'));
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (modes.isFeatureEnabled('gitHooks', currentMode) && hooks.installed) {
|
|
637
|
+
console.log(chalk.blue(' View hooks: caws hooks status'));
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (modes.isFeatureEnabled('provenance', currentMode) && provenance.exists) {
|
|
641
|
+
console.log(chalk.blue(' View provenance: caws provenance show'));
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (modes.isFeatureEnabled('waivers', currentMode) && waivers.exists && waivers.total > 0) {
|
|
645
|
+
console.log(chalk.blue(' View waivers: caws waivers list'));
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
console.log(chalk.blue(' Get help: caws help'));
|
|
649
|
+
console.log(chalk.blue(' Switch mode: caws mode set --interactive'));
|
|
650
|
+
|
|
651
|
+
console.log('');
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Calculate overall project progress (mode-aware)
|
|
656
|
+
* @param {Object} data - Status data
|
|
657
|
+
* @returns {number} Overall progress percentage
|
|
658
|
+
*/
|
|
659
|
+
function calculateOverallProgress(data) {
|
|
660
|
+
const { spec, specs, hooks, provenance, waivers, currentMode } = data;
|
|
661
|
+
const modes = require('../config/modes');
|
|
662
|
+
|
|
663
|
+
let score = 0;
|
|
664
|
+
|
|
665
|
+
// Multi-spec system
|
|
666
|
+
if (specs && specs.length > 0) {
|
|
667
|
+
// Specs system (40%)
|
|
668
|
+
const completedSpecs = specs.filter((s) => s.status === 'completed').length;
|
|
669
|
+
if (specs.length > 0) {
|
|
670
|
+
const percentage = (completedSpecs / specs.length) * 40;
|
|
671
|
+
score += percentage;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Git hooks (20%) - only if enabled in mode
|
|
675
|
+
if (modes.isFeatureEnabled('gitHooks', currentMode)) {
|
|
676
|
+
if (hooks.installed) score += 20;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Provenance (20%) - only if enabled in mode
|
|
680
|
+
if (modes.isFeatureEnabled('provenance', currentMode)) {
|
|
681
|
+
if (provenance.exists) score += 20;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Waivers (15%) - only if enabled in mode
|
|
685
|
+
if (modes.isFeatureEnabled('waivers', currentMode)) {
|
|
686
|
+
if (waivers.exists) score += 15;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Quality gates (5%) - only if enabled in mode
|
|
690
|
+
if (modes.isFeatureEnabled('qualityGates', currentMode)) {
|
|
691
|
+
if (specs.length > 0) score += 5;
|
|
692
|
+
}
|
|
693
|
+
} else if (spec) {
|
|
694
|
+
// Legacy single spec system (30%)
|
|
695
|
+
if (spec) score += 30;
|
|
696
|
+
|
|
697
|
+
// Acceptance criteria progress (25%)
|
|
698
|
+
if (spec && spec.acceptance_criteria && spec.acceptance_criteria.length > 0) {
|
|
699
|
+
const completed = spec.acceptance_criteria.filter((c) => c.completed).length;
|
|
700
|
+
const percentage = (completed / spec.acceptance_criteria.length) * 25;
|
|
701
|
+
score += percentage;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Git hooks (15%) - only if enabled in mode
|
|
705
|
+
if (modes.isFeatureEnabled('gitHooks', currentMode)) {
|
|
706
|
+
if (hooks.installed) score += 15;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Provenance (15%) - only if enabled in mode
|
|
710
|
+
if (modes.isFeatureEnabled('provenance', currentMode)) {
|
|
711
|
+
if (provenance.exists) score += 15;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Waivers (10%) - only if enabled in mode
|
|
715
|
+
if (modes.isFeatureEnabled('waivers', currentMode)) {
|
|
716
|
+
if (waivers.exists) score += 10;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Quality gates (5%) - only if enabled in mode
|
|
720
|
+
if (modes.isFeatureEnabled('qualityGates', currentMode)) {
|
|
721
|
+
if (spec) score += 5;
|
|
722
|
+
}
|
|
723
|
+
} else {
|
|
724
|
+
// No specs system - check basic setup (mode-aware)
|
|
725
|
+
|
|
726
|
+
// Git hooks (30%) - only if enabled in mode
|
|
727
|
+
if (modes.isFeatureEnabled('gitHooks', currentMode)) {
|
|
728
|
+
if (hooks.installed) score += 30;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Provenance (30%) - only if enabled in mode
|
|
732
|
+
if (modes.isFeatureEnabled('provenance', currentMode)) {
|
|
733
|
+
if (provenance.exists) score += 30;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Waivers (20%) - only if enabled in mode
|
|
737
|
+
if (modes.isFeatureEnabled('waivers', currentMode)) {
|
|
738
|
+
if (waivers.exists) score += 20;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Quality gates (20%) - only if enabled in mode
|
|
742
|
+
if (modes.isFeatureEnabled('qualityGates', currentMode)) {
|
|
743
|
+
if (hooks.installed || provenance.exists) score += 20;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return Math.min(Math.round(score), 100);
|
|
748
|
+
}
|
|
749
|
+
|
|
328
750
|
/**
|
|
329
751
|
* Status command handler
|
|
330
752
|
* @param {Object} options - Command options
|
|
@@ -332,29 +754,137 @@ function generateSuggestions(data) {
|
|
|
332
754
|
async function statusCommand(options = {}) {
|
|
333
755
|
return safeAsync(
|
|
334
756
|
async () => {
|
|
757
|
+
// Check current mode and adjust behavior accordingly
|
|
758
|
+
const modes = require('../config/modes');
|
|
759
|
+
const currentMode = await modes.getCurrentMode();
|
|
760
|
+
|
|
335
761
|
// Load all status data
|
|
336
762
|
const spec = await loadWorkingSpec(options.spec || '.caws/working-spec.yaml');
|
|
763
|
+
const specs = await loadSpecsFromMultiSpec();
|
|
337
764
|
const hooks = await checkGitHooks();
|
|
338
765
|
const provenance = await loadProvenanceChain();
|
|
339
766
|
const waivers = await loadWaiverStatus();
|
|
340
767
|
const gates = await checkQualityGates();
|
|
341
768
|
|
|
342
|
-
// Display status
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
769
|
+
// Display status (visual mode if requested)
|
|
770
|
+
if (options.visual || options.json) {
|
|
771
|
+
if (options.json) {
|
|
772
|
+
// JSON output for automation
|
|
773
|
+
const result = {
|
|
774
|
+
command: 'status',
|
|
775
|
+
timestamp: new Date().toISOString(),
|
|
776
|
+
system: specs.length > 0 ? 'multi-spec' : 'single-spec',
|
|
777
|
+
specs:
|
|
778
|
+
specs.length > 0
|
|
779
|
+
? {
|
|
780
|
+
count: specs.length,
|
|
781
|
+
active: specs.filter((s) => s.status === 'active').length,
|
|
782
|
+
draft: specs.filter((s) => s.status === 'draft').length,
|
|
783
|
+
completed: specs.filter((s) => s.status === 'completed').length,
|
|
784
|
+
list: specs.map((s) => ({
|
|
785
|
+
id: s.id,
|
|
786
|
+
type: s.type,
|
|
787
|
+
status: s.status,
|
|
788
|
+
title: s.title,
|
|
789
|
+
})),
|
|
790
|
+
}
|
|
791
|
+
: null,
|
|
792
|
+
legacySpec: spec
|
|
793
|
+
? {
|
|
794
|
+
id: spec.id,
|
|
795
|
+
title: spec.title,
|
|
796
|
+
riskTier: spec.risk_tier,
|
|
797
|
+
mode: spec.mode,
|
|
798
|
+
acceptanceCriteria: spec.acceptance_criteria?.length || 0,
|
|
799
|
+
completedCriteria:
|
|
800
|
+
spec.acceptance_criteria?.filter((c) => c.completed).length || 0,
|
|
801
|
+
}
|
|
802
|
+
: null,
|
|
803
|
+
hooks: {
|
|
804
|
+
installed: hooks.installed,
|
|
805
|
+
count: hooks.count,
|
|
806
|
+
total: hooks.total,
|
|
807
|
+
active: hooks.active,
|
|
808
|
+
},
|
|
809
|
+
provenance: {
|
|
810
|
+
exists: provenance.exists,
|
|
811
|
+
count: provenance.count,
|
|
812
|
+
lastUpdate: provenance.lastUpdate,
|
|
813
|
+
},
|
|
814
|
+
waivers: {
|
|
815
|
+
exists: waivers.exists,
|
|
816
|
+
active: waivers.active,
|
|
817
|
+
expired: waivers.expired,
|
|
818
|
+
revoked: waivers.revoked,
|
|
819
|
+
total: waivers.total,
|
|
820
|
+
},
|
|
821
|
+
qualityGates: {
|
|
822
|
+
checked: gates.checked,
|
|
823
|
+
passed: gates.passed,
|
|
824
|
+
message: gates.message,
|
|
825
|
+
},
|
|
826
|
+
overallProgress: calculateOverallProgress({
|
|
827
|
+
spec,
|
|
828
|
+
specs,
|
|
829
|
+
hooks,
|
|
830
|
+
provenance,
|
|
831
|
+
waivers,
|
|
832
|
+
gates,
|
|
833
|
+
}),
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
console.log(JSON.stringify(result, null, 2));
|
|
837
|
+
} else {
|
|
838
|
+
// Visual output
|
|
839
|
+
displayVisualStatus(
|
|
840
|
+
{
|
|
841
|
+
spec,
|
|
842
|
+
specs,
|
|
843
|
+
hooks,
|
|
844
|
+
provenance,
|
|
845
|
+
waivers,
|
|
846
|
+
gates,
|
|
847
|
+
},
|
|
848
|
+
currentMode
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
} else {
|
|
852
|
+
// Original text-based output
|
|
853
|
+
displayStatus({
|
|
854
|
+
spec,
|
|
855
|
+
hooks,
|
|
856
|
+
provenance,
|
|
857
|
+
waivers,
|
|
858
|
+
gates,
|
|
859
|
+
});
|
|
860
|
+
}
|
|
350
861
|
|
|
351
862
|
const result = outputResult({
|
|
352
863
|
command: 'status',
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
864
|
+
mode: options.visual ? 'visual' : options.json ? 'json' : 'text',
|
|
865
|
+
system: specs.length > 0 ? 'multi-spec' : 'single-spec',
|
|
866
|
+
currentMode: currentMode,
|
|
867
|
+
specs: specs.length,
|
|
868
|
+
legacySpec: spec ? 'loaded' : 'not found',
|
|
869
|
+
hooks: modes.isFeatureEnabled('gitHooks', currentMode) ? hooks.installed : null,
|
|
870
|
+
provenance: modes.isFeatureEnabled('provenance', currentMode)
|
|
871
|
+
? provenance.count || 0
|
|
872
|
+
: null,
|
|
873
|
+
waivers: modes.isFeatureEnabled('waivers', currentMode) ? waivers.active || 0 : null,
|
|
874
|
+
gates: modes.isFeatureEnabled('qualityGates', currentMode)
|
|
875
|
+
? gates.passed
|
|
876
|
+
? 'passed'
|
|
877
|
+
: 'failed'
|
|
878
|
+
: null,
|
|
879
|
+
overallProgress: calculateOverallProgress({
|
|
880
|
+
spec,
|
|
881
|
+
specs,
|
|
882
|
+
hooks,
|
|
883
|
+
provenance,
|
|
884
|
+
waivers,
|
|
885
|
+
gates,
|
|
886
|
+
currentMode,
|
|
887
|
+
}),
|
|
358
888
|
});
|
|
359
889
|
|
|
360
890
|
return result;
|