@paths.design/caws-cli 3.3.1 → 3.4.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/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +39 -4
- package/dist/commands/evaluate.d.ts +8 -0
- package/dist/commands/evaluate.d.ts.map +1 -0
- package/dist/commands/evaluate.js +288 -0
- package/dist/commands/iterate.d.ts +8 -0
- package/dist/commands/iterate.d.ts.map +1 -0
- package/dist/commands/iterate.js +341 -0
- package/dist/commands/quality-monitor.d.ts +17 -0
- package/dist/commands/quality-monitor.d.ts.map +1 -0
- package/dist/commands/quality-monitor.js +265 -0
- package/dist/commands/status.d.ts +6 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +120 -20
- package/dist/commands/troubleshoot.d.ts +8 -0
- package/dist/commands/troubleshoot.d.ts.map +1 -0
- package/dist/commands/troubleshoot.js +104 -0
- package/dist/commands/waivers.d.ts +8 -0
- package/dist/commands/waivers.d.ts.map +1 -0
- package/dist/commands/waivers.js +293 -0
- package/dist/commands/workflow.d.ts +85 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +243 -0
- package/dist/error-handler.d.ts +91 -2
- package/dist/error-handler.d.ts.map +1 -1
- package/dist/error-handler.js +362 -16
- package/dist/index.js +95 -0
- package/dist/utils/typescript-detector.d.ts +31 -0
- package/dist/utils/typescript-detector.d.ts.map +1 -1
- package/dist/utils/typescript-detector.js +245 -7
- package/package.json +2 -1
- package/templates/apps/tools/caws/gates.ts +34 -0
- package/templates/apps/tools/caws/shared/gate-checker.ts +265 -13
- package/templates/apps/tools/caws/templates/working-spec.template.yml +14 -0
- package/dist/index-new.d.ts +0 -5
- package/dist/index-new.d.ts.map +0 -1
- package/dist/index-new.js +0 -317
- package/dist/index.js.backup +0 -4711
- package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
- package/templates/apps/tools/caws/provenance.js.backup +0 -73
package/dist/commands/status.js
CHANGED
|
@@ -8,6 +8,7 @@ const fs = require('fs-extra');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const yaml = require('js-yaml');
|
|
10
10
|
const chalk = require('chalk');
|
|
11
|
+
const { safeAsync, outputResult } = require('../error-handler');
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Load working specification
|
|
@@ -98,6 +99,68 @@ async function loadProvenanceChain() {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Load waiver status
|
|
104
|
+
* @returns {Promise<Object>} Waiver status
|
|
105
|
+
*/
|
|
106
|
+
async function loadWaiverStatus() {
|
|
107
|
+
const waiversDir = '.caws/waivers';
|
|
108
|
+
|
|
109
|
+
if (!(await fs.pathExists(waiversDir))) {
|
|
110
|
+
return {
|
|
111
|
+
exists: false,
|
|
112
|
+
active: 0,
|
|
113
|
+
expired: 0,
|
|
114
|
+
revoked: 0,
|
|
115
|
+
total: 0,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const waiverFiles = await fs.readdir(waiversDir);
|
|
121
|
+
const yamlFiles = waiverFiles.filter((f) => f.endsWith('.yaml'));
|
|
122
|
+
|
|
123
|
+
let active = 0;
|
|
124
|
+
let expired = 0;
|
|
125
|
+
let revoked = 0;
|
|
126
|
+
|
|
127
|
+
for (const file of yamlFiles) {
|
|
128
|
+
const waiverPath = path.join(waiversDir, file);
|
|
129
|
+
const content = await fs.readFile(waiverPath, 'utf8');
|
|
130
|
+
const waiver = yaml.load(content);
|
|
131
|
+
|
|
132
|
+
if (waiver.status === 'revoked') {
|
|
133
|
+
revoked++;
|
|
134
|
+
} else if (waiver.status === 'active') {
|
|
135
|
+
const now = new Date();
|
|
136
|
+
const expiresAt = new Date(waiver.expires_at);
|
|
137
|
+
if (now > expiresAt) {
|
|
138
|
+
expired++;
|
|
139
|
+
} else {
|
|
140
|
+
active++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
exists: true,
|
|
147
|
+
active,
|
|
148
|
+
expired,
|
|
149
|
+
revoked,
|
|
150
|
+
total: active + expired + revoked,
|
|
151
|
+
};
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return {
|
|
154
|
+
exists: false,
|
|
155
|
+
active: 0,
|
|
156
|
+
expired: 0,
|
|
157
|
+
revoked: 0,
|
|
158
|
+
total: 0,
|
|
159
|
+
error: error.message,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
101
164
|
/**
|
|
102
165
|
* Check quality gates status (simplified)
|
|
103
166
|
* @returns {Promise<Object>} Quality gates status
|
|
@@ -138,7 +201,7 @@ function getTimeSince(timestamp) {
|
|
|
138
201
|
* @param {Object} data - Status data
|
|
139
202
|
*/
|
|
140
203
|
function displayStatus(data) {
|
|
141
|
-
const { spec, hooks, provenance, gates } = data;
|
|
204
|
+
const { spec, hooks, provenance, waivers, gates } = data;
|
|
142
205
|
|
|
143
206
|
console.log(chalk.bold.cyan('\n📊 CAWS Project Status'));
|
|
144
207
|
console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
@@ -183,6 +246,26 @@ function displayStatus(data) {
|
|
|
183
246
|
|
|
184
247
|
console.log('');
|
|
185
248
|
|
|
249
|
+
// Waivers Status
|
|
250
|
+
if (waivers.exists && waivers.total > 0) {
|
|
251
|
+
console.log(chalk.green('✅ Quality Gate Waivers'));
|
|
252
|
+
console.log(
|
|
253
|
+
chalk.gray(
|
|
254
|
+
` ${waivers.active} active, ${waivers.expired} expired, ${waivers.revoked} revoked`
|
|
255
|
+
)
|
|
256
|
+
);
|
|
257
|
+
console.log(chalk.gray(` Total: ${waivers.total} waiver${waivers.total > 1 ? 's' : ''}`));
|
|
258
|
+
} else if (waivers.exists) {
|
|
259
|
+
console.log(chalk.blue('ℹ️ Quality Gate Waivers'));
|
|
260
|
+
console.log(chalk.gray(' No waivers configured'));
|
|
261
|
+
} else {
|
|
262
|
+
console.log(chalk.yellow('⚠️ Quality Gate Waivers'));
|
|
263
|
+
console.log(chalk.gray(' Waiver system not initialized'));
|
|
264
|
+
console.log(chalk.yellow(' 💡 Run: caws waivers create (when needed)'));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log('');
|
|
268
|
+
|
|
186
269
|
// Quality Gates Status
|
|
187
270
|
console.log(chalk.blue('ℹ️ Quality Gates'));
|
|
188
271
|
console.log(chalk.gray(` ${gates.message}`));
|
|
@@ -207,6 +290,9 @@ function displayStatus(data) {
|
|
|
207
290
|
if (provenance.exists) {
|
|
208
291
|
console.log(chalk.blue(' View provenance: caws provenance show --format=dashboard'));
|
|
209
292
|
}
|
|
293
|
+
if (waivers.exists && waivers.total > 0) {
|
|
294
|
+
console.log(chalk.blue(' View waivers: caws waivers list'));
|
|
295
|
+
}
|
|
210
296
|
console.log(chalk.blue(' Full documentation: docs/agents/full-guide.md'));
|
|
211
297
|
|
|
212
298
|
console.log('');
|
|
@@ -244,25 +330,38 @@ function generateSuggestions(data) {
|
|
|
244
330
|
* @param {Object} options - Command options
|
|
245
331
|
*/
|
|
246
332
|
async function statusCommand(options = {}) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
333
|
+
return safeAsync(
|
|
334
|
+
async () => {
|
|
335
|
+
// Load all status data
|
|
336
|
+
const spec = await loadWorkingSpec(options.spec || '.caws/working-spec.yaml');
|
|
337
|
+
const hooks = await checkGitHooks();
|
|
338
|
+
const provenance = await loadProvenanceChain();
|
|
339
|
+
const waivers = await loadWaiverStatus();
|
|
340
|
+
const gates = await checkQualityGates();
|
|
341
|
+
|
|
342
|
+
// Display status
|
|
343
|
+
displayStatus({
|
|
344
|
+
spec,
|
|
345
|
+
hooks,
|
|
346
|
+
provenance,
|
|
347
|
+
waivers,
|
|
348
|
+
gates,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const result = outputResult({
|
|
352
|
+
command: 'status',
|
|
353
|
+
spec: spec ? 'loaded' : 'not found',
|
|
354
|
+
hooks: hooks.installed,
|
|
355
|
+
provenance: provenance.entries?.length || 0,
|
|
356
|
+
waivers: waivers.active?.length || 0,
|
|
357
|
+
gates: gates.passed ? 'passed' : 'failed',
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
return result;
|
|
361
|
+
},
|
|
362
|
+
'status check',
|
|
363
|
+
true
|
|
364
|
+
);
|
|
266
365
|
}
|
|
267
366
|
|
|
268
367
|
module.exports = {
|
|
@@ -270,6 +369,7 @@ module.exports = {
|
|
|
270
369
|
loadWorkingSpec,
|
|
271
370
|
checkGitHooks,
|
|
272
371
|
loadProvenanceChain,
|
|
372
|
+
loadWaiverStatus,
|
|
273
373
|
checkQualityGates,
|
|
274
374
|
displayStatus,
|
|
275
375
|
generateSuggestions,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export = troubleshootCommand;
|
|
2
|
+
/**
|
|
3
|
+
* Troubleshoot command handler
|
|
4
|
+
* @param {string} guide - Guide key argument
|
|
5
|
+
* @param {Object} options - Command options
|
|
6
|
+
*/
|
|
7
|
+
declare function troubleshootCommand(guide: string, options: any): void;
|
|
8
|
+
//# sourceMappingURL=troubleshoot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"troubleshoot.d.ts","sourceRoot":"","sources":["../../src/commands/troubleshoot.js"],"names":[],"mappings":";AAqFA;;;;GAIG;AACH,4CAHW,MAAM,sBAchB"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CAWS CLI Troubleshoot Command
|
|
3
|
+
* Provides detailed troubleshooting guides for common CAWS issues
|
|
4
|
+
* @author @darianrosebrook
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const { getTroubleshootingGuide, getAllTroubleshootingGuides } = require('../error-handler');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Display a specific troubleshooting guide
|
|
12
|
+
* @param {string} guideKey - Key for the troubleshooting guide
|
|
13
|
+
*/
|
|
14
|
+
function displayGuide(guideKey) {
|
|
15
|
+
const guide = getTroubleshootingGuide(guideKey);
|
|
16
|
+
|
|
17
|
+
if (!guide) {
|
|
18
|
+
console.error(chalk.red(`❌ Troubleshooting guide '${guideKey}' not found.`));
|
|
19
|
+
console.log(chalk.yellow('\nAvailable guides:'));
|
|
20
|
+
const allGuides = getAllTroubleshootingGuides();
|
|
21
|
+
Object.keys(allGuides).forEach((key) => {
|
|
22
|
+
console.log(chalk.yellow(` ${key}: ${allGuides[key].title}`));
|
|
23
|
+
});
|
|
24
|
+
console.log(chalk.yellow('\nTry: caws troubleshoot --list for all available guides'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(chalk.bold.blue(`🔍 ${guide.title}`));
|
|
29
|
+
console.log(chalk.gray('═'.repeat(50)));
|
|
30
|
+
|
|
31
|
+
if (guide.symptoms && guide.symptoms.length > 0) {
|
|
32
|
+
console.log(chalk.yellow('\n📋 Symptoms:'));
|
|
33
|
+
guide.symptoms.forEach((symptom) => {
|
|
34
|
+
console.log(chalk.gray(` • ${symptom}`));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (guide.rootCauses && guide.rootCauses.length > 0) {
|
|
39
|
+
console.log(chalk.red('\n🔍 Possible Root Causes:'));
|
|
40
|
+
guide.rootCauses.forEach((cause) => {
|
|
41
|
+
console.log(chalk.gray(` • ${cause}`));
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (guide.solutions && guide.solutions.length > 0) {
|
|
46
|
+
console.log(chalk.green('\n✅ Solutions:'));
|
|
47
|
+
guide.solutions.forEach((solution, index) => {
|
|
48
|
+
console.log(chalk.gray(` ${index + 1}. ${solution}`));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (guide.commands && guide.commands.length > 0) {
|
|
53
|
+
console.log(chalk.cyan('\n💻 Try These Commands:'));
|
|
54
|
+
guide.commands.forEach((command) => {
|
|
55
|
+
console.log(chalk.gray(` $ ${command}`));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(chalk.gray('\n═'.repeat(50)));
|
|
60
|
+
console.log(chalk.blue('📚 For more help: caws --help or visit the documentation'));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* List all available troubleshooting guides
|
|
65
|
+
*/
|
|
66
|
+
function listGuides() {
|
|
67
|
+
console.log(chalk.bold.blue('🔧 Available Troubleshooting Guides'));
|
|
68
|
+
console.log(chalk.gray('═'.repeat(50)));
|
|
69
|
+
|
|
70
|
+
const allGuides = getAllTroubleshootingGuides();
|
|
71
|
+
Object.entries(allGuides).forEach(([key, guide]) => {
|
|
72
|
+
console.log(chalk.cyan(`${key}:`));
|
|
73
|
+
console.log(chalk.gray(` ${guide.title}`));
|
|
74
|
+
if (guide.symptoms && guide.symptoms.length > 0) {
|
|
75
|
+
console.log(
|
|
76
|
+
chalk.gray(` Symptoms: ${guide.symptoms[0]}${guide.symptoms.length > 1 ? '...' : ''}`)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
console.log('');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
console.log(chalk.yellow('Usage: caws troubleshoot <guide-key>'));
|
|
83
|
+
console.log(chalk.yellow('Example: caws troubleshoot coverage-report-not-found'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Troubleshoot command handler
|
|
88
|
+
* @param {string} guide - Guide key argument
|
|
89
|
+
* @param {Object} options - Command options
|
|
90
|
+
*/
|
|
91
|
+
function troubleshootCommand(guide, options) {
|
|
92
|
+
try {
|
|
93
|
+
if (options.list || !guide) {
|
|
94
|
+
listGuides();
|
|
95
|
+
} else {
|
|
96
|
+
displayGuide(guide);
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(chalk.red(`❌ Error: ${error.message}`));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = troubleshootCommand;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waivers command handler
|
|
3
|
+
*
|
|
4
|
+
* @param {string} subcommand - create, list, show, revoke
|
|
5
|
+
* @param {object} options - Command options
|
|
6
|
+
*/
|
|
7
|
+
export function waiversCommand(subcommand?: string, options?: object): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=waivers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waivers.d.ts","sourceRoot":"","sources":["../../src/commands/waivers.js"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,4CAHW,MAAM,YACN,MAAM,iBA2ChB"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAWS Waivers Command
|
|
3
|
+
*
|
|
4
|
+
* Manage quality gate waivers for exceptional circumstances.
|
|
5
|
+
* Waivers allow temporary exceptions to quality requirements
|
|
6
|
+
* with proper documentation and approval.
|
|
7
|
+
*
|
|
8
|
+
* @author @darianrosebrook
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const yaml = require('js-yaml');
|
|
14
|
+
const chalk = require('chalk');
|
|
15
|
+
const { initializeGlobalSetup } = require('../config');
|
|
16
|
+
|
|
17
|
+
const WAIVER_DIR = '.caws/waivers';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Waivers command handler
|
|
21
|
+
*
|
|
22
|
+
* @param {string} subcommand - create, list, show, revoke
|
|
23
|
+
* @param {object} options - Command options
|
|
24
|
+
*/
|
|
25
|
+
async function waiversCommand(subcommand = 'list', options = {}) {
|
|
26
|
+
try {
|
|
27
|
+
console.log('🔍 Detecting CAWS setup...');
|
|
28
|
+
const setup = initializeGlobalSetup();
|
|
29
|
+
|
|
30
|
+
if (setup.hasWorkingSpec) {
|
|
31
|
+
console.log(`✅ Detected ${setup.setupType} CAWS setup`);
|
|
32
|
+
console.log(` Capabilities: ${setup.capabilities.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Ensure waivers directory exists
|
|
36
|
+
const waiversDir = path.join(process.cwd(), WAIVER_DIR);
|
|
37
|
+
if (!fs.existsSync(waiversDir)) {
|
|
38
|
+
fs.mkdirSync(waiversDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
switch (subcommand) {
|
|
42
|
+
case 'create':
|
|
43
|
+
await createWaiver(options);
|
|
44
|
+
break;
|
|
45
|
+
case 'list':
|
|
46
|
+
await listWaivers(options);
|
|
47
|
+
break;
|
|
48
|
+
case 'show':
|
|
49
|
+
await showWaiver(options.id, options);
|
|
50
|
+
break;
|
|
51
|
+
case 'revoke':
|
|
52
|
+
await revokeWaiver(options.id, options);
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
console.error(chalk.red(`\n❌ Unknown waiver subcommand: ${subcommand}`));
|
|
56
|
+
console.log(chalk.yellow('\n💡 Available subcommands: create, list, show, revoke'));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error(chalk.red(`\n❌ Waiver command failed: ${error.message}`));
|
|
61
|
+
if (options.verbose) {
|
|
62
|
+
console.error(error.stack);
|
|
63
|
+
}
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a new waiver
|
|
70
|
+
*/
|
|
71
|
+
async function createWaiver(options) {
|
|
72
|
+
// Validate required fields
|
|
73
|
+
const required = ['title', 'reason', 'description', 'gates', 'expiresAt', 'approvedBy', 'impactLevel', 'mitigationPlan'];
|
|
74
|
+
const missing = required.filter(field => !options[field]);
|
|
75
|
+
|
|
76
|
+
if (missing.length > 0) {
|
|
77
|
+
console.error(chalk.red(`\n❌ Missing required fields: ${missing.join(', ')}`));
|
|
78
|
+
console.log(chalk.yellow('\n💡 Example:'));
|
|
79
|
+
console.log(' caws waivers create \\');
|
|
80
|
+
console.log(' --title="Emergency hotfix waiver" \\');
|
|
81
|
+
console.log(' --reason=emergency_hotfix \\');
|
|
82
|
+
console.log(' --description="Critical production bug requires immediate fix" \\');
|
|
83
|
+
console.log(' --gates=coverage,mutation \\');
|
|
84
|
+
console.log(' --expires-at=2025-12-31T23:59:59Z \\');
|
|
85
|
+
console.log(' --approved-by="@manager" \\');
|
|
86
|
+
console.log(' --impact-level=high \\');
|
|
87
|
+
console.log(' --mitigation-plan="Will add tests in follow-up PR within 48h"');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Generate waiver ID
|
|
92
|
+
const waiverId = `WV-${Date.now().toString().slice(-4)}`;
|
|
93
|
+
const timestamp = new Date().toISOString();
|
|
94
|
+
|
|
95
|
+
// Parse gates
|
|
96
|
+
const gates = typeof options.gates === 'string'
|
|
97
|
+
? options.gates.split(',').map(g => g.trim())
|
|
98
|
+
: options.gates;
|
|
99
|
+
|
|
100
|
+
// Create waiver object
|
|
101
|
+
const waiver = {
|
|
102
|
+
id: waiverId,
|
|
103
|
+
title: options.title,
|
|
104
|
+
reason: options.reason,
|
|
105
|
+
description: options.description,
|
|
106
|
+
gates: gates,
|
|
107
|
+
created_at: timestamp,
|
|
108
|
+
expires_at: options.expiresAt,
|
|
109
|
+
approved_by: options.approvedBy,
|
|
110
|
+
impact_level: options.impactLevel,
|
|
111
|
+
mitigation_plan: options.mitigationPlan,
|
|
112
|
+
status: 'active',
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Save waiver
|
|
116
|
+
const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
|
|
117
|
+
fs.writeFileSync(waiverPath, yaml.dump(waiver, { lineWidth: -1 }));
|
|
118
|
+
|
|
119
|
+
console.log(chalk.green(`\n✅ Waiver created: ${waiverId}`));
|
|
120
|
+
console.log(` Title: ${waiver.title}`);
|
|
121
|
+
console.log(` Reason: ${waiver.reason}`);
|
|
122
|
+
console.log(` Gates: ${waiver.gates.join(', ')}`);
|
|
123
|
+
console.log(` Expires: ${waiver.expires_at}`);
|
|
124
|
+
console.log(` Approved by: ${waiver.approved_by}`);
|
|
125
|
+
console.log(` Impact: ${waiver.impact_level}`);
|
|
126
|
+
console.log(chalk.yellow(`\n⚠️ Remember: This waiver expires on ${waiver.expires_at}`));
|
|
127
|
+
console.log(chalk.yellow(`⚠️ Mitigation plan: ${waiver.mitigation_plan}\n`));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* List all waivers
|
|
132
|
+
*/
|
|
133
|
+
async function listWaivers(_options) {
|
|
134
|
+
const waiversDir = path.join(process.cwd(), WAIVER_DIR);
|
|
135
|
+
|
|
136
|
+
if (!fs.existsSync(waiversDir)) {
|
|
137
|
+
console.log(chalk.yellow('\nℹ️ No waivers found\n'));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const waiverFiles = fs.readdirSync(waiversDir).filter(f => f.endsWith('.yaml'));
|
|
142
|
+
|
|
143
|
+
if (waiverFiles.length === 0) {
|
|
144
|
+
console.log(chalk.yellow('\nℹ️ No waivers found\n'));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const waivers = waiverFiles.map(file => {
|
|
149
|
+
const content = fs.readFileSync(path.join(waiversDir, file), 'utf8');
|
|
150
|
+
return yaml.load(content);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// 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');
|
|
157
|
+
|
|
158
|
+
console.log(chalk.blue('\n🔖 CAWS Quality Gate Waivers\n'));
|
|
159
|
+
console.log('─'.repeat(60));
|
|
160
|
+
|
|
161
|
+
if (activeWaivers.length > 0) {
|
|
162
|
+
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));
|
|
165
|
+
console.log(`🔖 ${chalk.bold(waiver.id)}: ${waiver.title}`);
|
|
166
|
+
console.log(` Reason: ${waiver.reason}`);
|
|
167
|
+
console.log(` Gates: ${waiver.gates.join(', ')}`);
|
|
168
|
+
console.log(` Expires: ${waiver.expires_at} (${daysLeft} days)`);
|
|
169
|
+
console.log(` Impact: ${waiver.impact_level}`);
|
|
170
|
+
console.log();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (expiredWaivers.length > 0) {
|
|
175
|
+
console.log(chalk.yellow('\n⚠️ Expired Waivers:\n'));
|
|
176
|
+
expiredWaivers.forEach(waiver => {
|
|
177
|
+
console.log(`🔖 ${chalk.bold(waiver.id)}: ${waiver.title}`);
|
|
178
|
+
console.log(` Expired: ${waiver.expires_at}`);
|
|
179
|
+
console.log();
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (revokedWaivers.length > 0) {
|
|
184
|
+
console.log(chalk.red('\n❌ Revoked Waivers:\n'));
|
|
185
|
+
revokedWaivers.forEach(waiver => {
|
|
186
|
+
console.log(`🔖 ${chalk.bold(waiver.id)}: ${waiver.title}`);
|
|
187
|
+
console.log(` Revoked: ${waiver.revoked_at}`);
|
|
188
|
+
console.log();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log(chalk.blue('📊 Summary:\n'));
|
|
193
|
+
console.log(` Active: ${activeWaivers.length}`);
|
|
194
|
+
console.log(` Expired: ${expiredWaivers.length}`);
|
|
195
|
+
console.log(` Revoked: ${revokedWaivers.length}`);
|
|
196
|
+
console.log(` Total: ${waivers.length}\n`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Show waiver details
|
|
201
|
+
*/
|
|
202
|
+
async function showWaiver(waiverId, _options) {
|
|
203
|
+
if (!waiverId) {
|
|
204
|
+
console.error(chalk.red('\n❌ Waiver ID required'));
|
|
205
|
+
console.log(chalk.yellow('💡 Usage: caws waivers show WV-1234\n'));
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
|
|
210
|
+
|
|
211
|
+
if (!fs.existsSync(waiverPath)) {
|
|
212
|
+
console.error(chalk.red(`\n❌ Waiver not found: ${waiverId}\n`));
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const content = fs.readFileSync(waiverPath, 'utf8');
|
|
217
|
+
const waiver = yaml.load(content);
|
|
218
|
+
|
|
219
|
+
const isExpired = new Date(waiver.expires_at) <= new Date();
|
|
220
|
+
const isActive = waiver.status === 'active' && !isExpired;
|
|
221
|
+
const statusIcon = isActive ? '✅' : isExpired ? '⚠️' : '❌';
|
|
222
|
+
|
|
223
|
+
console.log(chalk.blue('\n🔖 Waiver Details\n'));
|
|
224
|
+
console.log('─'.repeat(60));
|
|
225
|
+
console.log(`\n${statusIcon} Status: ${chalk.bold(isActive ? 'Active' : isExpired ? 'Expired' : waiver.status)}`);
|
|
226
|
+
console.log(`\n📋 ${chalk.bold(waiver.title)}`);
|
|
227
|
+
console.log(` ID: ${waiver.id}`);
|
|
228
|
+
console.log(` Reason: ${waiver.reason}`);
|
|
229
|
+
console.log(` Impact Level: ${waiver.impact_level}`);
|
|
230
|
+
console.log(`\n📝 Description:`);
|
|
231
|
+
console.log(` ${waiver.description}`);
|
|
232
|
+
console.log(`\n🔒 Waived Quality Gates:`);
|
|
233
|
+
waiver.gates.forEach(gate => {
|
|
234
|
+
console.log(` • ${gate}`);
|
|
235
|
+
});
|
|
236
|
+
console.log(`\n🛡️ Mitigation Plan:`);
|
|
237
|
+
console.log(` ${waiver.mitigation_plan}`);
|
|
238
|
+
console.log(`\n📅 Timeline:`);
|
|
239
|
+
console.log(` Created: ${waiver.created_at}`);
|
|
240
|
+
console.log(` Expires: ${waiver.expires_at}`);
|
|
241
|
+
if (waiver.revoked_at) {
|
|
242
|
+
console.log(` Revoked: ${waiver.revoked_at}`);
|
|
243
|
+
}
|
|
244
|
+
console.log(`\n✍️ Approved by: ${waiver.approved_by}\n`);
|
|
245
|
+
|
|
246
|
+
if (isExpired && waiver.status === 'active') {
|
|
247
|
+
console.log(chalk.yellow('⚠️ This waiver has expired. Consider revoking it.\n'));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Revoke a waiver
|
|
253
|
+
*/
|
|
254
|
+
async function revokeWaiver(waiverId, options) {
|
|
255
|
+
if (!waiverId) {
|
|
256
|
+
console.error(chalk.red('\n❌ Waiver ID required'));
|
|
257
|
+
console.log(chalk.yellow('💡 Usage: caws waivers revoke WV-1234\n'));
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const waiverPath = path.join(process.cwd(), WAIVER_DIR, `${waiverId}.yaml`);
|
|
262
|
+
|
|
263
|
+
if (!fs.existsSync(waiverPath)) {
|
|
264
|
+
console.error(chalk.red(`\n❌ Waiver not found: ${waiverId}\n`));
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const content = fs.readFileSync(waiverPath, 'utf8');
|
|
269
|
+
const waiver = yaml.load(content);
|
|
270
|
+
|
|
271
|
+
if (waiver.status === 'revoked') {
|
|
272
|
+
console.log(chalk.yellow(`\nℹ️ Waiver ${waiverId} is already revoked\n`));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Update waiver status
|
|
277
|
+
waiver.status = 'revoked';
|
|
278
|
+
waiver.revoked_at = new Date().toISOString();
|
|
279
|
+
waiver.revoked_by = options.revokedBy || 'system';
|
|
280
|
+
waiver.revocation_reason = options.reason || 'Manual revocation';
|
|
281
|
+
|
|
282
|
+
// Save updated waiver
|
|
283
|
+
fs.writeFileSync(waiverPath, yaml.dump(waiver, { lineWidth: -1 }));
|
|
284
|
+
|
|
285
|
+
console.log(chalk.green(`\n✅ Waiver revoked: ${waiverId}`));
|
|
286
|
+
console.log(` Title: ${waiver.title}`);
|
|
287
|
+
console.log(` Revoked at: ${waiver.revoked_at}`);
|
|
288
|
+
console.log(` Revoked by: ${waiver.revoked_by}`);
|
|
289
|
+
console.log(` Reason: ${waiver.revocation_reason}\n`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = { waiversCommand };
|
|
293
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow command handler
|
|
3
|
+
*
|
|
4
|
+
* @param {string} workflowType - Type of workflow
|
|
5
|
+
* @param {object} options - Command options
|
|
6
|
+
*/
|
|
7
|
+
export function workflowCommand(workflowType: string, options?: object): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Generate workflow guidance
|
|
10
|
+
*
|
|
11
|
+
* @param {string} workflowType - Type of workflow (tdd, refactor, feature)
|
|
12
|
+
* @param {number} currentStep - Current step number (1-based)
|
|
13
|
+
* @param {object} context - Optional context information
|
|
14
|
+
* @returns {object} Workflow guidance
|
|
15
|
+
*/
|
|
16
|
+
export function generateWorkflowGuidance(workflowType: string, currentStep: number, context?: object): object;
|
|
17
|
+
export namespace WORKFLOW_TEMPLATES {
|
|
18
|
+
namespace tdd {
|
|
19
|
+
let name: string;
|
|
20
|
+
let steps: string[];
|
|
21
|
+
let guidance: {
|
|
22
|
+
1: string;
|
|
23
|
+
2: string;
|
|
24
|
+
3: string;
|
|
25
|
+
4: string;
|
|
26
|
+
5: string;
|
|
27
|
+
6: string;
|
|
28
|
+
};
|
|
29
|
+
let recommendations: {
|
|
30
|
+
1: string[];
|
|
31
|
+
2: string[];
|
|
32
|
+
3: string[];
|
|
33
|
+
4: string[];
|
|
34
|
+
5: string[];
|
|
35
|
+
6: string[];
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
namespace refactor {
|
|
39
|
+
let name_1: string;
|
|
40
|
+
export { name_1 as name };
|
|
41
|
+
let steps_1: string[];
|
|
42
|
+
export { steps_1 as steps };
|
|
43
|
+
let guidance_1: {
|
|
44
|
+
1: string;
|
|
45
|
+
2: string;
|
|
46
|
+
3: string;
|
|
47
|
+
4: string;
|
|
48
|
+
5: string;
|
|
49
|
+
};
|
|
50
|
+
export { guidance_1 as guidance };
|
|
51
|
+
let recommendations_1: {
|
|
52
|
+
1: string[];
|
|
53
|
+
2: string[];
|
|
54
|
+
3: string[];
|
|
55
|
+
4: string[];
|
|
56
|
+
5: string[];
|
|
57
|
+
};
|
|
58
|
+
export { recommendations_1 as recommendations };
|
|
59
|
+
}
|
|
60
|
+
namespace feature {
|
|
61
|
+
let name_2: string;
|
|
62
|
+
export { name_2 as name };
|
|
63
|
+
let steps_2: string[];
|
|
64
|
+
export { steps_2 as steps };
|
|
65
|
+
let guidance_2: {
|
|
66
|
+
1: string;
|
|
67
|
+
2: string;
|
|
68
|
+
3: string;
|
|
69
|
+
4: string;
|
|
70
|
+
5: string;
|
|
71
|
+
6: string;
|
|
72
|
+
};
|
|
73
|
+
export { guidance_2 as guidance };
|
|
74
|
+
let recommendations_2: {
|
|
75
|
+
1: string[];
|
|
76
|
+
2: string[];
|
|
77
|
+
3: string[];
|
|
78
|
+
4: string[];
|
|
79
|
+
5: string[];
|
|
80
|
+
6: string[];
|
|
81
|
+
};
|
|
82
|
+
export { recommendations_2 as recommendations };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/commands/workflow.js"],"names":[],"mappings":"AA2IA;;;;;GAKG;AACH,8CAHW,MAAM,YACN,MAAM,iBA6FhB;AA7ID;;;;;;;GAOG;AACH,uDALW,MAAM,eACN,MAAM,YACN,MAAM,GACJ,MAAM,CAoClB"}
|