@paths.design/caws-cli 8.0.1 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +5 -6
  2. package/dist/commands/archive.d.ts +1 -0
  3. package/dist/commands/archive.d.ts.map +1 -1
  4. package/dist/commands/archive.js +114 -6
  5. package/dist/commands/burnup.d.ts.map +1 -1
  6. package/dist/commands/burnup.js +109 -10
  7. package/dist/commands/diagnose.js +1 -1
  8. package/dist/commands/init.d.ts.map +1 -1
  9. package/dist/commands/init.js +185 -39
  10. package/dist/commands/mode.d.ts +2 -1
  11. package/dist/commands/mode.d.ts.map +1 -1
  12. package/dist/commands/mode.js +24 -14
  13. package/dist/commands/provenance.d.ts.map +1 -1
  14. package/dist/commands/provenance.js +216 -93
  15. package/dist/commands/quality-gates.d.ts.map +1 -1
  16. package/dist/commands/quality-gates.js +3 -1
  17. package/dist/commands/specs.d.ts.map +1 -1
  18. package/dist/commands/specs.js +184 -6
  19. package/dist/commands/status.d.ts.map +1 -1
  20. package/dist/commands/status.js +134 -10
  21. package/dist/commands/templates.js +2 -2
  22. package/dist/commands/worktree.d.ts +7 -0
  23. package/dist/commands/worktree.d.ts.map +1 -0
  24. package/dist/commands/worktree.js +136 -0
  25. package/dist/config/lite-scope.d.ts +33 -0
  26. package/dist/config/lite-scope.d.ts.map +1 -0
  27. package/dist/config/lite-scope.js +158 -0
  28. package/dist/config/modes.d.ts +90 -51
  29. package/dist/config/modes.d.ts.map +1 -1
  30. package/dist/config/modes.js +26 -0
  31. package/dist/error-handler.d.ts +3 -16
  32. package/dist/error-handler.d.ts.map +1 -1
  33. package/dist/error-handler.js +6 -98
  34. package/dist/generators/jest-config-generator.d.ts +32 -0
  35. package/dist/generators/jest-config-generator.d.ts.map +1 -0
  36. package/dist/generators/jest-config-generator.js +242 -0
  37. package/dist/index.js +40 -7
  38. package/dist/minimal-cli.js +3 -1
  39. package/dist/scaffold/claude-hooks.d.ts +28 -0
  40. package/dist/scaffold/claude-hooks.d.ts.map +1 -0
  41. package/dist/scaffold/claude-hooks.js +344 -0
  42. package/dist/scaffold/index.d.ts +2 -0
  43. package/dist/scaffold/index.d.ts.map +1 -1
  44. package/dist/scaffold/index.js +96 -76
  45. package/dist/templates/.caws/schemas/scope.schema.json +52 -0
  46. package/dist/templates/.caws/schemas/working-spec.schema.json +1 -1
  47. package/dist/templates/.caws/schemas/worktrees.schema.json +36 -0
  48. package/dist/templates/.claude/README.md +190 -0
  49. package/dist/templates/.claude/hooks/audit.sh +96 -0
  50. package/dist/templates/.claude/hooks/block-dangerous.sh +123 -0
  51. package/dist/templates/.claude/hooks/lite-sprawl-check.sh +117 -0
  52. package/dist/templates/.claude/hooks/naming-check.sh +97 -0
  53. package/dist/templates/.claude/hooks/quality-check.sh +68 -0
  54. package/dist/templates/.claude/hooks/scan-secrets.sh +85 -0
  55. package/dist/templates/.claude/hooks/scope-guard.sh +192 -0
  56. package/dist/templates/.claude/hooks/simplification-guard.sh +92 -0
  57. package/dist/templates/.claude/hooks/validate-spec.sh +76 -0
  58. package/dist/templates/.claude/settings.json +95 -0
  59. package/dist/templates/.cursor/README.md +0 -3
  60. package/dist/templates/.github/copilot-instructions.md +82 -0
  61. package/dist/templates/.junie/guidelines.md +73 -0
  62. package/dist/templates/.vscode/launch.json +0 -27
  63. package/dist/templates/.windsurf/rules/caws-quality-standards.md +54 -0
  64. package/dist/templates/CLAUDE.md +101 -0
  65. package/dist/templates/agents.md +73 -1016
  66. package/dist/templates/docs/README.md +5 -5
  67. package/dist/test-analysis.d.ts +50 -1
  68. package/dist/test-analysis.d.ts.map +1 -1
  69. package/dist/test-analysis.js +203 -10
  70. package/dist/utils/error-categories.d.ts +52 -0
  71. package/dist/utils/error-categories.d.ts.map +1 -0
  72. package/dist/utils/error-categories.js +210 -0
  73. package/dist/utils/gitignore-updater.d.ts +1 -1
  74. package/dist/utils/gitignore-updater.d.ts.map +1 -1
  75. package/dist/utils/gitignore-updater.js +4 -0
  76. package/dist/utils/ide-detection.js +133 -0
  77. package/dist/utils/quality-gates-utils.d.ts +49 -0
  78. package/dist/utils/quality-gates-utils.d.ts.map +1 -0
  79. package/dist/utils/quality-gates-utils.js +402 -0
  80. package/dist/utils/typescript-detector.d.ts +8 -5
  81. package/dist/utils/typescript-detector.d.ts.map +1 -1
  82. package/dist/utils/typescript-detector.js +36 -90
  83. package/dist/validation/spec-validation.d.ts.map +1 -1
  84. package/dist/validation/spec-validation.js +59 -6
  85. package/dist/worktree/worktree-manager.d.ts +54 -0
  86. package/dist/worktree/worktree-manager.d.ts.map +1 -0
  87. package/dist/worktree/worktree-manager.js +378 -0
  88. package/package.json +9 -3
  89. package/templates/.caws/schemas/scope.schema.json +52 -0
  90. package/templates/.caws/schemas/working-spec.schema.json +1 -1
  91. package/templates/.caws/schemas/worktrees.schema.json +36 -0
  92. package/templates/.claude/README.md +190 -0
  93. package/templates/.claude/hooks/audit.sh +96 -0
  94. package/templates/.claude/hooks/block-dangerous.sh +123 -0
  95. package/templates/.claude/hooks/lite-sprawl-check.sh +117 -0
  96. package/templates/.claude/hooks/naming-check.sh +97 -0
  97. package/templates/.claude/hooks/quality-check.sh +68 -0
  98. package/templates/.claude/hooks/scan-secrets.sh +85 -0
  99. package/templates/.claude/hooks/scope-guard.sh +192 -0
  100. package/templates/.claude/hooks/simplification-guard.sh +92 -0
  101. package/templates/.claude/hooks/validate-spec.sh +76 -0
  102. package/templates/.claude/settings.json +95 -0
  103. package/templates/.cursor/README.md +0 -3
  104. package/templates/.github/copilot-instructions.md +82 -0
  105. package/templates/.junie/guidelines.md +73 -0
  106. package/templates/.vscode/launch.json +0 -27
  107. package/templates/.windsurf/rules/caws-quality-standards.md +54 -0
  108. package/templates/AGENTS.md +104 -0
  109. package/templates/CLAUDE.md +101 -0
  110. package/templates/docs/README.md +5 -5
  111. package/templates/.github/copilot/instructions.md +0 -311
  112. package/templates/agents.md +0 -1047
@@ -4,11 +4,11 @@
4
4
  This project is built with the **Coding Agent Workflow System (CAWS)** - an engineering-grade framework that ensures quality, reliability, and maintainability in AI-assisted development.
5
5
 
6
6
  ## Key Features
7
- - 🔒 **Quality Gates**: Automated validation of scope, budget, and standards
8
- - 🧪 **Comprehensive Testing**: Unit, contract, integration, and mutation testing
9
- - 📊 **Observability**: Structured logging, metrics, and tracing
10
- - 🔄 **Rollback Ready**: Feature flags and migration support
11
- - 📦 **Provenance Tracking**: SBOM and SLSA attestation generation
7
+ - **Quality Gates**: Automated validation of scope, budget, and standards
8
+ - **Comprehensive Testing**: Unit, contract, integration, and mutation testing
9
+ - **Observability**: Structured logging, metrics, and tracing
10
+ - **Rollback Ready**: Feature flags and migration support
11
+ - **Provenance Tracking**: SBOM and SLSA attestation generation
12
12
 
13
13
  ## Getting Started
14
14
 
@@ -55,7 +55,8 @@ export class WaiverPatternLearner {
55
55
  */
56
56
  loadWaivers(): any[];
57
57
  /**
58
- * Load historical working specs (mock implementation)
58
+ * Load historical working specs from git history
59
+ * Retrieves past versions of spec files to analyze patterns
59
60
  */
60
61
  loadHistoricalSpecs(): any[];
61
62
  /**
@@ -101,10 +102,36 @@ export class WaiverPatternLearner {
101
102
  export class ProjectSimilarityMatcher {
102
103
  constructor(projectRoot?: string);
103
104
  projectRoot: string;
105
+ patternLearner: WaiverPatternLearner;
104
106
  /**
105
107
  * Find projects similar to the current spec
108
+ * Uses real historical specs from git history when available
106
109
  */
107
110
  findSimilarProjects(currentSpec: any): {
111
+ project: any;
112
+ similarity_score: number;
113
+ budget_accuracy: number;
114
+ waiver_count: any;
115
+ details: {
116
+ id: any;
117
+ title: any;
118
+ risk_tier: any;
119
+ mode: any;
120
+ tech_stack: any;
121
+ feature_type: any;
122
+ actual_budget: {
123
+ files: any;
124
+ loc: any;
125
+ };
126
+ allocated_budget: {
127
+ files: any;
128
+ loc: any;
129
+ };
130
+ waivers: any;
131
+ _source: any;
132
+ _date: any;
133
+ };
134
+ }[] | {
108
135
  project: string;
109
136
  similarity_score: number;
110
137
  budget_accuracy: number;
@@ -127,6 +154,28 @@ export class ProjectSimilarityMatcher {
127
154
  waivers: string[];
128
155
  };
129
156
  }[];
157
+ /**
158
+ * Convert a spec object to project format for similarity comparison
159
+ */
160
+ specToProject(spec: any): {
161
+ id: any;
162
+ title: any;
163
+ risk_tier: any;
164
+ mode: any;
165
+ tech_stack: any;
166
+ feature_type: any;
167
+ actual_budget: {
168
+ files: any;
169
+ loc: any;
170
+ };
171
+ allocated_budget: {
172
+ files: any;
173
+ loc: any;
174
+ };
175
+ waivers: any;
176
+ _source: any;
177
+ _date: any;
178
+ };
130
179
  /**
131
180
  * Calculate similarity score between two specs/projects
132
181
  */
@@ -1 +1 @@
1
- {"version":3,"file":"test-analysis.d.ts","sourceRoot":"","sources":["../src/test-analysis.js"],"names":[],"mappings":"AAiZA;;GAEG;AACH,qFAsBC;AAhaD;;;GAGG;AACH;IACE,kCAEC;IADC,oBAA8B;IAGhC;;OAEG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAgCC;IAED;;OAEG;IACH,qBAsBC;IAED;;OAEG;IACH,6BAIC;IAED;;OAEG;IACH;;;;;;;;;;;;;;;MA6CC;IAED;;OAEG;IACH;;;;QAaC;IAED;;OAEG;IACH;;;;QAeC;CACF;AAED;;;GAGG;AACH;IACE,kCAEC;IADC,oBAA8B;IAGhC;;OAEG;IACH;;;;;;;;;;;;;;;;;;;;;;QAkEC;IAED;;OAEG;IACH,oDA6BC;CACF;AAED;;GAEG;AACH;IACE,kCAIC;IAHC,oBAA8B;IAC9B,qCAA2D;IAC3D,4CAAkE;IAGpE;;OAEG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA8DC;IAED;;OAEG;IACH,4EAsBC;CACF"}
1
+ {"version":3,"file":"test-analysis.d.ts","sourceRoot":"","sources":["../src/test-analysis.js"],"names":[],"mappings":"AAklBA;;GAEG;AACH,qFAsBC;AAjmBD;;;GAGG;AACH;IACE,kCAEC;IADC,oBAA8B;IAGhC;;OAEG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAgCC;IAED;;OAEG;IACH,qBAsBC;IAED;;;OAGG;IACH,6BA4GC;IAED;;OAEG;IACH;;;;;;;;;;;;;;;MA6CC;IAED;;OAEG;IACH;;;;QAaC;IAED;;OAEG;IACH;;;;QAeC;CACF;AAED;;;GAGG;AACH;IACE,kCAGC;IAFC,oBAA8B;IAC9B,qCAA2D;IAG7D;;;OAGG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyFC;IAED;;OAEG;IACH;;;;;;;;;;;;;;;;;;MA0DC;IAED;;OAEG;IACH,oDA6BC;CACF;AAED;;GAEG;AACH;IACE,kCAIC;IAHC,oBAA8B;IAC9B,qCAA2D;IAC3D,4CAAkE;IAGpE;;OAEG;IACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA8DC;IAED;;OAEG;IACH,4EAsBC;CACF"}
@@ -82,12 +82,117 @@ class WaiverPatternLearner {
82
82
  }
83
83
 
84
84
  /**
85
- * Load historical working specs (mock implementation)
85
+ * Load historical working specs from git history
86
+ * Retrieves past versions of spec files to analyze patterns
86
87
  */
87
88
  loadHistoricalSpecs() {
88
- // In a real implementation, this would load from git history or a local cache
89
- // For v0.1, we'll use mock data based on waivers
90
- return [];
89
+ const { execSync } = require('child_process');
90
+ const specs = [];
91
+
92
+ try {
93
+ // Get list of commits that modified spec files
94
+ const specPaths = [
95
+ '.caws/working-spec.yaml',
96
+ '.caws/specs/*.yaml',
97
+ ];
98
+
99
+ for (const specPattern of specPaths) {
100
+ try {
101
+ // Get commits that touched spec files
102
+ const logOutput = execSync(
103
+ `git log --pretty=format:"%H" --follow -- "${specPattern}" 2>/dev/null | head -20`,
104
+ { cwd: this.projectRoot, encoding: 'utf8' }
105
+ ).trim();
106
+
107
+ if (!logOutput) continue;
108
+
109
+ const commits = logOutput.split('\n').filter(Boolean);
110
+
111
+ for (const commitHash of commits) {
112
+ try {
113
+ // Get the list of files matching the pattern at that commit
114
+ const filesOutput = execSync(
115
+ `git ls-tree -r --name-only ${commitHash} -- "${specPattern}" 2>/dev/null`,
116
+ { cwd: this.projectRoot, encoding: 'utf8' }
117
+ ).trim();
118
+
119
+ if (!filesOutput) continue;
120
+
121
+ const files = filesOutput.split('\n').filter(Boolean);
122
+
123
+ for (const filePath of files) {
124
+ try {
125
+ // Get the spec content at that commit
126
+ const specContent = execSync(
127
+ `git show ${commitHash}:"${filePath}" 2>/dev/null`,
128
+ { cwd: this.projectRoot, encoding: 'utf8' }
129
+ );
130
+
131
+ const spec = yaml.load(specContent);
132
+ if (spec && spec.id) {
133
+ // Get commit date for context
134
+ const commitDate = execSync(
135
+ `git show -s --format=%ci ${commitHash}`,
136
+ { cwd: this.projectRoot, encoding: 'utf8' }
137
+ ).trim();
138
+
139
+ specs.push({
140
+ ...spec,
141
+ _commit: commitHash.substring(0, 7),
142
+ _date: commitDate,
143
+ _file: filePath,
144
+ });
145
+ }
146
+ } catch {
147
+ // Skip files that can't be loaded
148
+ }
149
+ }
150
+ } catch {
151
+ // Skip commits with issues
152
+ }
153
+ }
154
+ } catch {
155
+ // Pattern didn't match any files
156
+ }
157
+ }
158
+
159
+ // Also check archived specs in .caws/archive/
160
+ const archiveDir = path.join(this.projectRoot, '.caws', 'archive');
161
+ if (fs.existsSync(archiveDir)) {
162
+ const archiveFiles = fs.readdirSync(archiveDir)
163
+ .filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
164
+
165
+ for (const file of archiveFiles) {
166
+ try {
167
+ const archivePath = path.join(archiveDir, file);
168
+ const spec = yaml.load(fs.readFileSync(archivePath, 'utf8'));
169
+ if (spec && spec.id) {
170
+ specs.push({
171
+ ...spec,
172
+ _source: 'archive',
173
+ _file: file,
174
+ });
175
+ }
176
+ } catch {
177
+ // Skip invalid archive files
178
+ }
179
+ }
180
+ }
181
+
182
+ // Deduplicate by spec ID, keeping the most recent version
183
+ const uniqueSpecs = new Map();
184
+ for (const spec of specs) {
185
+ const existing = uniqueSpecs.get(spec.id);
186
+ if (!existing || (spec._date && (!existing._date || spec._date > existing._date))) {
187
+ uniqueSpecs.set(spec.id, spec);
188
+ }
189
+ }
190
+
191
+ return Array.from(uniqueSpecs.values());
192
+ } catch (error) {
193
+ console.warn(`Failed to load historical specs: ${error.message}`);
194
+ return [];
195
+ }
91
196
  }
92
197
 
93
198
  /**
@@ -186,16 +291,41 @@ class WaiverPatternLearner {
186
291
  class ProjectSimilarityMatcher {
187
292
  constructor(projectRoot = process.cwd()) {
188
293
  this.projectRoot = projectRoot;
294
+ this.patternLearner = new WaiverPatternLearner(projectRoot);
189
295
  }
190
296
 
191
297
  /**
192
298
  * Find projects similar to the current spec
299
+ * Uses real historical specs from git history when available
193
300
  */
194
301
  findSimilarProjects(currentSpec) {
195
- // For v0.1, we'll use mock historical data based on waiver patterns
196
- // In a real implementation, this would load from git history or local cache
302
+ // Load real historical specs first
303
+ const historicalSpecs = this.patternLearner.loadHistoricalSpecs();
304
+
305
+ // Convert historical specs to project format with budget data
306
+ const historicalProjects = historicalSpecs
307
+ .filter(spec => spec.id !== currentSpec.id) // Exclude current spec
308
+ .map(spec => this.specToProject(spec));
309
+
310
+ // If we have real historical data, use it
311
+ if (historicalProjects.length > 0) {
312
+ return historicalProjects
313
+ .map((project) => ({
314
+ project: project.id,
315
+ similarity_score: this.calculateSimilarity(currentSpec, project),
316
+ budget_accuracy: project.allocated_budget.files > 0
317
+ ? project.actual_budget.files / project.allocated_budget.files
318
+ : 1.0,
319
+ waiver_count: project.waivers?.length || 0,
320
+ details: project,
321
+ }))
322
+ .filter((p) => p.similarity_score > 0.3)
323
+ .sort((a, b) => b.similarity_score - a.similarity_score)
324
+ .slice(0, 5);
325
+ }
197
326
 
198
- const mockHistoricalProjects = [
327
+ // Fallback to demo data if no historical specs found
328
+ const demoProjects = [
199
329
  {
200
330
  id: 'PROJ-0123',
201
331
  title: 'API Enhancement',
@@ -231,9 +361,9 @@ class ProjectSimilarityMatcher {
231
361
  },
232
362
  ];
233
363
 
234
- // Add a mock project similar to ARCH-0001 for demonstration
364
+ // Add a demo project similar to ARCH-0001 for demonstration
235
365
  if (currentSpec.id === 'ARCH-0001') {
236
- mockHistoricalProjects.push({
366
+ demoProjects.push({
237
367
  id: 'ARCH-0002',
238
368
  title: 'Policy System Refactor',
239
369
  risk_tier: 1,
@@ -246,7 +376,7 @@ class ProjectSimilarityMatcher {
246
376
  });
247
377
  }
248
378
 
249
- return mockHistoricalProjects
379
+ return demoProjects
250
380
  .map((project) => ({
251
381
  project: project.id,
252
382
  similarity_score: this.calculateSimilarity(currentSpec, project),
@@ -259,6 +389,69 @@ class ProjectSimilarityMatcher {
259
389
  .slice(0, 5); // Top 5 matches
260
390
  }
261
391
 
392
+ /**
393
+ * Convert a spec object to project format for similarity comparison
394
+ */
395
+ specToProject(spec) {
396
+ // Extract budget info from spec
397
+ const budget = spec.budget || spec.scope?.budget || {};
398
+ const allocatedFiles = budget.max_files || budget.files || 50;
399
+ const allocatedLoc = budget.max_loc || budget.loc || 5000;
400
+
401
+ // If spec has actual metrics, use them; otherwise estimate from allocated
402
+ const actualFiles = spec.metrics?.files_changed || spec.actual_files || allocatedFiles;
403
+ const actualLoc = spec.metrics?.lines_changed || spec.actual_loc || allocatedLoc;
404
+
405
+ // Extract tech stack from spec metadata
406
+ let techStack = spec.tech_stack || spec.metadata?.tech_stack || 'unknown';
407
+ if (!techStack || techStack === 'unknown') {
408
+ // Try to infer from title or description
409
+ const text = `${spec.title || ''} ${spec.description || ''}`.toLowerCase();
410
+ if (text.includes('react') || text.includes('ui') || text.includes('component')) {
411
+ techStack = 'react';
412
+ } else if (text.includes('api') || text.includes('node') || text.includes('server')) {
413
+ techStack = 'node';
414
+ } else if (text.includes('python') || text.includes('django') || text.includes('flask')) {
415
+ techStack = 'python';
416
+ }
417
+ }
418
+
419
+ // Extract feature type
420
+ let featureType = spec.feature_type || spec.type || 'general';
421
+ if (featureType === 'general') {
422
+ const text = `${spec.title || ''} ${spec.description || ''}`.toLowerCase();
423
+ if (text.includes('api') || text.includes('endpoint')) {
424
+ featureType = 'api';
425
+ } else if (text.includes('ui') || text.includes('component') || text.includes('view')) {
426
+ featureType = 'ui';
427
+ } else if (text.includes('data') || text.includes('migration') || text.includes('database')) {
428
+ featureType = 'data';
429
+ } else if (text.includes('refactor') || text.includes('architecture')) {
430
+ featureType = 'architecture';
431
+ }
432
+ }
433
+
434
+ return {
435
+ id: spec.id,
436
+ title: spec.title || spec.name || spec.id,
437
+ risk_tier: spec.risk_tier || spec.tier || 2,
438
+ mode: spec.mode || 'feature',
439
+ tech_stack: techStack,
440
+ feature_type: featureType,
441
+ actual_budget: {
442
+ files: actualFiles,
443
+ loc: actualLoc,
444
+ },
445
+ allocated_budget: {
446
+ files: allocatedFiles,
447
+ loc: allocatedLoc,
448
+ },
449
+ waivers: spec.waivers || [],
450
+ _source: spec._source,
451
+ _date: spec._date,
452
+ };
453
+ }
454
+
262
455
  /**
263
456
  * Calculate similarity score between two specs/projects
264
457
  */
@@ -0,0 +1,52 @@
1
+ export namespace ERROR_CATEGORIES {
2
+ let VALIDATION: string;
3
+ let PERMISSION: string;
4
+ let FILESYSTEM: string;
5
+ let NETWORK: string;
6
+ let CONFIGURATION: string;
7
+ let USER_INPUT: string;
8
+ let DEPENDENCY: string;
9
+ let UNKNOWN: string;
10
+ }
11
+ export namespace ERROR_CODES {
12
+ import EACCES = ERROR_CATEGORIES.PERMISSION;
13
+ export { EACCES };
14
+ import EPERM = ERROR_CATEGORIES.PERMISSION;
15
+ export { EPERM };
16
+ import ENOENT = ERROR_CATEGORIES.FILESYSTEM;
17
+ export { ENOENT };
18
+ import ENOTFOUND = ERROR_CATEGORIES.NETWORK;
19
+ export { ENOTFOUND };
20
+ import ECONNREFUSED = ERROR_CATEGORIES.NETWORK;
21
+ export { ECONNREFUSED };
22
+ import ETIMEDOUT = ERROR_CATEGORIES.NETWORK;
23
+ export { ETIMEDOUT };
24
+ import ENOSPC = ERROR_CATEGORIES.FILESYSTEM;
25
+ export { ENOSPC };
26
+ import EEXIST = ERROR_CATEGORIES.FILESYSTEM;
27
+ export { EEXIST };
28
+ import EISDIR = ERROR_CATEGORIES.FILESYSTEM;
29
+ export { EISDIR };
30
+ import ENOTDIR = ERROR_CATEGORIES.FILESYSTEM;
31
+ export { ENOTDIR };
32
+ }
33
+ /**
34
+ * Get error category from error object or message
35
+ * @param {Error|string} error - Error object or message
36
+ * @returns {string} Error category
37
+ */
38
+ export function getErrorCategory(error: Error | string): string;
39
+ /**
40
+ * Get user-friendly error message based on category
41
+ * @param {string} category - Error category
42
+ * @param {string} originalMessage - Original error message
43
+ * @returns {string} User-friendly message
44
+ */
45
+ export function getFriendlyMessage(category: string, originalMessage: string): string;
46
+ /**
47
+ * Get recovery suggestions based on error category
48
+ * @param {string} category - Error category
49
+ * @returns {Array<string>} Array of recovery suggestions
50
+ */
51
+ export function getCategorySuggestions(category: string): Array<string>;
52
+ //# sourceMappingURL=error-categories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-categories.d.ts","sourceRoot":"","sources":["../../src/utils/error-categories.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA;;;;GAIG;AACH,wCAHW,KAAK,GAAC,MAAM,GACV,MAAM,CA8ElB;AAED;;;;;GAKG;AACH,6CAJW,MAAM,mBACN,MAAM,GACJ,MAAM,CAmBlB;AAED;;;;GAIG;AACH,iDAHW,MAAM,GACJ,KAAK,CAAC,MAAM,CAAC,CAsDzB"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * @fileoverview Centralized Error Categories
3
+ * Shared error categorization for consistent error handling across CAWS packages
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ /**
8
+ * Error categories for better user experience
9
+ */
10
+ const ERROR_CATEGORIES = {
11
+ VALIDATION: 'validation',
12
+ PERMISSION: 'permission',
13
+ FILESYSTEM: 'filesystem',
14
+ NETWORK: 'network',
15
+ CONFIGURATION: 'configuration',
16
+ USER_INPUT: 'user_input',
17
+ DEPENDENCY: 'dependency',
18
+ UNKNOWN: 'unknown',
19
+ };
20
+
21
+ /**
22
+ * Error code mappings for common system errors
23
+ */
24
+ const ERROR_CODES = {
25
+ EACCES: ERROR_CATEGORIES.PERMISSION,
26
+ EPERM: ERROR_CATEGORIES.PERMISSION,
27
+ ENOENT: ERROR_CATEGORIES.FILESYSTEM,
28
+ ENOTFOUND: ERROR_CATEGORIES.NETWORK,
29
+ ECONNREFUSED: ERROR_CATEGORIES.NETWORK,
30
+ ETIMEDOUT: ERROR_CATEGORIES.NETWORK,
31
+ ENOSPC: ERROR_CATEGORIES.FILESYSTEM,
32
+ EEXIST: ERROR_CATEGORIES.FILESYSTEM,
33
+ EISDIR: ERROR_CATEGORIES.FILESYSTEM,
34
+ ENOTDIR: ERROR_CATEGORIES.FILESYSTEM,
35
+ };
36
+
37
+ /**
38
+ * Get error category from error object or message
39
+ * @param {Error|string} error - Error object or message
40
+ * @returns {string} Error category
41
+ */
42
+ function getErrorCategory(error) {
43
+ const errorMessage = typeof error === 'string' ? error : (error?.message || '');
44
+ const errorCode = typeof error === 'object' && error?.code ? error.code : null;
45
+
46
+ // Check error codes first
47
+ if (errorCode && ERROR_CODES[errorCode]) {
48
+ return ERROR_CODES[errorCode];
49
+ }
50
+
51
+ // Check message patterns
52
+ const lowerMessage = errorMessage.toLowerCase();
53
+
54
+ if (
55
+ lowerMessage.includes('validation') ||
56
+ lowerMessage.includes('invalid') ||
57
+ lowerMessage.includes('required') ||
58
+ lowerMessage.includes('malformed') ||
59
+ lowerMessage.includes('syntax')
60
+ ) {
61
+ return ERROR_CATEGORIES.VALIDATION;
62
+ }
63
+
64
+ if (
65
+ lowerMessage.includes('permission') ||
66
+ lowerMessage.includes('access') ||
67
+ lowerMessage.includes('denied') ||
68
+ lowerMessage.includes('forbidden')
69
+ ) {
70
+ return ERROR_CATEGORIES.PERMISSION;
71
+ }
72
+
73
+ if (
74
+ lowerMessage.includes('file') ||
75
+ lowerMessage.includes('directory') ||
76
+ lowerMessage.includes('path') ||
77
+ lowerMessage.includes('not found') ||
78
+ lowerMessage.includes('does not exist') ||
79
+ lowerMessage.includes('enoent')
80
+ ) {
81
+ return ERROR_CATEGORIES.FILESYSTEM;
82
+ }
83
+
84
+ if (
85
+ lowerMessage.includes('network') ||
86
+ lowerMessage.includes('connection') ||
87
+ lowerMessage.includes('timeout')
88
+ ) {
89
+ return ERROR_CATEGORIES.NETWORK;
90
+ }
91
+
92
+ if (
93
+ lowerMessage.includes('config') ||
94
+ lowerMessage.includes('setting') ||
95
+ lowerMessage.includes('option') ||
96
+ lowerMessage.includes('missing') ||
97
+ lowerMessage.includes('empty')
98
+ ) {
99
+ return ERROR_CATEGORIES.CONFIGURATION;
100
+ }
101
+
102
+ if (
103
+ lowerMessage.includes('input') ||
104
+ lowerMessage.includes('prompt') ||
105
+ lowerMessage.includes('answer')
106
+ ) {
107
+ return ERROR_CATEGORIES.USER_INPUT;
108
+ }
109
+
110
+ if (
111
+ lowerMessage.includes('dependency') ||
112
+ lowerMessage.includes('module not found')
113
+ ) {
114
+ return ERROR_CATEGORIES.DEPENDENCY;
115
+ }
116
+
117
+ return ERROR_CATEGORIES.UNKNOWN;
118
+ }
119
+
120
+ /**
121
+ * Get user-friendly error message based on category
122
+ * @param {string} category - Error category
123
+ * @param {string} originalMessage - Original error message
124
+ * @returns {string} User-friendly message
125
+ */
126
+ function getFriendlyMessage(category, originalMessage) {
127
+ const messages = {
128
+ [ERROR_CATEGORIES.PERMISSION]:
129
+ 'Permission denied. Check file permissions or run with elevated privileges.',
130
+ [ERROR_CATEGORIES.FILESYSTEM]:
131
+ 'File system error. Check if the file/directory exists and is accessible.',
132
+ [ERROR_CATEGORIES.NETWORK]: 'Network error. Check your connection and try again.',
133
+ [ERROR_CATEGORIES.VALIDATION]:
134
+ 'Data validation failed. Check your input format and requirements.',
135
+ [ERROR_CATEGORIES.CONFIGURATION]:
136
+ 'Configuration error. Check your settings and required fields.',
137
+ [ERROR_CATEGORIES.USER_INPUT]: 'Invalid user input. Check the command syntax and parameters.',
138
+ [ERROR_CATEGORIES.DEPENDENCY]: 'Missing dependency. Install required packages.',
139
+ [ERROR_CATEGORIES.UNKNOWN]: 'An unexpected error occurred.',
140
+ };
141
+
142
+ return messages[category] || originalMessage;
143
+ }
144
+
145
+ /**
146
+ * Get recovery suggestions based on error category
147
+ * @param {string} category - Error category
148
+ * @returns {Array<string>} Array of recovery suggestions
149
+ */
150
+ function getCategorySuggestions(category) {
151
+ const suggestions = {
152
+ [ERROR_CATEGORIES.PERMISSION]: [
153
+ 'Try running with sudo/admin privileges',
154
+ 'Check file/directory permissions with chmod/chown',
155
+ 'Verify user has write access to the target directory',
156
+ ],
157
+ [ERROR_CATEGORIES.FILESYSTEM]: [
158
+ 'Verify the file/directory path is correct',
159
+ 'Check if the file is not corrupted',
160
+ 'Ensure sufficient disk space is available',
161
+ 'Check if the file is not being used by another process',
162
+ ],
163
+ [ERROR_CATEGORIES.NETWORK]: [
164
+ 'Check your internet connection',
165
+ 'Verify network configuration and firewall settings',
166
+ 'Try again in a few moments',
167
+ 'Check if the remote service is available',
168
+ ],
169
+ [ERROR_CATEGORIES.VALIDATION]: [
170
+ 'Review the input format and requirements',
171
+ 'Check for typos in file paths or values',
172
+ 'Validate against the schema documentation',
173
+ 'Use the --help flag to see correct syntax',
174
+ ],
175
+ [ERROR_CATEGORIES.CONFIGURATION]: [
176
+ 'Check that all required configuration files exist',
177
+ 'Verify configuration values are in the correct format',
178
+ 'Review the setup documentation',
179
+ 'Ensure environment variables are set correctly',
180
+ ],
181
+ [ERROR_CATEGORIES.USER_INPUT]: [
182
+ 'Check the command syntax with --help',
183
+ 'Verify all required arguments are provided',
184
+ 'Ensure arguments are in the correct order',
185
+ 'Check for typos in command names or options',
186
+ ],
187
+ [ERROR_CATEGORIES.DEPENDENCY]: [
188
+ 'Install missing dependencies with npm install',
189
+ 'Check if all peer dependencies are installed',
190
+ 'Verify Node.js version compatibility',
191
+ 'Clear npm cache and try again',
192
+ ],
193
+ [ERROR_CATEGORIES.UNKNOWN]: [
194
+ 'Check the logs for more detailed information',
195
+ 'Try restarting the process',
196
+ 'Verify system resources (memory, disk space)',
197
+ 'Report the issue with full error details',
198
+ ],
199
+ };
200
+
201
+ return suggestions[category] || suggestions[ERROR_CATEGORIES.UNKNOWN];
202
+ }
203
+
204
+ module.exports = {
205
+ ERROR_CATEGORIES,
206
+ ERROR_CODES,
207
+ getErrorCategory,
208
+ getFriendlyMessage,
209
+ getCategorySuggestions,
210
+ };
@@ -35,5 +35,5 @@ export function verifyGitignore(projectRoot: string): Promise<boolean>;
35
35
  * - Logs (caws.log, debug logs)
36
36
  * - Local overrides (caws.local.*)
37
37
  */
38
- export const CAWS_GITIGNORE_ENTRIES: "\n# CAWS Local Runtime Data (developer-specific, should not be tracked)\n# ====================================================================\n# Note: Specs, policy, waivers, provenance, and plans ARE tracked for team collaboration\n# Only local agent tracking, generated tools, and temporary files are ignored\n\n# Agent runtime tracking (local to each developer)\n.agent/\n\n# CAWS tools (now in .caws/tools/)\n.caws/tools/\n# Legacy location (for backward compatibility)\napps/tools/caws/\n\n# Temporary CAWS files\n**/*.caws.tmp\n**/*.working-spec.bak\n.caws/*.tmp\n.caws/*.bak\n\n# CAWS logs (local debugging)\ncaws-debug.log*\n**/caws.log\n.caws/*.log\n\n# Local development overrides (developer-specific)\ncaws.local.*\n.caws/local.*\n";
38
+ export const CAWS_GITIGNORE_ENTRIES: "\n# CAWS Local Runtime Data (developer-specific, should not be tracked)\n# ====================================================================\n# Note: Specs, policy, waivers, provenance, and plans ARE tracked for team collaboration\n# Only local agent tracking, generated tools, and temporary files are ignored\n\n# Agent runtime tracking (local to each developer)\n.agent/\n\n# CAWS tools (now in .caws/tools/)\n.caws/tools/\n# Legacy location (for backward compatibility)\napps/tools/caws/\n\n# Temporary CAWS files\n**/*.caws.tmp\n**/*.working-spec.bak\n.caws/*.tmp\n.caws/*.bak\n\n# CAWS logs (local debugging)\ncaws-debug.log*\n**/caws.log\n.caws/*.log\n\n# Local development overrides (developer-specific)\ncaws.local.*\n.caws/local.*\n\n# CAWS Worktrees (local, should not be tracked)\n.caws/worktrees/\n.caws/worktrees.json\n";
39
39
  //# sourceMappingURL=gitignore-updater.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gitignore-updater.d.ts","sourceRoot":"","sources":["../../src/utils/gitignore-updater.js"],"names":[],"mappings":"AA6DA;;;;;;GAMG;AACH,6CALW,MAAM,YAEd;IAAyB,KAAK,EAAtB,OAAO;CACf,GAAU,OAAO,CAAC,OAAO,CAAC,CA2D5B;AAED;;;;GAIG;AACH,6CAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAW5B;AAnID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,gxBA4BE"}
1
+ {"version":3,"file":"gitignore-updater.d.ts","sourceRoot":"","sources":["../../src/utils/gitignore-updater.js"],"names":[],"mappings":"AAiEA;;;;;;GAMG;AACH,6CALW,MAAM,YAEd;IAAyB,KAAK,EAAtB,OAAO;CACf,GAAU,OAAO,CAAC,OAAO,CAAC,CA2D5B;AAED;;;;GAIG;AACH,6CAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAW5B;AAvID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,22BAgCE"}
@@ -57,6 +57,10 @@ caws-debug.log*
57
57
  # Local development overrides (developer-specific)
58
58
  caws.local.*
59
59
  .caws/local.*
60
+
61
+ # CAWS Worktrees (local, should not be tracked)
62
+ .caws/worktrees/
63
+ .caws/worktrees.json
60
64
  `;
61
65
 
62
66
  /**