ccperm 1.3.3 → 1.4.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/dist/scanner.js +59 -65
- package/package.json +1 -1
package/dist/scanner.js
CHANGED
|
@@ -7,8 +7,8 @@ exports.countDeprecated = countDeprecated;
|
|
|
7
7
|
exports.findSettingsFiles = findSettingsFiles;
|
|
8
8
|
exports.scanFile = scanFile;
|
|
9
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
11
|
const node_os_1 = __importDefault(require("node:os"));
|
|
11
|
-
const node_child_process_1 = require("node:child_process");
|
|
12
12
|
const PERM_RE = /"(Bash|Write|Edit|Read|Glob|Grep|WebSearch|WebFetch|mcp_)[^"]*"/g;
|
|
13
13
|
const DEPRECATED_RE = /:\*\)|:\*"/g;
|
|
14
14
|
function countDeprecated(results) {
|
|
@@ -27,73 +27,67 @@ function countDeprecated(results) {
|
|
|
27
27
|
}
|
|
28
28
|
return out;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
const SKIP = new Set([
|
|
31
|
+
'node_modules', '.git', '.cache', '.local', '.npm', '.nvm', '.bun',
|
|
32
|
+
'.vscode', '.docker', '.cargo', '.rustup', 'go', '.gradle', '.m2',
|
|
33
|
+
'.Trash', 'Pictures', 'Music', 'Videos', 'Downloads',
|
|
34
|
+
'snap', '.snap',
|
|
35
|
+
'Library', 'Applications', '.Spotlight-V100', '.fseventsd',
|
|
36
|
+
'Movies', 'Photos', '.iCloud',
|
|
37
|
+
]);
|
|
38
|
+
async function findSettingsFiles(searchDir, onProgress, debug = false) {
|
|
39
|
+
const results = [];
|
|
40
|
+
const t0 = Date.now();
|
|
41
|
+
async function walk(dir) {
|
|
42
|
+
let entries;
|
|
43
|
+
try {
|
|
44
|
+
entries = await node_fs_1.default.promises.readdir(dir, { withFileTypes: true });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return; // permission denied, etc.
|
|
48
|
+
}
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const name = entry.name;
|
|
51
|
+
if (name === '.claude' && entry.isDirectory()) {
|
|
52
|
+
// found a .claude dir — check for settings files inside
|
|
53
|
+
const claudeDir = node_path_1.default.join(dir, '.claude');
|
|
54
|
+
let inner;
|
|
55
|
+
try {
|
|
56
|
+
inner = await node_fs_1.default.promises.readdir(claudeDir);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const f of inner) {
|
|
62
|
+
if (f.startsWith('settings') && f.endsWith('.json')) {
|
|
63
|
+
const full = node_path_1.default.join(claudeDir, f);
|
|
64
|
+
try {
|
|
65
|
+
await node_fs_1.default.promises.access(full, node_fs_1.default.constants.W_OK);
|
|
66
|
+
results.push(full);
|
|
67
|
+
onProgress?.(results.length);
|
|
68
|
+
if (debug)
|
|
69
|
+
console.error(` [debug] found: ${full}`);
|
|
70
|
+
}
|
|
71
|
+
catch { /* not writable */ }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
continue; // don't recurse into .claude
|
|
75
|
+
}
|
|
76
|
+
if (!entry.isDirectory())
|
|
77
|
+
continue;
|
|
78
|
+
if (SKIP.has(name))
|
|
79
|
+
continue;
|
|
80
|
+
if (name.startsWith('.') && name !== '.claude')
|
|
81
|
+
continue; // skip other hidden dirs
|
|
82
|
+
await walk(node_path_1.default.join(dir, name));
|
|
83
|
+
}
|
|
37
84
|
}
|
|
38
|
-
|
|
39
|
-
function findSettingsFiles(searchDir, onProgress, debug = false) {
|
|
40
|
-
const prune = [
|
|
41
|
-
// common
|
|
42
|
-
'node_modules', '.git', '.cache', '.local', '.npm', '.nvm', '.bun',
|
|
43
|
-
'.vscode', '.docker', '.cargo', '.rustup', 'go', '.gradle', '.m2',
|
|
44
|
-
'.Trash', 'Pictures', 'Music', 'Videos', 'Downloads',
|
|
45
|
-
// linux
|
|
46
|
-
'snap', '.snap',
|
|
47
|
-
// macOS
|
|
48
|
-
'Library', 'Applications', '.Spotlight-V100', '.fseventsd',
|
|
49
|
-
'Movies', 'Photos', '.iCloud',
|
|
50
|
-
];
|
|
51
|
-
const pruneArgs = prune.flatMap((d) => ['-name', d, '-o']).slice(0, -1);
|
|
52
|
-
const findArgs = [
|
|
53
|
-
searchDir,
|
|
54
|
-
'(', ...pruneArgs, ')', '-prune',
|
|
55
|
-
'-o', '-path', '*/.claude/settings*.json', '-type', 'f', '-print',
|
|
56
|
-
];
|
|
85
|
+
await walk(searchDir);
|
|
57
86
|
if (debug) {
|
|
58
|
-
console.error(
|
|
59
|
-
console.error(` [debug]
|
|
87
|
+
console.error(` [debug] scan completed in ${Date.now() - t0}ms`);
|
|
88
|
+
console.error(` [debug] found ${results.length} files`);
|
|
60
89
|
}
|
|
61
|
-
|
|
62
|
-
return new Promise((resolve) => {
|
|
63
|
-
const results = [];
|
|
64
|
-
let buf = '';
|
|
65
|
-
const child = (0, node_child_process_1.execFile)('find', findArgs, { encoding: 'utf8', timeout: 30000 });
|
|
66
|
-
child.stderr?.on('data', (chunk) => {
|
|
67
|
-
if (debug)
|
|
68
|
-
process.stderr.write(` [debug] stderr: ${chunk}`);
|
|
69
|
-
});
|
|
70
|
-
child.stdout?.on('data', (chunk) => {
|
|
71
|
-
buf += chunk;
|
|
72
|
-
const lines = buf.split('\n');
|
|
73
|
-
buf = lines.pop() || '';
|
|
74
|
-
for (const line of lines) {
|
|
75
|
-
if (line && isWritable(line))
|
|
76
|
-
results.push(line);
|
|
77
|
-
}
|
|
78
|
-
onProgress?.(results.length);
|
|
79
|
-
});
|
|
80
|
-
child.on('close', (code) => {
|
|
81
|
-
if (buf && isWritable(buf))
|
|
82
|
-
results.push(buf);
|
|
83
|
-
onProgress?.(results.length);
|
|
84
|
-
if (debug) {
|
|
85
|
-
console.error(` [debug] find exited with code ${code} in ${Date.now() - t0}ms`);
|
|
86
|
-
console.error(` [debug] found ${results.length} files`);
|
|
87
|
-
results.forEach((f) => console.error(` [debug] ${f}`));
|
|
88
|
-
}
|
|
89
|
-
resolve(results);
|
|
90
|
-
});
|
|
91
|
-
child.on('error', (err) => {
|
|
92
|
-
if (debug)
|
|
93
|
-
console.error(` [debug] find error: ${err.message}`);
|
|
94
|
-
resolve(results);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
90
|
+
return results;
|
|
97
91
|
}
|
|
98
92
|
function scanFile(filePath) {
|
|
99
93
|
const home = node_os_1.default.homedir();
|