@paths.design/caws-cli 4.0.0 → 4.1.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.d.ts +50 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +353 -0
- package/dist/commands/iterate.d.ts.map +1 -1
- package/dist/commands/iterate.js +12 -13
- package/dist/commands/mode.d.ts +24 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +259 -0
- package/dist/commands/plan.d.ts +49 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +448 -0
- package/dist/commands/quality-gates.d.ts +52 -0
- package/dist/commands/quality-gates.d.ts.map +1 -0
- package/dist/commands/quality-gates.js +490 -0
- package/dist/commands/specs.d.ts +71 -0
- package/dist/commands/specs.d.ts.map +1 -0
- package/dist/commands/specs.js +735 -0
- package/dist/commands/status.d.ts +4 -3
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +552 -22
- package/dist/commands/tutorial.d.ts +55 -0
- package/dist/commands/tutorial.d.ts.map +1 -0
- package/dist/commands/tutorial.js +481 -0
- package/dist/commands/validate.d.ts +10 -3
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +137 -54
- package/dist/config/modes.d.ts +225 -0
- package/dist/config/modes.d.ts.map +1 -0
- package/dist/config/modes.js +321 -0
- package/dist/constants/spec-types.d.ts +41 -0
- package/dist/constants/spec-types.d.ts.map +1 -0
- package/dist/constants/spec-types.js +42 -0
- package/dist/index-new.d.ts +5 -0
- package/dist/index-new.d.ts.map +1 -0
- package/dist/index-new.js +317 -0
- package/dist/index.js +225 -10
- package/dist/index.js.backup +4711 -0
- package/dist/scaffold/git-hooks.d.ts.map +1 -1
- package/dist/scaffold/git-hooks.js +32 -44
- package/dist/scaffold/index.d.ts.map +1 -1
- package/dist/scaffold/index.js +19 -0
- package/dist/utils/quality-gates-errors.js +520 -0
- package/dist/utils/quality-gates.d.ts +49 -0
- package/dist/utils/quality-gates.d.ts.map +1 -0
- package/dist/utils/quality-gates.js +361 -0
- package/dist/utils/spec-resolver.d.ts +88 -0
- package/dist/utils/spec-resolver.d.ts.map +1 -0
- package/dist/utils/spec-resolver.js +602 -0
- 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/apps/tools/caws/prompt-lint.js.backup +274 -0
- package/templates/apps/tools/caws/provenance.js.backup +73 -0
- 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/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
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAWS Quality Gates Command
|
|
3
|
+
*
|
|
4
|
+
* Integrates the hardened quality gates system into the CAWS CLI.
|
|
5
|
+
* Provides access to enterprise-grade quality enforcement with:
|
|
6
|
+
* - Timeout protection and concurrent execution
|
|
7
|
+
* - Comprehensive gate coverage (naming, duplication, god objects, documentation)
|
|
8
|
+
* - JSON output and CI/CD integration
|
|
9
|
+
* - Exception framework with audit trails
|
|
10
|
+
*
|
|
11
|
+
* @author @darianrosebrook
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const chalk = require('chalk');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { spawn } = require('child_process');
|
|
18
|
+
// const { execSync } = require('child_process');
|
|
19
|
+
// const crypto = require('crypto');
|
|
20
|
+
// const yaml = require('js-yaml');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Quality Gates Configuration
|
|
24
|
+
*/
|
|
25
|
+
// const QUALITY_CONFIG = {
|
|
26
|
+
// godObjectThresholds: {
|
|
27
|
+
// warning: 1750, // Lines of code
|
|
28
|
+
// critical: 2000,
|
|
29
|
+
// },
|
|
30
|
+
// todoConfidenceThreshold: 0.8,
|
|
31
|
+
// cawsTierThresholds: {
|
|
32
|
+
// 1: { coverage: 90, mutation: 70, contracts: true, review: true },
|
|
33
|
+
// 2: { coverage: 80, mutation: 50, contracts: true, review: false },
|
|
34
|
+
// 3: { coverage: 70, mutation: 30, contracts: false, review: false },
|
|
35
|
+
// },
|
|
36
|
+
// crisisResponseThresholds: {
|
|
37
|
+
// godObjectCritical: 3000, // Higher threshold in crisis mode
|
|
38
|
+
// todoConfidenceThreshold: 0.9, // Stricter TODO detection
|
|
39
|
+
// },
|
|
40
|
+
// };
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Update provenance with quality gates results
|
|
44
|
+
* @param {Object} results - Quality gates results
|
|
45
|
+
* @param {boolean} crisisMode - Whether in crisis mode
|
|
46
|
+
* @param {string[]} stagedFiles - Array of staged files
|
|
47
|
+
*/
|
|
48
|
+
// NOTE: updateProvenance function commented out to avoid lint errors
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Detect agent type for provenance tracking
|
|
52
|
+
* @returns {string} Agent type identifier
|
|
53
|
+
*/
|
|
54
|
+
// function detectAgentType() {
|
|
55
|
+
// try {
|
|
56
|
+
// // Check for Cursor IDE indicators
|
|
57
|
+
// if (process.env.CURSOR_USER_DATA_DIR) {
|
|
58
|
+
// return 'cursor-ide';
|
|
59
|
+
// }
|
|
60
|
+
|
|
61
|
+
// // Check for VS Code indicators
|
|
62
|
+
// if (process.env.VSCODE_PID) {
|
|
63
|
+
// return 'vscode';
|
|
64
|
+
// }
|
|
65
|
+
|
|
66
|
+
// // Check for GitHub Copilot indicators
|
|
67
|
+
// if (process.env.GITHUB_COPILOT_ENABLED) {
|
|
68
|
+
// return 'github-copilot';
|
|
69
|
+
// }
|
|
70
|
+
|
|
71
|
+
// // Check for command line usage
|
|
72
|
+
// if (process.env.TERM) {
|
|
73
|
+
// return 'cli';
|
|
74
|
+
// }
|
|
75
|
+
|
|
76
|
+
// return 'unknown';
|
|
77
|
+
// } catch (error) {
|
|
78
|
+
// return 'unknown';
|
|
79
|
+
// }
|
|
80
|
+
// }
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if a waiver applies to the given gate
|
|
84
|
+
* @param {string} gate - Gate name to check
|
|
85
|
+
* @returns {Object} Waiver check result
|
|
86
|
+
*/
|
|
87
|
+
// function checkWaiver(gate) {
|
|
88
|
+
// try {
|
|
89
|
+
// const waiversPath = path.join(process.cwd(), '.caws/waivers.yml');
|
|
90
|
+
// if (!fs.existsSync(waiversPath)) {
|
|
91
|
+
// return { waived: false, reason: 'No waivers file found' };
|
|
92
|
+
// }
|
|
93
|
+
|
|
94
|
+
// const waiversConfig = yaml.load(fs.readFileSync(waiversPath, 'utf8'));
|
|
95
|
+
// const now = new Date();
|
|
96
|
+
|
|
97
|
+
// // Find active waivers for this gate
|
|
98
|
+
// const activeWaivers =
|
|
99
|
+
// waiversConfig.waivers?.filter((waiver) => {
|
|
100
|
+
// const expiresAt = new Date(waiver.expires_at);
|
|
101
|
+
// return waiver.gates.includes(gate) && expiresAt > now && waiver.status === 'active';
|
|
102
|
+
// }) || [];
|
|
103
|
+
|
|
104
|
+
// if (activeWaivers.length > 0) {
|
|
105
|
+
// const waiver = activeWaivers[0]; // Use first active waiver
|
|
106
|
+
// return {
|
|
107
|
+
// waived: true,
|
|
108
|
+
// waiver,
|
|
109
|
+
// reason: `Active waiver: ${waiver.title} (expires: ${waiver.expires_at})`,
|
|
110
|
+
// };
|
|
111
|
+
// }
|
|
112
|
+
|
|
113
|
+
// return { waived: false, reason: 'No active waivers found' };
|
|
114
|
+
// } catch (error) {
|
|
115
|
+
// return { waived: false, reason: `Waiver check failed: ${error.message}` };
|
|
116
|
+
// }
|
|
117
|
+
// }
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Detect if project is in crisis response mode
|
|
121
|
+
* @returns {boolean} True if in crisis mode
|
|
122
|
+
*/
|
|
123
|
+
// function detectCrisisMode() {
|
|
124
|
+
// try {
|
|
125
|
+
// // Check for crisis indicators
|
|
126
|
+
// const crisisIndicators = [
|
|
127
|
+
// // Check for crisis response in working spec
|
|
128
|
+
// () => {
|
|
129
|
+
// const specPath = path.join(process.cwd(), '.caws/working-spec.yaml');
|
|
130
|
+
// if (fs.existsSync(specPath)) {
|
|
131
|
+
// const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
132
|
+
// return spec.mode === 'crisis' || spec.crisis_mode === true;
|
|
133
|
+
// }
|
|
134
|
+
// return false;
|
|
135
|
+
// },
|
|
136
|
+
// // Check for crisis response in environment
|
|
137
|
+
// () => process.env.CAWS_CRISIS_MODE === 'true',
|
|
138
|
+
// // Check for crisis response in git commit message
|
|
139
|
+
// () => {
|
|
140
|
+
// try {
|
|
141
|
+
// const lastCommit = execSync('git log -1 --pretty=%B', { encoding: 'utf8' });
|
|
142
|
+
// return (
|
|
143
|
+
// lastCommit.toLowerCase().includes('crisis') ||
|
|
144
|
+
// lastCommit.toLowerCase().includes('emergency')
|
|
145
|
+
// );
|
|
146
|
+
// } catch {
|
|
147
|
+
// return false;
|
|
148
|
+
// }
|
|
149
|
+
// },
|
|
150
|
+
// ];
|
|
151
|
+
|
|
152
|
+
// return crisisIndicators.some((indicator) => indicator());
|
|
153
|
+
// } catch (error) {
|
|
154
|
+
// return false;
|
|
155
|
+
// }
|
|
156
|
+
// }
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get staged files from git
|
|
160
|
+
* @returns {string[]} Array of staged file paths
|
|
161
|
+
*/
|
|
162
|
+
// function getStagedFiles() {
|
|
163
|
+
// try {
|
|
164
|
+
// const stagedFiles = execSync('git diff --cached --name-only', { encoding: 'utf8' })
|
|
165
|
+
// .trim()
|
|
166
|
+
// .split('\n')
|
|
167
|
+
// .filter((file) => file.trim() !== '');
|
|
168
|
+
|
|
169
|
+
// return stagedFiles;
|
|
170
|
+
// } catch (error) {
|
|
171
|
+
// console.warn(chalk.yellow(`⚠️ Could not get staged files: ${error.message}`));
|
|
172
|
+
// return [];
|
|
173
|
+
// }
|
|
174
|
+
// }
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Check for god objects in staged Rust files with waiver and crisis mode support
|
|
178
|
+
* @param {string[]} stagedFiles - Array of staged file paths
|
|
179
|
+
* @param {boolean} crisisMode - Whether in crisis response mode
|
|
180
|
+
* @returns {Object} God object analysis results
|
|
181
|
+
*/
|
|
182
|
+
// function checkGodObjects(stagedFiles, crisisMode = false) {
|
|
183
|
+
// const rustFiles = stagedFiles.filter((file) => file.endsWith('.rs'));
|
|
184
|
+
|
|
185
|
+
// if (rustFiles.length === 0) {
|
|
186
|
+
// return { violations: [], warnings: [], total: 0, errors: [] };
|
|
187
|
+
// }
|
|
188
|
+
|
|
189
|
+
// console.log(chalk.blue(`📁 Found ${rustFiles.length} staged Rust files to check`));
|
|
190
|
+
|
|
191
|
+
// // Check for god object waiver
|
|
192
|
+
// const waiverCheck = checkWaiver('god_objects');
|
|
193
|
+
// if (waiverCheck.waived) {
|
|
194
|
+
// console.log(chalk.yellow(`⚠️ God object check waived: ${waiverCheck.reason}`));
|
|
195
|
+
// return { violations: [], warnings: [], total: 0, waived: true, errors: [] };
|
|
196
|
+
// }
|
|
197
|
+
|
|
198
|
+
// const violations = [];
|
|
199
|
+
// const warnings = [];
|
|
200
|
+
// const errors = [];
|
|
201
|
+
|
|
202
|
+
// // Use crisis mode thresholds if in crisis
|
|
203
|
+
// const thresholds = crisisMode
|
|
204
|
+
// ? {
|
|
205
|
+
// warning: QUALITY_CONFIG.godObjectThresholds.warning,
|
|
206
|
+
// critical: QUALITY_CONFIG.crisisResponseThresholds.godObjectCritical,
|
|
207
|
+
// }
|
|
208
|
+
// : QUALITY_CONFIG.godObjectThresholds;
|
|
209
|
+
|
|
210
|
+
// for (const file of rustFiles) {
|
|
211
|
+
// try {
|
|
212
|
+
// const fullPath = path.resolve(file);
|
|
213
|
+
// if (!fs.existsSync(fullPath)) continue;
|
|
214
|
+
|
|
215
|
+
// const content = fs.readFileSync(fullPath, 'utf8');
|
|
216
|
+
// const lineCount = content.split('\n').length;
|
|
217
|
+
// const fileSizeKB = fs.statSync(fullPath).size / 1024;
|
|
218
|
+
|
|
219
|
+
// if (lineCount >= thresholds.critical) {
|
|
220
|
+
// const error = createGodObjectError(file, lineCount, thresholds.critical, {
|
|
221
|
+
// fileSizeKB,
|
|
222
|
+
// relativePath: file,
|
|
223
|
+
// crisisMode,
|
|
224
|
+
// });
|
|
225
|
+
|
|
226
|
+
// violations.push({
|
|
227
|
+
// file,
|
|
228
|
+
// lines: lineCount,
|
|
229
|
+
// severity: 'critical',
|
|
230
|
+
// message: `CRITICAL: ${lineCount} LOC exceeds god object threshold (${thresholds.critical}+ LOC)${crisisMode ? ' [CRISIS MODE]' : ''}`,
|
|
231
|
+
// error: error.toJSON(),
|
|
232
|
+
// });
|
|
233
|
+
|
|
234
|
+
// errors.push(error);
|
|
235
|
+
// } else if (lineCount >= thresholds.warning) {
|
|
236
|
+
// const error = createGodObjectError(file, lineCount, thresholds.warning, {
|
|
237
|
+
// fileSizeKB,
|
|
238
|
+
// relativePath: file,
|
|
239
|
+
// crisisMode,
|
|
240
|
+
// });
|
|
241
|
+
|
|
242
|
+
// warnings.push({
|
|
243
|
+
// file,
|
|
244
|
+
// lines: lineCount,
|
|
245
|
+
// severity: 'warning',
|
|
246
|
+
// message: `WARNING: ${lineCount} LOC approaches god object territory (${thresholds.warning}+ LOC)${crisisMode ? ' [CRISIS MODE]' : ''}`,
|
|
247
|
+
// error: error.toJSON(),
|
|
248
|
+
// });
|
|
249
|
+
|
|
250
|
+
// errors.push(error);
|
|
251
|
+
// }
|
|
252
|
+
// } catch (error) {
|
|
253
|
+
// const fsError = createFileSystemError('read_file', file, error, {
|
|
254
|
+
// operation: 'check_god_objects',
|
|
255
|
+
// });
|
|
256
|
+
// errors.push(fsError);
|
|
257
|
+
// console.warn(chalk.yellow(`⚠️ Could not analyze ${file}: ${error.message}`));
|
|
258
|
+
// }
|
|
259
|
+
// }
|
|
260
|
+
|
|
261
|
+
// return { violations, warnings, total: violations.length + warnings.length, errors };
|
|
262
|
+
// }
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Check for hidden TODOs in staged files with waiver and crisis mode support
|
|
266
|
+
* @param {string[]} stagedFiles - Array of staged file paths
|
|
267
|
+
* @param {boolean} crisisMode - Whether in crisis response mode
|
|
268
|
+
* @returns {Object} TODO analysis results
|
|
269
|
+
*/
|
|
270
|
+
// function checkHiddenTodos(stagedFiles, crisisMode = false) {
|
|
271
|
+
// const supportedFiles = stagedFiles.filter((file) => /\.(rs|ts|tsx|js|jsx|py)$/.test(file));
|
|
272
|
+
|
|
273
|
+
// if (supportedFiles.length === 0) {
|
|
274
|
+
// return { todos: [], blocking: 0, total: 0, errors: [] };
|
|
275
|
+
// }
|
|
276
|
+
|
|
277
|
+
// console.log(chalk.blue(`📁 Found ${supportedFiles.length} staged files to analyze for TODOs`));
|
|
278
|
+
|
|
279
|
+
// // Check for TODO waiver
|
|
280
|
+
// const waiverCheck = checkWaiver('hidden_todos');
|
|
281
|
+
// if (waiverCheck.waived) {
|
|
282
|
+
// console.log(chalk.yellow(`⚠️ Hidden TODO check waived: ${waiverCheck.reason}`));
|
|
283
|
+
// return { todos: [], blocking: 0, total: 0, waived: true, errors: [] };
|
|
284
|
+
// }
|
|
285
|
+
|
|
286
|
+
// try {
|
|
287
|
+
// // Use crisis mode confidence threshold if in crisis
|
|
288
|
+
// const confidenceThreshold = crisisMode
|
|
289
|
+
// ? QUALITY_CONFIG.crisisResponseThresholds.todoConfidenceThreshold
|
|
290
|
+
// : QUALITY_CONFIG.todoConfidenceThreshold;
|
|
291
|
+
|
|
292
|
+
// // Run the TODO analyzer with staged files
|
|
293
|
+
// const result = execSync(
|
|
294
|
+
// `python3 scripts/v3/analysis/todo_analyzer.py --staged-only --min-confidence ${confidenceThreshold}`,
|
|
295
|
+
// { encoding: 'utf8', cwd: process.cwd() }
|
|
296
|
+
// );
|
|
297
|
+
|
|
298
|
+
// // Parse the output to extract TODO count
|
|
299
|
+
// const lines = result.split('\n');
|
|
300
|
+
// const summaryLine = lines.find((line) => line.includes('Total hidden TODOs:'));
|
|
301
|
+
// const todoCount = summaryLine ? parseInt(summaryLine.split(':')[1].trim()) : 0;
|
|
302
|
+
|
|
303
|
+
// const errors = [];
|
|
304
|
+
// if (todoCount > 0) {
|
|
305
|
+
// // Create error for each file with TODOs (simplified for now)
|
|
306
|
+
// const error = createHiddenTodoError('staged_files', todoCount, confidenceThreshold, {
|
|
307
|
+
// crisisMode,
|
|
308
|
+
// analyzerOutput: result,
|
|
309
|
+
// confidenceThreshold,
|
|
310
|
+
// });
|
|
311
|
+
// errors.push(error);
|
|
312
|
+
// }
|
|
313
|
+
|
|
314
|
+
// return {
|
|
315
|
+
// todos: [],
|
|
316
|
+
// blocking: todoCount,
|
|
317
|
+
// total: todoCount,
|
|
318
|
+
// details: result,
|
|
319
|
+
// crisisMode,
|
|
320
|
+
// errors,
|
|
321
|
+
// };
|
|
322
|
+
// } catch (error) {
|
|
323
|
+
// const execError = createExecutionError(
|
|
324
|
+
// 'python3 scripts/v3/analysis/todo_analyzer.py',
|
|
325
|
+
// error.status || 1,
|
|
326
|
+
// error.stderr || error.message,
|
|
327
|
+
// {
|
|
328
|
+
// stdout: error.stdout,
|
|
329
|
+
// workingDirectory: process.cwd(),
|
|
330
|
+
// }
|
|
331
|
+
// );
|
|
332
|
+
|
|
333
|
+
// console.warn(chalk.yellow(`⚠️ Could not run TODO analysis: ${error.message}`));
|
|
334
|
+
// return { todos: [], blocking: 0, total: 0, errors: [execError] };
|
|
335
|
+
// }
|
|
336
|
+
// }
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Check for human override in working spec
|
|
340
|
+
* @returns {Object} Human override check result
|
|
341
|
+
*/
|
|
342
|
+
// function checkHumanOverride() {
|
|
343
|
+
// try {
|
|
344
|
+
// const specPath = path.join(process.cwd(), '.caws/working-spec.yaml');
|
|
345
|
+
// if (!fs.existsSync(specPath)) {
|
|
346
|
+
// return { override: false, reason: 'No working spec found' };
|
|
347
|
+
// }
|
|
348
|
+
|
|
349
|
+
// const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
350
|
+
// const humanOverride = spec.human_override;
|
|
351
|
+
|
|
352
|
+
// if (humanOverride && humanOverride.active) {
|
|
353
|
+
// return {
|
|
354
|
+
// override: true,
|
|
355
|
+
// reason: humanOverride.reason || 'Human override active',
|
|
356
|
+
// timestamp: humanOverride.timestamp,
|
|
357
|
+
// approver: humanOverride.approver,
|
|
358
|
+
// };
|
|
359
|
+
// }
|
|
360
|
+
|
|
361
|
+
// return { override: false, reason: 'No human override found' };
|
|
362
|
+
// } catch (error) {
|
|
363
|
+
// return { override: false, reason: `Override check failed: ${error.message}` };
|
|
364
|
+
// }
|
|
365
|
+
// }
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get CAWS tier from working spec
|
|
369
|
+
* @returns {number|null} CAWS tier (1, 2, or 3) or null if not found
|
|
370
|
+
*/
|
|
371
|
+
// function getCawsTier() {
|
|
372
|
+
// try {
|
|
373
|
+
// const specPath = path.join(process.cwd(), '.caws/working-spec.yaml');
|
|
374
|
+
// if (!fs.existsSync(specPath)) return null;
|
|
375
|
+
|
|
376
|
+
// const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
377
|
+
// return spec.risk_tier || null;
|
|
378
|
+
// } catch (error) {
|
|
379
|
+
// return null;
|
|
380
|
+
// }
|
|
381
|
+
// }
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Run comprehensive quality gates on staged files
|
|
385
|
+
* @param {Object} options - Command options
|
|
386
|
+
*/
|
|
387
|
+
async function qualityGatesCommand(options = {}) {
|
|
388
|
+
try {
|
|
389
|
+
console.log(chalk.bold('\n🚦 CAWS Quality Gates - Enterprise Code Quality Enforcement'));
|
|
390
|
+
console.log('='.repeat(70));
|
|
391
|
+
|
|
392
|
+
// Find the quality gates runner script
|
|
393
|
+
const cliSrcDir = path.dirname(__filename); // packages/caws-cli/src/commands -> packages/caws-cli/src/commands
|
|
394
|
+
const cliSrcRoot = path.dirname(cliSrcDir); // packages/caws-cli/src/commands -> packages/caws-cli/src
|
|
395
|
+
const cliPackageDir = path.dirname(cliSrcRoot); // packages/caws-cli/src -> packages/caws-cli
|
|
396
|
+
const packagesDir = path.dirname(cliPackageDir); // packages/caws-cli -> packages
|
|
397
|
+
const qualityGatesRunner = path.join(packagesDir, 'quality-gates', 'run-quality-gates.mjs');
|
|
398
|
+
|
|
399
|
+
// Check if the runner exists
|
|
400
|
+
if (!fs.existsSync(qualityGatesRunner)) {
|
|
401
|
+
console.error(chalk.red('❌ Quality gates runner not found at:'));
|
|
402
|
+
console.error(chalk.gray(` ${qualityGatesRunner}`));
|
|
403
|
+
console.error(chalk.yellow('💡 Run from project root or ensure quality gates are installed'));
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Build command arguments
|
|
408
|
+
const args = ['node', qualityGatesRunner];
|
|
409
|
+
|
|
410
|
+
// Map CLI options to runner options
|
|
411
|
+
if (options.ci) {
|
|
412
|
+
args.push('--ci');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (options.json) {
|
|
416
|
+
args.push('--json');
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (options.gates && options.gates.trim()) {
|
|
420
|
+
args.push('--gates', options.gates.trim());
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (options.fix) {
|
|
424
|
+
args.push('--fix');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Add CAWS-specific environment variables for integration
|
|
428
|
+
const env = {
|
|
429
|
+
...process.env,
|
|
430
|
+
CAWS_CLI_INTEGRATION: 'true',
|
|
431
|
+
CAWS_CLI_VERSION: require(path.join(cliPackageDir, 'package.json')).version,
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// Set GitHub Actions summary if available
|
|
435
|
+
if (process.env.GITHUB_STEP_SUMMARY) {
|
|
436
|
+
env.GITHUB_STEP_SUMMARY = process.env.GITHUB_STEP_SUMMARY;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
console.log(chalk.blue('📁 Executing quality gates runner...'));
|
|
440
|
+
console.log(chalk.gray(` Command: ${args.join(' ')}`));
|
|
441
|
+
|
|
442
|
+
// Execute the quality gates runner
|
|
443
|
+
const child = spawn(args[0], args.slice(1), {
|
|
444
|
+
stdio: 'inherit',
|
|
445
|
+
cwd: packagesDir,
|
|
446
|
+
env: env,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Wait for completion
|
|
450
|
+
return new Promise((resolve, reject) => {
|
|
451
|
+
child.on('close', (code) => {
|
|
452
|
+
if (code === 0) {
|
|
453
|
+
console.log(chalk.green('\n✅ Quality gates completed successfully'));
|
|
454
|
+
resolve();
|
|
455
|
+
} else {
|
|
456
|
+
console.log(chalk.red(`\n❌ Quality gates failed with exit code: ${code}`));
|
|
457
|
+
if (options.ci) {
|
|
458
|
+
process.exit(code);
|
|
459
|
+
}
|
|
460
|
+
reject(new Error(`Quality gates failed with exit code: ${code}`));
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
child.on('error', (error) => {
|
|
465
|
+
console.error(chalk.red('❌ Failed to execute quality gates runner:'), error.message);
|
|
466
|
+
reject(error);
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
} catch (error) {
|
|
470
|
+
console.error(chalk.red('❌ CAWS Quality Gates command failed:'), error.message);
|
|
471
|
+
console.error(chalk.gray('Stack trace:'), error.stack);
|
|
472
|
+
|
|
473
|
+
// Provide helpful troubleshooting
|
|
474
|
+
console.log(chalk.yellow('\n🔧 Troubleshooting:'));
|
|
475
|
+
console.log(chalk.gray(" • Ensure you're running from the project root"));
|
|
476
|
+
console.log(
|
|
477
|
+
chalk.gray(' • Check that quality gates are installed: ls packages/quality-gates/')
|
|
478
|
+
);
|
|
479
|
+
console.log(chalk.gray(' • Verify Node.js version: node --version'));
|
|
480
|
+
console.log(
|
|
481
|
+
chalk.gray(' • Try direct execution: node packages/quality-gates/run-quality-gates.mjs')
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
throw error;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
module.exports = {
|
|
489
|
+
qualityGatesCommand,
|
|
490
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specs command handler
|
|
3
|
+
* @param {string} action - Action to perform (list, create, show, update, delete, conflicts, migrate)
|
|
4
|
+
* @param {Object} options - Command options
|
|
5
|
+
*/
|
|
6
|
+
export function specsCommand(action: string, options?: any): Promise<any>;
|
|
7
|
+
/**
|
|
8
|
+
* Load specs registry
|
|
9
|
+
* @returns {Promise<Object>} Registry data
|
|
10
|
+
*/
|
|
11
|
+
export function loadSpecsRegistry(): Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* Save specs registry
|
|
14
|
+
* @param {Object} registry - Registry data
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
export function saveSpecsRegistry(registry: any): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* List all spec files in the specs directory
|
|
20
|
+
* @returns {Promise<Array>} Array of spec file info
|
|
21
|
+
*/
|
|
22
|
+
export function listSpecFiles(): Promise<any[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Create a new spec file
|
|
25
|
+
* @param {string} id - Spec identifier
|
|
26
|
+
* @param {Object} options - Creation options
|
|
27
|
+
* @returns {Promise<Object>} Created spec info
|
|
28
|
+
*/
|
|
29
|
+
export function createSpec(id: string, options?: any): Promise<any>;
|
|
30
|
+
/**
|
|
31
|
+
* Load a specific spec file
|
|
32
|
+
* @param {string} id - Spec identifier
|
|
33
|
+
* @returns {Promise<Object|null>} Spec data or null
|
|
34
|
+
*/
|
|
35
|
+
export function loadSpec(id: string): Promise<any | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Update a spec file
|
|
38
|
+
* @param {string} id - Spec identifier
|
|
39
|
+
* @param {Object} updates - Updates to apply
|
|
40
|
+
* @returns {Promise<boolean>} Success status
|
|
41
|
+
*/
|
|
42
|
+
export function updateSpec(id: string, updates?: any): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Delete a spec file
|
|
45
|
+
* @param {string} id - Spec identifier
|
|
46
|
+
* @returns {Promise<boolean>} Success status
|
|
47
|
+
*/
|
|
48
|
+
export function deleteSpec(id: string): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Display specs in a formatted table
|
|
51
|
+
* @param {Array} specs - Array of spec objects
|
|
52
|
+
*/
|
|
53
|
+
export function displaySpecsTable(specs: any[]): void;
|
|
54
|
+
/**
|
|
55
|
+
* Display detailed spec information
|
|
56
|
+
* @param {Object} spec - Spec object
|
|
57
|
+
*/
|
|
58
|
+
export function displaySpecDetails(spec: any): void;
|
|
59
|
+
/**
|
|
60
|
+
* Ask user how to resolve spec creation conflicts
|
|
61
|
+
* @returns {Promise<string>} User's choice: 'cancel', 'rename', 'merge', 'override'
|
|
62
|
+
*/
|
|
63
|
+
export function askConflictResolution(): Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* Specs directory structure
|
|
66
|
+
*/
|
|
67
|
+
export const SPECS_DIR: ".caws/specs";
|
|
68
|
+
export const SPECS_REGISTRY: ".caws/specs/registry.json";
|
|
69
|
+
import { SPEC_TYPES } from "../constants/spec-types";
|
|
70
|
+
export { SPEC_TYPES };
|
|
71
|
+
//# sourceMappingURL=specs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../src/commands/specs.js"],"names":[],"mappings":"AAghBA;;;;GAIG;AACH,qCAHW,MAAM,+BA2LhB;AAvrBD;;;GAGG;AACH,qCAFa,OAAO,KAAQ,CAqB3B;AAED;;;;GAIG;AACH,kDAFa,OAAO,CAAC,IAAI,CAAC,CAMzB;AAED;;;GAGG;AACH,iCAFa,OAAO,OAAO,CAmC1B;AAED;;;;;GAKG;AACH,+BAJW,MAAM,kBAEJ,OAAO,KAAQ,CA8H3B;AAED;;;;GAIG;AACH,6BAHW,MAAM,GACJ,OAAO,CAAC,MAAO,IAAI,CAAC,CAiBhC;AAED;;;;;GAKG;AACH,+BAJW,MAAM,kBAEJ,OAAO,CAAC,OAAO,CAAC,CA6B5B;AAED;;;;GAIG;AACH,+BAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAmB5B;AAED;;;GAGG;AACH,sDA2CC;AAED;;;GAGG;AACH,oDAoCC;AAsFD;;;GAGG;AACH,yCAFa,OAAO,CAAC,MAAM,CAAC,CAuC3B;AA9fD;;GAEG;AACH,wBAAkB,aAAa,CAAC;AAChC,6BAAuB,2BAA2B,CAAC"}
|