feat(M6): Set up orchestrator service foundation
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

Add NestJS-based orchestrator service structure for M6-AgentOrchestration.

Changes:
- Migrate from Express to NestJS architecture
- Add health check endpoint module
- Add placeholder modules: coordinator, git, killswitch, monitor, queue, spawner, valkey
- Update configuration for NestJS
- Update lockfile for new dependencies

This is foundational work for M6-AgentOrchestration milestone.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-02 13:16:19 -06:00
parent 9e06e977be
commit e808487725
21 changed files with 587 additions and 74 deletions

View File

@@ -0,0 +1,20 @@
import { Controller, Get } from "@nestjs/common";
@Controller("health")
export class HealthController {
@Get()
check() {
return {
status: "ok",
service: "orchestrator",
version: "0.0.6",
timestamp: new Date().toISOString(),
};
}
@Get("ready")
ready() {
// TODO: Check Valkey connection, Docker daemon
return { ready: true };
}
}

View File

@@ -0,0 +1,7 @@
import { Module } from "@nestjs/common";
import { HealthController } from "./health.controller";
@Module({
controllers: [HealthController],
})
export class HealthModule {}

View File

@@ -1,17 +0,0 @@
import { FastifyPluginAsync } from 'fastify';
export const healthRoutes: FastifyPluginAsync = async (fastify) => {
fastify.get('/health', async () => {
return {
status: 'ok',
service: 'orchestrator',
version: '0.0.6',
timestamp: new Date().toISOString()
};
});
fastify.get('/health/ready', async () => {
// TODO: Check Valkey connection, Docker daemon
return { ready: true };
});
};

View File

@@ -1,13 +0,0 @@
import Fastify from 'fastify';
import { healthRoutes } from './routes/health.routes.js';
export async function createServer() {
const fastify = Fastify({
logger: true,
});
// Health check routes
await fastify.register(healthRoutes);
return fastify;
}

View File

@@ -0,0 +1,22 @@
import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { BullModule } from "@nestjs/bullmq";
import { HealthModule } from "./api/health/health.module";
import { orchestratorConfig } from "./config/orchestrator.config";
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [orchestratorConfig],
}),
BullModule.forRoot({
connection: {
host: process.env.VALKEY_HOST ?? "localhost",
port: parseInt(process.env.VALKEY_PORT ?? "6379"),
},
}),
HealthModule,
],
})
export class AppModule {}

View File

@@ -0,0 +1,26 @@
import { registerAs } from "@nestjs/config";
export const orchestratorConfig = registerAs("orchestrator", () => ({
port: parseInt(process.env.ORCHESTRATOR_PORT ?? "3001", 10),
valkey: {
host: process.env.VALKEY_HOST ?? "localhost",
port: parseInt(process.env.VALKEY_PORT ?? "6379", 10),
url: process.env.VALKEY_URL ?? "redis://localhost:6379",
},
claude: {
apiKey: process.env.CLAUDE_API_KEY,
},
docker: {
socketPath: process.env.DOCKER_SOCKET ?? "/var/run/docker.sock",
},
git: {
userName: process.env.GIT_USER_NAME ?? "Mosaic Orchestrator",
userEmail: process.env.GIT_USER_EMAIL ?? "orchestrator@mosaicstack.dev",
},
killswitch: {
enabled: process.env.KILLSWITCH_ENABLED === "true",
},
sandbox: {
enabled: process.env.SANDBOX_ENABLED === "true",
},
}));

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class CoordinatorModule {}

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class GitModule {}

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class KillswitchModule {}

View File

@@ -1,28 +1,19 @@
/**
* Mosaic Orchestrator - Agent Orchestration Service
*
* Execution plane for Mosaic Stack agent coordination.
* Spawns, monitors, and manages Claude agents for autonomous work.
*/
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { Logger } from "@nestjs/common";
import { createServer } from './api/server.js';
const PORT = process.env.ORCHESTRATOR_PORT || 3001;
const logger = new Logger("Orchestrator");
async function bootstrap() {
console.log('🚀 Starting Mosaic Orchestrator...');
const server = await createServer();
await server.listen({
port: Number(PORT),
host: '0.0.0.0'
const app = await NestFactory.create(AppModule, {
logger: ["error", "warn", "log", "debug", "verbose"],
});
console.log(`✅ Orchestrator running on http://0.0.0.0:${PORT}`);
const port = process.env.ORCHESTRATOR_PORT ?? 3001;
await app.listen(Number(port), "0.0.0.0");
logger.log(`🚀 Orchestrator running on http://0.0.0.0:${String(port)}`);
}
bootstrap().catch((error) => {
console.error('Failed to start orchestrator:', error);
process.exit(1);
});
void bootstrap();

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class MonitorModule {}

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class QueueModule {}

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class SpawnerModule {}

View File

@@ -0,0 +1,4 @@
import { Module } from "@nestjs/common";
@Module({})
export class ValkeyModule {}