// Nucleic in-container control bridge.
//
// Forwards loopback TCP -> the relayed host control socket. The agent's MCP client and the
// git/gh/command interceptor shims connect to 127.0.0.1:<port> (loopback, inside the VM's own
// network namespace — invisible to macOS, so no incoming-connection / local-network prompts); we
// pipe each connection to the unix socket the containerization framework relays in from the host
// approval server (`UnixSocketConfiguration(.into)`).
//
// Launched by the container's root init when (and only when) a control socket is relayed in
// (see ContainerEngine), so it can reach the root-owned relayed socket while the non-root agent
// only ever touches loopback TCP — no socket-permission juggling. It's a pure byte forwarder: the
// HTTP/JSON-RPC framing the host server speaks flows through untouched.
//
// Defaults MUST match the Swift side: ContainerSpec.controlBridgePort (9099) and
// ContainerSpec.controlSocketGuestPath (/run/nucleic/control.sock).

const net = require("net");

const PORT = Number(process.env.NUCLEIC_BRIDGE_PORT || 9099);
const SOCK = process.env.NUCLEIC_BRIDGE_SOCKET || "/run/nucleic/control.sock";

const server = net.createServer((client) => {
  // One upstream unix connection per inbound TCP connection. The host side of the relay is dialed
  // lazily here (on the agent's first connect), by which point the host server is listening.
  const upstream = net.connect(SOCK);

  const teardown = () => {
    client.destroy();
    upstream.destroy();
  };
  client.on("error", teardown);
  upstream.on("error", (err) => {
    // The relayed socket isn't reachable yet (host server not listening, or no relay) — drop this
    // connection; the client retries. Never crash the bridge over one failed connection.
    console.error("nucleic-bridge: upstream error", err && err.message);
    teardown();
  });

  client.pipe(upstream);
  upstream.pipe(client);
});

server.on("error", (err) => {
  // A listen failure is fatal for the control plane; exit so the failure is visible. The container
  // init backgrounds us, so this never takes the VM down — a fresh container brings a fresh bridge.
  console.error("nucleic-bridge: listen error", err && err.message);
  process.exit(1);
});

server.listen(PORT, "127.0.0.1", () => {
  console.error(`nucleic-bridge: 127.0.0.1:${PORT} -> ${SOCK}`);
});
