ccperm 1.7.0 → 1.8.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/aggregator.js +11 -17
- package/dist/cli.js +3 -3
- package/dist/interactive.js +18 -26
- package/dist/renderer.js +9 -8
- package/package.json +1 -1
package/dist/aggregator.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.shortPath = shortPath;
|
|
4
4
|
exports.projectDir = projectDir;
|
|
5
|
-
exports.
|
|
5
|
+
exports.toFileEntries = toFileEntries;
|
|
6
6
|
exports.summarize = summarize;
|
|
7
7
|
function shortPath(display) {
|
|
8
8
|
const m = display.match(/\/([^/]+)\/\.claude\//);
|
|
@@ -12,25 +12,19 @@ function projectDir(display) {
|
|
|
12
12
|
const idx = display.indexOf('/.claude/');
|
|
13
13
|
return idx >= 0 ? display.slice(0, idx) : display;
|
|
14
14
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const dir = projectDir(r.display);
|
|
19
|
-
let merged = map.get(dir);
|
|
20
|
-
if (!merged) {
|
|
21
|
-
const name = r.isGlobal ? 'GLOBAL' : shortPath(r.display);
|
|
22
|
-
merged = { display: r.display, shortName: name, totalCount: 0, groups: new Map(), isGlobal: r.isGlobal };
|
|
23
|
-
map.set(dir, merged);
|
|
24
|
-
}
|
|
25
|
-
merged.totalCount += r.totalCount;
|
|
15
|
+
function toFileEntries(results) {
|
|
16
|
+
return results.map((r) => {
|
|
17
|
+
const groups = new Map();
|
|
26
18
|
for (const g of r.groups) {
|
|
27
|
-
|
|
19
|
+
groups.set(g.category, g.items.length);
|
|
28
20
|
}
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
const fileType = r.isGlobal ? 'global' : r.display.includes('settings.local.json') ? 'local' : 'shared';
|
|
22
|
+
const name = r.isGlobal ? 'GLOBAL' : shortPath(r.display);
|
|
23
|
+
return { display: r.display, shortName: name, totalCount: r.totalCount, groups, isGlobal: r.isGlobal, fileType };
|
|
24
|
+
});
|
|
31
25
|
}
|
|
32
26
|
function summarize(results) {
|
|
33
|
-
const
|
|
27
|
+
const dirs = new Set(results.map((r) => projectDir(r.display)));
|
|
34
28
|
const categoryTotals = new Map();
|
|
35
29
|
for (const r of results) {
|
|
36
30
|
for (const group of r.groups) {
|
|
@@ -41,7 +35,7 @@ function summarize(results) {
|
|
|
41
35
|
const projectsEmpty = results.filter((r) => r.totalCount === 0).length;
|
|
42
36
|
const totalPerms = [...categoryTotals.values()].reduce((a, b) => a + b, 0);
|
|
43
37
|
return {
|
|
44
|
-
totalProjects:
|
|
38
|
+
totalProjects: dirs.size,
|
|
45
39
|
projectsWithPerms,
|
|
46
40
|
projectsEmpty,
|
|
47
41
|
totalPerms,
|
package/dist/cli.js
CHANGED
|
@@ -88,17 +88,17 @@ async function main() {
|
|
|
88
88
|
}
|
|
89
89
|
console.log(` ${colors_js_1.GREEN}✔${colors_js_1.NC} Found ${colors_js_1.CYAN}${files.length}${colors_js_1.NC} settings files\n`);
|
|
90
90
|
const results = files.map(scanner_js_1.scanFile).filter((r) => r !== null);
|
|
91
|
-
const
|
|
91
|
+
const entries = (0, aggregator_js_1.toFileEntries)(results);
|
|
92
92
|
const summary = (0, aggregator_js_1.summarize)(results);
|
|
93
93
|
if (!isStatic) {
|
|
94
|
-
await (0, interactive_js_1.startInteractive)(
|
|
94
|
+
await (0, interactive_js_1.startInteractive)(entries, results);
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
if (isVerbose) {
|
|
98
98
|
(0, renderer_js_1.printVerbose)(results, summary);
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
101
|
-
(0, renderer_js_1.printCompact)(
|
|
101
|
+
(0, renderer_js_1.printCompact)(entries, summary);
|
|
102
102
|
}
|
|
103
103
|
(0, renderer_js_1.printFooter)(summary);
|
|
104
104
|
if (args.includes('--fix')) {
|
package/dist/interactive.js
CHANGED
|
@@ -116,7 +116,7 @@ function renderList(state, withPerms, emptyCount) {
|
|
|
116
116
|
const cats = ['Bash', 'WebFetch', 'MCP', 'Tools'];
|
|
117
117
|
const catsPresent = cats.filter((c) => withPerms.some((r) => r.groups.has(c)));
|
|
118
118
|
const catColWidth = catsPresent.length * 7;
|
|
119
|
-
const nameWidths = withPerms.map((r) => r.
|
|
119
|
+
const nameWidths = withPerms.map((r) => r.shortName.length + 2);
|
|
120
120
|
const nameWidth = Math.min(Math.max(...nameWidths, 7), inner - catColWidth - 8);
|
|
121
121
|
const hasGlobalSep = withPerms.some((r) => r.isGlobal) && withPerms.some((r) => !r.isGlobal);
|
|
122
122
|
// box takes: top(1) + header(2) + sep(1) + content + globalSep?(1) + emptyLine?(1) + bottom(1)
|
|
@@ -136,7 +136,8 @@ function renderList(state, withPerms, emptyCount) {
|
|
|
136
136
|
for (let i = state.scrollOffset; i < end; i++) {
|
|
137
137
|
const r = withPerms[i];
|
|
138
138
|
const isCursor = i === state.cursor;
|
|
139
|
-
const
|
|
139
|
+
const typeLabel = r.isGlobal ? '' : r.fileType === 'local' ? ' ˡ' : ' ˢ';
|
|
140
|
+
const displayName = r.isGlobal ? `★ ${r.shortName}` : `${r.shortName}${typeLabel}`;
|
|
140
141
|
const truncName = displayName.length > nameWidth ? displayName.slice(0, nameWidth - 1) + '…' : displayName;
|
|
141
142
|
const marker = isCursor ? `${colors_js_1.CYAN}▸ ` : ' ';
|
|
142
143
|
const nameStyle = isCursor ? `${colors_js_1.BOLD}` : r.isGlobal ? `${colors_js_1.YELLOW}` : `${colors_js_1.DIM}`;
|
|
@@ -167,31 +168,21 @@ function renderDetail(state, withPerms, results) {
|
|
|
167
168
|
const project = withPerms[state.selectedProject];
|
|
168
169
|
if (!project)
|
|
169
170
|
return;
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const projIdx = project.display.indexOf('/.claude/');
|
|
174
|
-
const projDir = projIdx >= 0 ? project.display.slice(0, projIdx) : project.display;
|
|
175
|
-
return dir === projDir;
|
|
176
|
-
});
|
|
171
|
+
const fileResult = results.find((r) => r.display === project.display);
|
|
172
|
+
if (!fileResult || fileResult.totalCount === 0)
|
|
173
|
+
return;
|
|
177
174
|
// build navigable rows
|
|
178
175
|
const navRows = [];
|
|
179
|
-
for (const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
navRows.push({ text: `${colors_js_1.
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (isOpen) {
|
|
190
|
-
const maxLen = w - 12;
|
|
191
|
-
for (const item of group.items) {
|
|
192
|
-
const name = item.name.length > maxLen ? item.name.slice(0, maxLen - 1) + '…' : item.name;
|
|
193
|
-
navRows.push({ text: ` ${colors_js_1.DIM}${name}${colors_js_1.NC}` });
|
|
194
|
-
}
|
|
176
|
+
for (const group of fileResult.groups) {
|
|
177
|
+
const key = `${fileResult.path}:${group.category}`;
|
|
178
|
+
const isOpen = state.expanded.has(key);
|
|
179
|
+
const arrow = isOpen ? '▾' : '▸';
|
|
180
|
+
navRows.push({ text: `${colors_js_1.YELLOW}${arrow} ${group.category}${colors_js_1.NC} ${colors_js_1.DIM}(${group.items.length})${colors_js_1.NC}`, key });
|
|
181
|
+
if (isOpen) {
|
|
182
|
+
const maxLen = w - 12;
|
|
183
|
+
for (const item of group.items) {
|
|
184
|
+
const name = item.name.length > maxLen ? item.name.slice(0, maxLen - 1) + '…' : item.name;
|
|
185
|
+
navRows.push({ text: ` ${colors_js_1.DIM}${name}${colors_js_1.NC}` });
|
|
195
186
|
}
|
|
196
187
|
}
|
|
197
188
|
}
|
|
@@ -219,7 +210,8 @@ function renderDetail(state, withPerms, results) {
|
|
|
219
210
|
const visible = navRows.slice(state.detailScroll, state.detailScroll + visibleRows);
|
|
220
211
|
const scrollInfo = navRows.length > visibleRows ? `${state.detailCursor + 1}/${navRows.length}` : '';
|
|
221
212
|
const lines = [];
|
|
222
|
-
|
|
213
|
+
const typeTag = project.fileType === 'global' ? 'global' : project.fileType;
|
|
214
|
+
lines.push(boxTop(`${project.shortName} (${typeTag}) ${project.totalCount} permissions`, scrollInfo, w));
|
|
223
215
|
for (let i = 0; i < visible.length; i++) {
|
|
224
216
|
const globalIdx = state.detailScroll + i;
|
|
225
217
|
const isCursor = globalIdx === state.detailCursor;
|
package/dist/renderer.js
CHANGED
|
@@ -11,15 +11,15 @@ function rpad(s, n) {
|
|
|
11
11
|
const str = String(s);
|
|
12
12
|
return str.length >= n ? str : ' '.repeat(n - str.length) + str;
|
|
13
13
|
}
|
|
14
|
-
function printCompact(
|
|
14
|
+
function printCompact(entries, summary) {
|
|
15
15
|
const cats = ['Bash', 'WebFetch', 'MCP', 'Tools'];
|
|
16
|
-
const catsPresent = cats.filter((c) =>
|
|
17
|
-
const globals =
|
|
18
|
-
const projects =
|
|
16
|
+
const catsPresent = cats.filter((c) => entries.some((r) => r.groups.has(c)));
|
|
17
|
+
const globals = entries.filter((r) => r.totalCount > 0 && r.isGlobal).sort((a, b) => b.totalCount - a.totalCount);
|
|
18
|
+
const projects = entries.filter((r) => r.totalCount > 0 && !r.isGlobal).sort((a, b) => b.totalCount - a.totalCount);
|
|
19
19
|
const withPerms = [...globals, ...projects];
|
|
20
|
-
const emptyCount =
|
|
20
|
+
const emptyCount = entries.filter((r) => r.totalCount === 0).length;
|
|
21
21
|
// header
|
|
22
|
-
const nameWidths = withPerms.map((r) => r.
|
|
22
|
+
const nameWidths = withPerms.map((r) => r.shortName.length + 2);
|
|
23
23
|
const nameWidth = Math.min(Math.max(...nameWidths, 7), 40);
|
|
24
24
|
const header = ` ${colors_js_1.DIM}${pad('PROJECT', nameWidth)} ${catsPresent.map((c) => rpad(c, 5)).join(' ')} TOTAL${colors_js_1.NC}`;
|
|
25
25
|
console.log(header);
|
|
@@ -27,7 +27,8 @@ function printCompact(merged, summary) {
|
|
|
27
27
|
// rows
|
|
28
28
|
for (let i = 0; i < withPerms.length; i++) {
|
|
29
29
|
const result = withPerms[i];
|
|
30
|
-
const
|
|
30
|
+
const typeLabel = result.isGlobal ? '' : result.fileType === 'local' ? ' ˡ' : ' ˢ';
|
|
31
|
+
const displayName = result.isGlobal ? `★ ${result.shortName}` : `${result.shortName}${typeLabel}`;
|
|
31
32
|
const truncName = displayName.length > nameWidth ? displayName.slice(0, nameWidth - 1) + '…' : displayName;
|
|
32
33
|
const nameStyle = result.isGlobal ? `${colors_js_1.YELLOW}` : `${colors_js_1.DIM}`;
|
|
33
34
|
const nameCol = ` ${nameStyle}${pad(truncName, nameWidth)}${colors_js_1.NC}`;
|
|
@@ -68,5 +69,5 @@ function printVerbose(results, summary) {
|
|
|
68
69
|
function printFooter(summary) {
|
|
69
70
|
console.log(`\n ${colors_js_1.DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors_js_1.NC}`);
|
|
70
71
|
const catSummary = [...summary.categoryTotals.entries()].map(([k, v]) => `${k}: ${colors_js_1.BOLD}${v}${colors_js_1.NC}${colors_js_1.DIM}`).join(' ');
|
|
71
|
-
console.log(` ${colors_js_1.BOLD}${summary.
|
|
72
|
+
console.log(` ${colors_js_1.BOLD}${summary.totalProjects}${colors_js_1.NC} projects ${colors_js_1.BOLD}${summary.totalPerms}${colors_js_1.NC} permissions ${colors_js_1.DIM}(${catSummary})${colors_js_1.NC}\n`);
|
|
72
73
|
}
|