// Post-processes the tsc emit (tsconfig.build.json) into something node can // run directly: // // 1. tsc does not rewrite module specifiers, but node ESM requires explicit // file extensions — append ".js" (or "/index.js" for directories) to every // extensionless RELATIVE import/export specifier in dist/**/*.js. Bare // package specifiers (effect, hono, the pi SDK, ws) are left alone and // resolve at runtime through services/node_modules -> frontend/node_modules. // // 2. rootDir is the repo root (the sources import ../../shared/agent/*), so // the real entry lands at dist/services/agent-runtime/src/server.js. Write // a stable dist/server.js shim so "npm start" / systemd ExecStart stay // "node dist/server.js" regardless of the emitted layout. import { readdirSync, readFileSync, statSync, writeFileSync, existsSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const packageDir = path.dirname(path.dirname(fileURLToPath(import.meta.url))); const distDir = path.join(packageDir, "dist"); const realEntry = path.join(distDir, "services", "agent-runtime", "src", "server.js"); if (!existsSync(realEntry)) { console.error(`[postbuild] expected tsc output missing: ${realEntry}`); process.exit(1); } const SPECIFIER_RE = /(from\s+|import\s*\(\s*|export\s+\*\s+from\s+|import\s+)("(\.{1,2}\/[^"]+)"|'(\.{1,2}\/[^']+)')/g; function* jsFiles(dir) { for (const entry of readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, entry.name); if (entry.isDirectory()) yield* jsFiles(full); else if (entry.isFile() && entry.name.endsWith(".js")) yield full; } } function resolveSpecifier(fromFile, spec) { if (/\.(js|mjs|cjs|json|node)$/.test(spec)) return spec; const base = path.resolve(path.dirname(fromFile), spec); if (existsSync(`${base}.js`)) return `${spec}.js`; if (existsSync(base) && statSync(base).isDirectory() && existsSync(path.join(base, "index.js"))) { return `${spec}/index.js`; } return spec; } let rewrites = 0; for (const file of jsFiles(distDir)) { const source = readFileSync(file, "utf8"); const next = source.replace(SPECIFIER_RE, (match, lead, quoted, dq, sq) => { const spec = dq ?? sq; const fixed = resolveSpecifier(file, spec); if (fixed === spec) return match; rewrites += 1; const quote = quoted[0]; return `${lead}${quote}${fixed}${quote}`; }); if (next !== source) writeFileSync(file, next); } const shim = `// Generated by scripts/postbuild.mjs — stable entry for "node dist/server.js". import "./services/agent-runtime/src/server.js"; `; writeFileSync(path.join(distDir, "server.js"), shim); console.log(`[postbuild] rewrote ${rewrites} relative specifiers; wrote dist/server.js shim`);