ccperm 1.4.3 → 1.5.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/interactive.js +60 -20
- package/package.json +1 -1
package/dist/interactive.js
CHANGED
|
@@ -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, detailScroll: 0 };
|
|
18
|
+
const state = { view: 'list', cursor: 0, scrollOffset: 0, selectedProject: 0, detailCursor: 0, detailScroll: 0, expanded: new Set() };
|
|
19
19
|
node_readline_1.default.emitKeypressEvents(process.stdin);
|
|
20
20
|
if (process.stdin.isTTY)
|
|
21
21
|
process.stdin.setRawMode(true);
|
|
@@ -60,7 +60,9 @@ function startInteractive(merged, results) {
|
|
|
60
60
|
}
|
|
61
61
|
else if (key.name === 'return') {
|
|
62
62
|
state.selectedProject = state.cursor;
|
|
63
|
+
state.detailCursor = 0;
|
|
63
64
|
state.detailScroll = 0;
|
|
65
|
+
state.expanded = new Set();
|
|
64
66
|
state.view = 'detail';
|
|
65
67
|
}
|
|
66
68
|
}
|
|
@@ -68,13 +70,18 @@ function startInteractive(merged, results) {
|
|
|
68
70
|
// detail view
|
|
69
71
|
if (key.name === 'escape' || key.name === 'backspace') {
|
|
70
72
|
state.view = 'list';
|
|
73
|
+
state.detailCursor = 0;
|
|
71
74
|
state.detailScroll = 0;
|
|
72
75
|
}
|
|
73
76
|
else if (key.name === 'up') {
|
|
74
|
-
state.
|
|
77
|
+
state.detailCursor = Math.max(0, state.detailCursor - 1);
|
|
75
78
|
}
|
|
76
79
|
else if (key.name === 'down') {
|
|
77
|
-
state.
|
|
80
|
+
state.detailCursor++;
|
|
81
|
+
}
|
|
82
|
+
else if (key.name === 'return') {
|
|
83
|
+
// toggle handled in renderDetail via detailRows
|
|
84
|
+
state._toggle = true;
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
render();
|
|
@@ -128,6 +135,7 @@ function renderList(state, withPerms, emptyCount) {
|
|
|
128
135
|
}
|
|
129
136
|
function renderDetail(state, withPerms, results) {
|
|
130
137
|
const rows = process.stdout.rows || 24;
|
|
138
|
+
const cols = process.stdout.columns || 80;
|
|
131
139
|
const project = withPerms[state.selectedProject];
|
|
132
140
|
if (!project)
|
|
133
141
|
return;
|
|
@@ -138,37 +146,69 @@ function renderDetail(state, withPerms, results) {
|
|
|
138
146
|
const projDir = projIdx >= 0 ? project.display.slice(0, projIdx) : project.display;
|
|
139
147
|
return dir === projDir;
|
|
140
148
|
});
|
|
141
|
-
// build
|
|
142
|
-
const
|
|
149
|
+
// build navigable rows
|
|
150
|
+
const navRows = [];
|
|
143
151
|
for (const result of projectResults) {
|
|
144
152
|
if (result.totalCount === 0)
|
|
145
153
|
continue;
|
|
146
|
-
// short filename: settings.local.json
|
|
147
154
|
const fileName = result.display.replace(/.*\/\.claude\//, '');
|
|
148
|
-
|
|
155
|
+
navRows.push({ line: ` ${colors_js_1.CYAN}${fileName}${colors_js_1.NC} ${colors_js_1.DIM}(${result.totalCount})${colors_js_1.NC}` });
|
|
149
156
|
for (const group of result.groups) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
157
|
+
const key = `${result.path}:${group.category}`;
|
|
158
|
+
const isOpen = state.expanded.has(key);
|
|
159
|
+
const arrow = isOpen ? '▾' : '▸';
|
|
160
|
+
navRows.push({ line: ` ${colors_js_1.YELLOW}${arrow} ${group.category}${colors_js_1.NC} ${colors_js_1.DIM}(${group.items.length})${colors_js_1.NC}`, key });
|
|
161
|
+
if (isOpen) {
|
|
162
|
+
const maxLen = cols - 10;
|
|
163
|
+
for (const item of group.items) {
|
|
164
|
+
const name = item.name.length > maxLen ? item.name.slice(0, maxLen - 1) + '…' : item.name;
|
|
165
|
+
navRows.push({ line: ` ${colors_js_1.DIM}${name}${colors_js_1.NC}` });
|
|
166
|
+
}
|
|
153
167
|
}
|
|
154
168
|
}
|
|
155
|
-
content.push(` ${colors_js_1.DIM}${'─'.repeat(40)}${colors_js_1.NC}`);
|
|
156
169
|
}
|
|
157
|
-
//
|
|
170
|
+
// handle toggle
|
|
171
|
+
if (state._toggle) {
|
|
172
|
+
delete state._toggle;
|
|
173
|
+
const row = navRows[state.detailCursor];
|
|
174
|
+
if (row?.key) {
|
|
175
|
+
if (state.expanded.has(row.key))
|
|
176
|
+
state.expanded.delete(row.key);
|
|
177
|
+
else
|
|
178
|
+
state.expanded.add(row.key);
|
|
179
|
+
// re-render needed — will happen on next render() call
|
|
180
|
+
renderDetail(state, withPerms, results);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// clamp cursor
|
|
185
|
+
if (state.detailCursor >= navRows.length)
|
|
186
|
+
state.detailCursor = Math.max(0, navRows.length - 1);
|
|
187
|
+
// scroll
|
|
158
188
|
const headerLines = 3;
|
|
159
189
|
const footerLines = 2;
|
|
160
190
|
const visibleRows = Math.max(1, rows - headerLines - footerLines);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
191
|
+
if (state.detailCursor < state.detailScroll)
|
|
192
|
+
state.detailScroll = state.detailCursor;
|
|
193
|
+
if (state.detailCursor >= state.detailScroll + visibleRows)
|
|
194
|
+
state.detailScroll = state.detailCursor - visibleRows + 1;
|
|
195
|
+
const visible = navRows.slice(state.detailScroll, state.detailScroll + visibleRows);
|
|
166
196
|
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}
|
|
197
|
+
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}`);
|
|
168
198
|
lines.push('');
|
|
169
|
-
|
|
199
|
+
for (let i = 0; i < visible.length; i++) {
|
|
200
|
+
const globalIdx = state.detailScroll + i;
|
|
201
|
+
const isCursor = globalIdx === state.detailCursor;
|
|
202
|
+
const row = visible[i];
|
|
203
|
+
if (isCursor) {
|
|
204
|
+
lines.push(row.line.replace(/^ /, `${colors_js_1.CYAN}> `));
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
lines.push(row.line);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
170
210
|
lines.push('');
|
|
171
|
-
lines.push(` ${colors_js_1.DIM}[↑↓]
|
|
211
|
+
lines.push(` ${colors_js_1.DIM}[↑↓] navigate [Enter] expand/collapse [Esc] back [q] quit${colors_js_1.NC}`);
|
|
172
212
|
process.stdout.write(lines.join('\n') + '\n');
|
|
173
213
|
}
|
|
174
214
|
function pad(s, n) {
|