#!/usr/bin/env node
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res) => function __init() {
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// src/server/orbit/adapters/git-worktree.ts
function currentHeadRef(cwd) {
  try {
    return (0, import_node_child_process.execFileSync)("git", ["rev-parse", "HEAD"], {
      cwd,
      encoding: "utf-8"
    }).trim();
  } catch {
    return "HEAD";
  }
}
function isGitWorktreeTracked(path, projectRoot) {
  try {
    const out = (0, import_node_child_process.execFileSync)("git", ["worktree", "list", "--porcelain"], {
      cwd: projectRoot,
      encoding: "utf-8",
      stdio: ["ignore", "pipe", "ignore"]
    });
    return out.split("\n").some((line) => line === `worktree ${path}`);
  } catch {
    return false;
  }
}
var import_node_child_process, import_node_fs, import_node_path, gitWorktreeAdapter;
var init_git_worktree = __esm({
  "src/server/orbit/adapters/git-worktree.ts"() {
    "use strict";
    import_node_child_process = require("node:child_process");
    import_node_fs = require("node:fs");
    import_node_path = require("node:path");
    gitWorktreeAdapter = {
      id: "builtin/git-worktree",
      async detect(ctx) {
        try {
          (0, import_node_child_process.execFileSync)("git", ["rev-parse", "--show-toplevel"], {
            cwd: ctx.projectRoot,
            stdio: "ignore"
          });
          return { ok: true };
        } catch {
          return { ok: false, reason: "git not available or projectRoot is not inside a git repo" };
        }
      },
      async create(input) {
        const { slug, branch, baseRef, config, ctx } = input;
        const basePath = config.basePath ?? ".claude/worktrees";
        const pattern = config.namingPattern ?? "{slug}";
        const dirName = pattern.replace(/\{slug\}/g, slug);
        const absBase = (0, import_node_path.isAbsolute)(basePath) ? basePath : (0, import_node_path.join)(ctx.projectRoot, basePath);
        const targetPath = (0, import_node_path.join)(absBase, dirName);
        if ((0, import_node_fs.existsSync)(targetPath)) {
          throw new Error(`worktree path already exists: ${targetPath}`);
        }
        const effectiveBase = baseRef ?? config.baseRef ?? currentHeadRef(ctx.projectRoot);
        const args = ["worktree", "add", targetPath, "-b", branch, effectiveBase];
        try {
          (0, import_node_child_process.execFileSync)("git", args, { cwd: ctx.projectRoot, stdio: ["ignore", "pipe", "pipe"] });
        } catch (e) {
          throw new Error(`git worktree add failed: ${e.message}`);
        }
        return {
          adapter: "builtin/git-worktree",
          path: targetPath,
          branch
        };
      },
      async remove(input) {
        const { state, force, ctx } = input;
        if (!isGitWorktreeTracked(state.path, ctx.projectRoot)) {
          return;
        }
        const args = ["worktree", "remove", state.path];
        if (force) args.push("--force");
        try {
          (0, import_node_child_process.execFileSync)("git", args, { cwd: ctx.projectRoot, stdio: ["ignore", "pipe", "pipe"] });
        } catch (e) {
          throw new Error(`git worktree remove failed: ${e.message}`);
        }
        try {
          (0, import_node_child_process.execFileSync)("git", ["branch", "-D", state.branch], {
            cwd: ctx.projectRoot,
            stdio: "ignore"
          });
        } catch {
        }
      }
    };
  }
});

// src/server/orbit/adapters/claude-code.ts
var import_node_fs2, claudeCodeAdapter;
var init_claude_code = __esm({
  "src/server/orbit/adapters/claude-code.ts"() {
    "use strict";
    import_node_fs2 = require("node:fs");
    claudeCodeAdapter = {
      id: "builtin/claude-code",
      async detect() {
        return { ok: true };
      },
      async create(input) {
        const { branch, config } = input;
        const path = config.existingPath;
        if (!path) {
          throw new Error(
            "builtin/claude-code adapter cannot create a worktree \u2014 it only registers paths supplied by Claude Code's WorktreeCreate hook payload. Use builtin/git-worktree for normal creation."
          );
        }
        if (!(0, import_node_fs2.existsSync)(path)) {
          throw new Error(`existingPath does not exist: ${path}`);
        }
        return { adapter: "builtin/claude-code", path, branch };
      },
      async remove(_input) {
      }
    };
  }
});

// src/server/launch-kit-paths.ts
var LAUNCHSECURE_DIR;
var init_launch_kit_paths = __esm({
  "src/server/launch-kit-paths.ts"() {
    "use strict";
    LAUNCHSECURE_DIR = ".launchsecure";
  }
});

// src/server/orbit/registry.ts
function emptyRegistry() {
  return { version: 1, worktrees: {} };
}
function ensureDir() {
  (0, import_node_fs3.mkdirSync)(REGISTRY_DIR, { recursive: true });
}
function readRegistry() {
  if (!(0, import_node_fs3.existsSync)(REGISTRY_PATH)) return emptyRegistry();
  try {
    const parsed = JSON.parse((0, import_node_fs3.readFileSync)(REGISTRY_PATH, "utf-8"));
    if (parsed?.version === 1 && parsed.worktrees && typeof parsed.worktrees === "object") {
      return parsed;
    }
  } catch {
  }
  return emptyRegistry();
}
function tryAcquireLock() {
  ensureDir();
  if ((0, import_node_fs3.existsSync)(LOCK_PATH)) {
    try {
      const age = Date.now() - (0, import_node_fs3.statSync)(LOCK_PATH).mtimeMs;
      if (age > STALE_LOCK_MS) {
        try {
          (0, import_node_fs3.rmdirSync)(LOCK_PATH);
        } catch {
        }
      }
    } catch {
    }
  }
  try {
    (0, import_node_fs3.mkdirSync)(LOCK_PATH);
    return true;
  } catch {
    return false;
  }
}
function releaseLock() {
  try {
    (0, import_node_fs3.rmdirSync)(LOCK_PATH);
  } catch {
  }
}
async function withLock(fn) {
  const start = Date.now();
  while (!tryAcquireLock()) {
    if (Date.now() - start > 3e4) {
      throw new Error(`could not acquire orbit registry lock at ${LOCK_PATH}`);
    }
    await new Promise((r) => setTimeout(r, 100));
  }
  try {
    return await fn();
  } finally {
    releaseLock();
  }
}
function writeRegistryAtomic(reg) {
  ensureDir();
  const tmp = `${REGISTRY_PATH}.tmp.${process.pid}`;
  (0, import_node_fs3.writeFileSync)(tmp, JSON.stringify(reg, null, 2) + "\n", "utf-8");
  (0, import_node_fs3.renameSync)(tmp, REGISTRY_PATH);
}
async function mutateRegistry(fn) {
  return withLock(() => {
    const current = readRegistry();
    const { next, result } = fn(current);
    writeRegistryAtomic(next);
    return result;
  });
}
async function registerWorktree(entry) {
  await mutateRegistry((reg) => {
    if (reg.worktrees[entry.slug]) {
      throw new Error(`worktree slug "${entry.slug}" already registered at ${reg.worktrees[entry.slug].path}`);
    }
    reg.worktrees[entry.slug] = entry;
    return { next: reg, result: void 0 };
  });
}
async function deregisterWorktree(slug) {
  return mutateRegistry((reg) => {
    const entry = reg.worktrees[slug] ?? null;
    if (entry) delete reg.worktrees[slug];
    return { next: reg, result: entry };
  });
}
function lookupWorktree(slug) {
  return readRegistry().worktrees[slug] ?? null;
}
function listWorktrees() {
  return Object.values(readRegistry().worktrees);
}
var import_node_fs3, import_node_os, import_node_path2, REGISTRY_DIR, REGISTRY_PATH, LOCK_PATH, STALE_LOCK_MS;
var init_registry = __esm({
  "src/server/orbit/registry.ts"() {
    "use strict";
    import_node_fs3 = require("node:fs");
    import_node_os = require("node:os");
    import_node_path2 = require("node:path");
    init_launch_kit_paths();
    REGISTRY_DIR = (0, import_node_path2.join)((0, import_node_os.homedir)(), LAUNCHSECURE_DIR, "orbit");
    REGISTRY_PATH = (0, import_node_path2.join)(REGISTRY_DIR, "state.json");
    LOCK_PATH = (0, import_node_path2.join)(REGISTRY_DIR, "state.json.lock");
    STALE_LOCK_MS = 6e4;
  }
});

// src/server/orbit/adapters/port-range.ts
function collectAllocatedBases() {
  const out = /* @__PURE__ */ new Set();
  for (const entry of listWorktrees()) {
    for (const r of Object.values(entry.resources)) {
      if (r.adapter !== "builtin/port-range") continue;
      const state = r.state;
      if (state && typeof state.base === "number") out.add(state.base);
    }
  }
  return out;
}
function isPortInUse(port) {
  try {
    const out = (0, import_node_child_process2.execFileSync)("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"], {
      encoding: "utf-8",
      stdio: ["ignore", "pipe", "ignore"],
      timeout: 500
    }).trim();
    return out.length > 0;
  } catch {
    return false;
  }
}
var import_node_child_process2, portRangeAdapter;
var init_port_range = __esm({
  "src/server/orbit/adapters/port-range.ts"() {
    "use strict";
    import_node_child_process2 = require("node:child_process");
    init_registry();
    portRangeAdapter = {
      id: "builtin/port-range",
      async detect() {
        return { ok: true };
      },
      async fork(input) {
        const { config, ctx } = input;
        const base = config.base ?? 3e3;
        const stride = config.stride ?? 10;
        const max = config.max ?? 100;
        if (!config.rewrite || !Array.isArray(config.rewrite.env) || typeof config.rewrite.replace !== "string") {
          throw new Error("port-range: config.rewrite.env (string[]) and config.rewrite.replace (string) are required");
        }
        const allocated = collectAllocatedBases();
        allocated.add(base);
        let chosen = null;
        for (let i = 1; i <= max; i++) {
          const candidate = base + i * stride;
          if (allocated.has(candidate)) continue;
          if (isPortInUse(candidate)) {
            ctx.logger.warn(`port ${candidate} is bound by another process \u2014 skipping`);
            continue;
          }
          chosen = candidate;
          break;
        }
        if (chosen === null) {
          throw new Error(`port-range: no free decade between ${base + stride} and ${base + max * stride}`);
        }
        return {
          base: chosen,
          stride,
          replace: config.rewrite.replace,
          envKeys: config.rewrite.env
        };
      },
      async drop(_input) {
        return {};
      },
      envRewrites(state) {
        const map = {};
        const fromPort = state.replace;
        const toPort = `:${state.base}`;
        for (const key of state.envKeys) {
          map[key] = (oldValue) => {
            if (typeof oldValue !== "string") return void 0;
            if (!oldValue.includes(fromPort)) return void 0;
            return oldValue.split(fromPort).join(toPort);
          };
        }
        return map;
      }
    };
  }
});

// src/server/orbit/pg-detect.ts
function resolvePgClient(versionHint) {
  const reasons = [];
  const dumpOnPath = which("pg_dump");
  const psqlOnPath = which("psql");
  if (dumpOnPath && psqlOnPath) {
    return { kind: "binary", pgDump: dumpOnPath, psql: psqlOnPath, version: probeVersion(dumpOnPath) };
  }
  if (dumpOnPath || psqlOnPath) {
    reasons.push(`PATH has only ${dumpOnPath ? "pg_dump" : "psql"} \u2014 need both`);
  } else {
    reasons.push("pg_dump + psql not on PATH");
  }
  const pgApp = findPostgresApp(versionHint);
  if (pgApp) return { kind: "binary", pgDump: pgApp.pgDump, psql: pgApp.psql, version: pgApp.version };
  reasons.push("no Postgres.app installation found");
  const brew = findHomebrew(versionHint);
  if (brew) return { kind: "binary", pgDump: brew.pgDump, psql: brew.psql, version: brew.version };
  reasons.push("no Homebrew postgresql@* prefix found");
  if (hasDocker()) {
    const image = versionHint ? `postgres:${versionHint}` : "postgres:17";
    return { kind: "docker", image };
  }
  reasons.push("docker not available");
  return { kind: "unavailable", reasons };
}
function resolvePgDump(versionHint) {
  const r = resolvePgClient(versionHint);
  if (r.kind === "binary") return { kind: "binary", path: r.pgDump, version: r.version };
  return r;
}
function which(bin) {
  try {
    const out = (0, import_node_child_process3.execFileSync)("which", [bin], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
    return out || null;
  } catch {
    return null;
  }
}
function probeVersion(binPath) {
  try {
    const out = (0, import_node_child_process3.execFileSync)(binPath, ["--version"], { encoding: "utf-8" }).trim();
    const m = /(\d+\.\d+|\d+)/.exec(out);
    return m ? m[1] : void 0;
  } catch {
    return void 0;
  }
}
function findPostgresApp(versionHint) {
  const root = "/Applications/Postgres.app/Contents/Versions";
  if (!(0, import_node_fs4.existsSync)(root)) return null;
  let versions;
  try {
    versions = (0, import_node_fs4.readdirSync)(root).filter((v) => /^\d+(\.\d+)?$/.test(v));
  } catch {
    return null;
  }
  const tryVersion = (v) => {
    const binDir = (0, import_node_path3.join)(root, v, "bin");
    const pgDump = (0, import_node_path3.join)(binDir, "pg_dump");
    const psql = (0, import_node_path3.join)(binDir, "psql");
    if ((0, import_node_fs4.existsSync)(pgDump) && (0, import_node_fs4.existsSync)(psql)) return { pgDump, psql, version: v };
    return null;
  };
  if (versionHint) {
    const hit = versions.find((v) => v.startsWith(String(versionHint)));
    if (hit) {
      const r = tryVersion(hit);
      if (r) return r;
    }
  }
  versions.sort((a, b) => parseFloat(b) - parseFloat(a));
  for (const v of versions) {
    const r = tryVersion(v);
    if (r) return r;
  }
  return null;
}
function findHomebrew(versionHint) {
  const candidates = versionHint ? [`postgresql@${versionHint}`] : ["postgresql@17", "postgresql@16", "postgresql@15", "postgresql"];
  for (const formula of candidates) {
    try {
      const prefix = (0, import_node_child_process3.execFileSync)("brew", ["--prefix", formula], {
        encoding: "utf-8",
        stdio: ["ignore", "pipe", "ignore"]
      }).trim();
      if (!prefix) continue;
      const pgDump = (0, import_node_path3.join)(prefix, "bin", "pg_dump");
      const psql = (0, import_node_path3.join)(prefix, "bin", "psql");
      if ((0, import_node_fs4.existsSync)(pgDump) && (0, import_node_fs4.existsSync)(psql)) {
        const m = /@(\d+)/.exec(formula);
        return { pgDump, psql, version: m ? m[1] : "unknown" };
      }
      const alt = (0, import_node_path3.join)(prefix, "libexec", "bin", "pg_dump");
      if ((0, import_node_fs4.existsSync)(alt)) {
        const altPsql = (0, import_node_path3.join)((0, import_node_path3.dirname)(alt), "psql");
        if ((0, import_node_fs4.existsSync)(altPsql)) {
          const m = /@(\d+)/.exec(formula);
          return { pgDump: alt, psql: altPsql, version: m ? m[1] : "unknown" };
        }
      }
    } catch {
    }
  }
  return null;
}
function hasDocker() {
  try {
    (0, import_node_child_process3.execFileSync)("docker", ["info"], { stdio: "ignore", timeout: 1500 });
    return true;
  } catch {
    return false;
  }
}
var import_node_child_process3, import_node_fs4, import_node_path3;
var init_pg_detect = __esm({
  "src/server/orbit/pg-detect.ts"() {
    "use strict";
    import_node_child_process3 = require("node:child_process");
    import_node_fs4 = require("node:fs");
    import_node_path3 = require("node:path");
  }
});

// src/server/orbit/adapters/postgres.ts
function isIdent(s) {
  return /^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/.test(s);
}
function q(ident) {
  return `"${ident.replace(/"/g, '""')}"`;
}
function resolveEnvRef(ref) {
  const m = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(ref);
  if (m) return process.env[m[1]] ?? null;
  return ref || null;
}
function composeAdminUrl(sourceUrl) {
  try {
    const u = new URL(sourceUrl);
    u.pathname = "/postgres";
    return u.toString();
  } catch {
    return sourceUrl;
  }
}
async function terminateConnections(admin, dbName) {
  await admin.query(
    `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`,
    [dbName]
  );
}
function stringifyClientResolution(r) {
  if (r.kind === "binary") return `binary:${r.pgDump}${r.version ? ` (v${r.version})` : ""}`;
  if (r.kind === "docker") return `docker:${r.image}`;
  return `unavailable (${r.reasons.join("; ")})`;
}
async function dumpRestoreClone(args) {
  const { admin, sourceUrl, dbName, version, schemaOnly, snapshot, logger } = args;
  const versionMajor = Math.floor(version / 1e4);
  const client = resolvePgClient(versionMajor);
  if (client.kind === "unavailable") {
    throw new Error(
      `orbit-pg: pg_dump + psql required for dump-restore: ${client.reasons.join("; ")}`
    );
  }
  const sourceUrlParsed = new URL(sourceUrl);
  const sourceDb = sourceUrlParsed.pathname.slice(1);
  if (!sourceDb) {
    throw new Error("orbit-pg: source URL has no database name in its path");
  }
  logger.step(`[orbit-pg] CREATE DATABASE ${q(dbName)}`);
  await admin.query(`CREATE DATABASE ${q(dbName)}`);
  const dstUrl = new URL(sourceUrl);
  dstUrl.pathname = `/${dbName}`;
  const dumpFlags = ["--no-owner", "--no-acl"];
  if (schemaOnly) dumpFlags.push("--schema-only");
  const pgDumpUrl = urlForShell(sourceUrl, client.kind);
  const psqlUrl = urlForShell(dstUrl.toString(), client.kind);
  const pgDumpCmd = client.kind === "binary" ? `${shellQuote(client.pgDump)} ${shellQuote(pgDumpUrl)} ${dumpFlags.join(" ")}` : `docker run --rm ${dockerNetworkArgs()}${shellQuote(client.image)} pg_dump ${shellQuote(pgDumpUrl)} ${dumpFlags.join(" ")}`;
  const psqlCmd = client.kind === "binary" ? `${shellQuote(client.psql)} ${shellQuote(psqlUrl)}` : `docker run --rm -i ${dockerNetworkArgs()}${shellQuote(client.image)} psql ${shellQuote(psqlUrl)}`;
  try {
    if (snapshot) {
      (0, import_node_fs5.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
      const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
      const snapshotPath = (0, import_node_path4.join)(SNAPSHOT_DIR, `${ts}_${sourceDb}_to_${dbName}.sql.gz`);
      logger.step(`[orbit-pg] pg_dump ${sourceDb} \u2192 ${snapshotPath}`);
      runShell(`${pgDumpCmd} | gzip > ${shellQuote(snapshotPath)}`, "pg_dump");
      logger.step(`[orbit-pg] restore ${snapshotPath} \u2192 ${dbName}${schemaOnly ? " (schema only)" : ""}`);
      runShell(`gunzip -c ${shellQuote(snapshotPath)} | ${psqlCmd} >/dev/null`, "psql restore");
      logger.ok(`[orbit-pg] cloned ${sourceDb} \u2192 ${dbName} (snapshot: ${snapshotPath})`);
    } else {
      logger.step(`[orbit-pg] pg_dump ${sourceDb} | psql ${dbName}${schemaOnly ? " (schema only)" : ""}`);
      runShell(`${pgDumpCmd} | ${psqlCmd} >/dev/null`, "pg_dump|psql");
      logger.ok(`[orbit-pg] cloned ${sourceDb} \u2192 ${dbName}`);
    }
  } catch (e) {
    try {
      await admin.query(`DROP DATABASE IF EXISTS ${q(dbName)}`);
    } catch {
    }
    throw e;
  }
}
function runShell(cmd, label) {
  const res = (0, import_node_child_process4.spawnSync)("bash", ["-c", `set -o pipefail; ${cmd}`], {
    stdio: ["ignore", "ignore", "pipe"]
  });
  if (res.status !== 0) {
    const stderr = res.stderr?.toString().trim() ?? "no stderr";
    throw new Error(`orbit-pg: ${label} failed (exit ${res.status}): ${stderr}`);
  }
}
async function runBackup(state, ctx) {
  (0, import_node_fs5.mkdirSync)(BACKUP_DIR, { recursive: true });
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
  const out = (0, import_node_path4.join)(BACKUP_DIR, `${ts}_${state.dbName}.sql.gz`);
  const versionMajor = Math.floor(state.version / 1e4);
  const resolution = resolvePgDump(versionMajor);
  if (resolution.kind === "unavailable") {
    throw new Error(`orbit-pg: pg_dump unavailable (${resolution.reasons.join("; ")}). Re-run with backup=false to skip.`);
  }
  const url = new URL(state.sourceUrl);
  url.pathname = `/${state.dbName}`;
  const dbUrl = urlForShell(url.toString(), resolution.kind === "docker" ? "docker" : "binary");
  const cmd = resolution.kind === "binary" ? `${shellQuote(resolution.path)} ${shellQuote(dbUrl)} --no-owner --no-acl | gzip > ${shellQuote(out)}` : `docker run --rm ${dockerNetworkArgs()}${shellQuote(resolution.image)} pg_dump ${shellQuote(dbUrl)} --no-owner --no-acl | gzip > ${shellQuote(out)}`;
  runShell(cmd, "pg_dump backup");
  if (!(0, import_node_fs5.existsSync)(out)) throw new Error(`pg_dump produced no output file: ${out}`);
  return out;
}
function shellQuote(s) {
  return `'${s.replace(/'/g, "'\\''")}'`;
}
function dockerizeUrl(url) {
  if (process.platform !== "darwin" && process.platform !== "win32") return url;
  try {
    const u = new URL(url);
    if (u.hostname === "localhost" || u.hostname === "127.0.0.1") {
      u.hostname = "host.docker.internal";
      return u.toString();
    }
    return url;
  } catch {
    return url;
  }
}
function dockerNetworkArgs() {
  return process.platform === "linux" ? "--network host " : "";
}
function cleanLibpqUrl(url) {
  try {
    const u = new URL(url);
    const PRISMA_ONLY = [
      "schema",
      "connection_limit",
      "pool_timeout",
      "pgbouncer",
      "socket_timeout",
      "statement_cache_size"
    ];
    for (const k of PRISMA_ONLY) u.searchParams.delete(k);
    return u.toString();
  } catch {
    return url;
  }
}
function urlForShell(url, kind) {
  const cleaned = cleanLibpqUrl(url);
  return kind === "docker" ? dockerizeUrl(cleaned) : cleaned;
}
var import_node_child_process4, import_node_fs5, import_node_os2, import_node_path4, import_pg, Client, BACKUP_DIR, SNAPSHOT_DIR, postgresAdapter;
var init_postgres = __esm({
  "src/server/orbit/adapters/postgres.ts"() {
    "use strict";
    import_node_child_process4 = require("node:child_process");
    import_node_fs5 = require("node:fs");
    import_node_os2 = require("node:os");
    import_node_path4 = require("node:path");
    import_pg = __toESM(require("pg"));
    init_launch_kit_paths();
    init_pg_detect();
    ({ Client } = import_pg.default);
    BACKUP_DIR = (0, import_node_path4.join)((0, import_node_os2.homedir)(), LAUNCHSECURE_DIR, "orbit", "backups");
    SNAPSHOT_DIR = (0, import_node_path4.join)((0, import_node_os2.homedir)(), LAUNCHSECURE_DIR, "orbit", "snapshots");
    postgresAdapter = {
      id: "orbit-pg",
      async detect(_ctx) {
        const url = resolveEnvRef("${DATABASE_URL}");
        if (!url) {
          return { ok: false, reason: "DATABASE_URL not set in environment" };
        }
        const client = new Client({ connectionString: url });
        try {
          await client.connect();
          const role = await client.query(
            `SELECT rolcreatedb AS create,
                pg_has_role(current_user, 'pg_signal_backend', 'MEMBER') AS signal,
                current_setting('server_version_num')::int AS version
         FROM pg_roles WHERE rolname = current_user`
          );
          const row = role.rows[0];
          if (!row) return { ok: false, reason: "current_user missing from pg_roles (unexpected)" };
          const caps = {
            rolcreatedb: row.create,
            pg_signal_backend: row.signal,
            server_version: row.version,
            pg_client: stringifyClientResolution(resolvePgClient(Math.floor(row.version / 1e4)))
          };
          if (!row.create) {
            return { ok: false, reason: "current_user lacks CREATEDB", capabilities: caps };
          }
          return { ok: true, capabilities: caps };
        } catch (e) {
          return { ok: false, reason: `connect failed: ${e.message}` };
        } finally {
          try {
            await client.end();
          } catch {
          }
        }
      },
      async fork(input) {
        const { slug, config, ctx } = input;
        const url = resolveEnvRef(config.source ?? "${DATABASE_URL}");
        if (!url) throw new Error("orbit-pg: source URL did not resolve (env var unset?)");
        const prefix = config.prefix ?? "orbit_";
        const strategy = config.strategy ?? "dump-restore";
        const template = config.template ?? `${prefix}template`;
        const dbName = `${prefix}${slug}`;
        const envKeys = config.rewrite?.env ?? ["DATABASE_URL"];
        const snapshot = config.snapshot ?? true;
        if (!isIdent(dbName)) throw new Error(`orbit-pg: derived dbName "${dbName}" is not a valid PG identifier`);
        if (strategy === "template-clone" && !isIdent(template)) {
          throw new Error(`orbit-pg: template "${template}" is not a valid PG identifier`);
        }
        const admin = new Client({ connectionString: composeAdminUrl(url) });
        await admin.connect();
        let version;
        try {
          version = (await admin.query(
            `SELECT current_setting('server_version_num')::int AS v`
          )).rows[0].v;
          if (strategy === "template-clone") {
            ctx.logger.step(`[orbit-pg] CREATE DATABASE ${q(dbName)} TEMPLATE ${q(template)}`);
            await terminateConnections(admin, template);
            const strategyClause = version >= 15e4 ? " STRATEGY = FILE_COPY" : "";
            await admin.query(`CREATE DATABASE ${q(dbName)} WITH TEMPLATE ${q(template)}${strategyClause}`);
            ctx.logger.ok(`[orbit-pg] created ${dbName} via template clone`);
          } else {
            const schemaOnly = strategy === "schema-only";
            await dumpRestoreClone({
              admin,
              sourceUrl: url,
              dbName,
              version,
              schemaOnly,
              snapshot,
              logger: ctx.logger
            });
          }
        } finally {
          try {
            await admin.end();
          } catch {
          }
        }
        return { dbName, sourceUrl: url, version, strategy, envKeys };
      },
      async drop(input) {
        const { state, backup, ctx } = input;
        const adminUrl = composeAdminUrl(state.sourceUrl);
        let backupPath;
        if (backup) {
          backupPath = await runBackup(state, ctx);
          ctx.logger.ok(`[orbit-pg] backup \u2192 ${backupPath}`);
        }
        const admin = new Client({ connectionString: adminUrl });
        await admin.connect();
        try {
          await terminateConnections(admin, state.dbName);
          ctx.logger.step(`[orbit-pg] DROP DATABASE ${q(state.dbName)}`);
          await admin.query(`DROP DATABASE IF EXISTS ${q(state.dbName)}`);
          ctx.logger.ok(`[orbit-pg] dropped ${state.dbName}`);
        } finally {
          try {
            await admin.end();
          } catch {
          }
        }
        return { backupPath };
      },
      envRewrites(state) {
        const map = {};
        for (const key of state.envKeys) {
          map[key] = (oldValue) => {
            if (typeof oldValue !== "string") return void 0;
            try {
              const u = new URL(oldValue);
              u.pathname = `/${state.dbName}`;
              return u.toString();
            } catch {
              return void 0;
            }
          };
        }
        return map;
      }
    };
  }
});

// src/server/orbit/adapter-registry.ts
function getWorktreeAdapter(id) {
  const a = WORKTREE[id];
  if (!a) {
    throw new Error(
      `unknown worktree adapter "${id}". Known: ${Object.keys(WORKTREE).join(", ")}.`
    );
  }
  return a;
}
function getResourceAdapter(id) {
  const a = RESOURCE[id];
  if (!a) {
    throw new Error(
      `unknown resource adapter "${id}". Known: ${Object.keys(RESOURCE).join(", ")}.`
    );
  }
  return a;
}
var WORKTREE, RESOURCE;
var init_adapter_registry = __esm({
  "src/server/orbit/adapter-registry.ts"() {
    "use strict";
    init_git_worktree();
    init_claude_code();
    init_port_range();
    init_postgres();
    WORKTREE = {
      "builtin/git-worktree": gitWorktreeAdapter,
      "builtin/claude-code": claudeCodeAdapter
    };
    RESOURCE = {
      "builtin/port-range": portRangeAdapter,
      "orbit-pg": postgresAdapter
    };
  }
});

// src/server/orbit/env-rewriter.ts
function copyEnvFile(srcPath, dstPath) {
  if (!(0, import_node_fs6.existsSync)(srcPath)) {
    throw new Error(`env source file not found: ${srcPath}`);
  }
  (0, import_node_fs6.copyFileSync)(srcPath, dstPath);
}
function rewriteEnvFile(filePath, rewrites) {
  if (!(0, import_node_fs6.existsSync)(filePath)) {
    throw new Error(`env file not found for rewrite: ${filePath}`);
  }
  const original = (0, import_node_fs6.readFileSync)(filePath, "utf-8");
  const lines = original.split(/\r?\n/);
  const result = { changed: [], unchanged: [], missing: [] };
  const touched = /* @__PURE__ */ new Set();
  const out = lines.map((line) => {
    const m = LINE_RE.exec(line);
    if (!m) return line;
    const [, indent, key, sep, rawValue] = m;
    if (!(key in rewrites)) return line;
    touched.add(key);
    const { quote, inner } = stripQuotes(rawValue);
    const transform = rewrites[key];
    const next2 = transform(inner, key);
    if (next2 === void 0 || next2 === inner) {
      result.unchanged.push(key);
      return line;
    }
    result.changed.push(key);
    return `${indent}${key}${sep}${quote}${next2}${quote}`;
  });
  for (const key of Object.keys(rewrites)) {
    if (!touched.has(key)) result.missing.push(key);
  }
  const next = out.join("\n");
  if (next !== original) {
    const tmp = `${filePath}.tmp.${process.pid}`;
    (0, import_node_fs6.writeFileSync)(tmp, next, "utf-8");
    (0, import_node_fs6.renameSync)(tmp, filePath);
  }
  return result;
}
function stripQuotes(raw) {
  const trimmed = raw.replace(/\s+#.*$/, "");
  if (trimmed.length >= 2) {
    const first = trimmed[0];
    const last = trimmed[trimmed.length - 1];
    if (first === '"' && last === '"' || first === "'" && last === "'") {
      return { quote: first, inner: trimmed.slice(1, -1) };
    }
  }
  return { quote: "", inner: trimmed };
}
var import_node_fs6, LINE_RE;
var init_env_rewriter = __esm({
  "src/server/orbit/env-rewriter.ts"() {
    "use strict";
    import_node_fs6 = require("node:fs");
    LINE_RE = /^(\s*)([A-Za-z_][A-Za-z0-9_]*)(\s*=\s*)(.*)$/;
  }
});

// src/server/orbit/gates/build-lint.ts
function finalize(checkPath, ctx, blockers, artifacts) {
  try {
    (0, import_node_child_process5.execFileSync)("git", ["worktree", "remove", "--force", checkPath], {
      cwd: ctx.projectRoot,
      stdio: "ignore"
    });
  } catch {
    try {
      (0, import_node_fs7.rmSync)(checkPath, { recursive: true, force: true });
    } catch {
    }
  }
  return {
    ok: blockers.length === 0,
    gateId: "builtin/build-lint",
    durationMs: 0,
    blockers,
    artifacts: Object.keys(artifacts).length > 0 ? artifacts : void 0
  };
}
function detectInstallCmd(projectRoot) {
  if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(projectRoot, "pnpm-lock.yaml"))) return "pnpm install --prefer-offline";
  if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(projectRoot, "yarn.lock"))) return "yarn install --prefer-offline";
  if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(projectRoot, "bun.lockb"))) return "bun install";
  return "npm install --prefer-offline --no-audit --no-fund";
}
function detectLintCmd(worktreePath) {
  return detectScriptCmd(worktreePath, "lint");
}
function detectBuildCmd(worktreePath) {
  return detectScriptCmd(worktreePath, "build");
}
function detectScriptCmd(worktreePath, scriptName) {
  const pkgPath = (0, import_node_path5.join)(worktreePath, "package.json");
  if (!(0, import_node_fs7.existsSync)(pkgPath)) return null;
  let pkg;
  try {
    pkg = JSON.parse((0, import_node_fs7.readFileSync)(pkgPath, "utf-8"));
  } catch {
    return null;
  }
  if (!pkg.scripts?.[scriptName]) return null;
  const pm = pkg.packageManager?.split("@")[0] ?? detectPmFromLock(worktreePath);
  return `${pm} run ${scriptName}`;
}
function loadOrbitEnv(orbitPath) {
  const file = (0, import_node_path5.join)(orbitPath, ".env.local");
  if (!(0, import_node_fs7.existsSync)(file)) return {};
  const out = {};
  let content;
  try {
    content = (0, import_node_fs7.readFileSync)(file, "utf-8");
  } catch {
    return {};
  }
  for (const line of content.split(/\r?\n/)) {
    const m = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line);
    if (!m) continue;
    let value = m[2].trim().replace(/\s+#.*$/, "");
    if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
      value = value.slice(1, -1);
    }
    out[m[1]] = value;
  }
  return out;
}
function detectPmFromLock(worktreePath) {
  if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(worktreePath, "pnpm-lock.yaml"))) return "pnpm";
  if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(worktreePath, "yarn.lock"))) return "yarn";
  if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(worktreePath, "bun.lockb"))) return "bun";
  return "npm";
}
function combineOutput(stdout, stderr) {
  const out = (stdout ?? "").trimEnd();
  const err2 = (stderr ?? "").trimEnd();
  if (!out && !err2) return "";
  if (!err2) return out + "\n";
  if (!out) return err2 + "\n";
  return `${out}

---STDERR---
${err2}
`;
}
function saveLog(slug, label, content) {
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
  const path = (0, import_node_path5.join)(LOG_DIR, `${ts}_${slug}_${label}.log`);
  (0, import_node_fs7.writeFileSync)(path, content, "utf-8");
  return path;
}
function shellQuote2(s) {
  return `'${s.replace(/'/g, "'\\''")}'`;
}
var import_node_child_process5, import_node_fs7, import_node_os3, import_node_path5, LOG_DIR, buildLintGate;
var init_build_lint = __esm({
  "src/server/orbit/gates/build-lint.ts"() {
    "use strict";
    import_node_child_process5 = require("node:child_process");
    import_node_fs7 = require("node:fs");
    import_node_os3 = require("node:os");
    import_node_path5 = require("node:path");
    init_launch_kit_paths();
    LOG_DIR = (0, import_node_path5.join)((0, import_node_os3.homedir)(), LAUNCHSECURE_DIR, "orbit", "gate-logs");
    buildLintGate = {
      id: "builtin/build-lint",
      name: "Build + lint on merged state",
      async detect(ctx) {
        try {
          (0, import_node_child_process5.execFileSync)("git", ["--version"], { cwd: ctx.projectRoot, stdio: "ignore" });
        } catch {
          return { ok: false, reason: "git not available" };
        }
        return { ok: true };
      },
      async check(ctx, config) {
        (0, import_node_fs7.mkdirSync)(LOG_DIR, { recursive: true });
        const checkPath = (0, import_node_path5.join)(ctx.projectRoot, ".claude", "worktrees", `__orbit-check-${ctx.entry.slug}__`);
        if ((0, import_node_fs7.existsSync)(checkPath)) {
          try {
            (0, import_node_child_process5.execFileSync)("git", ["worktree", "remove", "--force", checkPath], {
              cwd: ctx.projectRoot,
              stdio: "ignore"
            });
          } catch {
          }
          try {
            (0, import_node_fs7.rmSync)(checkPath, { recursive: true, force: true });
          } catch {
          }
        }
        const blockers = [];
        const artifacts = {};
        try {
          (0, import_node_child_process5.execFileSync)(
            "git",
            ["worktree", "add", "--detach", checkPath, ctx.entry.branch],
            { cwd: ctx.projectRoot, stdio: ["ignore", "pipe", "pipe"] }
          );
        } catch (e) {
          return {
            ok: false,
            gateId: "builtin/build-lint",
            durationMs: 0,
            blockers: [`failed to create ephemeral merge worktree: ${e.message}`]
          };
        }
        try {
          const mergeRes = (0, import_node_child_process5.spawnSync)(
            "git",
            ["merge", "--no-commit", "--no-ff", ctx.target],
            { cwd: checkPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
          );
          if (mergeRes.status !== 0) {
            const stderr = (mergeRes.stderr ?? "").toString().trim();
            blockers.push(`merge into ephemeral worktree failed: ${stderr.split("\n")[0] ?? "unknown"}`);
            return finalize(checkPath, ctx, blockers, artifacts);
          }
          const orbitEnv = loadOrbitEnv(ctx.entry.path);
          const spawnEnv = { ...process.env, ...orbitEnv };
          if (!(0, import_node_fs7.existsSync)((0, import_node_path5.join)(checkPath, "node_modules"))) {
            const installCmd = config.installCmd ?? detectInstallCmd(ctx.projectRoot);
            ctx.logger.step(`[build-lint] ${installCmd}`);
            const installRes = (0, import_node_child_process5.spawnSync)("bash", ["-c", `cd ${shellQuote2(checkPath)} && ${installCmd}`], {
              stdio: ["ignore", "pipe", "pipe"],
              encoding: "utf-8",
              env: spawnEnv
            });
            if (installRes.status !== 0) {
              const log = saveLog(ctx.entry.slug, "install", combineOutput(installRes.stdout, installRes.stderr));
              blockers.push("dependency install failed in ephemeral worktree");
              artifacts.install_log = log;
              return finalize(checkPath, ctx, blockers, artifacts);
            }
          }
          if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(checkPath, "prisma", "schema.prisma"))) {
            const prismaCmd = "npx prisma generate";
            ctx.logger.step(`[build-lint] ${prismaCmd}`);
            const prismaRes = (0, import_node_child_process5.spawnSync)("bash", ["-c", `cd ${shellQuote2(checkPath)} && ${prismaCmd}`], {
              stdio: ["ignore", "pipe", "pipe"],
              encoding: "utf-8",
              env: spawnEnv
            });
            if (prismaRes.status !== 0) {
              const log = saveLog(
                ctx.entry.slug,
                "prisma-generate",
                combineOutput(prismaRes.stdout, prismaRes.stderr)
              );
              blockers.push(`prisma generate failed (exit ${prismaRes.status}) \u2014 tsc will not be reliable`);
              artifacts["prisma-generate_log"] = log;
              return finalize(checkPath, ctx, blockers, artifacts);
            }
          }
          const tscMode = config.tsc ?? true;
          if (tscMode !== false) {
            const tscCmd = typeof tscMode === "string" ? tscMode : "npx tsc --noEmit";
            ctx.logger.step(`[build-lint] ${tscCmd}`);
            const tscRes = (0, import_node_child_process5.spawnSync)("bash", ["-c", `cd ${shellQuote2(checkPath)} && ${tscCmd}`], {
              stdio: ["ignore", "pipe", "pipe"],
              encoding: "utf-8",
              env: spawnEnv
            });
            if (tscRes.status !== 0) {
              const log = saveLog(ctx.entry.slug, "tsc", combineOutput(tscRes.stdout, tscRes.stderr));
              blockers.push(`tsc reported errors (exit ${tscRes.status})`);
              artifacts.tsc_log = log;
            }
          }
          const lintMode = config.lint ?? true;
          if (lintMode !== false) {
            const lintCmd = typeof lintMode === "string" ? lintMode : detectLintCmd(checkPath);
            if (lintCmd) {
              ctx.logger.step(`[build-lint] ${lintCmd}`);
              const lintRes = (0, import_node_child_process5.spawnSync)("bash", ["-c", `cd ${shellQuote2(checkPath)} && ${lintCmd}`], {
                stdio: ["ignore", "pipe", "pipe"],
                encoding: "utf-8",
                env: spawnEnv
              });
              if (lintRes.status !== 0) {
                const log = saveLog(ctx.entry.slug, "lint", combineOutput(lintRes.stdout, lintRes.stderr));
                blockers.push(`lint reported errors (exit ${lintRes.status})`);
                artifacts.lint_log = log;
              }
            } else if (lintMode === true) {
              ctx.logger.info(`[build-lint] no scripts.lint in package.json \u2014 skipping lint step`);
            }
          }
          const buildMode = config.build ?? true;
          if (buildMode !== false) {
            const buildCmd = typeof buildMode === "string" ? buildMode : detectBuildCmd(checkPath);
            if (buildCmd) {
              ctx.logger.step(`[build-lint] ${buildCmd}`);
              const buildRes = (0, import_node_child_process5.spawnSync)("bash", ["-c", `cd ${shellQuote2(checkPath)} && ${buildCmd}`], {
                stdio: ["ignore", "pipe", "pipe"],
                encoding: "utf-8",
                env: spawnEnv
              });
              if (buildRes.status !== 0) {
                const log = saveLog(ctx.entry.slug, "build", combineOutput(buildRes.stdout, buildRes.stderr));
                blockers.push(`build reported errors (exit ${buildRes.status})`);
                artifacts.build_log = log;
              }
            } else if (buildMode === true) {
              ctx.logger.info(`[build-lint] no scripts.build in package.json \u2014 skipping build step`);
            }
          }
          return finalize(checkPath, ctx, blockers, artifacts);
        } catch (e) {
          blockers.push(`build-lint gate threw: ${e.message}`);
          return finalize(checkPath, ctx, blockers, artifacts);
        }
      }
    };
  }
});

// src/server/orbit/gates/clean-tree.ts
var import_node_child_process6, import_node_fs8, cleanTreeGate;
var init_clean_tree = __esm({
  "src/server/orbit/gates/clean-tree.ts"() {
    "use strict";
    import_node_child_process6 = require("node:child_process");
    import_node_fs8 = require("node:fs");
    cleanTreeGate = {
      id: "builtin/clean-tree",
      name: "Orbit worktree has no uncommitted changes",
      async detect(ctx) {
        if (!(0, import_node_fs8.existsSync)(ctx.entry.path)) {
          return { ok: false, reason: `orbit worktree path missing: ${ctx.entry.path}` };
        }
        try {
          (0, import_node_child_process6.execFileSync)("git", ["rev-parse", "--is-inside-work-tree"], {
            cwd: ctx.entry.path,
            stdio: "ignore"
          });
          return { ok: true };
        } catch {
          return { ok: false, reason: `${ctx.entry.path} is not inside a git work tree` };
        }
      },
      async check(ctx, _config) {
        let output;
        try {
          output = (0, import_node_child_process6.execFileSync)("git", ["status", "--porcelain"], {
            cwd: ctx.entry.path,
            encoding: "utf-8",
            stdio: ["ignore", "pipe", "pipe"]
          });
        } catch (e) {
          return {
            ok: false,
            gateId: "builtin/clean-tree",
            durationMs: 0,
            blockers: [`git status failed in ${ctx.entry.path}: ${e.message}`]
          };
        }
        const lines = output.split("\n").filter((l) => l.length > 0);
        if (lines.length === 0) {
          return { ok: true, gateId: "builtin/clean-tree", durationMs: 0, blockers: [] };
        }
        return {
          ok: false,
          gateId: "builtin/clean-tree",
          durationMs: 0,
          blockers: [
            `orbit worktree has uncommitted changes (${lines.length} ${lines.length === 1 ? "entry" : "entries"}):`,
            ...lines.map((l) => `  ${l}`),
            `commit, stash, or remove these before merging.`
          ]
        };
      }
    };
  }
});

// src/server/orbit/gates/mergeability.ts
function refExists(cwd, ref) {
  try {
    (0, import_node_child_process7.execFileSync)("git", ["rev-parse", "--verify", ref], { cwd, stdio: "ignore" });
    return true;
  } catch {
    return false;
  }
}
var import_node_child_process7, mergeabilityGate;
var init_mergeability = __esm({
  "src/server/orbit/gates/mergeability.ts"() {
    "use strict";
    import_node_child_process7 = require("node:child_process");
    mergeabilityGate = {
      id: "builtin/mergeability",
      name: "Textual mergeability (git merge-tree)",
      async detect(ctx) {
        try {
          (0, import_node_child_process7.execFileSync)("git", ["rev-parse", "--show-toplevel"], {
            cwd: ctx.projectRoot,
            stdio: "ignore"
          });
          return { ok: true };
        } catch {
          return { ok: false, reason: "git not available in projectRoot" };
        }
      },
      async check(ctx, _config) {
        const blockers = [];
        if (!refExists(ctx.projectRoot, ctx.target)) {
          blockers.push(`target ref "${ctx.target}" does not exist`);
        }
        if (!refExists(ctx.projectRoot, ctx.entry.branch)) {
          blockers.push(`orbit branch "${ctx.entry.branch}" does not exist`);
        }
        if (blockers.length > 0) {
          return { ok: false, gateId: "builtin/mergeability", durationMs: 0, blockers };
        }
        let stdout = "";
        let exitCode = 0;
        try {
          stdout = (0, import_node_child_process7.execFileSync)(
            "git",
            ["merge-tree", "--write-tree", "--messages", ctx.target, ctx.entry.branch],
            { cwd: ctx.projectRoot, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
          );
        } catch (e) {
          const err2 = e;
          exitCode = err2.status ?? 1;
          stdout = err2.stdout?.toString() ?? "";
        }
        const lines = stdout.split("\n").filter((l) => l.length > 0);
        if (exitCode === 0 && lines.length <= 1) {
          return {
            ok: true,
            gateId: "builtin/mergeability",
            durationMs: 0,
            blockers: []
          };
        }
        const conflictLines = lines.slice(1);
        return {
          ok: false,
          gateId: "builtin/mergeability",
          durationMs: 0,
          blockers: conflictLines.length > 0 ? [`textual conflicts between ${ctx.entry.branch} and ${ctx.target}:`, ...conflictLines.map((l) => `  ${l}`)] : [`merge-tree reported exit ${exitCode} but produced no detail`]
        };
      }
    };
  }
});

// src/server/orbit/gate-registry.ts
function getMergeGate(id) {
  const g = GATES[id];
  if (!g) {
    throw new Error(
      `unknown merge gate "${id}". Known: ${Object.keys(GATES).join(", ")}.`
    );
  }
  return g;
}
var GATES;
var init_gate_registry = __esm({
  "src/server/orbit/gate-registry.ts"() {
    "use strict";
    init_build_lint();
    init_clean_tree();
    init_mergeability();
    GATES = {
      "builtin/clean-tree": cleanTreeGate,
      "builtin/mergeability": mergeabilityGate,
      "builtin/build-lint": buildLintGate
    };
  }
});

// src/server/orbit/gate-runner.ts
async function runMergeGates(manifest, ctx, options = {}) {
  const refs = manifest.gates?.merge ?? DEFAULT_GATES;
  const skip = new Set(options.skipGates ?? []);
  if (skip.size > 0) {
    const declared = new Set(refs.map((r) => r.adapter));
    for (const id of skip) {
      if (!declared.has(id)) {
        ctx.logger.warn(
          `--skip-gate "${id}" does not match any declared gate (declared: ${[...declared].join(", ")})`
        );
      }
    }
    const blockedRequired = refs.filter((r) => r.required && skip.has(r.adapter)).map((r) => r.adapter);
    if (blockedRequired.length > 0) {
      throw new Error(
        `cannot skip required gate(s): ${blockedRequired.join(", ")}. Remove "required": true from orbit.json if you really need to bypass.`
      );
    }
  }
  const start = Date.now();
  const results = [];
  for (const ref of refs) {
    if (skip.has(ref.adapter)) {
      ctx.logger.info(`[gate] skip ${ref.adapter} (--skip-gate)`);
      continue;
    }
    const gate = getMergeGate(ref.adapter);
    const detect = await gate.detect(ctx);
    if (!detect.ok) {
      results.push({
        ok: false,
        gateId: gate.id,
        durationMs: 0,
        blockers: [`gate ${gate.id} unavailable: ${detect.reason ?? "unknown"}`]
      });
      continue;
    }
    const gateStart = Date.now();
    try {
      const result = await gate.check(ctx, ref.config ?? {});
      results.push({ ...result, gateId: gate.id, durationMs: Date.now() - gateStart });
    } catch (e) {
      results.push({
        ok: false,
        gateId: gate.id,
        durationMs: Date.now() - gateStart,
        blockers: [`gate ${gate.id} threw: ${e.message}`]
      });
    }
  }
  return {
    allPassed: results.every((r) => r.ok),
    results,
    durationMs: Date.now() - start
  };
}
function formatGateResults(results) {
  const lines = [];
  for (const r of results) {
    const mark = r.ok ? "\u2713" : "\u2717";
    lines.push(`  ${mark} ${r.gateId} (${r.durationMs}ms)`);
    if (!r.ok) {
      for (const b of r.blockers) lines.push(`      ${b}`);
      if (r.artifacts) {
        for (const [k, v] of Object.entries(r.artifacts)) lines.push(`      ${k}: ${v}`);
      }
    }
  }
  return lines.join("\n");
}
var DEFAULT_GATES;
var init_gate_runner = __esm({
  "src/server/orbit/gate-runner.ts"() {
    "use strict";
    init_gate_registry();
    DEFAULT_GATES = [{ adapter: "builtin/mergeability", required: true }];
  }
});

// src/server/orbit/manifest.ts
function findManifestPath(projectRoot) {
  return (0, import_node_path6.join)(projectRoot, DEFAULT_MANIFEST_FILENAME);
}
function manifestExists(projectRoot) {
  return (0, import_node_fs9.existsSync)(findManifestPath(projectRoot));
}
function loadManifest(projectRoot) {
  const path = findManifestPath(projectRoot);
  if (!(0, import_node_fs9.existsSync)(path)) {
    throw new Error(
      `orbit.json not found at ${path}. Run \`launch-orbit init\` to create one.`
    );
  }
  let raw;
  try {
    raw = JSON.parse((0, import_node_fs9.readFileSync)(path, "utf-8"));
  } catch (e) {
    throw new Error(`orbit.json is not valid JSON: ${e.message}`);
  }
  return validateManifest(raw, path);
}
function validateManifest(raw, sourcePath) {
  if (!isRecord(raw)) throw err("must be an object", sourcePath);
  if (raw.version !== 1) throw err(`unsupported version ${String(raw.version)} (expected 1)`, sourcePath);
  const envFile = validateEnvFile(raw.envFile, sourcePath);
  const worktree = validateWorktreeRef(raw.worktree, sourcePath);
  const resources = validateResourcesArray(raw.resources, sourcePath);
  const gates = validateGates(raw.gates, sourcePath);
  const profiles = validateProfiles(raw.profiles, resources, sourcePath);
  return {
    version: 1,
    ...envFile !== void 0 ? { envFile } : {},
    worktree,
    resources,
    ...gates !== void 0 ? { gates } : {},
    ...profiles !== void 0 ? { profiles } : {}
  };
}
function validateProfiles(raw, resources, sourcePath) {
  if (raw === void 0) return void 0;
  if (!isRecord(raw)) throw err("profiles must be an object if present", sourcePath);
  const known = new Set(resources.map((r) => r.name));
  const out = {};
  for (const [name, value] of Object.entries(raw)) {
    if (!name) throw err("profiles keys must be non-empty strings", sourcePath);
    if (!isRecord(value)) throw err(`profiles.${name} must be an object`, sourcePath);
    if (!Array.isArray(value.resources)) {
      throw err(`profiles.${name}.resources must be an array of resource names`, sourcePath);
    }
    const list2 = [];
    const seen = /* @__PURE__ */ new Set();
    for (let i = 0; i < value.resources.length; i++) {
      const r = value.resources[i];
      if (typeof r !== "string" || !r) {
        throw err(`profiles.${name}.resources[${i}] must be a non-empty string`, sourcePath);
      }
      if (!known.has(r)) {
        throw err(
          `profiles.${name}.resources[${i}] "${r}" does not match any resource name (known: ${[...known].join(", ") || "(none)"})`,
          sourcePath
        );
      }
      if (seen.has(r)) {
        throw err(`profiles.${name}.resources[${i}] "${r}" duplicated`, sourcePath);
      }
      seen.add(r);
      list2.push(r);
    }
    out[name] = { resources: list2 };
  }
  return Object.keys(out).length > 0 ? out : void 0;
}
function validateGates(raw, sourcePath) {
  if (raw === void 0) return void 0;
  if (!isRecord(raw)) throw err("gates must be an object if present", sourcePath);
  const out = {};
  if (raw.merge !== void 0) {
    if (!Array.isArray(raw.merge)) throw err("gates.merge must be an array", sourcePath);
    const seen = /* @__PURE__ */ new Set();
    const list2 = [];
    for (let i = 0; i < raw.merge.length; i++) {
      const g = raw.merge[i];
      if (!isRecord(g)) throw err(`gates.merge[${i}] must be an object`, sourcePath);
      if (typeof g.adapter !== "string" || !g.adapter) {
        throw err(`gates.merge[${i}].adapter must be a non-empty string`, sourcePath);
      }
      if (seen.has(g.adapter)) {
        throw err(`gates.merge[${i}].adapter "${g.adapter}" duplicated`, sourcePath);
      }
      seen.add(g.adapter);
      const config = g.config;
      if (config !== void 0 && !isRecord(config)) {
        throw err(`gates.merge[${i}].config must be an object if present`, sourcePath);
      }
      const required = g.required;
      if (required !== void 0 && typeof required !== "boolean") {
        throw err(`gates.merge[${i}].required must be a boolean if present`, sourcePath);
      }
      list2.push({
        adapter: g.adapter,
        config,
        ...required ? { required: true } : {}
      });
    }
    out.merge = list2;
  }
  return Object.keys(out).length > 0 ? out : void 0;
}
function validateEnvFile(raw, sourcePath) {
  if (raw === void 0) return void 0;
  if (typeof raw !== "string" || !raw) throw err("envFile must be a non-empty string", sourcePath);
  if (raw.includes("..") || raw.startsWith("/")) {
    throw err(`envFile must be a project-relative path (got "${raw}")`, sourcePath);
  }
  return raw;
}
function validateWorktreeRef(raw, sourcePath) {
  if (!isRecord(raw)) throw err("worktree must be an object", sourcePath);
  if (typeof raw.adapter !== "string" || !raw.adapter) {
    throw err("worktree.adapter must be a non-empty string", sourcePath);
  }
  const config = raw.config;
  if (config !== void 0 && !isRecord(config)) {
    throw err("worktree.config must be an object if present", sourcePath);
  }
  return { adapter: raw.adapter, config };
}
function validateResourcesArray(raw, sourcePath) {
  if (!Array.isArray(raw)) throw err("resources must be an array", sourcePath);
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (let i = 0; i < raw.length; i++) {
    const r = raw[i];
    if (!isRecord(r)) throw err(`resources[${i}] must be an object`, sourcePath);
    if (typeof r.name !== "string" || !r.name) {
      throw err(`resources[${i}].name must be a non-empty string`, sourcePath);
    }
    if (seen.has(r.name)) throw err(`resources[${i}].name "${r.name}" is duplicated`, sourcePath);
    seen.add(r.name);
    if (typeof r.adapter !== "string" || !r.adapter) {
      throw err(`resources[${i}].adapter must be a non-empty string`, sourcePath);
    }
    const config = r.config;
    if (config !== void 0 && !isRecord(config)) {
      throw err(`resources[${i}].config must be an object if present`, sourcePath);
    }
    out.push({
      name: r.name,
      adapter: r.adapter,
      config
    });
  }
  return out;
}
function isRecord(x) {
  return typeof x === "object" && x !== null && !Array.isArray(x);
}
function err(msg, sourcePath) {
  return new Error(`orbit.json (${sourcePath}): ${msg}`);
}
var import_node_fs9, import_node_path6, DEFAULT_MANIFEST_FILENAME;
var init_manifest = __esm({
  "src/server/orbit/manifest.ts"() {
    "use strict";
    import_node_fs9 = require("node:fs");
    import_node_path6 = require("node:path");
    DEFAULT_MANIFEST_FILENAME = "orbit.json";
  }
});

// src/server/orbit/slug.ts
function slugify(branch) {
  let s = branch.toLowerCase();
  s = s.replace(/[^a-z0-9]+/g, "_");
  s = s.replace(/^_+|_+$/g, "");
  if (/^\d/.test(s)) s = `b_${s}`;
  if (s.length > MAX_SLUG_LEN) s = s.slice(0, MAX_SLUG_LEN).replace(/_+$/, "");
  if (!s) throw new Error(`branch "${branch}" produced empty slug`);
  return s;
}
var MAX_SLUG_LEN;
var init_slug = __esm({
  "src/server/orbit/slug.ts"() {
    "use strict";
    MAX_SLUG_LEN = 48;
  }
});

// src/server/orbit/orchestrator.ts
async function create(opts) {
  const start = Date.now();
  const slug = slugify(opts.branch);
  const manifest = loadManifestOrThrow(opts.projectRoot);
  const envFileName = opts.envFileName ?? manifest.envFile ?? DEFAULT_ENV_FILE;
  const ctx = {
    projectRoot: opts.projectRoot,
    manifestPath: (0, import_node_path7.join)(opts.projectRoot, "orbit.json"),
    manifest,
    logger: opts.logger,
    envFileName
  };
  if (lookupWorktree(slug)) {
    throw new Error(`worktree "${slug}" already registered. Run \`launch-orbit drop ${slug}\` first.`);
  }
  const effectiveResources = resolveProfile(manifest, opts.profile);
  if (opts.profile) {
    opts.logger.info(
      `profile "${opts.profile}" \u2192 resources: ${effectiveResources.map((r) => r.name).join(", ") || "(none)"}`
    );
  }
  const worktreeAdapter = getWorktreeAdapter(manifest.worktree.adapter);
  const wtDetect = await worktreeAdapter.detect(ctx);
  if (!wtDetect.ok) throw new Error(`worktree adapter "${worktreeAdapter.id}" unavailable: ${wtDetect.reason}`);
  const worktreeConfig = withHookPayload(manifest.worktree.config ?? {}, manifest.worktree.adapter, opts.hookPayload);
  opts.logger.step(`creating worktree via ${worktreeAdapter.id}`);
  const worktreeState = await worktreeAdapter.create({
    slug,
    branch: opts.branch,
    baseRef: opts.baseRef,
    config: worktreeConfig,
    ctx
  });
  opts.logger.ok(`worktree at ${worktreeState.path}`);
  const cleanups = [
    async () => {
      await worktreeAdapter.remove({ state: worktreeState, force: true, ctx });
    }
  ];
  const resourceStates = {};
  const rewriteFns = {};
  try {
    for (const ref of effectiveResources) {
      const adapter = getResourceAdapter(ref.adapter);
      const detect = await adapter.detect(ctx);
      if (!detect.ok) throw new Error(`resource adapter "${adapter.id}" unavailable: ${detect.reason}`);
      opts.logger.step(`fork resource "${ref.name}" via ${adapter.id}`);
      const state = await adapter.fork({ slug, config: ref.config ?? {}, ctx });
      opts.logger.ok(`resource "${ref.name}" forked`);
      resourceStates[ref.name] = { adapter: adapter.id, state };
      cleanups.push(async () => {
        try {
          await adapter.drop({ state, backup: false, ctx });
        } catch (e) {
          opts.logger.warn(`rollback: failed to drop ${ref.name}: ${e.message}`);
        }
      });
      if (adapter.envRewrites) {
        Object.assign(rewriteFns, adapter.envRewrites(state, ctx));
      }
    }
    const srcEnv = (0, import_node_path7.join)(opts.projectRoot, envFileName);
    const dstEnv = (0, import_node_path7.join)(worktreeState.path, envFileName);
    if ((0, import_node_fs10.existsSync)(srcEnv) && !(0, import_node_fs10.existsSync)(dstEnv)) {
      opts.logger.step(`copy ${envFileName} into worktree`);
      copyEnvFile(srcEnv, dstEnv);
    }
    if ((0, import_node_fs10.existsSync)(dstEnv) && Object.keys(rewriteFns).length > 0) {
      opts.logger.step(`rewrite ${envFileName} (${Object.keys(rewriteFns).join(", ")})`);
      const r = rewriteEnvFile(dstEnv, rewriteFns);
      if (r.missing.length > 0) {
        opts.logger.warn(`env keys not present in ${envFileName}: ${r.missing.join(", ")}`);
      }
      opts.logger.ok(`env rewritten (${r.changed.length} changed, ${r.unchanged.length} unchanged)`);
    }
    const entry = {
      slug,
      branch: opts.branch,
      path: worktreeState.path,
      createdAt: (/* @__PURE__ */ new Date()).toISOString(),
      projectRoot: opts.projectRoot,
      resources: resourceStates
    };
    await registerWorktree(entry);
    opts.logger.ok(`registered ${slug}`);
    try {
      opts.logger.step(`generate chart graph for worktree`);
      const chartEntry = (0, import_node_path7.join)(__dirname, "graph-mcp-entry.js");
      const result = (0, import_node_child_process8.spawnSync)(
        process.execPath,
        [chartEntry, "generate"],
        {
          cwd: worktreeState.path,
          stdio: "pipe",
          encoding: "utf-8",
          timeout: 6e4
        }
      );
      if (result.status === 0) {
        opts.logger.ok(`chart graph generated`);
      } else {
        const detail = (result.stderr || result.stdout || "").toString().trim().split("\n")[0]?.slice(0, 200) ?? "unknown";
        opts.logger.warn(
          `chart graph generation failed (${detail}). Re-run later with: launch-chart generate (from ${worktreeState.path})`
        );
      }
    } catch (e) {
      opts.logger.warn(`chart graph generation skipped: ${e.message}`);
    }
    return {
      slug,
      branch: opts.branch,
      path: worktreeState.path,
      envFile: dstEnv,
      durationMs: Date.now() - start,
      resources: Object.fromEntries(Object.entries(resourceStates).map(([k, v]) => [k, v.state])),
      nextAction: `cd ${worktreeState.path}`
    };
  } catch (err2) {
    opts.logger.error(`create failed: ${err2.message} \u2014 rolling back`);
    for (const undo of cleanups.reverse()) {
      try {
        await undo();
      } catch (e) {
        opts.logger.warn(`rollback step failed: ${e.message}`);
      }
    }
    throw err2;
  }
}
async function drop(opts) {
  const slug = slugify(opts.branch);
  const entry = lookupWorktree(slug);
  if (!entry) {
    return { slug, backups: {}, freed: {} };
  }
  const manifest = loadManifestOrThrow(opts.projectRoot);
  const ctx = {
    projectRoot: opts.projectRoot,
    manifestPath: (0, import_node_path7.join)(opts.projectRoot, "orbit.json"),
    manifest,
    logger: opts.logger,
    envFileName: manifest.envFile ?? DEFAULT_ENV_FILE
  };
  const backups = {};
  const freed = {};
  const ordered = [...manifest.resources].reverse();
  for (const ref of ordered) {
    const state = entry.resources[ref.name];
    if (!state) continue;
    const adapter = getResourceAdapter(state.adapter);
    opts.logger.step(`drop resource "${ref.name}" via ${adapter.id}`);
    const result = await adapter.drop({
      state: state.state,
      backup: opts.backup ?? true,
      ctx
    });
    if (result.backupPath) backups[ref.name] = result.backupPath;
    freed[ref.name] = state.state;
  }
  if ((0, import_node_fs10.existsSync)(entry.path)) {
    const blockers = findBlockingPids(entry.path);
    if (blockers.length > 0) {
      opts.logger.warn(`${blockers.length} process(es) holding files in worktree \u2014 terminating:`);
      for (const b of blockers) opts.logger.step(`  pid ${b.pid} (${b.cmd})`);
      terminateProcesses(blockers.map((b) => b.pid), opts.logger);
    }
  }
  const worktreeAdapter = getWorktreeAdapter(manifest.worktree.adapter);
  opts.logger.step(`remove worktree via ${worktreeAdapter.id}`);
  try {
    await worktreeAdapter.remove({
      state: { path: entry.path, branch: entry.branch },
      force: true,
      ctx
    });
  } catch (e) {
    opts.logger.warn(`worktree remove failed (continuing anyway): ${e.message}`);
  }
  if ((0, import_node_fs10.existsSync)(entry.path)) {
    opts.logger.step(`remove leftover dir at ${entry.path}`);
    try {
      (0, import_node_fs10.rmSync)(entry.path, { recursive: true, force: true });
    } catch (e) {
      opts.logger.warn(`leftover dir cleanup failed: ${e.message}`);
    }
  }
  await deregisterWorktree(slug);
  opts.logger.ok(`dropped ${slug}`);
  return { slug, backups, freed };
}
function list() {
  return listWorktrees().map((w) => ({
    slug: w.slug,
    branch: w.branch,
    path: w.path,
    age: formatAge(w.createdAt),
    resources: Object.fromEntries(Object.entries(w.resources).map(([k, v]) => [k, v.state]))
  }));
}
function switchTo(opts) {
  const slug = slugify(opts.branch);
  const entry = lookupWorktree(slug);
  if (!entry) throw new Error(`no orbit registered for branch "${opts.branch}" (slug ${slug})`);
  return {
    path: entry.path,
    envFile: (0, import_node_path7.join)(entry.path, DEFAULT_ENV_FILE),
    entry
  };
}
function doctor() {
  const issues = [];
  const trackedByRoot = /* @__PURE__ */ new Map();
  const tracked = (projectRoot) => {
    let s = trackedByRoot.get(projectRoot);
    if (s) return s;
    s = /* @__PURE__ */ new Set();
    try {
      const out = (0, import_node_child_process8.execFileSync)("git", ["worktree", "list", "--porcelain"], {
        cwd: projectRoot,
        encoding: "utf-8",
        stdio: ["ignore", "pipe", "ignore"]
      });
      for (const line of out.split("\n")) {
        if (line.startsWith("worktree ")) s.add(line.slice("worktree ".length));
      }
    } catch {
    }
    trackedByRoot.set(projectRoot, s);
    return s;
  };
  for (const w of listWorktrees()) {
    if (!(0, import_node_fs10.existsSync)(w.path)) {
      issues.push({ kind: "missing-worktree", slug: w.slug, detail: `path ${w.path} does not exist` });
      continue;
    }
    if (!tracked(w.projectRoot).has(w.path)) {
      issues.push({
        kind: "orphan-registration",
        slug: w.slug,
        detail: `${w.path} is in the orbit registry but not in \`git worktree list\` for ${w.projectRoot}. Run \`orbit drop ${w.branch}\` to reconcile.`
      });
    }
  }
  return issues;
}
function findBlockingPids(path) {
  let out;
  try {
    out = (0, import_node_child_process8.execFileSync)("lsof", ["-F", "pc", "+D", path], {
      encoding: "utf-8",
      stdio: ["ignore", "pipe", "ignore"]
    });
  } catch {
    return [];
  }
  const results = /* @__PURE__ */ new Map();
  let currentPid = 0;
  for (const line of out.split("\n")) {
    if (line.startsWith("p")) {
      currentPid = Number(line.slice(1));
      if (!Number.isFinite(currentPid) || currentPid === process.pid) currentPid = 0;
    } else if (line.startsWith("c") && currentPid && !results.has(currentPid)) {
      results.set(currentPid, line.slice(1));
    }
  }
  return [...results].map(([pid, cmd]) => ({ pid, cmd }));
}
function terminateProcesses(pids, logger) {
  for (const pid of pids) {
    try {
      process.kill(pid, "SIGTERM");
    } catch {
    }
  }
  const wakeUpAt = Date.now() + 750;
  while (Date.now() < wakeUpAt) {
    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);
  }
  for (const pid of pids) {
    try {
      process.kill(pid, 0);
      process.kill(pid, "SIGKILL");
      logger.warn(`pid ${pid} did not respond to SIGTERM \u2014 sent SIGKILL`);
    } catch {
    }
  }
}
async function checkMergeable(opts) {
  const start = Date.now();
  const slug = slugify(opts.branch);
  const entry = lookupWorktree(slug);
  if (!entry) throw new Error(`no orbit registered for branch "${opts.branch}" (slug ${slug})`);
  const manifest = loadManifestOrThrow(opts.projectRoot);
  const gateCtx = {
    entry,
    target: opts.target,
    projectRoot: opts.projectRoot,
    worktreePath: entry.path,
    manifest,
    logger: opts.logger
  };
  opts.logger.step(`running merge gates against target "${opts.target}"`);
  const agg = await runMergeGates(manifest, gateCtx, { skipGates: opts.skipGates });
  opts.logger.info(formatGateResults(agg.results));
  return {
    slug,
    branch: entry.branch,
    target: opts.target,
    passed: agg.allPassed,
    gates: agg.results,
    durationMs: Date.now() - start
  };
}
async function merge(opts) {
  const start = Date.now();
  const cleanup = opts.cleanup ?? "full";
  const check = await checkMergeable({
    branch: opts.branch,
    target: opts.target,
    skipGates: opts.skipGates,
    projectRoot: opts.projectRoot,
    logger: opts.logger
  });
  if (!check.passed) {
    const blockers = check.gates.flatMap((g) => g.blockers);
    opts.logger.error(`gates blocked the merge \u2014 fix the above and retry`);
    return {
      slug: check.slug,
      branch: check.branch,
      target: opts.target,
      merged: false,
      gates: check.gates,
      cleanedUp: false,
      blockedBy: blockers,
      durationMs: Date.now() - start
    };
  }
  const targetWorktree = findWorktreeFor(opts.projectRoot, opts.target);
  if (!targetWorktree) {
    return {
      slug: check.slug,
      branch: check.branch,
      target: opts.target,
      merged: false,
      gates: check.gates,
      cleanedUp: false,
      blockedBy: [`no worktree currently has "${opts.target}" checked out \u2014 check it out in main and retry`],
      durationMs: Date.now() - start
    };
  }
  opts.logger.step(`git merge --ff-only ${check.branch} (in ${targetWorktree})`);
  const mergeRes = (0, import_node_child_process8.spawnSync)(
    "git",
    ["merge", "--ff-only", check.branch],
    { cwd: targetWorktree, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
  );
  if (mergeRes.status !== 0) {
    const stderr = (mergeRes.stderr ?? "").toString().trim();
    opts.logger.warn(`ff-only failed (${stderr.split("\n")[0]}); attempting non-ff merge`);
    const merge2 = (0, import_node_child_process8.spawnSync)(
      "git",
      ["merge", "--no-ff", "-m", `Merge orbit ${check.slug} into ${opts.target}`, check.branch],
      { cwd: targetWorktree, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
    );
    if (merge2.status !== 0) {
      const detail = (merge2.stderr ?? merge2.stdout ?? "").toString().trim();
      return {
        slug: check.slug,
        branch: check.branch,
        target: opts.target,
        merged: false,
        gates: check.gates,
        cleanedUp: false,
        blockedBy: [`git merge failed despite passing gates: ${detail.split("\n")[0] ?? "unknown"}`],
        durationMs: Date.now() - start
      };
    }
  }
  const mergeSha = (0, import_node_child_process8.execFileSync)("git", ["rev-parse", "HEAD"], {
    cwd: targetWorktree,
    encoding: "utf-8"
  }).trim();
  opts.logger.ok(`merged ${check.branch} \u2192 ${opts.target} (${mergeSha.slice(0, 7)})`);
  let backupPath;
  let cleanedUp = false;
  if (cleanup === "full") {
    opts.logger.step(`cleanup: dropping orbit ${check.slug}`);
    const dropResult = await drop({
      branch: opts.branch,
      backup: true,
      projectRoot: opts.projectRoot,
      logger: opts.logger
    });
    backupPath = dropResult.backups.db;
    cleanedUp = true;
    opts.logger.ok(`cleaned up ${check.slug} (backup: ${backupPath ?? "n/a"})`);
  }
  return {
    slug: check.slug,
    branch: check.branch,
    target: opts.target,
    merged: true,
    mergeSha,
    gates: check.gates,
    cleanedUp,
    backupPath,
    durationMs: Date.now() - start
  };
}
function findWorktreeFor(projectRoot, branch) {
  try {
    const out = (0, import_node_child_process8.execFileSync)("git", ["worktree", "list", "--porcelain"], {
      cwd: projectRoot,
      encoding: "utf-8"
    });
    const blocks = out.split("\n\n").filter(Boolean);
    for (const block of blocks) {
      const lines = block.split("\n");
      const wtLine = lines.find((l) => l.startsWith("worktree "));
      const brLine = lines.find((l) => l.startsWith("branch "));
      if (!wtLine || !brLine) continue;
      const path = wtLine.slice("worktree ".length);
      const ref = brLine.slice("branch ".length);
      const name = ref.replace(/^refs\/heads\//, "");
      if (name === branch) return path;
    }
    return null;
  } catch {
    return null;
  }
}
function resolveProfile(manifest, profile) {
  if (!profile) return manifest.resources;
  const ref = manifest.profiles?.[profile];
  if (!ref) {
    const known = Object.keys(manifest.profiles ?? {});
    throw new Error(
      `profile "${profile}" not declared in orbit.json. Available: ${known.length > 0 ? known.join(", ") : "(none \u2014 add a `profiles` block to orbit.json)"}`
    );
  }
  const byName = new Map(manifest.resources.map((r) => [r.name, r]));
  return ref.resources.map((name) => {
    const r = byName.get(name);
    if (!r) throw new Error(`profile "${profile}" references unknown resource "${name}"`);
    return r;
  });
}
function loadManifestOrThrow(projectRoot) {
  if (!manifestExists(projectRoot)) {
    throw new Error(
      `orbit.json not found at ${projectRoot}/orbit.json. Run \`launch-orbit init\` to scaffold one.`
    );
  }
  return loadManifest(projectRoot);
}
function withHookPayload(config, adapterId, hookPayload) {
  if (adapterId !== "builtin/claude-code" || !hookPayload) return config;
  return { ...config, existingPath: hookPayload.path };
}
function formatAge(iso) {
  const ms = Date.now() - new Date(iso).getTime();
  const m = Math.floor(ms / 6e4);
  if (m < 60) return `${m}m`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h`;
  const d = Math.floor(h / 24);
  return `${d}d`;
}
var import_node_child_process8, import_node_fs10, import_node_path7, DEFAULT_ENV_FILE;
var init_orchestrator = __esm({
  "src/server/orbit/orchestrator.ts"() {
    "use strict";
    import_node_child_process8 = require("node:child_process");
    import_node_fs10 = require("node:fs");
    import_node_path7 = require("node:path");
    init_adapter_registry();
    init_env_rewriter();
    init_gate_runner();
    init_manifest();
    init_registry();
    init_slug();
    DEFAULT_ENV_FILE = ".env.local";
  }
});

// src/server/orbit/logger.ts
function createCliLogger(prefix = "orbit") {
  return {
    info: (m) => process.stdout.write(`[${prefix}] ${m}
`),
    warn: (m) => process.stderr.write(`[${prefix}] \u26A0 ${m}
`),
    error: (m) => process.stderr.write(`[${prefix}] \u2717 ${m}
`),
    step: (m) => process.stdout.write(`  \u2192 ${m}
`),
    ok: (m) => process.stdout.write(`    \u2713 ${m}
`)
  };
}
function createMcpLogger(prefix = "orbit") {
  const w = (m) => process.stderr.write(`[${prefix}] ${m}
`);
  return {
    info: w,
    warn: (m) => w(`\u26A0 ${m}`),
    error: (m) => w(`\u2717 ${m}`),
    step: (m) => w(`\u2192 ${m}`),
    ok: (m) => w(`  \u2713 ${m}`)
  };
}
var init_logger = __esm({
  "src/server/orbit/logger.ts"() {
    "use strict";
  }
});

// src/server/orbit-mcp.ts
var orbit_mcp_exports = {};
__export(orbit_mcp_exports, {
  startOrbitMcpServer: () => startOrbitMcpServer
});
async function handleTool(name, args) {
  const projectRoot = process.cwd();
  const logger = createMcpLogger();
  switch (name) {
    case "orbit.create": {
      const branch = String(args.branch ?? "");
      const baseRef = args.baseRef;
      const profile = args.profile;
      if (!branch) return text({ error: "branch is required" });
      const result = await create({ branch, baseRef, profile, projectRoot, logger });
      return text(result);
    }
    case "orbit.list": {
      return text(list());
    }
    case "orbit.switch": {
      const branch = String(args.branch ?? "");
      if (!branch) return text({ error: "branch is required" });
      const result = switchTo({ branch, projectRoot });
      return text({
        slug: result.entry.slug,
        path: result.path,
        envFile: result.envFile,
        nextAction: `cd ${result.path}`
      });
    }
    case "orbit.drop": {
      const branch = String(args.branch ?? "");
      if (!branch) return text({ error: "branch is required" });
      const backup = args.backup === false ? false : true;
      const result = await drop({ branch, backup, projectRoot, logger });
      return text(result);
    }
    case "orbit.doctor": {
      return text({ issues: doctor() });
    }
    case "orbit.check_mergeable": {
      const branch = String(args.branch ?? "");
      const target = String(args.target ?? "");
      if (!branch) return text({ error: "branch is required" });
      if (!target) return text({ error: "target is required" });
      const skipGates = parseSkipGates(args.skipGates);
      if (skipGates instanceof Error) return text({ error: skipGates.message });
      const result = await checkMergeable({ branch, target, skipGates, projectRoot, logger });
      return text(result);
    }
    case "orbit.merge": {
      const branch = String(args.branch ?? "");
      const target = String(args.target ?? "");
      if (!branch) return text({ error: "branch is required" });
      if (!target) return text({ error: "target is required" });
      const cleanupArg = args.cleanup;
      const cleanup = cleanupArg === "none" ? "none" : cleanupArg === "full" || cleanupArg === void 0 ? "full" : void 0;
      if (cleanup === void 0) {
        return text({ error: `cleanup must be "full" or "none" (got ${JSON.stringify(cleanupArg)})` });
      }
      const skipGates = parseSkipGates(args.skipGates);
      if (skipGates instanceof Error) return text({ error: skipGates.message });
      const result = await merge({ branch, target, cleanup, skipGates, projectRoot, logger });
      return text(result);
    }
    default:
      return text({ error: `unknown tool: ${name}` });
  }
}
function parseSkipGates(raw) {
  if (raw === void 0 || raw === null) return void 0;
  if (!Array.isArray(raw)) return new Error("skipGates must be an array of adapter ids");
  const out = [];
  for (const v of raw) {
    if (typeof v !== "string" || !v) return new Error("skipGates entries must be non-empty strings");
    out.push(v);
  }
  return out.length > 0 ? out : void 0;
}
function text(payload) {
  const t = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2);
  return { content: [{ type: "text", text: t }] };
}
function send(msg) {
  process.stdout.write(JSON.stringify(msg) + "\n");
}
function sendResponse(id, result) {
  send({ jsonrpc: "2.0", id, result });
}
function sendError(id, code, message) {
  send({ jsonrpc: "2.0", id, error: { code, message } });
}
async function handleMessage(parsed) {
  const id = parsed.id;
  const method = parsed.method;
  const params = parsed.params ?? {};
  switch (method) {
    case "initialize":
      sendResponse(id ?? null, {
        protocolVersion: "2024-11-05",
        capabilities: { tools: {} },
        serverInfo: SERVER_INFO
      });
      break;
    case "notifications/initialized":
      break;
    case "tools/list":
      sendResponse(id ?? null, { tools: TOOLS });
      break;
    case "tools/call": {
      const toolName = params.name;
      const toolArgs = params.arguments ?? {};
      try {
        const result = await handleTool(toolName, toolArgs);
        sendResponse(id ?? null, result);
      } catch (err2) {
        sendError(id ?? null, -32603, `Tool error: ${err2.message}`);
      }
      break;
    }
    case "ping":
      sendResponse(id ?? null, {});
      break;
    default:
      if (id !== void 0) sendError(id ?? null, -32601, `Method not found: ${method}`);
  }
}
function startOrbitMcpServer() {
  process.stderr.write("[launch-orbit] MCP server starting on stdio\n");
  process.stdin.setEncoding("utf-8");
  let buffer = "";
  process.stdin.on("data", (chunk) => {
    buffer += chunk;
    const lines = buffer.split("\n");
    buffer = lines.pop() || "";
    for (const line of lines) {
      const trimmed = line.trim();
      if (!trimmed) continue;
      try {
        handleMessage(JSON.parse(trimmed)).catch((err2) => {
          process.stderr.write(`[launch-orbit] message error: ${err2}
`);
        });
      } catch (err2) {
        process.stderr.write(`[launch-orbit] parse error: ${err2}
`);
      }
    }
  });
  process.stdin.on("end", () => {
    process.stderr.write("[launch-orbit] stdin closed, exiting\n");
    process.exit(0);
  });
}
var SERVER_INFO, TOOLS;
var init_orbit_mcp = __esm({
  "src/server/orbit-mcp.ts"() {
    "use strict";
    init_orchestrator();
    init_logger();
    SERVER_INFO = {
      name: "launch-orbit",
      version: "0.0.1"
    };
    TOOLS = [
      {
        name: "orbit.create",
        description: "Create an isolated worktree environment for a branch. Forks the resources declared in orbit.json (database, ports, etc.) so the new worktree is fully independent from the main one.\n\nPass `profile` to fork only a named subset of resources from orbit.json's `profiles` block \u2014 e.g. a frontend-only task can use a `fe` profile that skips the DB clone. Without `profile`, all manifest resources are forked.\n\nReturns: { slug, branch, path, envFile, durationMs, resources, nextAction }. The `path` is the absolute worktree directory \u2014 the caller should `cd` into it for subsequent commands. `nextAction` contains the exact shell command to do so.",
        inputSchema: {
          type: "object",
          properties: {
            branch: { type: "string", description: "Git branch name to create (also the slug source)." },
            baseRef: { type: "string", description: "Optional ref to branch from (default: current HEAD)." },
            profile: {
              type: "string",
              description: "Optional profile name from orbit.json's `profiles`. Scopes which resources are forked. Omit to fork all resources."
            }
          },
          required: ["branch"]
        }
      },
      {
        name: "orbit.list",
        description: "List every registered orbit on this machine across all projects. Returns an array of { slug, branch, path, age, resources }.",
        inputSchema: { type: "object", properties: {} }
      },
      {
        name: "orbit.switch",
        description: "Look up the path + env file of an existing orbit by branch name. Does NOT change any shell \u2014 the caller is expected to `cd` into the returned path. Useful for agents that need to operate inside an already-created orbit.",
        inputSchema: {
          type: "object",
          properties: {
            branch: { type: "string", description: "Branch name to look up." }
          },
          required: ["branch"]
        }
      },
      {
        name: "orbit.drop",
        description: "Tear down an orbit: backup the database (default true), drop the database, terminate any process holding files inside the worktree (chart/beacon MCPs, dev servers \u2014 via lsof+SIGTERM), remove the worktree, sweep any leftover on-disk dir, deregister. Idempotent: safe to retry on a partial state (e.g. git already removed the worktree but the registry still claims it). Returns { slug, backups, freed }.",
        inputSchema: {
          type: "object",
          properties: {
            branch: { type: "string", description: "Branch name to drop." },
            backup: { type: "boolean", description: "Whether to pg_dump first (default true)." }
          },
          required: ["branch"]
        }
      },
      {
        name: "orbit.doctor",
        description: "Report inconsistencies in the registry. Detects: 'missing-worktree' (registered path doesn't exist on disk), 'orphan-registration' (path exists + registered, but git no longer tracks it \u2014 the partial-drop state). Returns an array of issues. Fix with `orbit drop <branch>` \u2014 drop is now idempotent and resolves both kinds.",
        inputSchema: { type: "object", properties: {} }
      },
      {
        name: "orbit.check_mergeable",
        description: 'Run all configured pre-merge gates against an orbit + target branch WITHOUT actually merging. Used by agents to verify before calling orbit.merge. Default gates: builtin/mergeability (textual conflict check) and any others declared in orbit.json\'s `gates.merge`.\n\nPass `skipGates: ["builtin/build-lint"]` to bypass specific gates by adapter id. Gates marked `required: true` in orbit.json reject skipping and throw \u2014 typically used on the textual conflict check.\n\nReturns: { slug, branch, target, passed, gates: [{ gateId, ok, blockers, artifacts }], durationMs }. If `passed` is false, `gates` contains per-gate detail including human-readable blocker lines and paths to artifact logs (tsc output, lint output, etc.).',
        inputSchema: {
          type: "object",
          properties: {
            branch: { type: "string", description: "The orbit's branch (slug-able)." },
            target: { type: "string", description: "Branch we'd merge INTO." },
            skipGates: {
              type: "array",
              items: { type: "string" },
              description: 'Adapter ids to skip (e.g. ["builtin/build-lint"]). Throws if any id has `required: true` in orbit.json. Warns on unknown ids without failing.'
            }
          },
          required: ["branch", "target"]
        }
      },
      {
        name: "orbit.merge",
        description: 'Run gates, and if all pass, perform the merge into the target branch. Default cleanup behavior is `full` \u2014 after a successful merge, the orbit is dropped (DB pg_dump\'d, then DROP DATABASE; worktree removed; branch deleted). Use cleanup="none" to keep the orbit around post-merge.\n\nPass `skipGates: ["builtin/build-lint"]` to bypass specific gates by adapter id. Gates marked `required: true` in orbit.json reject skipping and throw.\n\nReturns: { slug, branch, target, merged, mergeSha, gates, cleanedUp, backupPath, durationMs, blockedBy }. If merged is false, blockedBy lists what stopped the merge (gate failures or git errors).',
        inputSchema: {
          type: "object",
          properties: {
            branch: { type: "string", description: "The orbit's branch (slug-able)." },
            target: { type: "string", description: "Branch to merge INTO. Must be checked out in some worktree." },
            cleanup: {
              type: "string",
              enum: ["full", "none"],
              description: "Post-merge action. `full` drops the orbit; `none` leaves it intact."
            },
            skipGates: {
              type: "array",
              items: { type: "string" },
              description: 'Adapter ids to skip (e.g. ["builtin/build-lint"]). Throws if any id has `required: true` in orbit.json. Warns on unknown ids without failing.'
            }
          },
          required: ["branch", "target"]
        }
      }
    ];
  }
});

// src/server/orbit-entry.ts
var import_node_fs11 = require("node:fs");
var import_node_path8 = require("node:path");
init_orchestrator();
init_logger();
function parseFlags(argv) {
  const positional = [];
  const flags = { emitCd: false, noBackup: false, skipGates: [] };
  for (let i = 0; i < argv.length; i++) {
    const a = argv[i];
    if (a === "--emit-cd") flags.emitCd = true;
    else if (a === "--no-backup") flags.noBackup = true;
    else if (a === "--base-ref") flags.baseRef = argv[++i];
    else if (a === "--profile") flags.profile = argv[++i];
    else if (a === "--skip-gate") {
      const id = argv[++i];
      if (!id) die("--skip-gate requires an adapter id (e.g. --skip-gate builtin/build-lint)");
      flags.skipGates.push(id);
    } else if (a === "--cleanup") {
      const v = argv[++i];
      if (v !== "full" && v !== "none") {
        process.stderr.write(`[launch-orbit] --cleanup must be "full" or "none" (got "${v}")
`);
        process.exit(2);
      }
      flags.cleanup = v;
    } else if (a.startsWith("--")) {
      process.stderr.write(`[launch-orbit] unknown flag: ${a}
`);
      process.exit(2);
    } else positional.push(a);
  }
  return { positional, flags };
}
async function main() {
  const argv = process.argv.slice(2);
  const subcommand = argv[0];
  if (!subcommand || subcommand === "mcp") {
    const { startOrbitMcpServer: startOrbitMcpServer2 } = await Promise.resolve().then(() => (init_orbit_mcp(), orbit_mcp_exports));
    startOrbitMcpServer2();
    return;
  }
  const { positional, flags } = parseFlags(argv.slice(1));
  const projectRoot = process.cwd();
  const logger = createCliLogger();
  try {
    switch (subcommand) {
      case "init": {
        runInit(projectRoot);
        return;
      }
      case "create": {
        const branch = positional[0];
        if (!branch) die("usage: launch-orbit create <branch> [--base-ref <ref>] [--profile <name>] [--emit-cd]");
        const result = await create({
          branch,
          baseRef: flags.baseRef,
          profile: flags.profile,
          projectRoot,
          logger
        });
        if (flags.emitCd) {
          process.stdout.write(`cd ${result.path}
`);
        } else {
          process.stdout.write(`
${JSON.stringify(result, null, 2)}
`);
        }
        return;
      }
      case "list": {
        const rows = list();
        if (rows.length === 0) {
          process.stdout.write("(no orbits registered)\n");
          return;
        }
        for (const r of rows) {
          process.stdout.write(`${r.slug}	${r.branch}	${r.age}	${r.path}
`);
        }
        return;
      }
      case "switch": {
        const branch = positional[0];
        if (!branch) die("usage: launch-orbit switch <branch> [--emit-cd]");
        const result = switchTo({ branch, projectRoot });
        if (flags.emitCd) {
          process.stdout.write(`cd ${result.path}
`);
        } else {
          process.stdout.write(`${JSON.stringify({ path: result.path, envFile: result.envFile, nextAction: `cd ${result.path}` }, null, 2)}
`);
        }
        return;
      }
      case "drop": {
        const branch = positional[0];
        if (!branch) die("usage: launch-orbit drop <branch> [--no-backup]");
        const result = await drop({
          branch,
          backup: !flags.noBackup,
          projectRoot,
          logger
        });
        process.stdout.write(`
${JSON.stringify(result, null, 2)}
`);
        return;
      }
      case "doctor": {
        const issues = doctor();
        if (issues.length === 0) {
          process.stdout.write("\u2713 no issues\n");
          return;
        }
        for (const i of issues) {
          process.stdout.write(`  \u26A0 [${i.kind}] ${i.detail}${i.slug ? ` (${i.slug})` : ""}
`);
        }
        process.exit(1);
      }
      case "check-merge": {
        const branch = positional[0];
        const target = positional[1];
        if (!branch || !target) {
          die("usage: launch-orbit check-merge <branch> <target> [--skip-gate <id> ...]");
        }
        const result = await checkMergeable({
          branch,
          target,
          skipGates: flags.skipGates.length > 0 ? flags.skipGates : void 0,
          projectRoot,
          logger
        });
        process.stdout.write(`
${JSON.stringify(result, null, 2)}
`);
        if (!result.passed) process.exit(1);
        return;
      }
      case "merge": {
        const branch = positional[0];
        const target = positional[1];
        if (!branch || !target) {
          die("usage: launch-orbit merge <branch> <target> [--cleanup full|none] [--skip-gate <id> ...]");
        }
        const result = await merge({
          branch,
          target,
          cleanup: flags.cleanup ?? "full",
          skipGates: flags.skipGates.length > 0 ? flags.skipGates : void 0,
          projectRoot,
          logger
        });
        process.stdout.write(`
${JSON.stringify(result, null, 2)}
`);
        if (!result.merged) process.exit(1);
        return;
      }
      default:
        die(`unknown subcommand: ${subcommand}`);
    }
  } catch (err2) {
    logger.error(err2.message);
    process.exit(1);
  }
}
function runInit(projectRoot) {
  const path = (0, import_node_path8.join)(projectRoot, "orbit.json");
  if ((0, import_node_fs11.existsSync)(path)) {
    process.stderr.write(`[launch-orbit] orbit.json already exists at ${path}
`);
    process.exit(1);
  }
  const starter = {
    $schema: "https://orbit.dev/schema/v1.json",
    version: 1,
    worktree: {
      adapter: "builtin/git-worktree",
      config: {
        basePath: ".claude/worktrees",
        namingPattern: "{slug}"
      }
    },
    resources: [
      {
        name: "db",
        adapter: "orbit-pg",
        config: {
          source: "${DATABASE_URL}",
          strategy: "dump-restore",
          prefix: "orbit_",
          snapshot: true,
          rewrite: { env: ["DATABASE_URL", "DIRECT_URL"] }
        }
      },
      {
        name: "ports",
        adapter: "builtin/port-range",
        config: {
          base: 3e3,
          stride: 10,
          rewrite: {
            env: ["APP_URL", "NEXT_PUBLIC_APP_URL", "NEXT_PUBLIC_API_URL", "GITHUB_CALLBACK_URL"],
            replace: ":3000"
          }
        }
      }
    ],
    gates: {
      merge: [
        { adapter: "builtin/clean-tree" },
        // `required: true` blocks --skip-gate on this one — silently merging a
        // textual conflict is the obvious footgun. Drop the flag if you really
        // need to bypass.
        { adapter: "builtin/mergeability", required: true },
        { adapter: "builtin/build-lint" }
      ]
    },
    profiles: {
      fe: { resources: ["ports"] },
      full: { resources: ["db", "ports"] }
    }
  };
  (0, import_node_fs11.writeFileSync)(path, JSON.stringify(starter, null, 2) + "\n", "utf-8");
  process.stdout.write(`\u2713 wrote ${path}
`);
}
function die(msg) {
  process.stderr.write(`[launch-orbit] ${msg}
`);
  process.exit(2);
}
void main();
