ccperm 1.4.1 → 1.4.2

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.
@@ -15,7 +15,7 @@ function startInteractive(merged, results) {
15
15
  resolve();
16
16
  return;
17
17
  }
18
- const state = { view: 'list', cursor: 0, scrollOffset: 0, selectedProject: 0 };
18
+ const state = { view: 'list', cursor: 0, scrollOffset: 0, selectedProject: 0, detailScroll: 0 };
19
19
  node_readline_1.default.emitKeypressEvents(process.stdin);
20
20
  if (process.stdin.isTTY)
21
21
  process.stdin.setRawMode(true);
@@ -60,6 +60,7 @@ function startInteractive(merged, results) {
60
60
  }
61
61
  else if (key.name === 'return') {
62
62
  state.selectedProject = state.cursor;
63
+ state.detailScroll = 0;
63
64
  state.view = 'detail';
64
65
  }
65
66
  }
@@ -67,6 +68,13 @@ function startInteractive(merged, results) {
67
68
  // detail view
68
69
  if (key.name === 'escape' || key.name === 'backspace') {
69
70
  state.view = 'list';
71
+ state.detailScroll = 0;
72
+ }
73
+ else if (key.name === 'up') {
74
+ state.detailScroll = Math.max(0, state.detailScroll - 1);
75
+ }
76
+ else if (key.name === 'down') {
77
+ state.detailScroll++;
70
78
  }
71
79
  }
72
80
  render();
@@ -119,10 +127,10 @@ function renderList(state, withPerms, emptyCount) {
119
127
  process.stdout.write(lines.join('\n') + '\n');
120
128
  }
121
129
  function renderDetail(state, withPerms, results) {
130
+ const rows = process.stdout.rows || 24;
122
131
  const project = withPerms[state.selectedProject];
123
132
  if (!project)
124
133
  return;
125
- // find ScanResults belonging to this project
126
134
  const projectResults = results.filter((r) => {
127
135
  const idx = r.display.indexOf('/.claude/');
128
136
  const dir = idx >= 0 ? r.display.slice(0, idx) : r.display;
@@ -130,21 +138,37 @@ function renderDetail(state, withPerms, results) {
130
138
  const projDir = projIdx >= 0 ? project.display.slice(0, projIdx) : project.display;
131
139
  return dir === projDir;
132
140
  });
133
- const lines = [];
134
- lines.push(` ${colors_js_1.CYAN}${colors_js_1.BOLD}${project.shortName}${colors_js_1.NC} ${colors_js_1.DIM}(${project.totalCount} permissions)${colors_js_1.NC}\n`);
141
+ // build content lines
142
+ const content = [];
135
143
  for (const result of projectResults) {
136
144
  if (result.totalCount === 0)
137
145
  continue;
138
- lines.push(` ${colors_js_1.DIM}${result.display}${colors_js_1.NC}`);
146
+ // short filename: settings.local.json
147
+ const fileName = result.display.replace(/.*\/\.claude\//, '');
148
+ content.push(` ${colors_js_1.CYAN}${fileName}${colors_js_1.NC} ${colors_js_1.DIM}(${result.totalCount})${colors_js_1.NC}`);
139
149
  for (const group of result.groups) {
140
- lines.push(` ${colors_js_1.YELLOW}${group.category}${colors_js_1.NC} ${colors_js_1.DIM}(${group.items.length})${colors_js_1.NC}`);
150
+ content.push(` ${colors_js_1.YELLOW}${group.category}${colors_js_1.NC} ${colors_js_1.DIM}(${group.items.length})${colors_js_1.NC}`);
141
151
  for (const item of group.items) {
142
- lines.push(` ${colors_js_1.DIM}${item.name}${colors_js_1.NC}`);
152
+ content.push(` ${colors_js_1.DIM}${item.name}${colors_js_1.NC}`);
143
153
  }
144
154
  }
145
- lines.push('');
155
+ content.push(` ${colors_js_1.DIM}${''.repeat(40)}${colors_js_1.NC}`);
146
156
  }
147
- lines.push(` ${colors_js_1.DIM}[Esc/Backspace] back [q] quit${colors_js_1.NC}`);
157
+ // header + footer take space
158
+ const headerLines = 3;
159
+ const footerLines = 2;
160
+ const visibleRows = Math.max(1, rows - headerLines - footerLines);
161
+ const maxScroll = Math.max(0, content.length - visibleRows);
162
+ if (state.detailScroll > maxScroll)
163
+ state.detailScroll = maxScroll;
164
+ const visible = content.slice(state.detailScroll, state.detailScroll + visibleRows);
165
+ const scrollPct = content.length <= visibleRows ? '' : ` ${colors_js_1.DIM}${state.detailScroll + visibleRows}/${content.length}${colors_js_1.NC}`;
166
+ const lines = [];
167
+ lines.push(` ${colors_js_1.CYAN}${colors_js_1.BOLD}${project.shortName}${colors_js_1.NC} ${colors_js_1.DIM}(${project.totalCount} permissions)${colors_js_1.NC}${scrollPct}`);
168
+ lines.push('');
169
+ lines.push(...visible);
170
+ lines.push('');
171
+ lines.push(` ${colors_js_1.DIM}[↑↓] scroll [Esc] back [q] quit${colors_js_1.NC}`);
148
172
  process.stdout.write(lines.join('\n') + '\n');
149
173
  }
150
174
  function pad(s, n) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccperm",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Audit Claude Code permissions across all your projects",
5
5
  "bin": {
6
6
  "ccperm": "bin/ccperm.js"