@git.zone/cli 1.21.5 → 2.0.0

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 (58) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/mod_commit/index.js +5 -2
  3. package/dist_ts/mod_commit/mod.helpers.js +24 -9
  4. package/dist_ts/mod_format/classes.baseformatter.js +4 -4
  5. package/dist_ts/mod_format/classes.changecache.js +29 -17
  6. package/dist_ts/mod_format/classes.diffreporter.js +10 -4
  7. package/dist_ts/mod_format/classes.formatstats.js +5 -2
  8. package/dist_ts/mod_format/classes.rollbackmanager.js +41 -17
  9. package/dist_ts/mod_format/format.cleanup.js +5 -3
  10. package/dist_ts/mod_format/format.copy.js +12 -4
  11. package/dist_ts/mod_format/format.gitignore.js +14 -5
  12. package/dist_ts/mod_format/format.license.js +4 -2
  13. package/dist_ts/mod_format/format.packagejson.js +6 -2
  14. package/dist_ts/mod_format/format.readme.js +9 -5
  15. package/dist_ts/mod_format/format.tsconfig.js +7 -4
  16. package/dist_ts/mod_format/formatters/cleanup.formatter.js +2 -2
  17. package/dist_ts/mod_format/formatters/prettier.formatter.js +19 -6
  18. package/dist_ts/mod_format/index.js +9 -3
  19. package/dist_ts/mod_meta/meta.classes.meta.js +82 -17
  20. package/dist_ts/mod_services/classes.serviceconfiguration.d.ts +7 -0
  21. package/dist_ts/mod_services/classes.serviceconfiguration.js +86 -10
  22. package/dist_ts/mod_services/classes.servicemanager.d.ts +33 -0
  23. package/dist_ts/mod_services/classes.servicemanager.js +319 -10
  24. package/dist_ts/mod_services/helpers.d.ts +1 -1
  25. package/dist_ts/mod_services/helpers.js +8 -4
  26. package/dist_ts/mod_services/index.js +51 -27
  27. package/dist_ts/mod_standard/index.js +22 -9
  28. package/dist_ts/mod_template/index.js +2 -2
  29. package/dist_ts/plugins.d.ts +2 -0
  30. package/dist_ts/plugins.js +4 -1
  31. package/package.json +7 -6
  32. package/readme.hints.md +55 -2
  33. package/ts/00_commitinfo_data.ts +1 -1
  34. package/ts/mod_commit/index.ts +4 -4
  35. package/ts/mod_commit/mod.helpers.ts +23 -11
  36. package/ts/mod_format/classes.baseformatter.ts +3 -3
  37. package/ts/mod_format/classes.changecache.ts +28 -16
  38. package/ts/mod_format/classes.diffreporter.ts +9 -8
  39. package/ts/mod_format/classes.formatstats.ts +4 -4
  40. package/ts/mod_format/classes.rollbackmanager.ts +40 -18
  41. package/ts/mod_format/format.cleanup.ts +4 -4
  42. package/ts/mod_format/format.copy.ts +11 -3
  43. package/ts/mod_format/format.gitignore.ts +13 -6
  44. package/ts/mod_format/format.license.ts +3 -3
  45. package/ts/mod_format/format.packagejson.ts +5 -3
  46. package/ts/mod_format/format.readme.ts +8 -11
  47. package/ts/mod_format/format.tsconfig.ts +6 -5
  48. package/ts/mod_format/formatters/cleanup.formatter.ts +1 -1
  49. package/ts/mod_format/formatters/prettier.formatter.ts +18 -8
  50. package/ts/mod_format/index.ts +10 -5
  51. package/ts/mod_meta/meta.classes.meta.ts +84 -41
  52. package/ts/mod_services/classes.serviceconfiguration.ts +121 -35
  53. package/ts/mod_services/classes.servicemanager.ts +365 -32
  54. package/ts/mod_services/helpers.ts +8 -4
  55. package/ts/mod_services/index.ts +73 -45
  56. package/ts/mod_standard/index.ts +23 -10
  57. package/ts/mod_template/index.ts +1 -1
  58. package/ts/plugins.ts +4 -0
@@ -7,12 +7,13 @@ import { logger } from '../gitzone.logging.js';
7
7
  export class ServiceManager {
8
8
  private config: ServiceConfiguration;
9
9
  private docker: DockerContainer;
10
-
10
+ private enabledServices: string[] | null = null;
11
+
11
12
  constructor() {
12
13
  this.config = new ServiceConfiguration();
13
14
  this.docker = new DockerContainer();
14
15
  }
15
-
16
+
16
17
  /**
17
18
  * Initialize the service manager
18
19
  */
@@ -22,15 +23,134 @@ export class ServiceManager {
22
23
  logger.log('error', 'Error: Docker is not installed. Please install Docker first.');
23
24
  process.exit(1);
24
25
  }
25
-
26
+
26
27
  // Load or create configuration
27
28
  await this.config.loadOrCreate();
28
29
  logger.log('info', `📋 Project: ${this.config.getConfig().PROJECT_NAME}`);
29
-
30
+
31
+ // Load service selection from npmextra.json
32
+ await this.loadServiceConfiguration();
33
+
30
34
  // Validate and update ports if needed
31
35
  await this.config.validateAndUpdatePorts();
32
36
  }
33
-
37
+
38
+ /**
39
+ * Load service configuration from npmextra.json
40
+ */
41
+ private async loadServiceConfiguration(): Promise<void> {
42
+ const npmextraConfig = new plugins.npmextra.Npmextra(process.cwd());
43
+ const gitzoneConfig = npmextraConfig.dataFor<any>('gitzone', {});
44
+
45
+ // Check if services array exists
46
+ if (!gitzoneConfig.services || !Array.isArray(gitzoneConfig.services) || gitzoneConfig.services.length === 0) {
47
+ // Prompt user to select services
48
+ const smartinteract = new plugins.smartinteract.SmartInteract();
49
+ const response = await smartinteract.askQuestion({
50
+ name: 'services',
51
+ type: 'checkbox',
52
+ message: 'Which services do you want to enable for this project?',
53
+ choices: [
54
+ { name: 'MongoDB', value: 'mongodb' },
55
+ { name: 'MinIO (S3)', value: 'minio' },
56
+ { name: 'Elasticsearch', value: 'elasticsearch' }
57
+ ],
58
+ default: ['mongodb', 'minio', 'elasticsearch']
59
+ });
60
+
61
+ this.enabledServices = response.value || ['mongodb', 'minio', 'elasticsearch'];
62
+
63
+ // Save to npmextra.json
64
+ await this.saveServiceConfiguration(this.enabledServices);
65
+ } else {
66
+ this.enabledServices = gitzoneConfig.services;
67
+ logger.log('info', `🔧 Enabled services: ${this.enabledServices.join(', ')}`);
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Save service configuration to npmextra.json
73
+ */
74
+ private async saveServiceConfiguration(services: string[]): Promise<void> {
75
+ const npmextraPath = plugins.path.join(process.cwd(), 'npmextra.json');
76
+ let npmextraData: any = {};
77
+
78
+ // Read existing npmextra.json if it exists
79
+ if (await plugins.smartfs.file(npmextraPath).exists()) {
80
+ const content = await plugins.smartfs.file(npmextraPath).encoding('utf8').read();
81
+ npmextraData = JSON.parse(content as string);
82
+ }
83
+
84
+ // Update gitzone.services
85
+ if (!npmextraData.gitzone) {
86
+ npmextraData.gitzone = {};
87
+ }
88
+ npmextraData.gitzone.services = services;
89
+
90
+ // Write back to npmextra.json
91
+ await plugins.smartfs
92
+ .file(npmextraPath)
93
+ .encoding('utf8')
94
+ .write(JSON.stringify(npmextraData, null, 2));
95
+
96
+ logger.log('ok', `✅ Saved service configuration to npmextra.json`);
97
+ logger.log('info', `🔧 Enabled services: ${services.join(', ')}`);
98
+ }
99
+
100
+ /**
101
+ * Check if a service is enabled
102
+ */
103
+ private isServiceEnabled(service: string): boolean {
104
+ if (!this.enabledServices) {
105
+ return true; // If no configuration, enable all
106
+ }
107
+ return this.enabledServices.includes(service);
108
+ }
109
+
110
+ /**
111
+ * Start all enabled services
112
+ */
113
+ public async startAll(): Promise<void> {
114
+ let first = true;
115
+ if (this.isServiceEnabled('mongodb')) {
116
+ if (!first) console.log();
117
+ await this.startMongoDB();
118
+ first = false;
119
+ }
120
+ if (this.isServiceEnabled('minio')) {
121
+ if (!first) console.log();
122
+ await this.startMinIO();
123
+ first = false;
124
+ }
125
+ if (this.isServiceEnabled('elasticsearch')) {
126
+ if (!first) console.log();
127
+ await this.startElasticsearch();
128
+ first = false;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Stop all enabled services
134
+ */
135
+ public async stopAll(): Promise<void> {
136
+ let first = true;
137
+ if (this.isServiceEnabled('mongodb')) {
138
+ if (!first) console.log();
139
+ await this.stopMongoDB();
140
+ first = false;
141
+ }
142
+ if (this.isServiceEnabled('minio')) {
143
+ if (!first) console.log();
144
+ await this.stopMinIO();
145
+ first = false;
146
+ }
147
+ if (this.isServiceEnabled('elasticsearch')) {
148
+ if (!first) console.log();
149
+ await this.stopElasticsearch();
150
+ first = false;
151
+ }
152
+ }
153
+
34
154
  /**
35
155
  * Start MongoDB service
36
156
  */
@@ -42,7 +162,7 @@ export class ServiceManager {
42
162
  const directories = this.config.getDataDirectories();
43
163
 
44
164
  // Ensure data directory exists
45
- await plugins.smartfile.fs.ensureDir(directories.mongo);
165
+ await plugins.smartfs.directory(directories.mongo).recursive().create();
46
166
 
47
167
  const status = await this.docker.getStatus(containers.mongo);
48
168
 
@@ -141,7 +261,7 @@ export class ServiceManager {
141
261
  const directories = this.config.getDataDirectories();
142
262
 
143
263
  // Ensure data directory exists
144
- await plugins.smartfile.fs.ensureDir(directories.minio);
264
+ await plugins.smartfs.directory(directories.minio).recursive().create();
145
265
 
146
266
  const status = await this.docker.getStatus(containers.minio);
147
267
 
@@ -259,7 +379,103 @@ export class ServiceManager {
259
379
  logger.log('info', ` API: http://${config.S3_HOST}:${config.S3_PORT}`);
260
380
  logger.log('info', ` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_ACCESSKEY}/***)`);
261
381
  }
262
-
382
+
383
+ /**
384
+ * Start Elasticsearch service
385
+ */
386
+ public async startElasticsearch(): Promise<void> {
387
+ logger.log('note', '📦 Elasticsearch:');
388
+
389
+ const config = this.config.getConfig();
390
+ const containers = this.config.getContainerNames();
391
+ const directories = this.config.getDataDirectories();
392
+
393
+ // Ensure data directory exists
394
+ await plugins.smartfs.directory(directories.elasticsearch).recursive().create();
395
+
396
+ const status = await this.docker.getStatus(containers.elasticsearch);
397
+
398
+ switch (status) {
399
+ case 'running':
400
+ logger.log('ok', ' Already running ✓');
401
+ break;
402
+
403
+ case 'stopped':
404
+ // Check if port mapping matches config
405
+ const esPortMappings = await this.docker.getPortMappings(containers.elasticsearch);
406
+ if (esPortMappings && esPortMappings['9200'] !== config.ELASTICSEARCH_PORT) {
407
+ logger.log('note', ' Port configuration changed, recreating container...');
408
+ await this.docker.remove(containers.elasticsearch, true);
409
+ // Fall through to create new container
410
+ const success = await this.docker.run({
411
+ name: containers.elasticsearch,
412
+ image: 'elasticsearch:8.11.0',
413
+ ports: {
414
+ [`0.0.0.0:${config.ELASTICSEARCH_PORT}`]: '9200'
415
+ },
416
+ volumes: {
417
+ [directories.elasticsearch]: '/usr/share/elasticsearch/data'
418
+ },
419
+ environment: {
420
+ 'discovery.type': 'single-node',
421
+ 'xpack.security.enabled': 'true',
422
+ 'ELASTIC_PASSWORD': config.ELASTICSEARCH_PASS,
423
+ 'ES_JAVA_OPTS': '-Xms512m -Xmx512m'
424
+ },
425
+ restart: 'unless-stopped'
426
+ });
427
+
428
+ if (success) {
429
+ logger.log('ok', ' Recreated with new port ✓');
430
+ } else {
431
+ logger.log('error', ' Failed to recreate container');
432
+ }
433
+ } else {
434
+ // Ports match, just start the container
435
+ if (await this.docker.start(containers.elasticsearch)) {
436
+ logger.log('ok', ' Started ✓');
437
+ } else {
438
+ logger.log('error', ' Failed to start');
439
+ }
440
+ }
441
+ break;
442
+
443
+ case 'not_exists':
444
+ logger.log('note', ' Creating container...');
445
+
446
+ const success = await this.docker.run({
447
+ name: containers.elasticsearch,
448
+ image: 'elasticsearch:8.11.0',
449
+ ports: {
450
+ [`0.0.0.0:${config.ELASTICSEARCH_PORT}`]: '9200'
451
+ },
452
+ volumes: {
453
+ [directories.elasticsearch]: '/usr/share/elasticsearch/data'
454
+ },
455
+ environment: {
456
+ 'discovery.type': 'single-node',
457
+ 'xpack.security.enabled': 'true',
458
+ 'ELASTIC_PASSWORD': config.ELASTICSEARCH_PASS,
459
+ 'ES_JAVA_OPTS': '-Xms512m -Xmx512m'
460
+ },
461
+ restart: 'unless-stopped'
462
+ });
463
+
464
+ if (success) {
465
+ logger.log('ok', ' Created and started ✓');
466
+ } else {
467
+ logger.log('error', ' Failed to create container');
468
+ }
469
+ break;
470
+ }
471
+
472
+ logger.log('info', ` Container: ${containers.elasticsearch}`);
473
+ logger.log('info', ` Port: ${config.ELASTICSEARCH_PORT}`);
474
+ logger.log('info', ` Connection: ${config.ELASTICSEARCH_URL}`);
475
+ logger.log('info', ` Username: ${config.ELASTICSEARCH_USER}`);
476
+ logger.log('info', ` Password: ${config.ELASTICSEARCH_PASS}`);
477
+ }
478
+
263
479
  /**
264
480
  * Stop MongoDB service
265
481
  */
@@ -285,10 +501,10 @@ export class ServiceManager {
285
501
  */
286
502
  public async stopMinIO(): Promise<void> {
287
503
  logger.log('note', '📦 S3/MinIO:');
288
-
504
+
289
505
  const containers = this.config.getContainerNames();
290
506
  const status = await this.docker.getStatus(containers.minio);
291
-
507
+
292
508
  if (status === 'running') {
293
509
  if (await this.docker.stop(containers.minio)) {
294
510
  logger.log('ok', ' Stopped ✓');
@@ -299,7 +515,27 @@ export class ServiceManager {
299
515
  logger.log('note', ' Not running');
300
516
  }
301
517
  }
302
-
518
+
519
+ /**
520
+ * Stop Elasticsearch service
521
+ */
522
+ public async stopElasticsearch(): Promise<void> {
523
+ logger.log('note', '📦 Elasticsearch:');
524
+
525
+ const containers = this.config.getContainerNames();
526
+ const status = await this.docker.getStatus(containers.elasticsearch);
527
+
528
+ if (status === 'running') {
529
+ if (await this.docker.stop(containers.elasticsearch)) {
530
+ logger.log('ok', ' Stopped ✓');
531
+ } else {
532
+ logger.log('error', ' Failed to stop');
533
+ }
534
+ } else {
535
+ logger.log('note', ' Not running');
536
+ }
537
+ }
538
+
303
539
  /**
304
540
  * Show service status
305
541
  */
@@ -385,8 +621,36 @@ export class ServiceManager {
385
621
  }
386
622
  break;
387
623
  }
624
+
625
+ // Elasticsearch status
626
+ const esStatus = await this.docker.getStatus(containers.elasticsearch);
627
+ switch (esStatus) {
628
+ case 'running':
629
+ logger.log('ok', '📦 Elasticsearch: 🟢 Running');
630
+ logger.log('info', ` ├─ Container: ${containers.elasticsearch}`);
631
+ logger.log('info', ` ├─ Port: ${config.ELASTICSEARCH_PORT}`);
632
+ logger.log('info', ` ├─ Connection: ${config.ELASTICSEARCH_URL}`);
633
+ logger.log('info', ` └─ Credentials: ${config.ELASTICSEARCH_USER}/${config.ELASTICSEARCH_PASS}`);
634
+ break;
635
+ case 'stopped':
636
+ logger.log('note', '📦 Elasticsearch: 🟡 Stopped');
637
+ logger.log('info', ` ├─ Container: ${containers.elasticsearch}`);
638
+ logger.log('info', ` └─ Port: ${config.ELASTICSEARCH_PORT}`);
639
+ break;
640
+ case 'not_exists':
641
+ logger.log('info', '📦 Elasticsearch: ⚪ Not installed');
642
+ // Check port availability
643
+ const esPort = parseInt(config.ELASTICSEARCH_PORT);
644
+ const esAvailable = await helpers.isPortAvailable(esPort);
645
+ if (!esAvailable) {
646
+ logger.log('error', ` └─ ⚠️ Port ${esPort} is in use by another process`);
647
+ } else {
648
+ logger.log('info', ` └─ Port ${esPort} is available`);
649
+ }
650
+ break;
651
+ }
388
652
  }
389
-
653
+
390
654
  /**
391
655
  * Show configuration
392
656
  */
@@ -420,6 +684,15 @@ export class ServiceManager {
420
684
  logger.log('info', ` Data: ${this.config.getDataDirectories().minio}`);
421
685
  logger.log('info', ` Endpoint: ${config.S3_ENDPOINT}`);
422
686
  logger.log('info', ` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`);
687
+
688
+ console.log();
689
+ logger.log('note', 'Elasticsearch:');
690
+ logger.log('info', ` Host: ${config.ELASTICSEARCH_HOST}:${config.ELASTICSEARCH_PORT}`);
691
+ logger.log('info', ` User: ${config.ELASTICSEARCH_USER}`);
692
+ logger.log('info', ' Password: ***');
693
+ logger.log('info', ` Container: ${this.config.getContainerNames().elasticsearch}`);
694
+ logger.log('info', ` Data: ${this.config.getDataDirectories().elasticsearch}`);
695
+ logger.log('info', ` Connection: ${config.ELASTICSEARCH_URL}`);
423
696
  }
424
697
 
425
698
  /**
@@ -477,16 +750,29 @@ export class ServiceManager {
477
750
  logger.log('note', 'S3/MinIO container is not running');
478
751
  }
479
752
  break;
480
-
753
+
754
+ case 'elasticsearch':
755
+ case 'es':
756
+ if (await this.docker.isRunning(containers.elasticsearch)) {
757
+ helpers.printHeader(`Elasticsearch Logs (last ${lines} lines)`);
758
+ const logs = await this.docker.logs(containers.elasticsearch, lines);
759
+ console.log(logs);
760
+ } else {
761
+ logger.log('note', 'Elasticsearch container is not running');
762
+ }
763
+ break;
764
+
481
765
  case 'all':
482
766
  case '':
483
767
  await this.showLogs('mongo', lines);
484
768
  console.log();
485
769
  await this.showLogs('minio', lines);
770
+ console.log();
771
+ await this.showLogs('elasticsearch', lines);
486
772
  break;
487
-
773
+
488
774
  default:
489
- logger.log('note', 'Usage: gitzone services logs [mongo|s3|all] [lines]');
775
+ logger.log('note', 'Usage: gitzone services logs [mongo|s3|elasticsearch|all] [lines]');
490
776
  break;
491
777
  }
492
778
  }
@@ -497,21 +783,28 @@ export class ServiceManager {
497
783
  public async removeContainers(): Promise<void> {
498
784
  const containers = this.config.getContainerNames();
499
785
  let removed = false;
500
-
786
+
501
787
  if (await this.docker.exists(containers.mongo)) {
502
788
  if (await this.docker.remove(containers.mongo, true)) {
503
789
  logger.log('ok', ' MongoDB container removed ✓');
504
790
  removed = true;
505
791
  }
506
792
  }
507
-
793
+
508
794
  if (await this.docker.exists(containers.minio)) {
509
795
  if (await this.docker.remove(containers.minio, true)) {
510
796
  logger.log('ok', ' S3/MinIO container removed ✓');
511
797
  removed = true;
512
798
  }
513
799
  }
514
-
800
+
801
+ if (await this.docker.exists(containers.elasticsearch)) {
802
+ if (await this.docker.remove(containers.elasticsearch, true)) {
803
+ logger.log('ok', ' Elasticsearch container removed ✓');
804
+ removed = true;
805
+ }
806
+ }
807
+
515
808
  if (!removed) {
516
809
  logger.log('note', ' No containers to remove');
517
810
  }
@@ -523,24 +816,60 @@ export class ServiceManager {
523
816
  public async cleanData(): Promise<void> {
524
817
  const directories = this.config.getDataDirectories();
525
818
  let cleaned = false;
526
-
527
- if (await plugins.smartfile.fs.fileExists(directories.mongo)) {
528
- await plugins.smartfile.fs.remove(directories.mongo);
819
+
820
+ if (await plugins.smartfs.directory(directories.mongo).exists()) {
821
+ await plugins.smartfs.directory(directories.mongo).recursive().delete();
529
822
  logger.log('ok', ' MongoDB data removed ✓');
530
823
  cleaned = true;
531
824
  }
532
-
533
- if (await plugins.smartfile.fs.fileExists(directories.minio)) {
534
- await plugins.smartfile.fs.remove(directories.minio);
825
+
826
+ if (await plugins.smartfs.directory(directories.minio).exists()) {
827
+ await plugins.smartfs.directory(directories.minio).recursive().delete();
535
828
  logger.log('ok', ' S3/MinIO data removed ✓');
536
829
  cleaned = true;
537
830
  }
538
-
831
+
832
+ if (await plugins.smartfs.directory(directories.elasticsearch).exists()) {
833
+ await plugins.smartfs.directory(directories.elasticsearch).recursive().delete();
834
+ logger.log('ok', ' Elasticsearch data removed ✓');
835
+ cleaned = true;
836
+ }
837
+
539
838
  if (!cleaned) {
540
839
  logger.log('note', ' No data to clean');
541
840
  }
542
841
  }
543
842
 
843
+ /**
844
+ * Configure which services are enabled
845
+ */
846
+ public async configureServices(): Promise<void> {
847
+ logger.log('note', 'Select which services to enable for this project:');
848
+ console.log();
849
+
850
+ const currentServices = this.enabledServices || ['mongodb', 'minio', 'elasticsearch'];
851
+
852
+ const smartinteract = new plugins.smartinteract.SmartInteract();
853
+ const response = await smartinteract.askQuestion({
854
+ name: 'services',
855
+ type: 'checkbox',
856
+ message: 'Which services do you want to enable?',
857
+ choices: [
858
+ { name: 'MongoDB', value: 'mongodb' },
859
+ { name: 'MinIO (S3)', value: 'minio' },
860
+ { name: 'Elasticsearch', value: 'elasticsearch' }
861
+ ],
862
+ default: currentServices
863
+ });
864
+
865
+ this.enabledServices = response.value || ['mongodb', 'minio', 'elasticsearch'];
866
+
867
+ // Save to npmextra.json
868
+ await this.saveServiceConfiguration(this.enabledServices);
869
+
870
+ logger.log('ok', '✅ Service configuration updated');
871
+ }
872
+
544
873
  /**
545
874
  * Reconfigure services with new ports
546
875
  */
@@ -551,20 +880,25 @@ export class ServiceManager {
551
880
 
552
881
  // Stop existing containers
553
882
  logger.log('note', '🛑 Stopping existing containers...');
554
-
883
+
555
884
  if (await this.docker.exists(containers.mongo)) {
556
885
  await this.docker.stop(containers.mongo);
557
886
  logger.log('ok', ' MongoDB stopped ✓');
558
887
  }
559
-
888
+
560
889
  if (await this.docker.exists(containers.minio)) {
561
890
  await this.docker.stop(containers.minio);
562
891
  logger.log('ok', ' S3/MinIO stopped ✓');
563
892
  }
564
-
893
+
894
+ if (await this.docker.exists(containers.elasticsearch)) {
895
+ await this.docker.stop(containers.elasticsearch);
896
+ logger.log('ok', ' Elasticsearch stopped ✓');
897
+ }
898
+
565
899
  // Reconfigure ports
566
900
  await this.config.reconfigurePorts();
567
-
901
+
568
902
  // Ask if user wants to restart services
569
903
  const smartinteract = new plugins.smartinteract.SmartInteract();
570
904
  const response = await smartinteract.askQuestion({
@@ -573,11 +907,10 @@ export class ServiceManager {
573
907
  message: 'Do you want to start services with new ports?',
574
908
  default: true
575
909
  });
576
-
910
+
577
911
  if (response.value) {
578
912
  console.log();
579
- await this.startMongoDB();
580
- await this.startMinIO();
913
+ await this.startAll();
581
914
  }
582
915
  }
583
916
  }
@@ -42,11 +42,15 @@ export const getRandomAvailablePort = async (): Promise<number> => {
42
42
  /**
43
43
  * Get the project name from package.json or directory
44
44
  */
45
- export const getProjectName = (): string => {
45
+ export const getProjectName = async (): Promise<string> => {
46
46
  try {
47
47
  const packageJsonPath = plugins.path.join(process.cwd(), 'package.json');
48
- if (plugins.smartfile.fs.fileExistsSync(packageJsonPath)) {
49
- const packageJson = plugins.smartfile.fs.toObjectSync(packageJsonPath);
48
+ if (await plugins.smartfs.file(packageJsonPath).exists()) {
49
+ const content = (await plugins.smartfs
50
+ .file(packageJsonPath)
51
+ .encoding('utf8')
52
+ .read()) as string;
53
+ const packageJson = JSON.parse(content);
50
54
  if (packageJson.name) {
51
55
  // Sanitize: @fin.cx/skr → fin-cx-skr
52
56
  return packageJson.name.replace(/@/g, '').replace(/[\/\.]/g, '-');
@@ -55,7 +59,7 @@ export const getProjectName = (): string => {
55
59
  } catch (error) {
56
60
  // Ignore errors and fall back to directory name
57
61
  }
58
-
62
+
59
63
  return plugins.path.basename(process.cwd());
60
64
  };
61
65