@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.
Files changed (119) hide show
  1. package/dist/commands/archive.js +353 -0
  2. package/dist/commands/iterate.js +12 -13
  3. package/dist/commands/mode.js +259 -0
  4. package/dist/commands/plan.js +448 -0
  5. package/dist/commands/quality-gates.js +490 -0
  6. package/dist/commands/specs.js +735 -0
  7. package/dist/commands/status.js +552 -22
  8. package/dist/commands/tutorial.js +481 -0
  9. package/dist/commands/validate.js +137 -54
  10. package/dist/commands/waivers.js +101 -26
  11. package/dist/config/modes.js +321 -0
  12. package/dist/constants/spec-types.js +42 -0
  13. package/dist/index.js +225 -10
  14. package/dist/scaffold/git-hooks.js +32 -44
  15. package/dist/scaffold/index.js +19 -0
  16. package/dist/utils/quality-gates-errors.js +520 -0
  17. package/dist/utils/quality-gates.js +361 -0
  18. package/dist/utils/spec-resolver.js +602 -0
  19. package/dist/waivers-manager.js +49 -4
  20. package/package.json +6 -5
  21. package/templates/.cursor/hooks/caws-scope-guard.sh +64 -8
  22. package/templates/.cursor/hooks/validate-spec.sh +22 -12
  23. package/templates/.cursor/rules/{01-claims-verification.mdc → 00-claims-verification.mdc} +1 -1
  24. package/templates/.cursor/rules/01-working-style.mdc +50 -0
  25. package/templates/.cursor/rules/{02-testing-standards.mdc → 02-quality-gates.mdc} +84 -29
  26. package/templates/.cursor/rules/03-naming-and-refactor.mdc +33 -0
  27. package/templates/.cursor/rules/04-logging-language-style.mdc +23 -0
  28. package/templates/.cursor/rules/05-safe-defaults-guards.mdc +23 -0
  29. package/templates/.cursor/rules/06-typescript-conventions.mdc +36 -0
  30. package/templates/.cursor/rules/07-process-ops.mdc +20 -0
  31. package/templates/.cursor/rules/08-solid-and-architecture.mdc +16 -0
  32. package/templates/.cursor/rules/09-docstrings.mdc +89 -0
  33. package/templates/.cursor/rules/10-authorship-and-attribution.mdc +15 -0
  34. package/templates/.cursor/rules/11-documentation-quality-standards.mdc +390 -0
  35. package/templates/.cursor/rules/12-scope-management-waivers.mdc +385 -0
  36. package/templates/.cursor/rules/13-implementation-completeness.mdc +516 -0
  37. package/templates/.cursor/rules/14-language-agnostic-standards.mdc +588 -0
  38. package/templates/.cursor/rules/15-sophisticated-todo-detection.mdc +425 -0
  39. package/templates/.cursor/rules/README.md +93 -7
  40. package/templates/scripts/quality-gates/check-god-objects.js +146 -0
  41. package/templates/scripts/quality-gates/run-quality-gates.js +50 -0
  42. package/templates/scripts/v3/analysis/todo_analyzer.py +1950 -0
  43. package/dist/budget-derivation.d.ts +0 -74
  44. package/dist/budget-derivation.d.ts.map +0 -1
  45. package/dist/cicd-optimizer.d.ts +0 -142
  46. package/dist/cicd-optimizer.d.ts.map +0 -1
  47. package/dist/commands/burnup.d.ts +0 -6
  48. package/dist/commands/burnup.d.ts.map +0 -1
  49. package/dist/commands/diagnose.d.ts +0 -52
  50. package/dist/commands/diagnose.d.ts.map +0 -1
  51. package/dist/commands/evaluate.d.ts +0 -8
  52. package/dist/commands/evaluate.d.ts.map +0 -1
  53. package/dist/commands/init.d.ts +0 -5
  54. package/dist/commands/init.d.ts.map +0 -1
  55. package/dist/commands/iterate.d.ts +0 -8
  56. package/dist/commands/iterate.d.ts.map +0 -1
  57. package/dist/commands/provenance.d.ts +0 -32
  58. package/dist/commands/provenance.d.ts.map +0 -1
  59. package/dist/commands/quality-monitor.d.ts +0 -17
  60. package/dist/commands/quality-monitor.d.ts.map +0 -1
  61. package/dist/commands/status.d.ts +0 -43
  62. package/dist/commands/status.d.ts.map +0 -1
  63. package/dist/commands/templates.d.ts +0 -74
  64. package/dist/commands/templates.d.ts.map +0 -1
  65. package/dist/commands/tool.d.ts +0 -13
  66. package/dist/commands/tool.d.ts.map +0 -1
  67. package/dist/commands/troubleshoot.d.ts +0 -8
  68. package/dist/commands/troubleshoot.d.ts.map +0 -1
  69. package/dist/commands/validate.d.ts +0 -8
  70. package/dist/commands/validate.d.ts.map +0 -1
  71. package/dist/commands/waivers.d.ts +0 -8
  72. package/dist/commands/waivers.d.ts.map +0 -1
  73. package/dist/commands/workflow.d.ts +0 -85
  74. package/dist/commands/workflow.d.ts.map +0 -1
  75. package/dist/config/index.d.ts +0 -29
  76. package/dist/config/index.d.ts.map +0 -1
  77. package/dist/error-handler.d.ts +0 -164
  78. package/dist/error-handler.d.ts.map +0 -1
  79. package/dist/generators/jest-config.d.ts +0 -32
  80. package/dist/generators/jest-config.d.ts.map +0 -1
  81. package/dist/generators/working-spec.d.ts +0 -13
  82. package/dist/generators/working-spec.d.ts.map +0 -1
  83. package/dist/index.d.ts +0 -5
  84. package/dist/index.d.ts.map +0 -1
  85. package/dist/minimal-cli.d.ts +0 -3
  86. package/dist/minimal-cli.d.ts.map +0 -1
  87. package/dist/policy/PolicyManager.d.ts +0 -104
  88. package/dist/policy/PolicyManager.d.ts.map +0 -1
  89. package/dist/scaffold/cursor-hooks.d.ts +0 -7
  90. package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
  91. package/dist/scaffold/git-hooks.d.ts +0 -20
  92. package/dist/scaffold/git-hooks.d.ts.map +0 -1
  93. package/dist/scaffold/index.d.ts +0 -20
  94. package/dist/scaffold/index.d.ts.map +0 -1
  95. package/dist/spec/SpecFileManager.d.ts +0 -146
  96. package/dist/spec/SpecFileManager.d.ts.map +0 -1
  97. package/dist/test-analysis.d.ts +0 -182
  98. package/dist/test-analysis.d.ts.map +0 -1
  99. package/dist/tool-interface.d.ts +0 -236
  100. package/dist/tool-interface.d.ts.map +0 -1
  101. package/dist/tool-loader.d.ts +0 -77
  102. package/dist/tool-loader.d.ts.map +0 -1
  103. package/dist/tool-validator.d.ts +0 -72
  104. package/dist/tool-validator.d.ts.map +0 -1
  105. package/dist/utils/detection.d.ts +0 -7
  106. package/dist/utils/detection.d.ts.map +0 -1
  107. package/dist/utils/finalization.d.ts +0 -17
  108. package/dist/utils/finalization.d.ts.map +0 -1
  109. package/dist/utils/project-analysis.d.ts +0 -14
  110. package/dist/utils/project-analysis.d.ts.map +0 -1
  111. package/dist/utils/typescript-detector.d.ts +0 -63
  112. package/dist/utils/typescript-detector.d.ts.map +0 -1
  113. package/dist/validation/spec-validation.d.ts +0 -43
  114. package/dist/validation/spec-validation.d.ts.map +0 -1
  115. package/dist/waivers-manager.d.ts +0 -167
  116. package/dist/waivers-manager.d.ts.map +0 -1
  117. package/templates/.cursor/rules/03-infrastructure-standards.mdc +0 -251
  118. package/templates/.cursor/rules/04-documentation-integrity.mdc +0 -291
  119. package/templates/.cursor/rules/05-production-readiness-checklist.mdc +0 -214
@@ -1,12 +1,10 @@
1
1
  /**
2
2
  * @fileoverview Validate Command Handler
3
- * Handles validation commands for CAWS CLI
3
+ * Handles validation commands for CAWS CLI with multi-spec support
4
4
  * @author @darianrosebrook
5
5
  */
6
6
 
7
- const fs = require('fs-extra');
8
7
  const path = require('path');
9
- const yaml = require('js-yaml');
10
8
  const chalk = require('chalk');
11
9
 
12
10
  // Import validation functionality
@@ -15,47 +13,40 @@ const {
15
13
  getComplianceGrade,
16
14
  } = require('../validation/spec-validation');
17
15
 
16
+ // Import spec resolution system
17
+ const { resolveSpec, suggestMigration } = require('../utils/spec-resolver');
18
+
18
19
  /**
19
20
  * Validate command handler
20
- * Enhanced with JSON output format support
21
- * @param {string} specFile - Path to spec file
21
+ * Enhanced with multi-spec support and JSON output format
22
+ * @param {string} specFile - Path to spec file (optional, uses spec resolution)
22
23
  * @param {Object} options - Command options
24
+ * @param {string} [options.specId] - Feature-specific spec ID
25
+ * @param {boolean} [options.interactive] - Use interactive spec selection
26
+ * @param {boolean} [options.format] - Output format (json)
23
27
  */
24
- async function validateCommand(specFile, options) {
28
+ async function validateCommand(specFile, options = {}) {
25
29
  try {
26
- let specPath = specFile || path.join('.caws', 'working-spec.yaml');
27
-
28
- if (!fs.existsSync(specPath)) {
29
- if (options.format === 'json') {
30
- console.log(
31
- JSON.stringify(
32
- {
33
- passed: false,
34
- verdict: 'fail',
35
- errors: [
36
- {
37
- field: 'spec_file',
38
- message: `Spec file not found: ${specPath}`,
39
- suggestion: 'Run "caws init" first to create a working spec',
40
- },
41
- ],
42
- },
43
- null,
44
- 2
45
- )
46
- );
47
- } else {
48
- console.error(chalk.red(`❌ Spec file not found: ${specPath}`));
49
- console.error(chalk.blue('💡 Run "caws init" first to create a working spec'));
50
- }
51
- process.exit(1);
52
- }
30
+ // Resolve spec using priority system
31
+ const resolved = await resolveSpec({
32
+ specId: options.specId,
33
+ specFile,
34
+ warnLegacy: options.format !== 'json',
35
+ interactive: options.interactive || false,
36
+ });
53
37
 
54
- const specContent = fs.readFileSync(specPath, 'utf8');
55
- const spec = yaml.load(specContent);
38
+ const { path: specPath, type: specType, spec } = resolved;
39
+
40
+ // Suggest migration if using legacy spec
41
+ if (specType === 'legacy' && options.format !== 'json') {
42
+ await suggestMigration();
43
+ }
56
44
 
57
45
  if (options.format !== 'json') {
58
- console.log(chalk.cyan('🔍 Validating CAWS working spec...'));
46
+ console.log(
47
+ chalk.cyan(`🔍 Validating ${specType === 'feature' ? 'feature' : 'working'} spec...`)
48
+ );
49
+ console.log(chalk.gray(` Spec: ${path.relative(process.cwd(), specPath)}`));
59
50
  }
60
51
 
61
52
  const result = validateWorkingSpecWithSuggestions(spec, {
@@ -64,16 +55,87 @@ async function validateCommand(specFile, options) {
64
55
  suggestions: !options.quiet,
65
56
  checkBudget: true,
66
57
  projectRoot: path.dirname(specPath),
58
+ specType,
67
59
  });
68
60
 
61
+ // Enhanced validation for multi-spec scenarios
62
+ const enhancedValidation = { ...result };
63
+
64
+ if (specType === 'feature') {
65
+ // Check for potential issues in feature specs
66
+ const featureIssues = [];
67
+
68
+ // Check scope conflicts (if multiple specs exist)
69
+ const { checkMultiSpecStatus } = require('../utils/spec-resolver');
70
+ const multiSpecStatus = await checkMultiSpecStatus();
71
+
72
+ if (multiSpecStatus.specCount > 1) {
73
+ const { checkScopeConflicts } = require('../utils/spec-resolver');
74
+ const conflicts = await checkScopeConflicts(
75
+ Object.keys(multiSpecStatus.registry?.specs || {})
76
+ );
77
+
78
+ if (conflicts.length > 0) {
79
+ const myConflicts = conflicts.filter((c) => c.spec1 === spec.id || c.spec2 === spec.id);
80
+
81
+ if (myConflicts.length > 0) {
82
+ featureIssues.push({
83
+ type: 'warning',
84
+ message: `Scope conflicts detected with other specs`,
85
+ details: myConflicts.map((c) => {
86
+ const otherSpec = c.spec1 === spec.id ? c.spec2 : c.spec1;
87
+ return `Conflict with ${otherSpec}: ${c.conflicts.join(', ')}`;
88
+ }),
89
+ });
90
+ }
91
+ }
92
+ }
93
+
94
+ // Check for missing contracts in feature specs
95
+ if (spec.contracts && spec.contracts.length === 0 && spec.mode === 'feature') {
96
+ featureIssues.push({
97
+ type: 'info',
98
+ message: 'Consider adding API contracts for better integration',
99
+ suggestion: 'Add contracts section to define API boundaries',
100
+ });
101
+ }
102
+
103
+ // Check for overly broad scopes
104
+ if (spec.scope && spec.scope.in) {
105
+ const broadPatterns = spec.scope.in.filter(
106
+ (pattern) => pattern === 'src/' || pattern === 'tests/' || pattern.includes('*')
107
+ );
108
+
109
+ if (broadPatterns.length > 0) {
110
+ featureIssues.push({
111
+ type: 'warning',
112
+ message: 'Broad scope patterns detected',
113
+ details: `Patterns like ${broadPatterns.join(', ')} may conflict with other features`,
114
+ suggestion: 'Use more specific scope.in paths',
115
+ });
116
+ }
117
+ }
118
+
119
+ // Add feature-specific issues to validation result
120
+ if (featureIssues.length > 0) {
121
+ enhancedValidation.issues = (enhancedValidation.issues || []).concat(featureIssues);
122
+ enhancedValidation.featureValidation = {
123
+ passed: featureIssues.filter((i) => i.type === 'error').length === 0,
124
+ issues: featureIssues,
125
+ };
126
+ }
127
+ }
128
+
129
+ const finalResult = enhancedValidation;
130
+
69
131
  // Format output based on requested format
70
132
  if (options.format === 'json') {
71
133
  // Structured JSON output matching CAWSValidationResult
72
134
  const jsonResult = {
73
- passed: result.valid,
135
+ passed: finalResult.valid,
74
136
  cawsVersion: '3.4.0',
75
137
  timestamp: new Date().toISOString(),
76
- verdict: result.valid ? 'pass' : 'fail',
138
+ verdict: finalResult.valid ? 'pass' : 'fail',
77
139
  spec: {
78
140
  id: spec.id,
79
141
  title: spec.title,
@@ -81,21 +143,29 @@ async function validateCommand(specFile, options) {
81
143
  mode: spec.mode,
82
144
  },
83
145
  validation: {
84
- errors: result.errors || [],
85
- warnings: result.warnings || [],
86
- fixes: result.fixes || [],
146
+ errors: finalResult.errors || [],
147
+ warnings: finalResult.warnings || [],
148
+ fixes: finalResult.fixes || [],
87
149
  },
88
- budgetCompliance: result.budget_check || null,
150
+ budgetCompliance: finalResult.budget_check || null,
151
+ specType,
152
+ specPath: path.relative(process.cwd(), specPath),
153
+ featureValidation: finalResult.featureValidation,
89
154
  };
90
155
 
91
156
  console.log(JSON.stringify(jsonResult, null, 2));
92
157
 
93
- if (!result.valid) {
94
- process.exit(1);
158
+ if (!finalResult.valid) {
159
+ // Don't call process.exit in test environment
160
+ if (process.env.NODE_ENV !== 'test' && !process.env.JEST_WORKER_ID) {
161
+ process.exit(1);
162
+ } else {
163
+ throw new Error('Validation failed');
164
+ }
95
165
  }
96
166
  } else {
97
167
  // Human-readable text output
98
- if (result.valid) {
168
+ if (finalResult.valid) {
99
169
  console.log(chalk.green('✅ Working spec validation passed'));
100
170
  if (!options.quiet) {
101
171
  console.log(chalk.gray(` Risk tier: ${spec.risk_tier}`));
@@ -103,10 +173,15 @@ async function validateCommand(specFile, options) {
103
173
  if (spec.title) {
104
174
  console.log(chalk.gray(` Title: ${spec.title}`));
105
175
  }
106
- if (result.complianceScore !== undefined) {
107
- const grade = getComplianceGrade(result.complianceScore);
108
- const scorePercent = (result.complianceScore * 100).toFixed(0);
109
- const scoreColor = result.complianceScore >= 0.9 ? 'green' : result.complianceScore >= 0.7 ? 'yellow' : 'red';
176
+ if (finalResult.complianceScore !== undefined) {
177
+ const grade = getComplianceGrade(finalResult.complianceScore);
178
+ const scorePercent = (finalResult.complianceScore * 100).toFixed(0);
179
+ const scoreColor =
180
+ finalResult.complianceScore >= 0.9
181
+ ? 'green'
182
+ : finalResult.complianceScore >= 0.7
183
+ ? 'yellow'
184
+ : 'red';
110
185
  console.log(chalk[scoreColor](` Compliance: ${scorePercent}% (Grade ${grade})`));
111
186
  }
112
187
  }
@@ -114,7 +189,7 @@ async function validateCommand(specFile, options) {
114
189
  console.log(chalk.red('❌ Working spec validation failed'));
115
190
 
116
191
  // Show errors
117
- result.errors.forEach((error, index) => {
192
+ finalResult.errors.forEach((error, index) => {
118
193
  console.log(` ${index + 1}. ${chalk.red(error.message)}`);
119
194
  if (error.suggestion) {
120
195
  console.log(` ${chalk.blue('💡 ' + error.suggestion)}`);
@@ -122,14 +197,19 @@ async function validateCommand(specFile, options) {
122
197
  });
123
198
 
124
199
  // Show warnings
125
- if (result.warnings && result.warnings.length > 0) {
200
+ if (finalResult.warnings && finalResult.warnings.length > 0) {
126
201
  console.log(chalk.yellow('\n⚠️ Warnings:'));
127
- result.warnings.forEach((warning, index) => {
202
+ finalResult.warnings.forEach((warning, index) => {
128
203
  console.log(` ${index + 1}. ${chalk.yellow(warning.message)}`);
129
204
  });
130
205
  }
131
206
 
132
- process.exit(1);
207
+ // Don't call process.exit in test environment
208
+ if (process.env.NODE_ENV !== 'test' && !process.env.JEST_WORKER_ID) {
209
+ process.exit(1);
210
+ } else {
211
+ throw new Error('Validation failed');
212
+ }
133
213
  }
134
214
  }
135
215
  } catch (error) {
@@ -148,7 +228,10 @@ async function validateCommand(specFile, options) {
148
228
  } else {
149
229
  console.error(chalk.red('❌ Error during validation:'), error.message);
150
230
  }
151
- process.exit(1);
231
+ // Don't call process.exit in test environment
232
+ if (process.env.NODE_ENV !== 'test' && !process.env.JEST_WORKER_ID) {
233
+ process.exit(1);
234
+ }
152
235
  }
153
236
  }
154
237
 
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * CAWS Waivers Command
3
- *
3
+ *
4
4
  * Manage quality gate waivers for exceptional circumstances.
5
5
  * Waivers allow temporary exceptions to quality requirements
6
6
  * with proper documentation and approval.
7
- *
7
+ *
8
8
  * @author @darianrosebrook
9
9
  */
10
10
 
@@ -13,12 +13,13 @@ const path = require('path');
13
13
  const yaml = require('js-yaml');
14
14
  const chalk = require('chalk');
15
15
  const { initializeGlobalSetup } = require('../config');
16
+ const WaiversManager = require('../waivers-manager');
16
17
 
17
18
  const WAIVER_DIR = '.caws/waivers';
18
19
 
19
20
  /**
20
21
  * Waivers command handler
21
- *
22
+ *
22
23
  * @param {string} subcommand - create, list, show, revoke
23
24
  * @param {object} options - Command options
24
25
  */
@@ -26,7 +27,7 @@ async function waiversCommand(subcommand = 'list', options = {}) {
26
27
  try {
27
28
  console.log('🔍 Detecting CAWS setup...');
28
29
  const setup = initializeGlobalSetup();
29
-
30
+
30
31
  if (setup.hasWorkingSpec) {
31
32
  console.log(`✅ Detected ${setup.setupType} CAWS setup`);
32
33
  console.log(` Capabilities: ${setup.capabilities.join(', ')}`);
@@ -70,9 +71,18 @@ async function waiversCommand(subcommand = 'list', options = {}) {
70
71
  */
71
72
  async function createWaiver(options) {
72
73
  // Validate required fields
73
- const required = ['title', 'reason', 'description', 'gates', 'expiresAt', 'approvedBy', 'impactLevel', 'mitigationPlan'];
74
- const missing = required.filter(field => !options[field]);
75
-
74
+ const required = [
75
+ 'title',
76
+ 'reason',
77
+ 'description',
78
+ 'gates',
79
+ 'expiresAt',
80
+ 'approvedBy',
81
+ 'impactLevel',
82
+ 'mitigationPlan',
83
+ ];
84
+ const missing = required.filter((field) => !options[field]);
85
+
76
86
  if (missing.length > 0) {
77
87
  console.error(chalk.red(`\n❌ Missing required fields: ${missing.join(', ')}`));
78
88
  console.log(chalk.yellow('\n💡 Example:'));
@@ -93,9 +103,10 @@ async function createWaiver(options) {
93
103
  const timestamp = new Date().toISOString();
94
104
 
95
105
  // Parse gates
96
- const gates = typeof options.gates === 'string'
97
- ? options.gates.split(',').map(g => g.trim())
98
- : options.gates;
106
+ const gates =
107
+ typeof options.gates === 'string'
108
+ ? options.gates.split(',').map((g) => g.trim())
109
+ : options.gates;
99
110
 
100
111
  // Create waiver object
101
112
  const waiver = {
@@ -112,10 +123,18 @@ async function createWaiver(options) {
112
123
  status: 'active',
113
124
  };
114
125
 
115
- // Save waiver
126
+ // Save individual waiver file
116
127
  const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
117
128
  fs.writeFileSync(waiverPath, yaml.dump(waiver, { lineWidth: -1 }));
118
129
 
130
+ // Also add to active waivers file
131
+ try {
132
+ await addToActiveWaivers(waiver);
133
+ } catch (error) {
134
+ console.error(`Failed to add waiver to active waivers: ${error.message}`);
135
+ console.error(error.stack);
136
+ }
137
+
119
138
  console.log(chalk.green(`\n✅ Waiver created: ${waiverId}`));
120
139
  console.log(` Title: ${waiver.title}`);
121
140
  console.log(` Reason: ${waiver.reason}`);
@@ -132,36 +151,42 @@ async function createWaiver(options) {
132
151
  */
133
152
  async function listWaivers(_options) {
134
153
  const waiversDir = path.join(process.cwd(), WAIVER_DIR);
135
-
154
+
136
155
  if (!fs.existsSync(waiversDir)) {
137
156
  console.log(chalk.yellow('\nℹ️ No waivers found\n'));
138
157
  return;
139
158
  }
140
159
 
141
- const waiverFiles = fs.readdirSync(waiversDir).filter(f => f.endsWith('.yaml'));
160
+ const waiverFiles = fs.readdirSync(waiversDir).filter((f) => f.endsWith('.yaml'));
142
161
 
143
162
  if (waiverFiles.length === 0) {
144
163
  console.log(chalk.yellow('\nℹ️ No waivers found\n'));
145
164
  return;
146
165
  }
147
166
 
148
- const waivers = waiverFiles.map(file => {
167
+ const waivers = waiverFiles.map((file) => {
149
168
  const content = fs.readFileSync(path.join(waiversDir, file), 'utf8');
150
169
  return yaml.load(content);
151
170
  });
152
171
 
153
172
  // Filter by status
154
- const activeWaivers = waivers.filter(w => w.status === 'active' && new Date(w.expires_at) > new Date());
155
- const expiredWaivers = waivers.filter(w => w.status === 'active' && new Date(w.expires_at) <= new Date());
156
- const revokedWaivers = waivers.filter(w => w.status === 'revoked');
173
+ const activeWaivers = waivers.filter(
174
+ (w) => w.status === 'active' && new Date(w.expires_at) > new Date()
175
+ );
176
+ const expiredWaivers = waivers.filter(
177
+ (w) => w.status === 'active' && new Date(w.expires_at) <= new Date()
178
+ );
179
+ const revokedWaivers = waivers.filter((w) => w.status === 'revoked');
157
180
 
158
181
  console.log(chalk.blue('\n🔖 CAWS Quality Gate Waivers\n'));
159
182
  console.log('─'.repeat(60));
160
183
 
161
184
  if (activeWaivers.length > 0) {
162
185
  console.log(chalk.green('\n✅ Active Waivers:\n'));
163
- activeWaivers.forEach(waiver => {
164
- const daysLeft = Math.ceil((new Date(waiver.expires_at) - new Date()) / (1000 * 60 * 60 * 24));
186
+ activeWaivers.forEach((waiver) => {
187
+ const daysLeft = Math.ceil(
188
+ (new Date(waiver.expires_at) - new Date()) / (1000 * 60 * 60 * 24)
189
+ );
165
190
  console.log(`🔖 ${chalk.bold(waiver.id)}: ${waiver.title}`);
166
191
  console.log(` Reason: ${waiver.reason}`);
167
192
  console.log(` Gates: ${waiver.gates.join(', ')}`);
@@ -173,7 +198,7 @@ async function listWaivers(_options) {
173
198
 
174
199
  if (expiredWaivers.length > 0) {
175
200
  console.log(chalk.yellow('\n⚠️ Expired Waivers:\n'));
176
- expiredWaivers.forEach(waiver => {
201
+ expiredWaivers.forEach((waiver) => {
177
202
  console.log(`🔖 ${chalk.bold(waiver.id)}: ${waiver.title}`);
178
203
  console.log(` Expired: ${waiver.expires_at}`);
179
204
  console.log();
@@ -182,7 +207,7 @@ async function listWaivers(_options) {
182
207
 
183
208
  if (revokedWaivers.length > 0) {
184
209
  console.log(chalk.red('\n❌ Revoked Waivers:\n'));
185
- revokedWaivers.forEach(waiver => {
210
+ revokedWaivers.forEach((waiver) => {
186
211
  console.log(`🔖 ${chalk.bold(waiver.id)}: ${waiver.title}`);
187
212
  console.log(` Revoked: ${waiver.revoked_at}`);
188
213
  console.log();
@@ -207,7 +232,7 @@ async function showWaiver(waiverId, _options) {
207
232
  }
208
233
 
209
234
  const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
210
-
235
+
211
236
  if (!fs.existsSync(waiverPath)) {
212
237
  console.error(chalk.red(`\n❌ Waiver not found: ${waiverId}\n`));
213
238
  process.exit(1);
@@ -222,7 +247,9 @@ async function showWaiver(waiverId, _options) {
222
247
 
223
248
  console.log(chalk.blue('\n🔖 Waiver Details\n'));
224
249
  console.log('─'.repeat(60));
225
- console.log(`\n${statusIcon} Status: ${chalk.bold(isActive ? 'Active' : isExpired ? 'Expired' : waiver.status)}`);
250
+ console.log(
251
+ `\n${statusIcon} Status: ${chalk.bold(isActive ? 'Active' : isExpired ? 'Expired' : waiver.status)}`
252
+ );
226
253
  console.log(`\n📋 ${chalk.bold(waiver.title)}`);
227
254
  console.log(` ID: ${waiver.id}`);
228
255
  console.log(` Reason: ${waiver.reason}`);
@@ -230,7 +257,7 @@ async function showWaiver(waiverId, _options) {
230
257
  console.log(`\n📝 Description:`);
231
258
  console.log(` ${waiver.description}`);
232
259
  console.log(`\n🔒 Waived Quality Gates:`);
233
- waiver.gates.forEach(gate => {
260
+ waiver.gates.forEach((gate) => {
234
261
  console.log(` • ${gate}`);
235
262
  });
236
263
  console.log(`\n🛡️ Mitigation Plan:`);
@@ -259,7 +286,7 @@ async function revokeWaiver(waiverId, options) {
259
286
  }
260
287
 
261
288
  const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
262
-
289
+
263
290
  if (!fs.existsSync(waiverPath)) {
264
291
  console.error(chalk.red(`\n❌ Waiver not found: ${waiverId}\n`));
265
292
  process.exit(1);
@@ -289,5 +316,53 @@ async function revokeWaiver(waiverId, options) {
289
316
  console.log(` Reason: ${waiver.revocation_reason}\n`);
290
317
  }
291
318
 
292
- module.exports = { waiversCommand };
319
+ /**
320
+ * Add waiver to active waivers file for quality gates integration
321
+ */
322
+ async function addToActiveWaivers(waiver) {
323
+ try {
324
+ const waiversManager = new WaiversManager();
325
+
326
+ // Load existing active waivers
327
+ const activeWaivers = await waiversManager.loadActiveWaivers();
328
+
329
+ // Check if waiver already exists
330
+ const existingIndex = activeWaivers.findIndex((w) => w.id === waiver.id);
331
+
332
+ // Normalize waiver format
333
+ const normalizedWaiver = {
334
+ id: waiver.id,
335
+ title: waiver.title || waiver.description || waiver.id,
336
+ reason: waiver.reason || waiver.reason_code || 'unknown',
337
+ description: waiver.description || waiver.title || waiver.id,
338
+ gates: Array.isArray(waiver.gates) ? waiver.gates : [waiver.gates],
339
+ expires_at: waiver.expires_at,
340
+ approved_by: waiver.approved_by || waiver.risk_owner || 'unknown',
341
+ created_at: waiver.created_at || waiver.approved_at || new Date().toISOString(),
342
+ risk_assessment: waiver.risk_assessment || {
343
+ impact_level: waiver.impact_level || 'medium',
344
+ mitigation_plan: waiver.mitigation || waiver.mitigation_plan || 'Unknown mitigation',
345
+ },
346
+ metadata: waiver.metadata || {},
347
+ };
348
+
349
+ if (existingIndex >= 0) {
350
+ // Update existing waiver
351
+ activeWaivers[existingIndex] = normalizedWaiver;
352
+ } else {
353
+ // Add new waiver
354
+ activeWaivers.push(normalizedWaiver);
355
+ }
293
356
 
357
+ // Save updated active waivers
358
+ await waiversManager.saveActiveWaivers(activeWaivers);
359
+ } catch (error) {
360
+ // Enhanced error logging
361
+ console.error(`Error adding waiver to active waivers: ${error.message}`);
362
+ console.error(error.stack);
363
+ console.warn(`Warning: Could not add waiver to active waivers file: ${error.message}`);
364
+ // Don't fail the waiver creation if this fails
365
+ }
366
+ }
367
+
368
+ module.exports = { waiversCommand };