@hatem427/code-guard-ci 3.6.3 → 3.6.4
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 +34 -2
- package/dist/scripts/cli.js +114 -2
- package/dist/scripts/cli.js.map +1 -1
- package/dist/scripts/config-generators/ai-config-generator.d.ts.map +1 -1
- package/dist/scripts/config-generators/ai-config-generator.js +2 -11
- package/dist/scripts/config-generators/ai-config-generator.js.map +1 -1
- package/dist/scripts/config-generators/eslint-generator.d.ts.map +1 -1
- package/dist/scripts/config-generators/eslint-generator.js +20 -0
- package/dist/scripts/config-generators/eslint-generator.js.map +1 -1
- package/dist/scripts/config-generators/frameworks/nextjs.d.ts.map +1 -1
- package/dist/scripts/config-generators/frameworks/nextjs.js +308 -61
- package/dist/scripts/config-generators/frameworks/nextjs.js.map +1 -1
- package/dist/scripts/utils/project-detector.d.ts +2 -0
- package/dist/scripts/utils/project-detector.d.ts.map +1 -1
- package/dist/scripts/utils/project-detector.js +42 -1
- package/dist/scripts/utils/project-detector.js.map +1 -1
- package/package.json +1 -1
- package/scripts/cli.ts +120 -2
- package/scripts/config-generators/ai-config-generator.ts +2 -11
- package/scripts/config-generators/eslint-generator.ts +22 -0
- package/scripts/config-generators/frameworks/nextjs.ts +309 -61
- package/scripts/utils/project-detector.ts +48 -1
|
@@ -106,6 +106,45 @@ function detectMonorepo(dir, pkg) {
|
|
|
106
106
|
return 'pnpm-workspaces'; // npm/yarn workspaces
|
|
107
107
|
return 'none';
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Detect app-level ESLint config files in Nx projects.
|
|
111
|
+
* These override the root-level ESLint config.
|
|
112
|
+
*/
|
|
113
|
+
function detectNxAppEslintConfigs(dir, monorepo) {
|
|
114
|
+
if (monorepo !== 'nx')
|
|
115
|
+
return [];
|
|
116
|
+
const eslintFiles = [
|
|
117
|
+
'.eslintrc', '.eslintrc.js', '.eslintrc.cjs', '.eslintrc.json', '.eslintrc.yml',
|
|
118
|
+
'eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs'
|
|
119
|
+
];
|
|
120
|
+
const found = [];
|
|
121
|
+
// Scan apps/ and libs/ directories (standard Nx layout)
|
|
122
|
+
const searchDirs = ['apps', 'libs', 'packages'];
|
|
123
|
+
for (const sub of searchDirs) {
|
|
124
|
+
const subDir = path.join(dir, sub);
|
|
125
|
+
if (!fs.existsSync(subDir) || !fs.statSync(subDir).isDirectory())
|
|
126
|
+
continue;
|
|
127
|
+
let entries;
|
|
128
|
+
try {
|
|
129
|
+
entries = fs.readdirSync(subDir);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
for (const entry of entries) {
|
|
135
|
+
const projectDir = path.join(subDir, entry);
|
|
136
|
+
if (!fs.statSync(projectDir).isDirectory())
|
|
137
|
+
continue;
|
|
138
|
+
for (const eslintFile of eslintFiles) {
|
|
139
|
+
const eslintPath = path.join(projectDir, eslintFile);
|
|
140
|
+
if (fs.existsSync(eslintPath)) {
|
|
141
|
+
found.push(path.relative(dir, eslintPath));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return found;
|
|
147
|
+
}
|
|
109
148
|
/**
|
|
110
149
|
* Detect existing tooling already configured in the project.
|
|
111
150
|
*/
|
|
@@ -171,6 +210,7 @@ function detectProject(startDir = process.cwd()) {
|
|
|
171
210
|
hasClaudeConfig: false, hasGeminiConfig: false,
|
|
172
211
|
hasWindsurfConfig: false, hasJunieConfig: false,
|
|
173
212
|
},
|
|
213
|
+
nxAppEslintConfigs: [],
|
|
174
214
|
};
|
|
175
215
|
if (!result)
|
|
176
216
|
return defaults;
|
|
@@ -179,7 +219,8 @@ function detectProject(startDir = process.cwd()) {
|
|
|
179
219
|
const packageManager = detectPackageManager(dir);
|
|
180
220
|
const usesTypeScript = hasDep(pkg, 'typescript') || fs.existsSync(path.join(dir, 'tsconfig.json'));
|
|
181
221
|
const existingTooling = detectExistingTooling(dir, pkg);
|
|
182
|
-
const
|
|
222
|
+
const nxAppEslintConfigs = detectNxAppEslintConfigs(dir, monorepo);
|
|
223
|
+
const base = { rootDir: dir, packageJson: pkg, monorepo, usesTypeScript, packageManager, existingTooling, nxAppEslintConfigs };
|
|
183
224
|
// Nuxt check (must come before Vue — Nuxt depends on Vue)
|
|
184
225
|
if (hasDep(pkg, 'nuxt')) {
|
|
185
226
|
return { ...base, type: 'nuxt', label: 'Nuxt' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-detector.js","sourceRoot":"","sources":["../../../scripts/utils/project-detector.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"project-detector.js","sourceRoot":"","sources":["../../../scripts/utils/project-detector.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hatem427/code-guard-ci",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.4",
|
|
4
4
|
"description": "Production-ready TypeScript tooling to enforce PR & coding guidelines for Angular, React, NextJS, NestJS, Fastify, Hono, and Node.js projects.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "dist/scripts/cli.js",
|
package/scripts/cli.ts
CHANGED
|
@@ -165,6 +165,12 @@ function initProject(): void {
|
|
|
165
165
|
console.log(` ${c.green('✓')} TypeScript: ${project.usesTypeScript ? c.green('Yes') : c.yellow('No')}`);
|
|
166
166
|
console.log(` ${c.green('✓')} Package Manager: ${c.bold(project.packageManager)}`);
|
|
167
167
|
console.log(` ${c.green('✓')} Monorepo: ${project.monorepo === 'none' ? c.dim('No') : c.bold(project.monorepo)}`);
|
|
168
|
+
if (project.monorepo === 'nx' && project.nxAppEslintConfigs.length > 0) {
|
|
169
|
+
console.log(` ${c.yellow('⚠')} Nx app-level ESLint configs detected (will be consolidated):`);
|
|
170
|
+
for (const cfg of project.nxAppEslintConfigs) {
|
|
171
|
+
console.log(` ${c.dim('•')} ${cfg}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
168
174
|
console.log('');
|
|
169
175
|
|
|
170
176
|
if (isDryRun) {
|
|
@@ -215,6 +221,16 @@ function initProject(): void {
|
|
|
215
221
|
recordCreatedFile(manifest, eslintFile);
|
|
216
222
|
}
|
|
217
223
|
|
|
224
|
+
// Track Nx app-level ESLint backups in manifest
|
|
225
|
+
if (project.monorepo === 'nx' && project.nxAppEslintConfigs.length > 0) {
|
|
226
|
+
for (const relPath of project.nxAppEslintConfigs) {
|
|
227
|
+
const backupRelPath = relPath + '.backup';
|
|
228
|
+
if (fs.existsSync(path.join(cwd, backupRelPath))) {
|
|
229
|
+
recordBackup(manifest, relPath, backupRelPath);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
218
234
|
console.log(` ${c.green('✓')} Created eslint.config.mjs`);
|
|
219
235
|
console.log(` ${c.green('✓')} Created .eslintignore\n`);
|
|
220
236
|
} catch (error: any) {
|
|
@@ -352,6 +368,39 @@ function initProject(): void {
|
|
|
352
368
|
console.warn(c.yellow(` ⚠️ VS Code settings generation failed: ${error.message}\n`));
|
|
353
369
|
}
|
|
354
370
|
|
|
371
|
+
// ── Step 8b: Generate MCP Configs (Angular projects) ──────────────────────
|
|
372
|
+
if (project.type === 'angular') {
|
|
373
|
+
console.log(c.bold('🔌 Step 8b: Creating MCP configs (Angular CLI server)...'));
|
|
374
|
+
try {
|
|
375
|
+
const { generateMCPConfigs, getMCPFileTargets } = requireGenerator('mcp-config-generator');
|
|
376
|
+
|
|
377
|
+
// Snapshot existing state before generation
|
|
378
|
+
const mcpTargets = getMCPFileTargets();
|
|
379
|
+
const mcpExisted: Record<string, boolean> = {};
|
|
380
|
+
for (const t of mcpTargets) {
|
|
381
|
+
const relPath = `${t.directory}/${t.fileName}`;
|
|
382
|
+
mcpExisted[relPath] = fs.existsSync(path.join(cwd, relPath));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const created = generateMCPConfigs(project);
|
|
386
|
+
|
|
387
|
+
for (const relPath of created) {
|
|
388
|
+
if (mcpExisted[relPath]) {
|
|
389
|
+
recordModifiedFile(manifest, relPath, 'mcp');
|
|
390
|
+
if (fs.existsSync(path.join(cwd, relPath + '.backup'))) {
|
|
391
|
+
recordBackup(manifest, relPath, relPath + '.backup');
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
recordCreatedFile(manifest, relPath);
|
|
395
|
+
}
|
|
396
|
+
console.log(` ${c.green('✓')} ${relPath}`);
|
|
397
|
+
}
|
|
398
|
+
console.log('');
|
|
399
|
+
} catch (error: any) {
|
|
400
|
+
console.warn(c.yellow(` ⚠️ MCP config generation failed: ${error.message}\n`));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
355
404
|
// ── Step 9: Setup Git Hooks ───────────────────────────────────────────────
|
|
356
405
|
if (!skipHooks) {
|
|
357
406
|
console.log(c.bold('🐶 Step 9: Setting up Git hooks...'));
|
|
@@ -569,7 +618,39 @@ function ensureCodeGuardianGitignore(cwd: string): void {
|
|
|
569
618
|
);
|
|
570
619
|
}
|
|
571
620
|
|
|
572
|
-
// ── 3. Ensure
|
|
621
|
+
// ── 3. Ensure generated dirs/files are in .gitignore ─────────────────────
|
|
622
|
+
const generatedEntries = [
|
|
623
|
+
'.claude',
|
|
624
|
+
'.cursor',
|
|
625
|
+
'.gemini',
|
|
626
|
+
'.github',
|
|
627
|
+
'.junie',
|
|
628
|
+
'.windsurf',
|
|
629
|
+
'AGENTS.md',
|
|
630
|
+
'docs',
|
|
631
|
+
'config',
|
|
632
|
+
'templates',
|
|
633
|
+
'.code-guardian',
|
|
634
|
+
];
|
|
635
|
+
|
|
636
|
+
// Check each entry as a standalone line (not substring) to avoid false positives
|
|
637
|
+
const contentLines = new Set(content.split('\n').map(l => l.trim()));
|
|
638
|
+
const entriesToAdd = generatedEntries.filter(e => !contentLines.has(e) && !contentLines.has(e + '/'));
|
|
639
|
+
if (entriesToAdd.length > 0) {
|
|
640
|
+
content += [
|
|
641
|
+
'',
|
|
642
|
+
'# Code Guardian — generated configs and directories',
|
|
643
|
+
...entriesToAdd,
|
|
644
|
+
'',
|
|
645
|
+
].join('\n');
|
|
646
|
+
changed = true;
|
|
647
|
+
messages.push(
|
|
648
|
+
` ${c.green('✓')} .gitignore: added generated dirs/files:\n` +
|
|
649
|
+
entriesToAdd.map(e => ` ${c.dim(e)}`).join('\n')
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// ── 4. Ensure tracked files are negated if the dir is still pattern-ignored
|
|
573
654
|
if (!broadMatch) {
|
|
574
655
|
// Dir wasn't broadly ignored — check if individual tracked files are ignored
|
|
575
656
|
// and add negations for any that are
|
|
@@ -643,7 +724,8 @@ function setupGitHooks(cwd: string): void {
|
|
|
643
724
|
echo "🛡️ Code Guardian — Pre-commit checks..."
|
|
644
725
|
|
|
645
726
|
# Skip all checks when BYPASS_RULES is set
|
|
646
|
-
|
|
727
|
+
BYPASS_LOWER=$(echo "$BYPASS_RULES" | tr '[:upper:]' '[:lower:]')
|
|
728
|
+
if [ "$BYPASS_LOWER" = "true" ] || [ "$BYPASS_LOWER" = "1" ]; then
|
|
647
729
|
echo "⚡ BYPASS_RULES detected — skipping checks."
|
|
648
730
|
exit 0
|
|
649
731
|
fi
|
|
@@ -775,6 +857,14 @@ function updatePackageJson(cwd: string, project: any, manifest?: any): void {
|
|
|
775
857
|
setScript('format', 'prettier --write .');
|
|
776
858
|
setScript('format:check', 'prettier --check .');
|
|
777
859
|
|
|
860
|
+
// Test scripts — add only if not already defined (prevents test:coverage errors in pre-commit)
|
|
861
|
+
if (!packageJson.scripts['test']) {
|
|
862
|
+
setScript('test', 'echo "No test framework configured — add your test runner here"');
|
|
863
|
+
}
|
|
864
|
+
if (!packageJson.scripts['test:coverage']) {
|
|
865
|
+
setScript('test:coverage', 'echo "No test coverage configured — add your test runner here"');
|
|
866
|
+
}
|
|
867
|
+
|
|
778
868
|
// Security scripts
|
|
779
869
|
setScript('set-bypass-password', `node node_modules/${packageName}/dist/scripts/set-bypass-password.js`);
|
|
780
870
|
setScript('set-admin-password', `node node_modules/${packageName}/dist/scripts/set-admin-password.js`);
|
|
@@ -1384,6 +1474,34 @@ async function uninstallCodeGuard(): Promise<void> {
|
|
|
1384
1474
|
}
|
|
1385
1475
|
}
|
|
1386
1476
|
|
|
1477
|
+
// Scan Nx app/lib directories for ESLint backup files
|
|
1478
|
+
const eslintBackupNames = [
|
|
1479
|
+
'.eslintrc.backup', '.eslintrc.js.backup', '.eslintrc.cjs.backup', '.eslintrc.json.backup',
|
|
1480
|
+
'.eslintrc.yml.backup', 'eslint.config.js.backup', 'eslint.config.mjs.backup', 'eslint.config.cjs.backup',
|
|
1481
|
+
];
|
|
1482
|
+
const nxSearchDirs = ['apps', 'libs', 'packages'];
|
|
1483
|
+
for (const sub of nxSearchDirs) {
|
|
1484
|
+
const subDir = path.join(cwd, sub);
|
|
1485
|
+
if (!fs.existsSync(subDir) || !fs.statSync(subDir).isDirectory()) continue;
|
|
1486
|
+
try {
|
|
1487
|
+
const entries = fs.readdirSync(subDir);
|
|
1488
|
+
for (const entry of entries) {
|
|
1489
|
+
const projectDir = path.join(subDir, entry);
|
|
1490
|
+
if (!fs.statSync(projectDir).isDirectory()) continue;
|
|
1491
|
+
for (const backupName of eslintBackupNames) {
|
|
1492
|
+
const backupAbs = path.join(projectDir, backupName);
|
|
1493
|
+
if (fs.existsSync(backupAbs)) {
|
|
1494
|
+
const relBackup = path.relative(cwd, backupAbs);
|
|
1495
|
+
const relOriginal = relBackup.replace(/\.backup$/, '');
|
|
1496
|
+
if (!backupsToRestore.some(b => b.backup === relBackup)) {
|
|
1497
|
+
backupsToRestore.push({ original: relOriginal, backup: relBackup });
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
} catch {}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1387
1505
|
if (existingFiles.length === 0 && existingDirs.length === 0 && aiActions.length === 0 && backupsToRestore.length === 0) {
|
|
1388
1506
|
console.log(c.yellow('⚠️ No Code Guardian files found to remove.\n'));
|
|
1389
1507
|
return;
|
|
@@ -24,6 +24,7 @@ import * as path from 'path';
|
|
|
24
24
|
import { spawnSync } from 'child_process';
|
|
25
25
|
import { DetectionResult, ProjectType } from '../utils/project-detector';
|
|
26
26
|
import { AIConfigRegistry, AIConfigTemplate, defaultRegistry } from '../utils/ai-config-registry';
|
|
27
|
+
import { nextjsGuidelines } from './frameworks';
|
|
27
28
|
|
|
28
29
|
export { AIConfigRegistry, defaultRegistry } from '../utils/ai-config-registry';
|
|
29
30
|
|
|
@@ -752,17 +753,7 @@ function getFrameworkGuidelines(type: ProjectType): string {
|
|
|
752
753
|
- Every \`<button>\` must have a \`type\` attribute`;
|
|
753
754
|
|
|
754
755
|
case 'nextjs':
|
|
755
|
-
return
|
|
756
|
-
- Use App Router (app/) over Pages Router (pages/)
|
|
757
|
-
- Mark client components with \`"use client"\` at the top
|
|
758
|
-
- Server Components are the default — keep them server-side when possible
|
|
759
|
-
- Use \`next/image\` instead of \`<img>\`
|
|
760
|
-
- Use \`next/link\` instead of \`<a>\`
|
|
761
|
-
- Export \`metadata\` object from page/layout files for SEO
|
|
762
|
-
- Use Route Handlers (app/api/) for API endpoints
|
|
763
|
-
- API routes must have try/catch error handling
|
|
764
|
-
- Use \`loading.tsx\` and \`error.tsx\` for loading/error states
|
|
765
|
-
- Prefer Server Actions for mutations`;
|
|
756
|
+
return nextjsGuidelines();
|
|
766
757
|
|
|
767
758
|
case 'angular':
|
|
768
759
|
return `## Angular Guidelines
|
|
@@ -23,10 +23,32 @@ export function generateEslintConfig(project: DetectionResult): void {
|
|
|
23
23
|
backupExistingConfig(project.rootDir);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// In Nx projects, backup app-level ESLint configs that override the root config
|
|
27
|
+
if (project.monorepo === 'nx' && project.nxAppEslintConfigs.length > 0) {
|
|
28
|
+
for (const relPath of project.nxAppEslintConfigs) {
|
|
29
|
+
const absPath = path.join(project.rootDir, relPath);
|
|
30
|
+
if (fs.existsSync(absPath)) {
|
|
31
|
+
fs.copyFileSync(absPath, absPath + '.backup');
|
|
32
|
+
console.log(` ⚠️ Backed up app-level ESLint config: ${relPath} → ${relPath}.backup`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
const isNx = project.monorepo === 'nx';
|
|
27
38
|
const config = isNx ? buildNxFlatConfig(project) : buildFlatConfig(project);
|
|
28
39
|
fs.writeFileSync(configPath, config);
|
|
29
40
|
|
|
41
|
+
// In Nx projects, remove app-level ESLint configs so they don't override root
|
|
42
|
+
if (project.monorepo === 'nx' && project.nxAppEslintConfigs.length > 0) {
|
|
43
|
+
for (const relPath of project.nxAppEslintConfigs) {
|
|
44
|
+
const absPath = path.join(project.rootDir, relPath);
|
|
45
|
+
if (fs.existsSync(absPath)) {
|
|
46
|
+
fs.unlinkSync(absPath);
|
|
47
|
+
console.log(` ✓ Removed app-level ESLint config: ${relPath} (root config applies)`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
30
52
|
// No need for .eslintignore — flat config uses ignores property
|
|
31
53
|
// Clean up old .eslintignore if it exists
|
|
32
54
|
const ignorePath = path.join(project.rootDir, '.eslintignore');
|