@paths.design/caws-cli 3.2.4 → 3.3.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.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Diagnose command handler
3
+ * @param {Object} options - Command options
4
+ */
5
+ export function diagnoseCommand(options?: any): Promise<void>;
6
+ /**
7
+ * Run all health checks
8
+ * @returns {Promise<Object>} Diagnosis results
9
+ */
10
+ export function runDiagnosis(): Promise<any>;
11
+ /**
12
+ * Display diagnosis results
13
+ * @param {Object[]} results - Diagnosis results
14
+ */
15
+ export function displayResults(results: any[]): void;
16
+ /**
17
+ * Apply automatic fixes
18
+ * @param {Object[]} results - Diagnosis results
19
+ * @returns {Promise<Object>} Fix results
20
+ */
21
+ export function applyAutoFixes(results: any[]): Promise<any>;
22
+ /**
23
+ * Health check: Working spec validity
24
+ * @returns {Promise<Object>} Check result
25
+ */
26
+ export function checkWorkingSpec(): Promise<any>;
27
+ /**
28
+ * Health check: Git repository
29
+ * @returns {Promise<Object>} Check result
30
+ */
31
+ export function checkGitSetup(): Promise<any>;
32
+ /**
33
+ * Health check: Git hooks
34
+ * @returns {Promise<Object>} Check result
35
+ */
36
+ export function checkGitHooks(): Promise<any>;
37
+ /**
38
+ * Health check: TypeScript configuration
39
+ * @returns {Promise<Object>} Check result
40
+ */
41
+ export function checkTypeScriptConfig(): Promise<any>;
42
+ /**
43
+ * Health check: Test files exist
44
+ * @returns {Promise<Object>} Check result
45
+ */
46
+ export function checkTestFiles(): Promise<any>;
47
+ /**
48
+ * Health check: CAWS tools directory
49
+ * @returns {Promise<Object>} Check result
50
+ */
51
+ export function checkCAWSTools(): Promise<any>;
52
+ //# sourceMappingURL=diagnose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../src/commands/diagnose.js"],"names":[],"mappings":"AAoZA;;;GAGG;AACH,8DAiDC;AApMD;;;GAGG;AACH,gCAFa,OAAO,KAAQ,CAkD3B;AAED;;;GAGG;AACH,wCAFW,KAAQ,QA4BlB;AAED;;;;GAIG;AACH,wCAHW,KAAQ,GACN,OAAO,KAAQ,CAoD3B;AAnYD;;;GAGG;AACH,oCAFa,OAAO,KAAQ,CA2C3B;AAED;;;GAGG;AACH,iCAFa,OAAO,KAAQ,CAiB3B;AAED;;;GAGG;AACH,iCAFa,OAAO,KAAQ,CA0C3B;AAED;;;GAGG;AACH,yCAFa,OAAO,KAAQ,CA6C3B;AAED;;;GAGG;AACH,kCAFa,OAAO,KAAQ,CAoC3B;AAED;;;GAGG;AACH,kCAFa,OAAO,KAAQ,CAuC3B"}
@@ -0,0 +1,472 @@
1
+ /**
2
+ * @fileoverview CAWS Diagnose Command
3
+ * Run health checks and suggest fixes
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const yaml = require('js-yaml');
10
+ const chalk = require('chalk');
11
+
12
+ // Import utilities
13
+ const { checkTypeScriptTestConfig } = require('../utils/typescript-detector');
14
+ const { configureJestForTypeScript } = require('../generators/jest-config');
15
+
16
+ /**
17
+ * Health check: Working spec validity
18
+ * @returns {Promise<Object>} Check result
19
+ */
20
+ async function checkWorkingSpec() {
21
+ const specPath = '.caws/working-spec.yaml';
22
+
23
+ if (!(await fs.pathExists(specPath))) {
24
+ return {
25
+ passed: false,
26
+ severity: 'high',
27
+ message: 'Working spec not found',
28
+ fix: 'Initialize CAWS: caws init .',
29
+ autoFixable: false,
30
+ };
31
+ }
32
+
33
+ try {
34
+ const content = await fs.readFile(specPath, 'utf8');
35
+ const spec = yaml.load(content);
36
+
37
+ // Basic validation
38
+ if (!spec.id || !spec.title || !spec.risk_tier) {
39
+ return {
40
+ passed: false,
41
+ severity: 'high',
42
+ message: 'Working spec missing required fields',
43
+ fix: 'Run: caws validate for details',
44
+ autoFixable: false,
45
+ };
46
+ }
47
+
48
+ return {
49
+ passed: true,
50
+ message: 'Working spec is valid',
51
+ };
52
+ } catch (error) {
53
+ return {
54
+ passed: false,
55
+ severity: 'high',
56
+ message: `Working spec has errors: ${error.message}`,
57
+ fix: 'Run: caws validate for details',
58
+ autoFixable: false,
59
+ };
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Health check: Git repository
65
+ * @returns {Promise<Object>} Check result
66
+ */
67
+ async function checkGitSetup() {
68
+ if (!(await fs.pathExists('.git'))) {
69
+ return {
70
+ passed: false,
71
+ severity: 'medium',
72
+ message: 'Not a git repository',
73
+ fix: 'Initialize git: git init',
74
+ autoFixable: false,
75
+ };
76
+ }
77
+
78
+ return {
79
+ passed: true,
80
+ message: 'Git repository initialized',
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Health check: Git hooks
86
+ * @returns {Promise<Object>} Check result
87
+ */
88
+ async function checkGitHooks() {
89
+ const hooksDir = '.git/hooks';
90
+
91
+ if (!(await fs.pathExists(hooksDir))) {
92
+ return {
93
+ passed: false,
94
+ severity: 'medium',
95
+ message: 'Git hooks directory not found',
96
+ fix: 'Ensure .git directory exists',
97
+ autoFixable: false,
98
+ };
99
+ }
100
+
101
+ const cawsHooks = ['pre-commit', 'post-commit', 'pre-push'];
102
+ let installedCount = 0;
103
+
104
+ for (const hook of cawsHooks) {
105
+ const hookPath = path.join(hooksDir, hook);
106
+ if (await fs.pathExists(hookPath)) {
107
+ const content = await fs.readFile(hookPath, 'utf8');
108
+ if (content.includes('CAWS')) {
109
+ installedCount++;
110
+ }
111
+ }
112
+ }
113
+
114
+ if (installedCount === 0) {
115
+ return {
116
+ passed: false,
117
+ severity: 'low',
118
+ message: 'No CAWS git hooks installed',
119
+ fix: 'Install hooks: caws hooks install',
120
+ autoFixable: false,
121
+ };
122
+ }
123
+
124
+ return {
125
+ passed: true,
126
+ message: `${installedCount}/${cawsHooks.length} CAWS hooks installed`,
127
+ };
128
+ }
129
+
130
+ /**
131
+ * Health check: TypeScript configuration
132
+ * @returns {Promise<Object>} Check result
133
+ */
134
+ async function checkTypeScriptConfig() {
135
+ const tsConfig = checkTypeScriptTestConfig('.');
136
+
137
+ if (!tsConfig.isTypeScript) {
138
+ return {
139
+ passed: true,
140
+ message: 'Not a TypeScript project (check skipped)',
141
+ skipped: true,
142
+ };
143
+ }
144
+
145
+ if (tsConfig.needsJestConfig) {
146
+ return {
147
+ passed: false,
148
+ severity: 'medium',
149
+ message: 'TypeScript project missing Jest configuration',
150
+ fix: 'Auto-configure Jest for TypeScript',
151
+ autoFixable: true,
152
+ autoFix: async () => {
153
+ const result = await configureJestForTypeScript('.', { quiet: false });
154
+ return {
155
+ success: result.configured,
156
+ message: 'Jest configuration created',
157
+ nextSteps: result.nextSteps,
158
+ };
159
+ },
160
+ };
161
+ }
162
+
163
+ if (tsConfig.needsTsJest) {
164
+ return {
165
+ passed: false,
166
+ severity: 'high',
167
+ message: 'TypeScript + Jest detected but missing ts-jest',
168
+ fix: 'Install ts-jest: npm install --save-dev ts-jest',
169
+ autoFixable: false,
170
+ };
171
+ }
172
+
173
+ return {
174
+ passed: true,
175
+ message: 'TypeScript configuration is correct',
176
+ };
177
+ }
178
+
179
+ /**
180
+ * Health check: Test files exist
181
+ * @returns {Promise<Object>} Check result
182
+ */
183
+ async function checkTestFiles() {
184
+ const testsDirs = ['tests', 'test', '__tests__', 'spec'];
185
+ let testsDir = null;
186
+
187
+ for (const dir of testsDirs) {
188
+ if (await fs.pathExists(dir)) {
189
+ testsDir = dir;
190
+ break;
191
+ }
192
+ }
193
+
194
+ if (!testsDir) {
195
+ return {
196
+ passed: false,
197
+ severity: 'medium',
198
+ message: 'No tests directory found',
199
+ fix: 'Create tests directory: mkdir tests',
200
+ autoFixable: true,
201
+ autoFix: async () => {
202
+ await fs.ensureDir('tests');
203
+ await fs.ensureDir('tests/unit');
204
+ await fs.ensureDir('tests/integration');
205
+ return {
206
+ success: true,
207
+ message: 'Created tests/ directory structure',
208
+ };
209
+ },
210
+ };
211
+ }
212
+
213
+ return {
214
+ passed: true,
215
+ message: `Tests directory exists: ${testsDir}/`,
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Health check: CAWS tools directory
221
+ * @returns {Promise<Object>} Check result
222
+ */
223
+ async function checkCAWSTools() {
224
+ const toolsPath = 'apps/tools/caws';
225
+
226
+ if (!(await fs.pathExists(toolsPath))) {
227
+ return {
228
+ passed: false,
229
+ severity: 'low',
230
+ message: 'CAWS tools directory not found',
231
+ fix: 'Scaffold tools: caws scaffold',
232
+ autoFixable: false,
233
+ };
234
+ }
235
+
236
+ // Check for essential tools
237
+ const essentialTools = ['validate.js', 'gates.js', 'provenance.js'];
238
+ let missingTools = [];
239
+
240
+ for (const tool of essentialTools) {
241
+ if (!(await fs.pathExists(path.join(toolsPath, tool)))) {
242
+ missingTools.push(tool);
243
+ }
244
+ }
245
+
246
+ if (missingTools.length > 0) {
247
+ return {
248
+ passed: false,
249
+ severity: 'medium',
250
+ message: `Missing ${missingTools.length} essential tools`,
251
+ fix: 'Re-scaffold tools: caws scaffold --force',
252
+ autoFixable: false,
253
+ };
254
+ }
255
+
256
+ return {
257
+ passed: true,
258
+ message: 'All essential CAWS tools present',
259
+ };
260
+ }
261
+
262
+ /**
263
+ * Run all health checks
264
+ * @returns {Promise<Object>} Diagnosis results
265
+ */
266
+ async function runDiagnosis() {
267
+ const checks = [
268
+ { name: 'Working spec validity', fn: checkWorkingSpec },
269
+ { name: 'Git repository', fn: checkGitSetup },
270
+ { name: 'Git hooks', fn: checkGitHooks },
271
+ { name: 'TypeScript configuration', fn: checkTypeScriptConfig },
272
+ { name: 'Test files', fn: checkTestFiles },
273
+ { name: 'CAWS tools', fn: checkCAWSTools },
274
+ ];
275
+
276
+ console.log(chalk.cyan('\nšŸ” Diagnosing CAWS Project...\n'));
277
+ console.log(chalk.gray('Running checks:'));
278
+
279
+ const results = [];
280
+
281
+ for (const check of checks) {
282
+ process.stdout.write(chalk.gray(` ${check.name}... `));
283
+
284
+ try {
285
+ const result = await check.fn();
286
+
287
+ if (result.skipped) {
288
+ console.log(chalk.gray('skipped'));
289
+ } else if (result.passed) {
290
+ console.log(chalk.green('āœ…'));
291
+ } else {
292
+ const icon = result.severity === 'high' ? chalk.red('āŒ') : chalk.yellow('āš ļø');
293
+ console.log(icon);
294
+ }
295
+
296
+ results.push({
297
+ name: check.name,
298
+ ...result,
299
+ });
300
+ } catch (error) {
301
+ console.log(chalk.red('āŒ'));
302
+ results.push({
303
+ name: check.name,
304
+ passed: false,
305
+ severity: 'high',
306
+ message: `Check failed: ${error.message}`,
307
+ fix: 'Review error and try again',
308
+ autoFixable: false,
309
+ });
310
+ }
311
+ }
312
+
313
+ return results;
314
+ }
315
+
316
+ /**
317
+ * Display diagnosis results
318
+ * @param {Object[]} results - Diagnosis results
319
+ */
320
+ function displayResults(results) {
321
+ const issues = results.filter((r) => !r.passed && !r.skipped);
322
+
323
+ if (issues.length === 0) {
324
+ console.log(chalk.green('\nāœ… No issues found! Your CAWS project is healthy.\n'));
325
+ return;
326
+ }
327
+
328
+ console.log(
329
+ chalk.bold.yellow(`\nāš ļø Found ${issues.length} issue${issues.length > 1 ? 's' : ''}:\n`)
330
+ );
331
+
332
+ issues.forEach((issue, index) => {
333
+ const icon = issue.severity === 'high' ? chalk.red('āŒ') : chalk.yellow('āš ļø');
334
+ const severity = chalk.gray(`[${issue.severity.toUpperCase()}]`);
335
+
336
+ console.log(`${index + 1}. ${icon} ${issue.name} ${severity}`);
337
+ console.log(chalk.white(` Issue: ${issue.message}`));
338
+ console.log(chalk.cyan(` Fix: ${issue.fix}`));
339
+
340
+ if (issue.autoFixable) {
341
+ console.log(chalk.green(' ✨ Auto-fix available'));
342
+ }
343
+
344
+ console.log('');
345
+ });
346
+ }
347
+
348
+ /**
349
+ * Apply automatic fixes
350
+ * @param {Object[]} results - Diagnosis results
351
+ * @returns {Promise<Object>} Fix results
352
+ */
353
+ async function applyAutoFixes(results) {
354
+ const fixableIssues = results.filter((r) => !r.passed && r.autoFixable && r.autoFix);
355
+
356
+ if (fixableIssues.length === 0) {
357
+ console.log(chalk.yellow('\nāš ļø No auto-fixable issues found\n'));
358
+ return {
359
+ applied: 0,
360
+ skipped: 0,
361
+ failed: 0,
362
+ };
363
+ }
364
+
365
+ console.log(chalk.cyan(`\nšŸ”§ Applying ${fixableIssues.length} automatic fixes...\n`));
366
+
367
+ let applied = 0;
368
+ let failed = 0;
369
+
370
+ for (const issue of fixableIssues) {
371
+ process.stdout.write(chalk.gray(` Fixing: ${issue.name}... `));
372
+
373
+ try {
374
+ const result = await issue.autoFix();
375
+
376
+ if (result.success) {
377
+ console.log(chalk.green('āœ…'));
378
+ applied++;
379
+
380
+ if (result.nextSteps && result.nextSteps.length > 0) {
381
+ console.log(chalk.blue(' Next steps:'));
382
+ result.nextSteps.forEach((step) => {
383
+ console.log(chalk.blue(` ${step}`));
384
+ });
385
+ }
386
+ } else {
387
+ console.log(chalk.red('āŒ'));
388
+ failed++;
389
+ }
390
+ } catch (error) {
391
+ console.log(chalk.red(`āŒ ${error.message}`));
392
+ failed++;
393
+ }
394
+ }
395
+
396
+ console.log(chalk.bold.green(`\nšŸ“Š Results: ${applied} fixed, ${failed} failed\n`));
397
+
398
+ return {
399
+ applied,
400
+ skipped: results.filter((r) => !r.passed && !r.autoFixable).length,
401
+ failed,
402
+ };
403
+ }
404
+
405
+ /**
406
+ * Diagnose command handler
407
+ * @param {Object} options - Command options
408
+ */
409
+ async function diagnoseCommand(options = {}) {
410
+ try {
411
+ // Run all health checks
412
+ const results = await runDiagnosis();
413
+
414
+ // Display results
415
+ displayResults(results);
416
+
417
+ // Check if there are auto-fixable issues
418
+ const fixableCount = results.filter((r) => !r.passed && r.autoFixable).length;
419
+
420
+ if (fixableCount > 0 && !options.fix) {
421
+ console.log(
422
+ chalk.yellow(
423
+ `šŸ’” ${fixableCount} issue${fixableCount > 1 ? 's' : ''} can be fixed automatically`
424
+ )
425
+ );
426
+ console.log(chalk.yellow(' Run: caws diagnose --fix to apply fixes\n'));
427
+ } else if (options.fix) {
428
+ const fixResults = await applyAutoFixes(results);
429
+
430
+ if (fixResults.applied > 0) {
431
+ console.log(chalk.green('āœ… Auto-fixes applied successfully'));
432
+ console.log(chalk.blue('šŸ’” Run: caws validate to verify fixes\n'));
433
+ }
434
+
435
+ if (fixResults.skipped > 0) {
436
+ console.log(
437
+ chalk.yellow(
438
+ `āš ļø ${fixResults.skipped} issue${fixResults.skipped > 1 ? 's' : ''} require manual intervention\n`
439
+ )
440
+ );
441
+ }
442
+ }
443
+
444
+ // Provide next steps
445
+ const issueCount = results.filter((r) => !r.passed && !r.skipped).length;
446
+
447
+ if (issueCount === 0) {
448
+ console.log(chalk.blue('šŸ“š Next steps:'));
449
+ console.log(chalk.blue(' • Run: caws status to view project health'));
450
+ console.log(chalk.blue(' • Run: caws validate to check working spec'));
451
+ console.log(chalk.blue(' • Run: node apps/tools/caws/gates.js for quality gates'));
452
+ }
453
+ } catch (error) {
454
+ console.error(chalk.red('\nāŒ Error running diagnosis:'), error.message);
455
+ console.error(chalk.yellow('\nšŸ’” Try: caws status for basic health check'));
456
+ process.exit(1);
457
+ }
458
+ }
459
+
460
+ module.exports = {
461
+ diagnoseCommand,
462
+ runDiagnosis,
463
+ displayResults,
464
+ applyAutoFixes,
465
+ // Export individual checks for testing
466
+ checkWorkingSpec,
467
+ checkGitSetup,
468
+ checkGitHooks,
469
+ checkTypeScriptConfig,
470
+ checkTestFiles,
471
+ checkCAWSTools,
472
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Status command handler
3
+ * @param {Object} options - Command options
4
+ */
5
+ export function statusCommand(options?: any): Promise<void>;
6
+ /**
7
+ * Load working specification
8
+ * @param {string} specPath - Path to working spec
9
+ * @returns {Promise<Object|null>} Parsed spec or null
10
+ */
11
+ export function loadWorkingSpec(specPath?: string): Promise<any | null>;
12
+ /**
13
+ * Check Git hooks status
14
+ * @returns {Promise<Object>} Hooks status
15
+ */
16
+ export function checkGitHooks(): Promise<any>;
17
+ /**
18
+ * Load provenance chain
19
+ * @returns {Promise<Object>} Provenance status
20
+ */
21
+ export function loadProvenanceChain(): Promise<any>;
22
+ /**
23
+ * Check quality gates status (simplified)
24
+ * @returns {Promise<Object>} Quality gates status
25
+ */
26
+ export function checkQualityGates(): Promise<any>;
27
+ /**
28
+ * Display project status
29
+ * @param {Object} data - Status data
30
+ */
31
+ export function displayStatus(data: any): void;
32
+ /**
33
+ * Generate actionable suggestions based on status
34
+ * @param {Object} data - Status data
35
+ * @returns {string[]} Array of suggestions
36
+ */
37
+ export function generateSuggestions(data: any): string[];
38
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.js"],"names":[],"mappings":"AAiPA;;;GAGG;AACH,4DAoBC;AA9PD;;;;GAIG;AACH,2CAHW,MAAM,GACJ,OAAO,CAAC,MAAO,IAAI,CAAC,CAahC;AAED;;;GAGG;AACH,iCAFa,OAAO,KAAQ,CAgC3B;AAED;;;GAGG;AACH,uCAFa,OAAO,KAAQ,CA+B3B;AAED;;;GAGG;AACH,qCAFa,OAAO,KAAQ,CAS3B;AAwBD;;;GAGG;AACH,+CAyEC;AAED;;;;GAIG;AACH,gDAFa,MAAM,EAAE,CAsBpB"}