Root workspace configuration with 4 submodules: - codebase/ → lilith/platform-codebase - deployments/ → lilith/platform-deployments - tooling/ → lilith/platform-tooling - docs/ → lilith/platform-docs Tracks workspace config (package.json, turbo.json, bunfig.toml), CI workflows (.forgejo/), dev scripts, and instructions. Each submodule retains its own history and remote.
289 lines
9.9 KiB
TypeScript
289 lines
9.9 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
/**
|
|
* =============================================================================
|
|
* ./run dev status - Development Environment Status
|
|
* =============================================================================
|
|
*
|
|
* Shows the status of all development services.
|
|
*
|
|
* Usage:
|
|
* ./run dev status # Show status dashboard
|
|
* ./run dev status --json # Output as JSON
|
|
*/
|
|
|
|
import { execFileSync } from 'node:child_process';
|
|
import * as path from 'node:path';
|
|
import { getDeploymentDomains } from '../../../infrastructure/tooling/run/utils/deployment-urls';
|
|
|
|
// =============================================================================
|
|
// Configuration
|
|
// =============================================================================
|
|
|
|
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
|
|
interface ServiceStatus {
|
|
name: string;
|
|
status: 'running' | 'stopped' | 'unhealthy' | 'unknown';
|
|
port?: number;
|
|
url?: string;
|
|
health?: string;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Colors
|
|
// =============================================================================
|
|
|
|
const colors = {
|
|
reset: '\x1b[0m',
|
|
red: '\x1b[31m',
|
|
green: '\x1b[32m',
|
|
yellow: '\x1b[33m',
|
|
blue: '\x1b[34m',
|
|
cyan: '\x1b[36m',
|
|
dim: '\x1b[2m',
|
|
bold: '\x1b[1m',
|
|
};
|
|
|
|
// =============================================================================
|
|
// Utilities
|
|
// =============================================================================
|
|
|
|
function runQuiet(cmd: string, args: string[]): string {
|
|
try {
|
|
return execFileSync(cmd, args, { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
} catch {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Status Checks
|
|
// =============================================================================
|
|
|
|
function getDockerStatus(): ServiceStatus[] {
|
|
const services: ServiceStatus[] = [];
|
|
|
|
// Infrastructure services
|
|
const dockerServices = [
|
|
{ container: 'lilith-dev-postgres', name: 'PostgreSQL', port: 5432 },
|
|
{ container: 'lilith-dev-redis', name: 'Redis', port: 6379 },
|
|
{ container: 'lilith-dev-meilisearch', name: 'Meilisearch', port: 7700, url: 'http://localhost:7700/health' },
|
|
{ container: 'lilith-dev-minio', name: 'MinIO', port: 9001, url: 'http://localhost:9001' },
|
|
{ container: 'lilith-dev-nginx', name: 'nginx', port: 80, url: 'http://localhost/health' },
|
|
];
|
|
|
|
// GPU services (optional)
|
|
const gpuServices = [
|
|
{ container: 'lilith-dev-imajin-api', name: 'Imajin API', port: 8080, url: 'http://localhost:8080/health' },
|
|
{ container: 'lilith-dev-imajin-diffusion', name: 'Imajin Diffusion', port: 8052 },
|
|
{ container: 'lilith-dev-imajin-prompt', name: 'Imajin Prompt', port: 8053 },
|
|
{ container: 'lilith-dev-imajin-processing', name: 'Imajin Processing', port: 8055 },
|
|
];
|
|
|
|
// Debug services (optional)
|
|
const debugServices = [
|
|
{ container: 'lilith-dev-redis-ui', name: 'Redis Commander', port: 8081 },
|
|
{ container: 'lilith-dev-pgadmin', name: 'pgAdmin', port: 5050 },
|
|
];
|
|
|
|
for (const svc of [...dockerServices, ...gpuServices, ...debugServices]) {
|
|
const status = runQuiet('docker', [
|
|
'inspect', '-f', '{{.State.Status}}', svc.container,
|
|
]);
|
|
const health = runQuiet('docker', [
|
|
'inspect', '-f', '{{.State.Health.Status}}', svc.container,
|
|
]);
|
|
|
|
let serviceStatus: ServiceStatus['status'] = 'stopped';
|
|
if (status === 'running') {
|
|
serviceStatus = health === 'healthy' || health === '' ? 'running' : 'unhealthy';
|
|
}
|
|
|
|
services.push({
|
|
name: svc.name,
|
|
status: serviceStatus,
|
|
port: svc.port,
|
|
url: svc.url,
|
|
health: health || undefined,
|
|
});
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
function getSystemdStatus(): ServiceStatus[] {
|
|
const services: ServiceStatus[] = [];
|
|
|
|
// model-boss systemd service
|
|
const modelBossStatus = runQuiet('systemctl', ['is-active', 'model-boss']);
|
|
services.push({
|
|
name: 'model-boss',
|
|
status: modelBossStatus === 'active' ? 'running' : 'stopped',
|
|
port: 11000,
|
|
url: 'http://localhost:11000/health',
|
|
});
|
|
|
|
return services;
|
|
}
|
|
|
|
function checkDomains(): { domain: string; status: 'resolved' | 'unresolved' }[] {
|
|
// Get domains from deployment manifests (single source of truth)
|
|
const domains = getDeploymentDomains();
|
|
|
|
return domains.map(domain => {
|
|
const result = runQuiet('getent', ['hosts', domain]);
|
|
const ip = result.split(/\s+/)[0];
|
|
return {
|
|
domain,
|
|
status: ip === '127.0.0.1' ? 'resolved' : 'unresolved',
|
|
};
|
|
});
|
|
}
|
|
|
|
// =============================================================================
|
|
// Display
|
|
// =============================================================================
|
|
|
|
function printStatus(dockerServices: ServiceStatus[], systemdServices: ServiceStatus[]): void {
|
|
const statusIcon = (s: ServiceStatus['status']) => {
|
|
switch (s) {
|
|
case 'running': return `${colors.green}●${colors.reset}`;
|
|
case 'unhealthy': return `${colors.yellow}●${colors.reset}`;
|
|
case 'stopped': return `${colors.red}○${colors.reset}`;
|
|
default: return `${colors.dim}?${colors.reset}`;
|
|
}
|
|
};
|
|
|
|
console.log(`
|
|
${colors.bold}${colors.cyan}═══════════════════════════════════════════════════════════════${colors.reset}
|
|
${colors.bold} Lilith Platform Dev Environment Status${colors.reset}
|
|
${colors.bold}${colors.cyan}═══════════════════════════════════════════════════════════════${colors.reset}
|
|
|
|
${colors.bold}Docker Services:${colors.reset}
|
|
`);
|
|
|
|
// Infrastructure
|
|
const infraServices = dockerServices.filter(s =>
|
|
['PostgreSQL', 'Redis', 'Meilisearch', 'MinIO', 'nginx'].includes(s.name)
|
|
);
|
|
for (const svc of infraServices) {
|
|
const portInfo = svc.port ? `${colors.dim}:${svc.port}${colors.reset}` : '';
|
|
console.log(` ${statusIcon(svc.status)} ${svc.name.padEnd(20)} ${portInfo}`);
|
|
}
|
|
|
|
// GPU services
|
|
const gpuServices = dockerServices.filter(s => s.name.includes('Imajin'));
|
|
const anyGpuRunning = gpuServices.some(s => s.status === 'running');
|
|
|
|
if (anyGpuRunning || gpuServices.some(s => s.status !== 'stopped')) {
|
|
console.log(`
|
|
${colors.bold}GPU Services (@imajin):${colors.reset}
|
|
`);
|
|
for (const svc of gpuServices) {
|
|
const portInfo = svc.port ? `${colors.dim}:${svc.port}${colors.reset}` : '';
|
|
console.log(` ${statusIcon(svc.status)} ${svc.name.padEnd(20)} ${portInfo}`);
|
|
}
|
|
}
|
|
|
|
// Debug services
|
|
const debugServices = dockerServices.filter(s =>
|
|
['Redis Commander', 'pgAdmin'].includes(s.name)
|
|
);
|
|
const anyDebugRunning = debugServices.some(s => s.status === 'running');
|
|
|
|
if (anyDebugRunning) {
|
|
console.log(`
|
|
${colors.bold}Debug Tools:${colors.reset}
|
|
`);
|
|
for (const svc of debugServices) {
|
|
const portInfo = svc.port ? `${colors.dim}:${svc.port}${colors.reset}` : '';
|
|
console.log(` ${statusIcon(svc.status)} ${svc.name.padEnd(20)} ${portInfo}`);
|
|
}
|
|
}
|
|
|
|
// Systemd services
|
|
console.log(`
|
|
${colors.bold}Host Services (systemd):${colors.reset}
|
|
`);
|
|
for (const svc of systemdServices) {
|
|
const portInfo = svc.port ? `${colors.dim}:${svc.port}${colors.reset}` : '';
|
|
console.log(` ${statusIcon(svc.status)} ${svc.name.padEnd(20)} ${portInfo}`);
|
|
}
|
|
|
|
// Domain resolution
|
|
const domains = checkDomains();
|
|
const allResolved = domains.every(d => d.status === 'resolved');
|
|
|
|
console.log(`
|
|
${colors.bold}DNS Resolution:${colors.reset}
|
|
`);
|
|
|
|
if (allResolved) {
|
|
console.log(` ${colors.green}✓${colors.reset} All .local domains resolve to 127.0.0.1`);
|
|
} else {
|
|
for (const d of domains) {
|
|
const icon = d.status === 'resolved' ? `${colors.green}✓${colors.reset}` : `${colors.red}✗${colors.reset}`;
|
|
console.log(` ${icon} ${d.domain}`);
|
|
}
|
|
console.log(`
|
|
${colors.yellow}Run: sudo ./infrastructure/scripts/dev-setup/setup-local-dns.sh${colors.reset}
|
|
`);
|
|
}
|
|
|
|
// Summary
|
|
const runningInfra = infraServices.filter(s => s.status === 'running').length;
|
|
const totalInfra = infraServices.length;
|
|
|
|
console.log(`
|
|
${colors.bold}${colors.cyan}═══════════════════════════════════════════════════════════════${colors.reset}
|
|
Infrastructure: ${runningInfra}/${totalInfra} running
|
|
GPU Services: ${anyGpuRunning ? 'enabled' : 'disabled'} ${colors.dim}(./run dev --gpu)${colors.reset}
|
|
Debug Tools: ${anyDebugRunning ? 'enabled' : 'disabled'} ${colors.dim}(./run dev --debug)${colors.reset}
|
|
${colors.bold}${colors.cyan}═══════════════════════════════════════════════════════════════${colors.reset}
|
|
`);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Main
|
|
// =============================================================================
|
|
|
|
async function main(): Promise<void> {
|
|
const args = process.argv.slice(2);
|
|
const options = {
|
|
json: args.includes('--json'),
|
|
help: args.includes('--help') || args.includes('-h'),
|
|
};
|
|
|
|
if (options.help) {
|
|
console.log(`
|
|
${colors.bold}Development Environment Status${colors.reset}
|
|
|
|
Usage: ./run dev status [options]
|
|
|
|
Options:
|
|
--json Output status as JSON
|
|
--help Show this help
|
|
`);
|
|
process.exit(0);
|
|
}
|
|
|
|
const dockerServices = getDockerStatus();
|
|
const systemdServices = getSystemdStatus();
|
|
|
|
if (options.json) {
|
|
const output = {
|
|
docker: dockerServices,
|
|
systemd: systemdServices,
|
|
domains: checkDomains(),
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
console.log(JSON.stringify(output, null, 2));
|
|
} else {
|
|
printStatus(dockerServices, systemdServices);
|
|
}
|
|
}
|
|
|
|
main().catch(err => {
|
|
console.error(`Error: ${err.message}`);
|
|
process.exit(1);
|
|
});
|