@torka/claude-qol 0.2.1 → 0.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/install.js +87 -20
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -13,11 +13,17 @@ const colors = {
|
|
|
13
13
|
green: '\x1b[32m',
|
|
14
14
|
yellow: '\x1b[33m',
|
|
15
15
|
blue: '\x1b[34m',
|
|
16
|
+
cyan: '\x1b[36m',
|
|
16
17
|
red: '\x1b[31m',
|
|
17
18
|
reset: '\x1b[0m',
|
|
18
19
|
bold: '\x1b[1m',
|
|
19
20
|
};
|
|
20
21
|
|
|
22
|
+
// Files that should not be overwritten if user has customized them
|
|
23
|
+
const PROTECTED_FILES = [
|
|
24
|
+
'auto_approve_safe.rules.json'
|
|
25
|
+
];
|
|
26
|
+
|
|
21
27
|
function log(message, color = 'reset') {
|
|
22
28
|
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
23
29
|
}
|
|
@@ -34,21 +40,16 @@ function logError(message) {
|
|
|
34
40
|
log(` ✗ ${message}`, 'red');
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
function
|
|
43
|
+
function logUpdate(message) {
|
|
38
44
|
log(` ↻ ${message}`, 'blue');
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const content2 = fs.readFileSync(file2);
|
|
48
|
-
return content1.equals(content2);
|
|
49
|
-
} catch {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
47
|
+
function logBackup(message) {
|
|
48
|
+
log(` ⤷ ${message}`, 'cyan');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function logPreserve(message) {
|
|
52
|
+
log(` ★ ${message}`, 'yellow');
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
/**
|
|
@@ -87,6 +88,32 @@ function getTargetBase() {
|
|
|
87
88
|
return path.join(process.env.INIT_CWD || process.cwd(), '.claude');
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Ensure entries exist in a .gitignore file (append if missing)
|
|
93
|
+
*/
|
|
94
|
+
function ensureGitignoreEntries(gitignorePath, entries, header) {
|
|
95
|
+
let existingContent = '';
|
|
96
|
+
if (fs.existsSync(gitignorePath)) {
|
|
97
|
+
existingContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const existingLines = new Set(
|
|
101
|
+
existingContent.split('\n').map(line => line.trim()).filter(Boolean)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const missingEntries = entries.filter(entry => !existingLines.has(entry));
|
|
105
|
+
|
|
106
|
+
if (missingEntries.length > 0) {
|
|
107
|
+
const newContent = existingContent.trimEnd() +
|
|
108
|
+
(existingContent ? '\n\n' : '') +
|
|
109
|
+
`# ${header}\n` +
|
|
110
|
+
missingEntries.join('\n') + '\n';
|
|
111
|
+
fs.writeFileSync(gitignorePath, newContent);
|
|
112
|
+
return missingEntries.length;
|
|
113
|
+
}
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
/**
|
|
91
118
|
* Recursively copy directory contents
|
|
92
119
|
*/
|
|
@@ -110,17 +137,31 @@ function copyDirRecursive(src, dest, stats) {
|
|
|
110
137
|
copyDirRecursive(srcPath, destPath, stats);
|
|
111
138
|
} else {
|
|
112
139
|
if (fs.existsSync(destPath)) {
|
|
113
|
-
// Check if
|
|
114
|
-
if (
|
|
115
|
-
stats.
|
|
140
|
+
// Check if this is a protected user config file
|
|
141
|
+
if (PROTECTED_FILES.includes(entry.name)) {
|
|
142
|
+
stats.preserved.push(destPath);
|
|
143
|
+
logPreserve(`Preserved (user config): ${path.relative(stats.targetBase, destPath)}`);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Check if files are identical (inline comparison)
|
|
148
|
+
const srcContent = fs.readFileSync(srcPath);
|
|
149
|
+
const destContent = fs.readFileSync(destPath);
|
|
150
|
+
const filesAreIdentical = srcContent.equals(destContent);
|
|
151
|
+
|
|
152
|
+
if (filesAreIdentical) {
|
|
153
|
+
stats.unchanged.push(destPath);
|
|
116
154
|
logSkip(`Unchanged: ${path.relative(stats.targetBase, destPath)}`);
|
|
117
155
|
} else {
|
|
118
156
|
// Backup existing file, then replace
|
|
119
|
-
const backupPath = destPath + '.
|
|
157
|
+
const backupPath = destPath + '.backup';
|
|
120
158
|
fs.copyFileSync(destPath, backupPath);
|
|
159
|
+
stats.backups.push(backupPath);
|
|
160
|
+
logBackup(`Backup: ${path.relative(stats.targetBase, backupPath)}`);
|
|
161
|
+
|
|
121
162
|
fs.copyFileSync(srcPath, destPath);
|
|
122
163
|
stats.updated.push(destPath);
|
|
123
|
-
|
|
164
|
+
logUpdate(`Updated: ${path.relative(stats.targetBase, destPath)}`);
|
|
124
165
|
}
|
|
125
166
|
} else {
|
|
126
167
|
fs.copyFileSync(srcPath, destPath);
|
|
@@ -148,10 +189,34 @@ function install() {
|
|
|
148
189
|
fs.mkdirSync(targetBase, { recursive: true });
|
|
149
190
|
}
|
|
150
191
|
|
|
192
|
+
// Ensure gitignore entries for package-installed files
|
|
193
|
+
const gitignorePath = path.join(targetBase, '.gitignore');
|
|
194
|
+
const gitignoreEntries = [
|
|
195
|
+
'scripts/auto_approve_safe.py',
|
|
196
|
+
'scripts/auto_approve_safe.rules.json',
|
|
197
|
+
'scripts/context-monitor.py',
|
|
198
|
+
'scripts/__pycache__/',
|
|
199
|
+
'commands/optimize-auto-approve-hook.md',
|
|
200
|
+
'skills/nash/',
|
|
201
|
+
'auto_approve_safe.decisions.jsonl',
|
|
202
|
+
'auto_approve_safe.decisions.archived.jsonl',
|
|
203
|
+
'*.backup',
|
|
204
|
+
];
|
|
205
|
+
const addedCount = ensureGitignoreEntries(
|
|
206
|
+
gitignorePath,
|
|
207
|
+
gitignoreEntries,
|
|
208
|
+
'Installed by @torka/claude-qol'
|
|
209
|
+
);
|
|
210
|
+
if (addedCount > 0) {
|
|
211
|
+
log(` Updated .gitignore (added ${addedCount} entries)`, 'green');
|
|
212
|
+
}
|
|
213
|
+
|
|
151
214
|
const stats = {
|
|
152
215
|
copied: [],
|
|
153
216
|
updated: [],
|
|
154
|
-
|
|
217
|
+
unchanged: [],
|
|
218
|
+
preserved: [],
|
|
219
|
+
backups: [],
|
|
155
220
|
targetBase,
|
|
156
221
|
};
|
|
157
222
|
|
|
@@ -176,8 +241,10 @@ function install() {
|
|
|
176
241
|
// Summary
|
|
177
242
|
log('\n' + colors.bold + '📊 Installation Summary' + colors.reset);
|
|
178
243
|
log(` Files copied: ${stats.copied.length}`, 'green');
|
|
179
|
-
log(` Files updated
|
|
180
|
-
log(`
|
|
244
|
+
log(` Files updated: ${stats.updated.length}`, 'blue');
|
|
245
|
+
log(` Backups created: ${stats.backups.length}`, 'cyan');
|
|
246
|
+
log(` Files unchanged: ${stats.unchanged.length}`, 'yellow');
|
|
247
|
+
log(` Files preserved (user config): ${stats.preserved.length}`, 'yellow');
|
|
181
248
|
|
|
182
249
|
// Post-install instructions
|
|
183
250
|
log('\n' + colors.bold + '📝 Configuration Required' + colors.reset);
|
package/package.json
CHANGED