@paths.design/caws-cli 8.2.1 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/budget-derivation.js +10 -10
- package/dist/commands/archive.js +22 -22
- package/dist/commands/burnup.js +7 -7
- package/dist/commands/diagnose.js +25 -25
- package/dist/commands/evaluate.js +20 -20
- package/dist/commands/init.js +71 -72
- package/dist/commands/iterate.js +21 -21
- package/dist/commands/mode.js +11 -11
- package/dist/commands/plan.js +5 -5
- package/dist/commands/provenance.js +86 -86
- package/dist/commands/quality-gates.js +3 -3
- package/dist/commands/quality-monitor.js +17 -17
- package/dist/commands/session.js +312 -0
- package/dist/commands/specs.js +44 -44
- package/dist/commands/status.js +43 -43
- package/dist/commands/templates.js +14 -14
- package/dist/commands/tool.js +1 -1
- package/dist/commands/troubleshoot.js +11 -11
- package/dist/commands/tutorial.js +119 -119
- package/dist/commands/validate.js +6 -6
- package/dist/commands/waivers.js +93 -60
- package/dist/commands/workflow.js +17 -17
- package/dist/commands/worktree.js +13 -13
- package/dist/config/index.js +5 -5
- package/dist/config/modes.js +7 -7
- package/dist/constants/spec-types.js +5 -5
- package/dist/error-handler.js +4 -4
- package/dist/generators/jest-config-generator.js +3 -3
- package/dist/generators/working-spec.js +4 -4
- package/dist/index.js +79 -27
- package/dist/minimal-cli.js +9 -9
- package/dist/policy/PolicyManager.js +1 -1
- package/dist/scaffold/claude-hooks.js +7 -7
- package/dist/scaffold/cursor-hooks.js +8 -8
- package/dist/scaffold/git-hooks.js +152 -152
- package/dist/scaffold/index.js +48 -48
- package/dist/session/session-manager.js +548 -0
- package/dist/test-analysis.js +20 -20
- package/dist/utils/command-wrapper.js +8 -8
- package/dist/utils/detection.js +7 -7
- package/dist/utils/finalization.js +21 -21
- package/dist/utils/git-lock.js +3 -3
- package/dist/utils/gitignore-updater.js +1 -1
- package/dist/utils/project-analysis.js +7 -7
- package/dist/utils/quality-gates-utils.js +35 -35
- package/dist/utils/spec-resolver.js +8 -8
- package/dist/utils/typescript-detector.js +5 -5
- package/dist/utils/yaml-validation.js +1 -1
- package/dist/validation/spec-validation.js +4 -4
- package/dist/worktree/worktree-manager.js +11 -5
- package/package.json +1 -1
|
@@ -81,7 +81,7 @@ const Output = {
|
|
|
81
81
|
true
|
|
82
82
|
);
|
|
83
83
|
} else {
|
|
84
|
-
console.log(chalk.green(
|
|
84
|
+
console.log(chalk.green(`${message}`));
|
|
85
85
|
if (Object.keys(data).length > 0 && !isJsonOutput()) {
|
|
86
86
|
console.log(chalk.gray(JSON.stringify(data, null, 2)));
|
|
87
87
|
}
|
|
@@ -106,9 +106,9 @@ const Output = {
|
|
|
106
106
|
false
|
|
107
107
|
);
|
|
108
108
|
} else {
|
|
109
|
-
console.error(chalk.red(
|
|
109
|
+
console.error(chalk.red(`${message}`));
|
|
110
110
|
if (suggestions.length > 0) {
|
|
111
|
-
console.error(chalk.yellow('\
|
|
111
|
+
console.error(chalk.yellow('\nSuggestions:'));
|
|
112
112
|
suggestions.forEach((suggestion) => {
|
|
113
113
|
console.error(chalk.yellow(` ${suggestion}`));
|
|
114
114
|
});
|
|
@@ -132,9 +132,9 @@ const Output = {
|
|
|
132
132
|
true
|
|
133
133
|
);
|
|
134
134
|
} else {
|
|
135
|
-
console.warn(chalk.yellow(
|
|
135
|
+
console.warn(chalk.yellow(`${message}`));
|
|
136
136
|
if (suggestion) {
|
|
137
|
-
console.warn(chalk.blue(`
|
|
137
|
+
console.warn(chalk.blue(` ${suggestion}`));
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
},
|
|
@@ -155,7 +155,7 @@ const Output = {
|
|
|
155
155
|
true
|
|
156
156
|
);
|
|
157
157
|
} else {
|
|
158
|
-
console.log(chalk.blue(
|
|
158
|
+
console.log(chalk.blue(`${message}`));
|
|
159
159
|
if (Object.keys(data).length > 0) {
|
|
160
160
|
console.log(chalk.gray(JSON.stringify(data, null, 2)));
|
|
161
161
|
}
|
|
@@ -177,7 +177,7 @@ const Output = {
|
|
|
177
177
|
*/
|
|
178
178
|
progress(message) {
|
|
179
179
|
if (!isJsonOutput()) {
|
|
180
|
-
console.log(chalk.blue(
|
|
180
|
+
console.log(chalk.blue(`${message}`));
|
|
181
181
|
}
|
|
182
182
|
},
|
|
183
183
|
|
|
@@ -188,7 +188,7 @@ const Output = {
|
|
|
188
188
|
section(title) {
|
|
189
189
|
if (!isJsonOutput()) {
|
|
190
190
|
console.log(chalk.bold(`\n${title}`));
|
|
191
|
-
console.log('
|
|
191
|
+
console.log('-'.repeat(Math.min(title.length, 60)));
|
|
192
192
|
}
|
|
193
193
|
},
|
|
194
194
|
};
|
package/dist/utils/detection.js
CHANGED
|
@@ -40,7 +40,7 @@ function detectCAWSSetup(cwd = process.cwd()) {
|
|
|
40
40
|
process.argv.includes('--help');
|
|
41
41
|
|
|
42
42
|
if (!isQuietCommand) {
|
|
43
|
-
console.log(chalk.blue('
|
|
43
|
+
console.log(chalk.blue('Detecting CAWS setup...'));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Check for existing CAWS setup
|
|
@@ -49,7 +49,7 @@ function detectCAWSSetup(cwd = process.cwd()) {
|
|
|
49
49
|
|
|
50
50
|
if (!hasCAWSDir) {
|
|
51
51
|
if (!isQuietCommand) {
|
|
52
|
-
console.log(chalk.gray('
|
|
52
|
+
console.log(chalk.gray('No .caws directory found - new project setup'));
|
|
53
53
|
}
|
|
54
54
|
return {
|
|
55
55
|
type: 'new',
|
|
@@ -107,7 +107,7 @@ function detectCAWSSetup(cwd = process.cwd()) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
if (!isQuietCommand) {
|
|
110
|
-
console.log(chalk.green(
|
|
110
|
+
console.log(chalk.green(`Detected ${setupType} CAWS setup`));
|
|
111
111
|
console.log(chalk.gray(` Capabilities: ${capabilities.join(', ')}`));
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -160,7 +160,7 @@ function detectCAWSSetup(cwd = process.cwd()) {
|
|
|
160
160
|
if (fs.existsSync(testPath)) {
|
|
161
161
|
templateDir = testPath;
|
|
162
162
|
if (!isQuietCommand) {
|
|
163
|
-
console.log(
|
|
163
|
+
console.log(`Found CAWS templates in ${source}:`);
|
|
164
164
|
console.log(` ${chalk.gray(testPath)}`);
|
|
165
165
|
}
|
|
166
166
|
break;
|
|
@@ -168,10 +168,10 @@ function detectCAWSSetup(cwd = process.cwd()) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
if (!templateDir && !isQuietCommand) {
|
|
171
|
-
console.warn(chalk.yellow('
|
|
172
|
-
console.warn(chalk.blue('
|
|
171
|
+
console.warn(chalk.yellow('CAWS templates not found in standard locations'));
|
|
172
|
+
console.warn(chalk.blue('This may limit available scaffolding features'));
|
|
173
173
|
console.warn(
|
|
174
|
-
chalk.blue('
|
|
174
|
+
chalk.blue('For full functionality, ensure caws-template package is available')
|
|
175
175
|
);
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -37,11 +37,11 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
37
37
|
try {
|
|
38
38
|
// Detect and configure language support
|
|
39
39
|
if (languageSupport) {
|
|
40
|
-
console.log(chalk.cyan('
|
|
40
|
+
console.log(chalk.cyan('Detecting project language...'));
|
|
41
41
|
const detectedLanguage = languageSupport.detectProjectLanguage();
|
|
42
42
|
|
|
43
43
|
if (detectedLanguage !== 'unknown') {
|
|
44
|
-
console.log(chalk.green(
|
|
44
|
+
console.log(chalk.green(`Detected language: ${detectedLanguage}`));
|
|
45
45
|
|
|
46
46
|
// Generate language-specific configuration
|
|
47
47
|
try {
|
|
@@ -50,25 +50,25 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
50
50
|
'.caws/language-config.json'
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
console.log(chalk.green('
|
|
53
|
+
console.log(chalk.green('Generated language-specific configuration'));
|
|
54
54
|
console.log(` Language: ${langConfig.name}`);
|
|
55
55
|
console.log(` Tier: ${langConfig.tier}`);
|
|
56
56
|
console.log(
|
|
57
57
|
` Thresholds: Branch ≥${langConfig.thresholds.min_branch * 100}%, Mutation ≥${langConfig.thresholds.min_mutation * 100}%`
|
|
58
58
|
);
|
|
59
59
|
} catch (langError) {
|
|
60
|
-
console.warn(chalk.yellow('
|
|
60
|
+
console.warn(chalk.yellow('Could not generate language config:'), langError.message);
|
|
61
61
|
}
|
|
62
62
|
} else {
|
|
63
63
|
console.log(
|
|
64
|
-
chalk.blue('
|
|
64
|
+
chalk.blue('Could not detect project language - using default configuration')
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// Setup Cursor hooks if enabled
|
|
70
70
|
if (answers && answers.enableCursorHooks) {
|
|
71
|
-
console.log(chalk.cyan('
|
|
71
|
+
console.log(chalk.cyan('Setting up Cursor hooks...'));
|
|
72
72
|
await scaffoldCursorHooks(
|
|
73
73
|
process.cwd(),
|
|
74
74
|
answers.cursorHookLevels || ['safety', 'quality', 'scope', 'audit']
|
|
@@ -76,7 +76,7 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
// Generate provenance manifest
|
|
79
|
-
console.log(chalk.cyan('
|
|
79
|
+
console.log(chalk.cyan('Generating provenance manifest...'));
|
|
80
80
|
|
|
81
81
|
const provenanceData = {
|
|
82
82
|
agent: 'caws-cli',
|
|
@@ -118,24 +118,24 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
118
118
|
) {
|
|
119
119
|
const provenance = tools.generateProvenance(provenanceData);
|
|
120
120
|
await tools.saveProvenance(provenance, '.agent/provenance.json');
|
|
121
|
-
console.log(chalk.green('
|
|
121
|
+
console.log(chalk.green('Provenance manifest generated'));
|
|
122
122
|
} else {
|
|
123
123
|
console.log(
|
|
124
|
-
chalk.yellow('
|
|
124
|
+
chalk.yellow('Provenance tools not available - skipping manifest generation')
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// Initialize git repository
|
|
129
129
|
if (options.git) {
|
|
130
130
|
try {
|
|
131
|
-
console.log(chalk.cyan('
|
|
131
|
+
console.log(chalk.cyan('Initializing git repository...'));
|
|
132
132
|
|
|
133
133
|
// Check if git is available
|
|
134
134
|
try {
|
|
135
135
|
require('child_process').execSync('git --version', { stdio: 'ignore' });
|
|
136
136
|
} catch (error) {
|
|
137
|
-
console.warn(chalk.yellow('
|
|
138
|
-
console.warn(chalk.blue('
|
|
137
|
+
console.warn(chalk.yellow('Git not found. Skipping git initialization.'));
|
|
138
|
+
console.warn(chalk.blue('Install git to enable automatic repository setup.'));
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -151,7 +151,7 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
151
151
|
require('child_process').execSync(`git config user.email "${authorEmail}"`, {
|
|
152
152
|
stdio: 'inherit',
|
|
153
153
|
});
|
|
154
|
-
console.log(chalk.green(
|
|
154
|
+
console.log(chalk.green(`Git configured: ${authorName} <${authorEmail}>`));
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
require('child_process').execSync('git init', { stdio: 'inherit' });
|
|
@@ -159,7 +159,7 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
159
159
|
require('child_process').execSync('git commit -m "Initial CAWS project setup"', {
|
|
160
160
|
stdio: 'inherit',
|
|
161
161
|
});
|
|
162
|
-
console.log(chalk.green('
|
|
162
|
+
console.log(chalk.green('Git repository initialized'));
|
|
163
163
|
|
|
164
164
|
// Update provenance with commit hash
|
|
165
165
|
const commitHash = require('child_process')
|
|
@@ -173,19 +173,19 @@ async function finalizeProject(projectName, options, answers) {
|
|
|
173
173
|
.digest('hex');
|
|
174
174
|
await fs.writeFile('.agent/provenance.json', JSON.stringify(currentProvenance, null, 2));
|
|
175
175
|
|
|
176
|
-
console.log(chalk.green('
|
|
176
|
+
console.log(chalk.green('Provenance updated with commit hash'));
|
|
177
177
|
} catch (error) {
|
|
178
178
|
console.warn(
|
|
179
|
-
chalk.yellow('
|
|
179
|
+
chalk.yellow('Failed to initialize git repository:'),
|
|
180
180
|
error?.message || String(error)
|
|
181
181
|
);
|
|
182
|
-
console.warn(chalk.blue('
|
|
182
|
+
console.warn(chalk.blue('You can initialize git manually later with:'));
|
|
183
183
|
console.warn(" git init && git add . && git commit -m 'Initial CAWS project setup'");
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
} catch (error) {
|
|
187
187
|
console.error(
|
|
188
|
-
chalk.red('
|
|
188
|
+
chalk.red('Error during project finalization:'),
|
|
189
189
|
error?.message || String(error)
|
|
190
190
|
);
|
|
191
191
|
}
|
|
@@ -199,15 +199,15 @@ function continueToSuccess() {
|
|
|
199
199
|
process.cwd() ===
|
|
200
200
|
path.resolve(process.argv[3] === '.' ? process.cwd() : process.argv[3] || 'caws-project');
|
|
201
201
|
|
|
202
|
-
console.log(chalk.green('\
|
|
202
|
+
console.log(chalk.green('\nCAWS project initialized successfully!'));
|
|
203
203
|
|
|
204
204
|
if (isCurrentDir) {
|
|
205
205
|
console.log(
|
|
206
|
-
|
|
206
|
+
`${chalk.cyan('Initialized in current directory')}: ${path.resolve(process.cwd())}`
|
|
207
207
|
);
|
|
208
208
|
console.log(chalk.gray(' (CAWS files added to your existing project)'));
|
|
209
209
|
} else {
|
|
210
|
-
console.log(
|
|
210
|
+
console.log(`${chalk.cyan('Project location')}: ${path.resolve(process.cwd())}`);
|
|
211
211
|
console.log(chalk.gray(' (New subdirectory created with CAWS structure)'));
|
|
212
212
|
}
|
|
213
213
|
|
package/dist/utils/git-lock.js
CHANGED
|
@@ -84,7 +84,7 @@ function formatGitLockError(lockStatus) {
|
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
let message = '
|
|
87
|
+
let message = 'Git lock detected\n';
|
|
88
88
|
message += ` ${lockStatus.message}\n`;
|
|
89
89
|
|
|
90
90
|
if (lockStatus.lockFiles.length > 0) {
|
|
@@ -99,12 +99,12 @@ function formatGitLockError(lockStatus) {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
if (lockStatus.suggestion) {
|
|
102
|
-
message += `\n
|
|
102
|
+
message += `\n ${lockStatus.suggestion}\n`;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (lockStatus.stale) {
|
|
106
106
|
message +=
|
|
107
|
-
'\n
|
|
107
|
+
'\n Warning: Removing stale locks may cause data loss if another process is actually running.\n';
|
|
108
108
|
message += ' Check for running git/editor processes before removing locks.\n';
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -124,7 +124,7 @@ async function updateGitignore(projectRoot, options = {}) {
|
|
|
124
124
|
|
|
125
125
|
return true;
|
|
126
126
|
} catch (error) {
|
|
127
|
-
console.warn(chalk.yellow(
|
|
127
|
+
console.warn(chalk.yellow(`Could not update .gitignore: ${error.message}`));
|
|
128
128
|
return false;
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -333,27 +333,27 @@ function getTodoAnalyzerSuggestion(cwd = process.cwd()) {
|
|
|
333
333
|
if (hasNpx) {
|
|
334
334
|
// npx available - works for any language, no installation needed
|
|
335
335
|
suggestions.push(
|
|
336
|
-
'
|
|
336
|
+
' - Use npx (no installation required): npx --yes @paths.design/quality-gates'
|
|
337
337
|
);
|
|
338
|
-
suggestions.push('
|
|
338
|
+
suggestions.push(' - Install package: npm install --save-dev @paths.design/quality-gates');
|
|
339
339
|
} else if (hasNodeJs) {
|
|
340
340
|
// Node.js available but npx not found (unusual)
|
|
341
|
-
suggestions.push('
|
|
341
|
+
suggestions.push(' - Install package: npm install --save-dev @paths.design/quality-gates');
|
|
342
342
|
suggestions.push(
|
|
343
|
-
'
|
|
343
|
+
' - Install npx: npm install -g npx (then use: npx --yes @paths.design/quality-gates)'
|
|
344
344
|
);
|
|
345
345
|
} else {
|
|
346
346
|
// Node.js not available - suggest installation
|
|
347
347
|
suggestions.push(
|
|
348
|
-
'
|
|
348
|
+
' - Install Node.js: https://nodejs.org/ (then use: npx --yes @paths.design/quality-gates)'
|
|
349
349
|
);
|
|
350
|
-
suggestions.push('
|
|
350
|
+
suggestions.push(' - Use CAWS MCP server: caws quality-gates (via MCP)');
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
// Check for project-specific scripts (language-agnostic - if they exist, suggest them)
|
|
354
354
|
const pythonScript = path.join(cwd, 'scripts', 'v3', 'analysis', 'todo_analyzer.py');
|
|
355
355
|
if (fs.existsSync(pythonScript)) {
|
|
356
|
-
suggestions.push(`
|
|
356
|
+
suggestions.push(` - Use project script: python3 ${pythonScript}`);
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
return suggestions.join('\n');
|
|
@@ -117,7 +117,7 @@ function getStagedFiles() {
|
|
|
117
117
|
|
|
118
118
|
return stagedFiles;
|
|
119
119
|
} catch (error) {
|
|
120
|
-
console.warn(
|
|
120
|
+
console.warn(`Could not get staged files: ${error.message}`);
|
|
121
121
|
return [];
|
|
122
122
|
}
|
|
123
123
|
}
|
|
@@ -144,7 +144,7 @@ function checkGodObjects(stagedFiles, language = 'rust') {
|
|
|
144
144
|
return { violations: [], warnings: [], total: 0 };
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
console.log(
|
|
147
|
+
console.log(`Found ${files.length} staged ${language} files to check`);
|
|
148
148
|
|
|
149
149
|
const violations = [];
|
|
150
150
|
const warnings = [];
|
|
@@ -173,7 +173,7 @@ function checkGodObjects(stagedFiles, language = 'rust') {
|
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
} catch (error) {
|
|
176
|
-
console.warn(
|
|
176
|
+
console.warn(`Could not analyze ${file}: ${error.message}`);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -194,7 +194,7 @@ function checkHiddenTodos(stagedFiles) {
|
|
|
194
194
|
return { todos: [], blocking: 0, total: 0 };
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
console.log(
|
|
197
|
+
console.log(`Found ${supportedFiles.length} staged files to analyze for TODOs`);
|
|
198
198
|
|
|
199
199
|
try {
|
|
200
200
|
// Find TODO analyzer .mjs file (preferred - no Python dependency)
|
|
@@ -229,17 +229,17 @@ function checkHiddenTodos(stagedFiles) {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
if (!analyzerPath) {
|
|
232
|
-
console.warn('
|
|
232
|
+
console.warn('TODO analyzer not found - skipping TODO analysis');
|
|
233
233
|
const suggestion = getTodoAnalyzerSuggestion(process.cwd());
|
|
234
|
-
console.warn('
|
|
234
|
+
console.warn('Available options for TODO analysis:');
|
|
235
235
|
console.warn(suggestion);
|
|
236
236
|
return { todos: [], blocking: 0, total: 0 };
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
if (usePython) {
|
|
240
|
-
console.warn('
|
|
240
|
+
console.warn('Using legacy Python TODO analyzer (deprecated)');
|
|
241
241
|
const suggestion = getTodoAnalyzerSuggestion(process.cwd());
|
|
242
|
-
console.warn('
|
|
242
|
+
console.warn('Consider upgrading to Node.js version:');
|
|
243
243
|
console.warn(suggestion);
|
|
244
244
|
}
|
|
245
245
|
|
|
@@ -262,7 +262,7 @@ function checkHiddenTodos(stagedFiles) {
|
|
|
262
262
|
details: result,
|
|
263
263
|
};
|
|
264
264
|
} catch (error) {
|
|
265
|
-
console.warn(
|
|
265
|
+
console.warn(`Could not run TODO analysis: ${error.message}`);
|
|
266
266
|
return { todos: [], blocking: 0, total: 0 };
|
|
267
267
|
}
|
|
268
268
|
}
|
|
@@ -275,18 +275,18 @@ function checkHiddenTodos(stagedFiles) {
|
|
|
275
275
|
function runQualityGates(options = {}) {
|
|
276
276
|
const { languages = ['rust'], checkTodos = true, checkGodObjects = true, ci = false } = options;
|
|
277
277
|
|
|
278
|
-
console.log(
|
|
278
|
+
console.log(`Running Quality Gates${ci ? ' (CI Mode)' : ' - Crisis Response Mode'}`);
|
|
279
279
|
console.log('==================================================');
|
|
280
280
|
|
|
281
281
|
// Get staged files
|
|
282
282
|
const stagedFiles = getStagedFiles();
|
|
283
283
|
|
|
284
284
|
if (stagedFiles.length === 0) {
|
|
285
|
-
console.log('
|
|
285
|
+
console.log('No staged files to analyze');
|
|
286
286
|
return { passed: true, violations: [], warnings: [] };
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
console.log(
|
|
289
|
+
console.log(`Analyzing ${stagedFiles.length} staged files`);
|
|
290
290
|
|
|
291
291
|
const results = {
|
|
292
292
|
passed: true,
|
|
@@ -296,37 +296,37 @@ function runQualityGates(options = {}) {
|
|
|
296
296
|
};
|
|
297
297
|
|
|
298
298
|
// Check naming conventions
|
|
299
|
-
console.log('\
|
|
300
|
-
console.log('
|
|
299
|
+
console.log('\nChecking naming conventions...');
|
|
300
|
+
console.log(' Naming conventions check passed');
|
|
301
301
|
|
|
302
302
|
// Check code freeze compliance
|
|
303
|
-
console.log('\
|
|
304
|
-
console.log('
|
|
303
|
+
console.log('\nChecking code freeze compliance...');
|
|
304
|
+
console.log(' Code freeze compliance check passed');
|
|
305
305
|
|
|
306
306
|
// Check duplication
|
|
307
|
-
console.log('\
|
|
308
|
-
console.log('
|
|
307
|
+
console.log('\nChecking duplication...');
|
|
308
|
+
console.log(' No duplication regression detected');
|
|
309
309
|
|
|
310
310
|
// Check god objects for each language
|
|
311
311
|
if (checkGodObjects) {
|
|
312
312
|
for (const language of languages) {
|
|
313
|
-
console.log(`\
|
|
313
|
+
console.log(`\nChecking god objects (${language})...`);
|
|
314
314
|
const godObjectResults = checkGodObjects(stagedFiles, language);
|
|
315
315
|
|
|
316
316
|
results.violations.push(...godObjectResults.violations);
|
|
317
317
|
results.warnings.push(...godObjectResults.warnings);
|
|
318
318
|
|
|
319
319
|
if (godObjectResults.violations.length > 0) {
|
|
320
|
-
console.log('
|
|
320
|
+
console.log(' God object violations detected:');
|
|
321
321
|
godObjectResults.violations.forEach((violation) => {
|
|
322
322
|
console.log(` ${violation.file}: ${violation.message}`);
|
|
323
323
|
});
|
|
324
324
|
} else {
|
|
325
|
-
console.log('
|
|
325
|
+
console.log(' No blocking god object violations');
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
if (godObjectResults.warnings.length > 0) {
|
|
329
|
-
console.log('
|
|
329
|
+
console.log(' God object warnings:');
|
|
330
330
|
godObjectResults.warnings.forEach((warning) => {
|
|
331
331
|
console.log(` ${warning.file}: ${warning.message}`);
|
|
332
332
|
});
|
|
@@ -336,22 +336,22 @@ function runQualityGates(options = {}) {
|
|
|
336
336
|
|
|
337
337
|
// Check hidden TODOs
|
|
338
338
|
if (checkTodos) {
|
|
339
|
-
console.log('\
|
|
339
|
+
console.log('\nChecking hidden TODOs...');
|
|
340
340
|
const todoResults = checkHiddenTodos(stagedFiles);
|
|
341
341
|
results.todos = todoResults.total;
|
|
342
342
|
|
|
343
343
|
if (todoResults.total > 0) {
|
|
344
|
-
console.log(`
|
|
345
|
-
console.log('
|
|
346
|
-
console.log('
|
|
344
|
+
console.log(` Found ${todoResults.total} hidden TODOs in staged files`);
|
|
345
|
+
console.log(' Fix stub implementations and placeholder code before committing');
|
|
346
|
+
console.log(' See docs/PLACEHOLDER-DETECTION-GUIDE.md for classification');
|
|
347
347
|
} else {
|
|
348
|
-
console.log('
|
|
348
|
+
console.log(' No critical hidden TODOs found in staged files');
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
// Summary
|
|
353
353
|
console.log('\n==================================================');
|
|
354
|
-
console.log('
|
|
354
|
+
console.log('QUALITY GATES RESULTS');
|
|
355
355
|
console.log('==================================================');
|
|
356
356
|
|
|
357
357
|
const totalViolations = results.violations.length;
|
|
@@ -359,7 +359,7 @@ function runQualityGates(options = {}) {
|
|
|
359
359
|
const totalTodos = results.todos;
|
|
360
360
|
|
|
361
361
|
if (totalViolations > 0) {
|
|
362
|
-
console.log(`\
|
|
362
|
+
console.log(`\nCRITICAL VIOLATIONS (${totalViolations}):`);
|
|
363
363
|
results.violations.forEach((violation) => {
|
|
364
364
|
console.log(` ${violation.file}: ${violation.message}`);
|
|
365
365
|
});
|
|
@@ -367,25 +367,25 @@ function runQualityGates(options = {}) {
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
if (totalWarnings > 0) {
|
|
370
|
-
console.log(`\
|
|
370
|
+
console.log(`\nWARNINGS (${totalWarnings}):`);
|
|
371
371
|
results.warnings.forEach((warning) => {
|
|
372
372
|
console.log(` ${warning.file}: ${warning.message}`);
|
|
373
373
|
});
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
if (totalTodos > 0) {
|
|
377
|
-
console.log(`\
|
|
377
|
+
console.log(`\nHIDDEN TODOS (${totalTodos}):`);
|
|
378
378
|
console.log(` Found ${totalTodos} hidden TODOs in staged files`);
|
|
379
379
|
results.passed = false;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
// Final result
|
|
383
383
|
if (results.passed) {
|
|
384
|
-
console.log('\
|
|
385
|
-
console.log('
|
|
384
|
+
console.log('\nALL QUALITY GATES PASSED');
|
|
385
|
+
console.log('Commit allowed - quality maintained!');
|
|
386
386
|
} else {
|
|
387
|
-
console.log('\
|
|
388
|
-
console.log('
|
|
387
|
+
console.log('\nQUALITY GATES FAILED');
|
|
388
|
+
console.log('Commit blocked - fix violations above');
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
return results;
|
|
@@ -62,7 +62,7 @@ async function resolveSpec(options = {}) {
|
|
|
62
62
|
const content = await fs.readFile(featurePath, 'utf8');
|
|
63
63
|
const spec = yaml.load(content);
|
|
64
64
|
|
|
65
|
-
console.log(chalk.green(
|
|
65
|
+
console.log(chalk.green(`Using feature-specific spec: ${specId}`));
|
|
66
66
|
|
|
67
67
|
return {
|
|
68
68
|
path: featurePath,
|
|
@@ -90,7 +90,7 @@ async function resolveSpec(options = {}) {
|
|
|
90
90
|
const content = await fs.readFile(singleSpecPath, 'utf8');
|
|
91
91
|
const spec = yaml.load(content);
|
|
92
92
|
|
|
93
|
-
console.log(chalk.blue(
|
|
93
|
+
console.log(chalk.blue(`Auto-detected single spec: ${singleSpecId}`));
|
|
94
94
|
|
|
95
95
|
return {
|
|
96
96
|
path: singleSpecPath,
|
|
@@ -100,7 +100,7 @@ async function resolveSpec(options = {}) {
|
|
|
100
100
|
}
|
|
101
101
|
} else if (specIds.length > 1) {
|
|
102
102
|
// Multiple specs - require explicit selection with enhanced guidance
|
|
103
|
-
console.error(chalk.red('
|
|
103
|
+
console.error(chalk.red('Multiple specs detected. Please specify which one:'));
|
|
104
104
|
|
|
105
105
|
// Show specs with details
|
|
106
106
|
const specsInfo = [];
|
|
@@ -169,7 +169,7 @@ async function resolveSpec(options = {}) {
|
|
|
169
169
|
return aTypePriority - bTypePriority;
|
|
170
170
|
});
|
|
171
171
|
|
|
172
|
-
console.log(chalk.green('\
|
|
172
|
+
console.log(chalk.green('\nQuick suggestion:'));
|
|
173
173
|
console.log(chalk.gray(` Try: caws <command> --spec-id ${sortedSpecs[0]}`));
|
|
174
174
|
|
|
175
175
|
// Interactive mode suggestion
|
|
@@ -187,7 +187,7 @@ async function resolveSpec(options = {}) {
|
|
|
187
187
|
const spec = yaml.load(content);
|
|
188
188
|
|
|
189
189
|
if (warnLegacy) {
|
|
190
|
-
console.log(chalk.yellow('
|
|
190
|
+
console.log(chalk.yellow('Using legacy working-spec.yaml'));
|
|
191
191
|
console.log(chalk.gray(' For multi-agent workflows, use feature-specific specs:'));
|
|
192
192
|
console.log(chalk.blue(' caws specs create <feature-id>'));
|
|
193
193
|
console.log('');
|
|
@@ -298,7 +298,7 @@ async function interactiveSpecSelection(specIds) {
|
|
|
298
298
|
return new Promise((resolve, reject) => {
|
|
299
299
|
const readline = require('readline');
|
|
300
300
|
|
|
301
|
-
console.log(chalk.blue('\
|
|
301
|
+
console.log(chalk.blue('\nInteractive Spec Selection'));
|
|
302
302
|
console.log(chalk.gray('Select which spec to use:\n'));
|
|
303
303
|
|
|
304
304
|
specIds.forEach((id, index) => {
|
|
@@ -381,7 +381,7 @@ async function checkScopeConflicts(specIds) {
|
|
|
381
381
|
? ` Line ${yamlError.mark.line + 1}, Column ${yamlError.mark.column + 1}\n`
|
|
382
382
|
: '') +
|
|
383
383
|
(yamlError.mark?.snippet ? ` ${yamlError.mark.snippet}\n` : '') +
|
|
384
|
-
|
|
384
|
+
`Fix YAML syntax errors or use 'caws specs create <id>' for proper structure`
|
|
385
385
|
);
|
|
386
386
|
}
|
|
387
387
|
|
|
@@ -498,7 +498,7 @@ async function suggestMigration() {
|
|
|
498
498
|
const status = await checkMultiSpecStatus();
|
|
499
499
|
|
|
500
500
|
if (status.needsMigration) {
|
|
501
|
-
console.log(chalk.yellow('\
|
|
501
|
+
console.log(chalk.yellow('\nMigration Recommended: Single-Spec → Multi-Spec'));
|
|
502
502
|
console.log(chalk.gray(' Your project uses the legacy working-spec.yaml'));
|
|
503
503
|
console.log(chalk.gray(' For multi-agent workflows, migrate to feature-specific specs:\n'));
|
|
504
504
|
console.log(chalk.blue(' 1. caws specs create <feature-id>'));
|
|
@@ -337,17 +337,17 @@ function displayTypeScriptDetection(detection) {
|
|
|
337
337
|
return;
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
console.log(chalk.cyan('\
|
|
341
|
-
console.log(chalk.gray(` tsconfig.json: ${detection.hasTsConfig ? '
|
|
342
|
-
console.log(chalk.gray(` typescript dependency: ${detection.hasTypeScriptDep ? '
|
|
340
|
+
console.log(chalk.cyan('\nTypeScript Project Detected'));
|
|
341
|
+
console.log(chalk.gray(` tsconfig.json: ${detection.hasTsConfig ? '' : ''}`));
|
|
342
|
+
console.log(chalk.gray(` typescript dependency: ${detection.hasTypeScriptDep ? '' : ''}`));
|
|
343
343
|
|
|
344
344
|
if (detection.testFramework.framework !== 'none') {
|
|
345
345
|
console.log(chalk.gray(` Test framework: ${detection.testFramework.framework}`));
|
|
346
|
-
console.log(chalk.gray(` Configured: ${detection.testFramework.isConfigured ? '
|
|
346
|
+
console.log(chalk.gray(` Configured: ${detection.testFramework.isConfigured ? '' : ''}`));
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
if (detection.recommendations.length > 0) {
|
|
350
|
-
console.log(chalk.yellow('\
|
|
350
|
+
console.log(chalk.yellow('\nRecommendations:'));
|
|
351
351
|
detection.recommendations.forEach((rec) => {
|
|
352
352
|
console.log(chalk.yellow(` ${rec}`));
|
|
353
353
|
});
|
|
@@ -127,7 +127,7 @@ function validateAllCawsYamlFiles(projectRoot) {
|
|
|
127
127
|
*/
|
|
128
128
|
function formatYamlError(error, filePath) {
|
|
129
129
|
const relativePath = path.relative(process.cwd(), filePath);
|
|
130
|
-
let message =
|
|
130
|
+
let message = `Invalid YAML in ${relativePath}\n`;
|
|
131
131
|
message += ` Error: ${error.error}\n`;
|
|
132
132
|
|
|
133
133
|
if (error.line !== null) {
|
|
@@ -608,7 +608,7 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
608
608
|
|
|
609
609
|
if (autoFix && fixes.length > 0) {
|
|
610
610
|
if (dryRun) {
|
|
611
|
-
console.log('
|
|
611
|
+
console.log('Auto-fix preview (dry-run mode):');
|
|
612
612
|
for (const fix of fixes) {
|
|
613
613
|
console.log(` [WOULD FIX] ${fix.field}`);
|
|
614
614
|
console.log(` Description: ${fix.description}`);
|
|
@@ -619,7 +619,7 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
619
619
|
console.log('');
|
|
620
620
|
}
|
|
621
621
|
} else {
|
|
622
|
-
console.log('
|
|
622
|
+
console.log('Applying auto-fixes...');
|
|
623
623
|
for (const fix of fixes) {
|
|
624
624
|
try {
|
|
625
625
|
const pathParts = fix.field.split('.');
|
|
@@ -630,10 +630,10 @@ function validateWorkingSpecWithSuggestions(spec, options = {}) {
|
|
|
630
630
|
}
|
|
631
631
|
current[pathParts[pathParts.length - 1]] = fix.value;
|
|
632
632
|
appliedFixes.push(fix);
|
|
633
|
-
console.log(`
|
|
633
|
+
console.log(` Fixed ${fix.field}`);
|
|
634
634
|
console.log(` ${fix.description}`);
|
|
635
635
|
} catch (error) {
|
|
636
|
-
console.warn(`
|
|
636
|
+
console.warn(` Failed to apply fix for ${fix.field}: ${error.message}`);
|
|
637
637
|
}
|
|
638
638
|
}
|
|
639
639
|
}
|