devkill 0.12.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.
Files changed (274) hide show
  1. package/LICENSE +21 -0
  2. package/README.es.md +253 -0
  3. package/README.id.md +238 -0
  4. package/README.md +377 -0
  5. package/README.pt.md +241 -0
  6. package/README.tr.md +242 -0
  7. package/lib/cli/cli.controller.d.ts +81 -0
  8. package/lib/cli/cli.controller.js +760 -0
  9. package/lib/cli/cli.controller.js.map +1 -0
  10. package/lib/cli/interfaces/cli-options.interface.d.ts +5 -0
  11. package/lib/cli/interfaces/cli-options.interface.js +2 -0
  12. package/lib/cli/interfaces/cli-options.interface.js.map +1 -0
  13. package/lib/cli/interfaces/command-keys.interface.d.ts +17 -0
  14. package/lib/cli/interfaces/command-keys.interface.js +2 -0
  15. package/lib/cli/interfaces/command-keys.interface.js.map +1 -0
  16. package/lib/cli/interfaces/config.interface.d.ts +17 -0
  17. package/lib/cli/interfaces/config.interface.js +2 -0
  18. package/lib/cli/interfaces/config.interface.js.map +1 -0
  19. package/lib/cli/interfaces/index.d.ts +11 -0
  20. package/lib/cli/interfaces/index.js +12 -0
  21. package/lib/cli/interfaces/index.js.map +1 -0
  22. package/lib/cli/interfaces/json-output.interface.d.ts +30 -0
  23. package/lib/cli/interfaces/json-output.interface.js +2 -0
  24. package/lib/cli/interfaces/json-output.interface.js.map +1 -0
  25. package/lib/cli/interfaces/key-press.interface.d.ts +7 -0
  26. package/lib/cli/interfaces/key-press.interface.js +2 -0
  27. package/lib/cli/interfaces/key-press.interface.js.map +1 -0
  28. package/lib/cli/interfaces/node-version.interface.d.ts +5 -0
  29. package/lib/cli/interfaces/node-version.interface.js +2 -0
  30. package/lib/cli/interfaces/node-version.interface.js.map +1 -0
  31. package/lib/cli/interfaces/stats.interface.d.ts +15 -0
  32. package/lib/cli/interfaces/stats.interface.js +2 -0
  33. package/lib/cli/interfaces/stats.interface.js.map +1 -0
  34. package/lib/cli/interfaces/ui-positions.interface.d.ts +5 -0
  35. package/lib/cli/interfaces/ui-positions.interface.js +2 -0
  36. package/lib/cli/interfaces/ui-positions.interface.js.map +1 -0
  37. package/lib/cli/interfaces/version.interface.d.ts +5 -0
  38. package/lib/cli/interfaces/version.interface.js +2 -0
  39. package/lib/cli/interfaces/version.interface.js.map +1 -0
  40. package/lib/cli/models/start-parameters.model.d.ts +7 -0
  41. package/lib/cli/models/start-parameters.model.js +25 -0
  42. package/lib/cli/models/start-parameters.model.js.map +1 -0
  43. package/lib/cli/services/console.service.d.ts +23 -0
  44. package/lib/cli/services/console.service.js +87 -0
  45. package/lib/cli/services/console.service.js.map +1 -0
  46. package/lib/cli/services/https.service.d.ts +4 -0
  47. package/lib/cli/services/https.service.js +32 -0
  48. package/lib/cli/services/https.service.js.map +1 -0
  49. package/lib/cli/services/index.d.ts +7 -0
  50. package/lib/cli/services/index.js +8 -0
  51. package/lib/cli/services/index.js.map +1 -0
  52. package/lib/cli/services/json-output.service.d.ts +20 -0
  53. package/lib/cli/services/json-output.service.js +101 -0
  54. package/lib/cli/services/json-output.service.js.map +1 -0
  55. package/lib/cli/services/results.service.d.ts +13 -0
  56. package/lib/cli/services/results.service.js +61 -0
  57. package/lib/cli/services/results.service.js.map +1 -0
  58. package/lib/cli/services/scan.service.d.ts +13 -0
  59. package/lib/cli/services/scan.service.js +79 -0
  60. package/lib/cli/services/scan.service.js.map +1 -0
  61. package/lib/cli/services/spinner.service.d.ts +9 -0
  62. package/lib/cli/services/spinner.service.js +27 -0
  63. package/lib/cli/services/spinner.service.js.map +1 -0
  64. package/lib/cli/services/ui.service.d.ts +17 -0
  65. package/lib/cli/services/ui.service.js +59 -0
  66. package/lib/cli/services/ui.service.js.map +1 -0
  67. package/lib/cli/services/update.service.d.ts +15 -0
  68. package/lib/cli/services/update.service.js +37 -0
  69. package/lib/cli/services/update.service.js.map +1 -0
  70. package/lib/cli/ui/base.ui.d.ts +28 -0
  71. package/lib/cli/ui/base.ui.js +49 -0
  72. package/lib/cli/ui/base.ui.js.map +1 -0
  73. package/lib/cli/ui/components/general.ui.d.ts +7 -0
  74. package/lib/cli/ui/components/general.ui.js +13 -0
  75. package/lib/cli/ui/components/general.ui.js.map +1 -0
  76. package/lib/cli/ui/components/header/header-ui.constants.d.ts +7 -0
  77. package/lib/cli/ui/components/header/header-ui.constants.js +7 -0
  78. package/lib/cli/ui/components/header/header-ui.constants.js.map +1 -0
  79. package/lib/cli/ui/components/header/header.ui.d.ts +18 -0
  80. package/lib/cli/ui/components/header/header.ui.js +96 -0
  81. package/lib/cli/ui/components/header/header.ui.js.map +1 -0
  82. package/lib/cli/ui/components/header/stats.ui.d.ts +25 -0
  83. package/lib/cli/ui/components/header/stats.ui.js +198 -0
  84. package/lib/cli/ui/components/header/stats.ui.js.map +1 -0
  85. package/lib/cli/ui/components/header/status.ui.d.ts +33 -0
  86. package/lib/cli/ui/components/header/status.ui.js +188 -0
  87. package/lib/cli/ui/components/header/status.ui.js.map +1 -0
  88. package/lib/cli/ui/components/help/help-command.ui.d.ts +9 -0
  89. package/lib/cli/ui/components/help/help-command.ui.js +61 -0
  90. package/lib/cli/ui/components/help/help-command.ui.js.map +1 -0
  91. package/lib/cli/ui/components/help/help.constants.d.ts +8 -0
  92. package/lib/cli/ui/components/help/help.constants.js +270 -0
  93. package/lib/cli/ui/components/help/help.constants.js.map +1 -0
  94. package/lib/cli/ui/components/help/help.ui.d.ts +30 -0
  95. package/lib/cli/ui/components/help/help.ui.js +176 -0
  96. package/lib/cli/ui/components/help/help.ui.js.map +1 -0
  97. package/lib/cli/ui/components/logs.ui.d.ts +24 -0
  98. package/lib/cli/ui/components/logs.ui.js +132 -0
  99. package/lib/cli/ui/components/logs.ui.js.map +1 -0
  100. package/lib/cli/ui/components/options.ui.d.ts +29 -0
  101. package/lib/cli/ui/components/options.ui.js +327 -0
  102. package/lib/cli/ui/components/options.ui.js.map +1 -0
  103. package/lib/cli/ui/components/profile-picker.ui.d.ts +25 -0
  104. package/lib/cli/ui/components/profile-picker.ui.js +117 -0
  105. package/lib/cli/ui/components/profile-picker.ui.js.map +1 -0
  106. package/lib/cli/ui/components/result-details.ui.d.ts +23 -0
  107. package/lib/cli/ui/components/result-details.ui.js +182 -0
  108. package/lib/cli/ui/components/result-details.ui.js.map +1 -0
  109. package/lib/cli/ui/components/results.ui.d.ts +86 -0
  110. package/lib/cli/ui/components/results.ui.js +620 -0
  111. package/lib/cli/ui/components/results.ui.js.map +1 -0
  112. package/lib/cli/ui/components/warning.ui.d.ts +12 -0
  113. package/lib/cli/ui/components/warning.ui.js +30 -0
  114. package/lib/cli/ui/components/warning.ui.js.map +1 -0
  115. package/lib/cli/ui/heavy.ui.d.ts +18 -0
  116. package/lib/cli/ui/heavy.ui.js +37 -0
  117. package/lib/cli/ui/heavy.ui.js.map +1 -0
  118. package/lib/cli/ui/index.d.ts +14 -0
  119. package/lib/cli/ui/index.js +15 -0
  120. package/lib/cli/ui/index.js.map +1 -0
  121. package/lib/constants/cli.constants.d.ts +14 -0
  122. package/lib/constants/cli.constants.js +138 -0
  123. package/lib/constants/cli.constants.js.map +1 -0
  124. package/lib/constants/index.d.ts +8 -0
  125. package/lib/constants/index.js +9 -0
  126. package/lib/constants/index.js.map +1 -0
  127. package/lib/constants/main.constants.d.ts +96 -0
  128. package/lib/constants/main.constants.js +79 -0
  129. package/lib/constants/main.constants.js.map +1 -0
  130. package/lib/constants/messages.constants.d.ts +31 -0
  131. package/lib/constants/messages.constants.js +37 -0
  132. package/lib/constants/messages.constants.js.map +1 -0
  133. package/lib/constants/options.constants.d.ts +6 -0
  134. package/lib/constants/options.constants.js +8 -0
  135. package/lib/constants/options.constants.js.map +1 -0
  136. package/lib/constants/os-service-map.constants.d.ts +10 -0
  137. package/lib/constants/os-service-map.constants.js +11 -0
  138. package/lib/constants/os-service-map.constants.js.map +1 -0
  139. package/lib/constants/result-descriptions.constants.d.ts +142 -0
  140. package/lib/constants/result-descriptions.constants.js +203 -0
  141. package/lib/constants/result-descriptions.constants.js.map +1 -0
  142. package/lib/constants/sort.result.d.ts +6 -0
  143. package/lib/constants/sort.result.js +22 -0
  144. package/lib/constants/sort.result.js.map +1 -0
  145. package/lib/constants/spinner.constants.d.ts +5 -0
  146. package/lib/constants/spinner.constants.js +88 -0
  147. package/lib/constants/spinner.constants.js.map +1 -0
  148. package/lib/constants/status.constants.d.ts +7 -0
  149. package/lib/constants/status.constants.js +9 -0
  150. package/lib/constants/status.constants.js.map +1 -0
  151. package/lib/constants/update.constants.d.ts +2 -0
  152. package/lib/constants/update.constants.js +3 -0
  153. package/lib/constants/update.constants.js.map +1 -0
  154. package/lib/constants/workers.constants.d.ts +14 -0
  155. package/lib/constants/workers.constants.js +16 -0
  156. package/lib/constants/workers.constants.js.map +1 -0
  157. package/lib/core/constants/global-ignored.constants.d.ts +1 -0
  158. package/lib/core/constants/global-ignored.constants.js +44 -0
  159. package/lib/core/constants/global-ignored.constants.js.map +1 -0
  160. package/lib/core/constants/index.d.ts +1 -0
  161. package/lib/core/constants/index.js +2 -0
  162. package/lib/core/constants/index.js.map +1 -0
  163. package/lib/core/constants/profiles.constants.d.ts +8 -0
  164. package/lib/core/constants/profiles.constants.js +138 -0
  165. package/lib/core/constants/profiles.constants.js.map +1 -0
  166. package/lib/core/devkill.d.ts +25 -0
  167. package/lib/core/devkill.js +129 -0
  168. package/lib/core/devkill.js.map +1 -0
  169. package/lib/core/index.d.ts +4 -0
  170. package/lib/core/index.js +5 -0
  171. package/lib/core/index.js.map +1 -0
  172. package/lib/core/interfaces/devkill.interface.d.ts +78 -0
  173. package/lib/core/interfaces/devkill.interface.js +2 -0
  174. package/lib/core/interfaces/devkill.interface.js.map +1 -0
  175. package/lib/core/interfaces/devkillrc-config.interface.d.ts +87 -0
  176. package/lib/core/interfaces/devkillrc-config.interface.js +12 -0
  177. package/lib/core/interfaces/devkillrc-config.interface.js.map +1 -0
  178. package/lib/core/interfaces/file-service.interface.d.ts +76 -0
  179. package/lib/core/interfaces/file-service.interface.js +2 -0
  180. package/lib/core/interfaces/file-service.interface.js.map +1 -0
  181. package/lib/core/interfaces/folder.interface.d.ts +89 -0
  182. package/lib/core/interfaces/folder.interface.js +2 -0
  183. package/lib/core/interfaces/folder.interface.js.map +1 -0
  184. package/lib/core/interfaces/index.d.ts +6 -0
  185. package/lib/core/interfaces/index.js +7 -0
  186. package/lib/core/interfaces/index.js.map +1 -0
  187. package/lib/core/interfaces/logger-service.interface.d.ts +59 -0
  188. package/lib/core/interfaces/logger-service.interface.js +2 -0
  189. package/lib/core/interfaces/logger-service.interface.js.map +1 -0
  190. package/lib/core/interfaces/npkill.interface.d.ts +78 -0
  191. package/lib/core/interfaces/npkill.interface.js +2 -0
  192. package/lib/core/interfaces/npkill.interface.js.map +1 -0
  193. package/lib/core/interfaces/npkillrc-config.interface.d.ts +87 -0
  194. package/lib/core/interfaces/npkillrc-config.interface.js +12 -0
  195. package/lib/core/interfaces/npkillrc-config.interface.js.map +1 -0
  196. package/lib/core/interfaces/profile.interface.d.ts +9 -0
  197. package/lib/core/interfaces/profile.interface.js +2 -0
  198. package/lib/core/interfaces/profile.interface.js.map +1 -0
  199. package/lib/core/interfaces/search-status.model.d.ts +35 -0
  200. package/lib/core/interfaces/search-status.model.js +48 -0
  201. package/lib/core/interfaces/search-status.model.js.map +1 -0
  202. package/lib/core/interfaces/services.interface.d.ts +26 -0
  203. package/lib/core/interfaces/services.interface.js +2 -0
  204. package/lib/core/interfaces/services.interface.js.map +1 -0
  205. package/lib/core/npkill.d.ts +25 -0
  206. package/lib/core/npkill.js +129 -0
  207. package/lib/core/npkill.js.map +1 -0
  208. package/lib/core/services/config/config-merger.d.ts +17 -0
  209. package/lib/core/services/config/config-merger.js +57 -0
  210. package/lib/core/services/config/config-merger.js.map +1 -0
  211. package/lib/core/services/config/config-validator.d.ts +3 -0
  212. package/lib/core/services/config/config-validator.js +43 -0
  213. package/lib/core/services/config/config-validator.js.map +1 -0
  214. package/lib/core/services/config/index.d.ts +4 -0
  215. package/lib/core/services/config/index.js +5 -0
  216. package/lib/core/services/config/index.js.map +1 -0
  217. package/lib/core/services/config/profile-validator.d.ts +6 -0
  218. package/lib/core/services/config/profile-validator.js +68 -0
  219. package/lib/core/services/config/profile-validator.js.map +1 -0
  220. package/lib/core/services/config/property-validators.d.ts +33 -0
  221. package/lib/core/services/config/property-validators.js +125 -0
  222. package/lib/core/services/config/property-validators.js.map +1 -0
  223. package/lib/core/services/config.service.d.ts +37 -0
  224. package/lib/core/services/config.service.js +100 -0
  225. package/lib/core/services/config.service.js.map +1 -0
  226. package/lib/core/services/files/files.service.d.ts +28 -0
  227. package/lib/core/services/files/files.service.js +207 -0
  228. package/lib/core/services/files/files.service.js.map +1 -0
  229. package/lib/core/services/files/files.worker.d.ts +1 -0
  230. package/lib/core/services/files/files.worker.js +286 -0
  231. package/lib/core/services/files/files.worker.js.map +1 -0
  232. package/lib/core/services/files/files.worker.service.d.ts +90 -0
  233. package/lib/core/services/files/files.worker.service.js +216 -0
  234. package/lib/core/services/files/files.worker.service.js.map +1 -0
  235. package/lib/core/services/files/index.d.ts +4 -0
  236. package/lib/core/services/files/index.js +5 -0
  237. package/lib/core/services/files/index.js.map +1 -0
  238. package/lib/core/services/files/unix-files.service.d.ts +9 -0
  239. package/lib/core/services/files/unix-files.service.js +28 -0
  240. package/lib/core/services/files/unix-files.service.js.map +1 -0
  241. package/lib/core/services/files/windows-files.service.d.ts +9 -0
  242. package/lib/core/services/files/windows-files.service.js +16 -0
  243. package/lib/core/services/files/windows-files.service.js.map +1 -0
  244. package/lib/core/services/index.d.ts +5 -0
  245. package/lib/core/services/index.js +6 -0
  246. package/lib/core/services/index.js.map +1 -0
  247. package/lib/core/services/logger.service.d.ts +22 -0
  248. package/lib/core/services/logger.service.js +84 -0
  249. package/lib/core/services/logger.service.js.map +1 -0
  250. package/lib/core/services/profiles.service.d.ts +54 -0
  251. package/lib/core/services/profiles.service.js +86 -0
  252. package/lib/core/services/profiles.service.js.map +1 -0
  253. package/lib/core/services/stream.service.d.ts +12 -0
  254. package/lib/core/services/stream.service.js +39 -0
  255. package/lib/core/services/stream.service.js.map +1 -0
  256. package/lib/dirname.d.ts +2 -0
  257. package/lib/dirname.js +6 -0
  258. package/lib/dirname.js.map +1 -0
  259. package/lib/index.d.ts +2 -0
  260. package/lib/index.js +11 -0
  261. package/lib/index.js.map +1 -0
  262. package/lib/main.d.ts +2 -0
  263. package/lib/main.js +19 -0
  264. package/lib/main.js.map +1 -0
  265. package/lib/utils/get-file-content.d.ts +1 -0
  266. package/lib/utils/get-file-content.js +6 -0
  267. package/lib/utils/get-file-content.js.map +1 -0
  268. package/lib/utils/is-safe-to-delete.d.ts +1 -0
  269. package/lib/utils/is-safe-to-delete.js +9 -0
  270. package/lib/utils/is-safe-to-delete.js.map +1 -0
  271. package/lib/utils/unit-conversions.d.ts +11 -0
  272. package/lib/utils/unit-conversions.js +54 -0
  273. package/lib/utils/unit-conversions.js.map +1 -0
  274. package/package.json +96 -0
@@ -0,0 +1,760 @@
1
+ import { Subject, firstValueFrom } from 'rxjs';
2
+ import { mergeMap, tap } from 'rxjs/operators';
3
+ import { DEFAULT_CONFIG, MIN_CLI_COLUMNS_SIZE, UI_POSITIONS, } from '../constants/index.js';
4
+ import { ERROR_MSG, INFO_MSGS } from '../constants/messages.constants.js';
5
+ import { DEFAULT_PROFILE } from '../core/constants/profiles.constants.js';
6
+ import { COLORS } from '../constants/cli.constants.js';
7
+ import { FOLDER_SORT } from '../constants/sort.result.js';
8
+ import { MENU_BAR_OPTIONS } from './ui/components/header/header-ui.constants.js';
9
+ import { GeneralUi, HeaderUi, HelpCommandUi, HelpUi, LogsUi, OptionsUi, ProfilePickerUi, ResultsUi, StatsUi, StatusUi, WarningUi, } from './ui/index.js';
10
+ import { homedir } from 'node:os';
11
+ import path from 'node:path';
12
+ import openExplorer from 'open-file-explorer';
13
+ import pc from 'picocolors';
14
+ import _dirname from '../dirname.js';
15
+ import { getFileContent } from '../utils/get-file-content.js';
16
+ import { isSafeToDelete } from '../utils/is-safe-to-delete.js';
17
+ import { ResultDetailsUi } from './ui/components/result-details.ui.js';
18
+ export class CliController {
19
+ stdout;
20
+ npkill;
21
+ logger;
22
+ searchStatus;
23
+ resultsService;
24
+ spinnerService;
25
+ consoleService;
26
+ updateService;
27
+ uiService;
28
+ scanService;
29
+ jsonOutputService;
30
+ profilesService;
31
+ configService;
32
+ config = DEFAULT_CONFIG;
33
+ profilesExplicitlySet = false;
34
+ searchStart;
35
+ searchDuration;
36
+ uiHeader;
37
+ uiGeneral;
38
+ uiStats;
39
+ uiStatus;
40
+ uiResults;
41
+ uiLogs;
42
+ uiWarning;
43
+ activeComponent = null;
44
+ constructor(stdout, npkill, logger, searchStatus, resultsService, spinnerService, consoleService, updateService, uiService, scanService, jsonOutputService, profilesService, configService) {
45
+ this.stdout = stdout;
46
+ this.npkill = npkill;
47
+ this.logger = logger;
48
+ this.searchStatus = searchStatus;
49
+ this.resultsService = resultsService;
50
+ this.spinnerService = spinnerService;
51
+ this.consoleService = consoleService;
52
+ this.updateService = updateService;
53
+ this.uiService = uiService;
54
+ this.scanService = scanService;
55
+ this.jsonOutputService = jsonOutputService;
56
+ this.profilesService = profilesService;
57
+ this.configService = configService;
58
+ }
59
+ init() {
60
+ this.logger.info(`Devkill CLI started! v${this.getVersion()}`);
61
+ this.loadConfigFile();
62
+ this.parseArguments();
63
+ if (this.config.jsonStream) {
64
+ this.logger.info('JSON stream mode enabled.');
65
+ this.setupJsonModeSignalHandlers();
66
+ this.scan();
67
+ return;
68
+ }
69
+ if (this.config.jsonSimple) {
70
+ this.logger.info('JSON simple mode enabled.');
71
+ this.setupJsonModeSignalHandlers();
72
+ this.scan();
73
+ return;
74
+ }
75
+ this.initUi();
76
+ if (this.consoleService.isRunningBuild()) {
77
+ this.uiHeader.programVersion = this.getVersion();
78
+ }
79
+ this.consoleService.startListenKeyEvents();
80
+ this.checkRequirements();
81
+ this.prepareScreen();
82
+ this.setupEventsListener();
83
+ if (this.config.checkUpdates) {
84
+ this.checkVersion();
85
+ }
86
+ if (!this.profilesExplicitlySet) {
87
+ this.showProfilePicker();
88
+ return;
89
+ }
90
+ if (this.config.deleteAll && !this.config.yes) {
91
+ this.showDeleteAllWarning();
92
+ this.uiWarning.confirm$
93
+ .pipe(tap(() => {
94
+ this.activeComponent = this.uiResults;
95
+ this.uiWarning.setDeleteAllWarningVisibility(false);
96
+ this.uiService.renderAll();
97
+ this.scan();
98
+ }))
99
+ .subscribe();
100
+ return;
101
+ }
102
+ this.scan();
103
+ }
104
+ showProfilePicker() {
105
+ const picker = new ProfilePickerUi(this.profilesService, this.config.profiles);
106
+ this.uiService.add(picker);
107
+ this.activeComponent = picker;
108
+ this.uiResults.setVisible(false);
109
+ this.uiService.renderAll();
110
+ picker.render();
111
+ picker.confirm$.subscribe((selectedProfiles) => {
112
+ picker.clear();
113
+ this.uiService.remove(picker.id);
114
+ this.config.profiles = selectedProfiles;
115
+ this.config.targets =
116
+ this.profilesService.getTargetsFromProfiles(selectedProfiles);
117
+ this.uiResults.setVisible(true);
118
+ this.activeComponent = this.uiResults;
119
+ this.uiService.renderAll();
120
+ this.scan();
121
+ });
122
+ picker.skip$.subscribe(() => {
123
+ picker.clear();
124
+ this.uiService.remove(picker.id);
125
+ this.uiResults.setVisible(true);
126
+ this.activeComponent = this.uiResults;
127
+ this.uiService.renderAll();
128
+ this.scan();
129
+ });
130
+ }
131
+ showDeleteAllWarning() {
132
+ this.uiWarning.setDeleteAllWarningVisibility(true);
133
+ this.activeComponent = this.uiWarning;
134
+ }
135
+ initUi() {
136
+ this.uiHeader = new HeaderUi(this.config);
137
+ this.uiService.add(this.uiHeader);
138
+ this.uiResults = new ResultsUi(this.resultsService, this.consoleService);
139
+ this.uiService.add(this.uiResults);
140
+ this.uiStats = new StatsUi(this.config, this.resultsService, this.logger);
141
+ this.uiService.add(this.uiStats);
142
+ this.uiStatus = new StatusUi(this.spinnerService, this.searchStatus);
143
+ this.uiService.add(this.uiStatus);
144
+ this.uiGeneral = new GeneralUi();
145
+ this.uiService.add(this.uiGeneral);
146
+ this.uiLogs = new LogsUi(this.logger);
147
+ this.uiService.add(this.uiLogs);
148
+ this.uiWarning = new WarningUi();
149
+ this.uiService.add(this.uiWarning);
150
+ // Set Events
151
+ this.uiResults.delete$.subscribe((folder) => this.deleteFolder(folder));
152
+ this.uiResults.showErrors$.subscribe(() => this.showErrorPopup(true));
153
+ this.uiLogs.close$.subscribe(() => this.showErrorPopup(false));
154
+ this.uiResults.openFolder$.subscribe((path) => openExplorer(path));
155
+ this.uiResults.showDetails$.subscribe((folder) => this.openResultsDetails(folder));
156
+ this.uiResults.endNpkill$.subscribe(() => this.quit());
157
+ this.uiResults.goOptions$.subscribe(() => this.openOptions());
158
+ this.uiResults.search$.subscribe((state) => {
159
+ if (state === null) {
160
+ this.uiHeader.setSearch(null);
161
+ }
162
+ else {
163
+ this.uiHeader.setSearch(state.text, state.isInputActive);
164
+ }
165
+ });
166
+ // Activate the main interactive component
167
+ this.activeComponent = this.uiResults;
168
+ }
169
+ openOptions() {
170
+ const changeConfig$ = new Subject();
171
+ const optionsUi = new OptionsUi(changeConfig$, this.config);
172
+ this.uiResults.clear();
173
+ this.uiResults.setVisible(false);
174
+ this.uiService.add(optionsUi);
175
+ this.activeComponent = optionsUi;
176
+ this.uiHeader.menuIndex$.next(MENU_BAR_OPTIONS.OPTIONS);
177
+ this.uiStats.reset();
178
+ this.uiService.renderAll();
179
+ changeConfig$.subscribe((configChanges) => {
180
+ Object.assign(this.config, configChanges);
181
+ if (configChanges.profiles !== undefined) {
182
+ const validProfiles = configChanges.profiles.filter((p) => this.profilesService.getInvalidProfileNames([p]).length === 0);
183
+ const resolvedTargets = validProfiles.length > 0
184
+ ? this.profilesService.getTargetsFromProfiles(validProfiles)
185
+ : this.config.targets;
186
+ this.config.profiles = validProfiles;
187
+ this.config.targets = resolvedTargets;
188
+ this.scan();
189
+ }
190
+ else if (configChanges.targets ||
191
+ configChanges.folderRoot ||
192
+ Object.keys(configChanges).includes('excludeSensitiveResults') ||
193
+ configChanges.exclude) {
194
+ this.scan();
195
+ }
196
+ if (configChanges.sortBy) {
197
+ this.resultsService.sortResults(configChanges.sortBy);
198
+ }
199
+ if (configChanges.sizeUnit) {
200
+ this.resultsService.setSizeUnit(configChanges.sizeUnit);
201
+ }
202
+ this.logger.info(`Config updated: ${JSON.stringify(configChanges)}`);
203
+ this.uiService.renderAll();
204
+ });
205
+ optionsUi.goToHelp$.subscribe(() => {
206
+ const helpUi = new HelpUi();
207
+ this.uiService.add(helpUi);
208
+ this.activeComponent = helpUi;
209
+ optionsUi.clear();
210
+ optionsUi.setVisible(false);
211
+ this.uiHeader.menuIndex$.next(MENU_BAR_OPTIONS.HELP);
212
+ this.uiStats.reset();
213
+ this.uiService.renderAll();
214
+ helpUi.render();
215
+ helpUi.goToOptions$.subscribe(() => {
216
+ helpUi.clear();
217
+ this.activeComponent = optionsUi;
218
+ this.uiService.remove(helpUi.id);
219
+ optionsUi.clear();
220
+ optionsUi.setVisible(true);
221
+ this.uiHeader.menuIndex$.next(MENU_BAR_OPTIONS.OPTIONS);
222
+ this.uiStats.reset();
223
+ this.uiService.renderAll();
224
+ });
225
+ });
226
+ optionsUi.goBack$.subscribe(() => {
227
+ optionsUi.clear();
228
+ this.activeComponent = this.uiResults;
229
+ this.uiService.remove(optionsUi.id);
230
+ this.uiResults.clear();
231
+ this.uiResults.setVisible(true);
232
+ this.uiHeader.menuIndex$.next(MENU_BAR_OPTIONS.DELETE);
233
+ this.uiStats.reset();
234
+ this.uiService.renderAll();
235
+ });
236
+ }
237
+ openResultsDetails(folder) {
238
+ const detailsUi = new ResultDetailsUi(folder, this.config);
239
+ this.uiResults.clear();
240
+ this.uiResults.setVisible(false);
241
+ this.uiService.add(detailsUi);
242
+ this.activeComponent = detailsUi;
243
+ // detailsUi.render();
244
+ this.uiHeader.menuIndex$.next(MENU_BAR_OPTIONS.INFO);
245
+ this.uiStats.reset();
246
+ this.uiService.renderAll();
247
+ detailsUi.openFolder$.subscribe((path) => openExplorer(path));
248
+ detailsUi.goBack$.subscribe(() => {
249
+ detailsUi.clear();
250
+ this.activeComponent = this.uiResults;
251
+ this.uiService.remove(detailsUi.id);
252
+ this.uiResults.clear();
253
+ this.uiResults.setVisible(true);
254
+ this.uiHeader.menuIndex$.next(MENU_BAR_OPTIONS.DELETE);
255
+ this.uiStats.reset();
256
+ this.uiService.renderAll();
257
+ });
258
+ }
259
+ loadConfigFile() {
260
+ const configPathArg = process.argv.indexOf('--config');
261
+ const customConfigPath = configPathArg !== -1 ? process.argv[configPathArg + 1] : undefined;
262
+ const result = this.configService.loadConfig(customConfigPath);
263
+ if (result.error) {
264
+ const isDefaultLocationNotFound = !customConfigPath && result.error === undefined;
265
+ if (isDefaultLocationNotFound) {
266
+ this.logger.info(`No config file found at ${result.configPath}`);
267
+ }
268
+ else {
269
+ this.logger.error(`Configuration error: ${result.error}`);
270
+ console.log(`${pc.red(pc.bold('Configuration Error'))} (${pc.yellow(result.configPath)})`);
271
+ console.log(pc.red(`${result.error}\n`));
272
+ console.log(pc.gray('Please fix the configuration file and try again.\n' +
273
+ 'For configuration reference, see: https://devkill.js.org/docs/devkillrc'));
274
+ this.exitWithError();
275
+ }
276
+ }
277
+ if (!result.config) {
278
+ return;
279
+ }
280
+ this.logger.info(`Loaded config from ${result.configPath}`);
281
+ if (result.config.rootDir !== undefined) {
282
+ this.config.folderRoot = result.config.rootDir;
283
+ }
284
+ if (result.config.exclude !== undefined) {
285
+ this.config.exclude = [
286
+ ...new Set([...this.config.exclude, ...result.config.exclude]),
287
+ ];
288
+ }
289
+ if (result.config.sortBy !== undefined) {
290
+ this.config.sortBy = result.config.sortBy;
291
+ }
292
+ if (result.config.sizeUnit !== undefined) {
293
+ this.config.sizeUnit = result.config.sizeUnit;
294
+ }
295
+ if (result.config.excludeSensitiveResults !== undefined) {
296
+ this.config.excludeSensitiveResults =
297
+ result.config.excludeSensitiveResults;
298
+ }
299
+ if (result.config.dryRun !== undefined) {
300
+ this.config.dryRun = result.config.dryRun;
301
+ }
302
+ if (result.config.checkUpdates !== undefined) {
303
+ this.config.checkUpdates = result.config.checkUpdates;
304
+ }
305
+ const userProfiles = this.configService.getUserDefinedProfiles(result.config);
306
+ const profileCount = Object.keys(userProfiles).length;
307
+ if (profileCount > 0) {
308
+ this.profilesService.setUserDefinedProfiles(userProfiles);
309
+ this.logger.info(`Loaded ${profileCount} custom profile(s) from config`);
310
+ }
311
+ if (result.config.defaultProfiles !== undefined) {
312
+ // Store default profiles from config to be used later if no CLI profiles are specified
313
+ this.config.profiles = result.config.defaultProfiles;
314
+ this.profilesExplicitlySet = true;
315
+ this.logger.info(`Default profiles set from config: ${result.config.defaultProfiles.join(', ')}`);
316
+ }
317
+ }
318
+ parseArguments() {
319
+ const options = this.consoleService.getParameters(process.argv);
320
+ if (options.isTrue('help')) {
321
+ this.showHelp();
322
+ this.exitGracefully();
323
+ }
324
+ if (options.isTrue('version')) {
325
+ this.showProgramVersion();
326
+ this.exitGracefully();
327
+ }
328
+ if (options.isTrue('profiles') && options.isTrue('target-folders')) {
329
+ console.log('Cannot use both --profiles and --targets options together.');
330
+ this.exitGracefully();
331
+ }
332
+ if (options.isTrue('profiles') &&
333
+ options.getStrings('profiles').length === 0) {
334
+ console.log(pc.bold(pc.bgYellow(pc.black(' Available profiles '))));
335
+ console.log(`Remember: ${pc.bold(pc.yellow('context matters'))}. What's safe to remove in one project or ecosystem could be important in another.\n`);
336
+ const defaultProfiles = this.config.profiles.length > 0
337
+ ? this.config.profiles
338
+ : [DEFAULT_PROFILE];
339
+ const userProfiles = this.profilesService.getProfiles('user');
340
+ const baseProfiles = this.profilesService.getProfiles('base');
341
+ let profilesToPrint = '';
342
+ if (Object.keys(userProfiles).length > 0) {
343
+ profilesToPrint += Object.entries(userProfiles).reduce((acc, [name, profile]) => {
344
+ const isDefault = defaultProfiles.includes(name);
345
+ const entry = ` ${pc.green(name)}${isDefault ? pc.italic(pc.magenta(' (default)')) : ''} ${pc.cyan('(user-defined)')} - ${profile.description}\n${pc.gray(` ${profile.targets.join(pc.italic(','))}\n\n`)}`;
346
+ return acc + entry;
347
+ }, '');
348
+ }
349
+ profilesToPrint += Object.entries(baseProfiles).reduce((acc, [name, profile]) => {
350
+ const isDefault = defaultProfiles.includes(name);
351
+ const entry = ` ${pc.green(name)}${isDefault ? pc.italic(pc.magenta(' (default)')) : ''} - ${profile.description}\n${pc.gray(` ${profile.targets.join(pc.italic(','))}\n\n`)}`;
352
+ return acc + entry;
353
+ }, '');
354
+ console.log(profilesToPrint);
355
+ this.exitGracefully();
356
+ }
357
+ if (options.isTrue('delete-all')) {
358
+ if (!options.isTrue('target-folders') || options.isTrue('profiles')) {
359
+ // TODO mejorar mensaje e incluir tip buscar lista targets de un profile.
360
+ console.log('--delete-all only can be used with --targets.');
361
+ console.log('You can copy all targets from a profile with `devkill --profiles`.');
362
+ this.exitWithError();
363
+ }
364
+ this.config.deleteAll = true;
365
+ }
366
+ if (options.isTrue('sort-by')) {
367
+ if (!this.isValidSortParam(options.getString('sort-by'))) {
368
+ this.invalidSortParam();
369
+ }
370
+ this.config.sortBy = options.getString('sort-by');
371
+ }
372
+ const exclude = options.getString('exclude');
373
+ if (exclude !== undefined && exclude !== '') {
374
+ console.log('EXCLUDE', exclude);
375
+ const userExcludeList = this.consoleService
376
+ .splitData(this.consoleService.replaceString(exclude, '"', ''), ',')
377
+ .map((path) => path.trim())
378
+ .filter(Boolean)
379
+ .map(path.normalize);
380
+ // Add custom filters to the default exclude list.
381
+ this.config.exclude = [...this.config.exclude, ...userExcludeList];
382
+ }
383
+ // Set folder root: CLI --directory takes precedence, then config rootDir, then process.cwd()
384
+ if (options.isTrue('directory')) {
385
+ this.config.folderRoot = options.getString('directory');
386
+ }
387
+ else if (!this.config.folderRoot) {
388
+ // Only use process.cwd() if folderRoot wasn't set by config
389
+ this.config.folderRoot = process.cwd();
390
+ }
391
+ if (options.isTrue('full-scan')) {
392
+ this.config.folderRoot = homedir();
393
+ }
394
+ if (options.isTrue('hide-errors')) {
395
+ this.config.showErrors = false;
396
+ }
397
+ if (options.isTrue('size-unit')) {
398
+ const sizeUnit = options.getString('size-unit');
399
+ if (this.isValidSizeUnit(sizeUnit)) {
400
+ this.config.sizeUnit = sizeUnit;
401
+ }
402
+ else {
403
+ this.invalidSizeUnitParam();
404
+ return;
405
+ }
406
+ }
407
+ if (options.isTrue('no-check-updates')) {
408
+ this.config.checkUpdates = false;
409
+ }
410
+ if (!options.isTrue('target-folders')) {
411
+ if (!options.isTrue('profiles')) {
412
+ // Use defaultProfiles from config if available, otherwise use DEFAULT_PROFILE
413
+ const profilesToUse = this.config.profiles.length > 0
414
+ ? this.config.profiles
415
+ : [DEFAULT_PROFILE];
416
+ this.logger.info(`Using default profile targets (${profilesToUse.join(', ')})`);
417
+ this.config.targets =
418
+ this.profilesService.getTargetsFromProfiles(profilesToUse);
419
+ }
420
+ else {
421
+ const selectedProfiles = options.getStrings('profiles');
422
+ const badProfiles = this.profilesService.getInvalidProfileNames(selectedProfiles);
423
+ if (badProfiles.length > 0) {
424
+ this.logger.warn(`The following profiles are invalid: ${badProfiles.join(', ')}`);
425
+ const profileText = badProfiles.length > 1 ? 'profiles' : 'profile';
426
+ console.log(pc.bold(pc.bgRed(pc.white(` Invalid ${profileText} `))));
427
+ console.log(`The following ${profileText} are invalid: ${pc.red(badProfiles.join(', '))}.`);
428
+ console.log(`You can list the available profiles with ${pc.bold(pc.green('--profiles'))} command ${pc.gray('(without arguments)')}.`);
429
+ this.exitWithError();
430
+ }
431
+ const targets = this.profilesService.getTargetsFromProfiles(selectedProfiles);
432
+ this.logger.info(`Using profiles ${selectedProfiles.join(', ')} | With targets ${targets.join(', ')}`);
433
+ this.config.profiles = selectedProfiles;
434
+ this.config.targets = targets;
435
+ this.profilesExplicitlySet = true;
436
+ }
437
+ }
438
+ if (options.isTrue('target-folders')) {
439
+ this.config.targets = options.getString('target-folders').split(',');
440
+ this.config.profiles = [];
441
+ this.profilesExplicitlySet = true;
442
+ }
443
+ if (options.isTrue('exclude-sensitive')) {
444
+ this.config.excludeSensitiveResults = true;
445
+ }
446
+ if (options.isTrue('dry-run')) {
447
+ this.config.dryRun = true;
448
+ }
449
+ if (options.isTrue('yes')) {
450
+ this.config.yes = true;
451
+ }
452
+ if (options.isTrue('jsonStream')) {
453
+ this.config.jsonStream = true;
454
+ }
455
+ if (options.isTrue('jsonSimple')) {
456
+ this.config.jsonSimple = true;
457
+ }
458
+ if (this.config.jsonStream && this.config.jsonSimple) {
459
+ this.logger.error(ERROR_MSG.CANT_USE_BOTH_JSON_OPTIONS);
460
+ this.exitWithError();
461
+ }
462
+ // Remove trailing slash from folderRoot for consistency
463
+ this.config.folderRoot = this.config.folderRoot.replace(/[/\\]$/, '');
464
+ }
465
+ showErrorPopup(visible) {
466
+ this.uiLogs.setVisible(visible);
467
+ // Need convert to pattern and have a stack for recover latest
468
+ // component.
469
+ this.uiResults.freezed = visible;
470
+ this.uiStats.freezed = visible;
471
+ this.uiStatus.freezed = visible;
472
+ if (visible) {
473
+ this.activeComponent = this.uiLogs;
474
+ this.uiLogs.render();
475
+ }
476
+ else {
477
+ this.activeComponent = this.uiResults;
478
+ this.uiService.renderAll();
479
+ }
480
+ }
481
+ invalidSortParam() {
482
+ this.uiService.print(INFO_MSGS.NO_VALID_SORT_NAME);
483
+ this.logger.error(INFO_MSGS.NO_VALID_SORT_NAME);
484
+ this.exitWithError();
485
+ }
486
+ showHelp() {
487
+ new HelpCommandUi(this.consoleService).show();
488
+ }
489
+ showProgramVersion() {
490
+ this.uiService.print(`v${this.getVersion()}`);
491
+ }
492
+ isValidColor(color) {
493
+ return Object.keys(COLORS).some((validColor) => validColor === color);
494
+ }
495
+ isValidSortParam(sortName) {
496
+ return Object.keys(FOLDER_SORT).includes(sortName);
497
+ }
498
+ isValidSizeUnit(sizeUnit) {
499
+ return ['auto', 'mb', 'gb'].includes(sizeUnit);
500
+ }
501
+ invalidSizeUnitParam() {
502
+ this.uiService.print(INFO_MSGS.NO_VALID_SIZE_UNIT);
503
+ this.logger.error(INFO_MSGS.NO_VALID_SIZE_UNIT);
504
+ this.exitWithError();
505
+ }
506
+ getVersion() {
507
+ const packageJson = `${_dirname}/../package.json`;
508
+ const packageData = JSON.parse(getFileContent(packageJson));
509
+ return packageData.version;
510
+ }
511
+ prepareScreen() {
512
+ this.uiService.setRawMode();
513
+ // this.uiService.prepareUi();
514
+ this.uiService.setCursorVisible(false);
515
+ this.uiService.clear();
516
+ this.uiService.renderAll();
517
+ }
518
+ checkRequirements() {
519
+ this.checkScreenRequirements();
520
+ this.checkFileRequirements();
521
+ }
522
+ checkScreenRequirements() {
523
+ if (this.isTerminalTooSmall()) {
524
+ this.uiService.print(INFO_MSGS.MIN_CLI_CLOMUNS);
525
+ this.logger.error(INFO_MSGS.MIN_CLI_CLOMUNS);
526
+ this.exitWithError();
527
+ }
528
+ }
529
+ checkFileRequirements() {
530
+ const result = this.npkill.isValidRootFolder(this.config.folderRoot);
531
+ if (!result.isValid) {
532
+ const errorMessage = result.invalidReason || 'Root folder is not valid. Unknown reason';
533
+ this.uiService.print(errorMessage);
534
+ this.logger.error(errorMessage);
535
+ this.exitWithError();
536
+ }
537
+ }
538
+ checkVersion() {
539
+ this.logger.info('Checking updates...');
540
+ this.updateService
541
+ .isUpdated(this.getVersion())
542
+ .then((isUpdated) => {
543
+ if (!isUpdated) {
544
+ this.showUpdateMessage();
545
+ this.logger.info('New version found!');
546
+ }
547
+ else {
548
+ this.logger.info('Npkill is update');
549
+ }
550
+ return isUpdated;
551
+ })
552
+ .catch((err) => {
553
+ const errorMessage = `${ERROR_MSG.CANT_GET_REMOTE_VERSION}: ${err.message}`;
554
+ this.newError(errorMessage);
555
+ });
556
+ }
557
+ showUpdateMessage() {
558
+ const message = pc.magenta(INFO_MSGS.NEW_UPDATE_FOUND);
559
+ this.uiService.printAt(message, UI_POSITIONS.NEW_UPDATE_FOUND);
560
+ }
561
+ isTerminalTooSmall() {
562
+ return this.stdout.columns <= MIN_CLI_COLUMNS_SIZE;
563
+ }
564
+ printFoldersSection() {
565
+ this.uiResults.render();
566
+ }
567
+ setupEventsListener() {
568
+ this.uiService.stdin.on('keypress', (_, key) => {
569
+ if (key.name !== '') {
570
+ this.keyPress(key);
571
+ }
572
+ else {
573
+ throw new Error(`Invalid key: ${JSON.stringify(key)}`);
574
+ }
575
+ });
576
+ this.stdout.on('resize', () => {
577
+ this.uiService.clear();
578
+ this.uiService.renderAll();
579
+ });
580
+ process.on('uncaughtException', (error) => {
581
+ this.newError(error.message);
582
+ });
583
+ process.on('unhandledRejection', (error) => {
584
+ this.newError(error.stack ?? error.message);
585
+ });
586
+ }
587
+ keyPress(key) {
588
+ const { name, ctrl } = key;
589
+ if (this.isQuitKey(ctrl, name)) {
590
+ this.quit();
591
+ }
592
+ if (this.activeComponent === null) {
593
+ this.logger.error('activeComponent is NULL in Controller.');
594
+ return;
595
+ }
596
+ this.activeComponent.onKeyInput(key);
597
+ }
598
+ scan() {
599
+ this.initializeScan();
600
+ const shouldOutputInJson = this.config.jsonSimple || this.config.jsonStream;
601
+ if (shouldOutputInJson) {
602
+ this.scanInJson();
603
+ }
604
+ else {
605
+ this.scanInUiMode();
606
+ }
607
+ }
608
+ initializeScan() {
609
+ this.searchStatus.reset();
610
+ this.resultsService.reset();
611
+ this.resultsService.setSizeUnit(this.config.sizeUnit);
612
+ }
613
+ scanInJson() {
614
+ const isStreamMode = this.config.jsonStream;
615
+ this.jsonOutputService.initializeSession(isStreamMode);
616
+ this.scanService
617
+ .scan(this.config)
618
+ .pipe(mergeMap((nodeFolder) => this.scanService.calculateFolderStats(nodeFolder, {
619
+ getModificationTimeForSensitiveResults: true,
620
+ }), 10), tap((folder) => this.jsonOutputService.processResult(folder)))
621
+ .subscribe({
622
+ error: (error) => this.jsonOutputService.writeError(error),
623
+ complete: () => {
624
+ this.jsonOutputService.completeScan();
625
+ this.exitGracefully();
626
+ },
627
+ });
628
+ }
629
+ scanSubscription = null;
630
+ scanInUiMode() {
631
+ if (this.scanSubscription) {
632
+ this.scanSubscription.unsubscribe();
633
+ }
634
+ this.uiStatus.reset();
635
+ this.uiStatus.start();
636
+ this.searchStart = Date.now();
637
+ this.scanSubscription = this.scanService
638
+ .scan(this.config)
639
+ .pipe(tap((nodeFolder) => this.processNodeFolderForUi(nodeFolder)), mergeMap((nodeFolder) => this.scanService.calculateFolderStats(nodeFolder), 10), tap((folder) => this.processFolderStatsForUi(folder)))
640
+ .subscribe({
641
+ next: () => this.printFoldersSection(),
642
+ error: (error) => this.newError(error),
643
+ complete: () => this.completeSearch(),
644
+ });
645
+ }
646
+ setupJsonModeSignalHandlers() {
647
+ const gracefulShutdown = () => {
648
+ this.jsonOutputService.handleShutdown();
649
+ this.exitGracefully();
650
+ };
651
+ process.on('SIGINT', gracefulShutdown);
652
+ process.on('SIGTERM', gracefulShutdown);
653
+ }
654
+ processNodeFolderForUi(nodeFolder) {
655
+ this.searchStatus.newResult();
656
+ this.resultsService.addResult(nodeFolder);
657
+ if (this.config.sortBy === 'path') {
658
+ this.resultsService.sortResults(this.config.sortBy);
659
+ this.uiResults.clear();
660
+ }
661
+ this.uiResults.render();
662
+ }
663
+ processFolderStatsForUi(folder) {
664
+ this.searchStatus.completeStatCalculation();
665
+ this.finishFolderStats();
666
+ if (this.config.deleteAll) {
667
+ this.deleteFolder(folder);
668
+ }
669
+ }
670
+ finishFolderStats() {
671
+ const needSort = this.config.sortBy === 'size' || this.config.sortBy === 'age';
672
+ if (needSort) {
673
+ this.resultsService.sortResults(this.config.sortBy);
674
+ this.uiResults.clear();
675
+ }
676
+ this.uiStats.render();
677
+ this.printFoldersSection();
678
+ }
679
+ completeSearch() {
680
+ this.setSearchDuration();
681
+ this.uiResults.completeSearch();
682
+ this.uiStatus.completeSearch(this.searchDuration);
683
+ }
684
+ setSearchDuration() {
685
+ this.searchDuration = +((Date.now() - this.searchStart) / 1000).toFixed(2);
686
+ }
687
+ isQuitKey(ctrl, name) {
688
+ return ctrl && name === 'c';
689
+ }
690
+ exitWithError() {
691
+ this.resetConsoleState();
692
+ const logPath = this.logger.getSuggestLogFilePath();
693
+ this.logger.saveToFile(logPath);
694
+ // eslint-disable-next-line n/no-process-exit
695
+ process.exit(1);
696
+ }
697
+ exitGracefully() {
698
+ this.resetConsoleState();
699
+ const logPath = this.logger.getSuggestLogFilePath();
700
+ this.logger.saveToFile(logPath);
701
+ // eslint-disable-next-line n/no-process-exit
702
+ process.exit(0);
703
+ }
704
+ quit() {
705
+ this.uiService.setRawMode(false);
706
+ this.uiService.clear();
707
+ this.uiService.setCursorVisible(true);
708
+ this.printExitMessage();
709
+ this.logger.info('Thank for using devkill. Bye!');
710
+ const logPath = this.logger.getSuggestLogFilePath();
711
+ this.logger.saveToFile(logPath);
712
+ // eslint-disable-next-line n/no-process-exit
713
+ process.exit(0);
714
+ }
715
+ resetConsoleState() {
716
+ this.uiService.print('\n');
717
+ this.uiService.setRawMode(false);
718
+ this.uiService.setCursorVisible(true);
719
+ }
720
+ printExitMessage() {
721
+ const { spaceReleased } = this.resultsService.getStats();
722
+ new GeneralUi().printExitMessage({ spaceReleased });
723
+ }
724
+ deleteFolder(folder) {
725
+ if (folder.status === 'deleted' || folder.status === 'deleting') {
726
+ return;
727
+ }
728
+ if (!isSafeToDelete(folder.path, this.config.targets)) {
729
+ this.newError(`Folder not safe to delete: ${String(folder.path)}`);
730
+ return;
731
+ }
732
+ folder.status = 'deleting';
733
+ this.searchStatus.pendingDeletions++;
734
+ this.uiStatus.render();
735
+ this.printFoldersSection();
736
+ firstValueFrom(this.npkill.delete$(String(folder.path), { dryRun: this.config.dryRun }))
737
+ .then(() => {
738
+ folder.status = 'deleted';
739
+ this.resultsService.invalidateStats();
740
+ this.searchStatus.pendingDeletions--;
741
+ this.uiStats.render();
742
+ this.uiStatus.render();
743
+ this.printFoldersSection();
744
+ return folder;
745
+ })
746
+ .catch((e) => {
747
+ folder.status = 'error-deleting';
748
+ this.resultsService.invalidateStats();
749
+ this.searchStatus.pendingDeletions--;
750
+ this.uiStatus.render();
751
+ this.printFoldersSection();
752
+ this.newError(e.message);
753
+ });
754
+ }
755
+ newError(error) {
756
+ this.logger.error(error);
757
+ this.uiStats.render();
758
+ }
759
+ }
760
+ //# sourceMappingURL=cli.controller.js.map