@hatem427/code-guard-ci 2.2.2 → 2.2.5
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/scripts/cli.js +204 -156
- package/dist/scripts/cli.js.map +1 -1
- package/dist/scripts/config-generators/mcp-config-generator.d.ts.map +1 -1
- package/dist/scripts/config-generators/mcp-config-generator.js +23 -6
- package/dist/scripts/config-generators/mcp-config-generator.js.map +1 -1
- package/dist/scripts/config-generators/vscode-generator.d.ts.map +1 -1
- package/dist/scripts/config-generators/vscode-generator.js +98 -28
- package/dist/scripts/config-generators/vscode-generator.js.map +1 -1
- package/package.json +1 -1
- package/scripts/cli.ts +229 -164
- package/scripts/config-generators/mcp-config-generator.ts +21 -7
- package/scripts/config-generators/vscode-generator.ts +94 -40
package/dist/scripts/cli.js
CHANGED
|
@@ -159,6 +159,22 @@ function initProject() {
|
|
|
159
159
|
const isDryRun = hasFlag('dry-run');
|
|
160
160
|
const skipAI = hasFlag('skip-ai');
|
|
161
161
|
const skipHooks = hasFlag('skip-hooks');
|
|
162
|
+
// ── Manifest: track all files we might create/modify ─────────────────────
|
|
163
|
+
// Snapshot which files exist BEFORE init so uninstall knows what we created
|
|
164
|
+
const trackedPaths = [
|
|
165
|
+
// Config files
|
|
166
|
+
'eslint.config.mjs', '.prettierrc.json', '.prettierignore', '.eslintignore',
|
|
167
|
+
'tsconfig.strict.json', 'tsconfig.json', '.lintstagedrc.json',
|
|
168
|
+
'.editorconfig', 'commitlint.config.js', 'lint-staged.config.js',
|
|
169
|
+
// VS Code
|
|
170
|
+
'.vscode/settings.json', '.vscode/extensions.json',
|
|
171
|
+
'.vscode/tasks.json', '.vscode/launch.json', '.vscode/mcp.json',
|
|
172
|
+
// MCP
|
|
173
|
+
'.cursor/mcp.json', '.gemini/settings.json',
|
|
174
|
+
// Husky
|
|
175
|
+
'.husky/pre-commit',
|
|
176
|
+
];
|
|
177
|
+
const preExisting = new Set(trackedPaths.filter(f => fs.existsSync(path.join(cwd, f))));
|
|
162
178
|
// ── Step 1: Detect Framework ────────────────────────────────────────────
|
|
163
179
|
console.log(c.bold('📡 Step 1: Detecting project...'));
|
|
164
180
|
// Dynamic import (handles both dev and built)
|
|
@@ -352,6 +368,53 @@ function initProject() {
|
|
|
352
368
|
console.log(c.bold('📁 Step 14: Copying Code Guardian rules and templates...'));
|
|
353
369
|
copyCodeGuardianFiles(cwd);
|
|
354
370
|
console.log('');
|
|
371
|
+
// ── Write manifest: record which files Code Guardian created ──────────────
|
|
372
|
+
try {
|
|
373
|
+
const manifestDir = path.join(cwd, '.code-guardian');
|
|
374
|
+
if (!fs.existsSync(manifestDir)) {
|
|
375
|
+
fs.mkdirSync(manifestDir, { recursive: true });
|
|
376
|
+
}
|
|
377
|
+
// Files newly created by Code Guardian (didn't exist before init)
|
|
378
|
+
const createdFiles = trackedPaths.filter(f => !preExisting.has(f) && fs.existsSync(path.join(cwd, f)));
|
|
379
|
+
// Files that existed before and were backed up / overwritten
|
|
380
|
+
const backedUpFiles = trackedPaths.filter(f => preExisting.has(f) && (fs.existsSync(path.join(cwd, f + '.backup')) ||
|
|
381
|
+
// ESLint: old config names may have been backed up
|
|
382
|
+
(f === 'eslint.config.mjs' && [
|
|
383
|
+
'.eslintrc.backup', '.eslintrc.js.backup', '.eslintrc.cjs.backup',
|
|
384
|
+
'.eslintrc.json.backup', '.eslintrc.yml.backup',
|
|
385
|
+
'eslint.config.js.backup', 'eslint.config.mjs.backup', 'eslint.config.cjs.backup',
|
|
386
|
+
].some(b => fs.existsSync(path.join(cwd, b))))));
|
|
387
|
+
// Husky: track if we created or appended
|
|
388
|
+
const huskyAction = !skipHooks && fs.existsSync(path.join(cwd, '.husky/pre-commit'))
|
|
389
|
+
? (preExisting.has('.husky/pre-commit') ? 'appended' : 'created')
|
|
390
|
+
: 'skipped';
|
|
391
|
+
// AI configs: track via registry
|
|
392
|
+
const aiFiles = [];
|
|
393
|
+
try {
|
|
394
|
+
const { defaultRegistry: reg } = requireUtil('ai-config-registry');
|
|
395
|
+
for (const t of reg.getAll()) {
|
|
396
|
+
const rel = t.directory ? `${t.directory}/${t.fileName}` : t.fileName;
|
|
397
|
+
const full = path.join(cwd, rel);
|
|
398
|
+
if (fs.existsSync(full)) {
|
|
399
|
+
aiFiles.push(rel);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
catch { }
|
|
404
|
+
const manifest = {
|
|
405
|
+
version: VERSION,
|
|
406
|
+
timestamp: new Date().toISOString(),
|
|
407
|
+
createdFiles,
|
|
408
|
+
backedUpFiles,
|
|
409
|
+
huskyAction,
|
|
410
|
+
aiFiles,
|
|
411
|
+
directories: ['config', 'templates', 'docs', '.code-guardian'],
|
|
412
|
+
};
|
|
413
|
+
fs.writeFileSync(path.join(manifestDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
// Non-critical — uninstall will fall back to heuristics
|
|
417
|
+
}
|
|
355
418
|
// ── Done! ─────────────────────────────────────────────────────────────────
|
|
356
419
|
console.log(c.bold(c.green('═══════════════════════════════════════════════════════════')));
|
|
357
420
|
console.log(c.bold(c.green(' ✅ Code Guardian initialized successfully!')));
|
|
@@ -901,61 +964,75 @@ async function uninstallCodeGuard() {
|
|
|
901
964
|
showBanner();
|
|
902
965
|
console.log(c.bold('🗑️ Code Guardian Uninstall\n'));
|
|
903
966
|
const cwd = process.cwd();
|
|
904
|
-
|
|
905
|
-
const
|
|
967
|
+
let manifest = null;
|
|
968
|
+
const manifestPath = path.join(cwd, '.code-guardian', 'manifest.json');
|
|
969
|
+
if (fs.existsSync(manifestPath)) {
|
|
970
|
+
try {
|
|
971
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
972
|
+
console.log(c.dim('ℹ Using manifest to identify Code Guardian files.\n'));
|
|
973
|
+
}
|
|
974
|
+
catch {
|
|
975
|
+
manifest = null;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
const manifestCreated = new Set(manifest?.createdFiles || []);
|
|
979
|
+
// ── Helper: was file created by Code Guardian? ───────────────────────────
|
|
980
|
+
// If manifest exists, check it. Otherwise assume all tracked files are ours.
|
|
981
|
+
function wasCreatedByUs(file) {
|
|
982
|
+
if (!manifest)
|
|
983
|
+
return true; // no manifest → legacy fallback, assume ours
|
|
984
|
+
return manifestCreated.has(file);
|
|
985
|
+
}
|
|
986
|
+
// ── Files created entirely by Code Guardian (always safe to delete) ──────
|
|
987
|
+
const allPossibleFiles = [
|
|
906
988
|
'.editorconfig',
|
|
907
989
|
'.lintstagedrc.json',
|
|
908
990
|
'lint-staged.config.js',
|
|
909
991
|
'tsconfig.strict.json',
|
|
992
|
+
'tsconfig.json',
|
|
993
|
+
'commitlint.config.js',
|
|
910
994
|
'.prettierignore',
|
|
911
995
|
];
|
|
996
|
+
// Only include files that exist AND were created by us (or no manifest)
|
|
997
|
+
const filesToRemove = allPossibleFiles.filter(f => fs.existsSync(path.join(cwd, f)) && wasCreatedByUs(f));
|
|
912
998
|
// ── Files that may have had a pre-existing version (backup/restore) ──────
|
|
913
|
-
// During init these get renamed to <file>.backup before we overwrite.
|
|
914
|
-
// On uninstall: if .backup exists → restore it, else → delete our file.
|
|
915
999
|
const restorableConfigs = [
|
|
916
|
-
// ESLint
|
|
917
1000
|
{ created: 'eslint.config.mjs', backups: [
|
|
918
1001
|
'eslint.config.mjs.backup', 'eslint.config.js.backup', 'eslint.config.cjs.backup',
|
|
919
1002
|
'.eslintrc.backup', '.eslintrc.js.backup', '.eslintrc.cjs.backup',
|
|
920
1003
|
'.eslintrc.json.backup', '.eslintrc.yml.backup',
|
|
921
1004
|
] },
|
|
922
|
-
// Prettier
|
|
923
1005
|
{ created: '.prettierrc.json', backups: [
|
|
924
1006
|
'.prettierrc.json.backup', '.prettierrc.backup', '.prettierrc.js.backup',
|
|
925
1007
|
'.prettierrc.cjs.backup', '.prettierrc.yml.backup', '.prettierrc.yaml.backup',
|
|
926
1008
|
'.prettierrc.toml.backup', 'prettier.config.js.backup',
|
|
927
1009
|
] },
|
|
928
|
-
// ESLint ignore (old format — we delete and backup during init)
|
|
929
1010
|
{ created: '.eslintignore', backups: ['.eslintignore.backup'] },
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
'.vscode/
|
|
934
|
-
'.vscode/
|
|
935
|
-
'.vscode/
|
|
936
|
-
|
|
937
|
-
'.
|
|
938
|
-
|
|
939
|
-
// ── MCP config files ─────────────────────────────────────────────────────
|
|
940
|
-
const mcpFiles = [
|
|
941
|
-
'.cursor/mcp.json',
|
|
942
|
-
'.gemini/settings.json',
|
|
1011
|
+
// VS Code files (backed up + merged during init)
|
|
1012
|
+
{ created: '.vscode/settings.json', backups: ['.vscode/settings.json.backup'] },
|
|
1013
|
+
{ created: '.vscode/extensions.json', backups: ['.vscode/extensions.json.backup'] },
|
|
1014
|
+
{ created: '.vscode/tasks.json', backups: ['.vscode/tasks.json.backup'] },
|
|
1015
|
+
{ created: '.vscode/launch.json', backups: ['.vscode/launch.json.backup'] },
|
|
1016
|
+
{ created: '.vscode/mcp.json', backups: ['.vscode/mcp.json.backup'] },
|
|
1017
|
+
// MCP config files (backed up + merged during init)
|
|
1018
|
+
{ created: '.cursor/mcp.json', backups: ['.cursor/mcp.json.backup'] },
|
|
1019
|
+
{ created: '.gemini/settings.json', backups: ['.gemini/settings.json.backup'] },
|
|
943
1020
|
];
|
|
944
1021
|
// ── Directories to remove entirely ───────────────────────────────────────
|
|
945
|
-
const dirsToRemove = [
|
|
946
|
-
|
|
947
|
-
];
|
|
948
|
-
// ── package.json scripts to remove ───────────────────────────────────────
|
|
1022
|
+
const dirsToRemove = ['.code-guardian', 'config', 'templates', 'docs'];
|
|
1023
|
+
// ── package.json scripts ─────────────────────────────────────────────────
|
|
949
1024
|
const scriptsToRemove = [
|
|
950
|
-
'precommit-check',
|
|
951
|
-
'
|
|
952
|
-
'generate-doc',
|
|
953
|
-
'generate-pr-checklist',
|
|
954
|
-
'set-bypass-password',
|
|
955
|
-
'set-admin-password',
|
|
956
|
-
'view-bypass-log',
|
|
957
|
-
'delete-bypass-logs',
|
|
1025
|
+
'precommit-check', 'auto-fix', 'generate-doc', 'generate-pr-checklist',
|
|
1026
|
+
'set-bypass-password', 'set-admin-password', 'view-bypass-log', 'delete-bypass-logs',
|
|
958
1027
|
];
|
|
1028
|
+
const conditionalScriptsToRemove = {
|
|
1029
|
+
'validate': (v) => v === 'code-guard validate',
|
|
1030
|
+
'lint': (v) => v.startsWith('eslint'),
|
|
1031
|
+
'lint:fix': (v) => v.startsWith('eslint') && v.includes('--fix'),
|
|
1032
|
+
'format': (v) => v.startsWith('prettier --write'),
|
|
1033
|
+
'format:check': (v) => v.startsWith('prettier --check'),
|
|
1034
|
+
'prepare': (v) => v === 'husky' || v === 'husky install',
|
|
1035
|
+
};
|
|
959
1036
|
// ── Detect AI config files via registry ──────────────────────────────────
|
|
960
1037
|
const { defaultRegistry } = requireUtil('ai-config-registry');
|
|
961
1038
|
const aiTemplates = defaultRegistry.getAll();
|
|
@@ -980,31 +1057,59 @@ async function uninstallCodeGuard() {
|
|
|
980
1057
|
aiActions.push({ name: t.name, filePath, relativePath, marker: t.marker, action: 'delete' });
|
|
981
1058
|
}
|
|
982
1059
|
}
|
|
983
|
-
// ──
|
|
984
|
-
const
|
|
985
|
-
const
|
|
986
|
-
const
|
|
987
|
-
const
|
|
1060
|
+
// ── Detect husky pre-commit status ───────────────────────────────────────
|
|
1061
|
+
const HOOK_START = '# --- code-guardian-hook-start ---';
|
|
1062
|
+
const HOOK_END = '# --- code-guardian-hook-end ---';
|
|
1063
|
+
const huskyDir = path.join(cwd, '.husky');
|
|
1064
|
+
const preCommitPath = path.join(huskyDir, 'pre-commit');
|
|
1065
|
+
let huskyAction = 'none';
|
|
1066
|
+
if (fs.existsSync(preCommitPath)) {
|
|
1067
|
+
const huskyContent = fs.readFileSync(preCommitPath, 'utf-8');
|
|
1068
|
+
if (huskyContent.includes(HOOK_START) || huskyContent.includes('code-guard')) {
|
|
1069
|
+
// Check if it was created by us or we appended to existing
|
|
1070
|
+
if (manifest) {
|
|
1071
|
+
huskyAction = manifest.huskyAction === 'created' ? 'delete' : 'strip';
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
// No manifest — check if only our content exists
|
|
1075
|
+
if (huskyContent.includes(HOOK_START)) {
|
|
1076
|
+
const startIdx = huskyContent.indexOf(HOOK_START);
|
|
1077
|
+
const endIdx = huskyContent.indexOf(HOOK_END);
|
|
1078
|
+
if (endIdx !== -1) {
|
|
1079
|
+
const before = huskyContent.substring(0, startIdx).replace(/^#!\/usr\/bin\/env\s+sh\s*/, '').trim();
|
|
1080
|
+
const after = huskyContent.substring(endIdx + HOOK_END.length).trim();
|
|
1081
|
+
huskyAction = (before.length === 0 && after.length === 0) ? 'delete' : 'strip';
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
huskyAction = 'delete'; // no markers but has code-guard references
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
// ── Gather restorables ───────────────────────────────────────────────────
|
|
988
1091
|
const restorables = [];
|
|
989
1092
|
for (const rc of restorableConfigs) {
|
|
990
1093
|
const createdPath = path.join(cwd, rc.created);
|
|
991
1094
|
if (!fs.existsSync(createdPath))
|
|
992
1095
|
continue;
|
|
993
|
-
// Find the first backup that exists
|
|
994
1096
|
const foundBackup = rc.backups.find(b => fs.existsSync(path.join(cwd, b))) || null;
|
|
995
1097
|
restorables.push({ created: rc.created, backupFile: foundBackup });
|
|
996
1098
|
}
|
|
997
|
-
|
|
998
|
-
|
|
1099
|
+
// ── Check if anything to do ──────────────────────────────────────────────
|
|
1100
|
+
const existingDirs = dirsToRemove.filter(d => fs.existsSync(path.join(cwd, d)));
|
|
1101
|
+
const totalFound = filesToRemove.length
|
|
1102
|
+
+ existingDirs.length + aiActions.length + restorables.length
|
|
1103
|
+
+ (huskyAction !== 'none' ? 1 : 0);
|
|
999
1104
|
if (totalFound === 0) {
|
|
1000
1105
|
console.log(c.yellow('⚠️ No Code Guardian files found to remove.\n'));
|
|
1001
1106
|
return;
|
|
1002
1107
|
}
|
|
1003
1108
|
// ── Show what will be removed ────────────────────────────────────────────
|
|
1004
1109
|
console.log(c.bold('The following will be cleaned up:\n'));
|
|
1005
|
-
if (
|
|
1110
|
+
if (filesToRemove.length > 0) {
|
|
1006
1111
|
console.log(c.bold('Config Files (created by Code Guardian — will be deleted):'));
|
|
1007
|
-
|
|
1112
|
+
filesToRemove.forEach(f => console.log(` ${c.red('✗')} ${f}`));
|
|
1008
1113
|
console.log('');
|
|
1009
1114
|
}
|
|
1010
1115
|
if (restorables.length > 0) {
|
|
@@ -1019,14 +1124,14 @@ async function uninstallCodeGuard() {
|
|
|
1019
1124
|
}
|
|
1020
1125
|
console.log('');
|
|
1021
1126
|
}
|
|
1022
|
-
if (
|
|
1023
|
-
console.log(c.bold('
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1127
|
+
if (huskyAction !== 'none') {
|
|
1128
|
+
console.log(c.bold('Git Hooks:'));
|
|
1129
|
+
if (huskyAction === 'delete') {
|
|
1130
|
+
console.log(` ${c.red('✗')} .husky/pre-commit ${c.dim('(created by Code Guardian)')}`);
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
console.log(` ${c.yellow('⚠')} .husky/pre-commit ${c.dim('(will strip Code Guardian hooks, keep your hooks)')}`);
|
|
1134
|
+
}
|
|
1030
1135
|
console.log('');
|
|
1031
1136
|
}
|
|
1032
1137
|
const aiDeletes = aiActions.filter(a => a.action === 'delete');
|
|
@@ -1062,23 +1167,17 @@ async function uninstallCodeGuard() {
|
|
|
1062
1167
|
try {
|
|
1063
1168
|
const createdPath = path.join(cwd, r.created);
|
|
1064
1169
|
if (r.backupFile) {
|
|
1065
|
-
// Restore: copy backup over the Code Guardian file, then delete backup
|
|
1066
1170
|
const backupPath = path.join(cwd, r.backupFile);
|
|
1067
|
-
// The backup might have a different name (e.g., .eslintrc.json.backup → restore as .eslintrc.json)
|
|
1068
1171
|
const restoredName = r.backupFile.replace(/\.backup$/, '');
|
|
1069
1172
|
const restoredPath = path.join(cwd, restoredName);
|
|
1070
|
-
|
|
1071
|
-
if (fs.existsSync(createdPath)) {
|
|
1173
|
+
if (fs.existsSync(createdPath))
|
|
1072
1174
|
fs.unlinkSync(createdPath);
|
|
1073
|
-
}
|
|
1074
|
-
// Restore the backup
|
|
1075
1175
|
fs.copyFileSync(backupPath, restoredPath);
|
|
1076
1176
|
fs.unlinkSync(backupPath);
|
|
1077
1177
|
console.log(` ${c.green('✓')} Restored ${restoredName} ${c.dim(`(from ${r.backupFile})`)}`);
|
|
1078
1178
|
removedCount++;
|
|
1079
1179
|
}
|
|
1080
1180
|
else {
|
|
1081
|
-
// No backup → just delete our file
|
|
1082
1181
|
fs.unlinkSync(createdPath);
|
|
1083
1182
|
console.log(` ${c.green('✓')} Removed ${r.created}`);
|
|
1084
1183
|
removedCount++;
|
|
@@ -1088,59 +1187,26 @@ async function uninstallCodeGuard() {
|
|
|
1088
1187
|
console.log(` ${c.red('✗')} Failed to handle ${r.created}: ${error.message}`);
|
|
1089
1188
|
}
|
|
1090
1189
|
}
|
|
1091
|
-
//
|
|
1092
|
-
// been caught above (e.g., user already manually restored but .backup remains)
|
|
1190
|
+
// Clean up orphan .backup files
|
|
1093
1191
|
const allBackupPatterns = restorableConfigs.flatMap(rc => rc.backups);
|
|
1094
1192
|
for (const bp of allBackupPatterns) {
|
|
1095
1193
|
const bpPath = path.join(cwd, bp);
|
|
1096
1194
|
if (fs.existsSync(bpPath)) {
|
|
1097
1195
|
try {
|
|
1098
|
-
// Check if the original (non-backup) already exists and is NOT a Code Guardian file
|
|
1099
|
-
// If so, just delete the orphan backup
|
|
1100
1196
|
fs.unlinkSync(bpPath);
|
|
1101
1197
|
console.log(` ${c.green('✓')} Cleaned up orphan backup ${bp}`);
|
|
1102
1198
|
}
|
|
1103
1199
|
catch { }
|
|
1104
1200
|
}
|
|
1105
1201
|
}
|
|
1202
|
+
// Clean up empty IDE directories after restore/delete
|
|
1203
|
+
cleanupEmptyDir(path.join(cwd, '.vscode'), cwd);
|
|
1204
|
+
cleanupEmptyDir(path.join(cwd, '.cursor'), cwd);
|
|
1205
|
+
cleanupEmptyDir(path.join(cwd, '.gemini'), cwd);
|
|
1106
1206
|
// ── 2. Remove simple config files ────────────────────────────────────────
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
const
|
|
1110
|
-
if (fs.existsSync(fullPath)) {
|
|
1111
|
-
try {
|
|
1112
|
-
fs.unlinkSync(fullPath);
|
|
1113
|
-
console.log(` ${c.green('✓')} Removed ${file}`);
|
|
1114
|
-
removedCount++;
|
|
1115
|
-
}
|
|
1116
|
-
catch (error) {
|
|
1117
|
-
console.log(` ${c.red('✗')} Failed to remove ${file}: ${error.message}`);
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
// ── 3. Remove VS Code files ──────────────────────────────────────────────
|
|
1122
|
-
if (existingVSCodeFiles.length > 0) {
|
|
1123
|
-
console.log(c.bold('\nRemoving VS Code files...\n'));
|
|
1124
|
-
for (const file of existingVSCodeFiles) {
|
|
1125
|
-
const fullPath = path.join(cwd, file);
|
|
1126
|
-
if (fs.existsSync(fullPath)) {
|
|
1127
|
-
try {
|
|
1128
|
-
fs.unlinkSync(fullPath);
|
|
1129
|
-
console.log(` ${c.green('✓')} Removed ${file}`);
|
|
1130
|
-
removedCount++;
|
|
1131
|
-
}
|
|
1132
|
-
catch (error) {
|
|
1133
|
-
console.log(` ${c.red('✗')} Failed to remove ${file}: ${error.message}`);
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
// Remove .vscode/ if empty
|
|
1138
|
-
cleanupEmptyDir(path.join(cwd, '.vscode'), cwd);
|
|
1139
|
-
}
|
|
1140
|
-
// ── 4. Remove MCP config files ───────────────────────────────────────────
|
|
1141
|
-
if (existingMCPFiles.length > 0) {
|
|
1142
|
-
console.log(c.bold('\nRemoving MCP config files...\n'));
|
|
1143
|
-
for (const file of existingMCPFiles) {
|
|
1207
|
+
if (filesToRemove.length > 0) {
|
|
1208
|
+
console.log(c.bold('\nRemoving Code Guardian files...\n'));
|
|
1209
|
+
for (const file of filesToRemove) {
|
|
1144
1210
|
const fullPath = path.join(cwd, file);
|
|
1145
1211
|
if (fs.existsSync(fullPath)) {
|
|
1146
1212
|
try {
|
|
@@ -1153,11 +1219,8 @@ async function uninstallCodeGuard() {
|
|
|
1153
1219
|
}
|
|
1154
1220
|
}
|
|
1155
1221
|
}
|
|
1156
|
-
// Clean up empty .cursor/ and .gemini/ directories
|
|
1157
|
-
cleanupEmptyDir(path.join(cwd, '.cursor'), cwd);
|
|
1158
|
-
cleanupEmptyDir(path.join(cwd, '.gemini'), cwd);
|
|
1159
1222
|
}
|
|
1160
|
-
// ──
|
|
1223
|
+
// ── 3. Handle AI config files ────────────────────────────────────────────
|
|
1161
1224
|
if (aiActions.length > 0) {
|
|
1162
1225
|
console.log(c.bold('\nCleaning AI config files...\n'));
|
|
1163
1226
|
for (const action of aiActions) {
|
|
@@ -1166,12 +1229,9 @@ async function uninstallCodeGuard() {
|
|
|
1166
1229
|
fs.unlinkSync(action.filePath);
|
|
1167
1230
|
console.log(` ${c.green('✓')} Removed ${action.relativePath}`);
|
|
1168
1231
|
removedCount++;
|
|
1169
|
-
|
|
1170
|
-
const parentDir = path.dirname(action.filePath);
|
|
1171
|
-
cleanupEmptyDir(parentDir, cwd);
|
|
1232
|
+
cleanupEmptyDir(path.dirname(action.filePath), cwd);
|
|
1172
1233
|
}
|
|
1173
1234
|
else {
|
|
1174
|
-
// Strip only Code Guardian section
|
|
1175
1235
|
const content = fs.readFileSync(action.filePath, 'utf-8');
|
|
1176
1236
|
const markerIdx = content.indexOf(action.marker);
|
|
1177
1237
|
if (markerIdx === -1)
|
|
@@ -1193,7 +1253,7 @@ async function uninstallCodeGuard() {
|
|
|
1193
1253
|
}
|
|
1194
1254
|
}
|
|
1195
1255
|
}
|
|
1196
|
-
// ──
|
|
1256
|
+
// ── 4. Remove directories ────────────────────────────────────────────────
|
|
1197
1257
|
if (existingDirs.length > 0) {
|
|
1198
1258
|
console.log(c.bold('\nRemoving directories...\n'));
|
|
1199
1259
|
for (const dir of dirsToRemove) {
|
|
@@ -1210,54 +1270,41 @@ async function uninstallCodeGuard() {
|
|
|
1210
1270
|
}
|
|
1211
1271
|
}
|
|
1212
1272
|
}
|
|
1213
|
-
// ──
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
fs.writeFileSync(hookPath, cleaned);
|
|
1240
|
-
try {
|
|
1241
|
-
fs.chmodSync(hookPath, '755');
|
|
1273
|
+
// ── 5. Clean git hooks ───────────────────────────────────────────────────
|
|
1274
|
+
if (huskyAction !== 'none') {
|
|
1275
|
+
console.log(c.bold('\nCleaning git hooks...\n'));
|
|
1276
|
+
if (fs.existsSync(preCommitPath)) {
|
|
1277
|
+
try {
|
|
1278
|
+
if (huskyAction === 'delete') {
|
|
1279
|
+
fs.unlinkSync(preCommitPath);
|
|
1280
|
+
console.log(` ${c.green('✓')} Removed .husky/pre-commit`);
|
|
1281
|
+
removedCount++;
|
|
1282
|
+
}
|
|
1283
|
+
else {
|
|
1284
|
+
const content = fs.readFileSync(preCommitPath, 'utf-8');
|
|
1285
|
+
const startIdx = content.indexOf(HOOK_START);
|
|
1286
|
+
const endIdx = content.indexOf(HOOK_END);
|
|
1287
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
1288
|
+
const before = content.substring(0, startIdx).trimEnd();
|
|
1289
|
+
const after = content.substring(endIdx + HOOK_END.length).trimEnd();
|
|
1290
|
+
const cleaned = (before + after).trimEnd() + '\n';
|
|
1291
|
+
fs.writeFileSync(preCommitPath, cleaned);
|
|
1292
|
+
try {
|
|
1293
|
+
fs.chmodSync(preCommitPath, '755');
|
|
1294
|
+
}
|
|
1295
|
+
catch { }
|
|
1296
|
+
console.log(` ${c.green('✓')} Stripped Code Guardian hooks from .husky/pre-commit ${c.dim('(your hooks preserved)')}`);
|
|
1297
|
+
removedCount++;
|
|
1298
|
+
}
|
|
1242
1299
|
}
|
|
1243
|
-
catch { }
|
|
1244
|
-
console.log(` ${c.green('✓')} Stripped Code Guardian hooks from .husky/${hookFile} ${c.dim('(your hooks preserved)')}`);
|
|
1245
|
-
removedCount++;
|
|
1246
1300
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
// No markers — check if the hook was entirely written by Code Guardian
|
|
1250
|
-
// (contains "code-guard check" or "code-guard" references)
|
|
1251
|
-
if (content.includes('code-guard') || content.includes('code_guard')) {
|
|
1252
|
-
fs.unlinkSync(hookPath);
|
|
1253
|
-
console.log(` ${c.green('✓')} Removed .husky/${hookFile}`);
|
|
1254
|
-
removedCount++;
|
|
1301
|
+
catch (error) {
|
|
1302
|
+
console.log(` ${c.red('✗')} Failed to clean .husky/pre-commit: ${error.message}`);
|
|
1255
1303
|
}
|
|
1256
1304
|
}
|
|
1305
|
+
cleanupEmptyDir(huskyDir, cwd);
|
|
1257
1306
|
}
|
|
1258
|
-
//
|
|
1259
|
-
cleanupEmptyDir(huskyDir, cwd);
|
|
1260
|
-
// ── 8. Clean package.json scripts ────────────────────────────────────────
|
|
1307
|
+
// ── 6. Clean package.json scripts ────────────────────────────────────────
|
|
1261
1308
|
console.log(c.bold('\nCleaning package.json scripts...\n'));
|
|
1262
1309
|
const packageJsonPath = path.join(cwd, 'package.json');
|
|
1263
1310
|
if (fs.existsSync(packageJsonPath)) {
|
|
@@ -1272,12 +1319,13 @@ async function uninstallCodeGuard() {
|
|
|
1272
1319
|
removedCount++;
|
|
1273
1320
|
}
|
|
1274
1321
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1322
|
+
for (const [script, matcher] of Object.entries(conditionalScriptsToRemove)) {
|
|
1323
|
+
if (packageJson.scripts && packageJson.scripts[script] && matcher(packageJson.scripts[script])) {
|
|
1324
|
+
delete packageJson.scripts[script];
|
|
1325
|
+
console.log(` ${c.green('✓')} Removed script: ${script}`);
|
|
1326
|
+
scriptRemoved = true;
|
|
1327
|
+
removedCount++;
|
|
1328
|
+
}
|
|
1281
1329
|
}
|
|
1282
1330
|
if (scriptRemoved) {
|
|
1283
1331
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|