i18ntk 2.2.0 → 2.3.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.
Files changed (34) hide show
  1. package/README.md +83 -50
  2. package/main/i18ntk-backup-class.js +37 -41
  3. package/main/i18ntk-backup.js +28 -30
  4. package/main/i18ntk-doctor.js +7 -6
  5. package/main/i18ntk-init.js +44 -8
  6. package/main/i18ntk-sizing.js +7 -8
  7. package/main/i18ntk-usage.js +17 -5
  8. package/main/i18ntk-validate.js +72 -22
  9. package/main/manage/commands/AnalyzeCommand.js +12 -14
  10. package/main/manage/commands/CommandRouter.js +15 -12
  11. package/main/manage/commands/FixerCommand.js +92 -36
  12. package/main/manage/commands/ValidateCommand.js +78 -27
  13. package/main/manage/index.js +158 -148
  14. package/main/manage/managers/DebugMenu.js +6 -6
  15. package/main/manage/managers/InteractiveMenu.js +6 -6
  16. package/main/manage/managers/LanguageMenu.js +5 -4
  17. package/main/manage/managers/SettingsMenu.js +6 -6
  18. package/main/manage/services/AuthenticationService.js +5 -6
  19. package/main/manage/services/ConfigurationService.js +22 -34
  20. package/main/manage/services/FileManagementService.js +6 -6
  21. package/main/manage/services/InitService.js +44 -8
  22. package/main/manage/services/UsageService.js +17 -5
  23. package/package.json +8 -7
  24. package/settings/settings-cli.js +2 -2
  25. package/settings/settings-manager.js +984 -968
  26. package/utils/config-helper.js +27 -16
  27. package/utils/config-manager.js +8 -7
  28. package/utils/i18n-helper.js +9 -13
  29. package/utils/init-helper.js +3 -2
  30. package/utils/json-output.js +11 -10
  31. package/utils/logger.js +4 -4
  32. package/utils/safe-json.js +3 -3
  33. package/utils/secure-backup.js +8 -7
  34. package/utils/setup-enforcer.js +63 -98
@@ -13,16 +13,21 @@
13
13
  * npm run i18ntk:manage -- --help
14
14
  */
15
15
 
16
- const path = require('path');
17
- const AdminAuth = require('../../utils/admin-auth');
18
- const SecurityUtils = require('../../utils/security');
19
- const configManager = require('../../settings/settings-manager');
20
- const { showFrameworkWarningOnce } = require('../../utils/cli-helper');
21
- const { createPrompt, isInteractive } = require('../../utils/prompt-helper');
22
- const { loadTranslations, t, refreshLanguageFromSettings} = require('../../utils/i18n-helper');
23
- const cliHelper = require('../../utils/cli-helper');
24
- const { loadConfig, saveConfig, ensureConfigDefaults } = require('../../utils/config');
25
- const pkg = require('../../package.json');
16
+ const path = require('path');
17
+ const fs = require('fs');
18
+ const AdminAuth = require('../../utils/admin-auth');
19
+ const SecurityUtils = require('../../utils/security');
20
+ const configManager = require('../../settings/settings-manager');
21
+ const { validateSourceDir } = require('../../utils/config-helper');
22
+ const { checkInitialized } = require('../../utils/init-helper');
23
+ const { showFrameworkWarningOnce } = require('../../utils/cli-helper');
24
+ const { createPrompt, isInteractive } = require('../../utils/prompt-helper');
25
+ const { loadTranslations, t, refreshLanguageFromSettings} = require('../../utils/i18n-helper');
26
+ const cliHelper = require('../../utils/cli-helper');
27
+ const { blue } = require('../../utils/colors-new');
28
+ const { loadConfig, saveConfig, ensureConfigDefaults } = require('../../utils/config');
29
+ const SettingsCLI = require('../../settings/settings-cli');
30
+ const pkg = require('../../package.json');
26
31
  const SetupEnforcer = require('../../utils/setup-enforcer');
27
32
  const CommandRouter = require('./commands/CommandRouter');
28
33
 
@@ -73,9 +78,8 @@ class I18nManager {
73
78
  loadTranslations(uiLanguage);
74
79
 
75
80
  // Validate source directory exists
76
- const {validateSourceDir, displayPaths} = require('../../utils/config-helper');
77
- try {
78
- validateSourceDir(this.config.sourceDir, 'i18ntk-manage');
81
+ try {
82
+ validateSourceDir(this.config.sourceDir, 'i18ntk-manage');
79
83
  } catch (err) {
80
84
  console.log(t('init.requiredTitle'));
81
85
  console.log(t('init.requiredBody'));
@@ -132,10 +136,10 @@ class I18nManager {
132
136
  if (SecurityUtils.safeExistsSync(resolvedPath)) {
133
137
  // Check if it contains language directories
134
138
  try {
135
- const items = require('fs').readdirSync(resolvedPath);
139
+ const items = fs.readdirSync(resolvedPath);
136
140
  const hasLanguageDirs = items.some(item => {
137
141
  const itemPath = path.join(resolvedPath, item);
138
- return require('fs').statSync(itemPath).isDirectory() &&
142
+ return fs.statSync(itemPath).isDirectory() &&
139
143
  ['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(item);
140
144
  });
141
145
 
@@ -170,7 +174,6 @@ class I18nManager {
170
174
  };
171
175
 
172
176
  try {
173
- const { checkInitialized } = require('../../utils/init-helper');
174
177
  const initStatus = await checkInitialized();
175
178
  if (initStatus?.initialized || initStatus?.config?.setup?.completed) {
176
179
  markInternalFrameworkDetected();
@@ -335,8 +338,8 @@ class I18nManager {
335
338
  }
336
339
  clearStartupTimeout();
337
340
 
338
- prompt = createPrompt({ noPrompt: args.noPrompt || Boolean(args.adminPin) });
339
- const interactive = isInteractive({ noPrompt: args.noPrompt || Boolean(args.adminPin) });
341
+ prompt = createPrompt({ noPrompt: args.noPrompt });
342
+ const interactive = isInteractive({ noPrompt: args.noPrompt });
340
343
 
341
344
  // Load settings and UI language
342
345
  const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
@@ -346,15 +349,10 @@ class I18nManager {
346
349
  // Initialize CommandRouter
347
350
  this.commandRouter = new CommandRouter(this.config, this.ui, this.adminAuth);
348
351
 
349
- if (args.adminPin) {
350
- this.adminAuth.verifyPin = async () => true;
351
- this.prompt = async () => '';
352
- }
353
-
354
- if (args.help) {
355
- this.showHelp();
356
- return;
357
- }
352
+ if (args.help) {
353
+ this.showHelp();
354
+ return;
355
+ }
358
356
 
359
357
  let cfgAfterInitCheck = {};
360
358
  if (interactive && !shouldSkipInitCheck) {
@@ -366,7 +364,7 @@ class I18nManager {
366
364
  }
367
365
 
368
366
  this.config = { ...this.config, ...cfgAfterInitCheck };
369
- await this.initialize({ interactive, noPrompt: args.noPrompt || Boolean(args.adminPin) });
367
+ await this.initialize({ interactive, noPrompt: args.noPrompt });
370
368
  clearStartupTimeout();
371
369
  let commandToExecute = requestedCommand;
372
370
 
@@ -380,8 +378,7 @@ class I18nManager {
380
378
  // Handle debug flag
381
379
  if (args.debug) {
382
380
  // Enable debug mode for this session
383
- const { blue } = require('../../utils/colors-new');
384
- console.log(blue('Debug mode enabled'));
381
+ console.log(blue('Debug mode enabled'));
385
382
  }
386
383
 
387
384
  if (commandToExecute) {
@@ -489,11 +486,7 @@ class I18nManager {
489
486
  // ... existing code for ensureInitializedOrExit, maybePromptFramework, showInteractiveMenu, etc. ...
490
487
 
491
488
  async ensureInitializedOrExit(prompt) {
492
- const { checkInitialized } = require('../../utils/init-helper');
493
- const cliHelper = require('../../utils/cli-helper');
494
- const pkg = require('../../package.json');
495
-
496
- const { initialized, config } = await checkInitialized();
489
+ const { initialized, config } = await checkInitialized();
497
490
 
498
491
  if (!initialized) {
499
492
  console.log('\nThis project is not yet initialized with i18ntk.');
@@ -608,10 +601,7 @@ class I18nManager {
608
601
  if (!SecurityUtils) {
609
602
  throw new Error('SecurityUtils is not available. This may indicate a module loading issue.');
610
603
  }
611
- const fs = require('fs');
612
- const path = require('path');
613
-
614
- const packageJsonPath = path.join(process.cwd(), 'package.json');
604
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
615
605
  const pyprojectPath = path.join(process.cwd(), 'pyproject.toml');
616
606
  const requirementsPath = path.join(process.cwd(), 'requirements.txt');
617
607
  const goModPath = path.join(process.cwd(), 'go.mod');
@@ -622,7 +612,6 @@ class I18nManager {
622
612
  let detectedFramework = 'generic';
623
613
 
624
614
  try {
625
- const { checkInitialized } = require('../../utils/init-helper');
626
615
  const initStatus = await checkInitialized();
627
616
  if (initStatus?.initialized || initStatus?.config?.setup?.completed) {
628
617
  return { detectedLanguage: 'javascript', detectedFramework: 'i18ntk' };
@@ -738,9 +727,7 @@ class I18nManager {
738
727
  }
739
728
 
740
729
  async customGlob(patterns, options = {}) {
741
- const fs = require('fs');
742
- const path = require('path');
743
- const cwd = options.cwd || process.cwd();
730
+ const cwd = options.cwd || process.cwd();
744
731
  const ignorePatterns = options.ignore || [];
745
732
 
746
733
  function matchesPattern(filename, pattern) {
@@ -944,8 +931,7 @@ class I18nManager {
944
931
  const authRequired = await this.adminAuth.isAuthRequiredForScript('summaryReports');
945
932
  if (authRequired) {
946
933
  console.log(`\n${t('adminCli.protectedAccess')}`);
947
- const cliHelper = require('../../utils/cli-helper');
948
- const pin = await cliHelper.promptPin(t('adminCli.enterPin') + ': ');
934
+ const pin = await cliHelper.promptPin(t('adminCli.enterPin') + ': ');
949
935
  const isValid = await this.adminAuth.verifyPin(pin);
950
936
 
951
937
  if (!isValid) {
@@ -1061,8 +1047,7 @@ class I18nManager {
1061
1047
  console.log(t('language.changed', { language: selectedLang.name }));
1062
1048
 
1063
1049
  // Force reload translations for the entire system
1064
- const { loadTranslations } = require('../../utils/i18n-helper');
1065
- loadTranslations(selectedLang.code);
1050
+ loadTranslations(selectedLang.code);
1066
1051
 
1067
1052
  // Return to main menu with new language
1068
1053
  await this.prompt('\n' + t('language.pressEnterToContinue'));
@@ -1079,8 +1064,7 @@ class I18nManager {
1079
1064
  const authRequired = await this.adminAuth.isAuthRequiredForScript('debugMenu');
1080
1065
  if (authRequired) {
1081
1066
  console.log(`\n${t('adminPin.protectedAccess')}`);
1082
- const cliHelper = require('../../utils/cli-helper');
1083
- const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
1067
+ const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
1084
1068
  const isValid = await this.adminAuth.verifyPin(pin);
1085
1069
 
1086
1070
  if (!isValid) {
@@ -1140,35 +1124,46 @@ class I18nManager {
1140
1124
  console.log(`\n${t('debug.recentDebugLogs')}`);
1141
1125
  console.log('============================================================');
1142
1126
 
1143
- try {
1144
- const logsDir = path.join(__dirname, '..', '..', 'scripts', 'debug', 'logs');
1145
- if (SecurityUtils.safeExistsSync(logsDir)) {
1146
- const files = require('fs').readdirSync(logsDir)
1147
- .filter(file => file.endsWith('.log') || file.endsWith('.txt'))
1148
- .sort((a, b) => {
1149
- const statA = require('fs').statSync(path.join(logsDir, a));
1150
- const statB = require('fs').statSync(path.join(logsDir, b));
1151
- return statB.mtime - statA.mtime;
1152
- })
1153
- .slice(0, 5);
1154
-
1155
- if (files.length > 0) {
1156
- files.forEach((file, index) => {
1157
- const filePath = path.join(logsDir, file);
1158
- const stats = require('fs').statSync(filePath);
1159
- console.log(`${index + 1}. ${file} (${stats.mtime.toLocaleString()})`);
1160
- });
1161
-
1162
- const choice = await this.prompt('\n' + t('debug.selectLogPrompt', { count: files.length }));
1163
- const fileIndex = parseInt(choice) - 1;
1164
-
1165
- if (fileIndex >= 0 && fileIndex < files.length) {
1166
- const logContent = SecurityUtils.safeReadFileSync(path.join(logsDir, files[fileIndex]), logsDir, 'utf8');
1167
- console.log(`\n${t('debug.contentOf', { filename: files[fileIndex] })}:`);
1168
- console.log('============================================================');
1169
- console.log(logContent.slice(-2000)); // Show last 2000 characters
1170
- console.log('============================================================');
1171
- }
1127
+ try {
1128
+ const logsDir = path.join(__dirname, '..', '..', 'scripts', 'debug', 'logs');
1129
+ const validatedLogsDir = SecurityUtils.validatePath(logsDir, process.cwd());
1130
+ if (validatedLogsDir && SecurityUtils.safeExistsSync(validatedLogsDir, process.cwd())) {
1131
+ const files = fs.readdirSync(validatedLogsDir)
1132
+ .filter(file => file.endsWith('.log') || file.endsWith('.txt'))
1133
+ .sort((a, b) => {
1134
+ const statA = fs.statSync(path.join(validatedLogsDir, a));
1135
+ const statB = fs.statSync(path.join(validatedLogsDir, b));
1136
+ return statB.mtime - statA.mtime;
1137
+ })
1138
+ .slice(0, 5);
1139
+
1140
+ if (files.length > 0) {
1141
+ files.forEach((file, index) => {
1142
+ const filePath = path.join(validatedLogsDir, file);
1143
+ const validatedFilePath = SecurityUtils.validatePath(filePath, validatedLogsDir);
1144
+ if (!validatedFilePath) {
1145
+ return;
1146
+ }
1147
+ const stats = fs.statSync(validatedFilePath);
1148
+ console.log(`${index + 1}. ${file} (${stats.mtime.toLocaleString()})`);
1149
+ });
1150
+
1151
+ const choice = await this.prompt('\n' + t('debug.selectLogPrompt', { count: files.length }));
1152
+ const fileIndex = parseInt(choice) - 1;
1153
+
1154
+ if (fileIndex >= 0 && fileIndex < files.length) {
1155
+ const logPath = SecurityUtils.validatePath(path.join(validatedLogsDir, files[fileIndex]), validatedLogsDir);
1156
+ if (!logPath) {
1157
+ console.log(t('debug.debugLogsDirectoryNotFound'));
1158
+ return;
1159
+ }
1160
+ const logContent = SecurityUtils.safeReadFileSync(logPath, validatedLogsDir, 'utf8');
1161
+ console.log(`\n${t('debug.contentOf', { filename: files[fileIndex] })}:`);
1162
+ console.log('============================================================');
1163
+ const tailLines = String(logContent || '').split(/\r?\n/).slice(-40).join('\n');
1164
+ console.log(tailLines);
1165
+ console.log('============================================================');
1166
+ }
1172
1167
  } else {
1173
1168
  console.log(t('debug.noDebugLogsFound'));
1174
1169
  }
@@ -1188,8 +1183,7 @@ class I18nManager {
1188
1183
  const authRequired = await this.adminAuth.isAuthRequiredForScript('deleteReports');
1189
1184
  if (authRequired) {
1190
1185
  console.log(`\n${t('adminPin.protectedAccess')}`);
1191
- const cliHelper = require('../../utils/cli-helper');
1192
- const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
1186
+ const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
1193
1187
  const isValid = await this.adminAuth.verifyPin(pin);
1194
1188
 
1195
1189
  if (!isValid) {
@@ -1215,22 +1209,25 @@ class I18nManager {
1215
1209
  { path: path.join(process.cwd(), 'utils', 'i18ntk-reports'), name: 'Utils Reports', type: 'reports' }
1216
1210
  ].filter(dir => dir.path && typeof dir.path === 'string');
1217
1211
 
1218
- try {
1219
- console.log(t('operations.scanningForFiles'));
1220
-
1221
- let availableDirs = [];
1222
-
1223
- // Check which directories exist and have files
1224
- for (const dir of targetDirs) {
1225
- if (SecurityUtils.safeExistsSync(dir.path)) {
1226
- const files = this.getAllReportFiles(dir.path);
1227
- if (files.length > 0) {
1228
- availableDirs.push({
1229
- ...dir,
1230
- files: files.map(file => ({ path: file, dir: dir.path })),
1231
- count: files.length
1232
- });
1233
- }
1212
+ try {
1213
+ console.log(t('operations.scanningForFiles'));
1214
+
1215
+ let availableDirs = [];
1216
+ const projectRoot = process.cwd();
1217
+
1218
+ // Check which directories exist and have files
1219
+ for (const dir of targetDirs) {
1220
+ const validatedDirPath = SecurityUtils.validatePath(dir.path, projectRoot);
1221
+ if (validatedDirPath && SecurityUtils.safeExistsSync(validatedDirPath, projectRoot)) {
1222
+ const files = this.getAllReportFiles(validatedDirPath, validatedDirPath);
1223
+ if (files.length > 0) {
1224
+ availableDirs.push({
1225
+ ...dir,
1226
+ path: validatedDirPath,
1227
+ files: files.map(file => ({ path: file, dir: validatedDirPath })),
1228
+ count: files.length
1229
+ });
1230
+ }
1234
1231
  }
1235
1232
  }
1236
1233
 
@@ -1329,15 +1326,20 @@ class I18nManager {
1329
1326
  if (confirm.toLowerCase() === 'y' || confirm.toLowerCase() === 'yes') {
1330
1327
  let deletedCount = 0;
1331
1328
 
1332
- for (const fileInfo of filesToDelete) {
1333
- try {
1334
- require('fs').unlinkSync(fileInfo.path);
1335
- console.log(t('operations.deletedFile', { filename: path.basename(fileInfo.path) }));
1336
- deletedCount++;
1337
- } catch (error) {
1338
- console.log(t('operations.failedToDeleteFile', { filename: path.basename(fileInfo.path), error: error.message }));
1339
- }
1340
- }
1329
+ for (const fileInfo of filesToDelete) {
1330
+ try {
1331
+ const validatedDeletePath = SecurityUtils.validatePath(fileInfo.path, process.cwd());
1332
+ if (!validatedDeletePath) {
1333
+ console.log(t('operations.failedToDeleteFile', { filename: path.basename(fileInfo.path), error: 'Invalid path' }));
1334
+ continue;
1335
+ }
1336
+ fs.unlinkSync(validatedDeletePath);
1337
+ console.log(t('operations.deletedFile', { filename: path.basename(validatedDeletePath) }));
1338
+ deletedCount++;
1339
+ } catch (error) {
1340
+ console.log(t('operations.failedToDeleteFile', { filename: path.basename(fileInfo.path), error: error.message }));
1341
+ }
1342
+ }
1341
1343
 
1342
1344
  console.log(`\n🎉 Successfully deleted ${deletedCount} files!`);
1343
1345
  } else {
@@ -1352,30 +1354,41 @@ class I18nManager {
1352
1354
  await this.showInteractiveMenu();
1353
1355
  }
1354
1356
 
1355
- getAllReportFiles(dir) {
1356
- if (!dir || typeof dir !== 'string') {
1357
- return [];
1358
- }
1359
-
1360
- let files = [];
1361
-
1362
- try {
1363
- if (!SecurityUtils.safeExistsSync(dir)) {
1364
- return [];
1365
- }
1366
-
1367
- const items = require('fs').readdirSync(dir);
1368
- for (const item of items) {
1369
- const fullPath = path.join(dir, item);
1370
-
1371
- try {
1372
- const stat = require('fs').statSync(fullPath);
1373
-
1374
- if (stat.isDirectory()) {
1375
- files.push(...this.getAllReportFiles(fullPath));
1376
- } else if (
1377
- // Common report file extensions
1378
- item.endsWith('.json') ||
1357
+ getAllReportFiles(dir, rootDir = dir) {
1358
+ if (!dir || typeof dir !== 'string') {
1359
+ return [];
1360
+ }
1361
+
1362
+ let files = [];
1363
+
1364
+ try {
1365
+ const validatedDir = SecurityUtils.validatePath(dir, rootDir);
1366
+ if (!validatedDir || !SecurityUtils.safeExistsSync(validatedDir, rootDir)) {
1367
+ return [];
1368
+ }
1369
+
1370
+ const items = fs.readdirSync(validatedDir);
1371
+ for (const item of items) {
1372
+ const fullPath = path.join(validatedDir, item);
1373
+
1374
+ try {
1375
+ const linkStat = fs.lstatSync(fullPath);
1376
+ if (linkStat.isSymbolicLink()) {
1377
+ continue;
1378
+ }
1379
+
1380
+ const safeFullPath = SecurityUtils.validatePath(fullPath, rootDir);
1381
+ if (!safeFullPath) {
1382
+ continue;
1383
+ }
1384
+
1385
+ const stat = fs.statSync(safeFullPath);
1386
+
1387
+ if (stat.isDirectory()) {
1388
+ files.push(...this.getAllReportFiles(safeFullPath, rootDir));
1389
+ } else if (
1390
+ // Common report file extensions
1391
+ item.endsWith('.json') ||
1379
1392
  item.endsWith('.html') ||
1380
1393
  item.endsWith('.txt') ||
1381
1394
  item.endsWith('.log') ||
@@ -1386,13 +1399,13 @@ class I18nManager {
1386
1399
  item.includes('_report.') ||
1387
1400
  item.includes('report-') ||
1388
1401
  item.includes('report_') ||
1389
- item.includes('analysis-') ||
1390
- item.includes('validation-')
1391
- ) {
1392
- files.push(fullPath);
1393
- }
1394
- } catch (error) {
1395
- // Skip individual files that can't be accessed
1402
+ item.includes('analysis-') ||
1403
+ item.includes('validation-')
1404
+ ) {
1405
+ files.push(safeFullPath);
1406
+ }
1407
+ } catch (error) {
1408
+ // Skip individual files that can't be accessed
1396
1409
  continue;
1397
1410
  }
1398
1411
  }
@@ -1404,12 +1417,12 @@ class I18nManager {
1404
1417
  return files;
1405
1418
  }
1406
1419
 
1407
- getFilesToDeleteKeepLast(allFiles, keepCount = 3) {
1408
- // Sort files by modification time (newest first)
1409
- const sortedFiles = allFiles.sort((a, b) => {
1410
- try {
1411
- const statA = require('fs').statSync(a.path || a);
1412
- const statB = require('fs').statSync(b.path || b);
1420
+ getFilesToDeleteKeepLast(allFiles, keepCount = 3) {
1421
+ // Sort files by modification time (newest first)
1422
+ const sortedFiles = [...allFiles].sort((a, b) => {
1423
+ try {
1424
+ const statA = fs.statSync(a.path || a);
1425
+ const statB = fs.statSync(b.path || b);
1413
1426
  return statB.mtime.getTime() - statA.mtime.getTime();
1414
1427
  } catch (error) {
1415
1428
  // If stat fails, sort by filename as fallback
@@ -1429,8 +1442,7 @@ class I18nManager {
1429
1442
  const authRequired = await this.adminAuth.isAuthRequiredForScript('settingsMenu');
1430
1443
  if (authRequired) {
1431
1444
  console.log(`\n${t('adminPin.protectedAccess')}`);
1432
- const cliHelper = require('../../utils/cli-helper');
1433
- const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
1445
+ const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
1434
1446
  const isValid = await this.adminAuth.verifyPin(pin);
1435
1447
 
1436
1448
  if (!isValid) {
@@ -1443,8 +1455,7 @@ class I18nManager {
1443
1455
  console.log(t('adminPin.accessGranted'));
1444
1456
  }
1445
1457
 
1446
- const SettingsCLI = require('../../settings/settings-cli');
1447
- const settingsCLI = new SettingsCLI();
1458
+ const settingsCLI = new SettingsCLI();
1448
1459
  await settingsCLI.run();
1449
1460
  } catch (error) {
1450
1461
  console.error('❌ Error opening settings:', error.message);
@@ -1454,8 +1465,7 @@ class I18nManager {
1454
1465
  }
1455
1466
 
1456
1467
  prompt(question) {
1457
- const cliHelper = require('../../utils/cli-helper');
1458
- // If interactive not available, return empty string to avoid hangs
1468
+ // If interactive not available, return empty string to avoid hangs
1459
1469
  if (!process.stdin.isTTY || process.stdin.destroyed) {
1460
1470
  console.log('\n⚠️ Interactive input not available, using default response.');
1461
1471
  return Promise.resolve('');
@@ -3,9 +3,10 @@
3
3
  * @module managers/DebugMenu
4
4
  */
5
5
 
6
- const path = require('path');
7
- const fs = require('fs');
8
- const { t } = require('../../../utils/i18n-helper');
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+ const { t } = require('../../../utils/i18n-helper');
9
+ const cliHelper = require('../../../utils/cli-helper');
9
10
 
10
11
  module.exports = class DebugMenu {
11
12
  constructor(manager) {
@@ -21,8 +22,7 @@ module.exports = class DebugMenu {
21
22
  const authRequired = await this.adminAuth.isAuthRequiredForScript('debugMenu');
22
23
  if (authRequired) {
23
24
  console.log(`\n${t('adminPin.protectedAccess')}`);
24
- const cliHelper = require('../../../utils/cli-helper');
25
- const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
25
+ const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
26
26
  const isValid = await this.adminAuth.verifyPin(pin);
27
27
 
28
28
  if (!isValid) {
@@ -137,4 +137,4 @@ module.exports = class DebugMenu {
137
137
  async show() {
138
138
  return this.showDebugMenu();
139
139
  }
140
- };
140
+ };
@@ -3,7 +3,9 @@
3
3
  * @module managers/InteractiveMenu
4
4
  */
5
5
 
6
- const { t } = require('../../../utils/i18n-helper');
6
+ const { t } = require('../../../utils/i18n-helper');
7
+ const cliHelper = require('../../../utils/cli-helper');
8
+ const summaryTool = require('../../i18ntk-summary');
7
9
 
8
10
  module.exports = class InteractiveMenu {
9
11
  constructor(manager) {
@@ -89,8 +91,7 @@ module.exports = class InteractiveMenu {
89
91
  const authRequired = await this.adminAuth.isAuthRequiredForScript('summaryReports');
90
92
  if (authRequired) {
91
93
  console.log(`\n${t('adminCli.protectedAccess')}`);
92
- const cliHelper = require('../../../utils/cli-helper');
93
- const pin = await cliHelper.promptPin(t('adminCli.enterPin') + ': ');
94
+ const pin = await cliHelper.promptPin(t('adminCli.enterPin') + ': ');
94
95
  const isValid = await this.adminAuth.verifyPin(pin);
95
96
 
96
97
  if (!isValid) {
@@ -105,8 +106,7 @@ module.exports = class InteractiveMenu {
105
106
 
106
107
  console.log(t('summary.status.generating'));
107
108
  try {
108
- const summaryTool = require('../../i18ntk-summary');
109
- const summary = new summaryTool();
109
+ const summary = new summaryTool();
110
110
  await summary.run({ fromMenu: true });
111
111
  console.log(t('summary.status.completed'));
112
112
 
@@ -174,4 +174,4 @@ module.exports = class InteractiveMenu {
174
174
  async show() {
175
175
  return this.showInteractiveMenu();
176
176
  }
177
- };
177
+ };
@@ -3,7 +3,9 @@
3
3
  * @module managers/LanguageMenu
4
4
  */
5
5
 
6
- const { t } = require('../../../utils/i18n-helper');
6
+ const { t } = require('../../../utils/i18n-helper');
7
+ const { loadTranslations } = require('../../../utils/i18n-helper');
8
+ const SecurityUtils = require('../../../utils/security');
7
9
 
8
10
  module.exports = class LanguageMenu {
9
11
  constructor(manager) {
@@ -45,8 +47,7 @@ module.exports = class LanguageMenu {
45
47
  }
46
48
 
47
49
  // Force reload translations for the entire system
48
- const { loadTranslations } = require('../../../utils/i18n-helper');
49
- loadTranslations(selectedLang);
50
+ loadTranslations(selectedLang);
50
51
 
51
52
  // Return to main menu with new language
52
53
  await this.manager.prompt('\n' + t('language.pressEnterToContinue'));
@@ -64,4 +65,4 @@ module.exports = class LanguageMenu {
64
65
  async show() {
65
66
  return this.showLanguageMenu();
66
67
  }
67
- };
68
+ };
@@ -3,7 +3,9 @@
3
3
  * @module managers/SettingsMenu
4
4
  */
5
5
 
6
- const { t } = require('../../../utils/i18n-helper');
6
+ const { t } = require('../../../utils/i18n-helper');
7
+ const cliHelper = require('../../../utils/cli-helper');
8
+ const SettingsCLI = require('../../../settings/settings-cli');
7
9
 
8
10
  module.exports = class SettingsMenu {
9
11
  constructor(manager) {
@@ -20,8 +22,7 @@ module.exports = class SettingsMenu {
20
22
  const authRequired = await this.adminAuth.isAuthRequiredForScript('settingsMenu');
21
23
  if (authRequired) {
22
24
  console.log(`\n${t('adminPin.protectedAccess')}`);
23
- const cliHelper = require('../../../utils/cli-helper');
24
- const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
25
+ const pin = await cliHelper.promptPin(t('adminPin.enterPin') + ': ');
25
26
  const isValid = await this.adminAuth.verifyPin(pin);
26
27
 
27
28
  if (!isValid) {
@@ -34,8 +35,7 @@ module.exports = class SettingsMenu {
34
35
  console.log(t('adminPin.accessGranted'));
35
36
  }
36
37
 
37
- const SettingsCLI = require('../../../settings/settings-cli');
38
- const settingsCLI = new SettingsCLI();
38
+ const settingsCLI = new SettingsCLI();
39
39
  await settingsCLI.run();
40
40
  } catch (error) {
41
41
  console.error('❌ Error opening settings:', error.message);
@@ -50,4 +50,4 @@ module.exports = class SettingsMenu {
50
50
  async show() {
51
51
  return this.showSettingsMenu();
52
52
  }
53
- };
53
+ };
@@ -4,7 +4,8 @@
4
4
  * @module services/AuthenticationService
5
5
  */
6
6
 
7
- const AdminAuth = require('../../../utils/admin-auth');
7
+ const AdminAuth = require('../../../utils/admin-auth');
8
+ const cliHelper = require('../../../utils/cli-helper');
8
9
 
9
10
  module.exports = class AuthenticationService {
10
11
  constructor(config = {}) {
@@ -74,8 +75,7 @@ module.exports = class AuthenticationService {
74
75
  }
75
76
 
76
77
  console.log(ui ? ui.t('adminCli.authRequired') : 'Admin authentication required');
77
- const cliHelper = require('../../../utils/cli-helper');
78
- const pin = await cliHelper.promptPin(ui ? ui.t('adminCli.enterPin') : 'Enter PIN: ');
78
+ const pin = await cliHelper.promptPin(ui ? ui.t('adminCli.enterPin') : 'Enter PIN: ');
79
79
  const isValid = await this.verifyPin(pin);
80
80
 
81
81
  if (!isValid) {
@@ -131,8 +131,7 @@ module.exports = class AuthenticationService {
131
131
  * @returns {Promise<string>} User input or empty string
132
132
  */
133
133
  async prompt(question) {
134
- const cliHelper = require('../../../utils/cli-helper');
135
- // If interactive not available, return empty string to avoid hangs
134
+ // If interactive not available, return empty string to avoid hangs
136
135
  if (!process.stdin.isTTY || process.stdin.destroyed) {
137
136
  console.log('\n⚠️ Interactive input not available, using default response.');
138
137
  return Promise.resolve('');
@@ -260,4 +259,4 @@ module.exports = class AuthenticationService {
260
259
  process.exit(1);
261
260
  }
262
261
  }
263
- };
262
+ };