claude-all-config 3.5.8 ā 3.5.10
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/VERSION +1 -1
- package/package.json +1 -1
- package/postinstall.js +127 -21
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.5.
|
|
1
|
+
3.5.10
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-all-config",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.10",
|
|
4
4
|
"description": "𦾠MONSTER ENGINEER v2 - Ultimate AI CLI with 63 Skills, 12 Superpowers, 14 Agents. Multi-Agent Orchestration, Cost-Aware, Security Scorecard, Parallel-First.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/postinstall.js
CHANGED
|
@@ -8,15 +8,65 @@ const fs = require('fs');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const { execSync } = require('child_process');
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
// --- Sudo-aware HOME detection ----------------------------------------------
|
|
12
|
+
// When the package is installed via `sudo npm install -g`, npm runs the
|
|
13
|
+
// postinstall as root, so process.env.HOME is /root and configs would land in
|
|
14
|
+
// the wrong place. We honor SUDO_USER to write into the invoking user's HOME
|
|
15
|
+
// and chown the result back to them so a follow-up non-sudo install does not
|
|
16
|
+
// trip over EACCES on root-owned files.
|
|
17
|
+
const SUDO_USER = process.env.SUDO_USER && process.env.SUDO_USER !== 'root'
|
|
18
|
+
? process.env.SUDO_USER : null;
|
|
19
|
+
const SUDO_UID = process.env.SUDO_UID ? Number(process.env.SUDO_UID) : null;
|
|
20
|
+
const SUDO_GID = process.env.SUDO_GID ? Number(process.env.SUDO_GID) : null;
|
|
21
|
+
|
|
22
|
+
function resolveHome() {
|
|
23
|
+
if (SUDO_USER) {
|
|
24
|
+
// Look up the real home from /etc/passwd
|
|
25
|
+
try {
|
|
26
|
+
const passwd = fs.readFileSync('/etc/passwd', 'utf8');
|
|
27
|
+
const line = passwd.split('\n').find(l => l.startsWith(SUDO_USER + ':'));
|
|
28
|
+
if (line) {
|
|
29
|
+
const parts = line.split(':');
|
|
30
|
+
if (parts[5] && fs.existsSync(parts[5])) return parts[5];
|
|
31
|
+
}
|
|
32
|
+
} catch {}
|
|
33
|
+
// Fallback to /home/$SUDO_USER
|
|
34
|
+
const fallback = `/home/${SUDO_USER}`;
|
|
35
|
+
if (fs.existsSync(fallback)) return fallback;
|
|
36
|
+
}
|
|
37
|
+
return process.env.HOME || process.env.USERPROFILE;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const HOME = resolveHome();
|
|
12
41
|
const PKG_DIR = __dirname;
|
|
13
42
|
|
|
14
|
-
|
|
43
|
+
if (SUDO_USER) {
|
|
44
|
+
console.log(`ā¹ļø Running under sudo ā installing for user '${SUDO_USER}' (HOME=${HOME})\n`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Recursively chown a path back to the invoking user when running under sudo.
|
|
48
|
+
function fixOwnership(target) {
|
|
49
|
+
if (SUDO_UID === null || SUDO_GID === null) return;
|
|
50
|
+
try { fs.lchownSync(target, SUDO_UID, SUDO_GID); } catch {}
|
|
51
|
+
let stat;
|
|
52
|
+
try { stat = fs.lstatSync(target); } catch { return; }
|
|
53
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) return;
|
|
54
|
+
let entries;
|
|
55
|
+
try { entries = fs.readdirSync(target); } catch { return; }
|
|
56
|
+
for (const entry of entries) fixOwnership(path.join(target, entry));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Detect installed CLIs ā also check the resolved user's ~/.local/bin so that
|
|
60
|
+
// a sudo invocation still finds claude installed via the native installer.
|
|
15
61
|
function commandExists(cmd) {
|
|
16
62
|
try {
|
|
17
63
|
execSync(`which ${cmd}`, { stdio: 'ignore' });
|
|
18
64
|
return true;
|
|
19
65
|
} catch {
|
|
66
|
+
if (HOME) {
|
|
67
|
+
const userBin = path.join(HOME, '.local', 'bin', cmd);
|
|
68
|
+
if (fs.existsSync(userBin)) return true;
|
|
69
|
+
}
|
|
20
70
|
return false;
|
|
21
71
|
}
|
|
22
72
|
}
|
|
@@ -33,32 +83,54 @@ if (!hasClaude && !hasGemini) {
|
|
|
33
83
|
}
|
|
34
84
|
console.log('');
|
|
35
85
|
|
|
36
|
-
// Copy function
|
|
86
|
+
// Copy function ā resilient: skip files that can't be copied (e.g., EACCES from
|
|
87
|
+
// previous sudo install) instead of crashing the whole postinstall.
|
|
37
88
|
function copyDir(src, dest) {
|
|
38
89
|
if (!fs.existsSync(src)) return 0;
|
|
39
90
|
|
|
40
|
-
|
|
41
|
-
fs.
|
|
91
|
+
try {
|
|
92
|
+
if (!fs.existsSync(dest)) {
|
|
93
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
return 0;
|
|
42
97
|
}
|
|
43
98
|
|
|
44
|
-
|
|
99
|
+
let files;
|
|
100
|
+
try { files = fs.readdirSync(src); } catch { return 0; }
|
|
45
101
|
let count = 0;
|
|
102
|
+
let skipped = 0;
|
|
46
103
|
|
|
47
104
|
files.forEach(file => {
|
|
48
105
|
const srcPath = path.join(src, file);
|
|
49
106
|
const destPath = path.join(dest, file);
|
|
50
107
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
108
|
+
let stat;
|
|
109
|
+
try { stat = fs.statSync(srcPath); } catch { return; }
|
|
110
|
+
|
|
111
|
+
if (stat.isDirectory()) {
|
|
112
|
+
try {
|
|
113
|
+
if (!fs.existsSync(destPath)) {
|
|
114
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
115
|
+
}
|
|
116
|
+
} catch { skipped++; return; }
|
|
55
117
|
count += copyDir(srcPath, destPath);
|
|
56
118
|
} else {
|
|
57
|
-
|
|
58
|
-
|
|
119
|
+
try {
|
|
120
|
+
fs.copyFileSync(srcPath, destPath);
|
|
121
|
+
count++;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
// EACCES from a prior root-owned copy, EBUSY, etc ā skip and continue
|
|
124
|
+
skipped++;
|
|
125
|
+
}
|
|
59
126
|
}
|
|
60
127
|
});
|
|
61
128
|
|
|
129
|
+
if (skipped > 0) {
|
|
130
|
+
// Surface a hint without aborting; user can sudo chown -R if they really want everything fresh
|
|
131
|
+
process.env._CA_COPY_SKIPS = String(Number(process.env._CA_COPY_SKIPS || 0) + skipped);
|
|
132
|
+
}
|
|
133
|
+
|
|
62
134
|
return count;
|
|
63
135
|
}
|
|
64
136
|
|
|
@@ -103,9 +175,13 @@ function installClaude() {
|
|
|
103
175
|
const mcpSrc = path.join(PKG_DIR, 'mcp.json');
|
|
104
176
|
const mcpDest = path.join(HOME, '.mcp.json');
|
|
105
177
|
if (fs.existsSync(mcpSrc)) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
178
|
+
try {
|
|
179
|
+
fs.copyFileSync(mcpSrc, mcpDest);
|
|
180
|
+
try { fs.chmodSync(mcpDest, 0o600); } catch {}
|
|
181
|
+
console.log(` š§ MCP config (7 servers)`);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.log(` ā ļø MCP config skipped (${e.code || 'error'}): ${mcpDest}`);
|
|
184
|
+
}
|
|
109
185
|
}
|
|
110
186
|
|
|
111
187
|
// Settings - create both settings.json AND settings.local.json
|
|
@@ -122,20 +198,31 @@ function installClaude() {
|
|
|
122
198
|
|
|
123
199
|
// Write settings.json (main config - Claude reads this)
|
|
124
200
|
const settingsJsonPath = path.join(CLAUDE_DIR, 'settings.json');
|
|
125
|
-
|
|
201
|
+
try {
|
|
202
|
+
fs.writeFileSync(settingsJsonPath, JSON.stringify(settings, null, 2));
|
|
203
|
+
} catch (e) {
|
|
204
|
+
console.log(` ā ļø settings.json skipped (${e.code || 'error'}) ā try: sudo chown -R $USER ~/.claude`);
|
|
205
|
+
}
|
|
126
206
|
|
|
127
207
|
// Write settings.local.json (backup/local overrides)
|
|
128
208
|
const settingsLocalPath = path.join(CLAUDE_DIR, 'settings.local.json');
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
209
|
+
try {
|
|
210
|
+
fs.writeFileSync(settingsLocalPath, JSON.stringify(settings, null, 2));
|
|
211
|
+
console.log(` āļø settings.json + settings.local.json (@proactive-mode enabled)`);
|
|
212
|
+
} catch (e) {
|
|
213
|
+
console.log(` ā ļø settings.local.json skipped (${e.code || 'error'})`);
|
|
214
|
+
}
|
|
132
215
|
|
|
133
216
|
// Copy CLAUDE.md (global instructions)
|
|
134
217
|
const claudeMdSrc = path.join(PKG_DIR, 'CLAUDE.md');
|
|
135
218
|
const claudeMdDest = path.join(CLAUDE_DIR, 'CLAUDE.md');
|
|
136
219
|
if (fs.existsSync(claudeMdSrc)) {
|
|
137
|
-
|
|
138
|
-
|
|
220
|
+
try {
|
|
221
|
+
fs.copyFileSync(claudeMdSrc, claudeMdDest);
|
|
222
|
+
console.log(` š CLAUDE.md (global instructions)`);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
console.log(` ā ļø CLAUDE.md skipped (${e.code || 'error'})`);
|
|
225
|
+
}
|
|
139
226
|
}
|
|
140
227
|
}
|
|
141
228
|
|
|
@@ -340,6 +427,25 @@ if (hasGemini) {
|
|
|
340
427
|
|
|
341
428
|
setupLocalBinSymlinks();
|
|
342
429
|
|
|
430
|
+
// If we ran under sudo, hand ownership back to the original user so that a
|
|
431
|
+
// follow-up non-sudo `npm install -g claude-all-config` does not hit EACCES.
|
|
432
|
+
if (SUDO_USER) {
|
|
433
|
+
console.log(`\nš Restoring ownership to ${SUDO_USER}...`);
|
|
434
|
+
fixOwnership(path.join(HOME, '.claude'));
|
|
435
|
+
fixOwnership(path.join(HOME, '.gemini'));
|
|
436
|
+
fixOwnership(path.join(HOME, '.mcp.json'));
|
|
437
|
+
fixOwnership(path.join(HOME, '.local'));
|
|
438
|
+
console.log(' ā
Ownership fixed.');
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const skips = Number(process.env._CA_COPY_SKIPS || 0);
|
|
442
|
+
if (skips > 0) {
|
|
443
|
+
console.log('');
|
|
444
|
+
console.log(`ā ļø ${skips} files were skipped (likely owned by root from a prior sudo install).`);
|
|
445
|
+
console.log(' To force-refresh everything, run:');
|
|
446
|
+
console.log(' sudo chown -R $USER ~/.claude ~/.gemini 2>/dev/null && npm install -g claude-all-config');
|
|
447
|
+
}
|
|
448
|
+
|
|
343
449
|
console.log('\nā
Installation complete!\n');
|
|
344
450
|
|
|
345
451
|
if (hasClaude) {
|