i18ntk 1.10.2 ā 2.0.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.
- package/LICENSE +1 -1
- package/README.md +141 -1191
- package/main/i18ntk-analyze.js +65 -84
- package/main/i18ntk-backup-class.js +420 -0
- package/main/i18ntk-backup.js +3 -3
- package/main/i18ntk-complete.js +90 -65
- package/main/i18ntk-doctor.js +123 -103
- package/main/i18ntk-fixer.js +61 -725
- package/main/i18ntk-go.js +14 -15
- package/main/i18ntk-init.js +77 -26
- package/main/i18ntk-java.js +27 -32
- package/main/i18ntk-js.js +70 -68
- package/main/i18ntk-manage.js +129 -30
- package/main/i18ntk-php.js +75 -75
- package/main/i18ntk-py.js +55 -56
- package/main/i18ntk-scanner.js +59 -57
- package/main/i18ntk-setup.js +9 -404
- package/main/i18ntk-sizing.js +6 -6
- package/main/i18ntk-summary.js +21 -18
- package/main/i18ntk-ui.js +11 -10
- package/main/i18ntk-usage.js +54 -18
- package/main/i18ntk-validate.js +13 -13
- package/main/manage/commands/AnalyzeCommand.js +1124 -0
- package/main/manage/commands/BackupCommand.js +62 -0
- package/main/manage/commands/CommandRouter.js +295 -0
- package/main/manage/commands/CompleteCommand.js +61 -0
- package/main/manage/commands/DoctorCommand.js +60 -0
- package/main/manage/commands/FixerCommand.js +624 -0
- package/main/manage/commands/InitCommand.js +62 -0
- package/main/manage/commands/ScannerCommand.js +654 -0
- package/main/manage/commands/SizingCommand.js +60 -0
- package/main/manage/commands/SummaryCommand.js +61 -0
- package/main/manage/commands/UsageCommand.js +60 -0
- package/main/manage/commands/ValidateCommand.js +978 -0
- package/main/manage/index-fixed.js +1447 -0
- package/main/manage/index.js +1462 -0
- package/main/manage/managers/DebugMenu.js +140 -0
- package/main/manage/managers/InteractiveMenu.js +177 -0
- package/main/manage/managers/LanguageMenu.js +62 -0
- package/main/manage/managers/SettingsMenu.js +53 -0
- package/main/manage/services/AuthenticationService.js +263 -0
- package/main/manage/services/ConfigurationService-fixed.js +449 -0
- package/main/manage/services/ConfigurationService.js +449 -0
- package/main/manage/services/FileManagementService.js +368 -0
- package/main/manage/services/FrameworkDetectionService.js +458 -0
- package/main/manage/services/InitService.js +1051 -0
- package/main/manage/services/SetupService.js +462 -0
- package/main/manage/services/SummaryService.js +450 -0
- package/main/manage/services/UsageService.js +1502 -0
- package/package.json +32 -29
- package/runtime/enhanced.d.ts +221 -221
- package/runtime/index.d.ts +29 -29
- package/runtime/index.full.d.ts +331 -331
- package/runtime/index.js +7 -6
- package/scripts/build-lite.js +17 -17
- package/scripts/deprecate-versions.js +23 -6
- package/scripts/export-translations.js +5 -5
- package/scripts/fix-all-i18n.js +3 -3
- package/scripts/fix-and-purify-i18n.js +3 -2
- package/scripts/fix-locale-control-chars.js +110 -0
- package/scripts/lint-locales.js +80 -0
- package/scripts/locale-optimizer.js +8 -8
- package/scripts/prepublish.js +21 -21
- package/scripts/security-check.js +117 -117
- package/scripts/sync-translations.js +4 -4
- package/scripts/sync-ui-locales.js +9 -8
- package/scripts/validate-all-translations.js +8 -7
- package/scripts/verify-deprecations.js +157 -161
- package/scripts/verify-translations.js +6 -5
- package/settings/i18ntk-config.json +282 -282
- package/settings/language-config.json +5 -5
- package/settings/settings-cli.js +9 -9
- package/settings/settings-manager.js +18 -18
- package/ui-locales/de.json +2417 -2348
- package/ui-locales/en.json +2415 -2352
- package/ui-locales/es.json +2425 -2353
- package/ui-locales/fr.json +2418 -2348
- package/ui-locales/ja.json +2463 -2361
- package/ui-locales/ru.json +2463 -2359
- package/ui-locales/zh.json +2418 -2351
- package/utils/admin-auth.js +2 -2
- package/utils/admin-cli.js +297 -297
- package/utils/admin-pin.js +9 -9
- package/utils/cli-helper.js +9 -9
- package/utils/config-helper.js +73 -104
- package/utils/config-manager.js +204 -171
- package/utils/config.js +5 -4
- package/utils/env-manager.js +249 -263
- package/utils/framework-detector.js +27 -24
- package/utils/i18n-helper.js +85 -41
- package/utils/init-helper.js +152 -94
- package/utils/json-output.js +98 -98
- package/utils/mini-commander.js +179 -0
- package/utils/missing-key-validator.js +5 -5
- package/utils/plugin-loader.js +40 -29
- package/utils/prompt.js +14 -44
- package/utils/safe-json.js +40 -0
- package/utils/secure-errors.js +3 -3
- package/utils/security-check-improved.js +390 -0
- package/utils/security-config.js +5 -5
- package/utils/security-fixed.js +607 -0
- package/utils/security.js +652 -602
- package/utils/setup-enforcer.js +136 -44
- package/utils/setup-validator.js +33 -32
- package/utils/ultra-performance-optimizer.js +11 -9
- package/utils/watch-locales.js +2 -1
- package/utils/prompt-fixed.js +0 -55
- package/utils/security-check.js +0 -454
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Management Service
|
|
3
|
+
* Handles file operations, globbing, and cleanup operations
|
|
4
|
+
* @module services/FileManagementService
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const SecurityUtils = require('../../../utils/security');
|
|
10
|
+
|
|
11
|
+
module.exports = class FileManagementService {
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.settings = null;
|
|
15
|
+
this.configManager = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the service with required dependencies
|
|
20
|
+
* @param {Object} configManager - Configuration manager instance
|
|
21
|
+
*/
|
|
22
|
+
initialize(configManager) {
|
|
23
|
+
this.configManager = configManager;
|
|
24
|
+
this.settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Custom glob implementation using Node.js built-in modules (zero dependencies)
|
|
29
|
+
* @param {string[]} patterns - Array of glob patterns
|
|
30
|
+
* @param {Object} options - Options object with cwd and ignore properties
|
|
31
|
+
* @returns {Promise<string[]>} Array of matching file paths
|
|
32
|
+
*/
|
|
33
|
+
async customGlob(patterns, options = {}) {
|
|
34
|
+
const cwd = options.cwd || process.cwd();
|
|
35
|
+
const ignorePatterns = options.ignore || [];
|
|
36
|
+
|
|
37
|
+
function matchesPattern(filename, pattern) {
|
|
38
|
+
// Simple pattern matching for **/*.{js,jsx,ts,tsx} style patterns
|
|
39
|
+
if (pattern.includes('**/*')) {
|
|
40
|
+
const extensionPart = pattern.split('*.')[1];
|
|
41
|
+
if (extensionPart) {
|
|
42
|
+
const extensions = extensionPart.replace('{', '').replace('}', '').split(',');
|
|
43
|
+
return extensions.some(ext => filename.endsWith('.' + ext.trim()));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return filename.includes(pattern.replace('**/', ''));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function shouldIgnore(filePath) {
|
|
50
|
+
return ignorePatterns.some(pattern => {
|
|
51
|
+
if (pattern.includes('**/')) {
|
|
52
|
+
const patternEnd = pattern.replace('**/', '');
|
|
53
|
+
return filePath.includes('/' + patternEnd) || filePath.includes('\\' + patternEnd);
|
|
54
|
+
}
|
|
55
|
+
return filePath.includes(pattern);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function findFiles(dir, results = []) {
|
|
60
|
+
try {
|
|
61
|
+
const items = fs.readdirSync(dir);
|
|
62
|
+
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
const fullPath = path.join(dir, item);
|
|
65
|
+
const relativePath = path.relative(cwd, fullPath);
|
|
66
|
+
|
|
67
|
+
if (shouldIgnore(relativePath)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const stat = fs.statSync(fullPath);
|
|
73
|
+
|
|
74
|
+
if (stat.isDirectory()) {
|
|
75
|
+
findFiles(fullPath, results);
|
|
76
|
+
} else if (stat.isFile()) {
|
|
77
|
+
// Check if file matches any of our patterns
|
|
78
|
+
for (const pattern of patterns) {
|
|
79
|
+
if (matchesPattern(item, pattern)) {
|
|
80
|
+
results.push(relativePath);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
// Skip files we can't access
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
// Skip directories we can't access
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return findFiles(cwd);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Enhanced delete reports and logs functionality
|
|
102
|
+
* @param {Object} prompt - Prompt interface for user interaction
|
|
103
|
+
* @param {Object} ui - UI instance for translations (optional)
|
|
104
|
+
* @returns {Promise<void>}
|
|
105
|
+
*/
|
|
106
|
+
async deleteReports(prompt, ui = null) {
|
|
107
|
+
// Check for PIN protection
|
|
108
|
+
const authRequired = await this.isAuthRequiredForScript('deleteReports');
|
|
109
|
+
if (authRequired) {
|
|
110
|
+
console.log(`\n${ui ? ui.t('adminPin.protectedAccess') : 'Protected Access'}`);
|
|
111
|
+
const cliHelper = require('../../../utils/cli-helper');
|
|
112
|
+
const pin = await cliHelper.promptPin((ui ? ui.t('adminPin.enterPin') : 'Enter PIN: ') + ': ');
|
|
113
|
+
const isValid = await this.verifyPin(pin);
|
|
114
|
+
if (!isValid) {
|
|
115
|
+
console.log(ui ? ui.t('adminPin.invalidPin') : 'Invalid PIN');
|
|
116
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
console.log(ui ? ui.t('adminPin.accessGranted') : 'Access granted');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(`\n${ui ? ui.t('operations.deleteReportsTitle') : 'Delete Reports and Logs'}`);
|
|
123
|
+
console.log('============================================================');
|
|
124
|
+
|
|
125
|
+
const targetDirs = [
|
|
126
|
+
{ path: path.join(process.cwd(), 'i18ntk-reports'), name: 'Reports', type: 'reports' },
|
|
127
|
+
{ path: path.join(process.cwd(), 'reports'), name: 'Legacy Reports', type: 'reports' },
|
|
128
|
+
{ path: path.join(process.cwd(), 'reports', 'backups'), name: 'Reports Backups', type: 'backups' },
|
|
129
|
+
{ path: path.join(process.cwd(), 'scripts', 'debug', 'logs'), name: 'Debug Logs', type: 'logs' },
|
|
130
|
+
{ path: path.join(process.cwd(), 'scripts', 'debug', 'reports'), name: 'Debug Reports', type: 'reports' },
|
|
131
|
+
{ path: path.join(process.cwd(), 'settings', 'backups'), name: 'Settings Backups', type: 'backups' },
|
|
132
|
+
{ path: path.join(process.cwd(), 'utils', 'i18ntk-reports'), name: 'Utils Reports', type: 'reports' }
|
|
133
|
+
].filter(dir => dir.path && typeof dir.path === 'string');
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
console.log(ui ? ui.t('operations.scanningForFiles') : 'Scanning for files...');
|
|
137
|
+
|
|
138
|
+
let availableDirs = [];
|
|
139
|
+
|
|
140
|
+
// Check which directories exist and have files
|
|
141
|
+
for (const dir of targetDirs) {
|
|
142
|
+
if (SecurityUtils.safeExistsSync(dir.path)) {
|
|
143
|
+
const files = this.getAllReportFiles(dir.path);
|
|
144
|
+
if (files.length > 0) {
|
|
145
|
+
availableDirs.push({
|
|
146
|
+
...dir,
|
|
147
|
+
files: files.map(file => ({ path: file, dir: dir.path })),
|
|
148
|
+
count: files.length
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (availableDirs.length === 0) {
|
|
155
|
+
console.log(ui ? ui.t('operations.noFilesFoundToDelete') : 'No files found to delete');
|
|
156
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Show available directories
|
|
161
|
+
console.log(ui ? ui.t('operations.availableDirectories') : 'Available directories:');
|
|
162
|
+
availableDirs.forEach((dir, index) => {
|
|
163
|
+
console.log(` ${index + 1}. ${dir.name} (${dir.count} files)`);
|
|
164
|
+
});
|
|
165
|
+
console.log(` ${availableDirs.length + 1}. ${ui ? ui.t('operations.allDirectories') : 'All directories'}`);
|
|
166
|
+
console.log(` 0. ${ui ? ui.t('operations.cancelOption') : 'Cancel'}`);
|
|
167
|
+
|
|
168
|
+
const dirChoice = await prompt(`\nSelect directory to clean (0-${availableDirs.length + 1}): `);
|
|
169
|
+
const dirIndex = parseInt(dirChoice) - 1;
|
|
170
|
+
|
|
171
|
+
let selectedDirs = [];
|
|
172
|
+
|
|
173
|
+
if (dirChoice.trim() === '0') {
|
|
174
|
+
console.log(ui ? ui.t('operations.cancelled') : 'Cancelled');
|
|
175
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
176
|
+
return;
|
|
177
|
+
} else if (dirIndex === availableDirs.length) {
|
|
178
|
+
selectedDirs = availableDirs;
|
|
179
|
+
} else if (dirIndex >= 0 && dirIndex < availableDirs.length) {
|
|
180
|
+
selectedDirs = [availableDirs[dirIndex]];
|
|
181
|
+
} else {
|
|
182
|
+
console.log(ui ? ui.t('operations.invalidSelection') : 'Invalid selection');
|
|
183
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Collect all files from selected directories
|
|
188
|
+
let allFiles = [];
|
|
189
|
+
selectedDirs.forEach(dir => {
|
|
190
|
+
allFiles.push(...dir.files);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
console.log(ui ? ui.t('operations.foundFilesInSelectedDirectories', { count: allFiles.length }) : `Found ${allFiles.length} files in selected directories`);
|
|
194
|
+
selectedDirs.forEach(dir => {
|
|
195
|
+
console.log(` š ${dir.name}: ${dir.count} files`);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Show deletion options
|
|
199
|
+
console.log(ui ? ui.t('operations.deletionOptions') : 'Deletion options:');
|
|
200
|
+
console.log(` 1. ${ui ? ui.t('operations.deleteAllFiles') : 'Delete all files'}`);
|
|
201
|
+
console.log(` 2. ${ui ? ui.t('operations.keepLast3Files') : 'Keep last 3 files'}`);
|
|
202
|
+
console.log(` 3. ${ui ? ui.t('operations.keepLast5Files') : 'Keep last 5 files'}`);
|
|
203
|
+
console.log(` 0. ${ui ? ui.t('operations.cancelReportOption') : 'Cancel'}`);
|
|
204
|
+
|
|
205
|
+
const option = await prompt('\nSelect option (0-3): ');
|
|
206
|
+
|
|
207
|
+
let filesToDelete = [];
|
|
208
|
+
|
|
209
|
+
switch (option.trim()) {
|
|
210
|
+
case '1':
|
|
211
|
+
filesToDelete = allFiles;
|
|
212
|
+
break;
|
|
213
|
+
case '2':
|
|
214
|
+
filesToDelete = this.getFilesToDeleteKeepLast(allFiles, 3);
|
|
215
|
+
break;
|
|
216
|
+
case '3':
|
|
217
|
+
filesToDelete = this.getFilesToDeleteKeepLast(allFiles, 5);
|
|
218
|
+
break;
|
|
219
|
+
case '0':
|
|
220
|
+
console.log(ui ? ui.t('operations.cancelled') : 'Cancelled');
|
|
221
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
222
|
+
return;
|
|
223
|
+
default:
|
|
224
|
+
console.log(ui ? ui.t('menu.invalidOption') : 'Invalid option');
|
|
225
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (filesToDelete.length === 0) {
|
|
230
|
+
console.log(ui ? ui.t('operations.noFilesToDelete') : 'No files to delete');
|
|
231
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log(ui ? ui.t('operations.filesToDeleteCount', { count: filesToDelete.length }) : `Files to delete: ${filesToDelete.length}`);
|
|
236
|
+
console.log(ui ? ui.t('operations.filesToKeepCount', { count: allFiles.length - filesToDelete.length }) : `Files to keep: ${allFiles.length - filesToDelete.length}`);
|
|
237
|
+
|
|
238
|
+
const confirm = await prompt(ui ? ui.t('operations.confirmDeletion') : 'Are you sure you want to delete these files? (y/N): ');
|
|
239
|
+
|
|
240
|
+
if (confirm.toLowerCase() === 'y' || confirm.toLowerCase() === 'yes') {
|
|
241
|
+
let deletedCount = 0;
|
|
242
|
+
|
|
243
|
+
for (const fileInfo of filesToDelete) {
|
|
244
|
+
try {
|
|
245
|
+
fs.unlinkSync(fileInfo.path);
|
|
246
|
+
console.log(ui ? ui.t('operations.deletedFile', { filename: path.basename(fileInfo.path) }) : `Deleted: ${path.basename(fileInfo.path)}`);
|
|
247
|
+
deletedCount++;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.log(ui ? ui.t('operations.failedToDeleteFile', { filename: path.basename(fileInfo.path), error: error.message }) : `Failed to delete ${path.basename(fileInfo.path)}: ${error.message}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
console.log(`\nš Successfully deleted ${deletedCount} files!`);
|
|
254
|
+
} else {
|
|
255
|
+
console.log(ui ? ui.t('operations.cancelled') : 'Cancelled');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(`ā Error during deletion process: ${error.message}`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
await prompt(ui ? ui.t('menu.pressEnterToContinue') : 'Press Enter to continue...');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Helper method to get all report and log files recursively
|
|
267
|
+
* @param {string} dir - Directory to scan
|
|
268
|
+
* @returns {string[]} Array of file paths
|
|
269
|
+
*/
|
|
270
|
+
getAllReportFiles(dir) {
|
|
271
|
+
if (!dir || typeof dir !== 'string') {
|
|
272
|
+
return [];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let files = [];
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
if (!SecurityUtils.safeExistsSync(dir)) {
|
|
279
|
+
return [];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const items = fs.readdirSync(dir);
|
|
283
|
+
for (const item of items) {
|
|
284
|
+
const fullPath = path.join(dir, item);
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
const stat = fs.statSync(fullPath);
|
|
288
|
+
|
|
289
|
+
if (stat.isDirectory()) {
|
|
290
|
+
files.push(...this.getAllReportFiles(fullPath));
|
|
291
|
+
} else if (
|
|
292
|
+
// Common report file extensions
|
|
293
|
+
item.endsWith('.json') ||
|
|
294
|
+
item.endsWith('.html') ||
|
|
295
|
+
item.endsWith('.txt') ||
|
|
296
|
+
item.endsWith('.log') ||
|
|
297
|
+
item.endsWith('.csv') ||
|
|
298
|
+
item.endsWith('.md') ||
|
|
299
|
+
// Specific report filename patterns
|
|
300
|
+
item.includes('-report.') ||
|
|
301
|
+
item.includes('_report.') ||
|
|
302
|
+
item.includes('report-') ||
|
|
303
|
+
item.includes('report_') ||
|
|
304
|
+
item.includes('analysis-') ||
|
|
305
|
+
item.includes('validation-')
|
|
306
|
+
) {
|
|
307
|
+
files.push(fullPath);
|
|
308
|
+
}
|
|
309
|
+
} catch (error) {
|
|
310
|
+
// Skip individual files that can't be accessed
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
} catch (error) {
|
|
315
|
+
// Silent fail for inaccessible directories
|
|
316
|
+
console.log(`ā ļø Could not access directory: ${dir}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return files;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Helper method to determine which files to delete when keeping last N files
|
|
324
|
+
* @param {Array} allFiles - Array of file objects with path property
|
|
325
|
+
* @param {number} keepCount - Number of files to keep
|
|
326
|
+
* @returns {Array} Array of files to delete
|
|
327
|
+
*/
|
|
328
|
+
getFilesToDeleteKeepLast(allFiles, keepCount = 3) {
|
|
329
|
+
// Sort files by modification time (newest first)
|
|
330
|
+
const sortedFiles = allFiles.sort((a, b) => {
|
|
331
|
+
try {
|
|
332
|
+
const statA = fs.statSync(a.path || a);
|
|
333
|
+
const statB = fs.statSync(b.path || b);
|
|
334
|
+
return statB.mtime.getTime() - statA.mtime.getTime();
|
|
335
|
+
} catch (error) {
|
|
336
|
+
// If stat fails, sort by filename as fallback
|
|
337
|
+
const pathA = a.path || a;
|
|
338
|
+
const pathB = b.path || b;
|
|
339
|
+
return pathB.localeCompare(pathA);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Keep the N newest files, delete the rest
|
|
344
|
+
return sortedFiles.slice(keepCount);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Check if authentication is required for a script
|
|
349
|
+
* @param {string} scriptName - Name of the script
|
|
350
|
+
* @returns {Promise<boolean>} True if authentication is required
|
|
351
|
+
*/
|
|
352
|
+
async isAuthRequiredForScript(scriptName) {
|
|
353
|
+
// This would need to be implemented based on the authentication service
|
|
354
|
+
// For now, return false as a placeholder
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Verify PIN for authentication
|
|
360
|
+
* @param {string} pin - PIN to verify
|
|
361
|
+
* @returns {Promise<boolean>} True if PIN is valid
|
|
362
|
+
*/
|
|
363
|
+
async verifyPin(pin) {
|
|
364
|
+
// This would need to be implemented based on the authentication service
|
|
365
|
+
// For now, return true as a placeholder
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
};
|