@paths.design/caws-cli 3.1.0 ā 3.2.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/README.md +295 -150
- package/dist/budget-derivation.d.ts +35 -0
- package/dist/budget-derivation.d.ts.map +1 -0
- package/dist/budget-derivation.js +204 -0
- package/dist/cicd-optimizer.d.ts +142 -0
- package/dist/cicd-optimizer.d.ts.map +1 -0
- package/dist/cicd-optimizer.js +504 -0
- package/dist/commands/burnup.d.ts +6 -0
- package/dist/commands/burnup.d.ts.map +1 -0
- package/dist/commands/burnup.js +90 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +514 -0
- package/dist/commands/provenance.d.ts +32 -0
- package/dist/commands/provenance.d.ts.map +1 -0
- package/dist/commands/provenance.js +979 -0
- package/dist/commands/tool.d.ts +13 -0
- package/dist/commands/tool.d.ts.map +1 -0
- package/dist/commands/tool.js +138 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +80 -0
- package/dist/config/index.d.ts +29 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +132 -0
- package/dist/error-handler.d.ts +50 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +253 -0
- package/dist/generators/working-spec.d.ts +13 -0
- package/dist/generators/working-spec.d.ts.map +1 -0
- package/dist/generators/working-spec.js +204 -0
- package/dist/index.d.ts +3 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +193 -2983
- package/dist/scaffold/cursor-hooks.d.ts +7 -0
- package/dist/scaffold/cursor-hooks.d.ts.map +1 -0
- package/dist/scaffold/cursor-hooks.js +152 -0
- package/dist/scaffold/git-hooks.d.ts +20 -0
- package/dist/scaffold/git-hooks.d.ts.map +1 -0
- package/dist/scaffold/git-hooks.js +417 -0
- package/dist/scaffold/index.d.ts +20 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +486 -0
- package/dist/test-analysis.d.ts +182 -0
- package/dist/test-analysis.d.ts.map +1 -0
- package/dist/test-analysis.js +580 -0
- package/dist/tool-interface.d.ts +236 -0
- package/dist/tool-interface.d.ts.map +1 -0
- package/dist/tool-interface.js +314 -0
- package/dist/tool-loader.d.ts +77 -0
- package/dist/tool-loader.d.ts.map +1 -0
- package/dist/tool-loader.js +298 -0
- package/dist/tool-validator.d.ts +72 -0
- package/dist/tool-validator.d.ts.map +1 -0
- package/dist/tool-validator.js +387 -0
- package/dist/utils/detection.d.ts +7 -0
- package/dist/utils/detection.d.ts.map +1 -0
- package/dist/utils/detection.js +174 -0
- package/dist/utils/finalization.d.ts +17 -0
- package/dist/utils/finalization.d.ts.map +1 -0
- package/dist/utils/finalization.js +229 -0
- package/dist/utils/project-analysis.d.ts +14 -0
- package/dist/utils/project-analysis.d.ts.map +1 -0
- package/dist/utils/project-analysis.js +105 -0
- package/dist/validation/spec-validation.d.ts +29 -0
- package/dist/validation/spec-validation.d.ts.map +1 -0
- package/dist/validation/spec-validation.js +376 -0
- package/dist/waivers-manager.d.ts +167 -0
- package/dist/waivers-manager.d.ts.map +1 -0
- package/dist/waivers-manager.js +549 -0
- package/package.json +10 -12
- package/templates/.cursor/README.md +311 -0
- package/templates/.cursor/hooks/audit.sh +55 -0
- package/templates/.cursor/hooks/block-dangerous.sh +77 -0
- package/templates/.cursor/hooks/caws-quality-check.sh +52 -0
- package/templates/.cursor/hooks/caws-scope-guard.sh +74 -0
- package/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
- package/templates/.cursor/hooks/format.sh +38 -0
- package/templates/.cursor/hooks/naming-check.sh +64 -0
- package/templates/.cursor/hooks/scan-secrets.sh +46 -0
- package/templates/.cursor/hooks/scope-guard.sh +52 -0
- package/templates/.cursor/hooks/validate-spec.sh +38 -0
- package/templates/.cursor/hooks.json +59 -0
- package/templates/.github/copilot/instructions.md +311 -0
- package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
- package/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
- package/templates/.vscode/launch.json +56 -0
- package/templates/.vscode/settings.json +93 -0
- package/templates/.windsurf/workflows/caws-guided-development.md +92 -0
- package/templates/apps/tools/caws/README.md +1 -1
- package/templates/apps/tools/caws/schemas/working-spec.schema.json +21 -3
- package/templates/codemod/test.js +93 -1
- package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
- package/templates/apps/tools/caws/provenance.js.backup +0 -73
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CAWS CLI Error Handler - Centralized error handling utilities
|
|
3
|
+
* Provides consistent error categorization, formatting, and recovery suggestions
|
|
4
|
+
* @author @darianrosebrook
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Error categories for better user experience
|
|
11
|
+
*/
|
|
12
|
+
const ERROR_CATEGORIES = {
|
|
13
|
+
VALIDATION: 'validation',
|
|
14
|
+
PERMISSION: 'permission',
|
|
15
|
+
FILESYSTEM: 'filesystem',
|
|
16
|
+
NETWORK: 'network',
|
|
17
|
+
CONFIGURATION: 'configuration',
|
|
18
|
+
USER_INPUT: 'user_input',
|
|
19
|
+
DEPENDENCY: 'dependency',
|
|
20
|
+
UNKNOWN: 'unknown',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Error code mappings for common system errors
|
|
25
|
+
*/
|
|
26
|
+
const ERROR_CODES = {
|
|
27
|
+
EACCES: ERROR_CATEGORIES.PERMISSION,
|
|
28
|
+
EPERM: ERROR_CATEGORIES.PERMISSION,
|
|
29
|
+
ENOENT: ERROR_CATEGORIES.FILESYSTEM,
|
|
30
|
+
ENOTFOUND: ERROR_CATEGORIES.NETWORK,
|
|
31
|
+
ECONNREFUSED: ERROR_CATEGORIES.NETWORK,
|
|
32
|
+
ETIMEDOUT: ERROR_CATEGORIES.NETWORK,
|
|
33
|
+
ENOSPC: ERROR_CATEGORIES.FILESYSTEM,
|
|
34
|
+
EEXIST: ERROR_CATEGORIES.FILESYSTEM,
|
|
35
|
+
EISDIR: ERROR_CATEGORIES.FILESYSTEM,
|
|
36
|
+
ENOTDIR: ERROR_CATEGORIES.FILESYSTEM,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get error category from error object or message
|
|
41
|
+
* @param {Error|string} error - Error object or message
|
|
42
|
+
* @returns {string} Error category
|
|
43
|
+
*/
|
|
44
|
+
function getErrorCategory(error) {
|
|
45
|
+
const errorMessage = typeof error === 'string' ? error : error.message;
|
|
46
|
+
const errorCode = typeof error === 'object' && error.code ? error.code : null;
|
|
47
|
+
|
|
48
|
+
// Check error codes first
|
|
49
|
+
if (errorCode && ERROR_CODES[errorCode]) {
|
|
50
|
+
return ERROR_CODES[errorCode];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Check message patterns
|
|
54
|
+
const lowerMessage = errorMessage.toLowerCase();
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
lowerMessage.includes('validation') ||
|
|
58
|
+
lowerMessage.includes('invalid') ||
|
|
59
|
+
lowerMessage.includes('required')
|
|
60
|
+
) {
|
|
61
|
+
return ERROR_CATEGORIES.VALIDATION;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
lowerMessage.includes('permission') ||
|
|
66
|
+
lowerMessage.includes('access') ||
|
|
67
|
+
lowerMessage.includes('denied')
|
|
68
|
+
) {
|
|
69
|
+
return ERROR_CATEGORIES.PERMISSION;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
lowerMessage.includes('file') ||
|
|
74
|
+
lowerMessage.includes('directory') ||
|
|
75
|
+
lowerMessage.includes('path')
|
|
76
|
+
) {
|
|
77
|
+
return ERROR_CATEGORIES.FILESYSTEM;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (
|
|
81
|
+
lowerMessage.includes('network') ||
|
|
82
|
+
lowerMessage.includes('connection') ||
|
|
83
|
+
lowerMessage.includes('timeout')
|
|
84
|
+
) {
|
|
85
|
+
return ERROR_CATEGORIES.NETWORK;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
lowerMessage.includes('config') ||
|
|
90
|
+
lowerMessage.includes('setting') ||
|
|
91
|
+
lowerMessage.includes('option')
|
|
92
|
+
) {
|
|
93
|
+
return ERROR_CATEGORIES.CONFIGURATION;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
lowerMessage.includes('input') ||
|
|
98
|
+
lowerMessage.includes('prompt') ||
|
|
99
|
+
lowerMessage.includes('answer')
|
|
100
|
+
) {
|
|
101
|
+
return ERROR_CATEGORIES.USER_INPUT;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return ERROR_CATEGORIES.UNKNOWN;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Enhanced error class with category and recovery suggestions
|
|
109
|
+
*/
|
|
110
|
+
class CAWSError extends Error {
|
|
111
|
+
constructor(message, category = null, suggestions = []) {
|
|
112
|
+
super(message);
|
|
113
|
+
this.name = 'CAWSError';
|
|
114
|
+
this.category = category || getErrorCategory(message);
|
|
115
|
+
this.suggestions = Array.isArray(suggestions) ? suggestions : [suggestions].filter(Boolean);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Wrap async operations with consistent error handling
|
|
121
|
+
* @param {Function} operation - Async operation to wrap
|
|
122
|
+
* @param {string} context - Context for error messages
|
|
123
|
+
* @returns {Promise<any>} Operation result or throws handled error
|
|
124
|
+
*/
|
|
125
|
+
async function safeAsync(operation, context = '') {
|
|
126
|
+
try {
|
|
127
|
+
return await operation();
|
|
128
|
+
} catch (error) {
|
|
129
|
+
const category = getErrorCategory(error);
|
|
130
|
+
const enhancedError = new CAWSError(
|
|
131
|
+
`${context}: ${error.message}`,
|
|
132
|
+
category,
|
|
133
|
+
getRecoverySuggestions(error, category)
|
|
134
|
+
);
|
|
135
|
+
enhancedError.originalError = error;
|
|
136
|
+
throw enhancedError;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get recovery suggestions based on error category
|
|
142
|
+
* @param {Error} error - Original error
|
|
143
|
+
* @param {string} category - Error category
|
|
144
|
+
* @returns {string[]} Array of recovery suggestions
|
|
145
|
+
*/
|
|
146
|
+
function getRecoverySuggestions(error, category) {
|
|
147
|
+
const suggestions = [];
|
|
148
|
+
|
|
149
|
+
switch (category) {
|
|
150
|
+
case ERROR_CATEGORIES.PERMISSION:
|
|
151
|
+
suggestions.push('Try running the command with elevated privileges (sudo)');
|
|
152
|
+
suggestions.push('Check file/directory permissions with `ls -la`');
|
|
153
|
+
break;
|
|
154
|
+
|
|
155
|
+
case ERROR_CATEGORIES.FILESYSTEM:
|
|
156
|
+
if (error.code === 'ENOENT') {
|
|
157
|
+
suggestions.push('Verify the file/directory path exists');
|
|
158
|
+
suggestions.push('Check for typos in file names');
|
|
159
|
+
} else if (error.code === 'EEXIST') {
|
|
160
|
+
suggestions.push('The file/directory already exists');
|
|
161
|
+
suggestions.push('Use a different name or remove the existing item');
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
|
|
165
|
+
case ERROR_CATEGORIES.VALIDATION:
|
|
166
|
+
suggestions.push('Run `caws validate --suggestions` for detailed validation help');
|
|
167
|
+
suggestions.push('Check your working spec format against the documentation');
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
case ERROR_CATEGORIES.CONFIGURATION:
|
|
171
|
+
suggestions.push('Run `caws init --interactive` to reconfigure your project');
|
|
172
|
+
suggestions.push('Check your .caws directory and configuration files');
|
|
173
|
+
break;
|
|
174
|
+
|
|
175
|
+
case ERROR_CATEGORIES.NETWORK:
|
|
176
|
+
suggestions.push('Check your internet connection');
|
|
177
|
+
suggestions.push('Verify the URL/service is accessible');
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
default:
|
|
181
|
+
suggestions.push('Run the command with --help for usage information');
|
|
182
|
+
suggestions.push('Check the CAWS documentation at docs/README.md');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return suggestions;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Handle CLI errors with consistent formatting and user guidance
|
|
190
|
+
* @param {Error} error - Error to handle
|
|
191
|
+
* @param {boolean} exit - Whether to exit the process (default: true)
|
|
192
|
+
*/
|
|
193
|
+
function handleCliError(error, exit = true) {
|
|
194
|
+
const category = error.category || getErrorCategory(error);
|
|
195
|
+
const suggestions = error.suggestions || getRecoverySuggestions(error, category);
|
|
196
|
+
|
|
197
|
+
// Format error output
|
|
198
|
+
console.error(chalk.red(`\nā Error (${category}): ${error.message}`));
|
|
199
|
+
|
|
200
|
+
if (suggestions && suggestions.length > 0) {
|
|
201
|
+
console.error(chalk.yellow('\nš” Suggestions:'));
|
|
202
|
+
suggestions.forEach((suggestion) => {
|
|
203
|
+
console.error(chalk.yellow(` ⢠${suggestion}`));
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
console.error(
|
|
208
|
+
chalk.gray(
|
|
209
|
+
'\nš For more help, visit: https://github.com/Paths-Design/coding-agent-working-standard'
|
|
210
|
+
)
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (exit) {
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Validate required environment and dependencies
|
|
220
|
+
* @returns {Object} Validation result with any errors
|
|
221
|
+
*/
|
|
222
|
+
function validateEnvironment() {
|
|
223
|
+
const errors = [];
|
|
224
|
+
const warnings = [];
|
|
225
|
+
|
|
226
|
+
// Check Node.js version
|
|
227
|
+
const nodeVersion = process.versions.node;
|
|
228
|
+
const majorVersion = parseInt(nodeVersion.split('.')[0], 10);
|
|
229
|
+
if (majorVersion < 18) {
|
|
230
|
+
errors.push(`Node.js version ${nodeVersion} is not supported. Minimum required: 18.0.0`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Check if running in supported environment
|
|
234
|
+
if (!process.cwd()) {
|
|
235
|
+
errors.push('Unable to determine current working directory');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
valid: errors.length === 0,
|
|
240
|
+
errors,
|
|
241
|
+
warnings,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = {
|
|
246
|
+
CAWSError,
|
|
247
|
+
ERROR_CATEGORIES,
|
|
248
|
+
getErrorCategory,
|
|
249
|
+
safeAsync,
|
|
250
|
+
handleCliError,
|
|
251
|
+
validateEnvironment,
|
|
252
|
+
getRecoverySuggestions,
|
|
253
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate working spec YAML with user input
|
|
3
|
+
* @param {Object} answers - User responses
|
|
4
|
+
* @returns {string} - Generated YAML content
|
|
5
|
+
*/
|
|
6
|
+
export function generateWorkingSpec(answers: any): string;
|
|
7
|
+
/**
|
|
8
|
+
* Validate generated working spec against JSON schema
|
|
9
|
+
* @param {string} specContent - YAML spec content
|
|
10
|
+
* @param {Object} answers - User responses for error context
|
|
11
|
+
*/
|
|
12
|
+
export function validateGeneratedSpec(specContent: string, _answers: any): void;
|
|
13
|
+
//# sourceMappingURL=working-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-spec.d.ts","sourceRoot":"","sources":["../../src/generators/working-spec.js"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,mDAFa,MAAM,CAqJlB;AAED;;;;GAIG;AACH,mDAHW,MAAM,uBA8BhB"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Working Spec Generation Utilities
|
|
3
|
+
* Functions for generating and validating CAWS working specifications
|
|
4
|
+
* @author @darianrosebrook
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const yaml = require('js-yaml');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
|
|
10
|
+
// Import validation utilities
|
|
11
|
+
const { validateWorkingSpec } = require('../validation/spec-validation');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate working spec YAML with user input
|
|
15
|
+
* @param {Object} answers - User responses
|
|
16
|
+
* @returns {string} - Generated YAML content
|
|
17
|
+
*/
|
|
18
|
+
function generateWorkingSpec(answers) {
|
|
19
|
+
const template = {
|
|
20
|
+
id: answers.projectId,
|
|
21
|
+
title: answers.projectTitle,
|
|
22
|
+
risk_tier: answers.riskTier,
|
|
23
|
+
mode: answers.projectMode,
|
|
24
|
+
change_budget: {
|
|
25
|
+
max_files: answers.maxFiles,
|
|
26
|
+
max_loc: answers.maxLoc,
|
|
27
|
+
},
|
|
28
|
+
blast_radius: {
|
|
29
|
+
modules: answers.blastModules
|
|
30
|
+
.split(',')
|
|
31
|
+
.map((m) => m.trim())
|
|
32
|
+
.filter((m) => m),
|
|
33
|
+
data_migration: answers.dataMigration,
|
|
34
|
+
},
|
|
35
|
+
operational_rollback_slo: answers.rollbackSlo,
|
|
36
|
+
threats: (answers.projectThreats || '')
|
|
37
|
+
.split('\n')
|
|
38
|
+
.map((t) => t.trim())
|
|
39
|
+
.filter((t) => t && !t.startsWith('-') === false), // Allow lines starting with -
|
|
40
|
+
scope: {
|
|
41
|
+
in: (answers.scopeIn || '')
|
|
42
|
+
.split(',')
|
|
43
|
+
.map((s) => s.trim())
|
|
44
|
+
.filter((s) => s),
|
|
45
|
+
out: (answers.scopeOut || '')
|
|
46
|
+
.split(',')
|
|
47
|
+
.map((s) => s.trim())
|
|
48
|
+
.filter((s) => s),
|
|
49
|
+
},
|
|
50
|
+
invariants: (answers.projectInvariants || '')
|
|
51
|
+
.split('\n')
|
|
52
|
+
.map((i) => i.trim())
|
|
53
|
+
.filter((i) => i),
|
|
54
|
+
acceptance: answers.acceptanceCriteria
|
|
55
|
+
.split('\n')
|
|
56
|
+
.filter((a) => a.trim())
|
|
57
|
+
.map((criteria, index) => {
|
|
58
|
+
const id = `A${index + 1}`;
|
|
59
|
+
const upperCriteria = criteria.toUpperCase();
|
|
60
|
+
|
|
61
|
+
// Try different variations of the format
|
|
62
|
+
let given = '';
|
|
63
|
+
let when = '';
|
|
64
|
+
let then = '';
|
|
65
|
+
|
|
66
|
+
if (
|
|
67
|
+
upperCriteria.includes('GIVEN') &&
|
|
68
|
+
upperCriteria.includes('WHEN') &&
|
|
69
|
+
upperCriteria.includes('THEN')
|
|
70
|
+
) {
|
|
71
|
+
given = criteria.split(/WHEN/i)[0]?.replace(/GIVEN/i, '').trim() || '';
|
|
72
|
+
const whenThen = criteria.split(/WHEN/i)[1];
|
|
73
|
+
when = whenThen?.split(/THEN/i)[0]?.trim() || '';
|
|
74
|
+
then = whenThen?.split(/THEN/i)[1]?.trim() || '';
|
|
75
|
+
} else {
|
|
76
|
+
// Fallback: just split by lines and create simple criteria
|
|
77
|
+
given = 'Current system state';
|
|
78
|
+
when = criteria.replace(/^(GIVEN|WHEN|THEN)/i, '').trim();
|
|
79
|
+
then = 'Expected behavior occurs';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
id,
|
|
84
|
+
given: given || 'Current system state',
|
|
85
|
+
when: when || criteria,
|
|
86
|
+
then: then || 'Expected behavior occurs',
|
|
87
|
+
};
|
|
88
|
+
}),
|
|
89
|
+
non_functional: {
|
|
90
|
+
a11y: answers.a11yRequirements
|
|
91
|
+
.split(',')
|
|
92
|
+
.map((a) => a.trim())
|
|
93
|
+
.filter((a) => a),
|
|
94
|
+
perf: { api_p95_ms: answers.perfBudget },
|
|
95
|
+
security: answers.securityRequirements
|
|
96
|
+
.split(',')
|
|
97
|
+
.map((s) => s.trim())
|
|
98
|
+
.filter((s) => s),
|
|
99
|
+
},
|
|
100
|
+
contracts: [
|
|
101
|
+
{
|
|
102
|
+
type: answers.contractType,
|
|
103
|
+
path: answers.contractPath,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
observability: {
|
|
107
|
+
logs: answers.observabilityLogs
|
|
108
|
+
.split(',')
|
|
109
|
+
.map((l) => l.trim())
|
|
110
|
+
.filter((l) => l),
|
|
111
|
+
metrics: answers.observabilityMetrics
|
|
112
|
+
.split(',')
|
|
113
|
+
.map((m) => m.trim())
|
|
114
|
+
.filter((m) => m),
|
|
115
|
+
traces: answers.observabilityTraces
|
|
116
|
+
.split(',')
|
|
117
|
+
.map((t) => t.trim())
|
|
118
|
+
.filter((t) => t),
|
|
119
|
+
},
|
|
120
|
+
migrations: (answers.migrationPlan || '')
|
|
121
|
+
.split('\n')
|
|
122
|
+
.map((m) => m.trim())
|
|
123
|
+
.filter((m) => m),
|
|
124
|
+
rollback: (answers.rollbackPlan || '')
|
|
125
|
+
.split('\n')
|
|
126
|
+
.map((r) => r.trim())
|
|
127
|
+
.filter((r) => r),
|
|
128
|
+
human_override: answers.needsOverride
|
|
129
|
+
? {
|
|
130
|
+
enabled: true,
|
|
131
|
+
approver: answers.overrideApprover,
|
|
132
|
+
rationale: answers.overrideRationale,
|
|
133
|
+
waived_gates: answers.waivedGates,
|
|
134
|
+
approved_at: new Date().toISOString(),
|
|
135
|
+
expires_at: new Date(
|
|
136
|
+
Date.now() + answers.overrideExpiresDays * 24 * 60 * 60 * 1000
|
|
137
|
+
).toISOString(),
|
|
138
|
+
}
|
|
139
|
+
: undefined,
|
|
140
|
+
experimental_mode: answers.isExperimental
|
|
141
|
+
? {
|
|
142
|
+
enabled: true,
|
|
143
|
+
rationale: answers.experimentalRationale,
|
|
144
|
+
expires_at: new Date(
|
|
145
|
+
Date.now() + answers.experimentalExpiresDays * 24 * 60 * 60 * 1000
|
|
146
|
+
).toISOString(),
|
|
147
|
+
sandbox_location: answers.experimentalSandbox,
|
|
148
|
+
}
|
|
149
|
+
: undefined,
|
|
150
|
+
ai_assessment: {
|
|
151
|
+
confidence_level: answers.aiConfidence,
|
|
152
|
+
uncertainty_areas: answers.uncertaintyAreas
|
|
153
|
+
.split(',')
|
|
154
|
+
.map((a) => a.trim())
|
|
155
|
+
.filter((a) => a),
|
|
156
|
+
complexity_factors: answers.complexityFactors
|
|
157
|
+
.split(',')
|
|
158
|
+
.map((f) => f.trim())
|
|
159
|
+
.filter((f) => f),
|
|
160
|
+
risk_factors: [], // Could be populated by AI analysis
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return yaml.dump(template, { indent: 2 });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Validate generated working spec against JSON schema
|
|
169
|
+
* @param {string} specContent - YAML spec content
|
|
170
|
+
* @param {Object} answers - User responses for error context
|
|
171
|
+
*/
|
|
172
|
+
function validateGeneratedSpec(specContent, _answers) {
|
|
173
|
+
try {
|
|
174
|
+
const spec = yaml.load(specContent);
|
|
175
|
+
|
|
176
|
+
const isValid = validateWorkingSpec(spec);
|
|
177
|
+
|
|
178
|
+
if (!isValid) {
|
|
179
|
+
console.error(chalk.red('ā Generated working spec failed validation:'));
|
|
180
|
+
validateWorkingSpec.errors.forEach((error) => {
|
|
181
|
+
console.error(` - ${error.instancePath || 'root'}: ${error.message}`);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Provide helpful guidance
|
|
185
|
+
console.log(chalk.blue('\nš” Validation Tips:'));
|
|
186
|
+
console.log(' - Ensure risk_tier is 1, 2, or 3');
|
|
187
|
+
console.log(' - Check that scope.in is not empty');
|
|
188
|
+
console.log(' - Verify invariants and acceptance criteria are provided');
|
|
189
|
+
console.log(' - For tier 1 and 2, ensure contracts are specified');
|
|
190
|
+
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log(chalk.green('ā
Generated working spec passed validation'));
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error(chalk.red('ā Error validating working spec:'), error.message);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = {
|
|
202
|
+
generateWorkingSpec,
|
|
203
|
+
validateGeneratedSpec,
|
|
204
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* @returns {string} - Generated YAML content
|
|
6
|
-
*/
|
|
7
|
-
export function generateWorkingSpec(answers: any): string;
|
|
8
|
-
/**
|
|
9
|
-
* Validate generated working spec against JSON schema
|
|
10
|
-
* @param {string} specContent - YAML spec content
|
|
11
|
-
* @param {Object} answers - User responses for error context
|
|
12
|
-
*/
|
|
13
|
-
export function validateGeneratedSpec(specContent: string, _answers: any): void;
|
|
2
|
+
import { generateWorkingSpec } from "./generators/working-spec";
|
|
3
|
+
import { validateGeneratedSpec } from "./generators/working-spec";
|
|
4
|
+
export { generateWorkingSpec, validateGeneratedSpec };
|
|
14
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":""}
|