@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.
Files changed (95) hide show
  1. package/README.md +295 -150
  2. package/dist/budget-derivation.d.ts +35 -0
  3. package/dist/budget-derivation.d.ts.map +1 -0
  4. package/dist/budget-derivation.js +204 -0
  5. package/dist/cicd-optimizer.d.ts +142 -0
  6. package/dist/cicd-optimizer.d.ts.map +1 -0
  7. package/dist/cicd-optimizer.js +504 -0
  8. package/dist/commands/burnup.d.ts +6 -0
  9. package/dist/commands/burnup.d.ts.map +1 -0
  10. package/dist/commands/burnup.js +90 -0
  11. package/dist/commands/init.d.ts +5 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/init.js +514 -0
  14. package/dist/commands/provenance.d.ts +22 -0
  15. package/dist/commands/provenance.d.ts.map +1 -0
  16. package/dist/commands/provenance.js +594 -0
  17. package/dist/commands/tool.d.ts +13 -0
  18. package/dist/commands/tool.d.ts.map +1 -0
  19. package/dist/commands/tool.js +138 -0
  20. package/dist/commands/validate.d.ts +7 -0
  21. package/dist/commands/validate.d.ts.map +1 -0
  22. package/dist/commands/validate.js +80 -0
  23. package/dist/config/index.d.ts +29 -0
  24. package/dist/config/index.d.ts.map +1 -0
  25. package/dist/config/index.js +132 -0
  26. package/dist/error-handler.d.ts +50 -0
  27. package/dist/error-handler.d.ts.map +1 -0
  28. package/dist/error-handler.js +253 -0
  29. package/dist/generators/working-spec.d.ts +13 -0
  30. package/dist/generators/working-spec.d.ts.map +1 -0
  31. package/dist/generators/working-spec.js +204 -0
  32. package/dist/index-new.d.ts +5 -0
  33. package/dist/index-new.d.ts.map +1 -0
  34. package/dist/index-new.js +317 -0
  35. package/dist/index.d.ts +3 -12
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +100 -1659
  38. package/dist/index.js.backup +4711 -0
  39. package/dist/scaffold/cursor-hooks.d.ts +7 -0
  40. package/dist/scaffold/cursor-hooks.d.ts.map +1 -0
  41. package/dist/scaffold/cursor-hooks.js +152 -0
  42. package/dist/scaffold/index.d.ts +20 -0
  43. package/dist/scaffold/index.d.ts.map +1 -0
  44. package/dist/scaffold/index.js +486 -0
  45. package/dist/test-analysis.d.ts +182 -0
  46. package/dist/test-analysis.d.ts.map +1 -0
  47. package/dist/test-analysis.js +580 -0
  48. package/dist/tool-interface.d.ts +236 -0
  49. package/dist/tool-interface.d.ts.map +1 -0
  50. package/dist/tool-interface.js +314 -0
  51. package/dist/tool-loader.d.ts +77 -0
  52. package/dist/tool-loader.d.ts.map +1 -0
  53. package/dist/tool-loader.js +298 -0
  54. package/dist/tool-validator.d.ts +72 -0
  55. package/dist/tool-validator.d.ts.map +1 -0
  56. package/dist/tool-validator.js +387 -0
  57. package/dist/utils/detection.d.ts +7 -0
  58. package/dist/utils/detection.d.ts.map +1 -0
  59. package/dist/utils/detection.js +174 -0
  60. package/dist/utils/finalization.d.ts +17 -0
  61. package/dist/utils/finalization.d.ts.map +1 -0
  62. package/dist/utils/finalization.js +229 -0
  63. package/dist/utils/project-analysis.d.ts +14 -0
  64. package/dist/utils/project-analysis.d.ts.map +1 -0
  65. package/dist/utils/project-analysis.js +105 -0
  66. package/dist/validation/spec-validation.d.ts +29 -0
  67. package/dist/validation/spec-validation.d.ts.map +1 -0
  68. package/dist/validation/spec-validation.js +376 -0
  69. package/dist/waivers-manager.d.ts +167 -0
  70. package/dist/waivers-manager.d.ts.map +1 -0
  71. package/dist/waivers-manager.js +549 -0
  72. package/package.json +10 -12
  73. package/templates/.cursor/README.md +311 -0
  74. package/templates/.cursor/hooks/audit.sh +55 -0
  75. package/templates/.cursor/hooks/block-dangerous.sh +77 -0
  76. package/templates/.cursor/hooks/caws-quality-check.sh +52 -0
  77. package/templates/.cursor/hooks/caws-scope-guard.sh +74 -0
  78. package/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
  79. package/templates/.cursor/hooks/format.sh +38 -0
  80. package/templates/.cursor/hooks/naming-check.sh +64 -0
  81. package/templates/.cursor/hooks/scan-secrets.sh +46 -0
  82. package/templates/.cursor/hooks/scope-guard.sh +52 -0
  83. package/templates/.cursor/hooks/validate-spec.sh +38 -0
  84. package/templates/.cursor/hooks.json +59 -0
  85. package/templates/.github/copilot/instructions.md +311 -0
  86. package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
  87. package/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
  88. package/templates/.vscode/launch.json +56 -0
  89. package/templates/.vscode/settings.json +93 -0
  90. package/templates/.windsurf/workflows/caws-guided-development.md +92 -0
  91. package/templates/apps/tools/caws/README.md +1 -1
  92. package/templates/apps/tools/caws/prompt-lint.js.backup +274 -0
  93. package/templates/apps/tools/caws/provenance.js.backup +73 -0
  94. package/templates/apps/tools/caws/schemas/working-spec.schema.json +21 -3
  95. package/templates/codemod/test.js +93 -1
@@ -0,0 +1,138 @@
1
+ /**
2
+ * @fileoverview Tool Command Handler
3
+ * Handles tool execution commands for CAWS CLI
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const path = require('path');
8
+ const chalk = require('chalk');
9
+
10
+ // Import tool system
11
+ const ToolLoader = require('../tool-loader');
12
+ const ToolValidator = require('../tool-validator');
13
+
14
+ // Tool system state
15
+ let toolLoader = null;
16
+ let toolValidator = null;
17
+
18
+ /**
19
+ * Initialize tool system
20
+ * @returns {Promise<ToolLoader|null>} Initialized tool loader or null if failed
21
+ */
22
+ async function initializeToolSystem() {
23
+ if (toolLoader) return toolLoader;
24
+
25
+ try {
26
+ toolLoader = new ToolLoader({
27
+ toolsDir: path.join(process.cwd(), 'apps/tools/caws'),
28
+ });
29
+
30
+ toolValidator = new ToolValidator();
31
+
32
+ // Set up event listeners for tool system
33
+ toolLoader.on('discovery:complete', ({ tools: _tools, count }) => {
34
+ if (count > 0) {
35
+ console.log(chalk.blue(`šŸ”§ Discovered ${count} tools`));
36
+ }
37
+ });
38
+
39
+ toolLoader.on('tool:loaded', ({ id, metadata }) => {
40
+ console.log(chalk.gray(` āœ“ Loaded tool: ${metadata.name} (${id})`));
41
+ });
42
+
43
+ toolLoader.on('tool:error', ({ id, error }) => {
44
+ console.warn(chalk.yellow(`āš ļø Failed to load tool ${id}: ${error}`));
45
+ });
46
+
47
+ // Auto-discover tools on initialization
48
+ await toolLoader.discoverTools();
49
+
50
+ return toolLoader;
51
+ } catch (error) {
52
+ console.warn(chalk.yellow('āš ļø Tool system initialization failed:'), error.message);
53
+ console.warn(chalk.blue('šŸ’” Continuing without dynamic tools'));
54
+ return null;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Execute tool command handler
60
+ * @param {string} toolId - ID of the tool to execute
61
+ * @param {Object} options - Command options
62
+ */
63
+ async function executeTool(toolId, options) {
64
+ try {
65
+ // Initialize tool system
66
+ const loader = await initializeToolSystem();
67
+
68
+ if (!loader) {
69
+ console.error(chalk.red('āŒ Tool system not available'));
70
+ process.exit(1);
71
+ }
72
+
73
+ // Load all tools first
74
+ await loader.loadAllTools();
75
+ const tool = loader.getTool(toolId);
76
+
77
+ if (!tool) {
78
+ console.error(chalk.red(`āŒ Tool '${toolId}' not found`));
79
+ console.log(chalk.blue('šŸ’” Available tools:'));
80
+ const tools = loader.getAllTools();
81
+ for (const [id, t] of tools) {
82
+ console.log(` - ${id}: ${t.metadata.name}`);
83
+ }
84
+ process.exit(1);
85
+ }
86
+
87
+ // Validate tool before execution
88
+ const validation = await toolValidator.validateTool(tool);
89
+ if (!validation.valid) {
90
+ console.error(chalk.red('āŒ Tool validation failed:'));
91
+ validation.errors.forEach((error) => {
92
+ console.error(` ${chalk.red('āœ—')} ${error}`);
93
+ });
94
+ process.exit(1);
95
+ }
96
+
97
+ // Parse parameters
98
+ let params = {};
99
+ if (options.params) {
100
+ try {
101
+ params = JSON.parse(options.params);
102
+ } catch (error) {
103
+ console.error(chalk.red('āŒ Invalid JSON parameters:'), error.message);
104
+ process.exit(1);
105
+ }
106
+ }
107
+
108
+ console.log(chalk.blue(`šŸš€ Executing tool: ${tool.metadata.name}`));
109
+
110
+ // Execute tool
111
+ const result = await tool.module.execute(params, {
112
+ workingDirectory: process.cwd(),
113
+ timeout: options.timeout,
114
+ });
115
+
116
+ // Display results
117
+ if (result.success) {
118
+ console.log(chalk.green('āœ… Tool execution successful'));
119
+ if (result.output && typeof result.output === 'object') {
120
+ console.log(chalk.gray('Output:'), JSON.stringify(result.output, null, 2));
121
+ }
122
+ } else {
123
+ console.error(chalk.red('āŒ Tool execution failed'));
124
+ result.errors.forEach((error) => {
125
+ console.error(` ${chalk.red('āœ—')} ${error}`);
126
+ });
127
+ process.exit(1);
128
+ }
129
+ } catch (error) {
130
+ console.error(chalk.red(`āŒ Error executing tool ${toolId}:`), error.message);
131
+ process.exit(1);
132
+ }
133
+ }
134
+
135
+ module.exports = {
136
+ initializeToolSystem,
137
+ executeTool,
138
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Validate command handler
3
+ * @param {string} specFile - Path to spec file
4
+ * @param {Object} options - Command options
5
+ */
6
+ export function validateCommand(specFile: string, options: any): Promise<void>;
7
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.js"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,0CAHW,MAAM,+BA2DhB"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @fileoverview Validate Command Handler
3
+ * Handles validation commands for CAWS CLI
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 validation functionality
13
+ const { validateWorkingSpecWithSuggestions } = require('../validation/spec-validation');
14
+
15
+ /**
16
+ * Validate command handler
17
+ * @param {string} specFile - Path to spec file
18
+ * @param {Object} options - Command options
19
+ */
20
+ async function validateCommand(specFile, options) {
21
+ try {
22
+ let specPath = specFile || path.join('.caws', 'working-spec.yaml');
23
+
24
+ if (!fs.existsSync(specPath)) {
25
+ console.error(chalk.red(`āŒ Spec file not found: ${specPath}`));
26
+ console.error(chalk.blue('šŸ’” Run "caws init" first to create a working spec'));
27
+ process.exit(1);
28
+ }
29
+
30
+ const specContent = fs.readFileSync(specPath, 'utf8');
31
+ const spec = yaml.load(specContent);
32
+
33
+ console.log(chalk.cyan('šŸ” Validating CAWS working spec...'));
34
+
35
+ const result = validateWorkingSpecWithSuggestions(spec, {
36
+ autoFix: options.autoFix,
37
+ suggestions: !options.quiet,
38
+ checkBudget: true,
39
+ projectRoot: path.dirname(specPath),
40
+ });
41
+
42
+ if (result.valid) {
43
+ console.log(chalk.green('āœ… Working spec validation passed'));
44
+ if (!options.quiet) {
45
+ console.log(chalk.gray(` Risk tier: ${spec.risk_tier}`));
46
+ console.log(chalk.gray(` Mode: ${spec.mode}`));
47
+ if (spec.title) {
48
+ console.log(chalk.gray(` Title: ${spec.title}`));
49
+ }
50
+ }
51
+ } else {
52
+ console.log(chalk.red('āŒ Working spec validation failed'));
53
+
54
+ // Show errors
55
+ result.errors.forEach((error, index) => {
56
+ console.log(` ${index + 1}. ${chalk.red(error.message)}`);
57
+ if (error.suggestion) {
58
+ console.log(` ${chalk.blue('šŸ’” ' + error.suggestion)}`);
59
+ }
60
+ });
61
+
62
+ // Show warnings
63
+ if (result.warnings && result.warnings.length > 0) {
64
+ console.log(chalk.yellow('\nāš ļø Warnings:'));
65
+ result.warnings.forEach((warning, index) => {
66
+ console.log(` ${index + 1}. ${chalk.yellow(warning.message)}`);
67
+ });
68
+ }
69
+
70
+ process.exit(1);
71
+ }
72
+ } catch (error) {
73
+ console.error(chalk.red('āŒ Error during validation:'), error.message);
74
+ process.exit(1);
75
+ }
76
+ }
77
+
78
+ module.exports = {
79
+ validateCommand,
80
+ };
@@ -0,0 +1,29 @@
1
+ import CLI_VERSION_1 = require("../../package.json");
2
+ import CLI_VERSION = CLI_VERSION_1.version;
3
+ /**
4
+ * Initialize global setup detection
5
+ * @returns {Object} Setup configuration
6
+ */
7
+ export function initializeGlobalSetup(): any;
8
+ /**
9
+ * Load provenance tools dynamically
10
+ * @returns {Object|null} Provenance tools or null if not available
11
+ */
12
+ export function loadProvenanceTools(): any | null;
13
+ /**
14
+ * Initialize language support tools
15
+ * @returns {Object|null} Language support tools or null if not available
16
+ */
17
+ export function initializeLanguageSupport(): any | null;
18
+ /**
19
+ * Get global CAWS setup
20
+ * @returns {Object} CAWS setup configuration
21
+ */
22
+ export function getGlobalCAWSSetup(): any;
23
+ /**
24
+ * Set global CAWS setup (for testing or override)
25
+ * @param {Object} setup - Setup configuration
26
+ */
27
+ export function setGlobalCAWSSetup(setup: any): void;
28
+ export { CLI_VERSION };
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.js"],"names":[],"mappings":";mCAakD,OAAO;AAOzD;;;GAGG;AACH,6CAkBC;AAED;;;GAGG;AACH,uCAFa,MAAO,IAAI,CAqBvB;AAED;;;GAGG;AACH,6CAFa,MAAO,IAAI,CAmCvB;AAED;;;GAGG;AACH,0CAEC;AAED;;;GAGG;AACH,qDAEC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @fileoverview CAWS Configuration Module
3
+ * Global configuration and provenance tools management
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const path = require('path');
8
+ const chalk = require('chalk');
9
+
10
+ // Import detection utilities
11
+ const { detectCAWSSetup } = require('../utils/detection');
12
+
13
+ // CLI version from package.json
14
+ const CLI_VERSION = require('../../package.json').version;
15
+
16
+ // Global state
17
+ let provenanceTools = null;
18
+ let cawsSetup = null;
19
+ let languageSupport = null;
20
+
21
+ /**
22
+ * Initialize global setup detection
23
+ * @returns {Object} Setup configuration
24
+ */
25
+ function initializeGlobalSetup() {
26
+ if (cawsSetup) return cawsSetup;
27
+
28
+ try {
29
+ cawsSetup = detectCAWSSetup();
30
+ } catch (error) {
31
+ console.warn(chalk.yellow('āš ļø Failed to detect CAWS setup:'), error.message);
32
+ cawsSetup = {
33
+ type: 'unknown',
34
+ hasCAWSDir: false,
35
+ cawsDir: null,
36
+ capabilities: [],
37
+ hasTemplateDir: false,
38
+ templateDir: null,
39
+ };
40
+ }
41
+
42
+ return cawsSetup;
43
+ }
44
+
45
+ /**
46
+ * Load provenance tools dynamically
47
+ * @returns {Object|null} Provenance tools or null if not available
48
+ */
49
+ function loadProvenanceTools() {
50
+ if (provenanceTools) return provenanceTools; // Already loaded
51
+
52
+ try {
53
+ const setup = cawsSetup || initializeGlobalSetup();
54
+ if (setup?.hasTemplateDir && setup?.templateDir) {
55
+ const { generateProvenance, saveProvenance } = require(
56
+ path.join(setup.templateDir, 'apps/tools/caws/provenance.js')
57
+ );
58
+ provenanceTools = { generateProvenance, saveProvenance };
59
+ console.log('āœ… Loaded provenance tools from:', setup.templateDir);
60
+ }
61
+ } catch (error) {
62
+ // Fallback for environments without template
63
+ provenanceTools = null;
64
+ console.warn('āš ļø Provenance tools not available:', error.message);
65
+ }
66
+
67
+ return provenanceTools;
68
+ }
69
+
70
+ /**
71
+ * Initialize language support tools
72
+ * @returns {Object|null} Language support tools or null if not available
73
+ */
74
+ function initializeLanguageSupport() {
75
+ if (languageSupport) return languageSupport;
76
+
77
+ try {
78
+ // Try multiple possible locations for language support
79
+ const possiblePaths = [
80
+ path.join(__dirname, '../../../caws-template/apps/tools/caws/language-support.js'),
81
+ path.join(__dirname, '../../../../caws-template/apps/tools/caws/language-support.js'),
82
+ path.join(process.cwd(), 'packages/caws-template/apps/tools/caws/language-support.js'),
83
+ path.join(process.cwd(), 'caws-template/apps/tools/caws/language-support.js'),
84
+ ];
85
+
86
+ for (const testPath of possiblePaths) {
87
+ try {
88
+ languageSupport = require(testPath);
89
+ // Only log if not running version command
90
+ if (!process.argv.includes('--version') && !process.argv.includes('-V')) {
91
+ console.log(`āœ… Loaded language support from: ${testPath}`);
92
+ }
93
+ break;
94
+ } catch (pathError) {
95
+ // Continue to next path
96
+ }
97
+ }
98
+ } catch (error) {
99
+ console.warn(chalk.yellow('āš ļø Language support tools not available'));
100
+ console.warn(chalk.blue('šŸ’” This may limit language-specific configuration features'));
101
+ console.warn(
102
+ chalk.blue('šŸ’” For full functionality, ensure caws-template package is available')
103
+ );
104
+ }
105
+
106
+ return languageSupport;
107
+ }
108
+
109
+ /**
110
+ * Get global CAWS setup
111
+ * @returns {Object} CAWS setup configuration
112
+ */
113
+ function getGlobalCAWSSetup() {
114
+ return cawsSetup || initializeGlobalSetup();
115
+ }
116
+
117
+ /**
118
+ * Set global CAWS setup (for testing or override)
119
+ * @param {Object} setup - Setup configuration
120
+ */
121
+ function setGlobalCAWSSetup(setup) {
122
+ cawsSetup = setup;
123
+ }
124
+
125
+ module.exports = {
126
+ CLI_VERSION,
127
+ initializeGlobalSetup,
128
+ loadProvenanceTools,
129
+ initializeLanguageSupport,
130
+ getGlobalCAWSSetup,
131
+ setGlobalCAWSSetup,
132
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Enhanced error class with category and recovery suggestions
3
+ */
4
+ export class CAWSError extends Error {
5
+ constructor(message: any, category?: any, suggestions?: any[]);
6
+ category: any;
7
+ suggestions: any[];
8
+ }
9
+ export namespace ERROR_CATEGORIES {
10
+ let VALIDATION: string;
11
+ let PERMISSION: string;
12
+ let FILESYSTEM: string;
13
+ let NETWORK: string;
14
+ let CONFIGURATION: string;
15
+ let USER_INPUT: string;
16
+ let DEPENDENCY: string;
17
+ let UNKNOWN: string;
18
+ }
19
+ /**
20
+ * Get error category from error object or message
21
+ * @param {Error|string} error - Error object or message
22
+ * @returns {string} Error category
23
+ */
24
+ export function getErrorCategory(error: Error | string): string;
25
+ /**
26
+ * Wrap async operations with consistent error handling
27
+ * @param {Function} operation - Async operation to wrap
28
+ * @param {string} context - Context for error messages
29
+ * @returns {Promise<any>} Operation result or throws handled error
30
+ */
31
+ export function safeAsync(operation: Function, context?: string): Promise<any>;
32
+ /**
33
+ * Handle CLI errors with consistent formatting and user guidance
34
+ * @param {Error} error - Error to handle
35
+ * @param {boolean} exit - Whether to exit the process (default: true)
36
+ */
37
+ export function handleCliError(error: Error, exit?: boolean): void;
38
+ /**
39
+ * Validate required environment and dependencies
40
+ * @returns {Object} Validation result with any errors
41
+ */
42
+ export function validateEnvironment(): any;
43
+ /**
44
+ * Get recovery suggestions based on error category
45
+ * @param {Error} error - Original error
46
+ * @param {string} category - Error category
47
+ * @returns {string[]} Array of recovery suggestions
48
+ */
49
+ export function getRecoverySuggestions(error: Error, category: string): string[];
50
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.js"],"names":[],"mappings":"AA0GA;;GAEG;AACH;IACE,+DAKC;IAFC,cAAqD;IACrD,mBAA2F;CAE9F;;;;;;;;;;;AA9ED;;;;GAIG;AACH,wCAHW,KAAK,GAAC,MAAM,GACV,MAAM,CA+DlB;AAcD;;;;;GAKG;AACH,yDAHW,MAAM,GACJ,OAAO,CAAC,GAAG,CAAC,CAexB;AAkDD;;;;GAIG;AACH,sCAHW,KAAK,SACL,OAAO,QAyBjB;AAED;;;GAGG;AACH,2CAqBC;AAvGD;;;;;GAKG;AACH,8CAJW,KAAK,YACL,MAAM,GACJ,MAAM,EAAE,CA0CpB"}
@@ -0,0 +1,253 @@
1
+ /**
2
+ * @fileoverview CAWS CLI Error Handler - Centralized error handling utilities
3
+ * Provides consistent error categorization, formatting, and recovery suggestions
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+
9
+ /**
10
+ * Error categories for better user experience
11
+ */
12
+ const ERROR_CATEGORIES = {
13
+ VALIDATION: 'validation',
14
+ PERMISSION: 'permission',
15
+ FILESYSTEM: 'filesystem',
16
+ NETWORK: 'network',
17
+ CONFIGURATION: 'configuration',
18
+ USER_INPUT: 'user_input',
19
+ DEPENDENCY: 'dependency',
20
+ UNKNOWN: 'unknown',
21
+ };
22
+
23
+ /**
24
+ * Error code mappings for common system errors
25
+ */
26
+ const ERROR_CODES = {
27
+ EACCES: ERROR_CATEGORIES.PERMISSION,
28
+ EPERM: ERROR_CATEGORIES.PERMISSION,
29
+ ENOENT: ERROR_CATEGORIES.FILESYSTEM,
30
+ ENOTFOUND: ERROR_CATEGORIES.NETWORK,
31
+ ECONNREFUSED: ERROR_CATEGORIES.NETWORK,
32
+ ETIMEDOUT: ERROR_CATEGORIES.NETWORK,
33
+ ENOSPC: ERROR_CATEGORIES.FILESYSTEM,
34
+ EEXIST: ERROR_CATEGORIES.FILESYSTEM,
35
+ EISDIR: ERROR_CATEGORIES.FILESYSTEM,
36
+ ENOTDIR: ERROR_CATEGORIES.FILESYSTEM,
37
+ };
38
+
39
+ /**
40
+ * Get error category from error object or message
41
+ * @param {Error|string} error - Error object or message
42
+ * @returns {string} Error category
43
+ */
44
+ function getErrorCategory(error) {
45
+ const errorMessage = typeof error === 'string' ? error : error.message;
46
+ const errorCode = typeof error === 'object' && error.code ? error.code : null;
47
+
48
+ // Check error codes first
49
+ if (errorCode && ERROR_CODES[errorCode]) {
50
+ return ERROR_CODES[errorCode];
51
+ }
52
+
53
+ // Check message patterns
54
+ const lowerMessage = errorMessage.toLowerCase();
55
+
56
+ if (
57
+ lowerMessage.includes('validation') ||
58
+ lowerMessage.includes('invalid') ||
59
+ lowerMessage.includes('required')
60
+ ) {
61
+ return ERROR_CATEGORIES.VALIDATION;
62
+ }
63
+
64
+ if (
65
+ lowerMessage.includes('permission') ||
66
+ lowerMessage.includes('access') ||
67
+ lowerMessage.includes('denied')
68
+ ) {
69
+ return ERROR_CATEGORIES.PERMISSION;
70
+ }
71
+
72
+ if (
73
+ lowerMessage.includes('file') ||
74
+ lowerMessage.includes('directory') ||
75
+ lowerMessage.includes('path')
76
+ ) {
77
+ return ERROR_CATEGORIES.FILESYSTEM;
78
+ }
79
+
80
+ if (
81
+ lowerMessage.includes('network') ||
82
+ lowerMessage.includes('connection') ||
83
+ lowerMessage.includes('timeout')
84
+ ) {
85
+ return ERROR_CATEGORIES.NETWORK;
86
+ }
87
+
88
+ if (
89
+ lowerMessage.includes('config') ||
90
+ lowerMessage.includes('setting') ||
91
+ lowerMessage.includes('option')
92
+ ) {
93
+ return ERROR_CATEGORIES.CONFIGURATION;
94
+ }
95
+
96
+ if (
97
+ lowerMessage.includes('input') ||
98
+ lowerMessage.includes('prompt') ||
99
+ lowerMessage.includes('answer')
100
+ ) {
101
+ return ERROR_CATEGORIES.USER_INPUT;
102
+ }
103
+
104
+ return ERROR_CATEGORIES.UNKNOWN;
105
+ }
106
+
107
+ /**
108
+ * Enhanced error class with category and recovery suggestions
109
+ */
110
+ class CAWSError extends Error {
111
+ constructor(message, category = null, suggestions = []) {
112
+ super(message);
113
+ this.name = 'CAWSError';
114
+ this.category = category || getErrorCategory(message);
115
+ this.suggestions = Array.isArray(suggestions) ? suggestions : [suggestions].filter(Boolean);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Wrap async operations with consistent error handling
121
+ * @param {Function} operation - Async operation to wrap
122
+ * @param {string} context - Context for error messages
123
+ * @returns {Promise<any>} Operation result or throws handled error
124
+ */
125
+ async function safeAsync(operation, context = '') {
126
+ try {
127
+ return await operation();
128
+ } catch (error) {
129
+ const category = getErrorCategory(error);
130
+ const enhancedError = new CAWSError(
131
+ `${context}: ${error.message}`,
132
+ category,
133
+ getRecoverySuggestions(error, category)
134
+ );
135
+ enhancedError.originalError = error;
136
+ throw enhancedError;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Get recovery suggestions based on error category
142
+ * @param {Error} error - Original error
143
+ * @param {string} category - Error category
144
+ * @returns {string[]} Array of recovery suggestions
145
+ */
146
+ function getRecoverySuggestions(error, category) {
147
+ const suggestions = [];
148
+
149
+ switch (category) {
150
+ case ERROR_CATEGORIES.PERMISSION:
151
+ suggestions.push('Try running the command with elevated privileges (sudo)');
152
+ suggestions.push('Check file/directory permissions with `ls -la`');
153
+ break;
154
+
155
+ case ERROR_CATEGORIES.FILESYSTEM:
156
+ if (error.code === 'ENOENT') {
157
+ suggestions.push('Verify the file/directory path exists');
158
+ suggestions.push('Check for typos in file names');
159
+ } else if (error.code === 'EEXIST') {
160
+ suggestions.push('The file/directory already exists');
161
+ suggestions.push('Use a different name or remove the existing item');
162
+ }
163
+ break;
164
+
165
+ case ERROR_CATEGORIES.VALIDATION:
166
+ suggestions.push('Run `caws validate --suggestions` for detailed validation help');
167
+ suggestions.push('Check your working spec format against the documentation');
168
+ break;
169
+
170
+ case ERROR_CATEGORIES.CONFIGURATION:
171
+ suggestions.push('Run `caws init --interactive` to reconfigure your project');
172
+ suggestions.push('Check your .caws directory and configuration files');
173
+ break;
174
+
175
+ case ERROR_CATEGORIES.NETWORK:
176
+ suggestions.push('Check your internet connection');
177
+ suggestions.push('Verify the URL/service is accessible');
178
+ break;
179
+
180
+ default:
181
+ suggestions.push('Run the command with --help for usage information');
182
+ suggestions.push('Check the CAWS documentation at docs/README.md');
183
+ }
184
+
185
+ return suggestions;
186
+ }
187
+
188
+ /**
189
+ * Handle CLI errors with consistent formatting and user guidance
190
+ * @param {Error} error - Error to handle
191
+ * @param {boolean} exit - Whether to exit the process (default: true)
192
+ */
193
+ function handleCliError(error, exit = true) {
194
+ const category = error.category || getErrorCategory(error);
195
+ const suggestions = error.suggestions || getRecoverySuggestions(error, category);
196
+
197
+ // Format error output
198
+ console.error(chalk.red(`\nāŒ Error (${category}): ${error.message}`));
199
+
200
+ if (suggestions && suggestions.length > 0) {
201
+ console.error(chalk.yellow('\nšŸ’” Suggestions:'));
202
+ suggestions.forEach((suggestion) => {
203
+ console.error(chalk.yellow(` • ${suggestion}`));
204
+ });
205
+ }
206
+
207
+ console.error(
208
+ chalk.gray(
209
+ '\nšŸ“– For more help, visit: https://github.com/Paths-Design/coding-agent-working-standard'
210
+ )
211
+ );
212
+
213
+ if (exit) {
214
+ process.exit(1);
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Validate required environment and dependencies
220
+ * @returns {Object} Validation result with any errors
221
+ */
222
+ function validateEnvironment() {
223
+ const errors = [];
224
+ const warnings = [];
225
+
226
+ // Check Node.js version
227
+ const nodeVersion = process.versions.node;
228
+ const majorVersion = parseInt(nodeVersion.split('.')[0], 10);
229
+ if (majorVersion < 18) {
230
+ errors.push(`Node.js version ${nodeVersion} is not supported. Minimum required: 18.0.0`);
231
+ }
232
+
233
+ // Check if running in supported environment
234
+ if (!process.cwd()) {
235
+ errors.push('Unable to determine current working directory');
236
+ }
237
+
238
+ return {
239
+ valid: errors.length === 0,
240
+ errors,
241
+ warnings,
242
+ };
243
+ }
244
+
245
+ module.exports = {
246
+ CAWSError,
247
+ ERROR_CATEGORIES,
248
+ getErrorCategory,
249
+ safeAsync,
250
+ handleCliError,
251
+ validateEnvironment,
252
+ getRecoverySuggestions,
253
+ };