@paths.design/caws-cli 7.0.2 → 8.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 (217) hide show
  1. package/dist/budget-derivation.js +5 -4
  2. package/dist/commands/diagnose.js +24 -19
  3. package/dist/commands/init.js +51 -4
  4. package/dist/commands/quality-gates.js +147 -9
  5. package/dist/commands/specs.js +148 -14
  6. package/dist/commands/status.js +2 -2
  7. package/dist/commands/tool.js +2 -4
  8. package/dist/config/index.js +17 -8
  9. package/dist/generators/working-spec.js +19 -6
  10. package/dist/scaffold/git-hooks.js +245 -46
  11. package/dist/scaffold/index.js +53 -7
  12. package/dist/templates/.caws/tools/README.md +21 -0
  13. package/dist/templates/.cursor/README.md +311 -0
  14. package/dist/templates/.cursor/hooks/audit.sh +55 -0
  15. package/dist/templates/.cursor/hooks/block-dangerous.sh +83 -0
  16. package/dist/templates/.cursor/hooks/caws-quality-check.sh +52 -0
  17. package/dist/templates/.cursor/hooks/caws-scope-guard.sh +130 -0
  18. package/dist/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
  19. package/dist/templates/.cursor/hooks/format.sh +38 -0
  20. package/dist/templates/.cursor/hooks/naming-check.sh +64 -0
  21. package/dist/templates/.cursor/hooks/scan-secrets.sh +46 -0
  22. package/dist/templates/.cursor/hooks/scope-guard.sh +52 -0
  23. package/dist/templates/.cursor/hooks/validate-spec.sh +83 -0
  24. package/dist/templates/.cursor/hooks.json +59 -0
  25. package/dist/templates/.cursor/rules/00-claims-verification.mdc +144 -0
  26. package/dist/templates/.cursor/rules/01-working-style.mdc +50 -0
  27. package/dist/templates/.cursor/rules/02-quality-gates.mdc +370 -0
  28. package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +33 -0
  29. package/dist/templates/.cursor/rules/04-logging-language-style.mdc +23 -0
  30. package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +23 -0
  31. package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +36 -0
  32. package/dist/templates/.cursor/rules/07-process-ops.mdc +20 -0
  33. package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +16 -0
  34. package/dist/templates/.cursor/rules/09-docstrings.mdc +89 -0
  35. package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +390 -0
  36. package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +385 -0
  37. package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +516 -0
  38. package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +588 -0
  39. package/dist/templates/.cursor/rules/README.md +148 -0
  40. package/dist/templates/.github/copilot/instructions.md +311 -0
  41. package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
  42. package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
  43. package/dist/templates/.vscode/launch.json +56 -0
  44. package/dist/templates/.vscode/settings.json +93 -0
  45. package/dist/templates/.windsurf/workflows/caws-guided-development.md +92 -0
  46. package/dist/templates/COMMIT_CONVENTIONS.md +86 -0
  47. package/dist/templates/OIDC_SETUP.md +300 -0
  48. package/dist/templates/agents.md +1047 -0
  49. package/dist/templates/codemod/README.md +1 -0
  50. package/dist/templates/codemod/test.js +93 -0
  51. package/dist/templates/docs/README.md +150 -0
  52. package/dist/templates/scripts/quality-gates/check-god-objects.js +146 -0
  53. package/dist/templates/scripts/quality-gates/run-quality-gates.js +50 -0
  54. package/dist/templates/scripts/v3/analysis/todo_analyzer.py +1997 -0
  55. package/dist/tool-loader.js +6 -1
  56. package/dist/tool-validator.js +8 -2
  57. package/dist/utils/detection.js +4 -3
  58. package/dist/utils/git-lock.js +119 -0
  59. package/dist/utils/gitignore-updater.js +148 -0
  60. package/dist/utils/project-analysis.js +176 -16
  61. package/dist/utils/quality-gates.js +48 -7
  62. package/dist/utils/spec-resolver.js +27 -3
  63. package/dist/utils/yaml-validation.js +156 -0
  64. package/dist/validation/spec-validation.js +81 -2
  65. package/package.json +2 -2
  66. package/templates/.caws/schemas/waivers.schema.json +30 -0
  67. package/templates/.caws/schemas/working-spec.schema.json +133 -0
  68. package/templates/.caws/templates/working-spec.template.yml +74 -0
  69. package/templates/.caws/tools/README.md +21 -0
  70. package/templates/.caws/tools/scope-guard.js +208 -0
  71. package/templates/.caws/tools-allow.json +331 -0
  72. package/templates/.caws/waivers.yml +19 -0
  73. package/templates/.cursor/hooks/scope-guard.sh +2 -2
  74. package/templates/.cursor/hooks/validate-spec.sh +42 -7
  75. package/dist/budget-derivation.d.ts +0 -74
  76. package/dist/budget-derivation.d.ts.map +0 -1
  77. package/dist/cicd-optimizer.d.ts +0 -142
  78. package/dist/cicd-optimizer.d.ts.map +0 -1
  79. package/dist/commands/archive.d.ts +0 -50
  80. package/dist/commands/archive.d.ts.map +0 -1
  81. package/dist/commands/burnup.d.ts +0 -6
  82. package/dist/commands/burnup.d.ts.map +0 -1
  83. package/dist/commands/diagnose.d.ts +0 -52
  84. package/dist/commands/diagnose.d.ts.map +0 -1
  85. package/dist/commands/evaluate.d.ts +0 -8
  86. package/dist/commands/evaluate.d.ts.map +0 -1
  87. package/dist/commands/init.d.ts +0 -5
  88. package/dist/commands/init.d.ts.map +0 -1
  89. package/dist/commands/iterate.d.ts +0 -8
  90. package/dist/commands/iterate.d.ts.map +0 -1
  91. package/dist/commands/mode.d.ts +0 -24
  92. package/dist/commands/mode.d.ts.map +0 -1
  93. package/dist/commands/plan.d.ts +0 -49
  94. package/dist/commands/plan.d.ts.map +0 -1
  95. package/dist/commands/provenance.d.ts +0 -32
  96. package/dist/commands/provenance.d.ts.map +0 -1
  97. package/dist/commands/quality-gates.d.ts +0 -52
  98. package/dist/commands/quality-gates.d.ts.map +0 -1
  99. package/dist/commands/quality-monitor.d.ts +0 -17
  100. package/dist/commands/quality-monitor.d.ts.map +0 -1
  101. package/dist/commands/specs.d.ts +0 -71
  102. package/dist/commands/specs.d.ts.map +0 -1
  103. package/dist/commands/status.d.ts +0 -44
  104. package/dist/commands/status.d.ts.map +0 -1
  105. package/dist/commands/templates.d.ts +0 -74
  106. package/dist/commands/templates.d.ts.map +0 -1
  107. package/dist/commands/tool.d.ts +0 -13
  108. package/dist/commands/tool.d.ts.map +0 -1
  109. package/dist/commands/troubleshoot.d.ts +0 -8
  110. package/dist/commands/troubleshoot.d.ts.map +0 -1
  111. package/dist/commands/tutorial.d.ts +0 -55
  112. package/dist/commands/tutorial.d.ts.map +0 -1
  113. package/dist/commands/validate.d.ts +0 -15
  114. package/dist/commands/validate.d.ts.map +0 -1
  115. package/dist/commands/waivers.d.ts +0 -8
  116. package/dist/commands/waivers.d.ts.map +0 -1
  117. package/dist/commands/workflow.d.ts +0 -85
  118. package/dist/commands/workflow.d.ts.map +0 -1
  119. package/dist/config/index.d.ts +0 -29
  120. package/dist/config/index.d.ts.map +0 -1
  121. package/dist/config/modes.d.ts +0 -225
  122. package/dist/config/modes.d.ts.map +0 -1
  123. package/dist/constants/spec-types.d.ts +0 -41
  124. package/dist/constants/spec-types.d.ts.map +0 -1
  125. package/dist/error-handler.d.ts +0 -164
  126. package/dist/error-handler.d.ts.map +0 -1
  127. package/dist/generators/jest-config.d.ts +0 -32
  128. package/dist/generators/jest-config.d.ts.map +0 -1
  129. package/dist/generators/working-spec.d.ts +0 -13
  130. package/dist/generators/working-spec.d.ts.map +0 -1
  131. package/dist/index-new.d.ts +0 -5
  132. package/dist/index-new.d.ts.map +0 -1
  133. package/dist/index-new.js +0 -317
  134. package/dist/index.d.ts +0 -5
  135. package/dist/index.d.ts.map +0 -1
  136. package/dist/index.js.backup +0 -4711
  137. package/dist/minimal-cli.d.ts +0 -3
  138. package/dist/minimal-cli.d.ts.map +0 -1
  139. package/dist/policy/PolicyManager.d.ts +0 -104
  140. package/dist/policy/PolicyManager.d.ts.map +0 -1
  141. package/dist/scaffold/cursor-hooks.d.ts +0 -7
  142. package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
  143. package/dist/scaffold/git-hooks.d.ts +0 -20
  144. package/dist/scaffold/git-hooks.d.ts.map +0 -1
  145. package/dist/scaffold/index.d.ts +0 -20
  146. package/dist/scaffold/index.d.ts.map +0 -1
  147. package/dist/spec/SpecFileManager.d.ts +0 -146
  148. package/dist/spec/SpecFileManager.d.ts.map +0 -1
  149. package/dist/test-analysis.d.ts +0 -182
  150. package/dist/test-analysis.d.ts.map +0 -1
  151. package/dist/tool-interface.d.ts +0 -236
  152. package/dist/tool-interface.d.ts.map +0 -1
  153. package/dist/tool-loader.d.ts +0 -77
  154. package/dist/tool-loader.d.ts.map +0 -1
  155. package/dist/tool-validator.d.ts +0 -72
  156. package/dist/tool-validator.d.ts.map +0 -1
  157. package/dist/utils/detection.d.ts +0 -7
  158. package/dist/utils/detection.d.ts.map +0 -1
  159. package/dist/utils/finalization.d.ts +0 -17
  160. package/dist/utils/finalization.d.ts.map +0 -1
  161. package/dist/utils/project-analysis.d.ts +0 -14
  162. package/dist/utils/project-analysis.d.ts.map +0 -1
  163. package/dist/utils/quality-gates.d.ts +0 -49
  164. package/dist/utils/quality-gates.d.ts.map +0 -1
  165. package/dist/utils/spec-resolver.d.ts +0 -88
  166. package/dist/utils/spec-resolver.d.ts.map +0 -1
  167. package/dist/utils/typescript-detector.d.ts +0 -63
  168. package/dist/utils/typescript-detector.d.ts.map +0 -1
  169. package/dist/validation/spec-validation.d.ts +0 -43
  170. package/dist/validation/spec-validation.d.ts.map +0 -1
  171. package/dist/waivers-manager.d.ts +0 -167
  172. package/dist/waivers-manager.d.ts.map +0 -1
  173. package/templates/apps/tools/caws/COMPLETION_REPORT.md +0 -331
  174. package/templates/apps/tools/caws/MIGRATION_SUMMARY.md +0 -360
  175. package/templates/apps/tools/caws/README.md +0 -463
  176. package/templates/apps/tools/caws/TEST_STATUS.md +0 -365
  177. package/templates/apps/tools/caws/attest.js +0 -357
  178. package/templates/apps/tools/caws/ci-optimizer.js +0 -642
  179. package/templates/apps/tools/caws/config.ts +0 -245
  180. package/templates/apps/tools/caws/cross-functional.js +0 -876
  181. package/templates/apps/tools/caws/dashboard.js +0 -1112
  182. package/templates/apps/tools/caws/flake-detector.ts +0 -362
  183. package/templates/apps/tools/caws/gates.js +0 -198
  184. package/templates/apps/tools/caws/gates.ts +0 -271
  185. package/templates/apps/tools/caws/language-adapters.ts +0 -381
  186. package/templates/apps/tools/caws/language-support.d.ts +0 -367
  187. package/templates/apps/tools/caws/language-support.d.ts.map +0 -1
  188. package/templates/apps/tools/caws/language-support.js +0 -585
  189. package/templates/apps/tools/caws/legacy-assessment.ts +0 -408
  190. package/templates/apps/tools/caws/legacy-assessor.js +0 -764
  191. package/templates/apps/tools/caws/mutant-analyzer.js +0 -734
  192. package/templates/apps/tools/caws/perf-budgets.ts +0 -349
  193. package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
  194. package/templates/apps/tools/caws/property-testing.js +0 -707
  195. package/templates/apps/tools/caws/provenance.d.ts +0 -14
  196. package/templates/apps/tools/caws/provenance.d.ts.map +0 -1
  197. package/templates/apps/tools/caws/provenance.js +0 -132
  198. package/templates/apps/tools/caws/provenance.js.backup +0 -73
  199. package/templates/apps/tools/caws/provenance.ts +0 -211
  200. package/templates/apps/tools/caws/security-provenance.ts +0 -483
  201. package/templates/apps/tools/caws/shared/base-tool.ts +0 -281
  202. package/templates/apps/tools/caws/shared/config-manager.ts +0 -366
  203. package/templates/apps/tools/caws/shared/gate-checker.ts +0 -849
  204. package/templates/apps/tools/caws/shared/types.ts +0 -444
  205. package/templates/apps/tools/caws/shared/validator.ts +0 -305
  206. package/templates/apps/tools/caws/shared/waivers-manager.ts +0 -174
  207. package/templates/apps/tools/caws/spec-test-mapper.ts +0 -391
  208. package/templates/apps/tools/caws/test-quality.js +0 -578
  209. package/templates/apps/tools/caws/validate.js +0 -76
  210. package/templates/apps/tools/caws/validate.ts +0 -228
  211. package/templates/apps/tools/caws/waivers.js +0 -344
  212. /package/{templates/apps/tools/caws → dist/templates/.caws}/schemas/waivers.schema.json +0 -0
  213. /package/{templates/apps/tools/caws → dist/templates/.caws}/schemas/working-spec.schema.json +0 -0
  214. /package/{templates/apps/tools/caws → dist/templates/.caws}/templates/working-spec.template.yml +0 -0
  215. /package/{templates/apps/tools/caws → dist/templates/.caws/tools}/scope-guard.js +0 -0
  216. /package/{templates/apps/tools/caws → dist/templates/.caws}/tools-allow.json +0 -0
  217. /package/{templates/apps/tools/caws → dist/templates/.caws}/waivers.yml +0 -0
@@ -1,228 +0,0 @@
1
- #!/usr/bin/env tsx
2
-
3
- /**
4
- * CAWS Validation Tool
5
- * CLI wrapper for CawsValidator with schema validation
6
- *
7
- * @author @darianrosebrook
8
- */
9
-
10
- import * as path from 'path';
11
- import { CawsValidator } from './shared/validator.js';
12
- import { ValidationResult } from './shared/types.js';
13
-
14
- class ValidateCLI {
15
- private validator: CawsValidator;
16
-
17
- constructor() {
18
- this.validator = new CawsValidator();
19
- }
20
-
21
- /**
22
- * Validate a working specification file
23
- */
24
- validateWorkingSpec(specPath: string): ValidationResult {
25
- try {
26
- const result = this.validator.validateWorkingSpec(specPath);
27
-
28
- if (result.passed) {
29
- console.log('✅ Working specification is valid');
30
- console.log(` Score: ${(result.score * 100).toFixed(0)}%`);
31
-
32
- if (result.warnings && result.warnings.length > 0) {
33
- console.log('\n⚠️ Warnings:');
34
- result.warnings.forEach((warning) => console.log(` - ${warning}`));
35
- }
36
-
37
- if (result.details) {
38
- console.log('\n📊 Details:');
39
- if (result.details.risk_tier) {
40
- console.log(` Tier: ${result.details.risk_tier}`);
41
- }
42
- if (result.details.acceptance_count) {
43
- console.log(` Acceptance Criteria: ${result.details.acceptance_count}`);
44
- }
45
- if (result.details.contract_count) {
46
- console.log(` Contracts: ${result.details.contract_count}`);
47
- }
48
- }
49
- } else {
50
- console.error('❌ Working specification is invalid:');
51
- if (result.errors && result.errors.length > 0) {
52
- result.errors.forEach((error) => console.error(` - ${error}`));
53
- }
54
- }
55
-
56
- return result;
57
- } catch (error) {
58
- console.error(`❌ Validation failed: ${error}`);
59
- return {
60
- passed: false,
61
- errors: [`Validation error: ${error}`],
62
- score: 0,
63
- details: {},
64
- };
65
- }
66
- }
67
-
68
- /**
69
- * Validate a provenance file
70
- */
71
- validateProvenance(provenancePath: string): ValidationResult {
72
- try {
73
- const result = this.validator.validateProvenance(provenancePath);
74
-
75
- if (result.passed) {
76
- console.log('✅ Provenance file is valid');
77
- console.log(` Score: ${(result.score * 100).toFixed(0)}%`);
78
-
79
- if (result.details) {
80
- console.log('\n📊 Provenance Details:');
81
- if (result.details.agent) {
82
- console.log(` Agent: ${result.details.agent}`);
83
- }
84
- if (result.details.model) {
85
- console.log(` Model: ${result.details.model}`);
86
- }
87
- if (result.details.commit) {
88
- console.log(` Commit: ${result.details.commit}`);
89
- }
90
- }
91
- } else {
92
- console.error('❌ Provenance file is invalid:');
93
- if (result.errors && result.errors.length > 0) {
94
- result.errors.forEach((error) => console.error(` - ${error}`));
95
- }
96
- }
97
-
98
- return result;
99
- } catch (error) {
100
- console.error(`❌ Provenance validation failed: ${error}`);
101
- return {
102
- passed: false,
103
- errors: [`Validation error: ${error}`],
104
- score: 0,
105
- details: {},
106
- };
107
- }
108
- }
109
-
110
- /**
111
- * Validate a JSON file against a schema
112
- */
113
- validateJsonSchema(jsonPath: string, schemaPath: string): ValidationResult {
114
- try {
115
- const result = this.validator.validateJsonAgainstSchema(jsonPath, schemaPath);
116
-
117
- if (result.passed) {
118
- console.log('✅ JSON file is valid against schema');
119
- } else {
120
- console.error('❌ JSON file is invalid:');
121
- if (result.errors && result.errors.length > 0) {
122
- result.errors.forEach((error) => console.error(` - ${error}`));
123
- }
124
- }
125
-
126
- return result;
127
- } catch (error) {
128
- console.error(`❌ Schema validation failed: ${error}`);
129
- return {
130
- passed: false,
131
- errors: [`Validation error: ${error}`],
132
- score: 0,
133
- details: {},
134
- };
135
- }
136
- }
137
-
138
- /**
139
- * Validate a YAML file against a schema
140
- */
141
- validateYamlSchema(yamlPath: string, schemaPath: string): ValidationResult {
142
- try {
143
- const result = this.validator.validateYamlAgainstSchema(yamlPath, schemaPath);
144
-
145
- if (result.passed) {
146
- console.log('✅ YAML file is valid against schema');
147
- } else {
148
- console.error('❌ YAML file is invalid:');
149
- if (result.errors && result.errors.length > 0) {
150
- result.errors.forEach((error) => console.error(` - ${error}`));
151
- }
152
- }
153
-
154
- return result;
155
- } catch (error) {
156
- console.error(`❌ Schema validation failed: ${error}`);
157
- return {
158
- passed: false,
159
- errors: [`Validation error: ${error}`],
160
- score: 0,
161
- details: {},
162
- };
163
- }
164
- }
165
- }
166
-
167
- // Main CLI handler
168
- if (import.meta.url === `file://${process.argv[1]}`) {
169
- const command = process.argv[2];
170
- const cli = new ValidateCLI();
171
-
172
- switch (command) {
173
- case 'spec': {
174
- const specPath = process.argv[3] || '.caws/working-spec.yaml';
175
- const result = cli.validateWorkingSpec(specPath);
176
- process.exit(result.passed ? 0 : 1);
177
- }
178
-
179
- case 'provenance': {
180
- const provenancePath = process.argv[3] || '.agent/provenance.json';
181
- const result = cli.validateProvenance(provenancePath);
182
- process.exit(result.passed ? 0 : 1);
183
- }
184
-
185
- case 'json': {
186
- const jsonPath = process.argv[3];
187
- const schemaPath = process.argv[4];
188
-
189
- if (!jsonPath || !schemaPath) {
190
- console.error('Usage: validate.ts json <json-file> <schema-file>');
191
- process.exit(1);
192
- }
193
-
194
- const result = cli.validateJsonSchema(jsonPath, schemaPath);
195
- process.exit(result.passed ? 0 : 1);
196
- }
197
-
198
- case 'yaml': {
199
- const yamlPath = process.argv[3];
200
- const schemaPath = process.argv[4];
201
-
202
- if (!yamlPath || !schemaPath) {
203
- console.error('Usage: validate.ts yaml <yaml-file> <schema-file>');
204
- process.exit(1);
205
- }
206
-
207
- const result = cli.validateYamlSchema(yamlPath, schemaPath);
208
- process.exit(result.passed ? 0 : 1);
209
- }
210
-
211
- default:
212
- console.log('CAWS Validation Tool');
213
- console.log('');
214
- console.log('Commands:');
215
- console.log(' spec [path] - Validate working specification');
216
- console.log(' provenance [path] - Validate provenance file');
217
- console.log(' json <file> <schema> - Validate JSON against schema');
218
- console.log(' yaml <file> <schema> - Validate YAML against schema');
219
- console.log('');
220
- console.log('Examples:');
221
- console.log(' validate.ts spec .caws/working-spec.yaml');
222
- console.log(' validate.ts provenance .agent/provenance.json');
223
- console.log(' validate.ts yaml .caws/waivers.yml schemas/waivers.schema.json');
224
- process.exit(1);
225
- }
226
- }
227
-
228
- export { ValidateCLI };
@@ -1,344 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * @fileoverview CAWS Waivers Management Tool
5
- * Manages time-boxed waivers for quality gates
6
- * @author @darianrosebrook
7
- */
8
-
9
- const fs = require('fs');
10
- const yaml = require('js-yaml');
11
-
12
- /**
13
- * Waiver reasons enum
14
- */
15
- const WAIVER_REASONS = {
16
- URGENT_FIX: 'urgent_fix',
17
- EXPERIMENTAL: 'experimental',
18
- LEGACY_CODE: 'legacy_code',
19
- RESOURCE_CONSTRAINTS: 'resource_constraints',
20
- OTHER: 'other',
21
- };
22
-
23
- /**
24
- * Waivable gates
25
- */
26
- const WAIVABLE_GATES = ['coverage', 'mutation', 'contracts', 'manual_review', 'trust_score'];
27
-
28
- /**
29
- * Load waivers configuration
30
- * @param {string} waiversPath - Path to waivers.yml file
31
- * @returns {Object} Parsed waivers configuration
32
- */
33
- function loadWaiversConfig(waiversPath = '.caws/waivers.yml') {
34
- try {
35
- if (!fs.existsSync(waiversPath)) {
36
- return { waivers: [] };
37
- }
38
-
39
- const content = fs.readFileSync(waiversPath, 'utf8');
40
- return yaml.load(content);
41
- } catch (error) {
42
- console.error('❌ Error loading waivers config:', error.message);
43
- return { waivers: [] };
44
- }
45
- }
46
-
47
- /**
48
- * Save waivers configuration
49
- * @param {Object} config - Waivers configuration
50
- * @param {string} waiversPath - Path to save waivers.yml file
51
- */
52
- function saveWaiversConfig(config, waiversPath = '.caws/waivers.yml') {
53
- try {
54
- const yamlContent = yaml.dump(config, { indent: 2 });
55
- fs.writeFileSync(waiversPath, yamlContent);
56
- console.log(`✅ Waivers configuration saved to ${waiversPath}`);
57
- } catch (error) {
58
- console.error('❌ Error saving waivers config:', error.message);
59
- process.exit(1);
60
- }
61
- }
62
-
63
- /**
64
- * Find active waivers for a project and gate
65
- * @param {string} projectId - Project identifier
66
- * @param {string} gate - Gate to check
67
- * @param {string} waiversPath - Path to waivers.yml file
68
- * @returns {Array} Active waivers
69
- */
70
- function findActiveWaivers(projectId, gate, waiversPath = '.caws/waivers.yml') {
71
- const config = loadWaiversConfig(waiversPath);
72
- const now = new Date();
73
-
74
- return config.waivers.filter((waiver) => {
75
- const expiresAt = new Date(waiver.expires_at);
76
-
77
- // Filter out expired waivers
78
- if (now > expiresAt) {
79
- console.warn(`⚠️ Waiver ${waiver.id} has expired (${waiver.expires_at})`);
80
- return false;
81
- }
82
-
83
- // Check if project specific
84
- if (waiver.projects && waiver.projects.length > 0) {
85
- if (!waiver.projects.includes(projectId)) {
86
- return false;
87
- }
88
- }
89
-
90
- // Check if gate is waived
91
- return waiver.gates.includes(gate);
92
- });
93
- }
94
-
95
- /**
96
- * Create a new waiver
97
- * @param {Object} options - Waiver options
98
- */
99
- function createWaiver(options) {
100
- const {
101
- id,
102
- description,
103
- gates,
104
- reason,
105
- approver,
106
- expiresInDays = 7,
107
- projects = [],
108
- maxTrustScore = 79,
109
- } = options;
110
-
111
- // Validate inputs
112
- if (!id || !description || !gates || !reason || !approver) {
113
- console.error('❌ Missing required waiver fields');
114
- process.exit(1);
115
- }
116
-
117
- // Validate gates
118
- const invalidGates = gates.filter((gate) => !WAIVABLE_GATES.includes(gate));
119
- if (invalidGates.length > 0) {
120
- console.error(`❌ Invalid gates: ${invalidGates.join(', ')}`);
121
- console.error(`💡 Valid gates: ${WAIVABLE_GATES.join(', ')}`);
122
- process.exit(1);
123
- }
124
-
125
- // Validate reason
126
- if (!Object.values(WAIVER_REASONS).includes(reason)) {
127
- console.error(`❌ Invalid reason: ${reason}`);
128
- console.error(`💡 Valid reasons: ${Object.values(WAIVER_REASONS).join(', ')}`);
129
- process.exit(1);
130
- }
131
-
132
- const expiresAt = new Date();
133
- expiresAt.setDate(expiresAt.getDate() + expiresInDays);
134
-
135
- const waiver = {
136
- id,
137
- description,
138
- gates,
139
- reason,
140
- approver,
141
- expires_at: expiresAt.toISOString(),
142
- projects,
143
- max_trust_score: maxTrustScore,
144
- };
145
-
146
- // Load existing waivers
147
- const config = loadWaiversConfig();
148
-
149
- // Check for duplicate ID
150
- const existingWaiver = config.waivers.find((w) => w.id === id);
151
- if (existingWaiver) {
152
- console.error(`❌ Waiver with ID ${id} already exists`);
153
- process.exit(1);
154
- }
155
-
156
- // Add new waiver
157
- config.waivers.push(waiver);
158
-
159
- // Save configuration
160
- saveWaiversConfig(config);
161
-
162
- console.log(`✅ Created waiver ${id}`);
163
- console.log(` Description: ${description}`);
164
- console.log(` Gates: ${gates.join(', ')}`);
165
- console.log(` Reason: ${reason}`);
166
- console.log(` Expires: ${expiresAt.toISOString()}`);
167
- if (projects.length > 0) {
168
- console.log(` Projects: ${projects.join(', ')}`);
169
- }
170
- console.log(` Max Trust Score: ${maxTrustScore}`);
171
- }
172
-
173
- /**
174
- * List all waivers
175
- * @param {string} waiversPath - Path to waivers.yml file
176
- */
177
- function listWaivers(waiversPath = '.caws/waivers.yml') {
178
- const config = loadWaiversConfig(waiversPath);
179
-
180
- if (config.waivers.length === 0) {
181
- console.log('ℹ️ No waivers configured');
182
- return;
183
- }
184
-
185
- console.log('📋 Active Waivers:');
186
- const now = new Date();
187
-
188
- config.waivers.forEach((waiver) => {
189
- const expiresAt = new Date(waiver.expires_at);
190
- const isExpired = now > expiresAt;
191
- const status = isExpired ? '🔴 EXPIRED' : '🟢 ACTIVE';
192
- const daysLeft = Math.ceil((expiresAt - now) / (1000 * 60 * 60 * 24));
193
-
194
- console.log(`\n${status} Waiver: ${waiver.id}`);
195
- console.log(` Description: ${waiver.description}`);
196
- console.log(` Gates: ${waiver.gates.join(', ')}`);
197
- console.log(` Reason: ${waiver.reason}`);
198
- console.log(` Approver: ${waiver.approver}`);
199
- console.log(` Expires: ${waiver.expires_at} (${daysLeft} days)`);
200
- if (waiver.projects && waiver.projects.length > 0) {
201
- console.log(` Projects: ${waiver.projects.join(', ')}`);
202
- }
203
- if (waiver.max_trust_score) {
204
- console.log(` Max Trust Score: ${waiver.max_trust_score}`);
205
- }
206
- });
207
- }
208
-
209
- /**
210
- * Remove expired waivers
211
- * @param {string} waiversPath - Path to waivers.yml file
212
- */
213
- function cleanupExpiredWaivers(waiversPath = '.caws/waivers.yml') {
214
- const config = loadWaiversConfig(waiversPath);
215
- const now = new Date();
216
-
217
- const activeWaivers = config.waivers.filter((waiver) => {
218
- const expiresAt = new Date(waiver.expires_at);
219
- return now <= expiresAt;
220
- });
221
-
222
- const removedCount = config.waivers.length - activeWaivers.length;
223
-
224
- if (removedCount > 0) {
225
- config.waivers = activeWaivers;
226
- saveWaiversConfig(config);
227
- console.log(`✅ Cleaned up ${removedCount} expired waiver(s)`);
228
- } else {
229
- console.log('ℹ️ No expired waivers to clean up');
230
- }
231
- }
232
-
233
- /**
234
- * Check if a specific gate is waived for a project
235
- * @param {string} projectId - Project identifier
236
- * @param {string} gate - Gate to check
237
- * @param {string} waiversPath - Path to waivers.yml file
238
- * @returns {Object} Waiver status information
239
- */
240
- function checkWaiverStatus(projectId, gate, waiversPath = '.caws/waivers.yml') {
241
- const activeWaivers = findActiveWaivers(projectId, gate, waiversPath);
242
-
243
- if (activeWaivers.length === 0) {
244
- return {
245
- waived: false,
246
- reason: null,
247
- maxTrustScore: 100,
248
- };
249
- }
250
-
251
- // Find the most restrictive waiver (lowest max trust score)
252
- const applicableWaiver = activeWaivers.reduce((mostRestrictive, waiver) => {
253
- if (
254
- !mostRestrictive ||
255
- (waiver.max_trust_score && waiver.max_trust_score < mostRestrictive.max_trust_score)
256
- ) {
257
- return waiver;
258
- }
259
- return mostRestrictive;
260
- }, null);
261
-
262
- return {
263
- waived: true,
264
- reason: applicableWaiver.reason,
265
- maxTrustScore: applicableWaiver.max_trust_score || 79,
266
- waiverId: applicableWaiver.id,
267
- expiresAt: applicableWaiver.expires_at,
268
- };
269
- }
270
-
271
- // CLI interface
272
- if (require.main === module) {
273
- const command = process.argv[2];
274
-
275
- switch (command) {
276
- case 'create':
277
- createWaiver({
278
- id: process.argv[3],
279
- description: process.argv[4],
280
- gates: process.argv[5]?.split(',') || [],
281
- reason: process.argv[6],
282
- approver: process.argv[7],
283
- expiresInDays: parseInt(process.argv[8]) || 7,
284
- projects: process.argv[9]?.split(',') || [],
285
- maxTrustScore: parseInt(process.argv[10]) || 79,
286
- });
287
- break;
288
-
289
- case 'list':
290
- listWaivers();
291
- break;
292
-
293
- case 'cleanup':
294
- cleanupExpiredWaivers();
295
- break;
296
-
297
- case 'check':
298
- const projectId = process.argv[3];
299
- const gate = process.argv[4];
300
- if (!projectId || !gate) {
301
- console.error('❌ Usage: node waivers.js check <project-id> <gate>');
302
- process.exit(1);
303
- }
304
- const status = checkWaiverStatus(projectId, gate);
305
- console.log(`Waiver status for ${gate} on project ${projectId}:`);
306
- console.log(` Waived: ${status.waived}`);
307
- if (status.waived) {
308
- console.log(` Reason: ${status.reason}`);
309
- console.log(` Max Trust Score: ${status.maxTrustScore}`);
310
- console.log(` Waiver ID: ${status.waiverId}`);
311
- console.log(` Expires: ${status.expiresAt}`);
312
- }
313
- break;
314
-
315
- default:
316
- console.log('CAWS Waivers Management Tool');
317
- console.log('Usage:');
318
- console.log(
319
- ' node waivers.js create <id> <description> <gates> <reason> <approver> [expires-days] [projects] [max-trust-score]'
320
- );
321
- console.log(' node waivers.js list');
322
- console.log(' node waivers.js cleanup');
323
- console.log(' node waivers.js check <project-id> <gate>');
324
- console.log('');
325
- console.log('Examples:');
326
- console.log(
327
- ' node waivers.js create HOTFIX-001 "Urgent security fix" "mutation,coverage" urgent_fix "senior-dev" 3'
328
- );
329
- console.log(' node waivers.js check FEAT-1234 mutation');
330
- process.exit(1);
331
- }
332
- }
333
-
334
- module.exports = {
335
- loadWaiversConfig,
336
- saveWaiversConfig,
337
- findActiveWaivers,
338
- checkWaiverStatus,
339
- createWaiver,
340
- listWaivers,
341
- cleanupExpiredWaivers,
342
- WAIVER_REASONS,
343
- WAIVABLE_GATES,
344
- };