cntx-ui 2.0.0 → 2.0.1
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/package.json
CHANGED
package/server.js
CHANGED
|
@@ -29,6 +29,7 @@ export class CntxServer {
|
|
|
29
29
|
this.CNTX_DIR = join(cwd, '.cntx');
|
|
30
30
|
this.CONFIG_FILE = join(this.CNTX_DIR, 'config.json');
|
|
31
31
|
this.BUNDLES_FILE = join(this.CNTX_DIR, 'bundles.json');
|
|
32
|
+
this.HIDDEN_FILES_CONFIG = join(this.CNTX_DIR, 'hidden-files.json');
|
|
32
33
|
this.IGNORE_FILE = join(cwd, '.cntxignore');
|
|
33
34
|
this.CURSOR_RULES_FILE = join(cwd, '.cursorrules');
|
|
34
35
|
|
|
@@ -37,11 +38,19 @@ export class CntxServer {
|
|
|
37
38
|
this.watchers = [];
|
|
38
39
|
this.clients = new Set();
|
|
39
40
|
this.isScanning = false;
|
|
41
|
+
|
|
42
|
+
this.hiddenFilesConfig = {
|
|
43
|
+
globalHidden: [], // Files hidden across all bundles
|
|
44
|
+
bundleSpecific: {}, // Files hidden per bundle: { bundleName: [filePaths] }
|
|
45
|
+
userIgnorePatterns: [], // User-added ignore patterns
|
|
46
|
+
disabledSystemPatterns: [] // System patterns the user disabled
|
|
47
|
+
};
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
init() {
|
|
43
51
|
if (!existsSync(this.CNTX_DIR)) mkdirSync(this.CNTX_DIR, { recursive: true });
|
|
44
52
|
this.loadConfig();
|
|
53
|
+
this.loadHiddenFilesConfig();
|
|
45
54
|
this.loadIgnorePatterns();
|
|
46
55
|
this.loadBundleStates();
|
|
47
56
|
this.startWatching();
|
|
@@ -75,21 +84,183 @@ export class CntxServer {
|
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
|
|
87
|
+
loadHiddenFilesConfig() {
|
|
88
|
+
if (existsSync(this.HIDDEN_FILES_CONFIG)) {
|
|
89
|
+
try {
|
|
90
|
+
const config = JSON.parse(readFileSync(this.HIDDEN_FILES_CONFIG, 'utf8'));
|
|
91
|
+
this.hiddenFilesConfig = { ...this.hiddenFilesConfig, ...config };
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.warn('Could not load hidden files config:', e.message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
saveHiddenFilesConfig() {
|
|
99
|
+
try {
|
|
100
|
+
writeFileSync(this.HIDDEN_FILES_CONFIG, JSON.stringify(this.hiddenFilesConfig, null, 2));
|
|
101
|
+
} catch (e) {
|
|
102
|
+
console.error('Failed to save hidden files config:', e.message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
isFileHidden(filePath, bundleName = null) {
|
|
107
|
+
// Check global hidden files
|
|
108
|
+
if (this.hiddenFilesConfig.globalHidden.includes(filePath)) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check bundle-specific hidden files
|
|
113
|
+
if (bundleName && this.hiddenFilesConfig.bundleSpecific[bundleName]) {
|
|
114
|
+
return this.hiddenFilesConfig.bundleSpecific[bundleName].includes(filePath);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
toggleFileVisibility(filePath, bundleName = null, forceHide = null) {
|
|
121
|
+
if (bundleName) {
|
|
122
|
+
// Bundle-specific hiding
|
|
123
|
+
if (!this.hiddenFilesConfig.bundleSpecific[bundleName]) {
|
|
124
|
+
this.hiddenFilesConfig.bundleSpecific[bundleName] = [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const bundleHidden = this.hiddenFilesConfig.bundleSpecific[bundleName];
|
|
128
|
+
const isCurrentlyHidden = bundleHidden.includes(filePath);
|
|
129
|
+
|
|
130
|
+
if (forceHide === null) {
|
|
131
|
+
// Toggle current state
|
|
132
|
+
if (isCurrentlyHidden) {
|
|
133
|
+
this.hiddenFilesConfig.bundleSpecific[bundleName] = bundleHidden.filter(f => f !== filePath);
|
|
134
|
+
} else {
|
|
135
|
+
bundleHidden.push(filePath);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
// Force to specific state
|
|
139
|
+
if (forceHide && !isCurrentlyHidden) {
|
|
140
|
+
bundleHidden.push(filePath);
|
|
141
|
+
} else if (!forceHide && isCurrentlyHidden) {
|
|
142
|
+
this.hiddenFilesConfig.bundleSpecific[bundleName] = bundleHidden.filter(f => f !== filePath);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
// Global hiding
|
|
147
|
+
const isCurrentlyHidden = this.hiddenFilesConfig.globalHidden.includes(filePath);
|
|
148
|
+
|
|
149
|
+
if (forceHide === null) {
|
|
150
|
+
// Toggle current state
|
|
151
|
+
if (isCurrentlyHidden) {
|
|
152
|
+
this.hiddenFilesConfig.globalHidden = this.hiddenFilesConfig.globalHidden.filter(f => f !== filePath);
|
|
153
|
+
} else {
|
|
154
|
+
this.hiddenFilesConfig.globalHidden.push(filePath);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
// Force to specific state
|
|
158
|
+
if (forceHide && !isCurrentlyHidden) {
|
|
159
|
+
this.hiddenFilesConfig.globalHidden.push(filePath);
|
|
160
|
+
} else if (!forceHide && isCurrentlyHidden) {
|
|
161
|
+
this.hiddenFilesConfig.globalHidden = this.hiddenFilesConfig.globalHidden.filter(f => f !== filePath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.saveHiddenFilesConfig();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
bulkToggleFileVisibility(filePaths, bundleName = null, forceHide = null) {
|
|
170
|
+
filePaths.forEach(filePath => {
|
|
171
|
+
this.toggleFileVisibility(filePath, bundleName, forceHide);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
addUserIgnorePattern(pattern) {
|
|
176
|
+
if (!this.hiddenFilesConfig.userIgnorePatterns.includes(pattern)) {
|
|
177
|
+
this.hiddenFilesConfig.userIgnorePatterns.push(pattern);
|
|
178
|
+
this.saveHiddenFilesConfig();
|
|
179
|
+
this.loadIgnorePatterns();
|
|
180
|
+
this.generateAllBundles();
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
removeUserIgnorePattern(pattern) {
|
|
187
|
+
const index = this.hiddenFilesConfig.userIgnorePatterns.indexOf(pattern);
|
|
188
|
+
if (index > -1) {
|
|
189
|
+
this.hiddenFilesConfig.userIgnorePatterns.splice(index, 1);
|
|
190
|
+
this.saveHiddenFilesConfig();
|
|
191
|
+
this.loadIgnorePatterns();
|
|
192
|
+
this.generateAllBundles();
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
toggleSystemIgnorePattern(pattern) {
|
|
199
|
+
const index = this.hiddenFilesConfig.disabledSystemPatterns.indexOf(pattern);
|
|
200
|
+
if (index > -1) {
|
|
201
|
+
// Re-enable the pattern
|
|
202
|
+
this.hiddenFilesConfig.disabledSystemPatterns.splice(index, 1);
|
|
203
|
+
} else {
|
|
204
|
+
// Disable the pattern
|
|
205
|
+
this.hiddenFilesConfig.disabledSystemPatterns.push(pattern);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
this.saveHiddenFilesConfig();
|
|
209
|
+
this.loadIgnorePatterns();
|
|
210
|
+
this.generateAllBundles();
|
|
211
|
+
}
|
|
212
|
+
|
|
78
213
|
loadIgnorePatterns() {
|
|
214
|
+
const systemPatterns = [
|
|
215
|
+
'**/.git/**',
|
|
216
|
+
'**/node_modules/**',
|
|
217
|
+
'**/.cntx/**'
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
// Read from .cntxignore file
|
|
221
|
+
let filePatterns = [];
|
|
79
222
|
if (existsSync(this.IGNORE_FILE)) {
|
|
80
|
-
|
|
223
|
+
filePatterns = readFileSync(this.IGNORE_FILE, 'utf8')
|
|
81
224
|
.split('\n')
|
|
82
225
|
.map(line => line.trim())
|
|
83
226
|
.filter(line => line && !line.startsWith('#'));
|
|
84
|
-
} else {
|
|
85
|
-
this.ignorePatterns = [
|
|
86
|
-
// Keep minimal patterns since we handle most stuff in shouldIgnoreAnything
|
|
87
|
-
'**/.git/**',
|
|
88
|
-
'**/node_modules/**',
|
|
89
|
-
'**/.cntx/**'
|
|
90
|
-
];
|
|
91
|
-
writeFileSync(this.IGNORE_FILE, this.ignorePatterns.join('\n'));
|
|
92
227
|
}
|
|
228
|
+
|
|
229
|
+
// Combine all patterns
|
|
230
|
+
this.ignorePatterns = [
|
|
231
|
+
// System patterns (filtered by disabled list)
|
|
232
|
+
...systemPatterns.filter(pattern =>
|
|
233
|
+
!this.hiddenFilesConfig.disabledSystemPatterns.includes(pattern)
|
|
234
|
+
),
|
|
235
|
+
// File patterns
|
|
236
|
+
...filePatterns.filter(pattern =>
|
|
237
|
+
!systemPatterns.includes(pattern) &&
|
|
238
|
+
!this.hiddenFilesConfig.userIgnorePatterns.includes(pattern)
|
|
239
|
+
),
|
|
240
|
+
// User-added patterns
|
|
241
|
+
...this.hiddenFilesConfig.userIgnorePatterns
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
// Update .cntxignore file with current patterns
|
|
245
|
+
const allPatterns = [
|
|
246
|
+
'# System patterns',
|
|
247
|
+
...systemPatterns.map(pattern =>
|
|
248
|
+
this.hiddenFilesConfig.disabledSystemPatterns.includes(pattern)
|
|
249
|
+
? `# ${pattern}`
|
|
250
|
+
: pattern
|
|
251
|
+
),
|
|
252
|
+
'',
|
|
253
|
+
'# User patterns',
|
|
254
|
+
...this.hiddenFilesConfig.userIgnorePatterns,
|
|
255
|
+
'',
|
|
256
|
+
'# File-specific patterns (edit manually)',
|
|
257
|
+
...filePatterns.filter(pattern =>
|
|
258
|
+
!systemPatterns.includes(pattern) &&
|
|
259
|
+
!this.hiddenFilesConfig.userIgnorePatterns.includes(pattern)
|
|
260
|
+
)
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
writeFileSync(this.IGNORE_FILE, allPatterns.join('\n'));
|
|
93
264
|
}
|
|
94
265
|
|
|
95
266
|
loadBundleStates() {
|
|
@@ -534,10 +705,15 @@ Add your specific project rules and preferences below:
|
|
|
534
705
|
console.log(`Generating bundle: ${name}`);
|
|
535
706
|
const allFiles = this.getAllFiles();
|
|
536
707
|
|
|
537
|
-
|
|
708
|
+
// Filter files by bundle patterns
|
|
709
|
+
let bundleFiles = allFiles.filter(file =>
|
|
538
710
|
bundle.patterns.some(pattern => this.matchesPattern(file, pattern))
|
|
539
711
|
);
|
|
540
712
|
|
|
713
|
+
// Remove hidden files
|
|
714
|
+
bundleFiles = bundleFiles.filter(file => !this.isFileHidden(file, name));
|
|
715
|
+
|
|
716
|
+
bundle.files = bundleFiles;
|
|
541
717
|
bundle.content = this.generateBundleXML(name, bundle.files);
|
|
542
718
|
bundle.changed = false;
|
|
543
719
|
bundle.lastGenerated = new Date().toISOString();
|
|
@@ -606,6 +782,53 @@ Add your specific project rules and preferences below:
|
|
|
606
782
|
.replace(/'/g, ''');
|
|
607
783
|
}
|
|
608
784
|
|
|
785
|
+
getFileStats(filePath) {
|
|
786
|
+
try {
|
|
787
|
+
const fullPath = join(this.CWD, filePath);
|
|
788
|
+
const stat = statSync(fullPath);
|
|
789
|
+
return {
|
|
790
|
+
size: stat.size,
|
|
791
|
+
mtime: stat.mtime
|
|
792
|
+
};
|
|
793
|
+
} catch (e) {
|
|
794
|
+
return {
|
|
795
|
+
size: 0,
|
|
796
|
+
mtime: new Date()
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
getFileListWithVisibility(bundleName = null) {
|
|
802
|
+
const allFiles = this.getAllFiles();
|
|
803
|
+
|
|
804
|
+
return allFiles.map(filePath => {
|
|
805
|
+
const fileStats = this.getFileStats(filePath);
|
|
806
|
+
const isGloballyHidden = this.hiddenFilesConfig.globalHidden.includes(filePath);
|
|
807
|
+
const bundleHidden = bundleName ? this.isFileHidden(filePath, bundleName) : false;
|
|
808
|
+
|
|
809
|
+
// Determine which bundles this file appears in
|
|
810
|
+
const inBundles = [];
|
|
811
|
+
this.bundles.forEach((bundle, name) => {
|
|
812
|
+
const matchesPattern = bundle.patterns.some(pattern => this.matchesPattern(filePath, pattern));
|
|
813
|
+
const notHidden = !this.isFileHidden(filePath, name);
|
|
814
|
+
if (matchesPattern && notHidden) {
|
|
815
|
+
inBundles.push(name);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
return {
|
|
820
|
+
path: filePath,
|
|
821
|
+
size: fileStats.size,
|
|
822
|
+
modified: fileStats.mtime,
|
|
823
|
+
visible: !isGloballyHidden && !bundleHidden,
|
|
824
|
+
globallyHidden: isGloballyHidden,
|
|
825
|
+
bundleHidden: bundleHidden,
|
|
826
|
+
inBundles: inBundles,
|
|
827
|
+
matchesIgnorePattern: this.shouldIgnoreFile(join(this.CWD, filePath))
|
|
828
|
+
};
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
|
|
609
832
|
startServer(port = 3333) {
|
|
610
833
|
const server = createServer((req, res) => {
|
|
611
834
|
const url = new URL(req.url, `http://localhost:${port}`);
|
|
@@ -705,7 +928,7 @@ Add your specific project rules and preferences below:
|
|
|
705
928
|
}
|
|
706
929
|
}
|
|
707
930
|
|
|
708
|
-
// API Routes
|
|
931
|
+
// API Routes
|
|
709
932
|
if (url.pathname === '/api/bundles') {
|
|
710
933
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
711
934
|
const bundleData = Array.from(this.bundles.entries()).map(([name, bundle]) => ({
|
|
@@ -865,6 +1088,167 @@ Add your specific project rules and preferences below:
|
|
|
865
1088
|
res.end('Method not allowed');
|
|
866
1089
|
}
|
|
867
1090
|
|
|
1091
|
+
} else if (url.pathname === '/api/hidden-files') {
|
|
1092
|
+
if (req.method === 'GET') {
|
|
1093
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1094
|
+
const stats = {
|
|
1095
|
+
totalFiles: this.getAllFiles().length,
|
|
1096
|
+
globallyHidden: this.hiddenFilesConfig.globalHidden.length,
|
|
1097
|
+
bundleSpecificHidden: this.hiddenFilesConfig.bundleSpecific,
|
|
1098
|
+
ignorePatterns: {
|
|
1099
|
+
system: [
|
|
1100
|
+
{ pattern: '**/.git/**', active: !this.hiddenFilesConfig.disabledSystemPatterns.includes('**/.git/**') },
|
|
1101
|
+
{ pattern: '**/node_modules/**', active: !this.hiddenFilesConfig.disabledSystemPatterns.includes('**/node_modules/**') },
|
|
1102
|
+
{ pattern: '**/.cntx/**', active: !this.hiddenFilesConfig.disabledSystemPatterns.includes('**/.cntx/**') }
|
|
1103
|
+
],
|
|
1104
|
+
user: this.hiddenFilesConfig.userIgnorePatterns,
|
|
1105
|
+
disabled: this.hiddenFilesConfig.disabledSystemPatterns
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
res.end(JSON.stringify(stats));
|
|
1109
|
+
} else if (req.method === 'POST') {
|
|
1110
|
+
let body = '';
|
|
1111
|
+
req.on('data', chunk => body += chunk);
|
|
1112
|
+
req.on('end', () => {
|
|
1113
|
+
try {
|
|
1114
|
+
const { action, filePath, filePaths, bundleName, forceHide } = JSON.parse(body);
|
|
1115
|
+
|
|
1116
|
+
if (action === 'toggle' && filePath) {
|
|
1117
|
+
this.toggleFileVisibility(filePath, bundleName, forceHide);
|
|
1118
|
+
} else if (action === 'bulk-toggle' && filePaths) {
|
|
1119
|
+
this.bulkToggleFileVisibility(filePaths, bundleName, forceHide);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
this.generateAllBundles();
|
|
1123
|
+
this.broadcastUpdate();
|
|
1124
|
+
|
|
1125
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1126
|
+
res.end(JSON.stringify({ success: true }));
|
|
1127
|
+
} catch (e) {
|
|
1128
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
1129
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
} else if (url.pathname === '/api/files-with-visibility') {
|
|
1135
|
+
const bundleName = url.searchParams.get('bundle');
|
|
1136
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1137
|
+
const files = this.getFileListWithVisibility(bundleName);
|
|
1138
|
+
res.end(JSON.stringify(files));
|
|
1139
|
+
|
|
1140
|
+
} else if (url.pathname === '/api/ignore-patterns') {
|
|
1141
|
+
if (req.method === 'GET') {
|
|
1142
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1143
|
+
|
|
1144
|
+
// Read file patterns
|
|
1145
|
+
let filePatterns = [];
|
|
1146
|
+
if (existsSync(this.IGNORE_FILE)) {
|
|
1147
|
+
filePatterns = readFileSync(this.IGNORE_FILE, 'utf8')
|
|
1148
|
+
.split('\n')
|
|
1149
|
+
.map(line => line.trim())
|
|
1150
|
+
.filter(line => line && !line.startsWith('#'));
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const systemPatterns = ['**/.git/**', '**/node_modules/**', '**/.cntx/**'];
|
|
1154
|
+
|
|
1155
|
+
const patterns = {
|
|
1156
|
+
system: systemPatterns.map(pattern => ({
|
|
1157
|
+
pattern,
|
|
1158
|
+
active: !this.hiddenFilesConfig.disabledSystemPatterns.includes(pattern)
|
|
1159
|
+
})),
|
|
1160
|
+
user: this.hiddenFilesConfig.userIgnorePatterns.map(pattern => ({ pattern, active: true })),
|
|
1161
|
+
file: filePatterns.filter(pattern =>
|
|
1162
|
+
!systemPatterns.includes(pattern) &&
|
|
1163
|
+
!this.hiddenFilesConfig.userIgnorePatterns.includes(pattern)
|
|
1164
|
+
).map(pattern => ({ pattern, active: true }))
|
|
1165
|
+
};
|
|
1166
|
+
res.end(JSON.stringify(patterns));
|
|
1167
|
+
|
|
1168
|
+
} else if (req.method === 'POST') {
|
|
1169
|
+
let body = '';
|
|
1170
|
+
req.on('data', chunk => body += chunk);
|
|
1171
|
+
req.on('end', () => {
|
|
1172
|
+
try {
|
|
1173
|
+
const { action, pattern } = JSON.parse(body);
|
|
1174
|
+
let success = false;
|
|
1175
|
+
|
|
1176
|
+
switch (action) {
|
|
1177
|
+
case 'add':
|
|
1178
|
+
success = this.addUserIgnorePattern(pattern);
|
|
1179
|
+
break;
|
|
1180
|
+
case 'remove':
|
|
1181
|
+
success = this.removeUserIgnorePattern(pattern);
|
|
1182
|
+
break;
|
|
1183
|
+
case 'toggle-system':
|
|
1184
|
+
this.toggleSystemIgnorePattern(pattern);
|
|
1185
|
+
success = true;
|
|
1186
|
+
break;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
this.broadcastUpdate();
|
|
1190
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1191
|
+
res.end(JSON.stringify({ success }));
|
|
1192
|
+
} catch (e) {
|
|
1193
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
1194
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
} else if (url.pathname === '/api/bundle-visibility-stats') {
|
|
1200
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1201
|
+
const stats = {};
|
|
1202
|
+
|
|
1203
|
+
this.bundles.forEach((bundle, bundleName) => {
|
|
1204
|
+
const allFiles = this.getAllFiles();
|
|
1205
|
+
const matchingFiles = allFiles.filter(file =>
|
|
1206
|
+
bundle.patterns.some(pattern => this.matchesPattern(file, pattern))
|
|
1207
|
+
);
|
|
1208
|
+
|
|
1209
|
+
const visibleFiles = matchingFiles.filter(file => !this.isFileHidden(file, bundleName));
|
|
1210
|
+
const hiddenFiles = matchingFiles.length - visibleFiles.length;
|
|
1211
|
+
|
|
1212
|
+
stats[bundleName] = {
|
|
1213
|
+
total: matchingFiles.length,
|
|
1214
|
+
visible: visibleFiles.length,
|
|
1215
|
+
hidden: hiddenFiles,
|
|
1216
|
+
patterns: bundle.patterns
|
|
1217
|
+
};
|
|
1218
|
+
});
|
|
1219
|
+
|
|
1220
|
+
res.end(JSON.stringify(stats));
|
|
1221
|
+
|
|
1222
|
+
} else if (url.pathname === '/api/reset-hidden-files') {
|
|
1223
|
+
if (req.method === 'POST') {
|
|
1224
|
+
let body = '';
|
|
1225
|
+
req.on('data', chunk => body += chunk);
|
|
1226
|
+
req.on('end', () => {
|
|
1227
|
+
try {
|
|
1228
|
+
const { scope, bundleName } = JSON.parse(body);
|
|
1229
|
+
|
|
1230
|
+
if (scope === 'global') {
|
|
1231
|
+
this.hiddenFilesConfig.globalHidden = [];
|
|
1232
|
+
} else if (scope === 'bundle' && bundleName) {
|
|
1233
|
+
delete this.hiddenFilesConfig.bundleSpecific[bundleName];
|
|
1234
|
+
} else if (scope === 'all') {
|
|
1235
|
+
this.hiddenFilesConfig.globalHidden = [];
|
|
1236
|
+
this.hiddenFilesConfig.bundleSpecific = {};
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
this.saveHiddenFilesConfig();
|
|
1240
|
+
this.generateAllBundles();
|
|
1241
|
+
this.broadcastUpdate();
|
|
1242
|
+
|
|
1243
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1244
|
+
res.end(JSON.stringify({ success: true }));
|
|
1245
|
+
} catch (e) {
|
|
1246
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
1247
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
|
|
868
1252
|
} else {
|
|
869
1253
|
res.writeHead(404);
|
|
870
1254
|
res.end('Not found');
|