| import { spawn, ChildProcess, exec } from "child_process"; |
| import path from "path"; |
| import fs from "fs"; |
|
|
| const rootDir = __dirname; |
| const exocoreWebDir = path.join(rootDir, "exocore-web"); |
|
|
| process.env.FORCE_COLOR = "3"; |
|
|
| const ANSI = { |
| cyan: (s: string) => `\x1b[96m${s}\x1b[0m`, |
| yellow: (s: string) => `\x1b[93m${s}\x1b[0m`, |
| red: (s: string) => `\x1b[91m${s}\x1b[0m`, |
| green: (s: string) => `\x1b[92m${s}\x1b[0m`, |
| bold: (s: string) => `\x1b[1m${s}\x1b[0m`, |
| }; |
|
|
| const log = { |
| info: (msg: string) => console.log(ANSI.cyan("[INFO]"), msg), |
| warn: (msg: string) => console.log(ANSI.yellow("[WARN]"), msg), |
| error: (msg: string) => console.log(ANSI.red("[ERROR]"), msg), |
| success: (msg: string) => console.log(ANSI.green("[SUCCESS]"), msg), |
| }; |
|
|
| function printLogo(): void { |
| const lines = [ |
| " ███████╗██╗ ██╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗", |
| " ██╔════╝╚██╗██╔╝██╔═══██╗██╔════╝██╔═══██╗██╔══██╗██╔════╝", |
| " █████╗ ╚███╔╝ ██║ ██║██║ ██║ ██║██████╔╝█████╗ ", |
| " ██╔══╝ ██╔██╗ ██║ ██║██║ ██║ ██║██╔══██╗██╔══╝ ", |
| " ███████╗██╔╝ ██╗╚██████╔╝╚██████╗╚██████╔╝██║ ██║███████╗", |
| " ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝", |
| ]; |
| const colors = ["\x1b[96m", "\x1b[96m", "\x1b[36m", "\x1b[36m", "\x1b[32m", "\x1b[32m"]; |
| console.log(""); |
| lines.forEach((line, i) => console.log(`${colors[i]}${line}\x1b[0m`)); |
| console.log(""); |
| console.log(ANSI.bold(ANSI.green(" ⚡ EXOCORE 2026 — Full System Architecture"))); |
| console.log(""); |
| } |
|
|
| interface BinResult { |
| cmd: string; |
| args: string[]; |
| } |
|
|
| function resolveBin(name: string): BinResult { |
| const rootBin = path.join(rootDir, "node_modules", ".bin", name); |
| const webBin = path.join(exocoreWebDir, "node_modules", ".bin", name); |
| if (fs.existsSync(rootBin)) return { cmd: rootBin, args: [] }; |
| if (fs.existsSync(webBin)) return { cmd: webBin, args: [] }; |
| return { cmd: "npx", args: [name] }; |
| } |
|
|
| function runProcess(name: string, command: string, args: string[], options: any = {}): ChildProcess { |
| const mergedOptions = { stdio: "inherit" as const, shell: false, ...options }; |
| log.info(`[START] ${name}: ${command} ${args.join(" ")}`); |
| return spawn(command, args, mergedOptions); |
| } |
|
|
| function waitForProcess(child: ChildProcess): Promise<void> { |
| return new Promise((resolve, reject) => { |
| child.on("exit", (code) => { |
| if (code === 0) resolve(); |
| else reject(new Error(`Failed with exit code ${code}`)); |
| }); |
| child.on("error", (err) => reject(err)); |
| }); |
| } |
|
|
| function freePort(port: number): Promise<void> { |
| return new Promise((resolve) => { |
| exec(`fuser -k ${port}/tcp 2>/dev/null || true`, () => { |
| setTimeout(resolve, 500); |
| }); |
| }); |
| } |
|
|
| async function runTypeCheck(): Promise<void> { |
| const tsc = resolveBin("tsc"); |
|
|
| log.warn("Running standard TypeScript check..."); |
| const serverCheck = runProcess("TypeCheck", tsc.cmd, [ |
| ...tsc.args, |
| "-p", path.join(exocoreWebDir, "tsconfig.server.json"), |
| "--noEmit" |
| ], { cwd: exocoreWebDir }); |
|
|
| await waitForProcess(serverCheck); |
| log.success("TypeScript check passed!"); |
| } |
|
|
| async function runViteBuild(): Promise<void> { |
| const vite = resolveBin("vite"); |
|
|
| log.warn("Building web assets with Vite..."); |
| const buildProcess = runProcess("ViteBuild", vite.cmd, [ |
| ...vite.args, |
| "build" |
| ], { cwd: exocoreWebDir }); |
|
|
| await waitForProcess(buildProcess); |
| log.success("Vite build successful!"); |
| } |
|
|
| async function startServer(): Promise<ChildProcess> { |
| log.info("Launching Exocore server..."); |
| const tsx = resolveBin("tsx"); |
| return runProcess("Server", tsx.cmd, [...tsx.args, "index.ts"], { |
| cwd: exocoreWebDir, |
| }); |
| } |
|
|
| async function main(): Promise<void> { |
| try { |
| printLogo(); |
|
|
| const port = process.env.PORT ? parseInt(process.env.PORT) : 5000; |
| log.info(`Clearing network port ${port}...`); |
| await freePort(port); |
| await runTypeCheck(); |
| await runViteBuild(); |
| const server = await startServer(); |
| process.on("SIGINT", () => { |
| console.log(""); |
| log.warn("System shutdown requested."); |
| server.kill(); |
| process.exit(0); |
| }); |
|
|
| } catch (err) { |
| const error = err instanceof Error ? err : new Error(String(err)); |
| console.log(""); |
| log.error("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); |
| log.error(`STARTUP FAILED: ${error.message}`); |
| log.error("Please resolve the build errors above to continue."); |
| log.error("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); |
| process.exit(1); |
| } |
| } |
|
|
| main(); |
|
|