/** * createRuntime - Bootstrap the full AirCoding runtime * DD §22.2. Wires all subsystems via ServiceRegistry. * * @module packages/cli/src/bootstrap/createRuntime */ import { readFileSync, existsSync } from 'fs' import { join } from 'path' import { RuntimeApp, ProjectionClient } from '@aircoding/runtime' import type { AirConfig } from './loadConfig.js' export interface BootResult { app: RuntimeApp projection_client: ProjectionClient start: () => Promise shutdown: () => Promise } /** * Load project_id from .air/shared/project.json (DD §6.1 stable UUID). * Falls back to generated UUID if project is not initialized. */ function load_project_id(project_root: string): string { const project_json = join(project_root, '.air', 'shared', 'project.json') if (existsSync(project_json)) { try { const parsed = JSON.parse(readFileSync(project_json, 'utf-8')) if (parsed.project_id) return parsed.project_id } catch { /* fall through to fallback */ } } // Fallback: generate if project not yet initialized return `proj_${Date.now().toString(36)}` } /** * Create and start the AirCoding runtime. */ export async function createRuntime(config: AirConfig): Promise { const project_root = config.project_root || process.cwd() // Load stable project_id from .air/shared/project.json const session_id = `session_${Date.now()}` const project_id = load_project_id(project_root) const app = new RuntimeApp({ project_root, session_id, project_id, log_dir: `${project_root}/.air/logs` }) return { app, projection_client: app.projection_client, start: () => app.start(), shutdown: () => app.shutdown() } }