MCPcopy Create free account
hub / github.com/Kilo-Org/cloud / startController

Function startController

services/kiloclaw/controller/src/index.ts:204–656  ·  view source on GitHub ↗
(env: NodeJS.ProcessEnv = process.env)

Source from the content-addressed store, hash-verified

202 return JSON.stringify({ status: 'ok', state: state.state });
203}
204
205export async function startController(env: NodeJS.ProcessEnv = process.env): Promise<void> {
206 // Mutable state ref — read by the health endpoint on every request,
207 // updated by bootstrap as it progresses through phases.
208 const controllerState: ControllerStateRef = {
209 current: { state: 'bootstrapping', phase: 'init' },
210 };
211
212 // ── Phase 1: Start HTTP server ──────────────────────────────────────
213 // The server starts FIRST so /_kilo/health is always reachable, even
214 // during bootstrap. During bootstrap, a lightweight inline handler
215 // serves health probes directly. After bootstrap, the Hono app with
216 // full routes takes over.
217 let app: Hono | null = null;
218
219 const server = http.createServer((req, res) => {
220 // Once bootstrap has completed and the Hono app is ready, delegate all requests.
221 if (app) {
222 void handleHttpRequest(app, req, res).catch(error => {
223 console.error('[controller] HTTP handler failed:', error);
224 res.statusCode = 500;
225 res.setHeader('content-type', 'application/json');
226 res.end(JSON.stringify({ error: 'Internal Server Error' }));
227 });
228 return;
229 }
230
231 // Pre-bootstrap: serve health probes inline without Hono.
232 // Strip query string so e.g. /_kilo/health?ts=123 still matches.
233 const pathname = (req.url ?? '/').split('?')[0];
234 if (pathname === '/_kilo/health' || pathname === '/health') {
235 res.statusCode = 200;
236 res.setHeader('content-type', 'application/json');
237 if (pathname === '/health') {
238 // Bare /health for Fly probes — no state details
239 res.end(JSON.stringify({ status: 'ok' }));
240 } else {
241 res.end(healthJson(controllerState.current));
242 }
243 return;
244 }
245
246 // All other routes: 503 during bootstrap
247 res.statusCode = 503;
248 res.setHeader('content-type', 'application/json');
249 res.end(JSON.stringify({ error: 'Service starting', state: controllerState.current.state }));
250 });
251
252 // Mutable ref for the WebSocket upgrade handler. Set once the Hono app and
253 // supervisor are ready. Registered on the server early so connections during
254 // bootstrap or degraded mode get a clean 503 rejection instead of hanging.
255 const wsUpgradeRef: {
256 handler: ((req: http.IncomingMessage, socket: Duplex, head: Buffer) => void) | null;
257 } = { handler: null };
258
259 server.on('upgrade', (req, socket, head) => {
260 if (wsUpgradeRef.handler) {
261 wsUpgradeRef.handler(req, socket, head);

Callers 2

index.tsFile · 0.85

Tested by

no test coverage detected