@paths.design/caws-cli 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/budget-derivation.d.ts +74 -0
- package/dist/budget-derivation.d.ts.map +1 -0
- package/dist/cicd-optimizer.d.ts +142 -0
- package/dist/cicd-optimizer.d.ts.map +1 -0
- package/dist/commands/archive.d.ts +51 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +114 -6
- package/dist/commands/burnup.d.ts +6 -0
- package/dist/commands/burnup.d.ts.map +1 -0
- package/dist/commands/burnup.js +109 -10
- package/dist/commands/diagnose.d.ts +52 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +1 -1
- package/dist/commands/evaluate.d.ts +8 -0
- package/dist/commands/evaluate.d.ts.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/iterate.d.ts +8 -0
- package/dist/commands/iterate.d.ts.map +1 -0
- package/dist/commands/mode.d.ts +24 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +24 -14
- package/dist/commands/plan.d.ts +49 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/provenance.d.ts +32 -0
- package/dist/commands/provenance.d.ts.map +1 -0
- package/dist/commands/provenance.js +216 -93
- package/dist/commands/quality-gates.d.ts +6 -0
- package/dist/commands/quality-gates.d.ts.map +1 -0
- package/dist/commands/quality-gates.js +82 -3
- package/dist/commands/quality-monitor.d.ts +17 -0
- package/dist/commands/quality-monitor.d.ts.map +1 -0
- package/dist/commands/specs.d.ts +71 -0
- package/dist/commands/specs.d.ts.map +1 -0
- package/dist/commands/specs.js +184 -6
- package/dist/commands/status.d.ts +44 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +134 -10
- package/dist/commands/templates.d.ts +74 -0
- package/dist/commands/templates.d.ts.map +1 -0
- package/dist/commands/templates.js +2 -2
- package/dist/commands/tool.d.ts +13 -0
- package/dist/commands/tool.d.ts.map +1 -0
- package/dist/commands/troubleshoot.d.ts +8 -0
- package/dist/commands/troubleshoot.d.ts.map +1 -0
- package/dist/commands/tutorial.d.ts +55 -0
- package/dist/commands/tutorial.d.ts.map +1 -0
- package/dist/commands/validate.d.ts +15 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/waivers.d.ts +8 -0
- package/dist/commands/waivers.d.ts.map +1 -0
- package/dist/commands/workflow.d.ts +85 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/config/index.d.ts +29 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/modes.d.ts +225 -0
- package/dist/config/modes.d.ts.map +1 -0
- package/dist/constants/spec-types.d.ts +41 -0
- package/dist/constants/spec-types.d.ts.map +1 -0
- package/dist/error-handler.d.ts +164 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +6 -98
- package/dist/generators/jest-config-generator.js +242 -0
- package/dist/generators/jest-config.d.ts +32 -0
- package/dist/generators/jest-config.d.ts.map +1 -0
- package/dist/generators/working-spec.d.ts +13 -0
- package/dist/generators/working-spec.d.ts.map +1 -0
- package/dist/index-new.d.ts +5 -0
- package/dist/index-new.d.ts.map +1 -0
- package/dist/index-new.js +317 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -7
- package/dist/index.js.backup +4711 -0
- package/dist/minimal-cli.d.ts +3 -0
- package/dist/minimal-cli.d.ts.map +1 -0
- package/dist/minimal-cli.js +3 -1
- package/dist/policy/PolicyManager.d.ts +104 -0
- package/dist/policy/PolicyManager.d.ts.map +1 -0
- package/dist/scaffold/claude-hooks.js +316 -0
- package/dist/scaffold/cursor-hooks.d.ts +7 -0
- package/dist/scaffold/cursor-hooks.d.ts.map +1 -0
- package/dist/scaffold/git-hooks.d.ts +38 -0
- package/dist/scaffold/git-hooks.d.ts.map +1 -0
- package/dist/scaffold/index.d.ts +15 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +18 -0
- package/dist/spec/SpecFileManager.d.ts +146 -0
- package/dist/spec/SpecFileManager.d.ts.map +1 -0
- package/dist/templates/.claude/README.md +190 -0
- package/dist/templates/.claude/hooks/audit.sh +96 -0
- package/dist/templates/.claude/hooks/block-dangerous.sh +90 -0
- package/dist/templates/.claude/hooks/naming-check.sh +97 -0
- package/dist/templates/.claude/hooks/quality-check.sh +68 -0
- package/dist/templates/.claude/hooks/scan-secrets.sh +85 -0
- package/dist/templates/.claude/hooks/scope-guard.sh +105 -0
- package/dist/templates/.claude/hooks/validate-spec.sh +76 -0
- package/dist/templates/.claude/settings.json +95 -0
- package/dist/test-analysis.d.ts +182 -0
- package/dist/test-analysis.d.ts.map +1 -0
- package/dist/test-analysis.js +203 -10
- package/dist/tool-interface.d.ts +236 -0
- package/dist/tool-interface.d.ts.map +1 -0
- package/dist/tool-loader.d.ts +77 -0
- package/dist/tool-loader.d.ts.map +1 -0
- package/dist/tool-validator.d.ts +72 -0
- package/dist/tool-validator.d.ts.map +1 -0
- package/dist/utils/async-utils.d.ts +73 -0
- package/dist/utils/async-utils.d.ts.map +1 -0
- package/dist/utils/command-wrapper.d.ts +66 -0
- package/dist/utils/command-wrapper.d.ts.map +1 -0
- package/dist/utils/detection.d.ts +14 -0
- package/dist/utils/detection.d.ts.map +1 -0
- package/dist/utils/error-categories.js +210 -0
- package/dist/utils/finalization.d.ts +17 -0
- package/dist/utils/finalization.d.ts.map +1 -0
- package/dist/utils/git-lock.d.ts +13 -0
- package/dist/utils/git-lock.d.ts.map +1 -0
- package/dist/utils/gitignore-updater.d.ts +39 -0
- package/dist/utils/gitignore-updater.d.ts.map +1 -0
- package/dist/utils/project-analysis.d.ts +34 -0
- package/dist/utils/project-analysis.d.ts.map +1 -0
- package/dist/utils/promise-utils.d.ts +30 -0
- package/dist/utils/promise-utils.d.ts.map +1 -0
- package/dist/utils/quality-gates-utils.js +402 -0
- package/dist/utils/quality-gates.d.ts +49 -0
- package/dist/utils/quality-gates.d.ts.map +1 -0
- package/dist/utils/spec-resolver.d.ts +80 -0
- package/dist/utils/spec-resolver.d.ts.map +1 -0
- package/dist/utils/typescript-detector.d.ts +63 -0
- package/dist/utils/typescript-detector.d.ts.map +1 -0
- package/dist/utils/typescript-detector.js +36 -90
- package/dist/utils/yaml-validation.d.ts +32 -0
- package/dist/utils/yaml-validation.d.ts.map +1 -0
- package/dist/validation/spec-validation.d.ts +43 -0
- package/dist/validation/spec-validation.d.ts.map +1 -0
- package/dist/validation/spec-validation.js +59 -6
- package/dist/waivers-manager.d.ts +167 -0
- package/dist/waivers-manager.d.ts.map +1 -0
- package/package.json +5 -3
- package/templates/.claude/README.md +190 -0
- package/templates/.claude/hooks/audit.sh +96 -0
- package/templates/.claude/hooks/block-dangerous.sh +90 -0
- package/templates/.claude/hooks/naming-check.sh +97 -0
- package/templates/.claude/hooks/quality-check.sh +68 -0
- package/templates/.claude/hooks/scan-secrets.sh +85 -0
- package/templates/.claude/hooks/scope-guard.sh +105 -0
- package/templates/.claude/hooks/validate-spec.sh +76 -0
- package/templates/.claude/settings.json +95 -0
|
@@ -101,10 +101,40 @@ function detectTestFramework(projectDir = process.cwd(), packageJson = null) {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
104
|
+
* Expand workspace glob patterns to actual directories
|
|
105
|
+
* Shared helper for npm, pnpm, and lerna workspace resolution
|
|
106
|
+
* @param {string[]} patterns - Workspace patterns (may include globs like "packages/*")
|
|
105
107
|
* @param {string} projectDir - Project directory path
|
|
106
|
-
* @returns {string[]} Array of workspace
|
|
108
|
+
* @returns {string[]} Array of resolved workspace directory paths
|
|
107
109
|
*/
|
|
110
|
+
function expandWorkspacePatterns(patterns, projectDir) {
|
|
111
|
+
const workspaceDirs = [];
|
|
112
|
+
for (const pattern of patterns) {
|
|
113
|
+
if (pattern.includes('*')) {
|
|
114
|
+
const baseDir = pattern.split('*')[0];
|
|
115
|
+
const fullBaseDir = path.join(projectDir, baseDir);
|
|
116
|
+
|
|
117
|
+
if (fs.existsSync(fullBaseDir)) {
|
|
118
|
+
const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
|
|
119
|
+
for (const entry of entries) {
|
|
120
|
+
if (entry.isDirectory()) {
|
|
121
|
+
const wsPath = path.join(fullBaseDir, entry.name);
|
|
122
|
+
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
123
|
+
workspaceDirs.push(wsPath);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
const wsPath = path.join(projectDir, pattern);
|
|
130
|
+
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
131
|
+
workspaceDirs.push(wsPath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return workspaceDirs;
|
|
136
|
+
}
|
|
137
|
+
|
|
108
138
|
/**
|
|
109
139
|
* Get workspace directories from npm/yarn package.json workspaces
|
|
110
140
|
* @param {string} projectDir - Project directory path
|
|
@@ -120,36 +150,7 @@ function getNpmWorkspaces(projectDir) {
|
|
|
120
150
|
try {
|
|
121
151
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
122
152
|
const workspaces = packageJson.workspaces || [];
|
|
123
|
-
|
|
124
|
-
// Convert glob patterns to actual directories (simple implementation)
|
|
125
|
-
const workspaceDirs = [];
|
|
126
|
-
for (const ws of workspaces) {
|
|
127
|
-
// Handle simple patterns like "packages/*" or "iterations/*"
|
|
128
|
-
if (ws.includes('*')) {
|
|
129
|
-
const baseDir = ws.split('*')[0];
|
|
130
|
-
const fullBaseDir = path.join(projectDir, baseDir);
|
|
131
|
-
|
|
132
|
-
if (fs.existsSync(fullBaseDir)) {
|
|
133
|
-
const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
|
|
134
|
-
for (const entry of entries) {
|
|
135
|
-
if (entry.isDirectory()) {
|
|
136
|
-
const wsPath = path.join(fullBaseDir, entry.name);
|
|
137
|
-
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
138
|
-
workspaceDirs.push(wsPath);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
// Direct path
|
|
145
|
-
const wsPath = path.join(projectDir, ws);
|
|
146
|
-
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
147
|
-
workspaceDirs.push(wsPath);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return workspaceDirs;
|
|
153
|
+
return expandWorkspacePatterns(workspaces, projectDir);
|
|
153
154
|
} catch (error) {
|
|
154
155
|
return [];
|
|
155
156
|
}
|
|
@@ -171,35 +172,7 @@ function getPnpmWorkspaces(projectDir) {
|
|
|
171
172
|
const yaml = require('js-yaml');
|
|
172
173
|
const config = yaml.load(fs.readFileSync(pnpmFile, 'utf8'));
|
|
173
174
|
const workspacePatterns = config.packages || [];
|
|
174
|
-
|
|
175
|
-
// Convert glob patterns to actual directories
|
|
176
|
-
const workspaceDirs = [];
|
|
177
|
-
for (const pattern of workspacePatterns) {
|
|
178
|
-
if (pattern.includes('*')) {
|
|
179
|
-
const baseDir = pattern.split('*')[0];
|
|
180
|
-
const fullBaseDir = path.join(projectDir, baseDir);
|
|
181
|
-
|
|
182
|
-
if (fs.existsSync(fullBaseDir)) {
|
|
183
|
-
const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
|
|
184
|
-
for (const entry of entries) {
|
|
185
|
-
if (entry.isDirectory()) {
|
|
186
|
-
const wsPath = path.join(fullBaseDir, entry.name);
|
|
187
|
-
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
188
|
-
workspaceDirs.push(wsPath);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
} else {
|
|
194
|
-
// Direct path
|
|
195
|
-
const wsPath = path.join(projectDir, pattern);
|
|
196
|
-
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
197
|
-
workspaceDirs.push(wsPath);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return workspaceDirs;
|
|
175
|
+
return expandWorkspacePatterns(workspacePatterns, projectDir);
|
|
203
176
|
} catch (error) {
|
|
204
177
|
return [];
|
|
205
178
|
}
|
|
@@ -220,35 +193,7 @@ function getLernaWorkspaces(projectDir) {
|
|
|
220
193
|
try {
|
|
221
194
|
const config = JSON.parse(fs.readFileSync(lernaFile, 'utf8'));
|
|
222
195
|
const workspacePatterns = config.packages || ['packages/*'];
|
|
223
|
-
|
|
224
|
-
// Convert glob patterns to actual directories
|
|
225
|
-
const workspaceDirs = [];
|
|
226
|
-
for (const pattern of workspacePatterns) {
|
|
227
|
-
if (pattern.includes('*')) {
|
|
228
|
-
const baseDir = pattern.split('*')[0];
|
|
229
|
-
const fullBaseDir = path.join(projectDir, baseDir);
|
|
230
|
-
|
|
231
|
-
if (fs.existsSync(fullBaseDir)) {
|
|
232
|
-
const entries = fs.readdirSync(fullBaseDir, { withFileTypes: true });
|
|
233
|
-
for (const entry of entries) {
|
|
234
|
-
if (entry.isDirectory()) {
|
|
235
|
-
const wsPath = path.join(fullBaseDir, entry.name);
|
|
236
|
-
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
237
|
-
workspaceDirs.push(wsPath);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
} else {
|
|
243
|
-
// Direct path
|
|
244
|
-
const wsPath = path.join(projectDir, pattern);
|
|
245
|
-
if (fs.existsSync(path.join(wsPath, 'package.json'))) {
|
|
246
|
-
workspaceDirs.push(wsPath);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return workspaceDirs;
|
|
196
|
+
return expandWorkspacePatterns(workspacePatterns, projectDir);
|
|
252
197
|
} catch (error) {
|
|
253
198
|
return [];
|
|
254
199
|
}
|
|
@@ -416,6 +361,7 @@ module.exports = {
|
|
|
416
361
|
getNpmWorkspaces,
|
|
417
362
|
getPnpmWorkspaces,
|
|
418
363
|
getLernaWorkspaces,
|
|
364
|
+
expandWorkspacePatterns,
|
|
419
365
|
checkHoistedDependency,
|
|
420
366
|
checkTypeScriptTestConfig,
|
|
421
367
|
generateRecommendations,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate YAML syntax for a file
|
|
3
|
+
* @param {string} filePath - Path to YAML file
|
|
4
|
+
* @returns {Object} Validation result with valid flag and error details
|
|
5
|
+
*/
|
|
6
|
+
export function validateYamlSyntax(filePath: string): any;
|
|
7
|
+
/**
|
|
8
|
+
* Validate YAML syntax for multiple files
|
|
9
|
+
* @param {string[]} filePaths - Array of file paths to validate
|
|
10
|
+
* @returns {Object} Validation results with summary
|
|
11
|
+
*/
|
|
12
|
+
export function validateYamlFiles(filePaths: string[]): any;
|
|
13
|
+
/**
|
|
14
|
+
* Find all YAML files in .caws directory
|
|
15
|
+
* @param {string} projectRoot - Project root directory
|
|
16
|
+
* @returns {string[]} Array of YAML file paths
|
|
17
|
+
*/
|
|
18
|
+
export function findCawsYamlFiles(projectRoot: string): string[];
|
|
19
|
+
/**
|
|
20
|
+
* Validate all CAWS YAML files in project
|
|
21
|
+
* @param {string} projectRoot - Project root directory
|
|
22
|
+
* @returns {Object} Validation results
|
|
23
|
+
*/
|
|
24
|
+
export function validateAllCawsYamlFiles(projectRoot: string): any;
|
|
25
|
+
/**
|
|
26
|
+
* Format validation error for display
|
|
27
|
+
* @param {Object} error - Error object from validateYamlSyntax
|
|
28
|
+
* @param {string} filePath - File path
|
|
29
|
+
* @returns {string} Formatted error message
|
|
30
|
+
*/
|
|
31
|
+
export function formatYamlError(error: any, filePath: string): string;
|
|
32
|
+
//# sourceMappingURL=yaml-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yaml-validation.d.ts","sourceRoot":"","sources":["../../src/utils/yaml-validation.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,6CAHW,MAAM,OA2BhB;AAED;;;;GAIG;AACH,6CAHW,MAAM,EAAE,OAgClB;AAED;;;;GAIG;AACH,+CAHW,MAAM,GACJ,MAAM,EAAE,CA6BpB;AAED;;;;GAIG;AACH,sDAHW,MAAM,OAMhB;AAED;;;;;GAKG;AACH,sDAHW,MAAM,GACJ,MAAM,CAoBlB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic validation of working spec
|
|
3
|
+
* @param {Object} spec - Working spec object
|
|
4
|
+
* @param {Object} options - Validation options
|
|
5
|
+
* @returns {Object} Validation result
|
|
6
|
+
*/
|
|
7
|
+
export function validateWorkingSpec(spec: any, _options?: {}): any;
|
|
8
|
+
/**
|
|
9
|
+
* Enhanced validation with suggestions and auto-fix
|
|
10
|
+
* @param {Object} spec - Working spec object
|
|
11
|
+
* @param {Object} options - Validation options
|
|
12
|
+
* @returns {Object} Enhanced validation result
|
|
13
|
+
*/
|
|
14
|
+
export function validateWorkingSpecWithSuggestions(spec: any, options?: any): any;
|
|
15
|
+
/**
|
|
16
|
+
* Get suggestion for a missing field
|
|
17
|
+
* @param {string} field - Field name
|
|
18
|
+
* @param {Object} _spec - Spec object (for context)
|
|
19
|
+
* @returns {string} Suggestion text
|
|
20
|
+
*/
|
|
21
|
+
export function getFieldSuggestion(field: string, _spec: any): string;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a field can be auto-fixed
|
|
24
|
+
* @param {string} field - Field name
|
|
25
|
+
* @param {Object} _spec - Spec object (for context)
|
|
26
|
+
* @returns {boolean} Whether field can be auto-fixed
|
|
27
|
+
*/
|
|
28
|
+
export function canAutoFixField(field: string, _spec: any): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Calculate compliance score based on errors and warnings
|
|
31
|
+
* Score ranges from 0 (many issues) to 1 (perfect)
|
|
32
|
+
* @param {Array} errors - Validation errors
|
|
33
|
+
* @param {Array} warnings - Validation warnings
|
|
34
|
+
* @returns {number} Compliance score (0-1)
|
|
35
|
+
*/
|
|
36
|
+
export function calculateComplianceScore(errors: any[], warnings: any[]): number;
|
|
37
|
+
/**
|
|
38
|
+
* Get compliance grade from score
|
|
39
|
+
* @param {number} score - Compliance score (0-1)
|
|
40
|
+
* @returns {string} Grade (A, B, C, D, F)
|
|
41
|
+
*/
|
|
42
|
+
export function getComplianceGrade(score: number): string;
|
|
43
|
+
//# sourceMappingURL=spec-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-validation.d.ts","sourceRoot":"","sources":["../../src/validation/spec-validation.js"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,mEA8HC;AAED;;;;;GAKG;AACH,kFAgdC;AAoCD;;;;;GAKG;AACH,0CAJW,MAAM,eAEJ,MAAM,CAkBlB;AAED;;;;;GAKG;AACH,uCAJW,MAAM,eAEJ,OAAO,CAKnB;AAnED;;;;;;GAMG;AACH,0EAFa,MAAM,CAclB;AAED;;;;GAIG;AACH,0CAHW,MAAM,GACJ,MAAM,CAQlB"}
|
|
@@ -5,6 +5,59 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { deriveBudget, checkBudgetCompliance } = require('../budget-derivation');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get actual budget statistics from git history
|
|
12
|
+
* Analyzes changes since last tag or initial commit
|
|
13
|
+
* @param {string} specDir - Project directory
|
|
14
|
+
* @returns {Object|null} Budget stats or null on failure
|
|
15
|
+
*/
|
|
16
|
+
function getActualBudgetStats(specDir) {
|
|
17
|
+
const cwd = specDir || process.cwd();
|
|
18
|
+
try {
|
|
19
|
+
// Get base ref (last tag or initial commit)
|
|
20
|
+
let baseRef;
|
|
21
|
+
try {
|
|
22
|
+
baseRef = execSync('git describe --tags --abbrev=0 2>/dev/null', {
|
|
23
|
+
cwd,
|
|
24
|
+
encoding: 'utf8'
|
|
25
|
+
}).trim();
|
|
26
|
+
} catch {
|
|
27
|
+
// No tags found, use initial commit
|
|
28
|
+
baseRef = execSync('git rev-list --max-parents=0 HEAD', {
|
|
29
|
+
cwd,
|
|
30
|
+
encoding: 'utf8'
|
|
31
|
+
}).trim();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Count files changed since base ref
|
|
35
|
+
const filesOutput = execSync(`git diff --name-only ${baseRef}..HEAD`, {
|
|
36
|
+
cwd,
|
|
37
|
+
encoding: 'utf8'
|
|
38
|
+
});
|
|
39
|
+
const files_changed = filesOutput.trim().split('\n').filter(Boolean).length;
|
|
40
|
+
|
|
41
|
+
// Count lines changed (added + removed)
|
|
42
|
+
const numstatOutput = execSync(`git diff --numstat ${baseRef}..HEAD`, {
|
|
43
|
+
cwd,
|
|
44
|
+
encoding: 'utf8'
|
|
45
|
+
});
|
|
46
|
+
let lines_changed = 0;
|
|
47
|
+
for (const line of numstatOutput.trim().split('\n').filter(Boolean)) {
|
|
48
|
+
const [added, removed] = line.split('\t');
|
|
49
|
+
// Handle binary files (shown as '-')
|
|
50
|
+
const addedNum = added === '-' ? 0 : parseInt(added, 10) || 0;
|
|
51
|
+
const removedNum = removed === '-' ? 0 : parseInt(removed, 10) || 0;
|
|
52
|
+
lines_changed += addedNum + removedNum;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { files_changed, lines_changed };
|
|
56
|
+
} catch {
|
|
57
|
+
// Git not available or not a repository
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
8
61
|
|
|
9
62
|
/**
|
|
10
63
|
* Basic validation of working spec
|
|
@@ -511,14 +564,14 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
511
564
|
try {
|
|
512
565
|
const derivedBudget = deriveBudget(spec, projectRoot);
|
|
513
566
|
|
|
514
|
-
//
|
|
515
|
-
const
|
|
516
|
-
files_changed:
|
|
517
|
-
lines_changed:
|
|
518
|
-
risk_tier: spec.risk_tier,
|
|
567
|
+
// Get actual stats from git history
|
|
568
|
+
const actualStats = getActualBudgetStats(projectRoot) || {
|
|
569
|
+
files_changed: 0,
|
|
570
|
+
lines_changed: 0,
|
|
519
571
|
};
|
|
572
|
+
actualStats.risk_tier = spec.risk_tier;
|
|
520
573
|
|
|
521
|
-
budgetCheck = checkBudgetCompliance(derivedBudget,
|
|
574
|
+
budgetCheck = checkBudgetCompliance(derivedBudget, actualStats);
|
|
522
575
|
|
|
523
576
|
if (!budgetCheck.compliant) {
|
|
524
577
|
for (const violation of budgetCheck.violations) {
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
export = WaiversManager;
|
|
2
|
+
/**
|
|
3
|
+
* Waiver Manager Class
|
|
4
|
+
* Handles waiver creation, validation, expiration, and audit logging
|
|
5
|
+
*/
|
|
6
|
+
declare class WaiversManager {
|
|
7
|
+
constructor(options?: {});
|
|
8
|
+
projectRoot: any;
|
|
9
|
+
waiversDir: string;
|
|
10
|
+
waiversFile: string;
|
|
11
|
+
auditLogFile: string;
|
|
12
|
+
/**
|
|
13
|
+
* Waiver Schema Definition
|
|
14
|
+
*/
|
|
15
|
+
getWaiverSchema(): {
|
|
16
|
+
type: string;
|
|
17
|
+
required: string[];
|
|
18
|
+
properties: {
|
|
19
|
+
id: {
|
|
20
|
+
type: string;
|
|
21
|
+
pattern: string;
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
title: {
|
|
25
|
+
type: string;
|
|
26
|
+
minLength: number;
|
|
27
|
+
maxLength: number;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
reason: {
|
|
31
|
+
type: string;
|
|
32
|
+
enum: string[];
|
|
33
|
+
description: string;
|
|
34
|
+
};
|
|
35
|
+
description: {
|
|
36
|
+
type: string;
|
|
37
|
+
minLength: number;
|
|
38
|
+
maxLength: number;
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
gates: {
|
|
42
|
+
type: string;
|
|
43
|
+
items: {
|
|
44
|
+
type: string;
|
|
45
|
+
enum: string[];
|
|
46
|
+
};
|
|
47
|
+
minItems: number;
|
|
48
|
+
description: string;
|
|
49
|
+
};
|
|
50
|
+
risk_assessment: {
|
|
51
|
+
type: string;
|
|
52
|
+
properties: {
|
|
53
|
+
impact_level: {
|
|
54
|
+
type: string;
|
|
55
|
+
enum: string[];
|
|
56
|
+
};
|
|
57
|
+
mitigation_plan: {
|
|
58
|
+
type: string;
|
|
59
|
+
minLength: number;
|
|
60
|
+
};
|
|
61
|
+
review_required: {
|
|
62
|
+
type: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
required: string[];
|
|
66
|
+
};
|
|
67
|
+
expires_at: {
|
|
68
|
+
type: string;
|
|
69
|
+
format: string;
|
|
70
|
+
description: string;
|
|
71
|
+
};
|
|
72
|
+
approved_by: {
|
|
73
|
+
type: string;
|
|
74
|
+
description: string;
|
|
75
|
+
};
|
|
76
|
+
created_at: {
|
|
77
|
+
type: string;
|
|
78
|
+
format: string;
|
|
79
|
+
description: string;
|
|
80
|
+
};
|
|
81
|
+
metadata: {
|
|
82
|
+
type: string;
|
|
83
|
+
properties: {
|
|
84
|
+
related_pr: {
|
|
85
|
+
type: string;
|
|
86
|
+
};
|
|
87
|
+
related_issue: {
|
|
88
|
+
type: string;
|
|
89
|
+
};
|
|
90
|
+
environment: {
|
|
91
|
+
type: string;
|
|
92
|
+
enum: string[];
|
|
93
|
+
};
|
|
94
|
+
urgency: {
|
|
95
|
+
type: string;
|
|
96
|
+
enum: string[];
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Create a new waiver
|
|
104
|
+
*/
|
|
105
|
+
createWaiver(waiverData: any): Promise<{
|
|
106
|
+
id: string;
|
|
107
|
+
title: any;
|
|
108
|
+
reason: any;
|
|
109
|
+
description: any;
|
|
110
|
+
gates: any;
|
|
111
|
+
risk_assessment: any;
|
|
112
|
+
expires_at: any;
|
|
113
|
+
approved_by: any;
|
|
114
|
+
created_at: string;
|
|
115
|
+
metadata: any;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Check if waiver applies to specific gates
|
|
119
|
+
*/
|
|
120
|
+
checkWaiverCoverage(gatesToCheck: any, context?: {}): Promise<{
|
|
121
|
+
coveredGates: any[];
|
|
122
|
+
waiverDetails: {
|
|
123
|
+
gate: any;
|
|
124
|
+
waiver_id: any;
|
|
125
|
+
reason: any;
|
|
126
|
+
expires_at: any;
|
|
127
|
+
approved_by: any;
|
|
128
|
+
}[];
|
|
129
|
+
allCovered: boolean;
|
|
130
|
+
}>;
|
|
131
|
+
/**
|
|
132
|
+
* Get all active waivers
|
|
133
|
+
*/
|
|
134
|
+
getActiveWaivers(): Promise<any[]>;
|
|
135
|
+
/**
|
|
136
|
+
* Revoke a waiver
|
|
137
|
+
*/
|
|
138
|
+
revokeWaiver(waiverId: any, reason?: string): Promise<any>;
|
|
139
|
+
/**
|
|
140
|
+
* Extend waiver expiration
|
|
141
|
+
*/
|
|
142
|
+
extendWaiver(waiverId: any, newExpiryDate: any, approvedBy: any): Promise<any>;
|
|
143
|
+
/**
|
|
144
|
+
* Get waiver statistics and health metrics
|
|
145
|
+
*/
|
|
146
|
+
getWaiverStats(): Promise<{
|
|
147
|
+
total_active: number;
|
|
148
|
+
by_reason: {};
|
|
149
|
+
by_risk_level: {};
|
|
150
|
+
expiring_soon: any[];
|
|
151
|
+
high_risk: any[];
|
|
152
|
+
total_gates_waived: number;
|
|
153
|
+
average_lifespan_days: number;
|
|
154
|
+
}>;
|
|
155
|
+
generateWaiverId(): Promise<string>;
|
|
156
|
+
validateWaiver(waiver: any): {
|
|
157
|
+
valid: boolean;
|
|
158
|
+
errors: string[];
|
|
159
|
+
};
|
|
160
|
+
checkWaiverConflicts(newWaiver: any): Promise<string[]>;
|
|
161
|
+
waiverAppliesToContext(waiver: any, context: any): boolean;
|
|
162
|
+
loadActiveWaivers(): Promise<any[]>;
|
|
163
|
+
saveActiveWaivers(waivers: any): Promise<void>;
|
|
164
|
+
auditLog(action: any, waiverId: any, details: any): Promise<void>;
|
|
165
|
+
flagForReview(waiver: any): Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=waivers-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waivers-manager.d.ts","sourceRoot":"","sources":["../src/waivers-manager.js"],"names":[],"mappings":";AAaA;;;GAGG;AACH;IACE,0BAUC;IATC,iBAAuD;IACvD,mBAAiE;IACjE,oBAAoE;IACpE,qBAAkE;IAQpE;;OAEG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiGC;IAED;;OAEG;IACH;;;;;;;;;;;OA4DC;IAED;;OAEG;IACH;;;;;;;;;;OA+BC;IAED;;OAEG;IACH,mCAgBC;IAED;;OAEG;IACH,2DAeC;IAED;;OAEG;IACH,+EAuBC;IAED;;OAEG;IACH;;;;;;;;OA2DC;IAID,oCAUC;IAED;;;MAkDC;IAED,wDAkBC;IAED,2DAUC;IAED,oCAyCC;IAED,+CAuBC;IAED,kEAaC;IAED,0CA2CC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paths.design/caws-cli",
|
|
3
|
-
"version": "8.
|
|
4
|
-
"description": "CAWS CLI - Coding Agent Workflow System command
|
|
3
|
+
"version": "8.1.0",
|
|
4
|
+
"description": "CAWS CLI - Coding Agent Workflow System command-line tools for spec management, quality gates, and AI-assisted development",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"caws": "dist/index.js"
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"format": "prettier --write src/**/*.js tests/**/*.js",
|
|
34
34
|
"validate": "echo 'CLI package validation not required'",
|
|
35
35
|
"caws:validate": "node ../../.caws/validate.js ../../.caws/working-spec.yaml",
|
|
36
|
-
"clean": "rm -rf dist test-caws-project .agent && npm run test:cleanup"
|
|
36
|
+
"clean": "rm -rf dist test-caws-project .agent && npm run test:cleanup",
|
|
37
|
+
"prepare": "husky"
|
|
37
38
|
},
|
|
38
39
|
"keywords": [
|
|
39
40
|
"caws",
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
"ajv": "8.17.1",
|
|
70
71
|
"esbuild": "0.25.10",
|
|
71
72
|
"eslint": "^9.0.0",
|
|
73
|
+
"husky": "9.1.7",
|
|
72
74
|
"jest": "30.1.3",
|
|
73
75
|
"js-yaml": "4.1.0",
|
|
74
76
|
"lint-staged": "15.5.2",
|