@git.zone/cli 2.13.15 → 2.14.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 (39) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/gitzone.cli.js +46 -35
  3. package/dist_ts/helpers.climode.d.ts +22 -0
  4. package/dist_ts/helpers.climode.js +158 -0
  5. package/dist_ts/helpers.smartconfig.d.ts +11 -0
  6. package/dist_ts/helpers.smartconfig.js +139 -0
  7. package/dist_ts/mod_commit/index.d.ts +2 -0
  8. package/dist_ts/mod_commit/index.js +204 -92
  9. package/dist_ts/mod_config/index.d.ts +7 -2
  10. package/dist_ts/mod_config/index.js +390 -176
  11. package/dist_ts/mod_format/classes.formatcontext.d.ts +11 -2
  12. package/dist_ts/mod_format/classes.formatcontext.js +14 -4
  13. package/dist_ts/mod_format/formatters/packagejson.formatter.js +1 -67
  14. package/dist_ts/mod_format/formatters/smartconfig.formatter.d.ts +2 -2
  15. package/dist_ts/mod_format/formatters/smartconfig.formatter.js +46 -39
  16. package/dist_ts/mod_format/index.d.ts +4 -1
  17. package/dist_ts/mod_format/index.js +221 -75
  18. package/dist_ts/mod_format/mod.plugins.d.ts +1 -2
  19. package/dist_ts/mod_format/mod.plugins.js +2 -3
  20. package/dist_ts/mod_services/index.d.ts +2 -0
  21. package/dist_ts/mod_services/index.js +366 -168
  22. package/dist_ts/mod_standard/index.d.ts +3 -1
  23. package/dist_ts/mod_standard/index.js +159 -59
  24. package/package.json +1 -1
  25. package/readme.hints.md +25 -32
  26. package/readme.md +87 -65
  27. package/ts/00_commitinfo_data.ts +1 -1
  28. package/ts/gitzone.cli.ts +50 -38
  29. package/ts/helpers.climode.ts +212 -0
  30. package/ts/helpers.smartconfig.ts +192 -0
  31. package/ts/mod_commit/index.ts +325 -98
  32. package/ts/mod_config/index.ts +490 -182
  33. package/ts/mod_format/classes.formatcontext.ts +20 -3
  34. package/ts/mod_format/formatters/packagejson.formatter.ts +0 -91
  35. package/ts/mod_format/formatters/smartconfig.formatter.ts +55 -39
  36. package/ts/mod_format/index.ts +279 -90
  37. package/ts/mod_format/mod.plugins.ts +0 -2
  38. package/ts/mod_services/index.ts +550 -183
  39. package/ts/mod_standard/index.ts +191 -58
@@ -1,12 +1,26 @@
1
- import * as plugins from './mod.plugins.js';
2
- import * as helpers from './helpers.js';
3
- import { ServiceManager } from './classes.servicemanager.js';
4
- import { GlobalRegistry } from './classes.globalregistry.js';
5
- import { logger } from '../gitzone.logging.js';
1
+ import * as plugins from "./mod.plugins.js";
2
+ import * as helpers from "./helpers.js";
3
+ import { ServiceManager } from "./classes.servicemanager.js";
4
+ import { GlobalRegistry } from "./classes.globalregistry.js";
5
+ import { logger } from "../gitzone.logging.js";
6
+ import type { ICliMode } from "../helpers.climode.js";
7
+ import { getCliMode, printJson } from "../helpers.climode.js";
8
+ import {
9
+ getCliConfigValueFromData,
10
+ readSmartconfigFile,
11
+ setCliConfigValueInData,
12
+ writeSmartconfigFile,
13
+ } from "../helpers.smartconfig.js";
6
14
 
7
15
  export const run = async (argvArg: any) => {
16
+ const mode = await getCliMode(argvArg);
8
17
  const isGlobal = argvArg.g || argvArg.global;
9
- const command = argvArg._[1] || 'help';
18
+ const command = argvArg._[1] || "help";
19
+
20
+ if (mode.help || command === "help") {
21
+ showHelp(mode);
22
+ return;
23
+ }
10
24
 
11
25
  // Handle global commands first
12
26
  if (isGlobal) {
@@ -14,264 +28,597 @@ export const run = async (argvArg: any) => {
14
28
  return;
15
29
  }
16
30
 
17
- // Local project commands
18
- const serviceManager = new ServiceManager();
19
- await serviceManager.init();
20
-
21
- const service = argvArg._[2] || 'all';
31
+ const service = argvArg._[2] || "all";
22
32
 
23
33
  switch (command) {
24
- case 'start':
25
- await handleStart(serviceManager, service);
26
- break;
27
-
28
- case 'stop':
29
- await handleStop(serviceManager, service);
30
- break;
31
-
32
- case 'restart':
33
- await handleRestart(serviceManager, service);
34
- break;
35
-
36
- case 'status':
37
- await serviceManager.showStatus();
38
- break;
39
-
40
- case 'config':
41
- if (service === 'services' || argvArg._[2] === 'services') {
34
+ case "config":
35
+ if (service === "services" || argvArg._[2] === "services") {
36
+ const serviceManager = new ServiceManager();
37
+ await serviceManager.init();
42
38
  await handleConfigureServices(serviceManager);
43
39
  } else {
44
- await serviceManager.showConfig();
40
+ await handleShowConfig(mode);
45
41
  }
46
42
  break;
47
43
 
48
- case 'compass':
49
- await serviceManager.showCompassConnection();
44
+ case "set":
45
+ await handleSetServices(argvArg._[2], mode);
50
46
  break;
51
-
52
- case 'logs':
53
- const lines = parseInt(argvArg._[3]) || 20;
54
- await serviceManager.showLogs(service, lines);
55
- break;
56
-
57
- case 'remove':
58
- await handleRemove(serviceManager);
47
+
48
+ case "enable":
49
+ await handleEnableServices(argvArg._.slice(2), mode);
59
50
  break;
60
-
61
- case 'clean':
62
- await handleClean(serviceManager);
51
+
52
+ case "disable":
53
+ await handleDisableServices(argvArg._.slice(2), mode);
63
54
  break;
64
-
65
- case 'reconfigure':
66
- await serviceManager.reconfigure();
55
+
56
+ case "start":
57
+ case "stop":
58
+ case "restart":
59
+ case "status":
60
+ case "compass":
61
+ case "logs":
62
+ case "remove":
63
+ case "clean":
64
+ case "reconfigure": {
65
+ const serviceManager = new ServiceManager();
66
+ await serviceManager.init();
67
+
68
+ switch (command) {
69
+ case "start":
70
+ await handleStart(serviceManager, service);
71
+ break;
72
+
73
+ case "stop":
74
+ await handleStop(serviceManager, service);
75
+ break;
76
+
77
+ case "restart":
78
+ await handleRestart(serviceManager, service);
79
+ break;
80
+
81
+ case "status":
82
+ await serviceManager.showStatus();
83
+ break;
84
+
85
+ case "compass":
86
+ await serviceManager.showCompassConnection();
87
+ break;
88
+
89
+ case "logs": {
90
+ const lines = parseInt(argvArg._[3]) || 20;
91
+ await serviceManager.showLogs(service, lines);
92
+ break;
93
+ }
94
+
95
+ case "remove":
96
+ await handleRemove(serviceManager);
97
+ break;
98
+
99
+ case "clean":
100
+ await handleClean(serviceManager);
101
+ break;
102
+
103
+ case "reconfigure":
104
+ await serviceManager.reconfigure();
105
+ break;
106
+ }
67
107
  break;
68
-
69
- case 'help':
108
+ }
70
109
  default:
71
- showHelp();
110
+ showHelp(mode);
72
111
  break;
73
112
  }
74
113
  };
75
114
 
115
+ const allowedServices = ["mongodb", "minio", "elasticsearch"];
116
+
117
+ const normalizeServiceName = (service: string): string => {
118
+ switch (service) {
119
+ case "mongo":
120
+ case "mongodb":
121
+ return "mongodb";
122
+ case "minio":
123
+ case "s3":
124
+ return "minio";
125
+ case "elastic":
126
+ case "elasticsearch":
127
+ case "es":
128
+ return "elasticsearch";
129
+ default:
130
+ return service;
131
+ }
132
+ };
133
+
134
+ async function readServicesConfig(): Promise<{
135
+ enabledServices: string[];
136
+ environment: Record<string, any> | null;
137
+ }> {
138
+ const smartconfigData = await readSmartconfigFile();
139
+ const enabledServices = getCliConfigValueFromData(
140
+ smartconfigData,
141
+ "services",
142
+ );
143
+ let environment: Record<string, any> | null = null;
144
+ const envPath = plugins.path.join(process.cwd(), ".nogit", "env.json");
145
+ if (await plugins.smartfs.file(envPath).exists()) {
146
+ const envContent = (await plugins.smartfs
147
+ .file(envPath)
148
+ .encoding("utf8")
149
+ .read()) as string;
150
+ environment = JSON.parse(envContent);
151
+ }
152
+
153
+ return {
154
+ enabledServices: Array.isArray(enabledServices) ? enabledServices : [],
155
+ environment,
156
+ };
157
+ }
158
+
159
+ async function updateEnabledServices(services: string[]): Promise<void> {
160
+ const smartconfigData = await readSmartconfigFile();
161
+ setCliConfigValueInData(smartconfigData, "services", services);
162
+ await writeSmartconfigFile(smartconfigData);
163
+ }
164
+
165
+ async function handleShowConfig(mode: ICliMode) {
166
+ const configData = await readServicesConfig();
167
+
168
+ if (mode.json) {
169
+ printJson(configData);
170
+ return;
171
+ }
172
+
173
+ helpers.printHeader("Current Services Configuration");
174
+ logger.log(
175
+ "info",
176
+ `Enabled Services: ${configData.enabledServices.length > 0 ? configData.enabledServices.join(", ") : "none configured"}`,
177
+ );
178
+ console.log();
179
+
180
+ if (!configData.environment) {
181
+ logger.log(
182
+ "note",
183
+ "No .nogit/env.json found yet. Start a service once to create runtime defaults.",
184
+ );
185
+ return;
186
+ }
187
+
188
+ const env = configData.environment;
189
+ logger.log("note", "MongoDB:");
190
+ logger.log("info", ` Host: ${env.MONGODB_HOST}:${env.MONGODB_PORT}`);
191
+ logger.log("info", ` Database: ${env.MONGODB_NAME}`);
192
+ logger.log("info", ` User: ${env.MONGODB_USER}`);
193
+ logger.log("info", ` Container: ${env.PROJECT_NAME}-mongodb`);
194
+ logger.log(
195
+ "info",
196
+ ` Data: ${plugins.path.join(process.cwd(), ".nogit", "mongodata")}`,
197
+ );
198
+ logger.log("info", ` Connection: ${env.MONGODB_URL}`);
199
+ console.log();
200
+
201
+ logger.log("note", "S3/MinIO:");
202
+ logger.log("info", ` Host: ${env.S3_HOST}`);
203
+ logger.log("info", ` API Port: ${env.S3_PORT}`);
204
+ logger.log("info", ` Console Port: ${env.S3_CONSOLE_PORT}`);
205
+ logger.log("info", ` Bucket: ${env.S3_BUCKET}`);
206
+ logger.log("info", ` Container: ${env.PROJECT_NAME}-minio`);
207
+ logger.log(
208
+ "info",
209
+ ` Data: ${plugins.path.join(process.cwd(), ".nogit", "miniodata")}`,
210
+ );
211
+ logger.log("info", ` Endpoint: ${env.S3_ENDPOINT}`);
212
+ console.log();
213
+
214
+ logger.log("note", "Elasticsearch:");
215
+ logger.log(
216
+ "info",
217
+ ` Host: ${env.ELASTICSEARCH_HOST}:${env.ELASTICSEARCH_PORT}`,
218
+ );
219
+ logger.log("info", ` User: ${env.ELASTICSEARCH_USER}`);
220
+ logger.log("info", ` Container: ${env.PROJECT_NAME}-elasticsearch`);
221
+ logger.log(
222
+ "info",
223
+ ` Data: ${plugins.path.join(process.cwd(), ".nogit", "esdata")}`,
224
+ );
225
+ logger.log("info", ` Connection: ${env.ELASTICSEARCH_URL}`);
226
+ }
227
+
228
+ async function handleSetServices(rawValue: string | undefined, mode: ICliMode) {
229
+ if (!rawValue) {
230
+ throw new Error("Specify a comma-separated list of services");
231
+ }
232
+
233
+ const requestedServices = rawValue
234
+ .split(",")
235
+ .map((service) => normalizeServiceName(service.trim()))
236
+ .filter(Boolean);
237
+ validateRequestedServices(requestedServices);
238
+ await updateEnabledServices(requestedServices);
239
+
240
+ if (mode.json) {
241
+ printJson({ ok: true, action: "set", enabledServices: requestedServices });
242
+ return;
243
+ }
244
+
245
+ logger.log("ok", `Enabled services set to: ${requestedServices.join(", ")}`);
246
+ }
247
+
248
+ async function handleEnableServices(
249
+ requestedServices: string[],
250
+ mode: ICliMode,
251
+ ) {
252
+ const normalizedServices = requestedServices.map((service) =>
253
+ normalizeServiceName(service),
254
+ );
255
+ validateRequestedServices(normalizedServices);
256
+
257
+ const configData = await readServicesConfig();
258
+ const nextServices = Array.from(
259
+ new Set([...configData.enabledServices, ...normalizedServices]),
260
+ );
261
+ await updateEnabledServices(nextServices);
262
+
263
+ if (mode.json) {
264
+ printJson({ ok: true, action: "enable", enabledServices: nextServices });
265
+ return;
266
+ }
267
+
268
+ logger.log("ok", `Enabled services: ${nextServices.join(", ")}`);
269
+ }
270
+
271
+ async function handleDisableServices(
272
+ requestedServices: string[],
273
+ mode: ICliMode,
274
+ ) {
275
+ const normalizedServices = requestedServices.map((service) =>
276
+ normalizeServiceName(service),
277
+ );
278
+ validateRequestedServices(normalizedServices);
279
+
280
+ const configData = await readServicesConfig();
281
+ const nextServices = configData.enabledServices.filter(
282
+ (service) => !normalizedServices.includes(service),
283
+ );
284
+ await updateEnabledServices(nextServices);
285
+
286
+ if (mode.json) {
287
+ printJson({ ok: true, action: "disable", enabledServices: nextServices });
288
+ return;
289
+ }
290
+
291
+ logger.log("ok", `Enabled services: ${nextServices.join(", ")}`);
292
+ }
293
+
294
+ function validateRequestedServices(services: string[]): void {
295
+ if (services.length === 0) {
296
+ throw new Error("Specify at least one service");
297
+ }
298
+
299
+ const invalidServices = services.filter(
300
+ (service) => !allowedServices.includes(service),
301
+ );
302
+ if (invalidServices.length > 0) {
303
+ throw new Error(`Unknown service(s): ${invalidServices.join(", ")}`);
304
+ }
305
+ }
306
+
76
307
  async function handleStart(serviceManager: ServiceManager, service: string) {
77
- helpers.printHeader('Starting Services');
308
+ helpers.printHeader("Starting Services");
78
309
 
79
310
  switch (service) {
80
- case 'mongo':
81
- case 'mongodb':
311
+ case "mongo":
312
+ case "mongodb":
82
313
  await serviceManager.startMongoDB();
83
314
  break;
84
315
 
85
- case 'minio':
86
- case 's3':
316
+ case "minio":
317
+ case "s3":
87
318
  await serviceManager.startMinIO();
88
319
  break;
89
320
 
90
- case 'elasticsearch':
91
- case 'es':
321
+ case "elasticsearch":
322
+ case "es":
92
323
  await serviceManager.startElasticsearch();
93
324
  break;
94
325
 
95
- case 'all':
96
- case '':
326
+ case "all":
327
+ case "":
97
328
  await serviceManager.startAll();
98
329
  break;
99
330
 
100
331
  default:
101
- logger.log('error', `Unknown service: ${service}`);
102
- logger.log('note', 'Use: mongo, s3, elasticsearch, or all');
332
+ logger.log("error", `Unknown service: ${service}`);
333
+ logger.log("note", "Use: mongo, s3, elasticsearch, or all");
103
334
  break;
104
335
  }
105
336
  }
106
337
 
107
338
  async function handleStop(serviceManager: ServiceManager, service: string) {
108
- helpers.printHeader('Stopping Services');
339
+ helpers.printHeader("Stopping Services");
109
340
 
110
341
  switch (service) {
111
- case 'mongo':
112
- case 'mongodb':
342
+ case "mongo":
343
+ case "mongodb":
113
344
  await serviceManager.stopMongoDB();
114
345
  break;
115
346
 
116
- case 'minio':
117
- case 's3':
347
+ case "minio":
348
+ case "s3":
118
349
  await serviceManager.stopMinIO();
119
350
  break;
120
351
 
121
- case 'elasticsearch':
122
- case 'es':
352
+ case "elasticsearch":
353
+ case "es":
123
354
  await serviceManager.stopElasticsearch();
124
355
  break;
125
356
 
126
- case 'all':
127
- case '':
357
+ case "all":
358
+ case "":
128
359
  await serviceManager.stopAll();
129
360
  break;
130
361
 
131
362
  default:
132
- logger.log('error', `Unknown service: ${service}`);
133
- logger.log('note', 'Use: mongo, s3, elasticsearch, or all');
363
+ logger.log("error", `Unknown service: ${service}`);
364
+ logger.log("note", "Use: mongo, s3, elasticsearch, or all");
134
365
  break;
135
366
  }
136
367
  }
137
368
 
138
369
  async function handleRestart(serviceManager: ServiceManager, service: string) {
139
- helpers.printHeader('Restarting Services');
370
+ helpers.printHeader("Restarting Services");
140
371
 
141
372
  switch (service) {
142
- case 'mongo':
143
- case 'mongodb':
373
+ case "mongo":
374
+ case "mongodb":
144
375
  await serviceManager.stopMongoDB();
145
376
  await plugins.smartdelay.delayFor(2000);
146
377
  await serviceManager.startMongoDB();
147
378
  break;
148
379
 
149
- case 'minio':
150
- case 's3':
380
+ case "minio":
381
+ case "s3":
151
382
  await serviceManager.stopMinIO();
152
383
  await plugins.smartdelay.delayFor(2000);
153
384
  await serviceManager.startMinIO();
154
385
  break;
155
386
 
156
- case 'elasticsearch':
157
- case 'es':
387
+ case "elasticsearch":
388
+ case "es":
158
389
  await serviceManager.stopElasticsearch();
159
390
  await plugins.smartdelay.delayFor(2000);
160
391
  await serviceManager.startElasticsearch();
161
392
  break;
162
393
 
163
- case 'all':
164
- case '':
394
+ case "all":
395
+ case "":
165
396
  await serviceManager.stopAll();
166
397
  await plugins.smartdelay.delayFor(2000);
167
398
  await serviceManager.startAll();
168
399
  break;
169
400
 
170
401
  default:
171
- logger.log('error', `Unknown service: ${service}`);
402
+ logger.log("error", `Unknown service: ${service}`);
172
403
  break;
173
404
  }
174
405
  }
175
406
 
176
407
  async function handleRemove(serviceManager: ServiceManager) {
177
- helpers.printHeader('Removing Containers');
178
- logger.log('note', '⚠️ This will remove containers but preserve data');
179
-
180
- const shouldContinue = await plugins.smartinteract.SmartInteract.getCliConfirmation('Continue?', false);
181
-
408
+ helpers.printHeader("Removing Containers");
409
+ logger.log("note", "⚠️ This will remove containers but preserve data");
410
+
411
+ const shouldContinue =
412
+ await plugins.smartinteract.SmartInteract.getCliConfirmation(
413
+ "Continue?",
414
+ false,
415
+ );
416
+
182
417
  if (shouldContinue) {
183
418
  await serviceManager.removeContainers();
184
419
  } else {
185
- logger.log('note', 'Cancelled');
420
+ logger.log("note", "Cancelled");
186
421
  }
187
422
  }
188
423
 
189
424
  async function handleClean(serviceManager: ServiceManager) {
190
- helpers.printHeader('Clean All');
191
- logger.log('error', '⚠️ WARNING: This will remove all containers and data!');
192
- logger.log('error', 'This action cannot be undone!');
425
+ helpers.printHeader("Clean All");
426
+ logger.log("error", "⚠️ WARNING: This will remove all containers and data!");
427
+ logger.log("error", "This action cannot be undone!");
193
428
 
194
429
  const smartinteraction = new plugins.smartinteract.SmartInteract();
195
430
  const confirmAnswer = await smartinteraction.askQuestion({
196
- name: 'confirm',
197
- type: 'input',
431
+ name: "confirm",
432
+ type: "input",
198
433
  message: 'Type "yes" to confirm:',
199
- default: 'no'
434
+ default: "no",
200
435
  });
201
436
 
202
- if (confirmAnswer.value === 'yes') {
437
+ if (confirmAnswer.value === "yes") {
203
438
  await serviceManager.removeContainers();
204
439
  console.log();
205
440
  await serviceManager.cleanData();
206
- logger.log('ok', 'All cleaned ✓');
441
+ logger.log("ok", "All cleaned ✓");
207
442
  } else {
208
- logger.log('note', 'Cancelled');
443
+ logger.log("note", "Cancelled");
209
444
  }
210
445
  }
211
446
 
212
447
  async function handleConfigureServices(serviceManager: ServiceManager) {
213
- helpers.printHeader('Configure Services');
448
+ helpers.printHeader("Configure Services");
214
449
  await serviceManager.configureServices();
215
450
  }
216
451
 
217
- function showHelp() {
218
- helpers.printHeader('GitZone Services Manager');
452
+ export function showHelp(mode?: ICliMode) {
453
+ if (mode?.json) {
454
+ printJson({
455
+ command: "services",
456
+ usage: "gitzone services <command> [options]",
457
+ commands: [
458
+ {
459
+ name: "config",
460
+ description:
461
+ "Show configured services and any existing runtime env.json data",
462
+ },
463
+ {
464
+ name: "set <csv>",
465
+ description: "Set the enabled service list without prompts",
466
+ },
467
+ {
468
+ name: "enable <service...>",
469
+ description: "Enable one or more services without prompts",
470
+ },
471
+ {
472
+ name: "disable <service...>",
473
+ description: "Disable one or more services without prompts",
474
+ },
475
+ { name: "start [service]", description: "Start services" },
476
+ { name: "stop [service]", description: "Stop services" },
477
+ { name: "status", description: "Show service status" },
478
+ ],
479
+ examples: [
480
+ "gitzone services config --json",
481
+ "gitzone services set mongodb,minio",
482
+ "gitzone services enable elasticsearch",
483
+ ],
484
+ });
485
+ return;
486
+ }
487
+
488
+ helpers.printHeader("GitZone Services Manager");
219
489
 
220
- logger.log('ok', 'Usage: gitzone services [command] [options]');
490
+ logger.log("ok", "Usage: gitzone services [command] [options]");
221
491
  console.log();
222
492
 
223
- logger.log('note', 'Commands:');
224
- logger.log('info', ' start [service] Start services (mongo|s3|elasticsearch|all)');
225
- logger.log('info', ' stop [service] Stop services (mongo|s3|elasticsearch|all)');
226
- logger.log('info', ' restart [service] Restart services (mongo|s3|elasticsearch|all)');
227
- logger.log('info', ' status Show service status');
228
- logger.log('info', ' config Show current configuration');
229
- logger.log('info', ' config services Configure which services are enabled');
230
- logger.log('info', ' compass Show MongoDB Compass connection string');
231
- logger.log('info', ' logs [service] Show logs (mongo|s3|elasticsearch|all) [lines]');
232
- logger.log('info', ' reconfigure Reassign ports and restart services');
233
- logger.log('info', ' remove Remove all containers');
234
- logger.log('info', ' clean Remove all containers and data ⚠️');
235
- logger.log('info', ' help Show this help message');
493
+ logger.log("note", "Commands:");
494
+ logger.log(
495
+ "info",
496
+ " start [service] Start services (mongo|s3|elasticsearch|all)",
497
+ );
498
+ logger.log(
499
+ "info",
500
+ " stop [service] Stop services (mongo|s3|elasticsearch|all)",
501
+ );
502
+ logger.log(
503
+ "info",
504
+ " restart [service] Restart services (mongo|s3|elasticsearch|all)",
505
+ );
506
+ logger.log("info", " status Show service status");
507
+ logger.log("info", " config Show current configuration");
508
+ logger.log(
509
+ "info",
510
+ " config services Configure which services are enabled",
511
+ );
512
+ logger.log(
513
+ "info",
514
+ " set <csv> Set enabled services without prompts",
515
+ );
516
+ logger.log("info", " enable <svc...> Enable one or more services");
517
+ logger.log("info", " disable <svc...> Disable one or more services");
518
+ logger.log(
519
+ "info",
520
+ " compass Show MongoDB Compass connection string",
521
+ );
522
+ logger.log(
523
+ "info",
524
+ " logs [service] Show logs (mongo|s3|elasticsearch|all) [lines]",
525
+ );
526
+ logger.log("info", " reconfigure Reassign ports and restart services");
527
+ logger.log("info", " remove Remove all containers");
528
+ logger.log("info", " clean Remove all containers and data ⚠️");
529
+ logger.log("info", " help Show this help message");
236
530
  console.log();
237
531
 
238
- logger.log('note', 'Available Services:');
239
- logger.log('info', ' • MongoDB (mongo) - Document database');
240
- logger.log('info', ' • MinIO (s3) - S3-compatible object storage');
241
- logger.log('info', ' • Elasticsearch (elasticsearch) - Search and analytics engine');
532
+ logger.log("note", "Available Services:");
533
+ logger.log("info", " • MongoDB (mongo) - Document database");
534
+ logger.log("info", " • MinIO (s3) - S3-compatible object storage");
535
+ logger.log(
536
+ "info",
537
+ " • Elasticsearch (elasticsearch) - Search and analytics engine",
538
+ );
242
539
  console.log();
243
540
 
244
- logger.log('note', 'Features:');
245
- logger.log('info', ' • Auto-creates .nogit/env.json with smart defaults');
246
- logger.log('info', ' • Random ports (20000-30000) for MongoDB/MinIO to avoid conflicts');
247
- logger.log('info', ' • Elasticsearch uses standard port 9200');
248
- logger.log('info', ' Project-specific containers for multi-project support');
249
- logger.log('info', ' • Preserves custom configuration values');
250
- logger.log('info', 'MongoDB Compass connection support');
541
+ logger.log("note", "Features:");
542
+ logger.log("info", " • Auto-creates .nogit/env.json with smart defaults");
543
+ logger.log(
544
+ "info",
545
+ "Random ports (20000-30000) for MongoDB/MinIO to avoid conflicts",
546
+ );
547
+ logger.log("info", "Elasticsearch uses standard port 9200");
548
+ logger.log(
549
+ "info",
550
+ " • Project-specific containers for multi-project support",
551
+ );
552
+ logger.log("info", " • Preserves custom configuration values");
553
+ logger.log("info", " • MongoDB Compass connection support");
251
554
  console.log();
252
555
 
253
- logger.log('note', 'Examples:');
254
- logger.log('info', ' gitzone services start # Start all services');
255
- logger.log('info', ' gitzone services start mongo # Start only MongoDB');
256
- logger.log('info', ' gitzone services start elasticsearch # Start only Elasticsearch');
257
- logger.log('info', ' gitzone services stop # Stop all services');
258
- logger.log('info', ' gitzone services status # Check service status');
259
- logger.log('info', ' gitzone services config # Show configuration');
260
- logger.log('info', ' gitzone services compass # Get MongoDB Compass connection');
261
- logger.log('info', ' gitzone services logs elasticsearch # Show Elasticsearch logs');
556
+ logger.log("note", "Examples:");
557
+ logger.log(
558
+ "info",
559
+ " gitzone services start # Start all services",
560
+ );
561
+ logger.log(
562
+ "info",
563
+ " gitzone services start mongo # Start only MongoDB",
564
+ );
565
+ logger.log(
566
+ "info",
567
+ " gitzone services start elasticsearch # Start only Elasticsearch",
568
+ );
569
+ logger.log(
570
+ "info",
571
+ " gitzone services stop # Stop all services",
572
+ );
573
+ logger.log(
574
+ "info",
575
+ " gitzone services status # Check service status",
576
+ );
577
+ logger.log(
578
+ "info",
579
+ " gitzone services config # Show configuration",
580
+ );
581
+ logger.log(
582
+ "info",
583
+ " gitzone services config --json # Show configuration as JSON",
584
+ );
585
+ logger.log(
586
+ "info",
587
+ " gitzone services set mongodb,minio # Configure services without prompts",
588
+ );
589
+ logger.log(
590
+ "info",
591
+ " gitzone services compass # Get MongoDB Compass connection",
592
+ );
593
+ logger.log(
594
+ "info",
595
+ " gitzone services logs elasticsearch # Show Elasticsearch logs",
596
+ );
262
597
  console.log();
263
598
 
264
- logger.log('note', 'Global Commands (-g/--global):');
265
- logger.log('info', ' list -g List all registered projects');
266
- logger.log('info', ' status -g Show status across all projects');
267
- logger.log('info', ' stop -g Stop all containers across all projects');
268
- logger.log('info', ' cleanup -g Remove stale registry entries');
599
+ logger.log("note", "Global Commands (-g/--global):");
600
+ logger.log("info", " list -g List all registered projects");
601
+ logger.log("info", " status -g Show status across all projects");
602
+ logger.log(
603
+ "info",
604
+ " stop -g Stop all containers across all projects",
605
+ );
606
+ logger.log("info", " cleanup -g Remove stale registry entries");
269
607
  console.log();
270
608
 
271
- logger.log('note', 'Global Examples:');
272
- logger.log('info', ' gitzone services list -g # List all registered projects');
273
- logger.log('info', ' gitzone services status -g # Show global container status');
274
- logger.log('info', ' gitzone services stop -g # Stop all (prompts for confirmation)');
609
+ logger.log("note", "Global Examples:");
610
+ logger.log(
611
+ "info",
612
+ " gitzone services list -g # List all registered projects",
613
+ );
614
+ logger.log(
615
+ "info",
616
+ " gitzone services status -g # Show global container status",
617
+ );
618
+ logger.log(
619
+ "info",
620
+ " gitzone services stop -g # Stop all (prompts for confirmation)",
621
+ );
275
622
  }
276
623
 
277
624
  // ==================== Global Command Handlers ====================
@@ -280,23 +627,23 @@ async function handleGlobalCommand(command: string) {
280
627
  const globalRegistry = GlobalRegistry.getInstance();
281
628
 
282
629
  switch (command) {
283
- case 'list':
630
+ case "list":
284
631
  await handleGlobalList(globalRegistry);
285
632
  break;
286
633
 
287
- case 'status':
634
+ case "status":
288
635
  await handleGlobalStatus(globalRegistry);
289
636
  break;
290
637
 
291
- case 'stop':
638
+ case "stop":
292
639
  await handleGlobalStop(globalRegistry);
293
640
  break;
294
641
 
295
- case 'cleanup':
642
+ case "cleanup":
296
643
  await handleGlobalCleanup(globalRegistry);
297
644
  break;
298
645
 
299
- case 'help':
646
+ case "help":
300
647
  default:
301
648
  showHelp();
302
649
  break;
@@ -304,13 +651,13 @@ async function handleGlobalCommand(command: string) {
304
651
  }
305
652
 
306
653
  async function handleGlobalList(globalRegistry: GlobalRegistry) {
307
- helpers.printHeader('Registered Projects (Global)');
654
+ helpers.printHeader("Registered Projects (Global)");
308
655
 
309
656
  const projects = await globalRegistry.getAllProjects();
310
657
  const projectPaths = Object.keys(projects);
311
658
 
312
659
  if (projectPaths.length === 0) {
313
- logger.log('note', 'No projects registered');
660
+ logger.log("note", "No projects registered");
314
661
  return;
315
662
  }
316
663
 
@@ -319,20 +666,20 @@ async function handleGlobalList(globalRegistry: GlobalRegistry) {
319
666
  const lastActive = new Date(project.lastActive).toLocaleString();
320
667
 
321
668
  console.log();
322
- logger.log('ok', `📁 ${project.projectName}`);
323
- logger.log('info', ` Path: ${project.projectPath}`);
324
- logger.log('info', ` Services: ${project.enabledServices.join(', ')}`);
325
- logger.log('info', ` Last Active: ${lastActive}`);
669
+ logger.log("ok", `📁 ${project.projectName}`);
670
+ logger.log("info", ` Path: ${project.projectPath}`);
671
+ logger.log("info", ` Services: ${project.enabledServices.join(", ")}`);
672
+ logger.log("info", ` Last Active: ${lastActive}`);
326
673
  }
327
674
  }
328
675
 
329
676
  async function handleGlobalStatus(globalRegistry: GlobalRegistry) {
330
- helpers.printHeader('Global Service Status');
677
+ helpers.printHeader("Global Service Status");
331
678
 
332
679
  const statuses = await globalRegistry.getGlobalStatus();
333
680
 
334
681
  if (statuses.length === 0) {
335
- logger.log('note', 'No projects registered');
682
+ logger.log("note", "No projects registered");
336
683
  return;
337
684
  }
338
685
 
@@ -341,28 +688,39 @@ async function handleGlobalStatus(globalRegistry: GlobalRegistry) {
341
688
 
342
689
  for (const project of statuses) {
343
690
  console.log();
344
- logger.log('ok', `📁 ${project.projectName}`);
345
- logger.log('info', ` Path: ${project.projectPath}`);
691
+ logger.log("ok", `📁 ${project.projectName}`);
692
+ logger.log("info", ` Path: ${project.projectPath}`);
346
693
 
347
694
  if (project.containers.length === 0) {
348
- logger.log('note', ' No containers configured');
695
+ logger.log("note", " No containers configured");
349
696
  continue;
350
697
  }
351
698
 
352
699
  for (const container of project.containers) {
353
700
  totalContainers++;
354
- const statusIcon = container.status === 'running' ? '🟢' : container.status === 'exited' ? '🟡' : '⚪';
355
- if (container.status === 'running') runningCount++;
356
- logger.log('info', ` ${statusIcon} ${container.name}: ${container.status}`);
701
+ const statusIcon =
702
+ container.status === "running"
703
+ ? "🟢"
704
+ : container.status === "exited"
705
+ ? "🟡"
706
+ : "⚪";
707
+ if (container.status === "running") runningCount++;
708
+ logger.log(
709
+ "info",
710
+ ` ${statusIcon} ${container.name}: ${container.status}`,
711
+ );
357
712
  }
358
713
  }
359
714
 
360
715
  console.log();
361
- logger.log('note', `Summary: ${runningCount}/${totalContainers} containers running across ${statuses.length} project(s)`);
716
+ logger.log(
717
+ "note",
718
+ `Summary: ${runningCount}/${totalContainers} containers running across ${statuses.length} project(s)`,
719
+ );
362
720
  }
363
721
 
364
722
  async function handleGlobalStop(globalRegistry: GlobalRegistry) {
365
- helpers.printHeader('Stop All Containers (Global)');
723
+ helpers.printHeader("Stop All Containers (Global)");
366
724
 
367
725
  const statuses = await globalRegistry.getGlobalStatus();
368
726
 
@@ -370,64 +728,73 @@ async function handleGlobalStop(globalRegistry: GlobalRegistry) {
370
728
  let runningCount = 0;
371
729
  for (const project of statuses) {
372
730
  for (const container of project.containers) {
373
- if (container.status === 'running') runningCount++;
731
+ if (container.status === "running") runningCount++;
374
732
  }
375
733
  }
376
734
 
377
735
  if (runningCount === 0) {
378
- logger.log('note', 'No running containers found');
736
+ logger.log("note", "No running containers found");
379
737
  return;
380
738
  }
381
739
 
382
- logger.log('note', `Found ${runningCount} running container(s) across ${statuses.length} project(s)`);
740
+ logger.log(
741
+ "note",
742
+ `Found ${runningCount} running container(s) across ${statuses.length} project(s)`,
743
+ );
383
744
  console.log();
384
745
 
385
746
  // Show what will be stopped
386
747
  for (const project of statuses) {
387
- const runningContainers = project.containers.filter(c => c.status === 'running');
748
+ const runningContainers = project.containers.filter(
749
+ (c) => c.status === "running",
750
+ );
388
751
  if (runningContainers.length > 0) {
389
- logger.log('info', `${project.projectName}:`);
752
+ logger.log("info", `${project.projectName}:`);
390
753
  for (const container of runningContainers) {
391
- logger.log('info', ` • ${container.name}`);
754
+ logger.log("info", ` • ${container.name}`);
392
755
  }
393
756
  }
394
757
  }
395
758
 
396
759
  console.log();
397
- const shouldContinue = await plugins.smartinteract.SmartInteract.getCliConfirmation(
398
- 'Stop all containers?',
399
- false
400
- );
760
+ const shouldContinue =
761
+ await plugins.smartinteract.SmartInteract.getCliConfirmation(
762
+ "Stop all containers?",
763
+ false,
764
+ );
401
765
 
402
766
  if (!shouldContinue) {
403
- logger.log('note', 'Cancelled');
767
+ logger.log("note", "Cancelled");
404
768
  return;
405
769
  }
406
770
 
407
- logger.log('note', 'Stopping all containers...');
771
+ logger.log("note", "Stopping all containers...");
408
772
  const result = await globalRegistry.stopAll();
409
773
 
410
774
  if (result.stopped.length > 0) {
411
- logger.log('ok', `Stopped: ${result.stopped.join(', ')}`);
775
+ logger.log("ok", `Stopped: ${result.stopped.join(", ")}`);
412
776
  }
413
777
  if (result.failed.length > 0) {
414
- logger.log('error', `Failed to stop: ${result.failed.join(', ')}`);
778
+ logger.log("error", `Failed to stop: ${result.failed.join(", ")}`);
415
779
  }
416
780
  }
417
781
 
418
782
  async function handleGlobalCleanup(globalRegistry: GlobalRegistry) {
419
- helpers.printHeader('Cleanup Registry (Global)');
783
+ helpers.printHeader("Cleanup Registry (Global)");
420
784
 
421
- logger.log('note', 'Checking for stale registry entries...');
785
+ logger.log("note", "Checking for stale registry entries...");
422
786
  const removed = await globalRegistry.cleanup();
423
787
 
424
788
  if (removed.length === 0) {
425
- logger.log('ok', 'No stale entries found');
789
+ logger.log("ok", "No stale entries found");
426
790
  return;
427
791
  }
428
792
 
429
- logger.log('ok', `Removed ${removed.length} stale entr${removed.length === 1 ? 'y' : 'ies'}:`);
793
+ logger.log(
794
+ "ok",
795
+ `Removed ${removed.length} stale entr${removed.length === 1 ? "y" : "ies"}:`,
796
+ );
430
797
  for (const path of removed) {
431
- logger.log('info', ` • ${path}`);
798
+ logger.log("info", ` • ${path}`);
432
799
  }
433
- }
800
+ }