@feardread/fear 1.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/FEAR.js +459 -0
- package/FEARServer.js +280 -0
- package/controllers/agent.js +438 -0
- package/controllers/auth/index.js +345 -0
- package/controllers/auth/token.js +50 -0
- package/controllers/blog.js +105 -0
- package/controllers/brand.js +10 -0
- package/controllers/cart.js +425 -0
- package/controllers/category.js +9 -0
- package/controllers/coupon.js +63 -0
- package/controllers/crud/crud.js +508 -0
- package/controllers/crud/index.js +36 -0
- package/controllers/email.js +34 -0
- package/controllers/enquiry.js +65 -0
- package/controllers/events.js +9 -0
- package/controllers/order.js +125 -0
- package/controllers/payment.js +31 -0
- package/controllers/product.js +147 -0
- package/controllers/review.js +247 -0
- package/controllers/tag.js +10 -0
- package/controllers/task.js +10 -0
- package/controllers/upload.js +41 -0
- package/controllers/user.js +401 -0
- package/index.js +7 -0
- package/libs/agent/index.js +561 -0
- package/libs/agent/modules/ai/ai.js +285 -0
- package/libs/agent/modules/ai/chat.js +518 -0
- package/libs/agent/modules/ai/config.js +688 -0
- package/libs/agent/modules/ai/operations.js +787 -0
- package/libs/agent/modules/analyze/api.js +546 -0
- package/libs/agent/modules/analyze/dorks.js +395 -0
- package/libs/agent/modules/ccard/README.md +454 -0
- package/libs/agent/modules/ccard/audit.js +479 -0
- package/libs/agent/modules/ccard/checker.js +674 -0
- package/libs/agent/modules/ccard/payment-processors.json +16 -0
- package/libs/agent/modules/ccard/validator.js +629 -0
- package/libs/agent/modules/code/analyzer.js +303 -0
- package/libs/agent/modules/code/jquery.js +1093 -0
- package/libs/agent/modules/code/react.js +1536 -0
- package/libs/agent/modules/code/refactor.js +499 -0
- package/libs/agent/modules/crypto/exchange.js +564 -0
- package/libs/agent/modules/net/proxy.js +409 -0
- package/libs/agent/modules/security/cve.js +442 -0
- package/libs/agent/modules/security/monitor.js +360 -0
- package/libs/agent/modules/security/scanner.js +300 -0
- package/libs/agent/modules/security/vulnerability.js +506 -0
- package/libs/agent/modules/security/web.js +465 -0
- package/libs/agent/modules/utils/browser.js +492 -0
- package/libs/agent/modules/utils/colorizer.js +285 -0
- package/libs/agent/modules/utils/manager.js +478 -0
- package/libs/cloud/index.js +228 -0
- package/libs/config/db.js +21 -0
- package/libs/config/validator.js +82 -0
- package/libs/db/index.js +318 -0
- package/libs/emailer/imap.js +126 -0
- package/libs/emailer/info.js +41 -0
- package/libs/emailer/smtp.js +77 -0
- package/libs/handler/async.js +3 -0
- package/libs/handler/error.js +66 -0
- package/libs/handler/index.js +161 -0
- package/libs/logger/index.js +49 -0
- package/libs/logger/morgan.js +24 -0
- package/libs/passport/passport.js +109 -0
- package/libs/search/api.js +384 -0
- package/libs/search/features.js +219 -0
- package/libs/search/service.js +64 -0
- package/libs/swagger/config.js +18 -0
- package/libs/swagger/index.js +35 -0
- package/libs/validator/index.js +254 -0
- package/models/blog.js +31 -0
- package/models/brand.js +12 -0
- package/models/cart.js +14 -0
- package/models/category.js +11 -0
- package/models/coupon.js +9 -0
- package/models/customer.js +0 -0
- package/models/enquiry.js +29 -0
- package/models/events.js +13 -0
- package/models/order.js +94 -0
- package/models/product.js +32 -0
- package/models/review.js +14 -0
- package/models/tag.js +10 -0
- package/models/task.js +11 -0
- package/models/user.js +68 -0
- package/package.json +12 -0
- package/routes/agent.js +615 -0
- package/routes/auth.js +13 -0
- package/routes/blog.js +19 -0
- package/routes/brand.js +15 -0
- package/routes/cart.js +105 -0
- package/routes/category.js +16 -0
- package/routes/coupon.js +15 -0
- package/routes/enquiry.js +14 -0
- package/routes/events.js +16 -0
- package/routes/mail.js +170 -0
- package/routes/order.js +19 -0
- package/routes/product.js +22 -0
- package/routes/review.js +11 -0
- package/routes/task.js +12 -0
- package/routes/user.js +17 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const colorizer = require('../utils/colorizer');
|
|
6
|
+
|
|
7
|
+
const FileBrowser = function () {
|
|
8
|
+
this.currentPath = process.cwd();
|
|
9
|
+
this.bookmarks = new Map();
|
|
10
|
+
this.history = [];
|
|
11
|
+
this.historyIndex = -1;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
FileBrowser.prototype = {
|
|
15
|
+
// List files and directories
|
|
16
|
+
async list(args) {
|
|
17
|
+
const targetPath = args.length > 0 ? args.join(' ') : this.currentPath;
|
|
18
|
+
const fullPath = path.resolve(this.currentPath, targetPath);
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const stats = await fs.stat(fullPath);
|
|
22
|
+
|
|
23
|
+
if (!stats.isDirectory()) {
|
|
24
|
+
console.log(colorizer.error('Not a directory: ' + fullPath));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const items = await fs.readdir(fullPath, { withFileTypes: true });
|
|
29
|
+
|
|
30
|
+
console.log(colorizer.section('📁 Directory Listing'));
|
|
31
|
+
console.log(colorizer.cyan(' Current Path: ') + colorizer.bright(fullPath));
|
|
32
|
+
console.log(colorizer.dim(' ' + '='.repeat(70)));
|
|
33
|
+
console.log();
|
|
34
|
+
|
|
35
|
+
// Sort: directories first, then files
|
|
36
|
+
const dirs = items.filter(item => item.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
|
|
37
|
+
const files = items.filter(item => !item.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
|
|
38
|
+
|
|
39
|
+
// Display directories
|
|
40
|
+
for (const dir of dirs) {
|
|
41
|
+
const itemPath = path.join(fullPath, dir.name);
|
|
42
|
+
const stats = await fs.stat(itemPath);
|
|
43
|
+
const modified = stats.mtime.toLocaleDateString();
|
|
44
|
+
|
|
45
|
+
console.log(colorizer.cyan(' 📁 ' + dir.name.padEnd(40)) +
|
|
46
|
+
colorizer.dim(modified.padEnd(15) + '<DIR>'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Display files
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
const itemPath = path.join(fullPath, file.name);
|
|
52
|
+
const stats = await fs.stat(itemPath);
|
|
53
|
+
const size = this.formatSize(stats.size);
|
|
54
|
+
const modified = stats.mtime.toLocaleDateString();
|
|
55
|
+
const icon = this.getFileIcon(file.name);
|
|
56
|
+
|
|
57
|
+
console.log(colorizer.bright(' ' + icon + ' ' + file.name.padEnd(40)) +
|
|
58
|
+
colorizer.dim(modified.padEnd(15) + size.padStart(10)));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log();
|
|
62
|
+
console.log(colorizer.dim(' Total: ' + dirs.length + ' directories, ' + files.length + ' files'));
|
|
63
|
+
console.log();
|
|
64
|
+
|
|
65
|
+
} catch (err) {
|
|
66
|
+
console.log(colorizer.error('Error listing directory: ' + err.message));
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Change directory
|
|
71
|
+
async cd(args) {
|
|
72
|
+
if (args.length === 0) {
|
|
73
|
+
console.log(colorizer.cyan('Current directory: ') + this.currentPath);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const targetPath = args.join(' ');
|
|
78
|
+
let newPath;
|
|
79
|
+
|
|
80
|
+
// Handle special cases
|
|
81
|
+
if (targetPath === '..') {
|
|
82
|
+
newPath = path.dirname(this.currentPath);
|
|
83
|
+
} else if (targetPath === '~' || targetPath === '$HOME') {
|
|
84
|
+
newPath = require('os').homedir();
|
|
85
|
+
} else if (targetPath === '-') {
|
|
86
|
+
// Go back in history
|
|
87
|
+
if (this.history.length > 0 && this.historyIndex > 0) {
|
|
88
|
+
this.historyIndex--;
|
|
89
|
+
newPath = this.history[this.historyIndex];
|
|
90
|
+
} else {
|
|
91
|
+
console.log(colorizer.warning('No previous directory in history'));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
newPath = path.resolve(this.currentPath, targetPath);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const stats = await fs.stat(newPath);
|
|
100
|
+
|
|
101
|
+
if (!stats.isDirectory()) {
|
|
102
|
+
console.log(colorizer.error('Not a directory: ' + newPath));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Update history
|
|
107
|
+
if (targetPath !== '-') {
|
|
108
|
+
this.history = this.history.slice(0, this.historyIndex + 1);
|
|
109
|
+
this.history.push(newPath);
|
|
110
|
+
this.historyIndex = this.history.length - 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.currentPath = newPath;
|
|
114
|
+
console.log(colorizer.green('Changed to: ') + colorizer.bright(this.currentPath));
|
|
115
|
+
|
|
116
|
+
// Auto-list after cd
|
|
117
|
+
await this.list([]);
|
|
118
|
+
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.log(colorizer.error('Error changing directory: ' + err.message));
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
// Display current path
|
|
125
|
+
pwd() {
|
|
126
|
+
console.log(colorizer.section('📍 Current Working Directory'));
|
|
127
|
+
console.log(colorizer.bright(' ' + this.currentPath));
|
|
128
|
+
console.log();
|
|
129
|
+
return Promise.resolve();
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// View file contents
|
|
133
|
+
async cat(args) {
|
|
134
|
+
if (args.length === 0) {
|
|
135
|
+
console.log(colorizer.error('Usage: cat <filename>'));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const filename = args.join(' ');
|
|
140
|
+
const fullPath = path.resolve(this.currentPath, filename);
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const stats = await fs.stat(fullPath);
|
|
144
|
+
|
|
145
|
+
if (stats.isDirectory()) {
|
|
146
|
+
console.log(colorizer.error('Cannot display directory contents. Use "ls" instead.'));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
151
|
+
const lines = content.split('\n');
|
|
152
|
+
|
|
153
|
+
console.log(colorizer.section('📄 File: ' + path.basename(fullPath)));
|
|
154
|
+
console.log(colorizer.cyan(' Path: ') + colorizer.dim(fullPath));
|
|
155
|
+
console.log(colorizer.cyan(' Size: ') + colorizer.dim(this.formatSize(stats.size)));
|
|
156
|
+
console.log(colorizer.cyan(' Lines: ') + colorizer.dim(lines.length));
|
|
157
|
+
console.log(colorizer.dim(' ' + '='.repeat(70)));
|
|
158
|
+
console.log();
|
|
159
|
+
|
|
160
|
+
// Display with line numbers
|
|
161
|
+
lines.forEach((line, i) => {
|
|
162
|
+
const lineNum = String(i + 1).padStart(4, ' ');
|
|
163
|
+
console.log(colorizer.dim(lineNum + ' │ ') + line);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
console.log();
|
|
167
|
+
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (err.code === 'ENOENT') {
|
|
170
|
+
console.log(colorizer.error('File not found: ' + fullPath));
|
|
171
|
+
} else {
|
|
172
|
+
console.log(colorizer.error('Error reading file: ' + err.message));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
// View file with pagination
|
|
178
|
+
async less(args) {
|
|
179
|
+
if (args.length === 0) {
|
|
180
|
+
console.log(colorizer.error('Usage: less <filename>'));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const filename = args.join(' ');
|
|
185
|
+
const fullPath = path.resolve(this.currentPath, filename);
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
189
|
+
const lines = content.split('\n');
|
|
190
|
+
const pageSize = 30;
|
|
191
|
+
|
|
192
|
+
console.log(colorizer.section('📄 File: ' + path.basename(fullPath)));
|
|
193
|
+
console.log(colorizer.dim(' Showing first ' + Math.min(pageSize, lines.length) + ' of ' + lines.length + ' lines'));
|
|
194
|
+
console.log(colorizer.dim(' ' + '='.repeat(70)));
|
|
195
|
+
console.log();
|
|
196
|
+
|
|
197
|
+
// Display first page
|
|
198
|
+
const firstPage = lines.slice(0, pageSize);
|
|
199
|
+
firstPage.forEach((line, i) => {
|
|
200
|
+
const lineNum = String(i + 1).padStart(4, ' ');
|
|
201
|
+
console.log(colorizer.dim(lineNum + ' │ ') + line);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (lines.length > pageSize) {
|
|
205
|
+
console.log();
|
|
206
|
+
console.log(colorizer.dim(' ... ' + (lines.length - pageSize) + ' more lines'));
|
|
207
|
+
console.log(colorizer.info(' Tip: Use "cat ' + filename + '" to view entire file'));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log();
|
|
211
|
+
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.log(colorizer.error('Error reading file: ' + err.message));
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
// Search for files
|
|
218
|
+
async find(args) {
|
|
219
|
+
if (args.length === 0) {
|
|
220
|
+
console.log(colorizer.error('Usage: find <pattern>'));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const pattern = args.join(' ').toLowerCase();
|
|
225
|
+
const results = [];
|
|
226
|
+
|
|
227
|
+
console.log(colorizer.section('🔍 Searching for: ' + pattern));
|
|
228
|
+
console.log(colorizer.dim(' Starting from: ' + this.currentPath));
|
|
229
|
+
console.log();
|
|
230
|
+
|
|
231
|
+
await this.searchRecursive(this.currentPath, pattern, results, 0);
|
|
232
|
+
|
|
233
|
+
if (results.length === 0) {
|
|
234
|
+
console.log(colorizer.warning(' No matches found'));
|
|
235
|
+
} else {
|
|
236
|
+
console.log(colorizer.green(' Found ' + results.length + ' matches:'));
|
|
237
|
+
console.log();
|
|
238
|
+
|
|
239
|
+
results.forEach(result => {
|
|
240
|
+
const relPath = path.relative(this.currentPath, result.path);
|
|
241
|
+
const icon = result.isDir ? '📁' : this.getFileIcon(result.name);
|
|
242
|
+
console.log(colorizer.bright(' ' + icon + ' ' + relPath));
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log();
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
// Recursive search helper
|
|
250
|
+
async searchRecursive(dir, pattern, results, depth) {
|
|
251
|
+
if (depth > 5) return; // Limit recursion depth
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
255
|
+
|
|
256
|
+
for (const item of items) {
|
|
257
|
+
// Skip hidden files and node_modules
|
|
258
|
+
if (item.name.startsWith('.') || item.name === 'node_modules') continue;
|
|
259
|
+
|
|
260
|
+
const fullPath = path.join(dir, item.name);
|
|
261
|
+
|
|
262
|
+
if (item.name.toLowerCase().includes(pattern)) {
|
|
263
|
+
results.push({
|
|
264
|
+
path: fullPath,
|
|
265
|
+
name: item.name,
|
|
266
|
+
isDir: item.isDirectory()
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (item.isDirectory() && results.length < 100) {
|
|
271
|
+
await this.searchRecursive(fullPath, pattern, results, depth + 1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} catch (err) {
|
|
275
|
+
// Skip directories we can't access
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
// File information
|
|
280
|
+
async info(args) {
|
|
281
|
+
if (args.length === 0) {
|
|
282
|
+
console.log(colorizer.error('Usage: file-info <filename>'));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const filename = args.join(' ');
|
|
287
|
+
const fullPath = path.resolve(this.currentPath, filename);
|
|
288
|
+
|
|
289
|
+
try {
|
|
290
|
+
const stats = await fs.stat(fullPath);
|
|
291
|
+
|
|
292
|
+
console.log(colorizer.section('ℹ️ File Information'));
|
|
293
|
+
console.log(colorizer.cyan(' Name: ') + colorizer.bright(path.basename(fullPath)));
|
|
294
|
+
console.log(colorizer.cyan(' Path: ') + colorizer.dim(fullPath));
|
|
295
|
+
console.log(colorizer.cyan(' Type: ') + (stats.isDirectory() ? 'Directory' : 'File'));
|
|
296
|
+
console.log(colorizer.cyan(' Size: ') + this.formatSize(stats.size));
|
|
297
|
+
console.log(colorizer.cyan(' Created: ') + stats.birthtime.toLocaleString());
|
|
298
|
+
console.log(colorizer.cyan(' Modified: ') + stats.mtime.toLocaleString());
|
|
299
|
+
console.log(colorizer.cyan(' Accessed: ') + stats.atime.toLocaleString());
|
|
300
|
+
|
|
301
|
+
// File extension and type
|
|
302
|
+
if (!stats.isDirectory()) {
|
|
303
|
+
const ext = path.extname(fullPath).toLowerCase();
|
|
304
|
+
console.log(colorizer.cyan(' Extension: ') + (ext || 'none'));
|
|
305
|
+
console.log(colorizer.cyan(' Mime Type: ') + this.getMimeType(ext));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log();
|
|
309
|
+
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.log(colorizer.error('Error getting file info: ' + err.message));
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
// Tree view
|
|
316
|
+
async tree(args) {
|
|
317
|
+
const maxDepth = args.length > 0 ? parseInt(args[0]) : 2;
|
|
318
|
+
|
|
319
|
+
console.log(colorizer.section('🌲 Directory Tree'));
|
|
320
|
+
console.log(colorizer.cyan(' ' + this.currentPath));
|
|
321
|
+
console.log();
|
|
322
|
+
|
|
323
|
+
await this.printTree(this.currentPath, '', maxDepth, 0);
|
|
324
|
+
console.log();
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
async printTree(dir, prefix, maxDepth, currentDepth) {
|
|
328
|
+
if (currentDepth >= maxDepth) return;
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
332
|
+
const filtered = items.filter(item => !item.name.startsWith('.') && item.name !== 'node_modules');
|
|
333
|
+
|
|
334
|
+
for (let i = 0; i < filtered.length; i++) {
|
|
335
|
+
const item = filtered[i];
|
|
336
|
+
const isLast = i === filtered.length - 1;
|
|
337
|
+
const connector = isLast ? '└── ' : '├── ';
|
|
338
|
+
const icon = item.isDirectory() ? '📁' : this.getFileIcon(item.name);
|
|
339
|
+
|
|
340
|
+
console.log(prefix + connector + icon + ' ' + item.name);
|
|
341
|
+
|
|
342
|
+
if (item.isDirectory()) {
|
|
343
|
+
const newPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
344
|
+
const fullPath = path.join(dir, item.name);
|
|
345
|
+
await this.printTree(fullPath, newPrefix, maxDepth, currentDepth + 1);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
} catch (err) {
|
|
349
|
+
// Skip directories we can't access
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
// Bookmarks
|
|
354
|
+
bookmark(args) {
|
|
355
|
+
if (args.length === 0) {
|
|
356
|
+
// List bookmarks
|
|
357
|
+
console.log(colorizer.section('🔖 Bookmarks'));
|
|
358
|
+
|
|
359
|
+
if (this.bookmarks.size === 0) {
|
|
360
|
+
console.log(colorizer.dim(' No bookmarks saved'));
|
|
361
|
+
} else {
|
|
362
|
+
for (const [name, path] of this.bookmarks) {
|
|
363
|
+
console.log(colorizer.cyan(' ' + name.padEnd(20)) + colorizer.dim(path));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
console.log();
|
|
367
|
+
return Promise.resolve();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const name = args[0];
|
|
371
|
+
|
|
372
|
+
if (args.length === 1) {
|
|
373
|
+
// Jump to bookmark
|
|
374
|
+
if (this.bookmarks.has(name)) {
|
|
375
|
+
const bookmarkedPath = this.bookmarks.get(name);
|
|
376
|
+
return this.cd([bookmarkedPath]);
|
|
377
|
+
} else {
|
|
378
|
+
console.log(colorizer.error('Bookmark not found: ' + name));
|
|
379
|
+
return Promise.resolve();
|
|
380
|
+
}
|
|
381
|
+
} else {
|
|
382
|
+
// Save bookmark
|
|
383
|
+
const targetPath = args.slice(1).join(' ');
|
|
384
|
+
const fullPath = path.resolve(this.currentPath, targetPath);
|
|
385
|
+
|
|
386
|
+
this.bookmarks.set(name, fullPath);
|
|
387
|
+
console.log(colorizer.green('Bookmark saved: ') + colorizer.cyan(name) + ' → ' + fullPath);
|
|
388
|
+
console.log();
|
|
389
|
+
return Promise.resolve();
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
// Show help
|
|
394
|
+
showHelp() {
|
|
395
|
+
console.log(colorizer.section('📁 File Browser Commands'));
|
|
396
|
+
console.log();
|
|
397
|
+
|
|
398
|
+
const commands = [
|
|
399
|
+
['ls [path]', 'List files and directories'],
|
|
400
|
+
['cd <path>', 'Change directory (.. for parent, ~ for home, - for previous)'],
|
|
401
|
+
['pwd', 'Show current directory'],
|
|
402
|
+
['cat <file>', 'Display file contents with line numbers'],
|
|
403
|
+
['less <file>', 'View first 30 lines of file'],
|
|
404
|
+
['find <pattern>', 'Search for files by name'],
|
|
405
|
+
['file-info <file>', 'Show detailed file information'],
|
|
406
|
+
['tree [depth]', 'Display directory tree (default depth: 2)'],
|
|
407
|
+
['bookmark [name] [path]', 'Save/jump to bookmarks'],
|
|
408
|
+
['browse-help', 'Show this help']
|
|
409
|
+
];
|
|
410
|
+
|
|
411
|
+
commands.forEach(([cmd, desc]) => {
|
|
412
|
+
console.log(colorizer.cyan(' ' + cmd.padEnd(25)) + colorizer.dim(desc));
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
console.log();
|
|
416
|
+
console.log(colorizer.info('Examples:'));
|
|
417
|
+
console.log(colorizer.dim(' ls ../src # List parent src directory'));
|
|
418
|
+
console.log(colorizer.dim(' cd ~/projects # Go to home projects folder'));
|
|
419
|
+
console.log(colorizer.dim(' find server.js # Find all files matching "server.js"'));
|
|
420
|
+
console.log(colorizer.dim(' tree 3 # Show tree with depth 3'));
|
|
421
|
+
console.log(colorizer.dim(' bookmark proj . # Save current dir as "proj"'));
|
|
422
|
+
console.log(colorizer.dim(' bookmark proj # Jump to "proj" bookmark'));
|
|
423
|
+
console.log();
|
|
424
|
+
|
|
425
|
+
return Promise.resolve();
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
// Helper: Format file size
|
|
429
|
+
formatSize(bytes) {
|
|
430
|
+
if (bytes === 0) return '0 B';
|
|
431
|
+
const k = 1024;
|
|
432
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
433
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
434
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
435
|
+
},
|
|
436
|
+
|
|
437
|
+
// Helper: Get file icon
|
|
438
|
+
getFileIcon(filename) {
|
|
439
|
+
const ext = path.extname(filename).toLowerCase();
|
|
440
|
+
const icons = {
|
|
441
|
+
'.js': '📜',
|
|
442
|
+
'.json': '📋',
|
|
443
|
+
'.md': '📝',
|
|
444
|
+
'.txt': '📄',
|
|
445
|
+
'.html': '🌐',
|
|
446
|
+
'.css': '🎨',
|
|
447
|
+
'.png': '🖼️',
|
|
448
|
+
'.jpg': '🖼️',
|
|
449
|
+
'.jpeg': '🖼️',
|
|
450
|
+
'.gif': '🖼️',
|
|
451
|
+
'.svg': '🎨',
|
|
452
|
+
'.pdf': '📕',
|
|
453
|
+
'.zip': '📦',
|
|
454
|
+
'.tar': '📦',
|
|
455
|
+
'.gz': '📦',
|
|
456
|
+
'.mp3': '🎵',
|
|
457
|
+
'.mp4': '🎬',
|
|
458
|
+
'.py': '🐍',
|
|
459
|
+
'.java': '☕',
|
|
460
|
+
'.cpp': '⚙️',
|
|
461
|
+
'.c': '⚙️',
|
|
462
|
+
'.sh': '💻',
|
|
463
|
+
'.yml': '⚙️',
|
|
464
|
+
'.yaml': '⚙️',
|
|
465
|
+
'.xml': '📰',
|
|
466
|
+
'.sql': '🗄️'
|
|
467
|
+
};
|
|
468
|
+
return icons[ext] || '📄';
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
// Helper: Get MIME type
|
|
472
|
+
getMimeType(ext) {
|
|
473
|
+
const types = {
|
|
474
|
+
'.js': 'application/javascript',
|
|
475
|
+
'.json': 'application/json',
|
|
476
|
+
'.html': 'text/html',
|
|
477
|
+
'.css': 'text/css',
|
|
478
|
+
'.txt': 'text/plain',
|
|
479
|
+
'.md': 'text/markdown',
|
|
480
|
+
'.png': 'image/png',
|
|
481
|
+
'.jpg': 'image/jpeg',
|
|
482
|
+
'.jpeg': 'image/jpeg',
|
|
483
|
+
'.gif': 'image/gif',
|
|
484
|
+
'.svg': 'image/svg+xml',
|
|
485
|
+
'.pdf': 'application/pdf',
|
|
486
|
+
'.zip': 'application/zip'
|
|
487
|
+
};
|
|
488
|
+
return types[ext] || 'application/octet-stream';
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
module.exports = FileBrowser;
|