@paths.design/caws-cli 3.0.0 ā 3.1.1
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 +22 -0
- package/dist/commands/provenance.d.ts.map +1 -0
- package/dist/commands/provenance.js +594 -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-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 +3 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -1659
- package/dist/index.js.backup +4711 -0
- 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/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/prompt-lint.js.backup +274 -0
- package/templates/apps/tools/caws/provenance.js.backup +73 -0
- package/templates/apps/tools/caws/schemas/working-spec.schema.json +21 -3
- package/templates/codemod/test.js +93 -1
package/dist/index.js
CHANGED
|
@@ -7,1685 +7,126 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { Command } = require('commander');
|
|
10
|
+
// eslint-disable-next-line no-unused-vars
|
|
10
11
|
const fs = require('fs-extra');
|
|
12
|
+
// eslint-disable-next-line no-unused-vars
|
|
11
13
|
const path = require('path');
|
|
12
|
-
|
|
14
|
+
// eslint-disable-next-line no-unused-vars
|
|
13
15
|
const yaml = require('js-yaml');
|
|
14
16
|
const chalk = require('chalk');
|
|
15
17
|
|
|
16
|
-
// Import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
// Import configuration and utilities
|
|
19
|
+
const {
|
|
20
|
+
CLI_VERSION,
|
|
21
|
+
initializeGlobalSetup,
|
|
22
|
+
loadProvenanceTools,
|
|
23
|
+
initializeLanguageSupport,
|
|
24
|
+
} = require('./config');
|
|
25
|
+
|
|
26
|
+
// Import command handlers
|
|
27
|
+
const { initProject } = require('./commands/init');
|
|
28
|
+
const { validateCommand } = require('./commands/validate');
|
|
29
|
+
const { burnupCommand } = require('./commands/burnup');
|
|
30
|
+
const { testAnalysisCommand } = require('./test-analysis');
|
|
31
|
+
const { provenanceCommand } = require('./commands/provenance');
|
|
32
|
+
const { executeTool } = require('./commands/tool');
|
|
33
|
+
|
|
34
|
+
// Import scaffold functionality
|
|
35
|
+
const { scaffoldProject, setScaffoldDependencies } = require('./scaffold');
|
|
36
|
+
|
|
37
|
+
// Import validation functionality
|
|
38
|
+
// eslint-disable-next-line no-unused-vars
|
|
39
|
+
const { validateWorkingSpecWithSuggestions } = require('./validation/spec-validation');
|
|
40
|
+
|
|
41
|
+
// Import finalization utilities
|
|
42
|
+
const {
|
|
43
|
+
// eslint-disable-next-line no-unused-vars
|
|
44
|
+
finalizeProject,
|
|
45
|
+
// eslint-disable-next-line no-unused-vars
|
|
46
|
+
continueToSuccess,
|
|
47
|
+
setFinalizationDependencies,
|
|
48
|
+
} = require('./utils/finalization');
|
|
49
|
+
|
|
50
|
+
// Import generators
|
|
51
|
+
const { generateWorkingSpec, validateGeneratedSpec } = require('./generators/working-spec');
|
|
52
|
+
|
|
53
|
+
// Initialize global configuration
|
|
43
54
|
const program = new Command();
|
|
44
55
|
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const isQuietCommand =
|
|
49
|
-
process.argv.includes('--version') ||
|
|
50
|
-
process.argv.includes('-V') ||
|
|
51
|
-
process.argv.includes('--help');
|
|
52
|
-
|
|
53
|
-
if (!isQuietCommand) {
|
|
54
|
-
console.log(chalk.blue('š Detecting CAWS setup...'));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Check for existing CAWS setup
|
|
58
|
-
const cawsDir = path.join(cwd, '.caws');
|
|
59
|
-
const hasCAWSDir = fs.existsSync(cawsDir);
|
|
60
|
-
|
|
61
|
-
if (!hasCAWSDir) {
|
|
62
|
-
if (!isQuietCommand) {
|
|
63
|
-
console.log(chalk.gray('ā¹ļø No .caws directory found - new project setup'));
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
type: 'new',
|
|
67
|
-
hasCAWSDir: false,
|
|
68
|
-
cawsDir: null,
|
|
69
|
-
capabilities: [],
|
|
70
|
-
hasTemplateDir: false,
|
|
71
|
-
templateDir: null,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Analyze existing setup
|
|
76
|
-
const files = fs.readdirSync(cawsDir);
|
|
77
|
-
const hasWorkingSpec = fs.existsSync(path.join(cawsDir, 'working-spec.yaml'));
|
|
78
|
-
const hasValidateScript = fs.existsSync(path.join(cawsDir, 'validate.js'));
|
|
79
|
-
const hasPolicy = fs.existsSync(path.join(cawsDir, 'policy'));
|
|
80
|
-
const hasSchemas = fs.existsSync(path.join(cawsDir, 'schemas'));
|
|
81
|
-
const hasTemplates = fs.existsSync(path.join(cawsDir, 'templates'));
|
|
82
|
-
|
|
83
|
-
// Check for multiple spec files (enhanced project pattern)
|
|
84
|
-
const specFiles = files.filter((f) => f.endsWith('-spec.yaml'));
|
|
85
|
-
const hasMultipleSpecs = specFiles.length > 1;
|
|
86
|
-
|
|
87
|
-
// Check for tools directory (enhanced setup)
|
|
88
|
-
const toolsDir = path.join(cwd, 'apps/tools/caws');
|
|
89
|
-
const hasTools = fs.existsSync(toolsDir);
|
|
90
|
-
|
|
91
|
-
// Determine setup type
|
|
92
|
-
let setupType = 'basic';
|
|
93
|
-
let capabilities = [];
|
|
94
|
-
|
|
95
|
-
if (hasMultipleSpecs && hasWorkingSpec) {
|
|
96
|
-
setupType = 'enhanced';
|
|
97
|
-
capabilities.push('multiple-specs', 'working-spec', 'domain-specific');
|
|
98
|
-
} else if (hasWorkingSpec) {
|
|
99
|
-
setupType = 'standard';
|
|
100
|
-
capabilities.push('working-spec');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (hasValidateScript) {
|
|
104
|
-
capabilities.push('validation');
|
|
105
|
-
}
|
|
106
|
-
if (hasPolicy) {
|
|
107
|
-
capabilities.push('policies');
|
|
108
|
-
}
|
|
109
|
-
if (hasSchemas) {
|
|
110
|
-
capabilities.push('schemas');
|
|
111
|
-
}
|
|
112
|
-
if (hasTemplates) {
|
|
113
|
-
capabilities.push('templates');
|
|
114
|
-
}
|
|
115
|
-
if (hasTools) {
|
|
116
|
-
capabilities.push('tools');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (!isQuietCommand) {
|
|
120
|
-
console.log(chalk.green(`ā
Detected ${setupType} CAWS setup`));
|
|
121
|
-
console.log(chalk.gray(` Capabilities: ${capabilities.join(', ')}`));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Check for template directory - try multiple possible locations
|
|
125
|
-
let templateDir = null;
|
|
126
|
-
const possibleTemplatePaths = [
|
|
127
|
-
// FIRST: Try bundled templates (for npm-installed CLI)
|
|
128
|
-
path.resolve(__dirname, '../templates'),
|
|
129
|
-
path.resolve(__dirname, 'templates'),
|
|
130
|
-
// Try relative to current working directory (for monorepo setups)
|
|
131
|
-
path.resolve(cwd, '../caws-template'),
|
|
132
|
-
path.resolve(cwd, '../../caws-template'),
|
|
133
|
-
path.resolve(cwd, '../../../caws-template'),
|
|
134
|
-
path.resolve(cwd, 'packages/caws-template'),
|
|
135
|
-
path.resolve(cwd, 'caws-template'),
|
|
136
|
-
// Try relative to CLI location (for installed CLI)
|
|
137
|
-
path.resolve(__dirname, '../caws-template'),
|
|
138
|
-
path.resolve(__dirname, '../../caws-template'),
|
|
139
|
-
path.resolve(__dirname, '../../../caws-template'),
|
|
140
|
-
// Try absolute paths for CI environments
|
|
141
|
-
path.resolve(process.cwd(), 'packages/caws-template'),
|
|
142
|
-
path.resolve(process.cwd(), '../packages/caws-template'),
|
|
143
|
-
path.resolve(process.cwd(), '../../packages/caws-template'),
|
|
144
|
-
path.resolve(process.cwd(), '../../../packages/caws-template'),
|
|
145
|
-
// Try from workspace root
|
|
146
|
-
path.resolve(process.cwd(), 'caws-template'),
|
|
147
|
-
// Try various other common locations
|
|
148
|
-
'/home/runner/work/coding-agent-working-standard/coding-agent-working-standard/packages/caws-template',
|
|
149
|
-
'/workspace/packages/caws-template',
|
|
150
|
-
'/caws/packages/caws-template',
|
|
151
|
-
];
|
|
152
|
-
|
|
153
|
-
for (const testPath of possibleTemplatePaths) {
|
|
154
|
-
if (fs.existsSync(testPath)) {
|
|
155
|
-
templateDir = testPath;
|
|
156
|
-
if (!isQuietCommand) {
|
|
157
|
-
console.log(`ā
Found template directory: ${testPath}`);
|
|
158
|
-
}
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const hasTemplateDir = templateDir !== null;
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
type: setupType,
|
|
167
|
-
hasCAWSDir: true,
|
|
168
|
-
cawsDir,
|
|
169
|
-
hasWorkingSpec,
|
|
170
|
-
hasMultipleSpecs,
|
|
171
|
-
hasValidateScript,
|
|
172
|
-
hasPolicy,
|
|
173
|
-
hasSchemas,
|
|
174
|
-
hasTemplates,
|
|
175
|
-
hasTools,
|
|
176
|
-
hasTemplateDir,
|
|
177
|
-
templateDir,
|
|
178
|
-
capabilities,
|
|
179
|
-
isEnhanced: setupType === 'enhanced',
|
|
180
|
-
isAdvanced: hasTools || hasValidateScript,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
let cawsSetup = null;
|
|
185
|
-
|
|
186
|
-
// Initialize global setup detection
|
|
187
|
-
try {
|
|
188
|
-
cawsSetup = detectCAWSSetup();
|
|
189
|
-
|
|
190
|
-
// If no template dir found in current directory, check CLI installation location
|
|
191
|
-
if (!cawsSetup.hasTemplateDir) {
|
|
192
|
-
const cliTemplatePaths = [
|
|
193
|
-
path.resolve(__dirname, '../templates'),
|
|
194
|
-
path.resolve(__dirname, 'templates'),
|
|
195
|
-
];
|
|
196
|
-
|
|
197
|
-
for (const testPath of cliTemplatePaths) {
|
|
198
|
-
if (fs.existsSync(testPath)) {
|
|
199
|
-
cawsSetup.templateDir = testPath;
|
|
200
|
-
cawsSetup.hasTemplateDir = true;
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} catch (error) {
|
|
206
|
-
console.warn('ā ļø Failed to detect CAWS setup globally:', error.message);
|
|
207
|
-
cawsSetup = {
|
|
208
|
-
type: 'unknown',
|
|
209
|
-
hasCAWSDir: false,
|
|
210
|
-
cawsDir: null,
|
|
211
|
-
hasWorkingSpec: false,
|
|
212
|
-
hasMultipleSpecs: false,
|
|
213
|
-
hasValidateScript: false,
|
|
214
|
-
hasPolicy: false,
|
|
215
|
-
hasSchemas: false,
|
|
216
|
-
hasTemplates: false,
|
|
217
|
-
hasTools: false,
|
|
218
|
-
hasTemplateDir: false,
|
|
219
|
-
templateDir: null,
|
|
220
|
-
capabilities: [],
|
|
221
|
-
isEnhanced: false,
|
|
222
|
-
isAdvanced: false,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Dynamic imports based on setup
|
|
227
|
-
let provenanceTools = null;
|
|
228
|
-
|
|
229
|
-
// Function to load provenance tools dynamically
|
|
230
|
-
function loadProvenanceTools() {
|
|
231
|
-
if (provenanceTools) return provenanceTools; // Already loaded
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
const setup = detectCAWSSetup();
|
|
235
|
-
if (setup?.hasTemplateDir && setup?.templateDir) {
|
|
236
|
-
const { generateProvenance, saveProvenance } = require(
|
|
237
|
-
path.join(setup.templateDir, 'apps/tools/caws/provenance.js')
|
|
238
|
-
);
|
|
239
|
-
provenanceTools = { generateProvenance, saveProvenance };
|
|
240
|
-
console.log('ā
Loaded provenance tools from:', setup.templateDir);
|
|
241
|
-
}
|
|
242
|
-
} catch (error) {
|
|
243
|
-
// Fallback for environments without template
|
|
244
|
-
provenanceTools = null;
|
|
245
|
-
console.warn('ā ļø Provenance tools not available:', error.message);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return provenanceTools;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const CLI_VERSION = require('../package.json').version;
|
|
252
|
-
|
|
253
|
-
// Initialize JSON Schema validator - using simplified validation for CLI stability
|
|
254
|
-
const validateWorkingSpec = (spec) => {
|
|
255
|
-
try {
|
|
256
|
-
// Basic structural validation for essential fields
|
|
257
|
-
const requiredFields = [
|
|
258
|
-
'id',
|
|
259
|
-
'title',
|
|
260
|
-
'risk_tier',
|
|
261
|
-
'mode',
|
|
262
|
-
'change_budget',
|
|
263
|
-
'blast_radius',
|
|
264
|
-
'operational_rollback_slo',
|
|
265
|
-
'scope',
|
|
266
|
-
'invariants',
|
|
267
|
-
'acceptance',
|
|
268
|
-
'non_functional',
|
|
269
|
-
'contracts',
|
|
270
|
-
];
|
|
271
|
-
|
|
272
|
-
for (const field of requiredFields) {
|
|
273
|
-
if (!spec[field]) {
|
|
274
|
-
return {
|
|
275
|
-
valid: false,
|
|
276
|
-
errors: [
|
|
277
|
-
{
|
|
278
|
-
instancePath: `/${field}`,
|
|
279
|
-
message: `Missing required field: ${field}`,
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Validate specific field formats
|
|
287
|
-
if (!/^[A-Z]+-\d+$/.test(spec.id)) {
|
|
288
|
-
return {
|
|
289
|
-
valid: false,
|
|
290
|
-
errors: [
|
|
291
|
-
{
|
|
292
|
-
instancePath: '/id',
|
|
293
|
-
message: 'Project ID should be in format: PREFIX-NUMBER (e.g., FEAT-1234)',
|
|
294
|
-
},
|
|
295
|
-
],
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Validate experimental mode
|
|
300
|
-
if (spec.experimental_mode) {
|
|
301
|
-
if (typeof spec.experimental_mode !== 'object') {
|
|
302
|
-
return {
|
|
303
|
-
valid: false,
|
|
304
|
-
errors: [
|
|
305
|
-
{
|
|
306
|
-
instancePath: '/experimental_mode',
|
|
307
|
-
message:
|
|
308
|
-
'Experimental mode must be an object with enabled, rationale, and expires_at fields',
|
|
309
|
-
},
|
|
310
|
-
],
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const requiredExpFields = ['enabled', 'rationale', 'expires_at'];
|
|
315
|
-
for (const field of requiredExpFields) {
|
|
316
|
-
if (!(field in spec.experimental_mode)) {
|
|
317
|
-
return {
|
|
318
|
-
valid: false,
|
|
319
|
-
errors: [
|
|
320
|
-
{
|
|
321
|
-
instancePath: `/experimental_mode/${field}`,
|
|
322
|
-
message: `Missing required experimental mode field: ${field}`,
|
|
323
|
-
},
|
|
324
|
-
],
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (spec.experimental_mode.enabled && spec.risk_tier < 3) {
|
|
330
|
-
return {
|
|
331
|
-
valid: false,
|
|
332
|
-
errors: [
|
|
333
|
-
{
|
|
334
|
-
instancePath: '/experimental_mode',
|
|
335
|
-
message: 'Experimental mode can only be used with Tier 3 (low risk) changes',
|
|
336
|
-
},
|
|
337
|
-
],
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (spec.risk_tier < 1 || spec.risk_tier > 3) {
|
|
343
|
-
return {
|
|
344
|
-
valid: false,
|
|
345
|
-
errors: [
|
|
346
|
-
{
|
|
347
|
-
instancePath: '/risk_tier',
|
|
348
|
-
message: 'Risk tier must be 1, 2, or 3',
|
|
349
|
-
},
|
|
350
|
-
],
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (!spec.scope || !spec.scope.in || spec.scope.in.length === 0) {
|
|
355
|
-
return {
|
|
356
|
-
valid: false,
|
|
357
|
-
errors: [
|
|
358
|
-
{
|
|
359
|
-
instancePath: '/scope/in',
|
|
360
|
-
message: 'Scope IN must not be empty',
|
|
361
|
-
},
|
|
362
|
-
],
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return { valid: true };
|
|
367
|
-
} catch (error) {
|
|
368
|
-
return {
|
|
369
|
-
valid: false,
|
|
370
|
-
errors: [
|
|
371
|
-
{
|
|
372
|
-
instancePath: '',
|
|
373
|
-
message: `Validation error: ${error.message}`,
|
|
374
|
-
},
|
|
375
|
-
],
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
// Only log schema validation if not running quiet commands
|
|
381
|
-
if (!process.argv.includes('--version') && !process.argv.includes('-V')) {
|
|
382
|
-
console.log(chalk.green('ā
Schema validation initialized successfully'));
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Generate working spec YAML with user input
|
|
387
|
-
* @param {Object} answers - User responses
|
|
388
|
-
* @returns {string} - Generated YAML content
|
|
389
|
-
*/
|
|
390
|
-
function generateWorkingSpec(answers) {
|
|
391
|
-
const template = {
|
|
392
|
-
id: answers.projectId,
|
|
393
|
-
title: answers.projectTitle,
|
|
394
|
-
risk_tier: answers.riskTier,
|
|
395
|
-
mode: answers.projectMode,
|
|
396
|
-
change_budget: {
|
|
397
|
-
max_files: answers.maxFiles,
|
|
398
|
-
max_loc: answers.maxLoc,
|
|
399
|
-
},
|
|
400
|
-
blast_radius: {
|
|
401
|
-
modules: answers.blastModules
|
|
402
|
-
.split(',')
|
|
403
|
-
.map((m) => m.trim())
|
|
404
|
-
.filter((m) => m),
|
|
405
|
-
data_migration: answers.dataMigration,
|
|
406
|
-
},
|
|
407
|
-
operational_rollback_slo: answers.rollbackSlo,
|
|
408
|
-
threats: (answers.projectThreats || '')
|
|
409
|
-
.split('\n')
|
|
410
|
-
.map((t) => t.trim())
|
|
411
|
-
.filter((t) => t && !t.startsWith('-') === false), // Allow lines starting with -
|
|
412
|
-
scope: {
|
|
413
|
-
in: (answers.scopeIn || '')
|
|
414
|
-
.split(',')
|
|
415
|
-
.map((s) => s.trim())
|
|
416
|
-
.filter((s) => s),
|
|
417
|
-
out: (answers.scopeOut || '')
|
|
418
|
-
.split(',')
|
|
419
|
-
.map((s) => s.trim())
|
|
420
|
-
.filter((s) => s),
|
|
421
|
-
},
|
|
422
|
-
invariants: (answers.projectInvariants || '')
|
|
423
|
-
.split('\n')
|
|
424
|
-
.map((i) => i.trim())
|
|
425
|
-
.filter((i) => i),
|
|
426
|
-
acceptance: answers.acceptanceCriteria
|
|
427
|
-
.split('\n')
|
|
428
|
-
.filter((a) => a.trim())
|
|
429
|
-
.map((criteria, index) => {
|
|
430
|
-
const id = `A${index + 1}`;
|
|
431
|
-
const upperCriteria = criteria.toUpperCase();
|
|
432
|
-
|
|
433
|
-
// Try different variations of the format
|
|
434
|
-
let given = '';
|
|
435
|
-
let when = '';
|
|
436
|
-
let then = '';
|
|
437
|
-
|
|
438
|
-
if (
|
|
439
|
-
upperCriteria.includes('GIVEN') &&
|
|
440
|
-
upperCriteria.includes('WHEN') &&
|
|
441
|
-
upperCriteria.includes('THEN')
|
|
442
|
-
) {
|
|
443
|
-
given = criteria.split(/WHEN/i)[0]?.replace(/GIVEN/i, '').trim() || '';
|
|
444
|
-
const whenThen = criteria.split(/WHEN/i)[1];
|
|
445
|
-
when = whenThen?.split(/THEN/i)[0]?.trim() || '';
|
|
446
|
-
then = whenThen?.split(/THEN/i)[1]?.trim() || '';
|
|
447
|
-
} else {
|
|
448
|
-
// Fallback: just split by lines and create simple criteria
|
|
449
|
-
given = 'Current system state';
|
|
450
|
-
when = criteria.replace(/^(GIVEN|WHEN|THEN)/i, '').trim();
|
|
451
|
-
then = 'Expected behavior occurs';
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
return {
|
|
455
|
-
id,
|
|
456
|
-
given: given || 'Current system state',
|
|
457
|
-
when: when || criteria,
|
|
458
|
-
then: then || 'Expected behavior occurs',
|
|
459
|
-
};
|
|
460
|
-
}),
|
|
461
|
-
non_functional: {
|
|
462
|
-
a11y: answers.a11yRequirements
|
|
463
|
-
.split(',')
|
|
464
|
-
.map((a) => a.trim())
|
|
465
|
-
.filter((a) => a),
|
|
466
|
-
perf: { api_p95_ms: answers.perfBudget },
|
|
467
|
-
security: answers.securityRequirements
|
|
468
|
-
.split(',')
|
|
469
|
-
.map((s) => s.trim())
|
|
470
|
-
.filter((s) => s),
|
|
471
|
-
},
|
|
472
|
-
contracts: [
|
|
473
|
-
{
|
|
474
|
-
type: answers.contractType,
|
|
475
|
-
path: answers.contractPath,
|
|
476
|
-
},
|
|
477
|
-
],
|
|
478
|
-
observability: {
|
|
479
|
-
logs: answers.observabilityLogs
|
|
480
|
-
.split(',')
|
|
481
|
-
.map((l) => l.trim())
|
|
482
|
-
.filter((l) => l),
|
|
483
|
-
metrics: answers.observabilityMetrics
|
|
484
|
-
.split(',')
|
|
485
|
-
.map((m) => m.trim())
|
|
486
|
-
.filter((m) => m),
|
|
487
|
-
traces: answers.observabilityTraces
|
|
488
|
-
.split(',')
|
|
489
|
-
.map((t) => t.trim())
|
|
490
|
-
.filter((t) => t),
|
|
491
|
-
},
|
|
492
|
-
migrations: (answers.migrationPlan || '')
|
|
493
|
-
.split('\n')
|
|
494
|
-
.map((m) => m.trim())
|
|
495
|
-
.filter((m) => m),
|
|
496
|
-
rollback: (answers.rollbackPlan || '')
|
|
497
|
-
.split('\n')
|
|
498
|
-
.map((r) => r.trim())
|
|
499
|
-
.filter((r) => r),
|
|
500
|
-
human_override: answers.needsOverride
|
|
501
|
-
? {
|
|
502
|
-
enabled: true,
|
|
503
|
-
approver: answers.overrideApprover,
|
|
504
|
-
rationale: answers.overrideRationale,
|
|
505
|
-
waived_gates: answers.waivedGates,
|
|
506
|
-
approved_at: new Date().toISOString(),
|
|
507
|
-
expires_at: new Date(
|
|
508
|
-
Date.now() + answers.overrideExpiresDays * 24 * 60 * 60 * 1000
|
|
509
|
-
).toISOString(),
|
|
510
|
-
}
|
|
511
|
-
: undefined,
|
|
512
|
-
experimental_mode: answers.isExperimental
|
|
513
|
-
? {
|
|
514
|
-
enabled: true,
|
|
515
|
-
rationale: answers.experimentalRationale,
|
|
516
|
-
expires_at: new Date(
|
|
517
|
-
Date.now() + answers.experimentalExpiresDays * 24 * 60 * 60 * 1000
|
|
518
|
-
).toISOString(),
|
|
519
|
-
sandbox_location: answers.experimentalSandbox,
|
|
520
|
-
}
|
|
521
|
-
: undefined,
|
|
522
|
-
ai_assessment: {
|
|
523
|
-
confidence_level: answers.aiConfidence,
|
|
524
|
-
uncertainty_areas: answers.uncertaintyAreas
|
|
525
|
-
.split(',')
|
|
526
|
-
.map((a) => a.trim())
|
|
527
|
-
.filter((a) => a),
|
|
528
|
-
complexity_factors: answers.complexityFactors
|
|
529
|
-
.split(',')
|
|
530
|
-
.map((f) => f.trim())
|
|
531
|
-
.filter((f) => f),
|
|
532
|
-
risk_factors: [], // Could be populated by AI analysis
|
|
533
|
-
},
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
return yaml.dump(template, { indent: 2 });
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/**
|
|
540
|
-
* Validate generated working spec against JSON schema
|
|
541
|
-
* @param {string} specContent - YAML spec content
|
|
542
|
-
* @param {Object} answers - User responses for error context
|
|
543
|
-
*/
|
|
544
|
-
function validateGeneratedSpec(specContent, _answers) {
|
|
545
|
-
try {
|
|
546
|
-
const spec = yaml.load(specContent);
|
|
547
|
-
|
|
548
|
-
const isValid = validateWorkingSpec(spec);
|
|
549
|
-
|
|
550
|
-
if (!isValid) {
|
|
551
|
-
console.error(chalk.red('ā Generated working spec failed validation:'));
|
|
552
|
-
validateWorkingSpec.errors.forEach((error) => {
|
|
553
|
-
console.error(` - ${error.instancePath || 'root'}: ${error.message}`);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
// Provide helpful guidance
|
|
557
|
-
console.log(chalk.blue('\nš” Validation Tips:'));
|
|
558
|
-
console.log(' - Ensure risk_tier is 1, 2, or 3');
|
|
559
|
-
console.log(' - Check that scope.in is not empty');
|
|
560
|
-
console.log(' - Verify invariants and acceptance criteria are provided');
|
|
561
|
-
console.log(' - For tier 1 and 2, ensure contracts are specified');
|
|
562
|
-
|
|
563
|
-
process.exit(1);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
console.log(chalk.green('ā
Generated working spec passed validation'));
|
|
567
|
-
} catch (error) {
|
|
568
|
-
console.error(chalk.red('ā Error validating working spec:'), error.message);
|
|
569
|
-
process.exit(1);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
/**
|
|
574
|
-
* Initialize a new project with CAWS
|
|
575
|
-
*/
|
|
576
|
-
async function initProject(projectName, options) {
|
|
577
|
-
console.log(chalk.cyan(`š Initializing new CAWS project: ${projectName}`));
|
|
578
|
-
|
|
579
|
-
let answers; // Will be set either interactively or with defaults
|
|
580
|
-
|
|
581
|
-
try {
|
|
582
|
-
// Validate project name
|
|
583
|
-
if (!projectName || projectName.trim() === '') {
|
|
584
|
-
console.error(chalk.red('ā Project name is required'));
|
|
585
|
-
console.error(chalk.blue('š” Usage: caws init <project-name>'));
|
|
586
|
-
process.exit(1);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// Special case: '.' means current directory, don't sanitize
|
|
590
|
-
if (projectName !== '.') {
|
|
591
|
-
// Sanitize project name
|
|
592
|
-
const sanitizedName = projectName.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();
|
|
593
|
-
if (sanitizedName !== projectName) {
|
|
594
|
-
console.warn(chalk.yellow(`ā ļø Project name sanitized to: ${sanitizedName}`));
|
|
595
|
-
projectName = sanitizedName;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// Validate project name length
|
|
600
|
-
if (projectName.length > 50) {
|
|
601
|
-
console.error(chalk.red('ā Project name is too long (max 50 characters)'));
|
|
602
|
-
console.error(chalk.blue('š” Usage: caws init <project-name>'));
|
|
603
|
-
process.exit(1);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// Validate project name format
|
|
607
|
-
if (projectName.length === 0) {
|
|
608
|
-
console.error(chalk.red('ā Project name cannot be empty'));
|
|
609
|
-
console.error(chalk.blue('š” Usage: caws init <project-name>'));
|
|
610
|
-
process.exit(1);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// Check for invalid characters that should cause immediate failure
|
|
614
|
-
if (projectName.includes('/') || projectName.includes('\\') || projectName.includes('..')) {
|
|
615
|
-
console.error(chalk.red('ā Project name contains invalid characters'));
|
|
616
|
-
console.error(chalk.blue('š” Usage: caws init <project-name>'));
|
|
617
|
-
console.error(chalk.blue('š” Project name should not contain: / \\ ..'));
|
|
618
|
-
process.exit(1);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// Determine if initializing in current directory
|
|
622
|
-
const initInCurrentDir = projectName === '.';
|
|
623
|
-
const targetDir = initInCurrentDir ? process.cwd() : path.resolve(process.cwd(), projectName);
|
|
624
|
-
|
|
625
|
-
// Check if directory already exists (skip check for current directory)
|
|
626
|
-
if (!initInCurrentDir && fs.existsSync(projectName)) {
|
|
627
|
-
console.error(chalk.red(`ā Directory ${projectName} already exists`));
|
|
628
|
-
console.error(chalk.blue('š” Choose a different name or remove the existing directory'));
|
|
629
|
-
process.exit(1);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// Save the original template directory before changing directories
|
|
633
|
-
const originalTemplateDir = cawsSetup?.hasTemplateDir ? cawsSetup.templateDir : null;
|
|
634
|
-
|
|
635
|
-
// Check for existing agents.md/caws.md in target directory
|
|
636
|
-
const existingAgentsMd = fs.existsSync(path.join(targetDir, 'agents.md'));
|
|
637
|
-
const existingCawsMd = fs.existsSync(path.join(targetDir, 'caws.md'));
|
|
638
|
-
|
|
639
|
-
// Create project directory and change to it (unless already in current directory)
|
|
640
|
-
if (!initInCurrentDir) {
|
|
641
|
-
await fs.ensureDir(projectName);
|
|
642
|
-
process.chdir(projectName);
|
|
643
|
-
console.log(chalk.green(`š Created project directory: ${projectName}`));
|
|
644
|
-
} else {
|
|
645
|
-
console.log(chalk.green(`š Initializing in current directory`));
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Detect and adapt to existing setup
|
|
649
|
-
const currentSetup = detectCAWSSetup(process.cwd());
|
|
650
|
-
|
|
651
|
-
if (currentSetup.type === 'new') {
|
|
652
|
-
// Create minimal CAWS structure
|
|
653
|
-
await fs.ensureDir('.caws');
|
|
654
|
-
await fs.ensureDir('.agent');
|
|
655
|
-
console.log(chalk.blue('ā¹ļø Created basic CAWS structure'));
|
|
56
|
+
// Initialize global state
|
|
57
|
+
const cawsSetup = initializeGlobalSetup();
|
|
58
|
+
const languageSupport = initializeLanguageSupport();
|
|
656
59
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
if (fs.existsSync(agentsMdSource)) {
|
|
664
|
-
// Use the pre-checked values for conflicts
|
|
665
|
-
if (existingAgentsMd) {
|
|
666
|
-
// Conflict: user already has agents.md
|
|
667
|
-
if (options.interactive && !options.nonInteractive) {
|
|
668
|
-
// Interactive mode: ask user
|
|
669
|
-
const overwriteAnswer = await inquirer.prompt([
|
|
670
|
-
{
|
|
671
|
-
type: 'confirm',
|
|
672
|
-
name: 'overwrite',
|
|
673
|
-
message: 'ā ļø agents.md already exists. Overwrite with CAWS guide?',
|
|
674
|
-
default: false,
|
|
675
|
-
},
|
|
676
|
-
]);
|
|
677
|
-
|
|
678
|
-
if (overwriteAnswer.overwrite) {
|
|
679
|
-
targetFile = 'agents.md';
|
|
680
|
-
} else {
|
|
681
|
-
targetFile = 'caws.md';
|
|
682
|
-
}
|
|
683
|
-
} else {
|
|
684
|
-
// Non-interactive mode: use caws.md instead
|
|
685
|
-
targetFile = 'caws.md';
|
|
686
|
-
console.log(chalk.blue('ā¹ļø agents.md exists, using caws.md for CAWS guide'));
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
// If caws.md also exists and that's our target, skip
|
|
691
|
-
if (targetFile === 'caws.md' && existingCawsMd) {
|
|
692
|
-
console.log(
|
|
693
|
-
chalk.yellow('ā ļø Both agents.md and caws.md exist, skipping guide copy')
|
|
694
|
-
);
|
|
695
|
-
} else {
|
|
696
|
-
const agentsMdDest = path.join(process.cwd(), targetFile);
|
|
697
|
-
await fs.copyFile(agentsMdSource, agentsMdDest);
|
|
698
|
-
console.log(chalk.green(`ā
Added ${targetFile} guide`));
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
} catch (templateError) {
|
|
702
|
-
console.warn(chalk.yellow('ā ļø Could not copy agents guide:'), templateError.message);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
} else {
|
|
706
|
-
// Already has CAWS setup
|
|
707
|
-
console.log(chalk.green('ā
CAWS project detected - skipping template copy'));
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// Set default answers for non-interactive mode
|
|
711
|
-
if (!options.interactive || options.nonInteractive) {
|
|
712
|
-
// Use directory name for current directory init
|
|
713
|
-
const displayName = initInCurrentDir ? path.basename(process.cwd()) : projectName;
|
|
714
|
-
|
|
715
|
-
answers = {
|
|
716
|
-
projectId: displayName.toUpperCase().replace(/[^A-Z0-9]/g, '-') + '-001',
|
|
717
|
-
projectTitle: displayName.charAt(0).toUpperCase() + displayName.slice(1).replace(/-/g, ' '),
|
|
718
|
-
riskTier: 2,
|
|
719
|
-
projectMode: 'feature',
|
|
720
|
-
maxFiles: 25,
|
|
721
|
-
maxLoc: 1000,
|
|
722
|
-
blastModules: 'core,ui',
|
|
723
|
-
dataMigration: false,
|
|
724
|
-
rollbackSlo: '5m',
|
|
725
|
-
projectThreats: 'Standard project threats',
|
|
726
|
-
scopeIn: 'project files',
|
|
727
|
-
scopeOut: 'external dependencies',
|
|
728
|
-
projectInvariants: 'System maintains consistency',
|
|
729
|
-
acceptanceCriteria: 'GIVEN current state WHEN action THEN expected result',
|
|
730
|
-
a11yRequirements: 'keyboard navigation, screen reader support',
|
|
731
|
-
perfBudget: 250,
|
|
732
|
-
securityRequirements: 'input validation, authentication',
|
|
733
|
-
contractType: 'openapi',
|
|
734
|
-
contractPath: 'apps/contracts/api.yaml',
|
|
735
|
-
observabilityLogs: 'auth.success,api.request',
|
|
736
|
-
observabilityMetrics: 'requests_total',
|
|
737
|
-
observabilityTraces: 'api_flow',
|
|
738
|
-
migrationPlan: 'Standard deployment process',
|
|
739
|
-
rollbackPlan: 'Feature flag disable and rollback',
|
|
740
|
-
needsOverride: false,
|
|
741
|
-
overrideRationale: '',
|
|
742
|
-
overrideApprover: '',
|
|
743
|
-
waivedGates: [],
|
|
744
|
-
overrideExpiresDays: 7,
|
|
745
|
-
isExperimental: false,
|
|
746
|
-
experimentalRationale: '',
|
|
747
|
-
experimentalSandbox: 'experimental/',
|
|
748
|
-
experimentalExpiresDays: 14,
|
|
749
|
-
aiConfidence: 7,
|
|
750
|
-
uncertaintyAreas: '',
|
|
751
|
-
complexityFactors: '',
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
// Generate working spec for non-interactive mode
|
|
755
|
-
const workingSpecContent = generateWorkingSpec(answers);
|
|
756
|
-
|
|
757
|
-
// Validate the generated spec
|
|
758
|
-
validateGeneratedSpec(workingSpecContent, answers);
|
|
759
|
-
|
|
760
|
-
// Save the working spec
|
|
761
|
-
await fs.writeFile('.caws/working-spec.yaml', workingSpecContent);
|
|
762
|
-
|
|
763
|
-
console.log(chalk.green('ā
Working spec generated and validated'));
|
|
764
|
-
|
|
765
|
-
// Finalize project with provenance and git initialization
|
|
766
|
-
await finalizeProject(projectName, options, answers);
|
|
767
|
-
|
|
768
|
-
continueToSuccess();
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
if (options.interactive && !options.nonInteractive) {
|
|
773
|
-
// Interactive setup with enhanced prompts
|
|
774
|
-
console.log(chalk.cyan('š§ Starting interactive project configuration...'));
|
|
775
|
-
console.log(chalk.blue('š” Press Ctrl+C at any time to exit and use defaults'));
|
|
776
|
-
|
|
777
|
-
const questions = [
|
|
778
|
-
{
|
|
779
|
-
type: 'input',
|
|
780
|
-
name: 'projectId',
|
|
781
|
-
message: 'š Project ID (e.g., FEAT-1234, AUTH-456):',
|
|
782
|
-
default: projectName.toUpperCase().replace(/[^A-Z0-9]/g, '-') + '-001',
|
|
783
|
-
validate: (input) => {
|
|
784
|
-
if (!input.trim()) return 'Project ID is required';
|
|
785
|
-
const pattern = /^[A-Z]+-\d+$/;
|
|
786
|
-
if (!pattern.test(input)) {
|
|
787
|
-
return 'Project ID should be in format: PREFIX-NUMBER (e.g., FEAT-1234)';
|
|
788
|
-
}
|
|
789
|
-
return true;
|
|
790
|
-
},
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
type: 'input',
|
|
794
|
-
name: 'projectTitle',
|
|
795
|
-
message: 'š Project Title (descriptive name):',
|
|
796
|
-
default: projectName.charAt(0).toUpperCase() + projectName.slice(1).replace(/-/g, ' '),
|
|
797
|
-
validate: (input) => {
|
|
798
|
-
if (!input.trim()) return 'Project title is required';
|
|
799
|
-
if (input.trim().length < 8) {
|
|
800
|
-
return 'Project title should be at least 8 characters long';
|
|
801
|
-
}
|
|
802
|
-
return true;
|
|
803
|
-
},
|
|
804
|
-
},
|
|
805
|
-
{
|
|
806
|
-
type: 'list',
|
|
807
|
-
name: 'riskTier',
|
|
808
|
-
message: 'ā ļø Risk Tier (higher tier = more rigor):',
|
|
809
|
-
choices: [
|
|
810
|
-
{
|
|
811
|
-
name: 'š“ Tier 1 - Critical (auth, billing, migrations) - Max rigor',
|
|
812
|
-
value: 1,
|
|
813
|
-
},
|
|
814
|
-
{
|
|
815
|
-
name: 'š” Tier 2 - Standard (features, APIs) - Standard rigor',
|
|
816
|
-
value: 2,
|
|
817
|
-
},
|
|
818
|
-
{
|
|
819
|
-
name: 'š¢ Tier 3 - Low Risk (UI, tooling) - Basic rigor',
|
|
820
|
-
value: 3,
|
|
821
|
-
},
|
|
822
|
-
],
|
|
823
|
-
default: 2,
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
type: 'list',
|
|
827
|
-
name: 'projectMode',
|
|
828
|
-
message: 'šÆ Project Mode:',
|
|
829
|
-
choices: [
|
|
830
|
-
{ name: '⨠feature (new functionality)', value: 'feature' },
|
|
831
|
-
{ name: 'š refactor (code restructuring)', value: 'refactor' },
|
|
832
|
-
{ name: 'š fix (bug fixes)', value: 'fix' },
|
|
833
|
-
{ name: 'š doc (documentation)', value: 'doc' },
|
|
834
|
-
{ name: 'š§¹ chore (maintenance)', value: 'chore' },
|
|
835
|
-
],
|
|
836
|
-
default: 'feature',
|
|
837
|
-
},
|
|
838
|
-
{
|
|
839
|
-
type: 'number',
|
|
840
|
-
name: 'maxFiles',
|
|
841
|
-
message: 'š Max files to change:',
|
|
842
|
-
default: (answers) => {
|
|
843
|
-
// Dynamic defaults based on risk tier
|
|
844
|
-
switch (answers.riskTier) {
|
|
845
|
-
case 1:
|
|
846
|
-
return 40;
|
|
847
|
-
case 2:
|
|
848
|
-
return 25;
|
|
849
|
-
case 3:
|
|
850
|
-
return 15;
|
|
851
|
-
default:
|
|
852
|
-
return 25;
|
|
853
|
-
}
|
|
854
|
-
},
|
|
855
|
-
validate: (input) => {
|
|
856
|
-
if (input < 1) return 'Must change at least 1 file';
|
|
857
|
-
return true;
|
|
858
|
-
},
|
|
859
|
-
},
|
|
860
|
-
{
|
|
861
|
-
type: 'number',
|
|
862
|
-
name: 'maxLoc',
|
|
863
|
-
message: 'š Max lines of code to change:',
|
|
864
|
-
default: (answers) => {
|
|
865
|
-
// Dynamic defaults based on risk tier
|
|
866
|
-
switch (answers.riskTier) {
|
|
867
|
-
case 1:
|
|
868
|
-
return 1500;
|
|
869
|
-
case 2:
|
|
870
|
-
return 1000;
|
|
871
|
-
case 3:
|
|
872
|
-
return 600;
|
|
873
|
-
default:
|
|
874
|
-
return 1000;
|
|
875
|
-
}
|
|
876
|
-
},
|
|
877
|
-
validate: (input) => {
|
|
878
|
-
if (input < 1) return 'Must change at least 1 line';
|
|
879
|
-
return true;
|
|
880
|
-
},
|
|
881
|
-
},
|
|
882
|
-
{
|
|
883
|
-
type: 'input',
|
|
884
|
-
name: 'blastModules',
|
|
885
|
-
message: 'š„ Blast Radius - Affected modules (comma-separated):',
|
|
886
|
-
default: 'core,api',
|
|
887
|
-
validate: (input) => {
|
|
888
|
-
if (!input.trim()) return 'At least one module must be specified';
|
|
889
|
-
return true;
|
|
890
|
-
},
|
|
891
|
-
},
|
|
892
|
-
{
|
|
893
|
-
type: 'confirm',
|
|
894
|
-
name: 'dataMigration',
|
|
895
|
-
message: 'šļø Requires data migration?',
|
|
896
|
-
default: false,
|
|
897
|
-
},
|
|
898
|
-
{
|
|
899
|
-
type: 'input',
|
|
900
|
-
name: 'rollbackSlo',
|
|
901
|
-
message: 'ā±ļø Operational rollback SLO (e.g., 5m, 1h, 24h):',
|
|
902
|
-
default: '5m',
|
|
903
|
-
validate: (input) => {
|
|
904
|
-
const pattern = /^([0-9]+m|[0-9]+h|[0-9]+d)$/;
|
|
905
|
-
if (!pattern.test(input)) {
|
|
906
|
-
return 'SLO should be in format: NUMBER + m/h/d (e.g., 5m, 1h, 24h)';
|
|
907
|
-
}
|
|
908
|
-
return true;
|
|
909
|
-
},
|
|
910
|
-
},
|
|
911
|
-
{
|
|
912
|
-
type: 'editor',
|
|
913
|
-
name: 'projectThreats',
|
|
914
|
-
message: 'ā ļø Project Threats & Risks (one per line, ESC to finish):',
|
|
915
|
-
default: (answers) => {
|
|
916
|
-
const baseThreats =
|
|
917
|
-
'- Race condition in concurrent operations\n- Performance degradation under load';
|
|
918
|
-
if (answers.dataMigration) {
|
|
919
|
-
return baseThreats + '\n- Data migration failure\n- Inconsistent data state';
|
|
920
|
-
}
|
|
921
|
-
return baseThreats;
|
|
922
|
-
},
|
|
923
|
-
},
|
|
924
|
-
{
|
|
925
|
-
type: 'input',
|
|
926
|
-
name: 'scopeIn',
|
|
927
|
-
message: "šÆ Scope IN - What's included (comma-separated):",
|
|
928
|
-
default: (answers) => {
|
|
929
|
-
if (answers.projectMode === 'feature') return 'user authentication, api endpoints';
|
|
930
|
-
if (answers.projectMode === 'refactor') return 'authentication module, user service';
|
|
931
|
-
if (answers.projectMode === 'fix') return 'error handling, validation';
|
|
932
|
-
return 'project files';
|
|
933
|
-
},
|
|
934
|
-
validate: (input) => {
|
|
935
|
-
if (!input.trim()) return 'At least one scope item must be specified';
|
|
936
|
-
return true;
|
|
937
|
-
},
|
|
938
|
-
},
|
|
939
|
-
{
|
|
940
|
-
type: 'input',
|
|
941
|
-
name: 'scopeOut',
|
|
942
|
-
message: "š« Scope OUT - What's excluded (comma-separated):",
|
|
943
|
-
default: (answers) => {
|
|
944
|
-
if (answers.projectMode === 'feature')
|
|
945
|
-
return 'legacy authentication, deprecated endpoints';
|
|
946
|
-
if (answers.projectMode === 'refactor')
|
|
947
|
-
return 'external dependencies, configuration files';
|
|
948
|
-
return 'unrelated features';
|
|
949
|
-
},
|
|
950
|
-
},
|
|
951
|
-
{
|
|
952
|
-
type: 'editor',
|
|
953
|
-
name: 'projectInvariants',
|
|
954
|
-
message: 'š”ļø System Invariants (one per line, ESC to finish):',
|
|
955
|
-
default:
|
|
956
|
-
'- System remains available\n- Data consistency maintained\n- User sessions preserved',
|
|
957
|
-
},
|
|
958
|
-
{
|
|
959
|
-
type: 'editor',
|
|
960
|
-
name: 'acceptanceCriteria',
|
|
961
|
-
message: 'ā
Acceptance Criteria (GIVEN...WHEN...THEN, one per line, ESC to finish):',
|
|
962
|
-
default: (answers) => {
|
|
963
|
-
if (answers.projectMode === 'feature') {
|
|
964
|
-
return 'GIVEN user is authenticated WHEN accessing protected endpoint THEN access is granted\nGIVEN invalid credentials WHEN attempting login THEN access is denied';
|
|
965
|
-
}
|
|
966
|
-
if (answers.projectMode === 'fix') {
|
|
967
|
-
return 'GIVEN existing functionality WHEN applying fix THEN behavior is preserved\nGIVEN error condition WHEN fix is applied THEN error is resolved';
|
|
968
|
-
}
|
|
969
|
-
return 'GIVEN current system state WHEN change is applied THEN expected behavior occurs';
|
|
970
|
-
},
|
|
971
|
-
validate: (input) => {
|
|
972
|
-
if (!input.trim()) return 'At least one acceptance criterion is required';
|
|
973
|
-
const lines = input
|
|
974
|
-
.trim()
|
|
975
|
-
.split('\n')
|
|
976
|
-
.filter((line) => line.trim());
|
|
977
|
-
if (lines.length === 0) return 'At least one acceptance criterion is required';
|
|
978
|
-
return true;
|
|
979
|
-
},
|
|
980
|
-
},
|
|
981
|
-
{
|
|
982
|
-
type: 'input',
|
|
983
|
-
name: 'a11yRequirements',
|
|
984
|
-
message: 'āæ Accessibility Requirements (comma-separated):',
|
|
985
|
-
default: 'keyboard navigation, screen reader support, color contrast',
|
|
986
|
-
},
|
|
987
|
-
{
|
|
988
|
-
type: 'number',
|
|
989
|
-
name: 'perfBudget',
|
|
990
|
-
message: 'ā” Performance Budget (API p95 latency in ms):',
|
|
991
|
-
default: 250,
|
|
992
|
-
validate: (input) => {
|
|
993
|
-
if (input < 1) return 'Performance budget must be at least 1ms';
|
|
994
|
-
if (input > 10000) return 'Performance budget seems too high (max 10s)';
|
|
995
|
-
return true;
|
|
996
|
-
},
|
|
997
|
-
},
|
|
998
|
-
{
|
|
999
|
-
type: 'input',
|
|
1000
|
-
name: 'securityRequirements',
|
|
1001
|
-
message: 'š Security Requirements (comma-separated):',
|
|
1002
|
-
default: 'input validation, rate limiting, authentication, authorization',
|
|
1003
|
-
},
|
|
1004
|
-
{
|
|
1005
|
-
type: 'list',
|
|
1006
|
-
name: 'contractType',
|
|
1007
|
-
message: 'š Contract Type:',
|
|
1008
|
-
choices: [
|
|
1009
|
-
{ name: 'OpenAPI (REST APIs)', value: 'openapi' },
|
|
1010
|
-
{ name: 'GraphQL Schema', value: 'graphql' },
|
|
1011
|
-
{ name: 'Protocol Buffers', value: 'proto' },
|
|
1012
|
-
{ name: 'Pact (consumer-driven)', value: 'pact' },
|
|
1013
|
-
],
|
|
1014
|
-
default: 'openapi',
|
|
1015
|
-
},
|
|
1016
|
-
{
|
|
1017
|
-
type: 'input',
|
|
1018
|
-
name: 'contractPath',
|
|
1019
|
-
message: 'š Contract File Path:',
|
|
1020
|
-
default: (answers) => {
|
|
1021
|
-
if (answers.contractType === 'openapi') return 'apps/contracts/api.yaml';
|
|
1022
|
-
if (answers.contractType === 'graphql') return 'apps/contracts/schema.graphql';
|
|
1023
|
-
if (answers.contractType === 'proto') return 'apps/contracts/service.proto';
|
|
1024
|
-
if (answers.contractType === 'pact') return 'apps/contracts/pacts/';
|
|
1025
|
-
return 'apps/contracts/api.yaml';
|
|
1026
|
-
},
|
|
1027
|
-
},
|
|
1028
|
-
{
|
|
1029
|
-
type: 'input',
|
|
1030
|
-
name: 'observabilityLogs',
|
|
1031
|
-
message: 'š Observability - Log Events (comma-separated):',
|
|
1032
|
-
default: 'auth.success, auth.failure, api.request, api.response',
|
|
1033
|
-
},
|
|
1034
|
-
{
|
|
1035
|
-
type: 'input',
|
|
1036
|
-
name: 'observabilityMetrics',
|
|
1037
|
-
message: 'š Observability - Metrics (comma-separated):',
|
|
1038
|
-
default: 'auth_attempts_total, auth_success_total, api_requests_total, api_errors_total',
|
|
1039
|
-
},
|
|
1040
|
-
{
|
|
1041
|
-
type: 'input',
|
|
1042
|
-
name: 'observabilityTraces',
|
|
1043
|
-
message: 'š Observability - Traces (comma-separated):',
|
|
1044
|
-
default: 'auth_flow, api_request',
|
|
1045
|
-
},
|
|
1046
|
-
{
|
|
1047
|
-
type: 'editor',
|
|
1048
|
-
name: 'migrationPlan',
|
|
1049
|
-
message: 'š Migration Plan (one per line, ESC to finish):',
|
|
1050
|
-
default: (answers) => {
|
|
1051
|
-
if (answers.dataMigration) {
|
|
1052
|
-
return '- Create new database schema\n- Add new auth table\n- Migrate existing users\n- Validate data integrity';
|
|
1053
|
-
}
|
|
1054
|
-
return '- Deploy feature flags\n- Roll out gradually\n- Monitor metrics';
|
|
1055
|
-
},
|
|
1056
|
-
validate: (input) => {
|
|
1057
|
-
if (!input.trim()) return 'Migration plan is required';
|
|
1058
|
-
return true;
|
|
1059
|
-
},
|
|
1060
|
-
},
|
|
1061
|
-
{
|
|
1062
|
-
type: 'editor',
|
|
1063
|
-
name: 'rollbackPlan',
|
|
1064
|
-
message: 'š Rollback Plan (one per line, ESC to finish):',
|
|
1065
|
-
default: (answers) => {
|
|
1066
|
-
if (answers.dataMigration) {
|
|
1067
|
-
return '- Feature flag kill-switch\n- Database rollback script\n- Restore from backup\n- Verify system state';
|
|
1068
|
-
}
|
|
1069
|
-
return '- Feature flag disable\n- Deploy previous version\n- Monitor for issues';
|
|
1070
|
-
},
|
|
1071
|
-
validate: (input) => {
|
|
1072
|
-
if (!input.trim()) return 'Rollback plan is required';
|
|
1073
|
-
return true;
|
|
1074
|
-
},
|
|
1075
|
-
},
|
|
1076
|
-
{
|
|
1077
|
-
type: 'confirm',
|
|
1078
|
-
name: 'needsOverride',
|
|
1079
|
-
message: 'šØ Need human override for urgent/low-risk change?',
|
|
1080
|
-
default: false,
|
|
1081
|
-
},
|
|
1082
|
-
{
|
|
1083
|
-
type: 'input',
|
|
1084
|
-
name: 'overrideRationale',
|
|
1085
|
-
message: 'š Override rationale (urgency, low risk, etc.):',
|
|
1086
|
-
when: (answers) => answers.needsOverride,
|
|
1087
|
-
validate: (input) => {
|
|
1088
|
-
if (!input.trim()) return 'Rationale is required for override';
|
|
1089
|
-
return true;
|
|
1090
|
-
},
|
|
1091
|
-
},
|
|
1092
|
-
{
|
|
1093
|
-
type: 'input',
|
|
1094
|
-
name: 'overrideApprover',
|
|
1095
|
-
message: 'š¤ Override approver (GitHub username or email):',
|
|
1096
|
-
when: (answers) => answers.needsOverride,
|
|
1097
|
-
validate: (input) => {
|
|
1098
|
-
if (!input.trim()) return 'Approver is required for override';
|
|
1099
|
-
return true;
|
|
1100
|
-
},
|
|
1101
|
-
},
|
|
1102
|
-
{
|
|
1103
|
-
type: 'checkbox',
|
|
1104
|
-
name: 'waivedGates',
|
|
1105
|
-
message: 'ā ļø Gates to waive (select with space):',
|
|
1106
|
-
choices: [
|
|
1107
|
-
{ name: 'Coverage testing', value: 'coverage' },
|
|
1108
|
-
{ name: 'Mutation testing', value: 'mutation' },
|
|
1109
|
-
{ name: 'Contract testing', value: 'contracts' },
|
|
1110
|
-
{ name: 'Manual review', value: 'manual_review' },
|
|
1111
|
-
{ name: 'Trust score check', value: 'trust_score' },
|
|
1112
|
-
],
|
|
1113
|
-
when: (answers) => answers.needsOverride,
|
|
1114
|
-
validate: (input) => {
|
|
1115
|
-
if (input.length === 0) return 'At least one gate must be waived';
|
|
1116
|
-
return true;
|
|
1117
|
-
},
|
|
1118
|
-
},
|
|
1119
|
-
{
|
|
1120
|
-
type: 'number',
|
|
1121
|
-
name: 'overrideExpiresDays',
|
|
1122
|
-
message: 'ā° Override expires in how many days?',
|
|
1123
|
-
default: 7,
|
|
1124
|
-
when: (answers) => answers.needsOverride,
|
|
1125
|
-
validate: (input) => {
|
|
1126
|
-
if (input < 1) return 'Must expire in at least 1 day';
|
|
1127
|
-
if (input > 30) return 'Cannot exceed 30 days';
|
|
1128
|
-
return true;
|
|
1129
|
-
},
|
|
1130
|
-
},
|
|
1131
|
-
{
|
|
1132
|
-
type: 'confirm',
|
|
1133
|
-
name: 'isExperimental',
|
|
1134
|
-
message: 'š§Ŗ Experimental/Prototype mode? (Reduced requirements for sandbox code)',
|
|
1135
|
-
default: false,
|
|
1136
|
-
},
|
|
1137
|
-
{
|
|
1138
|
-
type: 'input',
|
|
1139
|
-
name: 'experimentalRationale',
|
|
1140
|
-
message: 'š¬ Experimental rationale (what are you exploring?):',
|
|
1141
|
-
when: (answers) => answers.isExperimental,
|
|
1142
|
-
validate: (input) => {
|
|
1143
|
-
if (!input.trim()) return 'Rationale is required for experimental mode';
|
|
1144
|
-
return true;
|
|
1145
|
-
},
|
|
1146
|
-
},
|
|
1147
|
-
{
|
|
1148
|
-
type: 'input',
|
|
1149
|
-
name: 'experimentalSandbox',
|
|
1150
|
-
message: 'š Sandbox location (directory or feature flag):',
|
|
1151
|
-
default: 'experimental/',
|
|
1152
|
-
when: (answers) => answers.isExperimental,
|
|
1153
|
-
validate: (input) => {
|
|
1154
|
-
if (!input.trim()) return 'Sandbox location is required';
|
|
1155
|
-
return true;
|
|
1156
|
-
},
|
|
1157
|
-
},
|
|
1158
|
-
{
|
|
1159
|
-
type: 'number',
|
|
1160
|
-
name: 'experimentalExpiresDays',
|
|
1161
|
-
message: 'ā° Experimental code expires in how many days?',
|
|
1162
|
-
default: 14,
|
|
1163
|
-
when: (answers) => answers.isExperimental,
|
|
1164
|
-
validate: (input) => {
|
|
1165
|
-
if (input < 1) return 'Must expire in at least 1 day';
|
|
1166
|
-
if (input > 90) return 'Cannot exceed 90 days for experimental code';
|
|
1167
|
-
return true;
|
|
1168
|
-
},
|
|
1169
|
-
},
|
|
1170
|
-
{
|
|
1171
|
-
type: 'number',
|
|
1172
|
-
name: 'aiConfidence',
|
|
1173
|
-
message: 'š¤ AI confidence level (1-10, 10 = very confident):',
|
|
1174
|
-
default: 7,
|
|
1175
|
-
validate: (input) => {
|
|
1176
|
-
if (input < 1 || input > 10) return 'Must be between 1 and 10';
|
|
1177
|
-
return true;
|
|
1178
|
-
},
|
|
1179
|
-
},
|
|
1180
|
-
{
|
|
1181
|
-
type: 'input',
|
|
1182
|
-
name: 'uncertaintyAreas',
|
|
1183
|
-
message: 'ā Areas of uncertainty (comma-separated):',
|
|
1184
|
-
default: '',
|
|
1185
|
-
},
|
|
1186
|
-
{
|
|
1187
|
-
type: 'input',
|
|
1188
|
-
name: 'complexityFactors',
|
|
1189
|
-
message: 'š§ Complexity factors (comma-separated):',
|
|
1190
|
-
default: '',
|
|
1191
|
-
},
|
|
1192
|
-
];
|
|
1193
|
-
|
|
1194
|
-
console.log(chalk.cyan('ā³ Gathering project requirements...'));
|
|
1195
|
-
|
|
1196
|
-
let answers;
|
|
1197
|
-
try {
|
|
1198
|
-
answers = await inquirer.prompt(questions);
|
|
1199
|
-
} catch (error) {
|
|
1200
|
-
if (error.isTtyError) {
|
|
1201
|
-
console.error(chalk.red('ā Interactive prompts not supported in this environment'));
|
|
1202
|
-
console.error(chalk.blue('š” Run with --non-interactive flag to use defaults'));
|
|
1203
|
-
process.exit(1);
|
|
1204
|
-
} else {
|
|
1205
|
-
console.error(chalk.red('ā Error during interactive setup:'), error.message);
|
|
1206
|
-
process.exit(1);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
console.log(chalk.green('ā
Project requirements gathered successfully!'));
|
|
1211
|
-
|
|
1212
|
-
// Show summary before generating spec
|
|
1213
|
-
console.log(chalk.bold('\nš Configuration Summary:'));
|
|
1214
|
-
console.log(` ${chalk.cyan('Project')}: ${answers.projectTitle} (${answers.projectId})`);
|
|
1215
|
-
console.log(
|
|
1216
|
-
` ${chalk.cyan('Mode')}: ${answers.projectMode} | ${chalk.cyan('Tier')}: ${answers.riskTier}`
|
|
1217
|
-
);
|
|
1218
|
-
console.log(` ${chalk.cyan('Budget')}: ${answers.maxFiles} files, ${answers.maxLoc} lines`);
|
|
1219
|
-
console.log(` ${chalk.cyan('Data Migration')}: ${answers.dataMigration ? 'Yes' : 'No'}`);
|
|
1220
|
-
console.log(` ${chalk.cyan('Rollback SLO')}: ${answers.rollbackSlo}`);
|
|
1221
|
-
|
|
1222
|
-
// Generate working spec
|
|
1223
|
-
const workingSpecContent = generateWorkingSpec(answers);
|
|
1224
|
-
|
|
1225
|
-
// Validate the generated spec
|
|
1226
|
-
validateGeneratedSpec(workingSpecContent, answers);
|
|
1227
|
-
|
|
1228
|
-
// Save the working spec
|
|
1229
|
-
await fs.writeFile('.caws/working-spec.yaml', workingSpecContent);
|
|
1230
|
-
|
|
1231
|
-
console.log(chalk.green('ā
Working spec generated and validated'));
|
|
1232
|
-
|
|
1233
|
-
// Finalize project with provenance and git initialization
|
|
1234
|
-
await finalizeProject(projectName, options, answers);
|
|
1235
|
-
|
|
1236
|
-
continueToSuccess();
|
|
1237
|
-
}
|
|
1238
|
-
} catch (error) {
|
|
1239
|
-
console.error(chalk.red('ā Error during project initialization:'), error.message);
|
|
1240
|
-
|
|
1241
|
-
// Cleanup on error
|
|
1242
|
-
if (fs.existsSync(projectName)) {
|
|
1243
|
-
console.log(chalk.cyan('š§¹ Cleaning up failed initialization...'));
|
|
1244
|
-
try {
|
|
1245
|
-
await fs.remove(projectName);
|
|
1246
|
-
console.log(chalk.green('ā
Cleanup completed'));
|
|
1247
|
-
} catch (cleanupError) {
|
|
1248
|
-
console.warn(
|
|
1249
|
-
chalk.yellow('ā ļø Could not clean up:'),
|
|
1250
|
-
cleanupError?.message || cleanupError
|
|
1251
|
-
);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
process.exit(1);
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
// Generate provenance manifest and git initialization (for both modes)
|
|
1260
|
-
async function finalizeProject(projectName, options, answers) {
|
|
1261
|
-
try {
|
|
1262
|
-
// Detect and configure language support
|
|
1263
|
-
if (languageSupport) {
|
|
1264
|
-
console.log(chalk.cyan('š Detecting project language...'));
|
|
1265
|
-
const detectedLanguage = languageSupport.detectProjectLanguage();
|
|
1266
|
-
|
|
1267
|
-
if (detectedLanguage !== 'unknown') {
|
|
1268
|
-
console.log(chalk.green(`ā
Detected language: ${detectedLanguage}`));
|
|
1269
|
-
|
|
1270
|
-
// Generate language-specific configuration
|
|
1271
|
-
try {
|
|
1272
|
-
const langConfig = languageSupport.generateLanguageConfig(
|
|
1273
|
-
detectedLanguage,
|
|
1274
|
-
'.caws/language-config.json'
|
|
1275
|
-
);
|
|
1276
|
-
|
|
1277
|
-
console.log(chalk.green('ā
Generated language-specific configuration'));
|
|
1278
|
-
console.log(` Language: ${langConfig.name}`);
|
|
1279
|
-
console.log(` Tier: ${langConfig.tier}`);
|
|
1280
|
-
console.log(
|
|
1281
|
-
` Thresholds: Branch ā„${langConfig.thresholds.min_branch * 100}%, Mutation ā„${langConfig.thresholds.min_mutation * 100}%`
|
|
1282
|
-
);
|
|
1283
|
-
} catch (langError) {
|
|
1284
|
-
console.warn(chalk.yellow('ā ļø Could not generate language config:'), langError.message);
|
|
1285
|
-
}
|
|
1286
|
-
} else {
|
|
1287
|
-
console.log(
|
|
1288
|
-
chalk.blue('ā¹ļø Could not detect project language - using default configuration')
|
|
1289
|
-
);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
// Generate provenance manifest
|
|
1294
|
-
console.log(chalk.cyan('š¦ Generating provenance manifest...'));
|
|
1295
|
-
|
|
1296
|
-
const provenanceData = {
|
|
1297
|
-
agent: 'caws-cli',
|
|
1298
|
-
model: 'cli-interactive',
|
|
1299
|
-
modelHash: CLI_VERSION,
|
|
1300
|
-
toolAllowlist: [
|
|
1301
|
-
'node',
|
|
1302
|
-
'npm',
|
|
1303
|
-
'git',
|
|
1304
|
-
'fs-extra',
|
|
1305
|
-
'inquirer',
|
|
1306
|
-
'commander',
|
|
1307
|
-
'js-yaml',
|
|
1308
|
-
'ajv',
|
|
1309
|
-
'chalk',
|
|
1310
|
-
],
|
|
1311
|
-
prompts: Object.keys(answers),
|
|
1312
|
-
commit: null, // Will be set after git init
|
|
1313
|
-
artifacts: ['.caws/working-spec.yaml'],
|
|
1314
|
-
results: {
|
|
1315
|
-
project_id: answers.projectId,
|
|
1316
|
-
project_title: answers.projectTitle,
|
|
1317
|
-
risk_tier: answers.riskTier,
|
|
1318
|
-
mode: answers.projectMode,
|
|
1319
|
-
change_budget: {
|
|
1320
|
-
max_files: answers.maxFiles,
|
|
1321
|
-
max_loc: answers.maxLoc,
|
|
1322
|
-
},
|
|
1323
|
-
},
|
|
1324
|
-
approvals: [],
|
|
1325
|
-
};
|
|
1326
|
-
|
|
1327
|
-
// Generate provenance if tools are available
|
|
1328
|
-
const tools = loadProvenanceTools();
|
|
1329
|
-
if (
|
|
1330
|
-
tools &&
|
|
1331
|
-
typeof tools.generateProvenance === 'function' &&
|
|
1332
|
-
typeof tools.saveProvenance === 'function'
|
|
1333
|
-
) {
|
|
1334
|
-
const provenance = tools.generateProvenance(provenanceData);
|
|
1335
|
-
await tools.saveProvenance(provenance, '.agent/provenance.json');
|
|
1336
|
-
console.log(chalk.green('ā
Provenance manifest generated'));
|
|
1337
|
-
} else {
|
|
1338
|
-
console.log(
|
|
1339
|
-
chalk.yellow('ā ļø Provenance tools not available - skipping manifest generation')
|
|
1340
|
-
);
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
// Initialize git repository
|
|
1344
|
-
if (options.git) {
|
|
1345
|
-
try {
|
|
1346
|
-
console.log(chalk.cyan('š§ Initializing git repository...'));
|
|
1347
|
-
|
|
1348
|
-
// Check if git is available
|
|
1349
|
-
try {
|
|
1350
|
-
require('child_process').execSync('git --version', { stdio: 'ignore' });
|
|
1351
|
-
} catch (error) {
|
|
1352
|
-
console.warn(chalk.yellow('ā ļø Git not found. Skipping git initialization.'));
|
|
1353
|
-
console.warn(chalk.blue('š” Install git to enable automatic repository setup.'));
|
|
1354
|
-
return;
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
require('child_process').execSync('git init', { stdio: 'inherit' });
|
|
1358
|
-
require('child_process').execSync('git add .', { stdio: 'inherit' });
|
|
1359
|
-
require('child_process').execSync('git commit -m "Initial CAWS project setup"', {
|
|
1360
|
-
stdio: 'inherit',
|
|
1361
|
-
});
|
|
1362
|
-
console.log(chalk.green('ā
Git repository initialized'));
|
|
1363
|
-
|
|
1364
|
-
// Update provenance with commit hash
|
|
1365
|
-
const commitHash = require('child_process')
|
|
1366
|
-
.execSync('git rev-parse HEAD', { encoding: 'utf8' })
|
|
1367
|
-
.trim();
|
|
1368
|
-
const currentProvenance = JSON.parse(fs.readFileSync('.agent/provenance.json', 'utf8'));
|
|
1369
|
-
currentProvenance.commit = commitHash;
|
|
1370
|
-
currentProvenance.hash = require('crypto')
|
|
1371
|
-
.createHash('sha256')
|
|
1372
|
-
.update(JSON.stringify(currentProvenance, Object.keys(currentProvenance).sort()))
|
|
1373
|
-
.digest('hex');
|
|
1374
|
-
await fs.writeFile('.agent/provenance.json', JSON.stringify(currentProvenance, null, 2));
|
|
1375
|
-
|
|
1376
|
-
console.log(chalk.green('ā
Provenance updated with commit hash'));
|
|
1377
|
-
} catch (error) {
|
|
1378
|
-
console.warn(
|
|
1379
|
-
chalk.yellow('ā ļø Failed to initialize git repository:'),
|
|
1380
|
-
error?.message || String(error)
|
|
1381
|
-
);
|
|
1382
|
-
console.warn(chalk.blue('š” You can initialize git manually later with:'));
|
|
1383
|
-
console.warn(" git init && git add . && git commit -m 'Initial CAWS project setup'");
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
} catch (error) {
|
|
1387
|
-
console.error(
|
|
1388
|
-
chalk.red('ā Error during project finalization:'),
|
|
1389
|
-
error?.message || String(error)
|
|
1390
|
-
);
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
function continueToSuccess() {
|
|
1395
|
-
console.log(chalk.green('\nš Project initialized successfully!'));
|
|
1396
|
-
console.log(`š ${chalk.cyan('Project location')}: ${path.resolve(process.cwd())}`);
|
|
1397
|
-
console.log(chalk.bold('\nNext steps:'));
|
|
1398
|
-
console.log('1. Customize .caws/working-spec.yaml');
|
|
1399
|
-
console.log('2. npm install (if using Node.js)');
|
|
1400
|
-
console.log('3. Set up your CI/CD pipeline');
|
|
1401
|
-
console.log(chalk.blue('\nFor help: caws --help'));
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
/**
|
|
1405
|
-
* Scaffold existing project with CAWS components
|
|
1406
|
-
*/
|
|
1407
|
-
async function scaffoldProject(options) {
|
|
1408
|
-
const currentDir = process.cwd();
|
|
1409
|
-
const projectName = path.basename(currentDir);
|
|
1410
|
-
|
|
1411
|
-
console.log(chalk.cyan(`š§ Enhancing existing project with CAWS: ${projectName}`));
|
|
1412
|
-
|
|
1413
|
-
try {
|
|
1414
|
-
// Detect existing CAWS setup with current directory context
|
|
1415
|
-
const setup = detectCAWSSetup(currentDir);
|
|
1416
|
-
|
|
1417
|
-
// Preserve the original template directory from global cawsSetup
|
|
1418
|
-
// (needed because detectCAWSSetup from within a new project won't find the template)
|
|
1419
|
-
if (cawsSetup?.templateDir && !setup.templateDir) {
|
|
1420
|
-
setup.templateDir = cawsSetup.templateDir;
|
|
1421
|
-
setup.hasTemplateDir = true;
|
|
1422
|
-
} else if (!setup.templateDir) {
|
|
1423
|
-
// Try to find template directory using absolute paths that work in CI
|
|
1424
|
-
const possiblePaths = [
|
|
1425
|
-
'/home/runner/work/coding-agent-working-standard/coding-agent-working-standard/packages/caws-template',
|
|
1426
|
-
'/workspace/packages/caws-template',
|
|
1427
|
-
'/caws/packages/caws-template',
|
|
1428
|
-
path.resolve(process.cwd(), '../../../packages/caws-template'),
|
|
1429
|
-
path.resolve(process.cwd(), '../../packages/caws-template'),
|
|
1430
|
-
path.resolve(process.cwd(), '../packages/caws-template'),
|
|
1431
|
-
];
|
|
1432
|
-
|
|
1433
|
-
for (const testPath of possiblePaths) {
|
|
1434
|
-
if (fs.existsSync(testPath)) {
|
|
1435
|
-
setup.templateDir = testPath;
|
|
1436
|
-
setup.hasTemplateDir = true;
|
|
1437
|
-
break;
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
if (!setup.templateDir) {
|
|
1442
|
-
console.log(chalk.red(`ā No template directory available!`));
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// Override global cawsSetup with current context for scaffold operations
|
|
1447
|
-
cawsSetup = setup;
|
|
1448
|
-
|
|
1449
|
-
if (!setup.hasCAWSDir) {
|
|
1450
|
-
console.error(chalk.red('ā No .caws directory found'));
|
|
1451
|
-
console.error(chalk.blue('š” Run "caws init <project-name>" first to create a CAWS project'));
|
|
1452
|
-
process.exit(1);
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
// Adapt behavior based on setup type
|
|
1456
|
-
if (setup.isEnhanced) {
|
|
1457
|
-
console.log(chalk.green('šÆ Enhanced CAWS detected - adding automated publishing'));
|
|
1458
|
-
} else if (setup.isAdvanced) {
|
|
1459
|
-
console.log(chalk.blue('š§ Advanced CAWS detected - adding missing capabilities'));
|
|
1460
|
-
} else {
|
|
1461
|
-
console.log(chalk.blue('š Basic CAWS detected - enhancing with additional tools'));
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
// Generate provenance for scaffolding operation
|
|
1465
|
-
const scaffoldProvenance = {
|
|
1466
|
-
agent: 'caws-cli',
|
|
1467
|
-
model: 'cli-scaffold',
|
|
1468
|
-
modelHash: CLI_VERSION,
|
|
1469
|
-
toolAllowlist: ['node', 'fs-extra'],
|
|
1470
|
-
prompts: ['scaffold', options.force ? 'force' : 'normal'],
|
|
1471
|
-
commit: null,
|
|
1472
|
-
artifacts: [],
|
|
1473
|
-
results: {
|
|
1474
|
-
operation: 'scaffold',
|
|
1475
|
-
force_mode: options.force,
|
|
1476
|
-
target_directory: currentDir,
|
|
1477
|
-
},
|
|
1478
|
-
approvals: [],
|
|
1479
|
-
timestamp: new Date().toISOString(),
|
|
1480
|
-
version: CLI_VERSION,
|
|
1481
|
-
};
|
|
1482
|
-
|
|
1483
|
-
// Calculate hash after object is fully defined
|
|
1484
|
-
scaffoldProvenance.hash = require('crypto')
|
|
1485
|
-
.createHash('sha256')
|
|
1486
|
-
.update(JSON.stringify(scaffoldProvenance))
|
|
1487
|
-
.digest('hex');
|
|
1488
|
-
|
|
1489
|
-
// Determine what enhancements to add based on setup type
|
|
1490
|
-
const enhancements = [];
|
|
1491
|
-
|
|
1492
|
-
// Add CAWS tools directory structure (matches test expectations)
|
|
1493
|
-
enhancements.push({
|
|
1494
|
-
name: 'apps/tools/caws',
|
|
1495
|
-
description: 'CAWS tools directory',
|
|
1496
|
-
required: true,
|
|
1497
|
-
});
|
|
1498
|
-
|
|
1499
|
-
enhancements.push({
|
|
1500
|
-
name: 'codemod',
|
|
1501
|
-
description: 'Codemod transformation scripts',
|
|
1502
|
-
required: true,
|
|
1503
|
-
});
|
|
1504
|
-
|
|
1505
|
-
// Also add automated publishing for enhanced setups
|
|
1506
|
-
if (setup.isEnhanced) {
|
|
1507
|
-
enhancements.push({
|
|
1508
|
-
name: '.github/workflows/release.yml',
|
|
1509
|
-
description: 'GitHub Actions workflow for automated publishing',
|
|
1510
|
-
required: true,
|
|
1511
|
-
});
|
|
1512
|
-
|
|
1513
|
-
enhancements.push({
|
|
1514
|
-
name: '.releaserc.json',
|
|
1515
|
-
description: 'semantic-release configuration',
|
|
1516
|
-
required: true,
|
|
1517
|
-
});
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
// Add commit conventions for setups that don't have them
|
|
1521
|
-
if (!setup.hasTemplates || !fs.existsSync(path.join(currentDir, 'COMMIT_CONVENTIONS.md'))) {
|
|
1522
|
-
enhancements.push({
|
|
1523
|
-
name: 'COMMIT_CONVENTIONS.md',
|
|
1524
|
-
description: 'Commit message guidelines',
|
|
1525
|
-
required: false,
|
|
1526
|
-
});
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
// Add OIDC setup guide for setups that need it
|
|
1530
|
-
if (!setup.isEnhanced || !fs.existsSync(path.join(currentDir, 'OIDC_SETUP.md'))) {
|
|
1531
|
-
enhancements.push({
|
|
1532
|
-
name: 'OIDC_SETUP.md',
|
|
1533
|
-
description: 'OIDC trusted publisher setup guide',
|
|
1534
|
-
required: false,
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
// For enhanced setups, preserve existing tools
|
|
1539
|
-
if (setup.isEnhanced) {
|
|
1540
|
-
console.log(chalk.blue('ā¹ļø Preserving existing sophisticated CAWS tools'));
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
let addedCount = 0;
|
|
1544
|
-
let skippedCount = 0;
|
|
1545
|
-
const addedFiles = [];
|
|
1546
|
-
|
|
1547
|
-
for (const enhancement of enhancements) {
|
|
1548
|
-
if (!setup?.templateDir) {
|
|
1549
|
-
console.warn(
|
|
1550
|
-
chalk.yellow(`ā ļø Template directory not available for enhancement: ${enhancement.name}`)
|
|
1551
|
-
);
|
|
1552
|
-
continue;
|
|
1553
|
-
}
|
|
1554
|
-
const sourcePath = path.join(setup.templateDir, enhancement.name);
|
|
1555
|
-
const destPath = path.join(currentDir, enhancement.name);
|
|
1556
|
-
|
|
1557
|
-
if (!fs.existsSync(destPath)) {
|
|
1558
|
-
if (fs.existsSync(sourcePath)) {
|
|
1559
|
-
try {
|
|
1560
|
-
await fs.copy(sourcePath, destPath);
|
|
1561
|
-
console.log(chalk.green(`ā
Added ${enhancement.description}`));
|
|
1562
|
-
addedCount++;
|
|
1563
|
-
addedFiles.push(enhancement.name);
|
|
1564
|
-
} catch (copyError) {
|
|
1565
|
-
console.warn(chalk.yellow(`ā ļø Failed to add ${enhancement.name}:`), copyError.message);
|
|
1566
|
-
}
|
|
1567
|
-
} else {
|
|
1568
|
-
// If source doesn't exist in template, create the directory structure
|
|
1569
|
-
try {
|
|
1570
|
-
await fs.ensureDir(destPath);
|
|
1571
|
-
console.log(chalk.green(`ā
Created ${enhancement.description}`));
|
|
1572
|
-
addedCount++;
|
|
1573
|
-
addedFiles.push(enhancement.name);
|
|
1574
|
-
} catch (createError) {
|
|
1575
|
-
console.warn(
|
|
1576
|
-
chalk.yellow(`ā ļø Failed to create ${enhancement.name}:`),
|
|
1577
|
-
createError.message
|
|
1578
|
-
);
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
} else {
|
|
1582
|
-
if (options.force) {
|
|
1583
|
-
try {
|
|
1584
|
-
await fs.remove(destPath);
|
|
1585
|
-
if (fs.existsSync(sourcePath)) {
|
|
1586
|
-
await fs.copy(sourcePath, destPath);
|
|
1587
|
-
} else {
|
|
1588
|
-
await fs.ensureDir(destPath);
|
|
1589
|
-
}
|
|
1590
|
-
console.log(chalk.blue(`š Updated ${enhancement.description}`));
|
|
1591
|
-
addedCount++;
|
|
1592
|
-
addedFiles.push(enhancement.name);
|
|
1593
|
-
} catch (overwriteError) {
|
|
1594
|
-
console.warn(
|
|
1595
|
-
chalk.yellow(`ā ļø Failed to update ${enhancement.name}:`),
|
|
1596
|
-
overwriteError.message
|
|
1597
|
-
);
|
|
1598
|
-
}
|
|
1599
|
-
} else {
|
|
1600
|
-
console.log(`āļø Skipped ${enhancement.name} (already exists)`);
|
|
1601
|
-
skippedCount++;
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
// Update provenance with results
|
|
1607
|
-
scaffoldProvenance.artifacts = addedFiles;
|
|
1608
|
-
scaffoldProvenance.results.files_added = addedCount;
|
|
1609
|
-
scaffoldProvenance.results.files_skipped = skippedCount;
|
|
1610
|
-
|
|
1611
|
-
// Show summary
|
|
1612
|
-
console.log(chalk.green(`\nš Enhancement completed!`));
|
|
1613
|
-
console.log(chalk.bold(`š Summary: ${addedCount} added, ${skippedCount} skipped`));
|
|
1614
|
-
|
|
1615
|
-
if (addedCount > 0) {
|
|
1616
|
-
console.log(chalk.bold('\nš Next steps:'));
|
|
1617
|
-
console.log('1. Review the added files');
|
|
1618
|
-
console.log('2. Set up OIDC trusted publisher (see OIDC_SETUP.md)');
|
|
1619
|
-
console.log('3. Push to trigger automated publishing');
|
|
1620
|
-
console.log('4. Your existing CAWS tools remain unchanged');
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
if (setup.isEnhanced) {
|
|
1624
|
-
console.log(
|
|
1625
|
-
chalk.blue('\nšÆ Your enhanced CAWS setup has been improved with automated publishing!')
|
|
1626
|
-
);
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
if (options.force) {
|
|
1630
|
-
console.log(chalk.yellow('\nā ļø Force mode was used - review changes carefully'));
|
|
1631
|
-
}
|
|
1632
|
-
|
|
1633
|
-
// Save provenance manifest if tools are available
|
|
1634
|
-
const tools = loadProvenanceTools();
|
|
1635
|
-
if (tools && typeof tools.saveProvenance === 'function') {
|
|
1636
|
-
await tools.saveProvenance(scaffoldProvenance, '.agent/scaffold-provenance.json');
|
|
1637
|
-
console.log(chalk.green('ā
Scaffolding provenance saved'));
|
|
1638
|
-
} else {
|
|
1639
|
-
console.log(chalk.yellow('ā ļø Provenance tools not available - skipping manifest save'));
|
|
1640
|
-
}
|
|
1641
|
-
} catch (error) {
|
|
1642
|
-
// Handle circular reference errors from Commander.js
|
|
1643
|
-
if (error.message && error.message.includes('Converting circular structure to JSON')) {
|
|
1644
|
-
console.log(
|
|
1645
|
-
chalk.yellow('ā ļø Scaffolding completed with minor issues (circular reference handled)')
|
|
1646
|
-
);
|
|
1647
|
-
console.log(chalk.green('ā
CAWS components scaffolded successfully'));
|
|
1648
|
-
} else {
|
|
1649
|
-
console.error(chalk.red('ā Error during scaffolding:'), error.message);
|
|
1650
|
-
process.exit(1);
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
60
|
+
// Set up dependencies for modules that need them
|
|
61
|
+
setScaffoldDependencies({
|
|
62
|
+
cawsSetup,
|
|
63
|
+
loadProvenanceTools,
|
|
64
|
+
});
|
|
1654
65
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
// console.log(chalk.bold(`CAWS CLI v${CLI_VERSION}`));
|
|
1660
|
-
// console.log(chalk.cyan('Coding Agent Workflow System - Scaffolding Tool'));
|
|
1661
|
-
// console.log(chalk.gray('Author: @darianrosebrook'));
|
|
1662
|
-
// console.log(chalk.gray('License: MIT'));
|
|
1663
|
-
// }
|
|
66
|
+
setFinalizationDependencies({
|
|
67
|
+
languageSupport,
|
|
68
|
+
loadProvenanceTools,
|
|
69
|
+
});
|
|
1664
70
|
|
|
1665
|
-
// CLI
|
|
1666
|
-
program
|
|
1667
|
-
.name('caws')
|
|
1668
|
-
.description('CAWS - Coding Agent Workflow System CLI')
|
|
1669
|
-
.version(CLI_VERSION, '-v, --version', 'Show version information');
|
|
71
|
+
// Setup CLI program
|
|
72
|
+
program.name('caws').description('CAWS - Coding Agent Workflow System CLI').version(CLI_VERSION);
|
|
1670
73
|
|
|
74
|
+
// Init command
|
|
1671
75
|
program
|
|
1672
76
|
.command('init')
|
|
1673
|
-
.alias('i')
|
|
1674
77
|
.description('Initialize a new project with CAWS')
|
|
1675
|
-
.argument('
|
|
1676
|
-
.option('-i, --interactive', 'Run interactive setup', true)
|
|
1677
|
-
.option('-
|
|
1678
|
-
.option('
|
|
1679
|
-
.option('--no-git', "Don't initialize git repository")
|
|
78
|
+
.argument('[project-name]', 'Name of the project to create (use "." for current directory)')
|
|
79
|
+
.option('-i, --interactive', 'Run interactive setup wizard', true)
|
|
80
|
+
.option('--non-interactive', 'Skip interactive prompts (use defaults)', false)
|
|
81
|
+
.option('--template <template>', 'Use specific project template')
|
|
1680
82
|
.action(initProject);
|
|
1681
83
|
|
|
84
|
+
// Scaffold command
|
|
1682
85
|
program
|
|
1683
86
|
.command('scaffold')
|
|
1684
|
-
.alias('s')
|
|
1685
87
|
.description('Add CAWS components to existing project')
|
|
1686
|
-
.option('-f, --force', 'Overwrite existing files')
|
|
88
|
+
.option('-f, --force', 'Overwrite existing files', false)
|
|
89
|
+
.option('--minimal', 'Only essential components', false)
|
|
90
|
+
.option('--with-codemods', 'Include codemod scripts', false)
|
|
91
|
+
.option('--with-oidc', 'Include OIDC trusted publisher setup', false)
|
|
1687
92
|
.action(scaffoldProject);
|
|
1688
93
|
|
|
94
|
+
// Validate command
|
|
95
|
+
program
|
|
96
|
+
.command('validate')
|
|
97
|
+
.description('Validate CAWS working spec with suggestions')
|
|
98
|
+
.argument('[spec-file]', 'Path to working spec file (default: .caws/working-spec.yaml)')
|
|
99
|
+
.option('-q, --quiet', 'Suppress suggestions and warnings', false)
|
|
100
|
+
.option('--auto-fix', 'Automatically fix safe validation issues', false)
|
|
101
|
+
.action(validateCommand);
|
|
102
|
+
|
|
103
|
+
// Tool command
|
|
104
|
+
program
|
|
105
|
+
.command('tool')
|
|
106
|
+
.description('Execute CAWS tools programmatically')
|
|
107
|
+
.argument('<tool-id>', 'ID of the tool to execute')
|
|
108
|
+
.option('-p, --params <json>', 'Parameters as JSON string', '{}')
|
|
109
|
+
.option('-t, --timeout <ms>', 'Execution timeout in milliseconds', parseInt, 30000)
|
|
110
|
+
.action(executeTool);
|
|
111
|
+
|
|
112
|
+
// Test Analysis command
|
|
113
|
+
program
|
|
114
|
+
.command('test-analysis <subcommand> [options...]')
|
|
115
|
+
.description('Statistical analysis for budget prediction and test optimization')
|
|
116
|
+
.action(testAnalysisCommand);
|
|
117
|
+
|
|
118
|
+
// Provenance command
|
|
119
|
+
program
|
|
120
|
+
.command('provenance')
|
|
121
|
+
.description('Manage CAWS provenance tracking and audit trails')
|
|
122
|
+
.argument('<subcommand>', 'Command: update, show, verify, analyze-ai')
|
|
123
|
+
.option('-c, --commit <hash>', 'Git commit hash')
|
|
124
|
+
.option('-m, --message <msg>', 'Commit message')
|
|
125
|
+
.option('-a, --author <info>', 'Author information')
|
|
126
|
+
.option('-q, --quiet', 'Suppress output')
|
|
127
|
+
.option('-o, --output <path>', 'Output path for provenance files')
|
|
128
|
+
.action(provenanceCommand);
|
|
129
|
+
|
|
1689
130
|
// Error handling
|
|
1690
131
|
program.exitOverride((err) => {
|
|
1691
132
|
if (
|
|
@@ -1699,7 +140,7 @@ program.exitOverride((err) => {
|
|
|
1699
140
|
process.exit(1);
|
|
1700
141
|
});
|
|
1701
142
|
|
|
1702
|
-
// Parse and run
|
|
143
|
+
// Parse and run
|
|
1703
144
|
if (require.main === module) {
|
|
1704
145
|
try {
|
|
1705
146
|
program.parse();
|