@git.zone/cli 1.16.9 → 1.17.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.
@@ -0,0 +1,246 @@
1
+ import * as plugins from './mod.plugins.js';
2
+ import * as helpers from './helpers.js';
3
+ import { logger } from '../gitzone.logging.js';
4
+
5
+ export interface IServiceConfig {
6
+ PROJECT_NAME: string;
7
+ MONGODB_HOST: string;
8
+ MONGODB_NAME: string;
9
+ MONGODB_PORT: string;
10
+ MONGODB_USER: string;
11
+ MONGODB_PASS: string;
12
+ S3_HOST: string;
13
+ S3_PORT: string;
14
+ S3_CONSOLE_PORT: string;
15
+ S3_USER: string;
16
+ S3_PASS: string;
17
+ S3_BUCKET: string;
18
+ }
19
+
20
+ export class ServiceConfiguration {
21
+ private configPath: string;
22
+ private config: IServiceConfig;
23
+
24
+ constructor() {
25
+ this.configPath = plugins.path.join(process.cwd(), '.nogit', 'env.json');
26
+ }
27
+
28
+ /**
29
+ * Load or create the configuration
30
+ */
31
+ public async loadOrCreate(): Promise<IServiceConfig> {
32
+ await this.ensureNogitDirectory();
33
+
34
+ if (await this.configExists()) {
35
+ await this.loadConfig();
36
+ await this.updateMissingFields();
37
+ } else {
38
+ await this.createDefaultConfig();
39
+ }
40
+
41
+ return this.config;
42
+ }
43
+
44
+ /**
45
+ * Get the current configuration
46
+ */
47
+ public getConfig(): IServiceConfig {
48
+ return this.config;
49
+ }
50
+
51
+ /**
52
+ * Save the configuration to file
53
+ */
54
+ public async saveConfig(): Promise<void> {
55
+ await plugins.smartfile.memory.toFs(
56
+ JSON.stringify(this.config, null, 2),
57
+ this.configPath
58
+ );
59
+ }
60
+
61
+ /**
62
+ * Ensure .nogit directory exists
63
+ */
64
+ private async ensureNogitDirectory(): Promise<void> {
65
+ const nogitPath = plugins.path.join(process.cwd(), '.nogit');
66
+ await plugins.smartfile.fs.ensureDir(nogitPath);
67
+ }
68
+
69
+ /**
70
+ * Check if configuration file exists
71
+ */
72
+ private async configExists(): Promise<boolean> {
73
+ return plugins.smartfile.fs.fileExists(this.configPath);
74
+ }
75
+
76
+ /**
77
+ * Load configuration from file
78
+ */
79
+ private async loadConfig(): Promise<void> {
80
+ const configContent = await plugins.smartfile.fs.toStringSync(this.configPath);
81
+ this.config = JSON.parse(configContent);
82
+ }
83
+
84
+ /**
85
+ * Create default configuration
86
+ */
87
+ private async createDefaultConfig(): Promise<void> {
88
+ const projectName = helpers.getProjectName();
89
+ const mongoPort = await helpers.getRandomAvailablePort();
90
+ const s3Port = await helpers.getRandomAvailablePort();
91
+ let s3ConsolePort = s3Port + 1;
92
+
93
+ // Ensure console port is also available
94
+ while (!(await helpers.isPortAvailable(s3ConsolePort))) {
95
+ s3ConsolePort++;
96
+ }
97
+
98
+ this.config = {
99
+ PROJECT_NAME: projectName,
100
+ MONGODB_HOST: 'localhost',
101
+ MONGODB_NAME: projectName,
102
+ MONGODB_PORT: mongoPort.toString(),
103
+ MONGODB_USER: 'defaultadmin',
104
+ MONGODB_PASS: 'defaultpass',
105
+ S3_HOST: 'localhost',
106
+ S3_PORT: s3Port.toString(),
107
+ S3_CONSOLE_PORT: s3ConsolePort.toString(),
108
+ S3_USER: 'defaultadmin',
109
+ S3_PASS: 'defaultpass',
110
+ S3_BUCKET: `${projectName}-documents`
111
+ };
112
+
113
+ await this.saveConfig();
114
+
115
+ logger.log('ok', '✅ Created .nogit/env.json with project defaults');
116
+ logger.log('info', `📍 MongoDB port: ${mongoPort}`);
117
+ logger.log('info', `📍 S3 API port: ${s3Port}`);
118
+ logger.log('info', `📍 S3 Console port: ${s3ConsolePort}`);
119
+ }
120
+
121
+ /**
122
+ * Update missing fields in existing configuration
123
+ */
124
+ private async updateMissingFields(): Promise<void> {
125
+ const projectName = helpers.getProjectName();
126
+ let updated = false;
127
+ const fieldsAdded: string[] = [];
128
+
129
+ // Check and add missing fields
130
+ if (!this.config.PROJECT_NAME) {
131
+ this.config.PROJECT_NAME = projectName;
132
+ fieldsAdded.push('PROJECT_NAME');
133
+ updated = true;
134
+ }
135
+
136
+ if (!this.config.MONGODB_HOST) {
137
+ this.config.MONGODB_HOST = 'localhost';
138
+ fieldsAdded.push('MONGODB_HOST');
139
+ updated = true;
140
+ }
141
+
142
+ if (!this.config.MONGODB_NAME) {
143
+ this.config.MONGODB_NAME = projectName;
144
+ fieldsAdded.push('MONGODB_NAME');
145
+ updated = true;
146
+ }
147
+
148
+ if (!this.config.MONGODB_PORT) {
149
+ const port = await helpers.getRandomAvailablePort();
150
+ this.config.MONGODB_PORT = port.toString();
151
+ fieldsAdded.push(`MONGODB_PORT(${port})`);
152
+ updated = true;
153
+ }
154
+
155
+ if (!this.config.MONGODB_USER) {
156
+ this.config.MONGODB_USER = 'defaultadmin';
157
+ fieldsAdded.push('MONGODB_USER');
158
+ updated = true;
159
+ }
160
+
161
+ if (!this.config.MONGODB_PASS) {
162
+ this.config.MONGODB_PASS = 'defaultpass';
163
+ fieldsAdded.push('MONGODB_PASS');
164
+ updated = true;
165
+ }
166
+
167
+ if (!this.config.S3_HOST) {
168
+ this.config.S3_HOST = 'localhost';
169
+ fieldsAdded.push('S3_HOST');
170
+ updated = true;
171
+ }
172
+
173
+ if (!this.config.S3_PORT) {
174
+ const port = await helpers.getRandomAvailablePort();
175
+ this.config.S3_PORT = port.toString();
176
+ fieldsAdded.push(`S3_PORT(${port})`);
177
+ updated = true;
178
+ }
179
+
180
+ if (!this.config.S3_CONSOLE_PORT) {
181
+ const s3Port = parseInt(this.config.S3_PORT);
182
+ let consolePort = s3Port + 1;
183
+
184
+ while (!(await helpers.isPortAvailable(consolePort))) {
185
+ consolePort++;
186
+ }
187
+
188
+ this.config.S3_CONSOLE_PORT = consolePort.toString();
189
+ fieldsAdded.push(`S3_CONSOLE_PORT(${consolePort})`);
190
+ updated = true;
191
+ }
192
+
193
+ if (!this.config.S3_USER) {
194
+ this.config.S3_USER = 'defaultadmin';
195
+ fieldsAdded.push('S3_USER');
196
+ updated = true;
197
+ }
198
+
199
+ if (!this.config.S3_PASS) {
200
+ this.config.S3_PASS = 'defaultpass';
201
+ fieldsAdded.push('S3_PASS');
202
+ updated = true;
203
+ }
204
+
205
+ if (!this.config.S3_BUCKET) {
206
+ this.config.S3_BUCKET = `${projectName}-documents`;
207
+ fieldsAdded.push('S3_BUCKET');
208
+ updated = true;
209
+ }
210
+
211
+ if (updated) {
212
+ await this.saveConfig();
213
+ logger.log('ok', `✅ Added missing fields: ${fieldsAdded.join(', ')}`);
214
+ } else {
215
+ logger.log('ok', '✅ Configuration complete');
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Get MongoDB connection string
221
+ */
222
+ public getMongoConnectionString(useNetworkIp: boolean = false): string {
223
+ const host = useNetworkIp ? '${networkIp}' : this.config.MONGODB_HOST;
224
+ return `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${host}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
225
+ }
226
+
227
+ /**
228
+ * Get container names
229
+ */
230
+ public getContainerNames() {
231
+ return {
232
+ mongo: `${this.config.PROJECT_NAME}-mongodb`,
233
+ minio: `${this.config.PROJECT_NAME}-minio`
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Get data directories
239
+ */
240
+ public getDataDirectories() {
241
+ return {
242
+ mongo: plugins.path.join(process.cwd(), '.nogit', 'mongodata'),
243
+ minio: plugins.path.join(process.cwd(), '.nogit', 'miniodata')
244
+ };
245
+ }
246
+ }
@@ -0,0 +1,424 @@
1
+ import * as plugins from './mod.plugins.js';
2
+ import * as helpers from './helpers.js';
3
+ import { ServiceConfiguration } from './classes.serviceconfiguration.js';
4
+ import { DockerContainer } from './classes.dockercontainer.js';
5
+ import { logger } from '../gitzone.logging.js';
6
+
7
+ export class ServiceManager {
8
+ private config: ServiceConfiguration;
9
+ private docker: DockerContainer;
10
+
11
+ constructor() {
12
+ this.config = new ServiceConfiguration();
13
+ this.docker = new DockerContainer();
14
+ }
15
+
16
+ /**
17
+ * Initialize the service manager
18
+ */
19
+ public async init(): Promise<void> {
20
+ // Check Docker availability
21
+ if (!(await this.docker.checkDocker())) {
22
+ logger.log('error', 'Error: Docker is not installed. Please install Docker first.');
23
+ process.exit(1);
24
+ }
25
+
26
+ // Load or create configuration
27
+ await this.config.loadOrCreate();
28
+ logger.log('info', `📋 Project: ${this.config.getConfig().PROJECT_NAME}`);
29
+ }
30
+
31
+ /**
32
+ * Start MongoDB service
33
+ */
34
+ public async startMongoDB(): Promise<void> {
35
+ logger.log('note', '📦 MongoDB:');
36
+
37
+ const config = this.config.getConfig();
38
+ const containers = this.config.getContainerNames();
39
+ const directories = this.config.getDataDirectories();
40
+
41
+ // Ensure data directory exists
42
+ await plugins.smartfile.fs.ensureDir(directories.mongo);
43
+
44
+ const status = await this.docker.getStatus(containers.mongo);
45
+
46
+ switch (status) {
47
+ case 'running':
48
+ logger.log('ok', ' Already running ✓');
49
+ break;
50
+
51
+ case 'stopped':
52
+ if (await this.docker.start(containers.mongo)) {
53
+ logger.log('ok', ' Started ✓');
54
+ } else {
55
+ logger.log('error', ' Failed to start');
56
+ }
57
+ break;
58
+
59
+ case 'not_exists':
60
+ logger.log('note', ' Creating container...');
61
+
62
+ const success = await this.docker.run({
63
+ name: containers.mongo,
64
+ image: 'mongo:7.0',
65
+ ports: {
66
+ [`0.0.0.0:${config.MONGODB_PORT}`]: '27017'
67
+ },
68
+ volumes: {
69
+ [directories.mongo]: '/data/db'
70
+ },
71
+ environment: {
72
+ MONGO_INITDB_ROOT_USERNAME: config.MONGODB_USER,
73
+ MONGO_INITDB_ROOT_PASSWORD: config.MONGODB_PASS,
74
+ MONGO_INITDB_DATABASE: config.MONGODB_NAME
75
+ },
76
+ restart: 'unless-stopped',
77
+ command: '--bind_ip_all'
78
+ });
79
+
80
+ if (success) {
81
+ logger.log('ok', ' Created and started ✓');
82
+ } else {
83
+ logger.log('error', ' Failed to create container');
84
+ }
85
+ break;
86
+ }
87
+
88
+ logger.log('info', ` Container: ${containers.mongo}`);
89
+ logger.log('info', ` Port: ${config.MONGODB_PORT}`);
90
+ logger.log('info', ` Connection: ${this.config.getMongoConnectionString()}`);
91
+
92
+ // Show Compass connection string
93
+ const networkIp = await helpers.getLocalNetworkIp();
94
+ const compassString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`;
95
+ logger.log('ok', ` Compass: ${compassString}`);
96
+ }
97
+
98
+ /**
99
+ * Start MinIO service
100
+ */
101
+ public async startMinIO(): Promise<void> {
102
+ logger.log('note', '📦 S3/MinIO:');
103
+
104
+ const config = this.config.getConfig();
105
+ const containers = this.config.getContainerNames();
106
+ const directories = this.config.getDataDirectories();
107
+
108
+ // Ensure data directory exists
109
+ await plugins.smartfile.fs.ensureDir(directories.minio);
110
+
111
+ const status = await this.docker.getStatus(containers.minio);
112
+
113
+ switch (status) {
114
+ case 'running':
115
+ logger.log('ok', ' Already running ✓');
116
+ break;
117
+
118
+ case 'stopped':
119
+ if (await this.docker.start(containers.minio)) {
120
+ logger.log('ok', ' Started ✓');
121
+ } else {
122
+ logger.log('error', ' Failed to start');
123
+ }
124
+ break;
125
+
126
+ case 'not_exists':
127
+ logger.log('note', ' Creating container...');
128
+
129
+ const success = await this.docker.run({
130
+ name: containers.minio,
131
+ image: 'minio/minio',
132
+ ports: {
133
+ [config.S3_PORT]: '9000',
134
+ [config.S3_CONSOLE_PORT]: '9001'
135
+ },
136
+ volumes: {
137
+ [directories.minio]: '/data'
138
+ },
139
+ environment: {
140
+ MINIO_ROOT_USER: config.S3_USER,
141
+ MINIO_ROOT_PASSWORD: config.S3_PASS
142
+ },
143
+ restart: 'unless-stopped',
144
+ command: 'server /data --console-address ":9001"'
145
+ });
146
+
147
+ if (success) {
148
+ logger.log('ok', ' Created and started ✓');
149
+
150
+ // Wait for MinIO to be ready
151
+ await plugins.smartdelay.delayFor(3000);
152
+
153
+ // Create default bucket
154
+ await this.docker.exec(
155
+ containers.minio,
156
+ `mc alias set local http://localhost:9000 ${config.S3_USER} ${config.S3_PASS}`
157
+ );
158
+
159
+ await this.docker.exec(
160
+ containers.minio,
161
+ `mc mb local/${config.S3_BUCKET}`
162
+ );
163
+
164
+ logger.log('ok', ` Bucket '${config.S3_BUCKET}' created ✓`);
165
+ } else {
166
+ logger.log('error', ' Failed to create container');
167
+ }
168
+ break;
169
+ }
170
+
171
+ logger.log('info', ` Container: ${containers.minio}`);
172
+ logger.log('info', ` Port: ${config.S3_PORT}`);
173
+ logger.log('info', ` Bucket: ${config.S3_BUCKET}`);
174
+ logger.log('info', ` API: http://${config.S3_HOST}:${config.S3_PORT}`);
175
+ logger.log('info', ` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_USER}/***)`);
176
+ }
177
+
178
+ /**
179
+ * Stop MongoDB service
180
+ */
181
+ public async stopMongoDB(): Promise<void> {
182
+ logger.log('note', '📦 MongoDB:');
183
+
184
+ const containers = this.config.getContainerNames();
185
+ const status = await this.docker.getStatus(containers.mongo);
186
+
187
+ if (status === 'running') {
188
+ if (await this.docker.stop(containers.mongo)) {
189
+ logger.log('ok', ' Stopped ✓');
190
+ } else {
191
+ logger.log('error', ' Failed to stop');
192
+ }
193
+ } else {
194
+ logger.log('note', ' Not running');
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Stop MinIO service
200
+ */
201
+ public async stopMinIO(): Promise<void> {
202
+ logger.log('note', '📦 S3/MinIO:');
203
+
204
+ const containers = this.config.getContainerNames();
205
+ const status = await this.docker.getStatus(containers.minio);
206
+
207
+ if (status === 'running') {
208
+ if (await this.docker.stop(containers.minio)) {
209
+ logger.log('ok', ' Stopped ✓');
210
+ } else {
211
+ logger.log('error', ' Failed to stop');
212
+ }
213
+ } else {
214
+ logger.log('note', ' Not running');
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Show service status
220
+ */
221
+ public async showStatus(): Promise<void> {
222
+ helpers.printHeader('Service Status');
223
+
224
+ const config = this.config.getConfig();
225
+ const containers = this.config.getContainerNames();
226
+
227
+ logger.log('info', `Project: ${config.PROJECT_NAME}`);
228
+ console.log();
229
+
230
+ // MongoDB status
231
+ const mongoStatus = await this.docker.getStatus(containers.mongo);
232
+ switch (mongoStatus) {
233
+ case 'running':
234
+ logger.log('ok', '📦 MongoDB: 🟢 Running');
235
+ logger.log('info', ` ├─ Container: ${containers.mongo}`);
236
+ logger.log('info', ` ├─ Connection: ${this.config.getMongoConnectionString()}`);
237
+
238
+ // Show Compass connection string
239
+ const networkIp = await helpers.getLocalNetworkIp();
240
+ const compassString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`;
241
+ logger.log('ok', ` └─ Compass: ${compassString}`);
242
+ break;
243
+ case 'stopped':
244
+ logger.log('note', '📦 MongoDB: 🟡 Stopped');
245
+ logger.log('info', ` └─ Container: ${containers.mongo}`);
246
+ break;
247
+ case 'not_exists':
248
+ logger.log('info', '📦 MongoDB: ⚪ Not installed');
249
+ break;
250
+ }
251
+
252
+ // MinIO status
253
+ const minioStatus = await this.docker.getStatus(containers.minio);
254
+ switch (minioStatus) {
255
+ case 'running':
256
+ logger.log('ok', '📦 S3/MinIO: 🟢 Running');
257
+ logger.log('info', ` ├─ Container: ${containers.minio}`);
258
+ logger.log('info', ` ├─ API: http://${config.S3_HOST}:${config.S3_PORT}`);
259
+ logger.log('info', ` ├─ Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`);
260
+ logger.log('info', ` └─ Bucket: ${config.S3_BUCKET}`);
261
+ break;
262
+ case 'stopped':
263
+ logger.log('note', '📦 S3/MinIO: 🟡 Stopped');
264
+ logger.log('info', ` └─ Container: ${containers.minio}`);
265
+ break;
266
+ case 'not_exists':
267
+ logger.log('info', '📦 S3/MinIO: ⚪ Not installed');
268
+ break;
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Show configuration
274
+ */
275
+ public async showConfig(): Promise<void> {
276
+ helpers.printHeader('Current Configuration');
277
+
278
+ const config = this.config.getConfig();
279
+
280
+ logger.log('info', `Project: ${config.PROJECT_NAME}`);
281
+ console.log();
282
+
283
+ logger.log('note', 'MongoDB:');
284
+ logger.log('info', ` Host: ${config.MONGODB_HOST}:${config.MONGODB_PORT}`);
285
+ logger.log('info', ` Database: ${config.MONGODB_NAME}`);
286
+ logger.log('info', ` User: ${config.MONGODB_USER}`);
287
+ logger.log('info', ' Password: ***');
288
+ logger.log('info', ` Container: ${this.config.getContainerNames().mongo}`);
289
+ logger.log('info', ` Data: ${this.config.getDataDirectories().mongo}`);
290
+ logger.log('info', ` Connection: ${this.config.getMongoConnectionString()}`);
291
+
292
+ console.log();
293
+ logger.log('note', 'S3/MinIO:');
294
+ logger.log('info', ` Host: ${config.S3_HOST}`);
295
+ logger.log('info', ` API Port: ${config.S3_PORT}`);
296
+ logger.log('info', ` Console Port: ${config.S3_CONSOLE_PORT}`);
297
+ logger.log('info', ` User: ${config.S3_USER}`);
298
+ logger.log('info', ' Password: ***');
299
+ logger.log('info', ` Bucket: ${config.S3_BUCKET}`);
300
+ logger.log('info', ` Container: ${this.config.getContainerNames().minio}`);
301
+ logger.log('info', ` Data: ${this.config.getDataDirectories().minio}`);
302
+ logger.log('info', ` API URL: http://${config.S3_HOST}:${config.S3_PORT}`);
303
+ logger.log('info', ` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`);
304
+ }
305
+
306
+ /**
307
+ * Show MongoDB Compass connection string
308
+ */
309
+ public async showCompassConnection(): Promise<void> {
310
+ helpers.printHeader('MongoDB Compass Connection');
311
+
312
+ const config = this.config.getConfig();
313
+ const networkIp = await helpers.getLocalNetworkIp();
314
+
315
+ const connectionString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`;
316
+
317
+ logger.log('info', 'MongoDB Compass is a GUI tool for MongoDB. To connect:');
318
+ console.log();
319
+ logger.log('info', '1. Download MongoDB Compass from:');
320
+ logger.log('info', ' https://www.mongodb.com/products/compass');
321
+ console.log();
322
+ logger.log('info', '2. Open Compass and paste this connection string:');
323
+ logger.log('ok', ` ${connectionString}`);
324
+ console.log();
325
+ logger.log('note', 'Connection Details:');
326
+ logger.log('info', ` Network IP: ${networkIp}`);
327
+ logger.log('info', ` Port: ${config.MONGODB_PORT}`);
328
+ logger.log('info', ` Database: ${config.MONGODB_NAME}`);
329
+ logger.log('info', ` Username: ${config.MONGODB_USER}`);
330
+ logger.log('info', ` Auth Source: admin`);
331
+ }
332
+
333
+ /**
334
+ * Show logs for a service
335
+ */
336
+ public async showLogs(service: string, lines: number = 20): Promise<void> {
337
+ const containers = this.config.getContainerNames();
338
+
339
+ switch (service) {
340
+ case 'mongo':
341
+ case 'mongodb':
342
+ if (await this.docker.isRunning(containers.mongo)) {
343
+ helpers.printHeader(`MongoDB Logs (last ${lines} lines)`);
344
+ const logs = await this.docker.logs(containers.mongo, lines);
345
+ console.log(logs);
346
+ } else {
347
+ logger.log('note', 'MongoDB container is not running');
348
+ }
349
+ break;
350
+
351
+ case 'minio':
352
+ case 's3':
353
+ if (await this.docker.isRunning(containers.minio)) {
354
+ helpers.printHeader(`S3/MinIO Logs (last ${lines} lines)`);
355
+ const logs = await this.docker.logs(containers.minio, lines);
356
+ console.log(logs);
357
+ } else {
358
+ logger.log('note', 'S3/MinIO container is not running');
359
+ }
360
+ break;
361
+
362
+ case 'all':
363
+ case '':
364
+ await this.showLogs('mongo', lines);
365
+ console.log();
366
+ await this.showLogs('minio', lines);
367
+ break;
368
+
369
+ default:
370
+ logger.log('note', 'Usage: gitzone services logs [mongo|s3|all] [lines]');
371
+ break;
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Remove containers
377
+ */
378
+ public async removeContainers(): Promise<void> {
379
+ const containers = this.config.getContainerNames();
380
+ let removed = false;
381
+
382
+ if (await this.docker.exists(containers.mongo)) {
383
+ if (await this.docker.remove(containers.mongo, true)) {
384
+ logger.log('ok', ' MongoDB container removed ✓');
385
+ removed = true;
386
+ }
387
+ }
388
+
389
+ if (await this.docker.exists(containers.minio)) {
390
+ if (await this.docker.remove(containers.minio, true)) {
391
+ logger.log('ok', ' S3/MinIO container removed ✓');
392
+ removed = true;
393
+ }
394
+ }
395
+
396
+ if (!removed) {
397
+ logger.log('note', ' No containers to remove');
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Clean data directories
403
+ */
404
+ public async cleanData(): Promise<void> {
405
+ const directories = this.config.getDataDirectories();
406
+ let cleaned = false;
407
+
408
+ if (await plugins.smartfile.fs.fileExists(directories.mongo)) {
409
+ await plugins.smartfile.fs.remove(directories.mongo);
410
+ logger.log('ok', ' MongoDB data removed ✓');
411
+ cleaned = true;
412
+ }
413
+
414
+ if (await plugins.smartfile.fs.fileExists(directories.minio)) {
415
+ await plugins.smartfile.fs.remove(directories.minio);
416
+ logger.log('ok', ' S3/MinIO data removed ✓');
417
+ cleaned = true;
418
+ }
419
+
420
+ if (!cleaned) {
421
+ logger.log('note', ' No data to clean');
422
+ }
423
+ }
424
+ }