feat(mod_services): Add global service registry and global commands for managing project containers

This commit is contained in:
2025-11-29 17:56:46 +00:00
parent ddf5023ecb
commit 847e679e92
7 changed files with 431 additions and 17 deletions

View File

@@ -1,15 +1,25 @@
import * as plugins from './mod.plugins.js';
import * as helpers from './helpers.js';
import { ServiceManager } from './classes.servicemanager.js';
import { GlobalRegistry } from './classes.globalregistry.js';
import { logger } from '../gitzone.logging.js';
export const run = async (argvArg: any) => {
const isGlobal = argvArg.g || argvArg.global;
const command = argvArg._[1] || 'help';
// Handle global commands first
if (isGlobal) {
await handleGlobalCommand(command);
return;
}
// Local project commands
const serviceManager = new ServiceManager();
await serviceManager.init();
const command = argvArg._[1] || 'help';
const service = argvArg._[2] || 'all';
switch (command) {
case 'start':
await handleStart(serviceManager, service);
@@ -249,4 +259,175 @@ function showHelp() {
logger.log('info', ' gitzone services config # Show configuration');
logger.log('info', ' gitzone services compass # Get MongoDB Compass connection');
logger.log('info', ' gitzone services logs elasticsearch # Show Elasticsearch logs');
console.log();
logger.log('note', 'Global Commands (-g/--global):');
logger.log('info', ' list -g List all registered projects');
logger.log('info', ' status -g Show status across all projects');
logger.log('info', ' stop -g Stop all containers across all projects');
logger.log('info', ' cleanup -g Remove stale registry entries');
console.log();
logger.log('note', 'Global Examples:');
logger.log('info', ' gitzone services list -g # List all registered projects');
logger.log('info', ' gitzone services status -g # Show global container status');
logger.log('info', ' gitzone services stop -g # Stop all (prompts for confirmation)');
}
// ==================== Global Command Handlers ====================
async function handleGlobalCommand(command: string) {
const globalRegistry = GlobalRegistry.getInstance();
switch (command) {
case 'list':
await handleGlobalList(globalRegistry);
break;
case 'status':
await handleGlobalStatus(globalRegistry);
break;
case 'stop':
await handleGlobalStop(globalRegistry);
break;
case 'cleanup':
await handleGlobalCleanup(globalRegistry);
break;
case 'help':
default:
showHelp();
break;
}
}
async function handleGlobalList(globalRegistry: GlobalRegistry) {
helpers.printHeader('Registered Projects (Global)');
const projects = await globalRegistry.getAllProjects();
const projectPaths = Object.keys(projects);
if (projectPaths.length === 0) {
logger.log('note', 'No projects registered');
return;
}
for (const path of projectPaths) {
const project = projects[path];
const lastActive = new Date(project.lastActive).toLocaleString();
console.log();
logger.log('ok', `📁 ${project.projectName}`);
logger.log('info', ` Path: ${project.projectPath}`);
logger.log('info', ` Services: ${project.enabledServices.join(', ')}`);
logger.log('info', ` Last Active: ${lastActive}`);
}
}
async function handleGlobalStatus(globalRegistry: GlobalRegistry) {
helpers.printHeader('Global Service Status');
const statuses = await globalRegistry.getGlobalStatus();
if (statuses.length === 0) {
logger.log('note', 'No projects registered');
return;
}
let runningCount = 0;
let totalContainers = 0;
for (const project of statuses) {
console.log();
logger.log('ok', `📁 ${project.projectName}`);
logger.log('info', ` Path: ${project.projectPath}`);
if (project.containers.length === 0) {
logger.log('note', ' No containers configured');
continue;
}
for (const container of project.containers) {
totalContainers++;
const statusIcon = container.status === 'running' ? '🟢' : container.status === 'exited' ? '🟡' : '⚪';
if (container.status === 'running') runningCount++;
logger.log('info', ` ${statusIcon} ${container.name}: ${container.status}`);
}
}
console.log();
logger.log('note', `Summary: ${runningCount}/${totalContainers} containers running across ${statuses.length} project(s)`);
}
async function handleGlobalStop(globalRegistry: GlobalRegistry) {
helpers.printHeader('Stop All Containers (Global)');
const statuses = await globalRegistry.getGlobalStatus();
// Count running containers
let runningCount = 0;
for (const project of statuses) {
for (const container of project.containers) {
if (container.status === 'running') runningCount++;
}
}
if (runningCount === 0) {
logger.log('note', 'No running containers found');
return;
}
logger.log('note', `Found ${runningCount} running container(s) across ${statuses.length} project(s)`);
console.log();
// Show what will be stopped
for (const project of statuses) {
const runningContainers = project.containers.filter(c => c.status === 'running');
if (runningContainers.length > 0) {
logger.log('info', `${project.projectName}:`);
for (const container of runningContainers) {
logger.log('info', `${container.name}`);
}
}
}
console.log();
const shouldContinue = await plugins.smartinteract.SmartInteract.getCliConfirmation(
'Stop all containers?',
false
);
if (!shouldContinue) {
logger.log('note', 'Cancelled');
return;
}
logger.log('note', 'Stopping all containers...');
const result = await globalRegistry.stopAll();
if (result.stopped.length > 0) {
logger.log('ok', `Stopped: ${result.stopped.join(', ')}`);
}
if (result.failed.length > 0) {
logger.log('error', `Failed to stop: ${result.failed.join(', ')}`);
}
}
async function handleGlobalCleanup(globalRegistry: GlobalRegistry) {
helpers.printHeader('Cleanup Registry (Global)');
logger.log('note', 'Checking for stale registry entries...');
const removed = await globalRegistry.cleanup();
if (removed.length === 0) {
logger.log('ok', 'No stale entries found');
return;
}
logger.log('ok', `Removed ${removed.length} stale entr${removed.length === 1 ? 'y' : 'ies'}:`);
for (const path of removed) {
logger.log('info', `${path}`);
}
}