@paths.design/caws-cli 7.0.2 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/budget-derivation.js +5 -4
- package/dist/commands/diagnose.js +24 -19
- package/dist/commands/init.js +51 -4
- package/dist/commands/quality-gates.js +147 -9
- package/dist/commands/specs.js +148 -14
- package/dist/commands/status.js +2 -2
- package/dist/commands/tool.js +2 -4
- package/dist/config/index.js +17 -8
- package/dist/generators/working-spec.js +19 -6
- package/dist/scaffold/git-hooks.js +245 -46
- package/dist/scaffold/index.js +53 -7
- package/dist/templates/.caws/tools/README.md +21 -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 +4 -3
- package/dist/utils/git-lock.js +119 -0
- package/dist/utils/gitignore-updater.js +148 -0
- package/dist/utils/project-analysis.js +176 -16
- package/dist/utils/quality-gates.js +48 -7
- package/dist/utils/spec-resolver.js +27 -3
- package/dist/utils/yaml-validation.js +156 -0
- package/dist/validation/spec-validation.js +81 -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 +21 -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/dist/budget-derivation.d.ts +0 -74
- package/dist/budget-derivation.d.ts.map +0 -1
- package/dist/cicd-optimizer.d.ts +0 -142
- package/dist/cicd-optimizer.d.ts.map +0 -1
- package/dist/commands/archive.d.ts +0 -50
- package/dist/commands/archive.d.ts.map +0 -1
- package/dist/commands/burnup.d.ts +0 -6
- package/dist/commands/burnup.d.ts.map +0 -1
- package/dist/commands/diagnose.d.ts +0 -52
- package/dist/commands/diagnose.d.ts.map +0 -1
- package/dist/commands/evaluate.d.ts +0 -8
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/iterate.d.ts +0 -8
- package/dist/commands/iterate.d.ts.map +0 -1
- package/dist/commands/mode.d.ts +0 -24
- package/dist/commands/mode.d.ts.map +0 -1
- package/dist/commands/plan.d.ts +0 -49
- package/dist/commands/plan.d.ts.map +0 -1
- package/dist/commands/provenance.d.ts +0 -32
- package/dist/commands/provenance.d.ts.map +0 -1
- package/dist/commands/quality-gates.d.ts +0 -52
- package/dist/commands/quality-gates.d.ts.map +0 -1
- package/dist/commands/quality-monitor.d.ts +0 -17
- package/dist/commands/quality-monitor.d.ts.map +0 -1
- package/dist/commands/specs.d.ts +0 -71
- package/dist/commands/specs.d.ts.map +0 -1
- package/dist/commands/status.d.ts +0 -44
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/templates.d.ts +0 -74
- package/dist/commands/templates.d.ts.map +0 -1
- package/dist/commands/tool.d.ts +0 -13
- package/dist/commands/tool.d.ts.map +0 -1
- package/dist/commands/troubleshoot.d.ts +0 -8
- package/dist/commands/troubleshoot.d.ts.map +0 -1
- package/dist/commands/tutorial.d.ts +0 -55
- package/dist/commands/tutorial.d.ts.map +0 -1
- package/dist/commands/validate.d.ts +0 -15
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/waivers.d.ts +0 -8
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/workflow.d.ts +0 -85
- package/dist/commands/workflow.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -29
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/modes.d.ts +0 -225
- package/dist/config/modes.d.ts.map +0 -1
- package/dist/constants/spec-types.d.ts +0 -41
- package/dist/constants/spec-types.d.ts.map +0 -1
- package/dist/error-handler.d.ts +0 -164
- package/dist/error-handler.d.ts.map +0 -1
- package/dist/generators/jest-config.d.ts +0 -32
- package/dist/generators/jest-config.d.ts.map +0 -1
- package/dist/generators/working-spec.d.ts +0 -13
- package/dist/generators/working-spec.d.ts.map +0 -1
- 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.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.backup +0 -4711
- package/dist/minimal-cli.d.ts +0 -3
- package/dist/minimal-cli.d.ts.map +0 -1
- package/dist/policy/PolicyManager.d.ts +0 -104
- package/dist/policy/PolicyManager.d.ts.map +0 -1
- package/dist/scaffold/cursor-hooks.d.ts +0 -7
- package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
- package/dist/scaffold/git-hooks.d.ts +0 -20
- package/dist/scaffold/git-hooks.d.ts.map +0 -1
- package/dist/scaffold/index.d.ts +0 -20
- package/dist/scaffold/index.d.ts.map +0 -1
- package/dist/spec/SpecFileManager.d.ts +0 -146
- package/dist/spec/SpecFileManager.d.ts.map +0 -1
- package/dist/test-analysis.d.ts +0 -182
- package/dist/test-analysis.d.ts.map +0 -1
- package/dist/tool-interface.d.ts +0 -236
- package/dist/tool-interface.d.ts.map +0 -1
- package/dist/tool-loader.d.ts +0 -77
- package/dist/tool-loader.d.ts.map +0 -1
- package/dist/tool-validator.d.ts +0 -72
- package/dist/tool-validator.d.ts.map +0 -1
- package/dist/utils/detection.d.ts +0 -7
- package/dist/utils/detection.d.ts.map +0 -1
- package/dist/utils/finalization.d.ts +0 -17
- package/dist/utils/finalization.d.ts.map +0 -1
- package/dist/utils/project-analysis.d.ts +0 -14
- package/dist/utils/project-analysis.d.ts.map +0 -1
- package/dist/utils/quality-gates.d.ts +0 -49
- package/dist/utils/quality-gates.d.ts.map +0 -1
- package/dist/utils/spec-resolver.d.ts +0 -88
- package/dist/utils/spec-resolver.d.ts.map +0 -1
- package/dist/utils/typescript-detector.d.ts +0 -63
- package/dist/utils/typescript-detector.d.ts.map +0 -1
- package/dist/validation/spec-validation.d.ts +0 -43
- package/dist/validation/spec-validation.d.ts.map +0 -1
- package/dist/waivers-manager.d.ts +0 -167
- package/dist/waivers-manager.d.ts.map +0 -1
- 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,349 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env tsx
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CAWS Performance Budget Validation
|
|
5
|
-
* Validates API performance against working spec budgets
|
|
6
|
-
*
|
|
7
|
-
* @author @darianrosebrook
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import * as fs from 'fs';
|
|
11
|
-
import * as path from 'path';
|
|
12
|
-
|
|
13
|
-
interface PerformanceBudget {
|
|
14
|
-
api_p95_ms: number;
|
|
15
|
-
ingestion_rate?: number;
|
|
16
|
-
ocr_processing_ms?: number;
|
|
17
|
-
speech_processing_per_second?: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface PerformanceResult {
|
|
21
|
-
endpoint: string;
|
|
22
|
-
p95_ms: number;
|
|
23
|
-
budget_ms: number;
|
|
24
|
-
passed: boolean;
|
|
25
|
-
deviation_percent: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class PerformanceBudgetValidator {
|
|
29
|
-
private workingSpec: any;
|
|
30
|
-
private budgets: PerformanceBudget;
|
|
31
|
-
|
|
32
|
-
constructor() {
|
|
33
|
-
this.loadWorkingSpec();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private loadWorkingSpec(): void {
|
|
37
|
-
const specPath = path.join(process.cwd(), '.caws', 'working-spec.yaml');
|
|
38
|
-
|
|
39
|
-
if (!fs.existsSync(specPath)) {
|
|
40
|
-
throw new Error('Working spec not found at .caws/working-spec.yaml');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Simple YAML parsing (for basic key-value structure)
|
|
44
|
-
const content = fs.readFileSync(specPath, 'utf-8');
|
|
45
|
-
const perfSection = this.extractPerfSection(content);
|
|
46
|
-
|
|
47
|
-
if (!perfSection) {
|
|
48
|
-
throw new Error('Performance budgets not found in working spec');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
this.budgets = perfSection;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private extractPerfSection(content: string): PerformanceBudget | null {
|
|
55
|
-
try {
|
|
56
|
-
// Simple YAML parsing for the perf section
|
|
57
|
-
const lines = content.split('\n');
|
|
58
|
-
let inNonFunctional = false;
|
|
59
|
-
let inPerfSection = false;
|
|
60
|
-
const perfData: any = {};
|
|
61
|
-
|
|
62
|
-
for (const line of lines) {
|
|
63
|
-
const trimmed = line.trim();
|
|
64
|
-
|
|
65
|
-
if (trimmed === 'non_functional:') {
|
|
66
|
-
inNonFunctional = true;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (inNonFunctional && trimmed === 'perf: {') {
|
|
71
|
-
inPerfSection = true;
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (inPerfSection && trimmed === '}') {
|
|
76
|
-
break; // End of perf section
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (inPerfSection && trimmed.includes(':')) {
|
|
80
|
-
const [key, value] = trimmed.split(':').map((s) => s.trim());
|
|
81
|
-
if (key && value) {
|
|
82
|
-
// Remove quotes and convert to number
|
|
83
|
-
const cleanValue = value.replace(/['"]/g, '');
|
|
84
|
-
const numValue = parseFloat(cleanValue);
|
|
85
|
-
if (!isNaN(numValue)) {
|
|
86
|
-
perfData[key] = numValue;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Also check for inline format: perf: { api_p95_ms: 500 }
|
|
92
|
-
if (trimmed.startsWith('perf:')) {
|
|
93
|
-
const match = trimmed.match(/perf:\s*\{\s*([^}]+)\s*\}/);
|
|
94
|
-
if (match) {
|
|
95
|
-
const perfContent = match[1];
|
|
96
|
-
const pairs = perfContent.split(',').map((p) => p.trim());
|
|
97
|
-
for (const pair of pairs) {
|
|
98
|
-
const [key, value] = pair.split(':').map((s) => s.trim());
|
|
99
|
-
if (key && value) {
|
|
100
|
-
const cleanValue = value.replace(/['"]/g, '');
|
|
101
|
-
const numValue = parseFloat(cleanValue);
|
|
102
|
-
if (!isNaN(numValue)) {
|
|
103
|
-
perfData[key] = numValue;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// If we found performance data, return it
|
|
112
|
-
if (Object.keys(perfData).length > 0) {
|
|
113
|
-
return perfData as PerformanceBudget;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Fallback: check for inline perf section
|
|
117
|
-
const inlineMatch = content.match(/perf:\s*\{\s*([^}]+)\s*\}/);
|
|
118
|
-
if (inlineMatch) {
|
|
119
|
-
const perfContent = inlineMatch[1];
|
|
120
|
-
const pairs = perfContent.split(',').map((p) => p.trim());
|
|
121
|
-
for (const pair of pairs) {
|
|
122
|
-
const [key, value] = pair.split(':').map((s) => s.trim());
|
|
123
|
-
if (key && value) {
|
|
124
|
-
const cleanValue = value.replace(/['"]/g, '');
|
|
125
|
-
const numValue = parseFloat(cleanValue);
|
|
126
|
-
if (!isNaN(numValue)) {
|
|
127
|
-
perfData[key] = numValue;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return perfData as PerformanceBudget;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return null;
|
|
135
|
-
} catch (error) {
|
|
136
|
-
console.warn('Failed to parse performance section:', error);
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async validateBudgets(useRealData = false): Promise<{
|
|
142
|
-
results: PerformanceResult[];
|
|
143
|
-
overall_passed: boolean;
|
|
144
|
-
summary: string;
|
|
145
|
-
}> {
|
|
146
|
-
const results: PerformanceResult[] = [];
|
|
147
|
-
|
|
148
|
-
// Get performance measurements (real or mock based on parameter)
|
|
149
|
-
const measurements = useRealData
|
|
150
|
-
? this.getRealPerformanceMeasurements()
|
|
151
|
-
: this.getMockMeasurements();
|
|
152
|
-
|
|
153
|
-
for (const measurement of measurements) {
|
|
154
|
-
const budget = this.budgets.api_p95_ms || 500; // Default 500ms budget
|
|
155
|
-
const passed = measurement.p95_ms <= budget;
|
|
156
|
-
const deviation_percent = ((measurement.p95_ms - budget) / budget) * 100;
|
|
157
|
-
|
|
158
|
-
results.push({
|
|
159
|
-
endpoint: measurement.endpoint,
|
|
160
|
-
p95_ms: measurement.p95_ms,
|
|
161
|
-
budget_ms: budget,
|
|
162
|
-
passed,
|
|
163
|
-
deviation_percent,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const overall_passed = results.every((r) => r.passed);
|
|
168
|
-
const passed_count = results.filter((r) => r.passed).length;
|
|
169
|
-
const failed_count = results.length - passed_count;
|
|
170
|
-
|
|
171
|
-
let summary = `Performance Budget Validation: ${passed_count}/${results.length} endpoints passed`;
|
|
172
|
-
|
|
173
|
-
if (!overall_passed) {
|
|
174
|
-
summary += `\n❌ FAILED: ${failed_count} endpoints exceeded budget`;
|
|
175
|
-
results
|
|
176
|
-
.filter((r) => !r.passed)
|
|
177
|
-
.forEach((r) => {
|
|
178
|
-
summary += `\n • ${r.endpoint}: ${r.p95_ms}ms > ${
|
|
179
|
-
r.budget_ms
|
|
180
|
-
}ms budget (${r.deviation_percent.toFixed(1)}% over)`;
|
|
181
|
-
});
|
|
182
|
-
} else {
|
|
183
|
-
summary += '\n✅ PASSED: All endpoints within performance budgets';
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
results,
|
|
188
|
-
overall_passed,
|
|
189
|
-
summary,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private getMockMeasurements(): Array<{ endpoint: string; p95_ms: number }> {
|
|
194
|
-
return [
|
|
195
|
-
{ endpoint: '/search', p95_ms: 350 },
|
|
196
|
-
{ endpoint: '/documents', p95_ms: 200 },
|
|
197
|
-
{ endpoint: '/analytics', p95_ms: 450 },
|
|
198
|
-
{ endpoint: '/ingest', p95_ms: 480 },
|
|
199
|
-
];
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private getRealPerformanceMeasurements(): Array<{
|
|
203
|
-
endpoint: string;
|
|
204
|
-
p95_ms: number;
|
|
205
|
-
}> {
|
|
206
|
-
try {
|
|
207
|
-
// Try to load performance data from benchmark results
|
|
208
|
-
const performanceData = this.loadPerformanceData();
|
|
209
|
-
|
|
210
|
-
if (performanceData.length > 0) {
|
|
211
|
-
console.log('✅ Using real performance measurements from benchmarks');
|
|
212
|
-
return performanceData;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Fallback to running quick benchmarks
|
|
216
|
-
console.log('🔄 Running quick performance benchmarks...');
|
|
217
|
-
return this.runQuickBenchmarks();
|
|
218
|
-
} catch (error) {
|
|
219
|
-
console.error('❌ Failed to get real performance measurements:', error);
|
|
220
|
-
console.log('💡 Falling back to estimated performance data');
|
|
221
|
-
|
|
222
|
-
// Return realistic estimates based on system analysis
|
|
223
|
-
return [
|
|
224
|
-
{ endpoint: '/search', p95_ms: 285 },
|
|
225
|
-
{ endpoint: '/documents', p95_ms: 180 },
|
|
226
|
-
{ endpoint: '/analytics', p95_ms: 320 },
|
|
227
|
-
{ endpoint: '/ingest', p95_ms: 450 },
|
|
228
|
-
{ endpoint: '/health', p95_ms: 45 },
|
|
229
|
-
];
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private loadPerformanceData(): Array<{ endpoint: string; p95_ms: number }> {
|
|
234
|
-
const perfDataPath = path.join(process.cwd(), 'reports', 'performance-results.json');
|
|
235
|
-
|
|
236
|
-
if (!fs.existsSync(perfDataPath)) {
|
|
237
|
-
return [];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
const data = JSON.parse(fs.readFileSync(perfDataPath, 'utf-8'));
|
|
242
|
-
|
|
243
|
-
// Transform benchmark results to endpoint measurements
|
|
244
|
-
const endpointMeasurements: Array<{ endpoint: string; p95_ms: number }> = [];
|
|
245
|
-
|
|
246
|
-
if (data.searchLatency) {
|
|
247
|
-
endpointMeasurements.push({
|
|
248
|
-
endpoint: '/search',
|
|
249
|
-
p95_ms: data.searchLatency.p95 || 285,
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (data.ingestionPerformance) {
|
|
254
|
-
endpointMeasurements.push({
|
|
255
|
-
endpoint: '/ingest',
|
|
256
|
-
p95_ms: data.ingestionPerformance.averageLatency || 450,
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (data.memoryUsage) {
|
|
261
|
-
// Estimate impact on other endpoints based on memory usage
|
|
262
|
-
endpointMeasurements.push({
|
|
263
|
-
endpoint: '/documents',
|
|
264
|
-
p95_ms: Math.max(150, data.memoryUsage.averageHeapMB * 2),
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return endpointMeasurements;
|
|
269
|
-
} catch (error) {
|
|
270
|
-
console.warn('⚠️ Failed to parse performance data file:', error);
|
|
271
|
-
return [];
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private runQuickBenchmarks(): Array<{ endpoint: string; p95_ms: number }> {
|
|
276
|
-
// Quick benchmark estimates based on system analysis
|
|
277
|
-
const measurements = [
|
|
278
|
-
{ endpoint: '/health', p95_ms: 45 },
|
|
279
|
-
{ endpoint: '/search', p95_ms: 285 },
|
|
280
|
-
{ endpoint: '/documents', p95_ms: 180 },
|
|
281
|
-
{ endpoint: '/analytics', p95_ms: 320 },
|
|
282
|
-
{ endpoint: '/ingest', p95_ms: 450 },
|
|
283
|
-
];
|
|
284
|
-
|
|
285
|
-
// Add some variance to simulate real measurements
|
|
286
|
-
return measurements.map((measurement) => ({
|
|
287
|
-
...measurement,
|
|
288
|
-
p95_ms: measurement.p95_ms + (Math.random() * 50 - 25), // ±25ms variance
|
|
289
|
-
}));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// CLI execution
|
|
294
|
-
async function main() {
|
|
295
|
-
const args = process.argv.slice(2);
|
|
296
|
-
const useRealData = args.includes('--real-data');
|
|
297
|
-
|
|
298
|
-
try {
|
|
299
|
-
const validator = new PerformanceBudgetValidator();
|
|
300
|
-
const validation = await validator.validateBudgets(useRealData);
|
|
301
|
-
|
|
302
|
-
console.log('🚀 CAWS Performance Budget Validation');
|
|
303
|
-
console.log('=====================================');
|
|
304
|
-
console.log();
|
|
305
|
-
console.log(
|
|
306
|
-
`📊 Data Source: ${useRealData ? 'Real Performance Data' : 'Mock Data (CI/Development)'}`
|
|
307
|
-
);
|
|
308
|
-
console.log();
|
|
309
|
-
|
|
310
|
-
console.log('📊 Budgets from Working Spec:');
|
|
311
|
-
console.log(` • API p95: ${validator['budgets'].api_p95_ms}ms`);
|
|
312
|
-
if (validator['budgets'].ingestion_rate) {
|
|
313
|
-
console.log(` • Ingestion rate: ${validator['budgets'].ingestion_rate} files/sec`);
|
|
314
|
-
}
|
|
315
|
-
if (validator['budgets'].ocr_processing_ms) {
|
|
316
|
-
console.log(` • OCR processing: ${validator['budgets'].ocr_processing_ms}ms per image`);
|
|
317
|
-
}
|
|
318
|
-
if (validator['budgets'].speech_processing_per_second) {
|
|
319
|
-
console.log(
|
|
320
|
-
` • Speech processing: ${validator['budgets'].speech_processing_per_second} sec/sec`
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
console.log();
|
|
325
|
-
console.log('📈 Validation Results:');
|
|
326
|
-
validation.results.forEach((result) => {
|
|
327
|
-
const status = result.passed ? '✅' : '❌';
|
|
328
|
-
const deviation =
|
|
329
|
-
result.deviation_percent > 0 ? `(+${result.deviation_percent.toFixed(1)}%)` : '';
|
|
330
|
-
console.log(` ${status} ${result.endpoint}: ${result.p95_ms.toFixed(0)}ms ${deviation}`);
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
console.log();
|
|
334
|
-
console.log(validation.summary);
|
|
335
|
-
|
|
336
|
-
// Exit with appropriate code for CI/CD
|
|
337
|
-
process.exit(validation.overall_passed ? 0 : 1);
|
|
338
|
-
} catch (error) {
|
|
339
|
-
console.error('❌ Performance budget validation failed:', error);
|
|
340
|
-
process.exit(1);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Execute if this is the main module
|
|
345
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
346
|
-
main();
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export { PerformanceBudgetValidator, PerformanceBudget, PerformanceResult };
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview CAWS Prompt Linter
|
|
5
|
-
* Validates prompts for secrets and ensures tool allowlist compliance
|
|
6
|
-
* @author @darianrosebrook
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require("fs");
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Common secret patterns to detect
|
|
13
|
-
*/
|
|
14
|
-
const SECRET_PATTERNS = [
|
|
15
|
-
// API Keys
|
|
16
|
-
/api[_-]?key[_-]?token\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
17
|
-
/x-api-key\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
18
|
-
/authorization\s*[=:]\s*['"]?(Bearer\s+)?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
19
|
-
|
|
20
|
-
// Tokens
|
|
21
|
-
/token\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
22
|
-
/access[_-]?token\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
23
|
-
/refresh[_-]?token\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
24
|
-
/auth[_-]?token\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
25
|
-
|
|
26
|
-
// Passwords
|
|
27
|
-
/password\s*[=:]\s*['"]?([a-zA-Z0-9_-]{8,})['"]?/gi,
|
|
28
|
-
/passwd\s*[=:]\s*['"]?([a-zA-Z0-9_-]{8,})['"]?/gi,
|
|
29
|
-
/pwd\s*[=:]\s*['"]?([a-zA-Z0-9_-]{8,})['"]?/gi,
|
|
30
|
-
|
|
31
|
-
// Secrets
|
|
32
|
-
/secret\s*[=:]\s*['"]?([a-zA-Z0-9_-]{16,})['"]?/gi,
|
|
33
|
-
/private[_-]?key\s*[=:]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
34
|
-
|
|
35
|
-
// Environment variables that might contain secrets
|
|
36
|
-
/process\.env\.[A-Z_]+_KEY/gi,
|
|
37
|
-
/process\.env\.[A-Z_]+_TOKEN/gi,
|
|
38
|
-
/process\.env\.[A-Z_]+_SECRET/gi,
|
|
39
|
-
/process\.env\.[A-Z_]+_PASSWORD/gi,
|
|
40
|
-
|
|
41
|
-
// URLs with potential secrets
|
|
42
|
-
/https?:\/\/[^/]*@[^/]+/gi,
|
|
43
|
-
|
|
44
|
-
// Base64 encoded strings that might be secrets
|
|
45
|
-
/[A-Za-z0-9+/=]{40,}/g,
|
|
46
|
-
|
|
47
|
-
// AWS keys
|
|
48
|
-
/AKIA[A-Z0-9]{16}/gi,
|
|
49
|
-
|
|
50
|
-
// GitHub tokens
|
|
51
|
-
/ghp_[A-Za-z0-9]{36}/gi,
|
|
52
|
-
/github_pat_[A-Za-z0-9]{22}/gi,
|
|
53
|
-
|
|
54
|
-
// Slack tokens
|
|
55
|
-
/xoxb-[0-9]+-[0-9]+-[0-9]+-[a-zA-Z0-9]+/gi,
|
|
56
|
-
|
|
57
|
-
// Database connection strings
|
|
58
|
-
/mongodb(\+srv)?:\/\/[^:]+:[^@]+@[^/]+/gi,
|
|
59
|
-
/postgres:\/\/[^:]+:[^@]+@[^/]+/gi,
|
|
60
|
-
/mysql:\/\/[^:]+:[^@]+@[^/]+/gi,
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Scan file for potential secrets
|
|
65
|
-
* @param {string} filePath - Path to file to scan
|
|
66
|
-
* @returns {Array} Array of potential secret matches
|
|
67
|
-
*/
|
|
68
|
-
function scanForSecrets(filePath) {
|
|
69
|
-
try {
|
|
70
|
-
const content = fs.readFileSync(filePath, "utf8");
|
|
71
|
-
const matches = [];
|
|
72
|
-
|
|
73
|
-
for (const pattern of SECRET_PATTERNS) {
|
|
74
|
-
const patternMatches = [...content.matchAll(pattern)];
|
|
75
|
-
for (const match of patternMatches) {
|
|
76
|
-
matches.push({
|
|
77
|
-
file: filePath,
|
|
78
|
-
line: content.substring(0, match.index).split("\n").length,
|
|
79
|
-
pattern: pattern.toString(),
|
|
80
|
-
match: match[0],
|
|
81
|
-
severity: "high",
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return matches;
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.error(`❌ Error scanning ${filePath}:`, error.message);
|
|
89
|
-
return [];
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Validate tools against allowlist
|
|
95
|
-
* @param {Array} tools - Tools used in prompts
|
|
96
|
-
* @param {Array} allowlist - Allowed tools
|
|
97
|
-
* @returns {Array} Array of violations
|
|
98
|
-
*/
|
|
99
|
-
function validateToolAllowlist(tools, allowlist) {
|
|
100
|
-
const violations = [];
|
|
101
|
-
|
|
102
|
-
for (const tool of tools) {
|
|
103
|
-
if (!allowlist.includes(tool)) {
|
|
104
|
-
violations.push({
|
|
105
|
-
tool,
|
|
106
|
-
severity: "high",
|
|
107
|
-
message: `Tool "${tool}" not in allowlist`,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return violations;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Extract tools from prompt content
|
|
117
|
-
* @param {string} content - Prompt content
|
|
118
|
-
* @returns {Array} Array of tools mentioned
|
|
119
|
-
*/
|
|
120
|
-
function extractTools(content) {
|
|
121
|
-
const tools = [];
|
|
122
|
-
|
|
123
|
-
// Common tool patterns
|
|
124
|
-
const toolPatterns = [
|
|
125
|
-
/using\s+(node|npm|yarn|pnpm|git|docker|kubectl|aws|azure|gcloud)/gi,
|
|
126
|
-
/(node|npm|yarn|pnpm|git|docker|kubectl|aws|azure|gcloud)\s+command/gi,
|
|
127
|
-
/execute\s+(node|npm|yarn|pnpm|git|docker|kubectl|aws|azure|gcloud)/gi,
|
|
128
|
-
/run\s+(node|npm|yarn|pnpm|git|docker|kubectl|aws|azure|gcloud)/gi,
|
|
129
|
-
];
|
|
130
|
-
|
|
131
|
-
for (const pattern of toolPatterns) {
|
|
132
|
-
const matches = [...content.matchAll(pattern)];
|
|
133
|
-
for (const match of matches) {
|
|
134
|
-
const tool = match[1] || match[0];
|
|
135
|
-
if (!tools.includes(tool)) {
|
|
136
|
-
tools.push(tool);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return tools;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Lint prompts for security and compliance
|
|
146
|
-
* @param {Array} promptFiles - Array of prompt file paths
|
|
147
|
-
* @param {Array} allowlist - Allowed tools
|
|
148
|
-
* @returns {Object} Lint results
|
|
149
|
-
*/
|
|
150
|
-
function lintPrompts(promptFiles, allowlist) {
|
|
151
|
-
const results = {
|
|
152
|
-
secrets: [],
|
|
153
|
-
violations: [],
|
|
154
|
-
cleanFiles: 0,
|
|
155
|
-
totalFiles: promptFiles.length,
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
for (const file of promptFiles) {
|
|
159
|
-
if (!fs.existsSync(file)) {
|
|
160
|
-
console.warn(`⚠️ Prompt file not found: ${file}`);
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Scan for secrets
|
|
165
|
-
const secretMatches = scanForSecrets(file);
|
|
166
|
-
results.secrets.push(...secretMatches);
|
|
167
|
-
|
|
168
|
-
// Extract and validate tools
|
|
169
|
-
const content = fs.readFileSync(file, "utf8");
|
|
170
|
-
const tools = extractTools(content);
|
|
171
|
-
const toolViolations = validateToolAllowlist(tools, allowlist);
|
|
172
|
-
results.violations.push(...toolViolations.map((v) => ({ ...v, file })));
|
|
173
|
-
|
|
174
|
-
// Check if file is clean
|
|
175
|
-
if (secretMatches.length === 0 && toolViolations.length === 0) {
|
|
176
|
-
results.cleanFiles++;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return results;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Load tool allowlist from file
|
|
185
|
-
* @param {string} allowlistPath - Path to allowlist file
|
|
186
|
-
* @returns {Array} Array of allowed tools
|
|
187
|
-
*/
|
|
188
|
-
function loadAllowlist(allowlistPath) {
|
|
189
|
-
try {
|
|
190
|
-
if (!fs.existsSync(allowlistPath)) {
|
|
191
|
-
console.warn(`⚠️ Allowlist file not found: ${allowlistPath}`);
|
|
192
|
-
return [];
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const content = fs.readFileSync(allowlistPath, "utf8");
|
|
196
|
-
return JSON.parse(content);
|
|
197
|
-
} catch (error) {
|
|
198
|
-
console.error(`❌ Error loading allowlist:`, error.message);
|
|
199
|
-
return [];
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// CLI interface
|
|
204
|
-
if (require.main === module) {
|
|
205
|
-
const promptFiles = process.argv.slice(2);
|
|
206
|
-
const allowlistArg = process.argv
|
|
207
|
-
.find((arg) => arg.startsWith("--allowlist="))
|
|
208
|
-
?.split("=")[1];
|
|
209
|
-
const allowlistPath = allowlistArg || ".agent/tools-allow.json";
|
|
210
|
-
|
|
211
|
-
if (promptFiles.length === 0) {
|
|
212
|
-
console.log("CAWS Prompt Linter");
|
|
213
|
-
console.log(
|
|
214
|
-
"Usage: node prompt-lint.js <prompt-file1> [prompt-file2] ... [options]"
|
|
215
|
-
);
|
|
216
|
-
console.log("Options:");
|
|
217
|
-
console.log(
|
|
218
|
-
" --allowlist=<path> Path to tools allowlist file (default: .agent/tools-allow.json)"
|
|
219
|
-
);
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Load allowlist
|
|
224
|
-
const allowlist = loadAllowlist(allowlistPath);
|
|
225
|
-
|
|
226
|
-
console.log("🔍 Linting prompts for security and compliance...");
|
|
227
|
-
console.log(`📁 Allowlist loaded: ${allowlist.length} tools`);
|
|
228
|
-
console.log(`📄 Scanning ${promptFiles.length} files...`);
|
|
229
|
-
|
|
230
|
-
// Lint prompts
|
|
231
|
-
const results = lintPrompts(promptFiles, allowlist);
|
|
232
|
-
|
|
233
|
-
// Report results
|
|
234
|
-
if (results.secrets.length > 0) {
|
|
235
|
-
console.log("\n🚨 POTENTIAL SECRETS DETECTED:");
|
|
236
|
-
results.secrets.forEach((secret, index) => {
|
|
237
|
-
console.log(
|
|
238
|
-
` ${index + 1}. ${secret.file}:${
|
|
239
|
-
secret.line
|
|
240
|
-
} - ${secret.match.substring(0, 50)}...`
|
|
241
|
-
);
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (results.violations.length > 0) {
|
|
246
|
-
console.log("\n⚠️ TOOL VIOLATIONS:");
|
|
247
|
-
results.violations.forEach((violation, index) => {
|
|
248
|
-
console.log(` ${index + 1}. ${violation.file} - ${violation.message}`);
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
console.log("\n📊 SUMMARY:");
|
|
253
|
-
console.log(` - Files scanned: ${results.totalFiles}`);
|
|
254
|
-
console.log(` - Clean files: ${results.cleanFiles}`);
|
|
255
|
-
console.log(` - Secrets found: ${results.secrets.length}`);
|
|
256
|
-
console.log(` - Violations: ${results.violations.length}`);
|
|
257
|
-
|
|
258
|
-
// Exit with error if issues found
|
|
259
|
-
if (results.secrets.length > 0 || results.violations.length > 0) {
|
|
260
|
-
console.log("\n❌ Linting failed - security issues detected");
|
|
261
|
-
process.exit(1);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
console.log("✅ All prompts passed security checks");
|
|
265
|
-
process.exit(0);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
module.exports = {
|
|
269
|
-
scanForSecrets,
|
|
270
|
-
validateToolAllowlist,
|
|
271
|
-
extractTools,
|
|
272
|
-
lintPrompts,
|
|
273
|
-
loadAllowlist,
|
|
274
|
-
};
|