import { spawn } from "node:child_process"; import { createServer } from "node:http"; import { chmodSync, existsSync, lstatSync, mkdirSync, symlinkSync } from "node:fs"; import path from "node:path"; import { serveCloudWeb } from "/app/internal/dev-entrypoint/cloud-web-runtime.mjs"; const serviceId = process.env.HWLAB_SERVICE_ID || "hwlab-unknown"; const environment = process.env.HWLAB_ENVIRONMENT || "dev"; const runtimeKind = process.env.HWLAB_ARTIFACT_KIND || "health-placeholder"; const entrypoint = process.env.HWLAB_SERVICE_ENTRYPOINT || ""; const port = Number.parseInt(process.env.PORT || process.env.HWLAB_PORT || "8080", 10); function ensureCodeAgentRuntimeBase() { if (serviceId !== "hwlab-cloud-api") return; const workspace = process.env.HWLAB_CODE_AGENT_CODEX_WORKSPACE || process.env.HWLAB_CODE_AGENT_WORKSPACE || "/workspace/hwlab"; const codexHome = process.env.CODEX_HOME || process.env.HWLAB_CODE_AGENT_CODEX_HOME || "/codex-home"; process.env.HWLAB_CODE_AGENT_WORKSPACE = process.env.HWLAB_CODE_AGENT_WORKSPACE || workspace; process.env.HWLAB_CODE_AGENT_CODEX_WORKSPACE = process.env.HWLAB_CODE_AGENT_CODEX_WORKSPACE || workspace; process.env.HWLAB_CODE_AGENT_CODEX_SANDBOX = process.env.HWLAB_CODE_AGENT_CODEX_SANDBOX || "danger-full-access"; process.env.HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED = process.env.HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED || "1"; process.env.HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR = process.env.HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR || "repo-owned"; process.env.HWLAB_CODE_AGENT_PROVIDER = process.env.HWLAB_CODE_AGENT_PROVIDER || "codex-stdio"; process.env.CODEX_HOME = codexHome; process.env.HWLAB_CODE_AGENT_CODEX_COMMAND = process.env.HWLAB_CODE_AGENT_CODEX_COMMAND || "/app/node_modules/.bin/codex"; process.env.HWLAB_CODE_AGENT_SKILLS_DIRS = process.env.HWLAB_CODE_AGENT_SKILLS_DIRS || "/app/skills"; mkdirSync(path.dirname(workspace), { recursive: true }); if (!existsSync(workspace)) { if (workspace === "/workspace/hwlab" && existsSync("/app")) { symlinkSync("/app", workspace, "dir"); } else { mkdirSync(workspace, { recursive: true }); } } mkdirSync(codexHome, { recursive: true }); for (const target of [workspace, codexHome]) { try { const info = lstatSync(target); chmodSync(info.isSymbolicLink() ? path.resolve(target) : target, 0o777); } catch { // Runtime readiness reports the concrete blocker without exposing secret values. } } } ensureCodeAgentRuntimeBase(); function sendJson(response, statusCode, body) { const payload = JSON.stringify(body, null, 2); response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8", "content-length": Buffer.byteLength(payload) }); response.end(payload); } function healthPayload() { const commitId = process.env.HWLAB_COMMIT_ID || process.env.HWLAB_GIT_SHA || "unknown"; const imageReference = process.env.HWLAB_IMAGE || "unknown"; const imageTag = imageTagFromReference(imageReference) || shortRevision(commitId); const buildCreatedAt = normalizeIsoTimestamp( process.env.HWLAB_BUILD_CREATED_AT || process.env.HWLAB_IMAGE_CREATED_AT || process.env.SOURCE_DATE_EPOCH || process.env.BUILD_DATE ); const buildSource = process.env.HWLAB_BUILD_SOURCE || "runtime-env"; return { serviceId, environment, status: "ok", artifactKind: runtimeKind, revision: process.env.HWLAB_REVISION || commitId, commit: { id: commitId, source: buildSource }, image: { reference: imageReference, tag: imageTag, digest: process.env.HWLAB_IMAGE_DIGEST || "unknown" }, build: { createdAt: buildCreatedAt, source: buildSource, provenance: process.env.HWLAB_BUILD_PROVENANCE || null, metadataSource: buildCreatedAt ? "runtime-env:HWLAB_BUILD_CREATED_AT" : "unavailable", unavailableReason: buildCreatedAt ? null : "HWLAB_BUILD_CREATED_AT missing from runtime environment" } }; } function normalizeIsoTimestamp(value) { const source = String(value || "").trim(); if (!source) return null; if (/^\d+$/u.test(source)) { const seconds = Number.parseInt(source, 10); if (Number.isSafeInteger(seconds)) { const date = new Date(seconds * 1000); if (Number.isFinite(date.getTime())) return date.toISOString(); } } const date = new Date(source); return Number.isFinite(date.getTime()) ? date.toISOString() : null; } function imageTagFromReference(imageReference) { const source = String(imageReference || "").trim(); const slashIndex = source.lastIndexOf("/"); const colonIndex = source.lastIndexOf(":"); if (colonIndex <= slashIndex) return null; return source.slice(colonIndex + 1) || null; } function shortRevision(value) { const source = String(value || "").trim(); return source.length >= 7 ? source.slice(0, 7) : source || "unknown"; } function runEntrypoint(command, args) { const child = spawn(command, args, { cwd: "/app", env: process.env, stdio: "inherit" }); child.on("error", (error) => { process.stderr.write(JSON.stringify({ serviceId, status: "failed", error: "entrypoint_spawn_failed", command, reason: error.message }) + "\n"); process.exit(127); }); child.on("exit", (code, signal) => { if (signal) process.kill(process.pid, signal); else process.exit(code ?? 0); }); } function runNodeEntrypoint(file) { runEntrypoint(process.execPath, [file]); } function runBunEntrypoint(file) { const candidates = [ process.env.HWLAB_BUN_COMMAND, "/app/node_modules/.bin/bun", "/usr/local/bin/bun", "bun" ].filter(Boolean); const command = candidates.find((candidate) => !candidate.includes("/") || existsSync(candidate)) || "bun"; runEntrypoint(command, [file]); } function serveHealthOnly() { const server = createServer((request, response) => { const url = new URL(request.url || "/", "http://hwlab-artifact.local"); if (url.pathname === "/health/live" || url.pathname === "/health") { sendJson(response, 200, healthPayload()); return; } sendJson(response, 404, { error: "not_found", serviceId, path: url.pathname }); }); server.listen(port, "0.0.0.0", () => { process.stdout.write(JSON.stringify({ serviceId, environment, status: "listening", port }) + "\n"); }); } if (runtimeKind === "node-command" && entrypoint) { runNodeEntrypoint(entrypoint); } else if (runtimeKind === "bun-command" && entrypoint) { runBunEntrypoint(entrypoint); } else if (runtimeKind === "cloud-web") { await serveCloudWeb({ port, serviceId, healthPayload, sendJson }); } else { serveHealthOnly(); }