@torka/claude-qol 0.2.0 → 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 +100 -4
- 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,6 +40,18 @@ function logError(message) {
|
|
|
34
40
|
log(` ✗ ${message}`, 'red');
|
|
35
41
|
}
|
|
36
42
|
|
|
43
|
+
function logUpdate(message) {
|
|
44
|
+
log(` ↻ ${message}`, 'blue');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function logBackup(message) {
|
|
48
|
+
log(` ⤷ ${message}`, 'cyan');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function logPreserve(message) {
|
|
52
|
+
log(` ★ ${message}`, 'yellow');
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
/**
|
|
38
56
|
* Determine the target .claude directory based on installation context
|
|
39
57
|
*/
|
|
@@ -70,6 +88,32 @@ function getTargetBase() {
|
|
|
70
88
|
return path.join(process.env.INIT_CWD || process.cwd(), '.claude');
|
|
71
89
|
}
|
|
72
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
|
+
|
|
73
117
|
/**
|
|
74
118
|
* Recursively copy directory contents
|
|
75
119
|
*/
|
|
@@ -93,8 +137,32 @@ function copyDirRecursive(src, dest, stats) {
|
|
|
93
137
|
copyDirRecursive(srcPath, destPath, stats);
|
|
94
138
|
} else {
|
|
95
139
|
if (fs.existsSync(destPath)) {
|
|
96
|
-
|
|
97
|
-
|
|
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);
|
|
154
|
+
logSkip(`Unchanged: ${path.relative(stats.targetBase, destPath)}`);
|
|
155
|
+
} else {
|
|
156
|
+
// Backup existing file, then replace
|
|
157
|
+
const backupPath = destPath + '.backup';
|
|
158
|
+
fs.copyFileSync(destPath, backupPath);
|
|
159
|
+
stats.backups.push(backupPath);
|
|
160
|
+
logBackup(`Backup: ${path.relative(stats.targetBase, backupPath)}`);
|
|
161
|
+
|
|
162
|
+
fs.copyFileSync(srcPath, destPath);
|
|
163
|
+
stats.updated.push(destPath);
|
|
164
|
+
logUpdate(`Updated: ${path.relative(stats.targetBase, destPath)}`);
|
|
165
|
+
}
|
|
98
166
|
} else {
|
|
99
167
|
fs.copyFileSync(srcPath, destPath);
|
|
100
168
|
stats.copied.push(destPath);
|
|
@@ -121,9 +189,34 @@ function install() {
|
|
|
121
189
|
fs.mkdirSync(targetBase, { recursive: true });
|
|
122
190
|
}
|
|
123
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
|
+
|
|
124
214
|
const stats = {
|
|
125
215
|
copied: [],
|
|
126
|
-
|
|
216
|
+
updated: [],
|
|
217
|
+
unchanged: [],
|
|
218
|
+
preserved: [],
|
|
219
|
+
backups: [],
|
|
127
220
|
targetBase,
|
|
128
221
|
};
|
|
129
222
|
|
|
@@ -148,7 +241,10 @@ function install() {
|
|
|
148
241
|
// Summary
|
|
149
242
|
log('\n' + colors.bold + '📊 Installation Summary' + colors.reset);
|
|
150
243
|
log(` Files copied: ${stats.copied.length}`, 'green');
|
|
151
|
-
log(` Files
|
|
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');
|
|
152
248
|
|
|
153
249
|
// Post-install instructions
|
|
154
250
|
log('\n' + colors.bold + '📝 Configuration Required' + colors.reset);
|
package/package.json
CHANGED