@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.
- package/README.md +5 -6
- package/dist/commands/archive.d.ts +1 -0
- package/dist/commands/archive.d.ts.map +1 -1
- package/dist/commands/archive.js +114 -6
- package/dist/commands/burnup.d.ts.map +1 -1
- package/dist/commands/burnup.js +109 -10
- package/dist/commands/diagnose.js +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +185 -39
- package/dist/commands/mode.d.ts +2 -1
- package/dist/commands/mode.d.ts.map +1 -1
- package/dist/commands/mode.js +24 -14
- package/dist/commands/provenance.d.ts.map +1 -1
- package/dist/commands/provenance.js +216 -93
- package/dist/commands/quality-gates.d.ts.map +1 -1
- package/dist/commands/quality-gates.js +3 -1
- package/dist/commands/specs.d.ts.map +1 -1
- package/dist/commands/specs.js +184 -6
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +134 -10
- package/dist/commands/templates.js +2 -2
- package/dist/commands/worktree.d.ts +7 -0
- package/dist/commands/worktree.d.ts.map +1 -0
- package/dist/commands/worktree.js +136 -0
- package/dist/config/lite-scope.d.ts +33 -0
- package/dist/config/lite-scope.d.ts.map +1 -0
- package/dist/config/lite-scope.js +158 -0
- package/dist/config/modes.d.ts +90 -51
- package/dist/config/modes.d.ts.map +1 -1
- package/dist/config/modes.js +26 -0
- package/dist/error-handler.d.ts +3 -16
- package/dist/error-handler.d.ts.map +1 -1
- package/dist/error-handler.js +6 -98
- package/dist/generators/jest-config-generator.d.ts +32 -0
- package/dist/generators/jest-config-generator.d.ts.map +1 -0
- package/dist/generators/jest-config-generator.js +242 -0
- package/dist/index.js +40 -7
- package/dist/minimal-cli.js +3 -1
- package/dist/scaffold/claude-hooks.d.ts +28 -0
- package/dist/scaffold/claude-hooks.d.ts.map +1 -0
- package/dist/scaffold/claude-hooks.js +344 -0
- package/dist/scaffold/index.d.ts +2 -0
- package/dist/scaffold/index.d.ts.map +1 -1
- package/dist/scaffold/index.js +96 -76
- package/dist/templates/.caws/schemas/scope.schema.json +52 -0
- package/dist/templates/.caws/schemas/working-spec.schema.json +1 -1
- package/dist/templates/.caws/schemas/worktrees.schema.json +36 -0
- package/dist/templates/.claude/README.md +190 -0
- package/dist/templates/.claude/hooks/audit.sh +96 -0
- package/dist/templates/.claude/hooks/block-dangerous.sh +123 -0
- package/dist/templates/.claude/hooks/lite-sprawl-check.sh +117 -0
- package/dist/templates/.claude/hooks/naming-check.sh +97 -0
- package/dist/templates/.claude/hooks/quality-check.sh +68 -0
- package/dist/templates/.claude/hooks/scan-secrets.sh +85 -0
- package/dist/templates/.claude/hooks/scope-guard.sh +192 -0
- package/dist/templates/.claude/hooks/simplification-guard.sh +92 -0
- package/dist/templates/.claude/hooks/validate-spec.sh +76 -0
- package/dist/templates/.claude/settings.json +95 -0
- package/dist/templates/.cursor/README.md +0 -3
- package/dist/templates/.github/copilot-instructions.md +82 -0
- package/dist/templates/.junie/guidelines.md +73 -0
- package/dist/templates/.vscode/launch.json +0 -27
- package/dist/templates/.windsurf/rules/caws-quality-standards.md +54 -0
- package/dist/templates/CLAUDE.md +101 -0
- package/dist/templates/agents.md +73 -1016
- package/dist/templates/docs/README.md +5 -5
- package/dist/test-analysis.d.ts +50 -1
- package/dist/test-analysis.d.ts.map +1 -1
- package/dist/test-analysis.js +203 -10
- package/dist/utils/error-categories.d.ts +52 -0
- package/dist/utils/error-categories.d.ts.map +1 -0
- package/dist/utils/error-categories.js +210 -0
- package/dist/utils/gitignore-updater.d.ts +1 -1
- package/dist/utils/gitignore-updater.d.ts.map +1 -1
- package/dist/utils/gitignore-updater.js +4 -0
- package/dist/utils/ide-detection.js +133 -0
- package/dist/utils/quality-gates-utils.d.ts +49 -0
- package/dist/utils/quality-gates-utils.d.ts.map +1 -0
- package/dist/utils/quality-gates-utils.js +402 -0
- package/dist/utils/typescript-detector.d.ts +8 -5
- package/dist/utils/typescript-detector.d.ts.map +1 -1
- package/dist/utils/typescript-detector.js +36 -90
- package/dist/validation/spec-validation.d.ts.map +1 -1
- package/dist/validation/spec-validation.js +59 -6
- package/dist/worktree/worktree-manager.d.ts +54 -0
- package/dist/worktree/worktree-manager.d.ts.map +1 -0
- package/dist/worktree/worktree-manager.js +378 -0
- package/package.json +9 -3
- package/templates/.caws/schemas/scope.schema.json +52 -0
- package/templates/.caws/schemas/working-spec.schema.json +1 -1
- package/templates/.caws/schemas/worktrees.schema.json +36 -0
- package/templates/.claude/README.md +190 -0
- package/templates/.claude/hooks/audit.sh +96 -0
- package/templates/.claude/hooks/block-dangerous.sh +123 -0
- package/templates/.claude/hooks/lite-sprawl-check.sh +117 -0
- package/templates/.claude/hooks/naming-check.sh +97 -0
- package/templates/.claude/hooks/quality-check.sh +68 -0
- package/templates/.claude/hooks/scan-secrets.sh +85 -0
- package/templates/.claude/hooks/scope-guard.sh +192 -0
- package/templates/.claude/hooks/simplification-guard.sh +92 -0
- package/templates/.claude/hooks/validate-spec.sh +76 -0
- package/templates/.claude/settings.json +95 -0
- package/templates/.cursor/README.md +0 -3
- package/templates/.github/copilot-instructions.md +82 -0
- package/templates/.junie/guidelines.md +73 -0
- package/templates/.vscode/launch.json +0 -27
- package/templates/.windsurf/rules/caws-quality-standards.md +54 -0
- package/templates/AGENTS.md +104 -0
- package/templates/CLAUDE.md +101 -0
- package/templates/docs/README.md +5 -5
- package/templates/.github/copilot/instructions.md +0 -311
- 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
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
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
|
|
package/dist/test-analysis.d.ts
CHANGED
|
@@ -55,7 +55,8 @@ export class WaiverPatternLearner {
|
|
|
55
55
|
*/
|
|
56
56
|
loadWaivers(): any[];
|
|
57
57
|
/**
|
|
58
|
-
* Load historical working specs
|
|
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":"
|
|
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"}
|
package/dist/test-analysis.js
CHANGED
|
@@ -82,12 +82,117 @@ class WaiverPatternLearner {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Load historical working specs
|
|
85
|
+
* Load historical working specs from git history
|
|
86
|
+
* Retrieves past versions of spec files to analyze patterns
|
|
86
87
|
*/
|
|
87
88
|
loadHistoricalSpecs() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
//
|
|
196
|
-
|
|
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
|
-
|
|
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
|
|
364
|
+
// Add a demo project similar to ARCH-0001 for demonstration
|
|
235
365
|
if (currentSpec.id === 'ARCH-0001') {
|
|
236
|
-
|
|
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
|
|
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":"
|
|
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"}
|