autoworkflow 1.1.0 → 2.0.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/bin/cli.js DELETED
@@ -1,299 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * autoworkflow - CLI
4
- *
5
- * Usage:
6
- * npx autoworkflow run Run all checks (with fix loop)
7
- * npx autoworkflow list List all rules
8
- * npx autoworkflow check <id> Run specific rule
9
- * npx autoworkflow commit-msg Validate commit message
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
- const { execSync } = require('child_process');
15
-
16
- // Colors
17
- const c = {
18
- reset: '\x1b[0m',
19
- red: '\x1b[31m',
20
- green: '\x1b[32m',
21
- yellow: '\x1b[33m',
22
- blue: '\x1b[34m',
23
- cyan: '\x1b[36m',
24
- };
25
-
26
- const log = (color, msg) => console.log(`${color}${msg}${c.reset}`);
27
-
28
- // Find config file
29
- function findConfig() {
30
- const configPath = path.join(process.cwd(), 'enforce.config.json');
31
- if (fs.existsSync(configPath)) {
32
- return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
33
- }
34
- // Return defaults
35
- return {
36
- rules: {
37
- 'no-todo-comments': { enabled: true, blocking: true },
38
- 'no-console-logs': { enabled: true, blocking: true },
39
- 'typescript': { enabled: true, blocking: true },
40
- 'eslint': { enabled: true, blocking: true, autoFix: true },
41
- 'circular-deps': { enabled: true, blocking: true },
42
- },
43
- fixLoop: { enabled: true, maxAttempts: 5, autoFixRules: ['eslint'] },
44
- };
45
- }
46
-
47
- // Rule implementations
48
- const rules = {
49
- 'no-todo-comments': {
50
- name: 'No TODO/FIXME Comments',
51
- check: (config) => {
52
- try {
53
- const patterns = config.patterns || ['TODO', 'FIXME', 'XXX', 'HACK'];
54
- const output = execSync(
55
- `grep -rn "${patterns.join('\\|')}" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null | grep -v node_modules | grep -v ".git" || true`,
56
- { encoding: 'utf-8' }
57
- ).trim();
58
- const matches = output ? output.split('\n').filter(Boolean) : [];
59
- return { passed: matches.length === 0, details: matches.slice(0, 5) };
60
- } catch {
61
- return { passed: true, details: [] };
62
- }
63
- },
64
- },
65
-
66
- 'no-console-logs': {
67
- name: 'No Console Logs',
68
- check: (config) => {
69
- try {
70
- const output = execSync(
71
- 'grep -rn "console\\.\\(log\\|debug\\|info\\)" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null | grep -v node_modules | grep -v ".git" | grep -v "eslint-disable" || true',
72
- { encoding: 'utf-8' }
73
- ).trim();
74
- const matches = output ? output.split('\n').filter(Boolean) : [];
75
- return { passed: matches.length === 0, details: matches.slice(0, 5) };
76
- } catch {
77
- return { passed: true, details: [] };
78
- }
79
- },
80
- },
81
-
82
- 'typescript': {
83
- name: 'TypeScript',
84
- check: (config) => {
85
- try {
86
- const cmd = config.command || 'npx tsc --noEmit';
87
- execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' });
88
- return { passed: true, details: [] };
89
- } catch (error) {
90
- const output = error.stdout || error.message || '';
91
- const errors = output.split('\n').filter(l => l.includes('error')).slice(0, 5);
92
- return { passed: false, details: errors };
93
- }
94
- },
95
- },
96
-
97
- 'eslint': {
98
- name: 'ESLint',
99
- check: (config) => {
100
- try {
101
- const cmd = config.command || 'npx eslint . --max-warnings 0';
102
- execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' });
103
- return { passed: true, details: [] };
104
- } catch (error) {
105
- const output = error.stdout || error.message || '';
106
- const errors = output.split('\n').filter(l => l.includes('error') || l.includes('warning')).slice(0, 5);
107
- return { passed: false, details: errors };
108
- }
109
- },
110
- fix: (config) => {
111
- try {
112
- const cmd = config.fixCommand || 'npx eslint . --fix';
113
- execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' });
114
- return true;
115
- } catch {
116
- return false;
117
- }
118
- },
119
- },
120
-
121
- 'circular-deps': {
122
- name: 'Circular Dependencies',
123
- check: (config) => {
124
- try {
125
- const paths = config.paths || ['src/'];
126
- const output = execSync(
127
- `npx madge --circular --extensions ts,tsx,js,jsx ${paths.join(' ')} 2>&1`,
128
- { encoding: 'utf-8' }
129
- );
130
- const hasCircular = output.includes('Found');
131
- return { passed: !hasCircular, details: hasCircular ? output.split('\n').slice(0, 5) : [] };
132
- } catch {
133
- return { passed: true, details: [] };
134
- }
135
- },
136
- },
137
- };
138
-
139
- // Run all checks with fix loop
140
- function runChecks(config) {
141
- const fixLoop = config.fixLoop || { enabled: true, maxAttempts: 5 };
142
- let attempt = 0;
143
- let results = [];
144
- const fixedRules = [];
145
-
146
- log(c.blue, '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
147
- log(c.blue, '🔒 autoworkflow');
148
- log(c.blue, '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
149
- console.log('');
150
-
151
- while (attempt < fixLoop.maxAttempts) {
152
- attempt++;
153
-
154
- if (attempt > 1) {
155
- log(c.cyan, `\n🔄 Fix Loop - Attempt ${attempt}/${fixLoop.maxAttempts}\n`);
156
- }
157
-
158
- results = [];
159
- let index = 0;
160
- const ruleIds = Object.keys(config.rules).filter(id => config.rules[id]?.enabled);
161
-
162
- for (const ruleId of ruleIds) {
163
- const rule = rules[ruleId];
164
- const ruleConfig = config.rules[ruleId];
165
- if (!rule) continue;
166
-
167
- index++;
168
- const result = rule.check(ruleConfig);
169
- const status = result.passed ? c.green + '✅' : (ruleConfig.blocking ? c.red + '❌' : c.yellow + '⚠️');
170
-
171
- console.log(`${c.yellow}[${index}/${ruleIds.length}]${c.reset} ${rule.name}... ${status}${c.reset}`);
172
-
173
- if (!result.passed && result.details.length > 0) {
174
- result.details.forEach(d => console.log(` ${d}`));
175
- }
176
-
177
- results.push({ ruleId, ...result, blocking: ruleConfig.blocking, fixable: !!rule.fix && ruleConfig.autoFix });
178
- }
179
-
180
- // Check if we need to fix
181
- const failedFixable = results.filter(
182
- r => !r.passed && r.fixable && (fixLoop.autoFixRules || []).includes(r.ruleId)
183
- );
184
-
185
- if (failedFixable.length === 0) break;
186
-
187
- // Attempt fixes
188
- log(c.cyan, '\n🔧 Attempting auto-fix...');
189
- for (const result of failedFixable) {
190
- const rule = rules[result.ruleId];
191
- const ruleConfig = config.rules[result.ruleId];
192
- if (rule?.fix?.(ruleConfig)) {
193
- log(c.green, ` ✅ Fixed: ${rule.name}`);
194
- if (!fixedRules.includes(result.ruleId)) fixedRules.push(result.ruleId);
195
- }
196
- }
197
- }
198
-
199
- // Summary
200
- const failed = results.filter(r => !r.passed && r.blocking).length;
201
-
202
- console.log('');
203
- log(c.blue, '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
204
-
205
- if (failed > 0) {
206
- log(c.red, '⛔ COMMIT BLOCKED');
207
- log(c.red, ` ${failed} check(s) failed. Fix issues and try again.`);
208
- process.exit(1);
209
- } else {
210
- log(c.green, '✅ ALL CHECKS PASSED');
211
- if (fixedRules.length > 0) {
212
- log(c.green, ` Auto-fixed: ${fixedRules.join(', ')}`);
213
- }
214
- }
215
- console.log('');
216
- }
217
-
218
- // Validate commit message
219
- function validateCommitMessage(msgFile) {
220
- const config = findConfig();
221
- const commitConfig = config.commitMessage || {};
222
-
223
- if (!commitConfig.enabled) return;
224
-
225
- const message = fs.readFileSync(msgFile, 'utf-8').trim().split('\n')[0];
226
- const pattern = commitConfig.pattern || '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\\(.+\\))?: .{1,72}$';
227
-
228
- if (!new RegExp(pattern).test(message)) {
229
- log(c.red, '');
230
- log(c.red, '⛔ Invalid commit message format!');
231
- log(c.red, '');
232
- log(c.yellow, 'Expected: type(scope): description');
233
- log(c.yellow, 'Examples:');
234
- console.log(' feat: add user authentication');
235
- console.log(' fix(auth): resolve login bug');
236
- console.log(' docs: update readme');
237
- log(c.red, '');
238
- log(c.red, `Your message: "${message}"`);
239
- log(c.red, '');
240
- process.exit(1);
241
- }
242
- }
243
-
244
- // List rules
245
- function listRules(config) {
246
- log(c.blue, 'Available rules:');
247
- console.log('');
248
-
249
- for (const [id, ruleConfig] of Object.entries(config.rules)) {
250
- const rule = rules[id];
251
- const status = ruleConfig.enabled ? c.green + '✅' : c.red + '❌';
252
- const blocking = ruleConfig.blocking ? '🔒' : '⚠️';
253
- const name = rule?.name || id;
254
- console.log(` ${status}${c.reset} ${blocking} ${name} (${id})`);
255
- }
256
- console.log('');
257
- }
258
-
259
- // Main
260
- function main() {
261
- const args = process.argv.slice(2);
262
- const command = args[0] || 'run';
263
- const config = findConfig();
264
-
265
- switch (command) {
266
- case 'run':
267
- runChecks(config);
268
- break;
269
-
270
- case 'commit-msg':
271
- const msgFile = args[1];
272
- if (msgFile) validateCommitMessage(msgFile);
273
- break;
274
-
275
- case 'list':
276
- listRules(config);
277
- break;
278
-
279
- case '--help':
280
- case '-h':
281
- console.log('');
282
- log(c.blue, 'autoworkflow');
283
- console.log('');
284
- console.log('Usage:');
285
- console.log(' npx autoworkflow run Run all checks');
286
- console.log(' npx autoworkflow list List all rules');
287
- console.log(' npx autoworkflow commit-msg Validate commit message');
288
- console.log(' npx autoworkflow --help Show this help');
289
- console.log('');
290
- console.log('Configuration: enforce.config.json');
291
- console.log('');
292
- break;
293
-
294
- default:
295
- runChecks(config);
296
- }
297
- }
298
-
299
- main();
package/lib/index.js DELETED
@@ -1,9 +0,0 @@
1
- /**
2
- * autoworkflow
3
- *
4
- * Automatic code quality enforcement with fix loops.
5
- */
6
-
7
- module.exports = {
8
- version: '1.1.0',
9
- };