@paths.design/caws-cli 7.0.1 ā 7.0.3
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/budget-derivation.js +5 -4
- package/dist/commands/diagnose.js +26 -20
- package/dist/commands/init.js +72 -5
- package/dist/commands/specs.js +40 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/templates.js +10 -0
- package/dist/commands/tool.js +2 -3
- package/dist/commands/validate.js +12 -0
- package/dist/config/index.js +17 -8
- package/dist/generators/working-spec.js +42 -9
- package/dist/index.js +3 -1
- package/dist/scaffold/cursor-hooks.js +10 -2
- package/dist/scaffold/git-hooks.js +189 -32
- package/dist/scaffold/index.js +105 -17
- package/dist/templates/.caws/tools/README.md +20 -0
- package/dist/templates/.cursor/README.md +311 -0
- package/dist/templates/.cursor/hooks/audit.sh +55 -0
- package/dist/templates/.cursor/hooks/block-dangerous.sh +83 -0
- package/dist/templates/.cursor/hooks/caws-quality-check.sh +52 -0
- package/dist/templates/.cursor/hooks/caws-scope-guard.sh +130 -0
- package/dist/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
- package/dist/templates/.cursor/hooks/format.sh +38 -0
- package/dist/templates/.cursor/hooks/naming-check.sh +64 -0
- package/dist/templates/.cursor/hooks/scan-secrets.sh +46 -0
- package/dist/templates/.cursor/hooks/scope-guard.sh +52 -0
- package/dist/templates/.cursor/hooks/validate-spec.sh +83 -0
- package/dist/templates/.cursor/hooks.json +59 -0
- package/dist/templates/.cursor/rules/00-claims-verification.mdc +144 -0
- package/dist/templates/.cursor/rules/01-working-style.mdc +50 -0
- package/dist/templates/.cursor/rules/02-quality-gates.mdc +370 -0
- package/dist/templates/.cursor/rules/03-naming-and-refactor.mdc +33 -0
- package/dist/templates/.cursor/rules/04-logging-language-style.mdc +23 -0
- package/dist/templates/.cursor/rules/05-safe-defaults-guards.mdc +23 -0
- package/dist/templates/.cursor/rules/06-typescript-conventions.mdc +36 -0
- package/dist/templates/.cursor/rules/07-process-ops.mdc +20 -0
- package/dist/templates/.cursor/rules/08-solid-and-architecture.mdc +16 -0
- package/dist/templates/.cursor/rules/09-docstrings.mdc +89 -0
- package/dist/templates/.cursor/rules/10-documentation-quality-standards.mdc +390 -0
- package/dist/templates/.cursor/rules/11-scope-management-waivers.mdc +385 -0
- package/dist/templates/.cursor/rules/12-implementation-completeness.mdc +516 -0
- package/dist/templates/.cursor/rules/13-language-agnostic-standards.mdc +588 -0
- package/dist/templates/.cursor/rules/README.md +148 -0
- package/dist/templates/.github/copilot/instructions.md +311 -0
- package/dist/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
- package/dist/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
- package/dist/templates/.vscode/launch.json +56 -0
- package/dist/templates/.vscode/settings.json +93 -0
- package/dist/templates/.windsurf/workflows/caws-guided-development.md +92 -0
- package/dist/templates/COMMIT_CONVENTIONS.md +86 -0
- package/dist/templates/OIDC_SETUP.md +300 -0
- package/dist/templates/agents.md +1047 -0
- package/dist/templates/codemod/README.md +1 -0
- package/dist/templates/codemod/test.js +93 -0
- package/dist/templates/docs/README.md +150 -0
- package/dist/templates/scripts/quality-gates/check-god-objects.js +146 -0
- package/dist/templates/scripts/quality-gates/run-quality-gates.js +50 -0
- package/dist/templates/scripts/v3/analysis/todo_analyzer.py +1997 -0
- package/dist/tool-loader.js +6 -1
- package/dist/tool-validator.js +8 -2
- package/dist/utils/detection.js +34 -6
- package/dist/utils/git-lock.js +118 -0
- package/dist/utils/gitignore-updater.js +148 -0
- package/dist/utils/quality-gates.js +47 -7
- package/dist/utils/spec-resolver.js +23 -3
- package/dist/utils/yaml-validation.js +155 -0
- package/dist/validation/spec-validation.js +105 -2
- package/package.json +2 -2
- package/templates/.caws/schemas/waivers.schema.json +30 -0
- package/templates/.caws/schemas/working-spec.schema.json +133 -0
- package/templates/.caws/templates/working-spec.template.yml +74 -0
- package/templates/.caws/tools/README.md +20 -0
- package/templates/.caws/tools/scope-guard.js +208 -0
- package/templates/.caws/tools-allow.json +331 -0
- package/templates/.caws/waivers.yml +19 -0
- package/templates/.cursor/hooks/scope-guard.sh +2 -2
- package/templates/.cursor/hooks/validate-spec.sh +42 -7
- package/templates/apps/tools/caws/COMPLETION_REPORT.md +0 -331
- package/templates/apps/tools/caws/MIGRATION_SUMMARY.md +0 -360
- package/templates/apps/tools/caws/README.md +0 -463
- package/templates/apps/tools/caws/TEST_STATUS.md +0 -365
- package/templates/apps/tools/caws/attest.js +0 -357
- package/templates/apps/tools/caws/ci-optimizer.js +0 -642
- package/templates/apps/tools/caws/config.ts +0 -245
- package/templates/apps/tools/caws/cross-functional.js +0 -876
- package/templates/apps/tools/caws/dashboard.js +0 -1112
- package/templates/apps/tools/caws/flake-detector.ts +0 -362
- package/templates/apps/tools/caws/gates.js +0 -198
- package/templates/apps/tools/caws/gates.ts +0 -271
- package/templates/apps/tools/caws/language-adapters.ts +0 -381
- package/templates/apps/tools/caws/language-support.d.ts +0 -367
- package/templates/apps/tools/caws/language-support.d.ts.map +0 -1
- package/templates/apps/tools/caws/language-support.js +0 -585
- package/templates/apps/tools/caws/legacy-assessment.ts +0 -408
- package/templates/apps/tools/caws/legacy-assessor.js +0 -764
- package/templates/apps/tools/caws/mutant-analyzer.js +0 -734
- package/templates/apps/tools/caws/perf-budgets.ts +0 -349
- package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
- package/templates/apps/tools/caws/property-testing.js +0 -707
- package/templates/apps/tools/caws/provenance.d.ts +0 -14
- package/templates/apps/tools/caws/provenance.d.ts.map +0 -1
- package/templates/apps/tools/caws/provenance.js +0 -132
- package/templates/apps/tools/caws/provenance.js.backup +0 -73
- package/templates/apps/tools/caws/provenance.ts +0 -211
- package/templates/apps/tools/caws/security-provenance.ts +0 -483
- package/templates/apps/tools/caws/shared/base-tool.ts +0 -281
- package/templates/apps/tools/caws/shared/config-manager.ts +0 -366
- package/templates/apps/tools/caws/shared/gate-checker.ts +0 -849
- package/templates/apps/tools/caws/shared/types.ts +0 -444
- package/templates/apps/tools/caws/shared/validator.ts +0 -305
- package/templates/apps/tools/caws/shared/waivers-manager.ts +0 -174
- package/templates/apps/tools/caws/spec-test-mapper.ts +0 -391
- package/templates/apps/tools/caws/test-quality.js +0 -578
- package/templates/apps/tools/caws/validate.js +0 -76
- package/templates/apps/tools/caws/validate.ts +0 -228
- package/templates/apps/tools/caws/waivers.js +0 -344
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/schemas/waivers.schema.json +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/schemas/working-spec.schema.json +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/templates/working-spec.template.yml +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws/tools}/scope-guard.js +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/tools-allow.json +0 -0
- /package/{templates/apps/tools/caws ā dist/templates/.caws}/waivers.yml +0 -0
|
@@ -1,1112 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview CAWS Dashboard and Analytics Tool
|
|
5
|
-
* Provides comprehensive visualization and analytics for CAWS trust metrics
|
|
6
|
-
* @author @darianrosebrook
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Generate real provenance data for trust score calculation
|
|
14
|
-
* @returns {Object} Real provenance data based on project analysis
|
|
15
|
-
*/
|
|
16
|
-
function generateRealProvenanceData() {
|
|
17
|
-
return {
|
|
18
|
-
results: {
|
|
19
|
-
coverage_branch: getRealCoverage(),
|
|
20
|
-
mutation_score: getRealMutationScore(),
|
|
21
|
-
contracts: {
|
|
22
|
-
consumer: checkContractCompliance(),
|
|
23
|
-
provider: checkContractCompliance(),
|
|
24
|
-
},
|
|
25
|
-
a11y: checkAccessibilityCompliance(),
|
|
26
|
-
perf: checkPerformanceCompliance(),
|
|
27
|
-
flake_rate: getRealFlakeRate(),
|
|
28
|
-
mode_compliance: checkModeCompliance(),
|
|
29
|
-
scope_within_budget: checkScopeCompliance(),
|
|
30
|
-
sbom_valid: checkSBOMValidity(),
|
|
31
|
-
attestation_valid: checkAttestationValidity(),
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Get real test coverage from coverage reports
|
|
38
|
-
* @returns {number} Coverage percentage (0-1)
|
|
39
|
-
*/
|
|
40
|
-
function getRealCoverage() {
|
|
41
|
-
try {
|
|
42
|
-
const coveragePath = path.join(process.cwd(), 'coverage', 'coverage-summary.json');
|
|
43
|
-
if (fs.existsSync(coveragePath)) {
|
|
44
|
-
const coverageData = JSON.parse(fs.readFileSync(coveragePath, 'utf8'));
|
|
45
|
-
return coverageData.total.lines.pct / 100;
|
|
46
|
-
}
|
|
47
|
-
} catch (error) {
|
|
48
|
-
// No coverage data available
|
|
49
|
-
}
|
|
50
|
-
return 0.75; // Default estimate
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Get real mutation score from mutation reports
|
|
55
|
-
* @returns {number} Mutation score (0-1)
|
|
56
|
-
*/
|
|
57
|
-
function getRealMutationScore() {
|
|
58
|
-
try {
|
|
59
|
-
const mutationPath = path.join(process.cwd(), 'reports', 'mutation', 'mutation.json');
|
|
60
|
-
if (fs.existsSync(mutationPath)) {
|
|
61
|
-
const mutationData = JSON.parse(fs.readFileSync(mutationPath, 'utf8'));
|
|
62
|
-
let total = 0,
|
|
63
|
-
killed = 0;
|
|
64
|
-
|
|
65
|
-
Object.values(mutationData.files || {}).forEach((file) => {
|
|
66
|
-
if (file.mutants) {
|
|
67
|
-
file.mutants.forEach((mutant) => {
|
|
68
|
-
total++;
|
|
69
|
-
if (mutant.status === 'Killed') killed++;
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return total > 0 ? killed / total : 0;
|
|
75
|
-
}
|
|
76
|
-
} catch (error) {
|
|
77
|
-
// No mutation data available
|
|
78
|
-
}
|
|
79
|
-
return 0.55; // Default estimate
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Check contract compliance
|
|
84
|
-
* @returns {boolean} Whether contracts are compliant
|
|
85
|
-
*/
|
|
86
|
-
function checkContractCompliance() {
|
|
87
|
-
try {
|
|
88
|
-
// Check if contract tests exist and pass
|
|
89
|
-
const contractTestsPath = path.join(process.cwd(), 'packages', 'caws-cli', 'tests', 'contract');
|
|
90
|
-
return fs.existsSync(contractTestsPath);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Check accessibility compliance
|
|
98
|
-
* @returns {string} Accessibility compliance status
|
|
99
|
-
*/
|
|
100
|
-
function checkAccessibilityCompliance() {
|
|
101
|
-
try {
|
|
102
|
-
// Check if axe tests exist
|
|
103
|
-
const axeTestsPath = path.join(process.cwd(), 'packages', 'caws-cli', 'tests', 'axe');
|
|
104
|
-
return fs.existsSync(axeTestsPath) ? 'pass' : 'unknown';
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return 'unknown';
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Check performance compliance
|
|
112
|
-
* @returns {Object} Performance metrics
|
|
113
|
-
*/
|
|
114
|
-
function checkPerformanceCompliance() {
|
|
115
|
-
try {
|
|
116
|
-
// Check if performance budgets exist
|
|
117
|
-
const perfTestsPath = path.join(process.cwd(), 'packages', 'caws-cli', 'tests');
|
|
118
|
-
const hasPerfTests = fs.existsSync(path.join(perfTestsPath, 'perf-budgets.test.js'));
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
api_p95_ms: hasPerfTests ? 180 : 250, // Estimated based on test presence
|
|
122
|
-
};
|
|
123
|
-
} catch (error) {
|
|
124
|
-
return { api_p95_ms: 250 };
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Get real flake rate from test results
|
|
130
|
-
* @returns {number} Flake rate (0-1)
|
|
131
|
-
*/
|
|
132
|
-
function getRealFlakeRate() {
|
|
133
|
-
// This would analyze test run history for flakiness
|
|
134
|
-
// For now, return a reasonable estimate
|
|
135
|
-
return 0.02; // 2% flake rate estimate
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Check mode compliance
|
|
140
|
-
* @returns {string} Mode compliance status
|
|
141
|
-
*/
|
|
142
|
-
function checkModeCompliance() {
|
|
143
|
-
try {
|
|
144
|
-
const workingSpecPath = path.join(process.cwd(), '.caws', 'working-spec.yaml');
|
|
145
|
-
if (fs.existsSync(workingSpecPath)) {
|
|
146
|
-
const spec = fs.readFileSync(workingSpecPath, 'utf8');
|
|
147
|
-
return spec.includes('mode:') ? 'full' : 'partial';
|
|
148
|
-
}
|
|
149
|
-
} catch (error) {
|
|
150
|
-
return 'unknown';
|
|
151
|
-
}
|
|
152
|
-
return 'full';
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Check scope compliance
|
|
157
|
-
* @returns {boolean} Whether scope is within budget
|
|
158
|
-
*/
|
|
159
|
-
function checkScopeCompliance() {
|
|
160
|
-
try {
|
|
161
|
-
// Check if files are within reasonable limits
|
|
162
|
-
const sourceFiles = findSourceFiles(process.cwd());
|
|
163
|
-
return sourceFiles.length <= 100; // Reasonable file limit
|
|
164
|
-
} catch (error) {
|
|
165
|
-
return true; // Assume compliant if can't check
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Check SBOM validity
|
|
171
|
-
* @returns {boolean} Whether SBOM is valid
|
|
172
|
-
*/
|
|
173
|
-
function checkSBOMValidity() {
|
|
174
|
-
try {
|
|
175
|
-
// Check if SBOM files exist
|
|
176
|
-
const sbomPaths = ['.agent/sbom.json', 'sbom.json'];
|
|
177
|
-
return sbomPaths.some((sbomPath) => fs.existsSync(sbomPath));
|
|
178
|
-
} catch (error) {
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Check attestation validity
|
|
185
|
-
* @returns {boolean} Whether attestations are valid
|
|
186
|
-
*/
|
|
187
|
-
function checkAttestationValidity() {
|
|
188
|
-
try {
|
|
189
|
-
// Check if attestation files exist
|
|
190
|
-
const attestationPaths = ['.agent/attestation.json'];
|
|
191
|
-
return attestationPaths.some((attestationPath) => fs.existsSync(attestationPath));
|
|
192
|
-
} catch (error) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Find source files in the project
|
|
199
|
-
* @param {string} projectRoot - Project root directory
|
|
200
|
-
* @returns {string[]} Array of source file paths
|
|
201
|
-
*/
|
|
202
|
-
function findSourceFiles(projectRoot) {
|
|
203
|
-
const files = [];
|
|
204
|
-
|
|
205
|
-
function scanDirectory(dir) {
|
|
206
|
-
const items = fs.readdirSync(dir);
|
|
207
|
-
|
|
208
|
-
items.forEach((item) => {
|
|
209
|
-
const fullPath = path.join(dir, item);
|
|
210
|
-
const stat = fs.statSync(fullPath);
|
|
211
|
-
|
|
212
|
-
if (
|
|
213
|
-
stat.isDirectory() &&
|
|
214
|
-
!item.startsWith('.') &&
|
|
215
|
-
item !== 'node_modules' &&
|
|
216
|
-
item !== 'dist'
|
|
217
|
-
) {
|
|
218
|
-
scanDirectory(fullPath);
|
|
219
|
-
} else if (stat.isFile() && (item.endsWith('.js') || item.endsWith('.ts'))) {
|
|
220
|
-
files.push(fullPath);
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
scanDirectory(projectRoot);
|
|
226
|
-
return files;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Historical data reading function (currently unused but kept for future use)
|
|
230
|
-
// eslint-disable-next-line no-unused-vars
|
|
231
|
-
function readHistoricalData() {
|
|
232
|
-
try {
|
|
233
|
-
// Look for historical metrics files
|
|
234
|
-
const historyPath = path.join(process.cwd(), '.agent', 'metrics-history.json');
|
|
235
|
-
if (fs.existsSync(historyPath)) {
|
|
236
|
-
return JSON.parse(fs.readFileSync(historyPath, 'utf8'));
|
|
237
|
-
}
|
|
238
|
-
} catch (error) {
|
|
239
|
-
// No historical data available
|
|
240
|
-
}
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Generate simulated trends when real data isn't available
|
|
246
|
-
* @param {Object} dashboard - Dashboard data structure
|
|
247
|
-
* @param {number} days - Number of days to generate
|
|
248
|
-
*/
|
|
249
|
-
// eslint-disable-next-line no-unused-vars
|
|
250
|
-
function generateSimulatedTrends(dashboard, days) {
|
|
251
|
-
// Generate more realistic simulated trends based on current metrics
|
|
252
|
-
const baseTrustScore = dashboard.metrics.TRUST_SCORE.current || 75;
|
|
253
|
-
const baseCoverage = dashboard.metrics.COVERAGE.current || 80;
|
|
254
|
-
const baseMutation = dashboard.metrics.MUTATION_SCORE.current || 60;
|
|
255
|
-
|
|
256
|
-
for (let i = days; i >= 0; i--) {
|
|
257
|
-
const date = new Date();
|
|
258
|
-
date.setDate(date.getDate() - i);
|
|
259
|
-
|
|
260
|
-
// Generate trends with some realistic variation around current values
|
|
261
|
-
const trustVariation = Math.sin(i * 0.1) * 3 + (Math.random() - 0.5) * 2;
|
|
262
|
-
const coverageVariation = Math.sin(i * 0.15) * 2 + (Math.random() - 0.5) * 1.5;
|
|
263
|
-
const mutationVariation = Math.sin(i * 0.12) * 4 + (Math.random() - 0.5) * 3;
|
|
264
|
-
|
|
265
|
-
dashboard.trends.trust_score.push({
|
|
266
|
-
date: date.toISOString().split('T')[0],
|
|
267
|
-
value: Math.max(60, Math.min(95, baseTrustScore + trustVariation)),
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
dashboard.trends.coverage.push({
|
|
271
|
-
date: date.toISOString().split('T')[0],
|
|
272
|
-
value: Math.max(70, Math.min(95, baseCoverage + coverageVariation)),
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
dashboard.trends.mutation.push({
|
|
276
|
-
date: date.toISOString().split('T')[0],
|
|
277
|
-
value: Math.max(40, Math.min(80, baseMutation + mutationVariation)),
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Dashboard metrics and KPIs
|
|
284
|
-
*/
|
|
285
|
-
const DASHBOARD_METRICS = {
|
|
286
|
-
TRUST_SCORE: {
|
|
287
|
-
name: 'Trust Score',
|
|
288
|
-
description: 'Overall CAWS trust score (0-100)',
|
|
289
|
-
target: 82,
|
|
290
|
-
trend: 'higher_is_better',
|
|
291
|
-
},
|
|
292
|
-
|
|
293
|
-
COVERAGE: {
|
|
294
|
-
name: 'Test Coverage',
|
|
295
|
-
description: 'Branch coverage percentage',
|
|
296
|
-
target: 80,
|
|
297
|
-
trend: 'higher_is_better',
|
|
298
|
-
},
|
|
299
|
-
|
|
300
|
-
MUTATION_SCORE: {
|
|
301
|
-
name: 'Mutation Score',
|
|
302
|
-
description: 'Effective mutation testing score',
|
|
303
|
-
target: 60,
|
|
304
|
-
trend: 'higher_is_better',
|
|
305
|
-
},
|
|
306
|
-
|
|
307
|
-
TEST_QUALITY: {
|
|
308
|
-
name: 'Test Quality',
|
|
309
|
-
description: 'Advanced test quality score',
|
|
310
|
-
target: 70,
|
|
311
|
-
trend: 'higher_is_better',
|
|
312
|
-
},
|
|
313
|
-
|
|
314
|
-
FLAKE_RATE: {
|
|
315
|
-
name: 'Flake Rate',
|
|
316
|
-
description: 'Percentage of flaky tests',
|
|
317
|
-
target: 0.5,
|
|
318
|
-
trend: 'lower_is_better',
|
|
319
|
-
},
|
|
320
|
-
|
|
321
|
-
RISK_TIER_COMPLIANCE: {
|
|
322
|
-
name: 'Risk Tier Compliance',
|
|
323
|
-
description: 'Percentage of changes meeting tier requirements',
|
|
324
|
-
target: 95,
|
|
325
|
-
trend: 'higher_is_better',
|
|
326
|
-
},
|
|
327
|
-
|
|
328
|
-
CONTRACT_COMPLIANCE: {
|
|
329
|
-
name: 'Contract Compliance',
|
|
330
|
-
description: 'Percentage of changes with valid contracts',
|
|
331
|
-
target: 90,
|
|
332
|
-
trend: 'higher_is_better',
|
|
333
|
-
},
|
|
334
|
-
|
|
335
|
-
SECURITY_COMPLIANCE: {
|
|
336
|
-
name: 'Security Compliance',
|
|
337
|
-
description: 'Percentage of changes passing security checks',
|
|
338
|
-
target: 100,
|
|
339
|
-
trend: 'higher_is_better',
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Generate comprehensive dashboard data
|
|
345
|
-
* @param {string} projectDir - Project directory to analyze
|
|
346
|
-
* @returns {Object} Dashboard data
|
|
347
|
-
*/
|
|
348
|
-
function generateDashboardData(projectDir = process.cwd()) {
|
|
349
|
-
console.log(`š Generating CAWS dashboard for: ${projectDir}`);
|
|
350
|
-
|
|
351
|
-
const dashboard = {
|
|
352
|
-
metadata: {
|
|
353
|
-
generated_at: new Date().toISOString(),
|
|
354
|
-
project_name: path.basename(projectDir),
|
|
355
|
-
tool: 'caws-dashboard',
|
|
356
|
-
version: '1.0.0',
|
|
357
|
-
},
|
|
358
|
-
|
|
359
|
-
overview: {
|
|
360
|
-
trust_score: 0,
|
|
361
|
-
risk_distribution: {},
|
|
362
|
-
trend_data: [],
|
|
363
|
-
alerts: [],
|
|
364
|
-
},
|
|
365
|
-
|
|
366
|
-
metrics: {},
|
|
367
|
-
insights: [],
|
|
368
|
-
recommendations: [],
|
|
369
|
-
trends: {},
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
// Initialize metrics
|
|
373
|
-
Object.keys(DASHBOARD_METRICS).forEach((metric) => {
|
|
374
|
-
dashboard.metrics[metric] = {
|
|
375
|
-
current: 0,
|
|
376
|
-
target: DASHBOARD_METRICS[metric].target,
|
|
377
|
-
status: 'unknown',
|
|
378
|
-
trend: 'stable',
|
|
379
|
-
};
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
// Gather data from various sources
|
|
383
|
-
gatherProjectMetrics(dashboard, projectDir);
|
|
384
|
-
calculateTrends(dashboard, projectDir);
|
|
385
|
-
generateInsights(dashboard);
|
|
386
|
-
generateRecommendations(dashboard);
|
|
387
|
-
|
|
388
|
-
return dashboard;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Gather metrics from project files and tools
|
|
393
|
-
*/
|
|
394
|
-
function gatherProjectMetrics(dashboard, projectDir) {
|
|
395
|
-
// Get current working spec
|
|
396
|
-
const specPath = path.join(projectDir, '.caws/working-spec.yaml');
|
|
397
|
-
if (fs.existsSync(specPath)) {
|
|
398
|
-
try {
|
|
399
|
-
const yaml = require('js-yaml');
|
|
400
|
-
const spec = yaml.load(fs.readFileSync(specPath, 'utf8'));
|
|
401
|
-
|
|
402
|
-
dashboard.overview.current_tier = spec.risk_tier;
|
|
403
|
-
dashboard.overview.mode = spec.mode;
|
|
404
|
-
dashboard.overview.change_budget = spec.change_budget;
|
|
405
|
-
} catch (error) {
|
|
406
|
-
console.warn('ā ļø Could not parse working spec');
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Get trust score from gates tool with real data
|
|
411
|
-
try {
|
|
412
|
-
const { trustScore } = require('./gates');
|
|
413
|
-
const realProv = generateRealProvenanceData();
|
|
414
|
-
|
|
415
|
-
dashboard.metrics.TRUST_SCORE.current = trustScore(2, realProv);
|
|
416
|
-
dashboard.overview.trust_score = dashboard.metrics.TRUST_SCORE.current;
|
|
417
|
-
} catch (error) {
|
|
418
|
-
console.warn('ā ļø Could not calculate trust score');
|
|
419
|
-
dashboard.metrics.TRUST_SCORE.current = 75; // Default
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Get coverage data
|
|
423
|
-
try {
|
|
424
|
-
if (fs.existsSync('coverage/coverage-summary.json')) {
|
|
425
|
-
const coverageData = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
|
|
426
|
-
dashboard.metrics.COVERAGE.current = Math.round(coverageData.total.branches.pct || 0);
|
|
427
|
-
} else {
|
|
428
|
-
dashboard.metrics.COVERAGE.current = 70; // Default
|
|
429
|
-
}
|
|
430
|
-
} catch (error) {
|
|
431
|
-
dashboard.metrics.COVERAGE.current = 70; // Default
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// Get mutation data
|
|
435
|
-
try {
|
|
436
|
-
if (fs.existsSync('mutation-report.json')) {
|
|
437
|
-
const mutationData = JSON.parse(fs.readFileSync('mutation-report.json', 'utf8'));
|
|
438
|
-
dashboard.metrics.MUTATION_SCORE.current = Math.round(
|
|
439
|
-
(mutationData.killed / mutationData.total) * 100 || 0
|
|
440
|
-
);
|
|
441
|
-
} else {
|
|
442
|
-
dashboard.metrics.MUTATION_SCORE.current = 50; // Default
|
|
443
|
-
}
|
|
444
|
-
} catch (error) {
|
|
445
|
-
dashboard.metrics.MUTATION_SCORE.current = 50; // Default
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Get test quality data
|
|
449
|
-
try {
|
|
450
|
-
const { analyzeTestDirectory } = require('./test-quality');
|
|
451
|
-
const testResults = analyzeTestDirectory('tests');
|
|
452
|
-
dashboard.metrics.TEST_QUALITY.current = testResults.summary.averageQualityScore || 60;
|
|
453
|
-
} catch (error) {
|
|
454
|
-
dashboard.metrics.TEST_QUALITY.current = 60; // Default
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Calculate flake rate (simplified)
|
|
458
|
-
dashboard.metrics.FLAKE_RATE.current = 2; // 2% default
|
|
459
|
-
|
|
460
|
-
// Calculate compliance metrics
|
|
461
|
-
dashboard.metrics.RISK_TIER_COMPLIANCE.current = 95; // Default
|
|
462
|
-
dashboard.metrics.CONTRACT_COMPLIANCE.current = 90; // Default
|
|
463
|
-
dashboard.metrics.SECURITY_COMPLIANCE.current = 98; // Default
|
|
464
|
-
|
|
465
|
-
// Set status for each metric
|
|
466
|
-
Object.keys(dashboard.metrics).forEach((metric) => {
|
|
467
|
-
const metricInfo = dashboard.metrics[metric];
|
|
468
|
-
if (metricInfo.current >= metricInfo.target) {
|
|
469
|
-
metricInfo.status = 'passing';
|
|
470
|
-
} else if (metricInfo.current >= metricInfo.target * 0.8) {
|
|
471
|
-
metricInfo.status = 'warning';
|
|
472
|
-
} else {
|
|
473
|
-
metricInfo.status = 'failing';
|
|
474
|
-
}
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
// Risk distribution
|
|
478
|
-
dashboard.overview.risk_distribution = {
|
|
479
|
-
tier1: 15,
|
|
480
|
-
tier2: 60,
|
|
481
|
-
tier3: 25,
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* Calculate trends from historical data
|
|
487
|
-
*/
|
|
488
|
-
function calculateTrends(dashboard, _projectDir) {
|
|
489
|
-
// Generate real trend data based on project history
|
|
490
|
-
const days = 30;
|
|
491
|
-
dashboard.trends.trust_score = [];
|
|
492
|
-
dashboard.trends.coverage = [];
|
|
493
|
-
dashboard.trends.mutation = [];
|
|
494
|
-
|
|
495
|
-
for (let i = days; i >= 0; i--) {
|
|
496
|
-
const date = new Date();
|
|
497
|
-
date.setDate(date.getDate() - i);
|
|
498
|
-
|
|
499
|
-
dashboard.trends.trust_score.push({
|
|
500
|
-
date: date.toISOString().split('T')[0],
|
|
501
|
-
value: Math.max(
|
|
502
|
-
70,
|
|
503
|
-
Math.min(
|
|
504
|
-
95,
|
|
505
|
-
dashboard.metrics.TRUST_SCORE.current + Math.sin(i * 0.1) * 5 + Math.random() * 3
|
|
506
|
-
)
|
|
507
|
-
),
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
dashboard.trends.coverage.push({
|
|
511
|
-
date: date.toISOString().split('T')[0],
|
|
512
|
-
value: Math.max(
|
|
513
|
-
70,
|
|
514
|
-
Math.min(
|
|
515
|
-
90,
|
|
516
|
-
dashboard.metrics.COVERAGE.current + Math.sin(i * 0.15) * 3 + Math.random() * 2
|
|
517
|
-
)
|
|
518
|
-
),
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
dashboard.trends.mutation.push({
|
|
522
|
-
date: date.toISOString().split('T')[0],
|
|
523
|
-
value: Math.max(
|
|
524
|
-
40,
|
|
525
|
-
Math.min(
|
|
526
|
-
80,
|
|
527
|
-
dashboard.metrics.MUTATION_SCORE.current + Math.sin(i * 0.12) * 4 + Math.random() * 3
|
|
528
|
-
)
|
|
529
|
-
),
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Calculate trend directions
|
|
534
|
-
const recentTrust = dashboard.trends.trust_score.slice(-7).map((d) => d.value);
|
|
535
|
-
const olderTrust = dashboard.trends.trust_score.slice(-14, -7).map((d) => d.value);
|
|
536
|
-
const recentAvg = recentTrust.reduce((a, b) => a + b, 0) / recentTrust.length;
|
|
537
|
-
const olderAvg = olderTrust.reduce((a, b) => a + b, 0) / olderTrust.length;
|
|
538
|
-
|
|
539
|
-
if (recentAvg > olderAvg + 2) {
|
|
540
|
-
dashboard.metrics.TRUST_SCORE.trend = 'improving';
|
|
541
|
-
} else if (recentAvg < olderAvg - 2) {
|
|
542
|
-
dashboard.metrics.TRUST_SCORE.trend = 'declining';
|
|
543
|
-
} else {
|
|
544
|
-
dashboard.metrics.TRUST_SCORE.trend = 'stable';
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
/**
|
|
549
|
-
* Generate insights based on current metrics
|
|
550
|
-
*/
|
|
551
|
-
function generateInsights(dashboard) {
|
|
552
|
-
const insights = [];
|
|
553
|
-
|
|
554
|
-
// Trust score insights
|
|
555
|
-
if (dashboard.metrics.TRUST_SCORE.current >= 90) {
|
|
556
|
-
insights.push({
|
|
557
|
-
type: 'success',
|
|
558
|
-
message: 'Excellent trust score! Your CAWS implementation is highly effective.',
|
|
559
|
-
metric: 'TRUST_SCORE',
|
|
560
|
-
});
|
|
561
|
-
} else if (dashboard.metrics.TRUST_SCORE.current >= 80) {
|
|
562
|
-
insights.push({
|
|
563
|
-
type: 'info',
|
|
564
|
-
message: 'Good trust score. Consider focusing on areas with lower scores.',
|
|
565
|
-
metric: 'TRUST_SCORE',
|
|
566
|
-
});
|
|
567
|
-
} else {
|
|
568
|
-
insights.push({
|
|
569
|
-
type: 'warning',
|
|
570
|
-
message: 'Trust score needs improvement. Review failing metrics and address gaps.',
|
|
571
|
-
metric: 'TRUST_SCORE',
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// Coverage insights
|
|
576
|
-
if (dashboard.metrics.COVERAGE.current < 70) {
|
|
577
|
-
insights.push({
|
|
578
|
-
type: 'warning',
|
|
579
|
-
message: 'Test coverage is below target. Add more comprehensive tests.',
|
|
580
|
-
metric: 'COVERAGE',
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// Mutation score insights
|
|
585
|
-
if (dashboard.metrics.MUTATION_SCORE.current < 50) {
|
|
586
|
-
insights.push({
|
|
587
|
-
type: 'warning',
|
|
588
|
-
message: 'Mutation score indicates weak test effectiveness. Review test quality.',
|
|
589
|
-
metric: 'MUTATION_SCORE',
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Flake rate insights
|
|
594
|
-
if (dashboard.metrics.FLAKE_RATE.current > 1) {
|
|
595
|
-
insights.push({
|
|
596
|
-
type: 'warning',
|
|
597
|
-
message: 'High flake rate detected. Investigate and fix flaky tests.',
|
|
598
|
-
metric: 'FLAKE_RATE',
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
dashboard.insights = insights;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* Generate actionable recommendations
|
|
607
|
-
*/
|
|
608
|
-
function generateRecommendations(dashboard) {
|
|
609
|
-
const recommendations = [];
|
|
610
|
-
|
|
611
|
-
// Metric-specific recommendations
|
|
612
|
-
Object.keys(dashboard.metrics).forEach((metric) => {
|
|
613
|
-
const metricInfo = dashboard.metrics[metric];
|
|
614
|
-
const metricConfig = DASHBOARD_METRICS[metric];
|
|
615
|
-
|
|
616
|
-
if (metricInfo.current < metricInfo.target) {
|
|
617
|
-
const gap = metricInfo.target - metricInfo.current;
|
|
618
|
-
recommendations.push({
|
|
619
|
-
priority: gap > 20 ? 'high' : gap > 10 ? 'medium' : 'low',
|
|
620
|
-
category: metric,
|
|
621
|
-
message: `Improve ${metricConfig.name} from ${metricInfo.current} to ${metricInfo.target} (${metricConfig.description})`,
|
|
622
|
-
actions: getActionsForMetric(metric),
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
// General recommendations
|
|
628
|
-
if (dashboard.overview.risk_distribution.tier3 > 40) {
|
|
629
|
-
recommendations.push({
|
|
630
|
-
priority: 'medium',
|
|
631
|
-
category: 'RISK_MANAGEMENT',
|
|
632
|
-
message: 'High proportion of Tier 3 changes. Consider if some should be Tier 2.',
|
|
633
|
-
actions: [
|
|
634
|
-
'Review recent changes for appropriate tier classification',
|
|
635
|
-
'Consider elevating critical Tier 3 items',
|
|
636
|
-
],
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
dashboard.recommendations = recommendations;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
/**
|
|
644
|
-
* Get specific actions for improving a metric
|
|
645
|
-
*/
|
|
646
|
-
function getActionsForMetric(metric) {
|
|
647
|
-
const actions = {
|
|
648
|
-
TRUST_SCORE: [
|
|
649
|
-
'Review overall CAWS implementation',
|
|
650
|
-
'Ensure all quality gates are properly configured',
|
|
651
|
-
'Address failing individual metrics',
|
|
652
|
-
],
|
|
653
|
-
COVERAGE: [
|
|
654
|
-
'Add tests for uncovered code paths',
|
|
655
|
-
'Review existing tests for comprehensiveness',
|
|
656
|
-
'Set up coverage reporting in CI/CD',
|
|
657
|
-
],
|
|
658
|
-
MUTATION_SCORE: [
|
|
659
|
-
'Run mutation analysis to identify weak tests',
|
|
660
|
-
'Add tests that kill surviving mutants',
|
|
661
|
-
'Review test quality and assertion strength',
|
|
662
|
-
],
|
|
663
|
-
TEST_QUALITY: [
|
|
664
|
-
'Analyze test meaningfulness beyond coverage',
|
|
665
|
-
'Add edge case and error condition tests',
|
|
666
|
-
'Improve test naming and structure',
|
|
667
|
-
],
|
|
668
|
-
FLAKE_RATE: [
|
|
669
|
-
'Investigate and fix flaky tests',
|
|
670
|
-
'Add proper test isolation',
|
|
671
|
-
'Review async operations and timing issues',
|
|
672
|
-
],
|
|
673
|
-
RISK_TIER_COMPLIANCE: [
|
|
674
|
-
'Review tier classification guidelines',
|
|
675
|
-
'Ensure changes are appropriately tiered',
|
|
676
|
-
'Provide training on tier selection',
|
|
677
|
-
],
|
|
678
|
-
CONTRACT_COMPLIANCE: [
|
|
679
|
-
'Ensure contracts are updated for API changes',
|
|
680
|
-
'Run contract tests before merging',
|
|
681
|
-
'Review contract testing setup',
|
|
682
|
-
],
|
|
683
|
-
SECURITY_COMPLIANCE: [
|
|
684
|
-
'Review security scanning configuration',
|
|
685
|
-
'Address security vulnerabilities',
|
|
686
|
-
'Ensure secrets are properly handled',
|
|
687
|
-
],
|
|
688
|
-
};
|
|
689
|
-
|
|
690
|
-
return actions[metric] || ['Review and improve this metric'];
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Generate HTML dashboard report
|
|
695
|
-
*/
|
|
696
|
-
function generateHTMLDashboard(dashboard, outputPath = 'caws-dashboard.html') {
|
|
697
|
-
const html = generateDashboardHTML(dashboard);
|
|
698
|
-
|
|
699
|
-
fs.writeFileSync(outputPath, html);
|
|
700
|
-
console.log(`ā
Generated HTML dashboard: ${outputPath}`);
|
|
701
|
-
|
|
702
|
-
return outputPath;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Generate HTML dashboard content
|
|
707
|
-
*/
|
|
708
|
-
function generateDashboardHTML(dashboard) {
|
|
709
|
-
return `
|
|
710
|
-
<!DOCTYPE html>
|
|
711
|
-
<html lang="en">
|
|
712
|
-
<head>
|
|
713
|
-
<meta charset="UTF-8">
|
|
714
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
715
|
-
<title>CAWS Dashboard - ${dashboard.metadata.project_name}</title>
|
|
716
|
-
<style>
|
|
717
|
-
* {
|
|
718
|
-
margin: 0;
|
|
719
|
-
padding: 0;
|
|
720
|
-
box-sizing: border-box;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
body {
|
|
724
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
725
|
-
background: #f5f5f5;
|
|
726
|
-
color: #333;
|
|
727
|
-
line-height: 1.6;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
.header {
|
|
731
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
732
|
-
color: white;
|
|
733
|
-
padding: 2rem;
|
|
734
|
-
text-align: center;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
.header h1 {
|
|
738
|
-
font-size: 2.5rem;
|
|
739
|
-
margin-bottom: 0.5rem;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
.header .subtitle {
|
|
743
|
-
opacity: 0.9;
|
|
744
|
-
font-size: 1.1rem;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
.container {
|
|
748
|
-
max-width: 1200px;
|
|
749
|
-
margin: 0 auto;
|
|
750
|
-
padding: 2rem;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
.metrics-grid {
|
|
754
|
-
display: grid;
|
|
755
|
-
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
756
|
-
gap: 2rem;
|
|
757
|
-
margin-bottom: 3rem;
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
.metric-card {
|
|
761
|
-
background: white;
|
|
762
|
-
border-radius: 8px;
|
|
763
|
-
padding: 1.5rem;
|
|
764
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
765
|
-
border-left: 4px solid;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
.metric-card.success { border-left-color: #10b981; }
|
|
769
|
-
.metric-card.warning { border-left-color: #f59e0b; }
|
|
770
|
-
.metric-card.danger { border-left-color: #ef4444; }
|
|
771
|
-
.metric-card.info { border-left-color: #3b82f6; }
|
|
772
|
-
|
|
773
|
-
.metric-header {
|
|
774
|
-
display: flex;
|
|
775
|
-
justify-content: between;
|
|
776
|
-
align-items: center;
|
|
777
|
-
margin-bottom: 1rem;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
.metric-title {
|
|
781
|
-
font-size: 1.2rem;
|
|
782
|
-
font-weight: 600;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
.metric-value {
|
|
786
|
-
font-size: 2rem;
|
|
787
|
-
font-weight: 700;
|
|
788
|
-
margin: 0.5rem 0;
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
.metric-target {
|
|
792
|
-
color: #666;
|
|
793
|
-
font-size: 0.9rem;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
.metric-status {
|
|
797
|
-
padding: 0.25rem 0.75rem;
|
|
798
|
-
border-radius: 20px;
|
|
799
|
-
font-size: 0.8rem;
|
|
800
|
-
font-weight: 500;
|
|
801
|
-
text-transform: uppercase;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
.status-passing { background: #d1fae5; color: #065f46; }
|
|
805
|
-
.status-warning { background: #fef3c7; color: #92400e; }
|
|
806
|
-
.status-failing { background: #fee2e2; color: #991b1b; }
|
|
807
|
-
|
|
808
|
-
.trend-indicator {
|
|
809
|
-
margin-left: auto;
|
|
810
|
-
padding: 0.25rem 0.5rem;
|
|
811
|
-
border-radius: 4px;
|
|
812
|
-
font-size: 0.8rem;
|
|
813
|
-
font-weight: 500;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
.trend-improving { background: #dcfce7; color: #166534; }
|
|
817
|
-
.trend-declining { background: #fef2f2; color: #991b1b; }
|
|
818
|
-
.trend-stable { background: #f3f4f6; color: #374151; }
|
|
819
|
-
|
|
820
|
-
.insights-section {
|
|
821
|
-
background: white;
|
|
822
|
-
border-radius: 8px;
|
|
823
|
-
padding: 2rem;
|
|
824
|
-
margin-bottom: 2rem;
|
|
825
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
.insights-grid {
|
|
829
|
-
display: grid;
|
|
830
|
-
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
831
|
-
gap: 1rem;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
.insight-card {
|
|
835
|
-
padding: 1rem;
|
|
836
|
-
border-radius: 6px;
|
|
837
|
-
border-left: 4px solid;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
.insight-success { border-left-color: #10b981; background: #f0fdf4; }
|
|
841
|
-
.insight-info { border-left-color: #3b82f6; background: #eff6ff; }
|
|
842
|
-
.insight-warning { border-left-color: #f59e0b; background: #fffbeb; }
|
|
843
|
-
|
|
844
|
-
.recommendations-section {
|
|
845
|
-
background: white;
|
|
846
|
-
border-radius: 8px;
|
|
847
|
-
padding: 2rem;
|
|
848
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
.recommendation {
|
|
852
|
-
margin-bottom: 1.5rem;
|
|
853
|
-
padding: 1rem;
|
|
854
|
-
border-radius: 6px;
|
|
855
|
-
border-left: 4px solid;
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
.priority-high { border-left-color: #ef4444; background: #fef2f2; }
|
|
859
|
-
.priority-medium { border-left-color: #f59e0b; background: #fffbeb; }
|
|
860
|
-
.priority-low { border-left-color: #3b82f6; background: #eff6ff; }
|
|
861
|
-
|
|
862
|
-
.recommendation-header {
|
|
863
|
-
display: flex;
|
|
864
|
-
justify-content: between;
|
|
865
|
-
align-items: center;
|
|
866
|
-
margin-bottom: 0.5rem;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
.recommendation-title {
|
|
870
|
-
font-weight: 600;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
.priority-badge {
|
|
874
|
-
padding: 0.25rem 0.5rem;
|
|
875
|
-
border-radius: 12px;
|
|
876
|
-
font-size: 0.8rem;
|
|
877
|
-
font-weight: 500;
|
|
878
|
-
text-transform: uppercase;
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
.actions-list {
|
|
882
|
-
margin-top: 0.5rem;
|
|
883
|
-
padding-left: 1rem;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
.actions-list li {
|
|
887
|
-
margin-bottom: 0.25rem;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
.footer {
|
|
891
|
-
text-align: center;
|
|
892
|
-
margin-top: 3rem;
|
|
893
|
-
color: #666;
|
|
894
|
-
font-size: 0.9rem;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
@media (max-width: 768px) {
|
|
898
|
-
.container {
|
|
899
|
-
padding: 1rem;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
.metrics-grid {
|
|
903
|
-
grid-template-columns: 1fr;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
.header h1 {
|
|
907
|
-
font-size: 2rem;
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
</style>
|
|
911
|
-
</head>
|
|
912
|
-
<body>
|
|
913
|
-
<div class="header">
|
|
914
|
-
<h1>CAWS Dashboard</h1>
|
|
915
|
-
<div class="subtitle">Coding Agent Workflow System - ${dashboard.metadata.project_name}</div>
|
|
916
|
-
<div class="subtitle">Generated: ${new Date(dashboard.metadata.generated_at).toLocaleString()}</div>
|
|
917
|
-
</div>
|
|
918
|
-
|
|
919
|
-
<div class="container">
|
|
920
|
-
<!-- Overview Section -->
|
|
921
|
-
<div class="insights-section">
|
|
922
|
-
<h2>š Overview</h2>
|
|
923
|
-
<div class="insights-grid">
|
|
924
|
-
<div class="insight-card insight-info">
|
|
925
|
-
<h3>Current Trust Score</h3>
|
|
926
|
-
<div style="font-size: 2rem; font-weight: bold; color: #3b82f6;">
|
|
927
|
-
${dashboard.overview.trust_score}/100
|
|
928
|
-
</div>
|
|
929
|
-
</div>
|
|
930
|
-
<div class="insight-card insight-info">
|
|
931
|
-
<h3>Risk Distribution</h3>
|
|
932
|
-
<div>Tier 1: ${dashboard.overview.risk_distribution.tier1}%</div>
|
|
933
|
-
<div>Tier 2: ${dashboard.overview.risk_distribution.tier2}%</div>
|
|
934
|
-
<div>Tier 3: ${dashboard.overview.risk_distribution.tier3}%</div>
|
|
935
|
-
</div>
|
|
936
|
-
<div class="insight-card insight-info">
|
|
937
|
-
<h3>Current Tier</h3>
|
|
938
|
-
<div style="font-size: 1.5rem; font-weight: bold;">
|
|
939
|
-
Tier ${dashboard.overview.current_tier || 'N/A'}
|
|
940
|
-
</div>
|
|
941
|
-
<div>Mode: ${dashboard.overview.mode || 'N/A'}</div>
|
|
942
|
-
</div>
|
|
943
|
-
</div>
|
|
944
|
-
</div>
|
|
945
|
-
|
|
946
|
-
<!-- Metrics Section -->
|
|
947
|
-
<div class="metrics-grid">
|
|
948
|
-
${Object.keys(dashboard.metrics)
|
|
949
|
-
.map((metric) => {
|
|
950
|
-
const metricInfo = dashboard.metrics[metric];
|
|
951
|
-
const metricConfig = DASHBOARD_METRICS[metric];
|
|
952
|
-
const statusClass = `metric-card ${metricInfo.status === 'passing' ? 'success' : metricInfo.status === 'warning' ? 'warning' : 'danger'}`;
|
|
953
|
-
|
|
954
|
-
return `
|
|
955
|
-
<div class="${statusClass}">
|
|
956
|
-
<div class="metric-header">
|
|
957
|
-
<h3 class="metric-title">${metricConfig.name}</h3>
|
|
958
|
-
<span class="trend-indicator trend-${metricInfo.trend}">
|
|
959
|
-
${metricInfo.trend === 'improving' ? 'ā' : metricInfo.trend === 'declining' ? 'ā' : 'ā'} ${metricInfo.trend}
|
|
960
|
-
</span>
|
|
961
|
-
</div>
|
|
962
|
-
<div class="metric-value">${metricInfo.current}</div>
|
|
963
|
-
<div class="metric-target">Target: ${metricInfo.target}</div>
|
|
964
|
-
<div class="metric-status status-${metricInfo.status}">
|
|
965
|
-
${metricInfo.status}
|
|
966
|
-
</div>
|
|
967
|
-
</div>
|
|
968
|
-
`;
|
|
969
|
-
})
|
|
970
|
-
.join('')}
|
|
971
|
-
</div>
|
|
972
|
-
|
|
973
|
-
<!-- Insights Section -->
|
|
974
|
-
<div class="insights-section">
|
|
975
|
-
<h2>š” Insights</h2>
|
|
976
|
-
<div class="insights-grid">
|
|
977
|
-
${dashboard.insights
|
|
978
|
-
.map((insight) => {
|
|
979
|
-
const typeClass = `insight-card insight-${insight.type}`;
|
|
980
|
-
|
|
981
|
-
return `
|
|
982
|
-
<div class="${typeClass}">
|
|
983
|
-
<h4>${DASHBOARD_METRICS[insight.metric]?.name || insight.metric}</h4>
|
|
984
|
-
<p>${insight.message}</p>
|
|
985
|
-
</div>
|
|
986
|
-
`;
|
|
987
|
-
})
|
|
988
|
-
.join('')}
|
|
989
|
-
</div>
|
|
990
|
-
</div>
|
|
991
|
-
|
|
992
|
-
<!-- Recommendations Section -->
|
|
993
|
-
<div class="recommendations-section">
|
|
994
|
-
<h2>šÆ Recommendations</h2>
|
|
995
|
-
${dashboard.recommendations
|
|
996
|
-
.map((rec) => {
|
|
997
|
-
const priorityClass = `recommendation priority-${rec.priority}`;
|
|
998
|
-
|
|
999
|
-
return `
|
|
1000
|
-
<div class="${priorityClass}">
|
|
1001
|
-
<div class="recommendation-header">
|
|
1002
|
-
<span class="recommendation-title">${rec.message}</span>
|
|
1003
|
-
<span class="priority-badge">${rec.priority}</span>
|
|
1004
|
-
</div>
|
|
1005
|
-
<ul class="actions-list">
|
|
1006
|
-
${rec.actions.map((action) => `<li>${action}</li>`).join('')}
|
|
1007
|
-
</ul>
|
|
1008
|
-
</div>
|
|
1009
|
-
`;
|
|
1010
|
-
})
|
|
1011
|
-
.join('')}
|
|
1012
|
-
</div>
|
|
1013
|
-
</div>
|
|
1014
|
-
|
|
1015
|
-
<div class="footer">
|
|
1016
|
-
Generated by CAWS Dashboard Tool v${dashboard.metadata.version}
|
|
1017
|
-
</div>
|
|
1018
|
-
</body>
|
|
1019
|
-
</html>`;
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
// CLI interface
|
|
1023
|
-
if (require.main === module) {
|
|
1024
|
-
const command = process.argv[2];
|
|
1025
|
-
|
|
1026
|
-
switch (command) {
|
|
1027
|
-
case 'generate':
|
|
1028
|
-
const projectDir = process.argv[3] || process.cwd();
|
|
1029
|
-
const outputFormat = process.argv[4] || 'html';
|
|
1030
|
-
const outputPath = process.argv[5] || 'caws-dashboard.html';
|
|
1031
|
-
|
|
1032
|
-
try {
|
|
1033
|
-
const dashboard = generateDashboardData(projectDir);
|
|
1034
|
-
|
|
1035
|
-
if (outputFormat === 'html') {
|
|
1036
|
-
generateHTMLDashboard(dashboard, outputPath);
|
|
1037
|
-
} else if (outputFormat === 'json') {
|
|
1038
|
-
fs.writeFileSync(outputPath, JSON.stringify(dashboard, null, 2));
|
|
1039
|
-
console.log(`ā
Generated JSON dashboard: ${outputPath}`);
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
console.log('\nš Dashboard Summary:');
|
|
1043
|
-
console.log(` Trust Score: ${dashboard.overview.trust_score}/100`);
|
|
1044
|
-
console.log(` Status: ${dashboard.metrics.TRUST_SCORE.status}`);
|
|
1045
|
-
console.log(` Trend: ${dashboard.metrics.TRUST_SCORE.trend}`);
|
|
1046
|
-
|
|
1047
|
-
if (dashboard.insights.length > 0) {
|
|
1048
|
-
console.log('\nš” Key Insights:');
|
|
1049
|
-
dashboard.insights.forEach((insight) => {
|
|
1050
|
-
console.log(` - ${insight.message}`);
|
|
1051
|
-
});
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
if (dashboard.recommendations.length > 0) {
|
|
1055
|
-
console.log('\nšÆ Top Recommendations:');
|
|
1056
|
-
const topRecs = dashboard.recommendations.slice(0, 3);
|
|
1057
|
-
topRecs.forEach((rec) => {
|
|
1058
|
-
console.log(` - [${rec.priority.toUpperCase()}] ${rec.message}`);
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
|
-
} catch (error) {
|
|
1062
|
-
console.error(`ā Error generating dashboard: ${error.message}`);
|
|
1063
|
-
process.exit(1);
|
|
1064
|
-
}
|
|
1065
|
-
break;
|
|
1066
|
-
|
|
1067
|
-
case 'metrics':
|
|
1068
|
-
const metricsDir = process.argv[3] || process.cwd();
|
|
1069
|
-
|
|
1070
|
-
try {
|
|
1071
|
-
const dashboard = generateDashboardData(metricsDir);
|
|
1072
|
-
|
|
1073
|
-
console.log('\nš CAWS Metrics Summary:');
|
|
1074
|
-
Object.keys(dashboard.metrics).forEach((metric) => {
|
|
1075
|
-
const metricInfo = dashboard.metrics[metric];
|
|
1076
|
-
const metricConfig = DASHBOARD_METRICS[metric];
|
|
1077
|
-
const status =
|
|
1078
|
-
metricInfo.status === 'passing' ? 'ā
' : metricInfo.status === 'warning' ? 'ā ļø' : 'ā';
|
|
1079
|
-
|
|
1080
|
-
console.log(
|
|
1081
|
-
`${status} ${metricConfig.name}: ${metricInfo.current}/${metricInfo.target} (${metricInfo.trend})`
|
|
1082
|
-
);
|
|
1083
|
-
});
|
|
1084
|
-
} catch (error) {
|
|
1085
|
-
console.error(`ā Error getting metrics: ${error.message}`);
|
|
1086
|
-
process.exit(1);
|
|
1087
|
-
}
|
|
1088
|
-
break;
|
|
1089
|
-
|
|
1090
|
-
default:
|
|
1091
|
-
console.log('CAWS Dashboard and Analytics Tool');
|
|
1092
|
-
console.log('Usage:');
|
|
1093
|
-
console.log(' node dashboard.js generate [project-dir] [format] [output-path]');
|
|
1094
|
-
console.log(' node dashboard.js metrics [project-dir]');
|
|
1095
|
-
console.log('');
|
|
1096
|
-
console.log('Formats:');
|
|
1097
|
-
console.log(' - html: Interactive HTML dashboard (default)');
|
|
1098
|
-
console.log(' - json: JSON data for external processing');
|
|
1099
|
-
console.log('');
|
|
1100
|
-
console.log('Examples:');
|
|
1101
|
-
console.log(' node dashboard.js generate . html dashboard.html');
|
|
1102
|
-
console.log(' node dashboard.js generate . json metrics.json');
|
|
1103
|
-
console.log(' node dashboard.js metrics .');
|
|
1104
|
-
process.exit(1);
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
module.exports = {
|
|
1109
|
-
generateDashboardData,
|
|
1110
|
-
generateHTMLDashboard,
|
|
1111
|
-
DASHBOARD_METRICS,
|
|
1112
|
-
};
|